blob: d1f361a91971df2820d766cc2a27d50868d7b62a [file] [log] [blame]
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001" Test Vim9 classes
2
3source check.vim
4import './vim9.vim' as v9
5
6def Test_class_basic()
7 var lines =<< trim END
8 class NotWorking
9 endclass
10 END
11 v9.CheckScriptFailure(lines, 'E1316:')
12
13 lines =<< trim END
14 vim9script
15 class notWorking
16 endclass
17 END
18 v9.CheckScriptFailure(lines, 'E1314:')
19
20 lines =<< trim END
21 vim9script
22 class Not@working
23 endclass
24 END
25 v9.CheckScriptFailure(lines, 'E1315:')
26
27 lines =<< trim END
28 vim9script
29 abstract noclass Something
30 endclass
31 END
32 v9.CheckScriptFailure(lines, 'E475:')
33
34 lines =<< trim END
35 vim9script
36 abstract classy Something
37 endclass
38 END
39 v9.CheckScriptFailure(lines, 'E475:')
40
41 lines =<< trim END
42 vim9script
43 class Something
44 endcl
45 END
46 v9.CheckScriptFailure(lines, 'E1065:')
47
48 lines =<< trim END
49 vim9script
50 class Something
Bram Moolenaar94722c52023-01-28 19:19:03 +000051 endclass school's out
Bram Moolenaar00b28d62022-12-08 15:32:33 +000052 END
53 v9.CheckScriptFailure(lines, 'E488:')
54
55 lines =<< trim END
56 vim9script
57 class Something
58 endclass | echo 'done'
59 END
60 v9.CheckScriptFailure(lines, 'E488:')
61
62 lines =<< trim END
63 vim9script
64 class Something
65 this
66 endclass
67 END
68 v9.CheckScriptFailure(lines, 'E1317:')
69
70 lines =<< trim END
71 vim9script
72 class Something
73 this.
74 endclass
75 END
76 v9.CheckScriptFailure(lines, 'E1317:')
77
78 lines =<< trim END
79 vim9script
80 class Something
81 this .count
82 endclass
83 END
84 v9.CheckScriptFailure(lines, 'E1317:')
85
86 lines =<< trim END
87 vim9script
88 class Something
89 this. count
90 endclass
91 END
92 v9.CheckScriptFailure(lines, 'E1317:')
93
94 lines =<< trim END
95 vim9script
96 class Something
97 this.count: number
98 that.count
99 endclass
100 END
101 v9.CheckScriptFailure(lines, 'E1318: Not a valid command in a class: that.count')
102
103 lines =<< trim END
104 vim9script
105 class Something
106 this.count
107 endclass
108 END
109 v9.CheckScriptFailure(lines, 'E1022:')
110
111 lines =<< trim END
112 vim9script
113 class Something
Bram Moolenaarf54cedd2022-12-23 17:56:27 +0000114 def new()
115 this.state = 0
116 enddef
117 endclass
118 var obj = Something.new()
119 END
120 v9.CheckScriptFailure(lines, 'E1089:')
121
122 lines =<< trim END
123 vim9script
124 class Something
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000125 this.count : number
126 endclass
127 END
128 v9.CheckScriptFailure(lines, 'E1059:')
129
130 lines =<< trim END
131 vim9script
132 class Something
133 this.count:number
134 endclass
135 END
136 v9.CheckScriptFailure(lines, 'E1069:')
137
138 lines =<< trim END
139 vim9script
140
141 class TextPosition
142 this.lnum: number
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000143 this.col: number
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000144
Bram Moolenaar418b5472022-12-20 13:38:22 +0000145 # make a nicely formatted string
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000146 def ToString(): string
147 return $'({this.lnum}, {this.col})'
148 enddef
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000149 endclass
150
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000151 # use the automatically generated new() method
152 var pos = TextPosition.new(2, 12)
153 assert_equal(2, pos.lnum)
154 assert_equal(12, pos.col)
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000155
156 # call an object method
157 assert_equal('(2, 12)', pos.ToString())
Bram Moolenaarc0c2c262023-01-12 21:08:53 +0000158
159 assert_equal(v:t_class, type(TextPosition))
160 assert_equal(v:t_object, type(pos))
161 assert_equal('class<TextPosition>', typename(TextPosition))
162 assert_equal('object<TextPosition>', typename(pos))
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000163 END
164 v9.CheckScriptSuccess(lines)
165enddef
166
Bram Moolenaar657aea72023-01-27 13:16:19 +0000167def Test_class_interface_wrong_end()
168 var lines =<< trim END
169 vim9script
170 abstract class SomeName
171 this.member = 'text'
172 endinterface
173 END
174 v9.CheckScriptFailure(lines, 'E476: Invalid command: endinterface, expected endclass')
175
176 lines =<< trim END
177 vim9script
178 export interface AnotherName
179 this.member: string
180 endclass
181 END
182 v9.CheckScriptFailure(lines, 'E476: Invalid command: endclass, expected endinterface')
183enddef
184
Bram Moolenaar552bdca2023-02-17 21:08:50 +0000185def Test_object_not_set()
186 var lines =<< trim END
187 vim9script
188
189 class State
190 this.value = 'xyz'
191 endclass
192
Bram Moolenaarf2017f22023-02-17 21:29:57 +0000193 var state: State
Bram Moolenaar552bdca2023-02-17 21:08:50 +0000194 var db = {'xyz': 789}
195 echo db[state.value]
196 END
197 v9.CheckScriptFailure(lines, 'E1360:')
Bram Moolenaar0917e862023-02-18 14:42:44 +0000198
199 lines =<< trim END
200 vim9script
201
202 class Background
203 this.background = 'dark'
204 endclass
205
206 class Colorscheme
207 this._bg: Background
208
209 def GetBackground(): string
210 return this._bg.background
211 enddef
212 endclass
213
214 var bg: Background # UNINITIALIZED
215 echo Colorscheme.new(bg).GetBackground()
216 END
217 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object<Background> but got object<Unknown>')
Bram Moolenaar552bdca2023-02-17 21:08:50 +0000218enddef
219
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000220def Test_class_member_initializer()
221 var lines =<< trim END
222 vim9script
223
224 class TextPosition
225 this.lnum: number = 1
226 this.col: number = 1
227
Bram Moolenaar418b5472022-12-20 13:38:22 +0000228 # constructor with only the line number
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000229 def new(lnum: number)
230 this.lnum = lnum
231 enddef
232 endclass
233
234 var pos = TextPosition.new(3)
235 assert_equal(3, pos.lnum)
236 assert_equal(1, pos.col)
237
238 var instr = execute('disassemble TextPosition.new')
239 assert_match('new\_s*' ..
Bram Moolenaar3ea8a1b2022-12-10 19:03:51 +0000240 '0 NEW TextPosition size \d\+\_s*' ..
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000241 '\d PUSHNR 1\_s*' ..
242 '\d STORE_THIS 0\_s*' ..
243 '\d PUSHNR 1\_s*' ..
244 '\d STORE_THIS 1\_s*' ..
245 'this.lnum = lnum\_s*' ..
246 '\d LOAD arg\[-1]\_s*' ..
247 '\d PUSHNR 0\_s*' ..
248 '\d LOAD $0\_s*' ..
249 '\d\+ STOREINDEX object\_s*' ..
250 '\d\+ RETURN object.*',
251 instr)
252 END
253 v9.CheckScriptSuccess(lines)
254enddef
255
Bram Moolenaar2c1c8032023-02-18 18:38:37 +0000256def Test_member_any_used_as_object()
257 var lines =<< trim END
258 vim9script
259
260 class Inner
261 this.value: number = 0
262 endclass
263
264 class Outer
265 this.inner: any
266 endclass
267
268 def F(outer: Outer)
269 outer.inner.value = 1
270 enddef
271
272 var inner_obj = Inner.new(0)
273 var outer_obj = Outer.new(inner_obj)
274 F(outer_obj)
275 assert_equal(1, inner_obj.value)
276 END
277 v9.CheckScriptSuccess(lines)
278
279 lines =<< trim END
280 vim9script
281
282 class Inner
283 this.value: number = 0
284 endclass
285
286 class Outer
287 this.inner: Inner
288 endclass
289
290 def F(outer: Outer)
291 outer.inner.value = 1
292 enddef
293
294 def Test_assign_to_nested_typed_member()
295 var inner = Inner.new(0)
296 var outer = Outer.new(inner)
297 F(outer)
298 assert_equal(1, inner.value)
299 enddef
300
301 Test_assign_to_nested_typed_member()
302 END
303 v9.CheckScriptSuccess(lines)
304enddef
305
Bram Moolenaar4cae8452023-01-15 15:51:48 +0000306def Test_assignment_with_operator()
307 var lines =<< trim END
308 vim9script
309
310 class Foo
311 this.x: number
312
313 def Add(n: number)
314 this.x += n
315 enddef
316 endclass
317
318 var f = Foo.new(3)
319 f.Add(17)
320 assert_equal(20, f.x)
321 END
322 v9.CheckScriptSuccess(lines)
323enddef
324
Bram Moolenaarf4508042023-01-15 16:54:57 +0000325def Test_list_of_objects()
326 var lines =<< trim END
327 vim9script
328
329 class Foo
330 def Add()
331 enddef
332 endclass
333
334 def ProcessList(fooList: list<Foo>)
335 for foo in fooList
336 foo.Add()
337 endfor
338 enddef
339
340 var l: list<Foo> = [Foo.new()]
341 ProcessList(l)
342 END
343 v9.CheckScriptSuccess(lines)
344enddef
345
Bram Moolenaar912bfee2023-01-15 20:18:55 +0000346def Test_expr_after_using_object()
347 var lines =<< trim END
348 vim9script
349
350 class Something
351 this.label: string = ''
352 endclass
353
354 def Foo(): Something
355 var v = Something.new()
356 echo 'in Foo(): ' .. typename(v)
357 return v
358 enddef
359
360 Foo()
361 END
362 v9.CheckScriptSuccess(lines)
363enddef
364
Bram Moolenaar65b0d162022-12-13 18:43:22 +0000365def Test_class_default_new()
366 var lines =<< trim END
367 vim9script
368
369 class TextPosition
370 this.lnum: number = 1
371 this.col: number = 1
372 endclass
373
374 var pos = TextPosition.new()
375 assert_equal(1, pos.lnum)
376 assert_equal(1, pos.col)
377
378 pos = TextPosition.new(v:none, v:none)
379 assert_equal(1, pos.lnum)
380 assert_equal(1, pos.col)
381
382 pos = TextPosition.new(3, 22)
383 assert_equal(3, pos.lnum)
384 assert_equal(22, pos.col)
385
386 pos = TextPosition.new(v:none, 33)
387 assert_equal(1, pos.lnum)
388 assert_equal(33, pos.col)
389 END
390 v9.CheckScriptSuccess(lines)
391
392 lines =<< trim END
393 vim9script
394 class Person
395 this.name: string
396 this.age: number = 42
397 this.education: string = "unknown"
398
399 def new(this.name, this.age = v:none, this.education = v:none)
400 enddef
401 endclass
402
403 var piet = Person.new("Piet")
404 assert_equal("Piet", piet.name)
405 assert_equal(42, piet.age)
406 assert_equal("unknown", piet.education)
407
408 var chris = Person.new("Chris", 4, "none")
409 assert_equal("Chris", chris.name)
410 assert_equal(4, chris.age)
411 assert_equal("none", chris.education)
412 END
413 v9.CheckScriptSuccess(lines)
Bram Moolenaar74e12742022-12-13 21:14:28 +0000414
415 lines =<< trim END
416 vim9script
417 class Person
418 this.name: string
419 this.age: number = 42
420 this.education: string = "unknown"
421
422 def new(this.name, this.age = v:none, this.education = v:none)
423 enddef
424 endclass
425
426 var missing = Person.new()
427 END
428 v9.CheckScriptFailure(lines, 'E119:')
Bram Moolenaar65b0d162022-12-13 18:43:22 +0000429enddef
430
Bram Moolenaar74e12742022-12-13 21:14:28 +0000431def Test_class_object_member_inits()
432 var lines =<< trim END
433 vim9script
434 class TextPosition
435 this.lnum: number
436 this.col = 1
437 this.addcol: number = 2
438 endclass
439
440 var pos = TextPosition.new()
441 assert_equal(0, pos.lnum)
442 assert_equal(1, pos.col)
443 assert_equal(2, pos.addcol)
444 END
445 v9.CheckScriptSuccess(lines)
446
447 lines =<< trim END
448 vim9script
449 class TextPosition
450 this.lnum
451 this.col = 1
452 endclass
453 END
454 v9.CheckScriptFailure(lines, 'E1022:')
455
456 lines =<< trim END
457 vim9script
458 class TextPosition
459 this.lnum = v:none
460 this.col = 1
461 endclass
462 END
463 v9.CheckScriptFailure(lines, 'E1330:')
464enddef
465
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000466def Test_class_object_member_access()
467 var lines =<< trim END
468 vim9script
469 class Triple
470 this._one = 1
471 this.two = 2
472 public this.three = 3
473
474 def GetOne(): number
475 return this._one
476 enddef
477 endclass
478
479 var trip = Triple.new()
480 assert_equal(1, trip.GetOne())
481 assert_equal(2, trip.two)
482 assert_equal(3, trip.three)
483 assert_fails('echo trip._one', 'E1333')
484
485 assert_fails('trip._one = 11', 'E1333')
486 assert_fails('trip.two = 22', 'E1335')
487 trip.three = 33
488 assert_equal(33, trip.three)
Bram Moolenaard505d172022-12-18 21:42:55 +0000489
490 assert_fails('trip.four = 4', 'E1334')
491 END
492 v9.CheckScriptSuccess(lines)
Bram Moolenaar590162c2022-12-24 21:24:06 +0000493
494 lines =<< trim END
495 vim9script
496
497 class MyCar
498 this.make: string
Bram Moolenaar574950d2023-01-03 19:08:50 +0000499 this.age = 5
Bram Moolenaar590162c2022-12-24 21:24:06 +0000500
501 def new(make_arg: string)
502 this.make = make_arg
503 enddef
504
505 def GetMake(): string
506 return $"make = {this.make}"
507 enddef
Bram Moolenaar574950d2023-01-03 19:08:50 +0000508 def GetAge(): number
509 return this.age
510 enddef
Bram Moolenaar590162c2022-12-24 21:24:06 +0000511 endclass
512
513 var c = MyCar.new("abc")
514 assert_equal('make = abc', c.GetMake())
515
516 c = MyCar.new("def")
517 assert_equal('make = def', c.GetMake())
518
519 var c2 = MyCar.new("123")
520 assert_equal('make = 123', c2.GetMake())
Bram Moolenaar574950d2023-01-03 19:08:50 +0000521
522 def CheckCar()
523 assert_equal("make = def", c.GetMake())
524 assert_equal(5, c.GetAge())
525 enddef
526 CheckCar()
Bram Moolenaar590162c2022-12-24 21:24:06 +0000527 END
528 v9.CheckScriptSuccess(lines)
Bram Moolenaar6ef54712022-12-25 19:31:36 +0000529
530 lines =<< trim END
531 vim9script
532
533 class MyCar
534 this.make: string
535
536 def new(make_arg: string)
537 this.make = make_arg
538 enddef
539 endclass
540
541 var c = MyCar.new("abc")
542 var c = MyCar.new("def")
543 END
544 v9.CheckScriptFailure(lines, 'E1041:')
Bram Moolenaarb149d222023-01-24 13:03:37 +0000545
546 lines =<< trim END
547 vim9script
548
549 class Foo
550 this.x: list<number> = []
551
552 def Add(n: number): any
553 this.x->add(n)
554 return this
555 enddef
556 endclass
557
558 echo Foo.new().Add(1).Add(2).x
559 echo Foo.new().Add(1).Add(2)
560 .x
561 echo Foo.new().Add(1)
562 .Add(2).x
563 echo Foo.new()
564 .Add(1).Add(2).x
565 echo Foo.new()
566 .Add(1)
567 .Add(2)
568 .x
569 END
570 v9.CheckScriptSuccess(lines)
Bram Moolenaard505d172022-12-18 21:42:55 +0000571enddef
572
Bram Moolenaarbcf31ec2023-01-02 20:32:24 +0000573def Test_class_object_compare()
574 var class_lines =<< trim END
575 vim9script
576 class Item
577 this.nr = 0
578 this.name = 'xx'
579 endclass
580 END
581
582 # used at the script level and in a compiled function
583 var test_lines =<< trim END
584 var i1 = Item.new()
585 assert_equal(i1, i1)
586 assert_true(i1 is i1)
587 var i2 = Item.new()
588 assert_equal(i1, i2)
589 assert_false(i1 is i2)
590 var i3 = Item.new(0, 'xx')
591 assert_equal(i1, i3)
592
593 var io1 = Item.new(1, 'xx')
594 assert_notequal(i1, io1)
595 var io2 = Item.new(0, 'yy')
596 assert_notequal(i1, io2)
597 END
598
599 v9.CheckScriptSuccess(class_lines + test_lines)
Bram Moolenaar46ab9252023-01-03 14:01:21 +0000600 v9.CheckScriptSuccess(
601 class_lines + ['def Test()'] + test_lines + ['enddef', 'Test()'])
Bram Moolenaarbcf31ec2023-01-02 20:32:24 +0000602
603 for op in ['>', '>=', '<', '<=', '=~', '!~']
604 var op_lines = [
605 'var i1 = Item.new()',
606 'var i2 = Item.new()',
607 'echo i1 ' .. op .. ' i2',
608 ]
609 v9.CheckScriptFailure(class_lines + op_lines, 'E1153: Invalid operation for object')
Bram Moolenaar46ab9252023-01-03 14:01:21 +0000610 v9.CheckScriptFailure(class_lines
611 + ['def Test()'] + op_lines + ['enddef', 'Test()'], 'E1153: Invalid operation for object')
Bram Moolenaarbcf31ec2023-01-02 20:32:24 +0000612 endfor
613enddef
614
Bram Moolenaar6481acc2023-01-11 21:14:17 +0000615def Test_object_type()
616 var lines =<< trim END
617 vim9script
618
619 class One
620 this.one = 1
621 endclass
622 class Two
623 this.two = 2
624 endclass
625 class TwoMore extends Two
626 this.more = 9
627 endclass
628
629 var o: One = One.new()
630 var t: Two = Two.new()
631 var m: TwoMore = TwoMore.new()
632 var tm: Two = TwoMore.new()
633
634 t = m
635 END
636 v9.CheckScriptSuccess(lines)
637
638 lines =<< trim END
639 vim9script
640
641 class One
642 this.one = 1
643 endclass
644 class Two
645 this.two = 2
646 endclass
647
648 var o: One = Two.new()
649 END
650 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object<One> but got object<Two>')
Bram Moolenaara94bd9d2023-01-12 15:01:32 +0000651
652 lines =<< trim END
653 vim9script
654
655 interface One
656 def GetMember(): number
657 endinterface
658 class Two implements One
659 this.one = 1
660 def GetMember(): number
661 return this.one
662 enddef
663 endclass
664
665 var o: One = Two.new(5)
666 assert_equal(5, o.GetMember())
667 END
668 v9.CheckScriptSuccess(lines)
Bram Moolenaar450c7a92023-01-16 16:39:37 +0000669
670 lines =<< trim END
671 vim9script
672
673 class Num
674 this.n: number = 0
675 endclass
676
677 def Ref(name: string): func(Num): Num
678 return (arg: Num): Num => {
679 return eval(name)(arg)
680 }
681 enddef
682
683 const Fn = Ref('Double')
684 var Double = (m: Num): Num => Num.new(m.n * 2)
685
686 echo Fn(Num.new(4))
687 END
688 v9.CheckScriptSuccess(lines)
Bram Moolenaar6481acc2023-01-11 21:14:17 +0000689enddef
690
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000691def Test_class_member()
692 # check access rules
Bram Moolenaard505d172022-12-18 21:42:55 +0000693 var lines =<< trim END
694 vim9script
695 class TextPos
696 this.lnum = 1
697 this.col = 1
698 static counter = 0
Bram Moolenaar9f2d97e2022-12-31 19:01:02 +0000699 static _secret = 7
700 public static anybody = 42
Bram Moolenaard505d172022-12-18 21:42:55 +0000701
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000702 static def AddToCounter(nr: number)
Bram Moolenaard505d172022-12-18 21:42:55 +0000703 counter += nr
704 enddef
705 endclass
706
707 assert_equal(0, TextPos.counter)
708 TextPos.AddToCounter(3)
709 assert_equal(3, TextPos.counter)
Bram Moolenaarf54cedd2022-12-23 17:56:27 +0000710 assert_fails('echo TextPos.noSuchMember', 'E1338:')
Bram Moolenaar94722c52023-01-28 19:19:03 +0000711
Bram Moolenaar3259ff32023-01-04 18:54:09 +0000712 def GetCounter(): number
713 return TextPos.counter
714 enddef
715 assert_equal(3, GetCounter())
Bram Moolenaard505d172022-12-18 21:42:55 +0000716
Bram Moolenaarf54cedd2022-12-23 17:56:27 +0000717 assert_fails('TextPos.noSuchMember = 2', 'E1337:')
Bram Moolenaar9f2d97e2022-12-31 19:01:02 +0000718 assert_fails('TextPos.counter = 5', 'E1335:')
719 assert_fails('TextPos.counter += 5', 'E1335:')
720
721 assert_fails('echo TextPos._secret', 'E1333:')
722 assert_fails('TextPos._secret = 8', 'E1333:')
723
724 assert_equal(42, TextPos.anybody)
725 TextPos.anybody = 12
726 assert_equal(12, TextPos.anybody)
727 TextPos.anybody += 5
728 assert_equal(17, TextPos.anybody)
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000729 END
730 v9.CheckScriptSuccess(lines)
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000731
Bram Moolenaar4cae8452023-01-15 15:51:48 +0000732 # example in the help
733 lines =<< trim END
734 vim9script
735 class OtherThing
736 this.size: number
737 static totalSize: number
738
739 def new(this.size)
740 totalSize += this.size
741 enddef
742 endclass
743 assert_equal(0, OtherThing.totalSize)
744 var to3 = OtherThing.new(3)
745 assert_equal(3, OtherThing.totalSize)
746 var to7 = OtherThing.new(7)
747 assert_equal(10, OtherThing.totalSize)
748 END
749 v9.CheckScriptSuccess(lines)
750
Bram Moolenaar62a69232023-01-24 15:07:04 +0000751 # access private member in lambda
752 lines =<< trim END
753 vim9script
754
755 class Foo
756 this._x: number = 0
757
758 def Add(n: number): number
759 const F = (): number => this._x + n
760 return F()
761 enddef
762 endclass
763
764 var foo = Foo.new()
765 assert_equal(5, foo.Add(5))
766 END
767 v9.CheckScriptSuccess(lines)
768
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000769 # check shadowing
770 lines =<< trim END
771 vim9script
772
773 class Some
774 static count = 0
775 def Method(count: number)
776 echo count
777 enddef
778 endclass
779
780 var s = Some.new()
781 s.Method(7)
782 END
783 v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: count')
784
785 lines =<< trim END
786 vim9script
787
788 class Some
789 static count = 0
790 def Method(arg: number)
791 var count = 3
792 echo arg count
793 enddef
794 endclass
795
796 var s = Some.new()
797 s.Method(7)
798 END
799 v9.CheckScriptFailure(lines, 'E1341: Variable already declared in the class: count')
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000800enddef
801
Bram Moolenaarcf760d52023-01-05 13:16:04 +0000802func Test_class_garbagecollect()
803 let lines =<< trim END
804 vim9script
805
806 class Point
807 this.p = [2, 3]
808 static pl = ['a', 'b']
809 static pd = {a: 'a', b: 'b'}
810 endclass
811
812 echo Point.pl Point.pd
813 call test_garbagecollect_now()
814 echo Point.pl Point.pd
815 END
816 call v9.CheckScriptSuccess(lines)
817endfunc
818
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000819def Test_class_function()
820 var lines =<< trim END
821 vim9script
822 class Value
823 this.value = 0
824 static objects = 0
825
826 def new(v: number)
827 this.value = v
828 ++objects
829 enddef
830
831 static def GetCount(): number
832 return objects
833 enddef
834 endclass
835
836 assert_equal(0, Value.GetCount())
837 var v1 = Value.new(2)
838 assert_equal(1, Value.GetCount())
839 var v2 = Value.new(7)
840 assert_equal(2, Value.GetCount())
841 END
842 v9.CheckScriptSuccess(lines)
843enddef
844
Bram Moolenaar91c9d6d2022-12-14 17:30:37 +0000845def Test_class_object_to_string()
846 var lines =<< trim END
847 vim9script
848 class TextPosition
849 this.lnum = 1
850 this.col = 22
851 endclass
852
853 assert_equal("class TextPosition", string(TextPosition))
854
855 var pos = TextPosition.new()
856 assert_equal("object of TextPosition {lnum: 1, col: 22}", string(pos))
857 END
858 v9.CheckScriptSuccess(lines)
859enddef
Bram Moolenaar74e12742022-12-13 21:14:28 +0000860
Bram Moolenaar554d0312023-01-05 19:59:18 +0000861def Test_interface_basics()
862 var lines =<< trim END
863 vim9script
864 interface Something
865 this.value: string
866 static count: number
867 def GetCount(): number
868 endinterface
869 END
870 v9.CheckScriptSuccess(lines)
871
872 lines =<< trim END
873 interface SomethingWrong
874 static count = 7
875 endinterface
876 END
877 v9.CheckScriptFailure(lines, 'E1342:')
878
879 lines =<< trim END
880 vim9script
881
882 interface Some
883 static count: number
884 def Method(count: number)
885 endinterface
886 END
Bram Moolenaard40f00c2023-01-13 17:36:49 +0000887 v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: count')
888
889 lines =<< trim END
890 vim9script
891
892 interface Some
893 this.value: number
894 def Method(value: number)
895 endinterface
896 END
897 v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: value')
Bram Moolenaar554d0312023-01-05 19:59:18 +0000898
899 lines =<< trim END
900 vim9script
901 interface somethingWrong
902 static count = 7
903 endinterface
904 END
905 v9.CheckScriptFailure(lines, 'E1343: Interface name must start with an uppercase letter: somethingWrong')
906
907 lines =<< trim END
908 vim9script
909 interface SomethingWrong
910 this.value: string
911 static count = 7
912 def GetCount(): number
913 endinterface
914 END
915 v9.CheckScriptFailure(lines, 'E1344:')
916
917 lines =<< trim END
918 vim9script
919 interface SomethingWrong
920 this.value: string
921 static count: number
922 def GetCount(): number
923 return 5
924 enddef
925 endinterface
926 END
927 v9.CheckScriptFailure(lines, 'E1345: Not a valid command in an interface: return 5')
Bram Moolenaar53f54e42023-01-26 20:36:56 +0000928
929 lines =<< trim END
930 vim9script
931 export interface EnterExit
932 def Enter(): void
933 def Exit(): void
934 endinterface
935 END
936 writefile(lines, 'XdefIntf.vim', 'D')
937
938 lines =<< trim END
939 vim9script
940 import './XdefIntf.vim' as defIntf
941 export def With(ee: defIntf.EnterExit, F: func)
942 ee.Enter()
943 try
944 F()
945 finally
946 ee.Exit()
947 endtry
948 enddef
949 END
950 v9.CheckScriptSuccess(lines)
Bram Moolenaar657aea72023-01-27 13:16:19 +0000951
952 var imported =<< trim END
953 vim9script
954 export abstract class EnterExit
955 def Enter(): void
956 enddef
957 def Exit(): void
958 enddef
959 endclass
960 END
961 writefile(imported, 'XdefIntf2.vim', 'D')
962
963 lines[1] = " import './XdefIntf2.vim' as defIntf"
964 v9.CheckScriptSuccess(lines)
Bram Moolenaar554d0312023-01-05 19:59:18 +0000965enddef
966
Bram Moolenaar94674f22023-01-06 18:42:20 +0000967def Test_class_implements_interface()
968 var lines =<< trim END
969 vim9script
970
971 interface Some
972 static count: number
973 def Method(nr: number)
974 endinterface
975
976 class SomeImpl implements Some
977 static count: number
978 def Method(nr: number)
979 echo nr
980 enddef
981 endclass
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000982
983 interface Another
984 this.member: string
985 endinterface
986
987 class SomeImpl implements Some, Another
988 this.member = 'abc'
989 static count: number
990 def Method(nr: number)
991 echo nr
992 enddef
993 endclass
994
Bram Moolenaar94674f22023-01-06 18:42:20 +0000995 END
996 v9.CheckScriptSuccess(lines)
997
998 lines =<< trim END
999 vim9script
1000
1001 interface Some
1002 static counter: number
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001003 endinterface
1004
1005 class SomeImpl implements Some implements Some
1006 static count: number
1007 endclass
1008 END
1009 v9.CheckScriptFailure(lines, 'E1350:')
1010
1011 lines =<< trim END
1012 vim9script
1013
1014 interface Some
1015 static counter: number
1016 endinterface
1017
1018 class SomeImpl implements Some, Some
1019 static count: number
1020 endclass
1021 END
1022 v9.CheckScriptFailure(lines, 'E1351: Duplicate interface after "implements": Some')
1023
1024 lines =<< trim END
1025 vim9script
1026
1027 interface Some
1028 static counter: number
Bram Moolenaar94674f22023-01-06 18:42:20 +00001029 def Method(nr: number)
1030 endinterface
1031
1032 class SomeImpl implements Some
1033 static count: number
1034 def Method(nr: number)
1035 echo nr
1036 enddef
1037 endclass
1038 END
1039 v9.CheckScriptFailure(lines, 'E1348: Member "counter" of interface "Some" not implemented')
1040
1041 lines =<< trim END
1042 vim9script
1043
1044 interface Some
1045 static count: number
1046 def Methods(nr: number)
1047 endinterface
1048
1049 class SomeImpl implements Some
1050 static count: number
1051 def Method(nr: number)
1052 echo nr
1053 enddef
1054 endclass
1055 END
1056 v9.CheckScriptFailure(lines, 'E1349: Function "Methods" of interface "Some" not implemented')
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001057
1058 # Check different order of members in class and interface works.
1059 lines =<< trim END
1060 vim9script
1061
1062 interface Result
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001063 public this.label: string
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001064 this.errpos: number
1065 endinterface
1066
1067 # order of members is opposite of interface
1068 class Failure implements Result
1069 this.errpos: number = 42
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001070 public this.label: string = 'label'
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001071 endclass
1072
1073 def Test()
1074 var result: Result = Failure.new()
1075
1076 assert_equal('label', result.label)
1077 assert_equal(42, result.errpos)
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001078
1079 result.label = 'different'
1080 assert_equal('different', result.label)
1081 assert_equal(42, result.errpos)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001082 enddef
1083
1084 Test()
1085 END
1086 v9.CheckScriptSuccess(lines)
Bram Moolenaar94674f22023-01-06 18:42:20 +00001087enddef
1088
Bram Moolenaard0200c82023-01-28 15:19:40 +00001089def Test_call_interface_method()
1090 var lines =<< trim END
1091 vim9script
1092 interface Base
1093 def Enter(): void
1094 endinterface
1095
1096 class Child implements Base
1097 def Enter(): void
1098 g:result ..= 'child'
1099 enddef
1100 endclass
1101
1102 def F(obj: Base)
1103 obj.Enter()
1104 enddef
1105
1106 g:result = ''
1107 F(Child.new())
1108 assert_equal('child', g:result)
1109 unlet g:result
1110 END
1111 v9.CheckScriptSuccess(lines)
1112
1113 lines =<< trim END
1114 vim9script
1115 class Base
1116 def Enter(): void
1117 g:result ..= 'base'
1118 enddef
1119 endclass
1120
1121 class Child extends Base
1122 def Enter(): void
1123 g:result ..= 'child'
1124 enddef
1125 endclass
1126
1127 def F(obj: Base)
1128 obj.Enter()
1129 enddef
1130
1131 g:result = ''
1132 F(Child.new())
1133 assert_equal('child', g:result)
1134 unlet g:result
1135 END
1136 v9.CheckScriptSuccess(lines)
Bram Moolenaarb8bebd02023-01-30 20:24:23 +00001137
Bram Moolenaar7a1bdae2023-02-04 15:45:27 +00001138 # method of interface returns a value
1139 lines =<< trim END
1140 vim9script
1141 interface Base
1142 def Enter(): string
1143 endinterface
1144
1145 class Child implements Base
1146 def Enter(): string
1147 g:result ..= 'child'
1148 return "/resource"
1149 enddef
1150 endclass
1151
1152 def F(obj: Base)
1153 var r = obj.Enter()
1154 g:result ..= r
1155 enddef
1156
1157 g:result = ''
1158 F(Child.new())
1159 assert_equal('child/resource', g:result)
1160 unlet g:result
1161 END
1162 v9.CheckScriptSuccess(lines)
1163
1164 lines =<< trim END
1165 vim9script
1166 class Base
1167 def Enter(): string
1168 return null_string
1169 enddef
1170 endclass
1171
1172 class Child extends Base
1173 def Enter(): string
1174 g:result ..= 'child'
1175 return "/resource"
1176 enddef
1177 endclass
1178
1179 def F(obj: Base)
1180 var r = obj.Enter()
1181 g:result ..= r
1182 enddef
1183
1184 g:result = ''
1185 F(Child.new())
1186 assert_equal('child/resource', g:result)
1187 unlet g:result
1188 END
1189 v9.CheckScriptSuccess(lines)
1190
1191
Bram Moolenaarb8bebd02023-01-30 20:24:23 +00001192 # No class that implements the interface.
1193 lines =<< trim END
1194 vim9script
1195
1196 interface IWithEE
1197 def Enter(): any
1198 def Exit(): void
1199 endinterface
1200
1201 def With1(ee: IWithEE, F: func)
1202 var r = ee.Enter()
1203 enddef
1204
1205 defcompile
1206 END
1207 v9.CheckScriptSuccess(lines)
Bram Moolenaard0200c82023-01-28 15:19:40 +00001208enddef
1209
Bram Moolenaareca2c5f2023-01-07 12:08:41 +00001210def Test_class_used_as_type()
1211 var lines =<< trim END
1212 vim9script
1213
1214 class Point
1215 this.x = 0
1216 this.y = 0
1217 endclass
1218
1219 var p: Point
1220 p = Point.new(2, 33)
1221 assert_equal(2, p.x)
1222 assert_equal(33, p.y)
1223 END
1224 v9.CheckScriptSuccess(lines)
1225
1226 lines =<< trim END
1227 vim9script
1228
1229 interface HasX
1230 this.x: number
1231 endinterface
1232
1233 class Point implements HasX
1234 this.x = 0
1235 this.y = 0
1236 endclass
1237
1238 var p: Point
1239 p = Point.new(2, 33)
1240 var hx = p
1241 assert_equal(2, hx.x)
1242 END
1243 v9.CheckScriptSuccess(lines)
1244
1245 lines =<< trim END
1246 vim9script
1247
1248 class Point
1249 this.x = 0
1250 this.y = 0
1251 endclass
1252
1253 var p: Point
1254 p = 'text'
1255 END
Bram Moolenaar6481acc2023-01-11 21:14:17 +00001256 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object<Point> but got string')
Bram Moolenaareca2c5f2023-01-07 12:08:41 +00001257enddef
1258
Bram Moolenaar83677162023-01-08 19:54:10 +00001259def Test_class_extends()
1260 var lines =<< trim END
1261 vim9script
1262 class Base
1263 this.one = 1
1264 def GetOne(): number
1265 return this.one
1266 enddef
1267 endclass
1268 class Child extends Base
1269 this.two = 2
1270 def GetTotal(): number
1271 return this.one + this.two
1272 enddef
1273 endclass
1274 var o = Child.new()
1275 assert_equal(1, o.one)
1276 assert_equal(2, o.two)
1277 assert_equal(1, o.GetOne())
1278 assert_equal(3, o.GetTotal())
1279 END
1280 v9.CheckScriptSuccess(lines)
1281
1282 lines =<< trim END
1283 vim9script
1284 class Base
1285 this.one = 1
1286 endclass
1287 class Child extends Base
1288 this.two = 2
1289 endclass
1290 var o = Child.new(3, 44)
1291 assert_equal(3, o.one)
1292 assert_equal(44, o.two)
1293 END
1294 v9.CheckScriptSuccess(lines)
1295
1296 lines =<< trim END
1297 vim9script
1298 class Base
1299 this.one = 1
1300 endclass
1301 class Child extends Base extends Base
1302 this.two = 2
1303 endclass
1304 END
1305 v9.CheckScriptFailure(lines, 'E1352: Duplicate "extends"')
1306
1307 lines =<< trim END
1308 vim9script
1309 class Child extends BaseClass
1310 this.two = 2
1311 endclass
1312 END
1313 v9.CheckScriptFailure(lines, 'E1353: Class name not found: BaseClass')
1314
1315 lines =<< trim END
1316 vim9script
1317 var SomeVar = 99
1318 class Child extends SomeVar
1319 this.two = 2
1320 endclass
1321 END
1322 v9.CheckScriptFailure(lines, 'E1354: Cannot extend SomeVar')
Bram Moolenaar58b40092023-01-11 15:59:05 +00001323
1324 lines =<< trim END
1325 vim9script
1326 class Base
1327 this.name: string
1328 def ToString(): string
1329 return this.name
1330 enddef
1331 endclass
1332
1333 class Child extends Base
1334 this.age: number
1335 def ToString(): string
1336 return super.ToString() .. ': ' .. this.age
1337 enddef
1338 endclass
1339
1340 var o = Child.new('John', 42)
1341 assert_equal('John: 42', o.ToString())
1342 END
1343 v9.CheckScriptSuccess(lines)
Bram Moolenaar6aa09372023-01-11 17:59:38 +00001344
1345 lines =<< trim END
1346 vim9script
1347 class Child
1348 this.age: number
1349 def ToString(): number
1350 return this.age
1351 enddef
1352 def ToString(): string
1353 return this.age
1354 enddef
1355 endclass
1356 END
1357 v9.CheckScriptFailure(lines, 'E1355: Duplicate function: ToString')
1358
1359 lines =<< trim END
1360 vim9script
1361 class Child
1362 this.age: number
1363 def ToString(): string
1364 return super .ToString() .. ': ' .. this.age
1365 enddef
1366 endclass
1367 var o = Child.new(42)
1368 echo o.ToString()
1369 END
1370 v9.CheckScriptFailure(lines, 'E1356:')
1371
1372 lines =<< trim END
1373 vim9script
1374 class Base
1375 this.name: string
1376 def ToString(): string
1377 return this.name
1378 enddef
1379 endclass
1380
1381 var age = 42
1382 def ToString(): string
1383 return super.ToString() .. ': ' .. age
1384 enddef
1385 echo ToString()
1386 END
1387 v9.CheckScriptFailure(lines, 'E1357:')
1388
1389 lines =<< trim END
1390 vim9script
1391 class Child
1392 this.age: number
1393 def ToString(): string
1394 return super.ToString() .. ': ' .. this.age
1395 enddef
1396 endclass
1397 var o = Child.new(42)
1398 echo o.ToString()
1399 END
1400 v9.CheckScriptFailure(lines, 'E1358:')
Bram Moolenaar6481acc2023-01-11 21:14:17 +00001401
1402 lines =<< trim END
1403 vim9script
1404 class Base
1405 this.name: string
1406 static def ToString(): string
1407 return 'Base class'
1408 enddef
1409 endclass
1410
1411 class Child extends Base
1412 this.age: number
1413 def ToString(): string
1414 return Base.ToString() .. ': ' .. this.age
1415 enddef
1416 endclass
1417
1418 var o = Child.new('John', 42)
1419 assert_equal('Base class: 42', o.ToString())
1420 END
1421 v9.CheckScriptSuccess(lines)
Bram Moolenaar4cae8452023-01-15 15:51:48 +00001422
1423 lines =<< trim END
1424 vim9script
1425 class Base
1426 this.value = 1
1427 def new(init: number)
1428 this.value = number + 1
1429 enddef
1430 endclass
1431 class Child extends Base
1432 def new()
1433 this.new(3)
1434 enddef
1435 endclass
1436 var c = Child.new()
1437 END
1438 v9.CheckScriptFailure(lines, 'E1325: Method not found on class "Child": new(')
Bram Moolenaarae3205a2023-01-15 20:49:00 +00001439
1440 # base class with more than one object member
1441 lines =<< trim END
1442 vim9script
1443
1444 class Result
1445 this.success: bool
1446 this.value: any = null
1447 endclass
1448
1449 class Success extends Result
1450 def new(this.value = v:none)
1451 this.success = true
1452 enddef
1453 endclass
1454
1455 var v = Success.new('asdf')
1456 assert_equal("object of Success {success: true, value: 'asdf'}", string(v))
1457 END
1458 v9.CheckScriptSuccess(lines)
Bram Moolenaar83677162023-01-08 19:54:10 +00001459enddef
1460
Bram Moolenaar094cf9f2023-02-10 15:52:25 +00001461def Test_using_base_class()
1462 var lines =<< trim END
1463 vim9script
1464
1465 class BaseEE
1466 def Enter(): any
1467 return null
1468 enddef
1469 def Exit(resource: any): void
1470 enddef
1471 endclass
1472
1473 class ChildEE extends BaseEE
1474 def Enter(): any
1475 return 42
1476 enddef
1477
1478 def Exit(resource: number): void
1479 g:result ..= '/exit'
1480 enddef
1481 endclass
1482
1483 def With(ee: BaseEE)
1484 var r = ee.Enter()
1485 try
1486 g:result ..= r
1487 finally
1488 g:result ..= '/finally'
1489 ee.Exit(r)
1490 endtry
1491 enddef
1492
1493 g:result = ''
1494 With(ChildEE.new())
1495 assert_equal('42/finally/exit', g:result)
1496 END
1497 v9.CheckScriptSuccess(lines)
1498 unlet g:result
1499enddef
1500
1501
Bram Moolenaara86655a2023-01-12 17:06:27 +00001502def Test_class_import()
1503 var lines =<< trim END
1504 vim9script
1505 export class Animal
1506 this.kind: string
1507 this.name: string
1508 endclass
1509 END
1510 writefile(lines, 'Xanimal.vim', 'D')
1511
1512 lines =<< trim END
1513 vim9script
1514 import './Xanimal.vim' as animal
1515
1516 var a: animal.Animal
1517 a = animal.Animal.new('fish', 'Eric')
1518 assert_equal('fish', a.kind)
1519 assert_equal('Eric', a.name)
Bram Moolenaar40594002023-01-12 20:04:51 +00001520
1521 var b: animal.Animal = animal.Animal.new('cat', 'Garfield')
1522 assert_equal('cat', b.kind)
1523 assert_equal('Garfield', b.name)
Bram Moolenaara86655a2023-01-12 17:06:27 +00001524 END
1525 v9.CheckScriptSuccess(lines)
1526enddef
1527
Bram Moolenaar24a8d062023-01-14 13:12:06 +00001528def Test_abstract_class()
1529 var lines =<< trim END
1530 vim9script
1531 abstract class Base
1532 this.name: string
1533 endclass
1534 class Person extends Base
1535 this.age: number
1536 endclass
1537 var p: Base = Person.new('Peter', 42)
1538 assert_equal('Peter', p.name)
1539 assert_equal(42, p.age)
1540 END
1541 v9.CheckScriptSuccess(lines)
1542
1543 lines =<< trim END
1544 vim9script
1545 abstract class Base
1546 this.name: string
1547 endclass
1548 class Person extends Base
1549 this.age: number
1550 endclass
1551 var p = Base.new('Peter')
1552 END
1553 v9.CheckScriptFailure(lines, 'E1325: Method not found on class "Base": new(')
1554
1555 lines =<< trim END
1556 abstract class Base
1557 this.name: string
1558 endclass
1559 END
1560 v9.CheckScriptFailure(lines, 'E1316:')
1561enddef
1562
Bram Moolenaar486fc252023-01-18 14:51:07 +00001563def Test_closure_in_class()
1564 var lines =<< trim END
1565 vim9script
1566
1567 class Foo
1568 this.y: list<string> = ['B']
1569
1570 def new()
1571 g:result = filter(['A', 'B'], (_, v) => index(this.y, v) == -1)
1572 enddef
1573 endclass
1574
1575 Foo.new()
1576 assert_equal(['A'], g:result)
1577 END
1578 v9.CheckScriptSuccess(lines)
1579enddef
1580
Bram Moolenaar8dbab1d2023-01-27 20:14:02 +00001581def Test_defer_with_object()
1582 var lines =<< trim END
1583 vim9script
1584
1585 class CWithEE
1586 def Enter()
1587 g:result ..= "entered/"
1588 enddef
1589 def Exit()
1590 g:result ..= "exited"
1591 enddef
1592 endclass
1593
1594 def With(ee: CWithEE, F: func)
1595 ee.Enter()
1596 defer ee.Exit()
1597 F()
1598 enddef
1599
1600 g:result = ''
1601 var obj = CWithEE.new()
1602 obj->With(() => {
1603 g:result ..= "called/"
1604 })
1605 assert_equal('entered/called/exited', g:result)
1606 END
1607 v9.CheckScriptSuccess(lines)
1608 unlet g:result
Bram Moolenaar313e4722023-02-08 20:55:27 +00001609
1610 lines =<< trim END
1611 vim9script
1612
1613 class BaseWithEE
1614 def Enter()
1615 g:result ..= "entered-base/"
1616 enddef
1617 def Exit()
1618 g:result ..= "exited-base"
1619 enddef
1620 endclass
1621
1622 class CWithEE extends BaseWithEE
1623 def Enter()
1624 g:result ..= "entered-child/"
1625 enddef
1626 def Exit()
1627 g:result ..= "exited-child"
1628 enddef
1629 endclass
1630
1631 def With(ee: BaseWithEE, F: func)
1632 ee.Enter()
1633 defer ee.Exit()
1634 F()
1635 enddef
1636
1637 g:result = ''
1638 var obj = CWithEE.new()
1639 obj->With(() => {
1640 g:result ..= "called/"
1641 })
1642 assert_equal('entered-child/called/exited-child', g:result)
1643 END
1644 v9.CheckScriptSuccess(lines)
1645 unlet g:result
Bram Moolenaar8dbab1d2023-01-27 20:14:02 +00001646enddef
1647
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001648
1649" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker