blob: 684bf6d1f6901356e24858fa74d30585c36a0a6b [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
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200138 # Test for unsupported comment specifier
139 lines =<< trim END
140 vim9script
141 class Something
142 # comment
143 #{
144 endclass
145 END
146 v9.CheckScriptFailure(lines, 'E1170:')
147
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000148 lines =<< trim END
149 vim9script
150
151 class TextPosition
152 this.lnum: number
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000153 this.col: number
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000154
Bram Moolenaar418b5472022-12-20 13:38:22 +0000155 # make a nicely formatted string
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000156 def ToString(): string
157 return $'({this.lnum}, {this.col})'
158 enddef
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000159 endclass
160
Bram Moolenaard28d7b92022-12-08 20:42:00 +0000161 # use the automatically generated new() method
162 var pos = TextPosition.new(2, 12)
163 assert_equal(2, pos.lnum)
164 assert_equal(12, pos.col)
Bram Moolenaarffdaca92022-12-09 21:41:48 +0000165
166 # call an object method
167 assert_equal('(2, 12)', pos.ToString())
Bram Moolenaarc0c2c262023-01-12 21:08:53 +0000168
169 assert_equal(v:t_class, type(TextPosition))
170 assert_equal(v:t_object, type(pos))
171 assert_equal('class<TextPosition>', typename(TextPosition))
172 assert_equal('object<TextPosition>', typename(pos))
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000173 END
174 v9.CheckScriptSuccess(lines)
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200175
176 # When referencing object methods, space cannot be used after a "."
177 lines =<< trim END
178 vim9script
179 class A
180 def Foo(): number
181 return 10
182 enddef
183 endclass
184 var a = A.new()
185 var v = a. Foo()
186 END
187 v9.CheckScriptFailure(lines, 'E1202:')
188
189 # Using an object without specifying a method or a member variable
190 lines =<< trim END
191 vim9script
192 class A
193 def Foo(): number
194 return 10
195 enddef
196 endclass
197 var a = A.new()
198 var v = a.
199 END
200 v9.CheckScriptFailure(lines, 'E15:')
201
202 # Error when parsing the arguments of an object method.
203 lines =<< trim END
204 vim9script
205 class A
206 def Foo()
207 enddef
208 endclass
209 var a = A.new()
210 var v = a.Foo(,)
211 END
212 v9.CheckScriptFailure(lines, 'E15:')
Bram Moolenaar00b28d62022-12-08 15:32:33 +0000213enddef
214
Bram Moolenaar83ae6152023-02-25 19:59:31 +0000215def Test_class_defined_twice()
216 # class defined twice should fail
217 var lines =<< trim END
218 vim9script
219 class There
220 endclass
221 class There
222 endclass
223 END
224 v9.CheckScriptFailure(lines, 'E1041: Redefining script item: "There"')
225
226 # one class, reload same script twice is OK
227 lines =<< trim END
228 vim9script
229 class There
230 endclass
231 END
232 writefile(lines, 'XclassTwice.vim', 'D')
233 source XclassTwice.vim
234 source XclassTwice.vim
235enddef
236
Bram Moolenaarc4e1b862023-02-26 18:58:23 +0000237def Test_returning_null_object()
238 # this was causing an internal error
239 var lines =<< trim END
240 vim9script
241
242 class BufferList
243 def Current(): any
244 return null_object
245 enddef
246 endclass
247
248 var buffers = BufferList.new()
249 echo buffers.Current()
250 END
251 v9.CheckScriptSuccess(lines)
252enddef
253
Bram Moolenaard13dd302023-03-11 20:56:35 +0000254def Test_using_null_class()
255 var lines =<< trim END
256 @_ = null_class.member
257 END
258 v9.CheckDefExecAndScriptFailure(lines, ['E715:', 'E1363:'])
259enddef
260
Bram Moolenaar657aea72023-01-27 13:16:19 +0000261def Test_class_interface_wrong_end()
262 var lines =<< trim END
263 vim9script
264 abstract class SomeName
265 this.member = 'text'
266 endinterface
267 END
268 v9.CheckScriptFailure(lines, 'E476: Invalid command: endinterface, expected endclass')
269
270 lines =<< trim END
271 vim9script
272 export interface AnotherName
273 this.member: string
274 endclass
275 END
276 v9.CheckScriptFailure(lines, 'E476: Invalid command: endclass, expected endinterface')
277enddef
278
Bram Moolenaar552bdca2023-02-17 21:08:50 +0000279def Test_object_not_set()
280 var lines =<< trim END
281 vim9script
282
283 class State
284 this.value = 'xyz'
285 endclass
286
Bram Moolenaarf2017f22023-02-17 21:29:57 +0000287 var state: State
Bram Moolenaar552bdca2023-02-17 21:08:50 +0000288 var db = {'xyz': 789}
289 echo db[state.value]
290 END
291 v9.CheckScriptFailure(lines, 'E1360:')
Bram Moolenaar0917e862023-02-18 14:42:44 +0000292
293 lines =<< trim END
294 vim9script
295
Bram Moolenaarc3f971f2023-03-02 17:38:33 +0000296 class Class
297 this.id: string
298 def Method1()
299 echo 'Method1' .. this.id
300 enddef
301 endclass
302
303 var obj: Class
304 def Func()
305 obj.Method1()
306 enddef
307 Func()
308 END
309 v9.CheckScriptFailure(lines, 'E1360:')
310
311 lines =<< trim END
312 vim9script
313
Bram Moolenaar0917e862023-02-18 14:42:44 +0000314 class Background
315 this.background = 'dark'
316 endclass
317
318 class Colorscheme
319 this._bg: Background
320
321 def GetBackground(): string
322 return this._bg.background
323 enddef
324 endclass
325
326 var bg: Background # UNINITIALIZED
327 echo Colorscheme.new(bg).GetBackground()
328 END
329 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object<Background> but got object<Unknown>')
Ernie Raelf77a7f72023-03-03 15:05:30 +0000330
331 # TODO: this should not give an error but be handled at runtime
332 lines =<< trim END
333 vim9script
334
335 class Class
336 this.id: string
337 def Method1()
338 echo 'Method1' .. this.id
339 enddef
340 endclass
341
342 var obj = null_object
343 def Func()
344 obj.Method1()
345 enddef
346 Func()
347 END
348 v9.CheckScriptFailure(lines, 'E1363:')
Bram Moolenaar552bdca2023-02-17 21:08:50 +0000349enddef
350
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000351def Test_class_member_initializer()
352 var lines =<< trim END
353 vim9script
354
355 class TextPosition
356 this.lnum: number = 1
357 this.col: number = 1
358
Bram Moolenaar418b5472022-12-20 13:38:22 +0000359 # constructor with only the line number
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000360 def new(lnum: number)
361 this.lnum = lnum
362 enddef
363 endclass
364
365 var pos = TextPosition.new(3)
366 assert_equal(3, pos.lnum)
367 assert_equal(1, pos.col)
368
369 var instr = execute('disassemble TextPosition.new')
370 assert_match('new\_s*' ..
Bram Moolenaar3ea8a1b2022-12-10 19:03:51 +0000371 '0 NEW TextPosition size \d\+\_s*' ..
Bram Moolenaar7ce7daf2022-12-10 18:42:12 +0000372 '\d PUSHNR 1\_s*' ..
373 '\d STORE_THIS 0\_s*' ..
374 '\d PUSHNR 1\_s*' ..
375 '\d STORE_THIS 1\_s*' ..
376 'this.lnum = lnum\_s*' ..
377 '\d LOAD arg\[-1]\_s*' ..
378 '\d PUSHNR 0\_s*' ..
379 '\d LOAD $0\_s*' ..
380 '\d\+ STOREINDEX object\_s*' ..
381 '\d\+ RETURN object.*',
382 instr)
383 END
384 v9.CheckScriptSuccess(lines)
385enddef
386
Bram Moolenaar2c1c8032023-02-18 18:38:37 +0000387def Test_member_any_used_as_object()
388 var lines =<< trim END
389 vim9script
390
391 class Inner
392 this.value: number = 0
393 endclass
394
395 class Outer
396 this.inner: any
397 endclass
398
399 def F(outer: Outer)
400 outer.inner.value = 1
401 enddef
402
403 var inner_obj = Inner.new(0)
404 var outer_obj = Outer.new(inner_obj)
405 F(outer_obj)
406 assert_equal(1, inner_obj.value)
407 END
408 v9.CheckScriptSuccess(lines)
409
410 lines =<< trim END
411 vim9script
412
413 class Inner
414 this.value: number = 0
415 endclass
416
417 class Outer
418 this.inner: Inner
419 endclass
420
421 def F(outer: Outer)
422 outer.inner.value = 1
423 enddef
424
425 def Test_assign_to_nested_typed_member()
426 var inner = Inner.new(0)
427 var outer = Outer.new(inner)
428 F(outer)
429 assert_equal(1, inner.value)
430 enddef
431
432 Test_assign_to_nested_typed_member()
433 END
434 v9.CheckScriptSuccess(lines)
435enddef
436
Bram Moolenaar4cae8452023-01-15 15:51:48 +0000437def Test_assignment_with_operator()
438 var lines =<< trim END
439 vim9script
440
441 class Foo
442 this.x: number
443
444 def Add(n: number)
445 this.x += n
446 enddef
447 endclass
448
449 var f = Foo.new(3)
450 f.Add(17)
451 assert_equal(20, f.x)
Bram Moolenaar22363c62023-04-24 17:15:25 +0100452
453 def AddToFoo(obj: Foo)
454 obj.x += 3
455 enddef
456
457 AddToFoo(f)
458 assert_equal(23, f.x)
Bram Moolenaar4cae8452023-01-15 15:51:48 +0000459 END
460 v9.CheckScriptSuccess(lines)
461enddef
462
Bram Moolenaarf4508042023-01-15 16:54:57 +0000463def Test_list_of_objects()
464 var lines =<< trim END
465 vim9script
466
467 class Foo
468 def Add()
469 enddef
470 endclass
471
472 def ProcessList(fooList: list<Foo>)
473 for foo in fooList
474 foo.Add()
475 endfor
476 enddef
477
478 var l: list<Foo> = [Foo.new()]
479 ProcessList(l)
480 END
481 v9.CheckScriptSuccess(lines)
482enddef
483
Bram Moolenaar912bfee2023-01-15 20:18:55 +0000484def Test_expr_after_using_object()
485 var lines =<< trim END
486 vim9script
487
488 class Something
489 this.label: string = ''
490 endclass
491
492 def Foo(): Something
493 var v = Something.new()
494 echo 'in Foo(): ' .. typename(v)
495 return v
496 enddef
497
498 Foo()
499 END
500 v9.CheckScriptSuccess(lines)
501enddef
502
Bram Moolenaar65b0d162022-12-13 18:43:22 +0000503def Test_class_default_new()
504 var lines =<< trim END
505 vim9script
506
507 class TextPosition
508 this.lnum: number = 1
509 this.col: number = 1
510 endclass
511
512 var pos = TextPosition.new()
513 assert_equal(1, pos.lnum)
514 assert_equal(1, pos.col)
515
516 pos = TextPosition.new(v:none, v:none)
517 assert_equal(1, pos.lnum)
518 assert_equal(1, pos.col)
519
520 pos = TextPosition.new(3, 22)
521 assert_equal(3, pos.lnum)
522 assert_equal(22, pos.col)
523
524 pos = TextPosition.new(v:none, 33)
525 assert_equal(1, pos.lnum)
526 assert_equal(33, pos.col)
527 END
528 v9.CheckScriptSuccess(lines)
529
530 lines =<< trim END
531 vim9script
532 class Person
533 this.name: string
534 this.age: number = 42
535 this.education: string = "unknown"
536
537 def new(this.name, this.age = v:none, this.education = v:none)
538 enddef
539 endclass
540
541 var piet = Person.new("Piet")
542 assert_equal("Piet", piet.name)
543 assert_equal(42, piet.age)
544 assert_equal("unknown", piet.education)
545
546 var chris = Person.new("Chris", 4, "none")
547 assert_equal("Chris", chris.name)
548 assert_equal(4, chris.age)
549 assert_equal("none", chris.education)
550 END
551 v9.CheckScriptSuccess(lines)
Bram Moolenaar74e12742022-12-13 21:14:28 +0000552
553 lines =<< trim END
554 vim9script
555 class Person
556 this.name: string
557 this.age: number = 42
558 this.education: string = "unknown"
559
560 def new(this.name, this.age = v:none, this.education = v:none)
561 enddef
562 endclass
563
564 var missing = Person.new()
565 END
566 v9.CheckScriptFailure(lines, 'E119:')
Bram Moolenaar65b0d162022-12-13 18:43:22 +0000567enddef
568
h-east2261c892023-08-16 21:49:54 +0900569
570def Test_class_new_with_object_member()
571 var lines =<< trim END
572 vim9script
573
574 class C
575 this.str: string
576 this.num: number
577 def new(this.str, this.num)
578 enddef
579 def newVals(this.str, this.num)
580 enddef
581 endclass
582
583 def Check()
584 try
585 var c = C.new('cats', 2)
586 assert_equal('cats', c.str)
587 assert_equal(2, c.num)
588
589 c = C.newVals('dogs', 4)
590 assert_equal('dogs', c.str)
591 assert_equal(4, c.num)
592 catch
593 assert_report($'Unexpected exception was caught: {v:exception}')
594 endtry
595 enddef
596
597 Check()
598 END
599 v9.CheckScriptSuccess(lines)
600
601 lines =<< trim END
602 vim9script
603
604 class C
605 this.str: string
606 this.num: number
607 def new(this.str, this.num)
608 enddef
609 endclass
610
611 def Check()
612 try
613 var c = C.new(1, 2)
614 catch
615 assert_report($'Unexpected exception was caught: {v:exception}')
616 endtry
617 enddef
618
619 Check()
620 END
621 v9.CheckScriptFailure(lines, 'E1013:')
622
623 lines =<< trim END
624 vim9script
625
626 class C
627 this.str: string
628 this.num: number
629 def newVals(this.str, this.num)
630 enddef
631 endclass
632
633 def Check()
634 try
635 var c = C.newVals('dogs', 'apes')
636 catch
637 assert_report($'Unexpected exception was caught: {v:exception}')
638 endtry
639 enddef
640
641 Check()
642 END
643 v9.CheckScriptFailure(lines, 'E1013:')
644enddef
645
Bram Moolenaar74e12742022-12-13 21:14:28 +0000646def Test_class_object_member_inits()
647 var lines =<< trim END
648 vim9script
649 class TextPosition
650 this.lnum: number
651 this.col = 1
652 this.addcol: number = 2
653 endclass
654
655 var pos = TextPosition.new()
656 assert_equal(0, pos.lnum)
657 assert_equal(1, pos.col)
658 assert_equal(2, pos.addcol)
659 END
660 v9.CheckScriptSuccess(lines)
661
662 lines =<< trim END
663 vim9script
664 class TextPosition
665 this.lnum
666 this.col = 1
667 endclass
668 END
669 v9.CheckScriptFailure(lines, 'E1022:')
670
671 lines =<< trim END
672 vim9script
673 class TextPosition
674 this.lnum = v:none
675 this.col = 1
676 endclass
677 END
678 v9.CheckScriptFailure(lines, 'E1330:')
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200679
680 # Test for initializing an object member with an unknown variable/type
681 lines =<< trim END
682 vim9script
683 class A
684 this.value = init_val
685 endclass
686 END
687 v9.CheckScriptFailureList(lines, ['E121:', 'E1329:'])
Bram Moolenaar74e12742022-12-13 21:14:28 +0000688enddef
689
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000690def Test_class_object_member_access()
691 var lines =<< trim END
692 vim9script
693 class Triple
694 this._one = 1
695 this.two = 2
696 public this.three = 3
697
698 def GetOne(): number
699 return this._one
700 enddef
701 endclass
702
703 var trip = Triple.new()
704 assert_equal(1, trip.GetOne())
705 assert_equal(2, trip.two)
706 assert_equal(3, trip.three)
707 assert_fails('echo trip._one', 'E1333')
708
709 assert_fails('trip._one = 11', 'E1333')
710 assert_fails('trip.two = 22', 'E1335')
711 trip.three = 33
712 assert_equal(33, trip.three)
Bram Moolenaard505d172022-12-18 21:42:55 +0000713
714 assert_fails('trip.four = 4', 'E1334')
715 END
716 v9.CheckScriptSuccess(lines)
Bram Moolenaar590162c2022-12-24 21:24:06 +0000717
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200718 # Test for a public member variable name beginning with an underscore
719 lines =<< trim END
720 vim9script
721 class A
722 public this._val = 10
723 endclass
724 END
725 v9.CheckScriptFailure(lines, 'E1332:')
726
Bram Moolenaar590162c2022-12-24 21:24:06 +0000727 lines =<< trim END
728 vim9script
729
730 class MyCar
731 this.make: string
Bram Moolenaar574950d2023-01-03 19:08:50 +0000732 this.age = 5
Bram Moolenaar590162c2022-12-24 21:24:06 +0000733
734 def new(make_arg: string)
735 this.make = make_arg
736 enddef
737
738 def GetMake(): string
739 return $"make = {this.make}"
740 enddef
Bram Moolenaar574950d2023-01-03 19:08:50 +0000741 def GetAge(): number
742 return this.age
743 enddef
Bram Moolenaar590162c2022-12-24 21:24:06 +0000744 endclass
745
746 var c = MyCar.new("abc")
747 assert_equal('make = abc', c.GetMake())
748
749 c = MyCar.new("def")
750 assert_equal('make = def', c.GetMake())
751
752 var c2 = MyCar.new("123")
753 assert_equal('make = 123', c2.GetMake())
Bram Moolenaar574950d2023-01-03 19:08:50 +0000754
755 def CheckCar()
756 assert_equal("make = def", c.GetMake())
757 assert_equal(5, c.GetAge())
758 enddef
759 CheckCar()
Bram Moolenaar590162c2022-12-24 21:24:06 +0000760 END
761 v9.CheckScriptSuccess(lines)
Bram Moolenaar6ef54712022-12-25 19:31:36 +0000762
763 lines =<< trim END
764 vim9script
765
766 class MyCar
767 this.make: string
768
769 def new(make_arg: string)
770 this.make = make_arg
771 enddef
772 endclass
773
774 var c = MyCar.new("abc")
775 var c = MyCar.new("def")
776 END
777 v9.CheckScriptFailure(lines, 'E1041:')
Bram Moolenaarb149d222023-01-24 13:03:37 +0000778
779 lines =<< trim END
780 vim9script
781
782 class Foo
783 this.x: list<number> = []
784
785 def Add(n: number): any
786 this.x->add(n)
787 return this
788 enddef
789 endclass
790
791 echo Foo.new().Add(1).Add(2).x
792 echo Foo.new().Add(1).Add(2)
793 .x
794 echo Foo.new().Add(1)
795 .Add(2).x
796 echo Foo.new()
797 .Add(1).Add(2).x
798 echo Foo.new()
799 .Add(1)
800 .Add(2)
801 .x
802 END
803 v9.CheckScriptSuccess(lines)
Yegappan Lakshmananb1027282023-08-19 11:26:42 +0200804
805 # Test for "public" cannot be abbreviated
806 lines =<< trim END
807 vim9script
808 class Something
809 pub this.val = 1
810 endclass
811 END
812 v9.CheckScriptFailure(lines, 'E1065:')
813
814 # Test for "public" keyword must be followed by "this" or "static".
815 lines =<< trim END
816 vim9script
817 class Something
818 public val = 1
819 endclass
820 END
821 v9.CheckScriptFailure(lines, 'E1331:')
822
823 # Test for "static" cannot be abbreviated
824 lines =<< trim END
825 vim9script
826 class Something
827 stat this.val = 1
828 endclass
829 END
830 v9.CheckScriptFailure(lines, 'E1065:')
Bram Moolenaard505d172022-12-18 21:42:55 +0000831enddef
832
Bram Moolenaarbcf31ec2023-01-02 20:32:24 +0000833def Test_class_object_compare()
834 var class_lines =<< trim END
835 vim9script
836 class Item
837 this.nr = 0
838 this.name = 'xx'
839 endclass
840 END
841
842 # used at the script level and in a compiled function
843 var test_lines =<< trim END
844 var i1 = Item.new()
845 assert_equal(i1, i1)
846 assert_true(i1 is i1)
847 var i2 = Item.new()
848 assert_equal(i1, i2)
849 assert_false(i1 is i2)
850 var i3 = Item.new(0, 'xx')
851 assert_equal(i1, i3)
852
853 var io1 = Item.new(1, 'xx')
854 assert_notequal(i1, io1)
855 var io2 = Item.new(0, 'yy')
856 assert_notequal(i1, io2)
857 END
858
859 v9.CheckScriptSuccess(class_lines + test_lines)
Bram Moolenaar46ab9252023-01-03 14:01:21 +0000860 v9.CheckScriptSuccess(
861 class_lines + ['def Test()'] + test_lines + ['enddef', 'Test()'])
Bram Moolenaarbcf31ec2023-01-02 20:32:24 +0000862
863 for op in ['>', '>=', '<', '<=', '=~', '!~']
864 var op_lines = [
865 'var i1 = Item.new()',
866 'var i2 = Item.new()',
867 'echo i1 ' .. op .. ' i2',
868 ]
869 v9.CheckScriptFailure(class_lines + op_lines, 'E1153: Invalid operation for object')
Bram Moolenaar46ab9252023-01-03 14:01:21 +0000870 v9.CheckScriptFailure(class_lines
871 + ['def Test()'] + op_lines + ['enddef', 'Test()'], 'E1153: Invalid operation for object')
Bram Moolenaarbcf31ec2023-01-02 20:32:24 +0000872 endfor
873enddef
874
Bram Moolenaar6481acc2023-01-11 21:14:17 +0000875def Test_object_type()
876 var lines =<< trim END
877 vim9script
878
879 class One
880 this.one = 1
881 endclass
882 class Two
883 this.two = 2
884 endclass
885 class TwoMore extends Two
886 this.more = 9
887 endclass
888
889 var o: One = One.new()
890 var t: Two = Two.new()
891 var m: TwoMore = TwoMore.new()
892 var tm: Two = TwoMore.new()
893
894 t = m
895 END
896 v9.CheckScriptSuccess(lines)
897
898 lines =<< trim END
899 vim9script
900
901 class One
902 this.one = 1
903 endclass
904 class Two
905 this.two = 2
906 endclass
907
908 var o: One = Two.new()
909 END
910 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object<One> but got object<Two>')
Bram Moolenaara94bd9d2023-01-12 15:01:32 +0000911
912 lines =<< trim END
913 vim9script
914
915 interface One
916 def GetMember(): number
917 endinterface
918 class Two implements One
919 this.one = 1
920 def GetMember(): number
921 return this.one
922 enddef
923 endclass
924
925 var o: One = Two.new(5)
926 assert_equal(5, o.GetMember())
927 END
928 v9.CheckScriptSuccess(lines)
Bram Moolenaar450c7a92023-01-16 16:39:37 +0000929
930 lines =<< trim END
931 vim9script
932
933 class Num
934 this.n: number = 0
935 endclass
936
937 def Ref(name: string): func(Num): Num
938 return (arg: Num): Num => {
939 return eval(name)(arg)
940 }
941 enddef
942
943 const Fn = Ref('Double')
944 var Double = (m: Num): Num => Num.new(m.n * 2)
945
946 echo Fn(Num.new(4))
947 END
948 v9.CheckScriptSuccess(lines)
Bram Moolenaar6481acc2023-01-11 21:14:17 +0000949enddef
950
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000951def Test_class_member()
952 # check access rules
Bram Moolenaard505d172022-12-18 21:42:55 +0000953 var lines =<< trim END
954 vim9script
955 class TextPos
956 this.lnum = 1
957 this.col = 1
958 static counter = 0
Bram Moolenaar9f2d97e2022-12-31 19:01:02 +0000959 static _secret = 7
960 public static anybody = 42
Bram Moolenaard505d172022-12-18 21:42:55 +0000961
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000962 static def AddToCounter(nr: number)
Bram Moolenaard505d172022-12-18 21:42:55 +0000963 counter += nr
964 enddef
965 endclass
966
967 assert_equal(0, TextPos.counter)
968 TextPos.AddToCounter(3)
969 assert_equal(3, TextPos.counter)
Bram Moolenaarf54cedd2022-12-23 17:56:27 +0000970 assert_fails('echo TextPos.noSuchMember', 'E1338:')
Bram Moolenaar94722c52023-01-28 19:19:03 +0000971
Bram Moolenaar3259ff32023-01-04 18:54:09 +0000972 def GetCounter(): number
973 return TextPos.counter
974 enddef
975 assert_equal(3, GetCounter())
Bram Moolenaard505d172022-12-18 21:42:55 +0000976
Bram Moolenaarf54cedd2022-12-23 17:56:27 +0000977 assert_fails('TextPos.noSuchMember = 2', 'E1337:')
Bram Moolenaar9f2d97e2022-12-31 19:01:02 +0000978 assert_fails('TextPos.counter = 5', 'E1335:')
979 assert_fails('TextPos.counter += 5', 'E1335:')
980
981 assert_fails('echo TextPos._secret', 'E1333:')
982 assert_fails('TextPos._secret = 8', 'E1333:')
983
984 assert_equal(42, TextPos.anybody)
985 TextPos.anybody = 12
986 assert_equal(12, TextPos.anybody)
987 TextPos.anybody += 5
988 assert_equal(17, TextPos.anybody)
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000989 END
990 v9.CheckScriptSuccess(lines)
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000991
Bram Moolenaar4cae8452023-01-15 15:51:48 +0000992 # example in the help
993 lines =<< trim END
994 vim9script
995 class OtherThing
996 this.size: number
997 static totalSize: number
998
999 def new(this.size)
1000 totalSize += this.size
1001 enddef
1002 endclass
1003 assert_equal(0, OtherThing.totalSize)
1004 var to3 = OtherThing.new(3)
1005 assert_equal(3, OtherThing.totalSize)
1006 var to7 = OtherThing.new(7)
1007 assert_equal(10, OtherThing.totalSize)
1008 END
1009 v9.CheckScriptSuccess(lines)
1010
Bram Moolenaar4e2406c2023-06-24 19:22:21 +01001011 # using static class member twice
1012 lines =<< trim END
1013 vim9script
1014
1015 class HTML
1016 static author: string = 'John Doe'
1017
1018 static def MacroSubstitute(s: string): string
1019 return substitute(s, '{{author}}', author, 'gi')
1020 enddef
1021 endclass
1022
1023 assert_equal('some text', HTML.MacroSubstitute('some text'))
1024 assert_equal('some text', HTML.MacroSubstitute('some text'))
1025 END
1026 v9.CheckScriptSuccess(lines)
1027
Bram Moolenaar62a69232023-01-24 15:07:04 +00001028 # access private member in lambda
1029 lines =<< trim END
1030 vim9script
1031
1032 class Foo
1033 this._x: number = 0
1034
1035 def Add(n: number): number
1036 const F = (): number => this._x + n
1037 return F()
1038 enddef
1039 endclass
1040
1041 var foo = Foo.new()
1042 assert_equal(5, foo.Add(5))
1043 END
1044 v9.CheckScriptSuccess(lines)
1045
h-east2bd6a092023-05-19 19:01:17 +01001046 # access private member in lambda body
1047 lines =<< trim END
1048 vim9script
1049
1050 class Foo
1051 this._x: number = 6
1052
1053 def Add(n: number): number
1054 var Lam = () => {
1055 this._x = this._x + n
1056 }
1057 Lam()
1058 return this._x
1059 enddef
1060 endclass
1061
1062 var foo = Foo.new()
1063 assert_equal(13, foo.Add(7))
1064 END
1065 v9.CheckScriptSuccess(lines)
1066
Bram Moolenaar6acf7572023-01-01 19:53:30 +00001067 # check shadowing
1068 lines =<< trim END
1069 vim9script
1070
1071 class Some
1072 static count = 0
1073 def Method(count: number)
1074 echo count
1075 enddef
1076 endclass
1077
1078 var s = Some.new()
1079 s.Method(7)
1080 END
1081 v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: count')
1082
1083 lines =<< trim END
1084 vim9script
1085
1086 class Some
1087 static count = 0
1088 def Method(arg: number)
1089 var count = 3
1090 echo arg count
1091 enddef
1092 endclass
1093
1094 var s = Some.new()
1095 s.Method(7)
1096 END
1097 v9.CheckScriptFailure(lines, 'E1341: Variable already declared in the class: count')
Yegappan Lakshmananb1027282023-08-19 11:26:42 +02001098
1099 # Test for using an invalid type for a member variable
1100 lines =<< trim END
1101 vim9script
1102 class A
1103 this.val: xxx
1104 endclass
1105 END
1106 v9.CheckScriptFailure(lines, 'E1010:')
1107
1108 # Test for no space before or after the '=' when initializing a member
1109 # variable
1110 lines =<< trim END
1111 vim9script
1112 class A
1113 this.val: number= 10
1114 endclass
1115 END
1116 v9.CheckScriptFailure(lines, 'E1004:')
1117 lines =<< trim END
1118 vim9script
1119 class A
1120 this.val: number =10
1121 endclass
1122 END
1123 v9.CheckScriptFailure(lines, 'E1004:')
1124
1125 # Access a non-existing member
1126 lines =<< trim END
1127 vim9script
1128 class A
1129 endclass
1130 var a = A.new()
1131 var v = a.bar
1132 END
1133 v9.CheckScriptFailure(lines, 'E1326:')
Bram Moolenaar3d473ee2022-12-14 20:59:32 +00001134enddef
1135
Bram Moolenaarcf760d52023-01-05 13:16:04 +00001136func Test_class_garbagecollect()
1137 let lines =<< trim END
1138 vim9script
1139
1140 class Point
1141 this.p = [2, 3]
1142 static pl = ['a', 'b']
1143 static pd = {a: 'a', b: 'b'}
1144 endclass
1145
1146 echo Point.pl Point.pd
1147 call test_garbagecollect_now()
1148 echo Point.pl Point.pd
1149 END
1150 call v9.CheckScriptSuccess(lines)
Bram Moolenaarf7ca56f2023-06-05 16:53:25 +01001151
1152 let lines =<< trim END
1153 vim9script
1154
1155 interface View
1156 endinterface
1157
1158 class Widget
1159 this.view: View
1160 endclass
1161
1162 class MyView implements View
1163 this.widget: Widget
1164
1165 def new()
1166 # this will result in a circular reference to this object
1167 this.widget = Widget.new(this)
1168 enddef
1169 endclass
1170
1171 var view = MyView.new()
1172
1173 # overwrite "view", will be garbage-collected next
1174 view = MyView.new()
1175 test_garbagecollect_now()
1176 END
1177 call v9.CheckScriptSuccess(lines)
Bram Moolenaarcf760d52023-01-05 13:16:04 +00001178endfunc
1179
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001180def Test_class_function()
1181 var lines =<< trim END
1182 vim9script
1183 class Value
1184 this.value = 0
1185 static objects = 0
1186
1187 def new(v: number)
1188 this.value = v
1189 ++objects
1190 enddef
1191
1192 static def GetCount(): number
1193 return objects
1194 enddef
1195 endclass
1196
1197 assert_equal(0, Value.GetCount())
1198 var v1 = Value.new(2)
1199 assert_equal(1, Value.GetCount())
1200 var v2 = Value.new(7)
1201 assert_equal(2, Value.GetCount())
1202 END
1203 v9.CheckScriptSuccess(lines)
Yegappan Lakshmananb1027282023-08-19 11:26:42 +02001204
1205 # Test for cleaning up after a class definition failure when using class
1206 # functions.
1207 lines =<< trim END
1208 vim9script
1209 class A
1210 static def Foo()
1211 enddef
1212 aaa
1213 endclass
1214 END
1215 v9.CheckScriptFailure(lines, 'E1318:')
Bram Moolenaar6bafdd42023-01-01 12:58:33 +00001216enddef
1217
Bram Moolenaar99a7c0d2023-02-21 19:55:14 +00001218def Test_class_defcompile()
1219 var lines =<< trim END
1220 vim9script
1221
1222 class C
1223 def Fo(i: number): string
1224 return i
1225 enddef
1226 endclass
1227
1228 defcompile C.Fo
1229 END
1230 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number')
1231
1232 lines =<< trim END
1233 vim9script
1234
1235 class C
1236 static def Fc(): number
1237 return 'x'
1238 enddef
1239 endclass
1240
1241 defcompile C.Fc
1242 END
1243 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected number but got string')
Yegappan Lakshmananb1027282023-08-19 11:26:42 +02001244
1245 # Trying to compile a function using a non-existing class variable
1246 lines =<< trim END
1247 vim9script
1248 defcompile x.Foo()
1249 END
1250 v9.CheckScriptFailure(lines, 'E475:')
1251
1252 # Trying to compile a function using a variable which is not a class
1253 lines =<< trim END
1254 vim9script
1255 var x: number
1256 defcompile x.Foo()
1257 END
1258 v9.CheckScriptFailure(lines, 'E475:')
1259
1260 # Trying to compile a function without specifying the name
1261 lines =<< trim END
1262 vim9script
1263 class A
1264 endclass
1265 defcompile A.
1266 END
1267 v9.CheckScriptFailure(lines, 'E475:')
1268
1269 # Trying to compile a non-existing class object member function
1270 lines =<< trim END
1271 vim9script
1272 class A
1273 endclass
1274 var a = A.new()
1275 defcompile a.Foo()
1276 END
1277 v9.CheckScriptFailureList(lines, ['E1334:', 'E475:'])
Bram Moolenaar99a7c0d2023-02-21 19:55:14 +00001278enddef
1279
Bram Moolenaar91c9d6d2022-12-14 17:30:37 +00001280def Test_class_object_to_string()
1281 var lines =<< trim END
1282 vim9script
1283 class TextPosition
1284 this.lnum = 1
1285 this.col = 22
1286 endclass
1287
1288 assert_equal("class TextPosition", string(TextPosition))
1289
1290 var pos = TextPosition.new()
1291 assert_equal("object of TextPosition {lnum: 1, col: 22}", string(pos))
1292 END
1293 v9.CheckScriptSuccess(lines)
1294enddef
Bram Moolenaar74e12742022-12-13 21:14:28 +00001295
Bram Moolenaar554d0312023-01-05 19:59:18 +00001296def Test_interface_basics()
1297 var lines =<< trim END
1298 vim9script
1299 interface Something
1300 this.value: string
1301 static count: number
1302 def GetCount(): number
1303 endinterface
1304 END
1305 v9.CheckScriptSuccess(lines)
1306
1307 lines =<< trim END
1308 interface SomethingWrong
1309 static count = 7
1310 endinterface
1311 END
1312 v9.CheckScriptFailure(lines, 'E1342:')
1313
1314 lines =<< trim END
1315 vim9script
1316
1317 interface Some
1318 static count: number
1319 def Method(count: number)
1320 endinterface
1321 END
h-east61378a12023-04-18 19:07:29 +01001322 v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: count', 5)
Bram Moolenaard40f00c2023-01-13 17:36:49 +00001323
1324 lines =<< trim END
1325 vim9script
1326
1327 interface Some
1328 this.value: number
1329 def Method(value: number)
1330 endinterface
1331 END
h-east61378a12023-04-18 19:07:29 +01001332 # The argument name and the object member name are the same, but this is not a
1333 # problem because object members are always accessed with the "this." prefix.
1334 v9.CheckScriptSuccess(lines)
Bram Moolenaar554d0312023-01-05 19:59:18 +00001335
1336 lines =<< trim END
1337 vim9script
1338 interface somethingWrong
1339 static count = 7
1340 endinterface
1341 END
1342 v9.CheckScriptFailure(lines, 'E1343: Interface name must start with an uppercase letter: somethingWrong')
1343
1344 lines =<< trim END
1345 vim9script
1346 interface SomethingWrong
1347 this.value: string
1348 static count = 7
1349 def GetCount(): number
1350 endinterface
1351 END
1352 v9.CheckScriptFailure(lines, 'E1344:')
1353
1354 lines =<< trim END
1355 vim9script
1356 interface SomethingWrong
1357 this.value: string
1358 static count: number
1359 def GetCount(): number
1360 return 5
1361 enddef
1362 endinterface
1363 END
1364 v9.CheckScriptFailure(lines, 'E1345: Not a valid command in an interface: return 5')
Bram Moolenaar53f54e42023-01-26 20:36:56 +00001365
1366 lines =<< trim END
1367 vim9script
1368 export interface EnterExit
1369 def Enter(): void
1370 def Exit(): void
1371 endinterface
1372 END
1373 writefile(lines, 'XdefIntf.vim', 'D')
1374
1375 lines =<< trim END
1376 vim9script
1377 import './XdefIntf.vim' as defIntf
1378 export def With(ee: defIntf.EnterExit, F: func)
1379 ee.Enter()
1380 try
1381 F()
1382 finally
1383 ee.Exit()
1384 endtry
1385 enddef
1386 END
1387 v9.CheckScriptSuccess(lines)
Bram Moolenaar657aea72023-01-27 13:16:19 +00001388
1389 var imported =<< trim END
1390 vim9script
1391 export abstract class EnterExit
1392 def Enter(): void
1393 enddef
1394 def Exit(): void
1395 enddef
1396 endclass
1397 END
1398 writefile(imported, 'XdefIntf2.vim', 'D')
1399
1400 lines[1] = " import './XdefIntf2.vim' as defIntf"
1401 v9.CheckScriptSuccess(lines)
Bram Moolenaar554d0312023-01-05 19:59:18 +00001402enddef
1403
Bram Moolenaar94674f22023-01-06 18:42:20 +00001404def Test_class_implements_interface()
1405 var lines =<< trim END
1406 vim9script
1407
1408 interface Some
1409 static count: number
1410 def Method(nr: number)
1411 endinterface
1412
1413 class SomeImpl implements Some
1414 static count: number
1415 def Method(nr: number)
1416 echo nr
1417 enddef
1418 endclass
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001419
1420 interface Another
1421 this.member: string
1422 endinterface
1423
Bram Moolenaar83ae6152023-02-25 19:59:31 +00001424 class AnotherImpl implements Some, Another
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001425 this.member = 'abc'
1426 static count: number
1427 def Method(nr: number)
1428 echo nr
1429 enddef
1430 endclass
Bram Moolenaar94674f22023-01-06 18:42:20 +00001431 END
1432 v9.CheckScriptSuccess(lines)
1433
1434 lines =<< trim END
1435 vim9script
1436
1437 interface Some
1438 static counter: number
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001439 endinterface
1440
1441 class SomeImpl implements Some implements Some
1442 static count: number
1443 endclass
1444 END
1445 v9.CheckScriptFailure(lines, 'E1350:')
1446
1447 lines =<< trim END
1448 vim9script
1449
1450 interface Some
1451 static counter: number
1452 endinterface
1453
1454 class SomeImpl implements Some, Some
1455 static count: number
1456 endclass
1457 END
1458 v9.CheckScriptFailure(lines, 'E1351: Duplicate interface after "implements": Some')
1459
1460 lines =<< trim END
1461 vim9script
1462
1463 interface Some
1464 static counter: number
Bram Moolenaar94674f22023-01-06 18:42:20 +00001465 def Method(nr: number)
1466 endinterface
1467
1468 class SomeImpl implements Some
1469 static count: number
1470 def Method(nr: number)
1471 echo nr
1472 enddef
1473 endclass
1474 END
1475 v9.CheckScriptFailure(lines, 'E1348: Member "counter" of interface "Some" not implemented')
1476
1477 lines =<< trim END
1478 vim9script
1479
1480 interface Some
1481 static count: number
1482 def Methods(nr: number)
1483 endinterface
1484
1485 class SomeImpl implements Some
1486 static count: number
1487 def Method(nr: number)
1488 echo nr
1489 enddef
1490 endclass
1491 END
1492 v9.CheckScriptFailure(lines, 'E1349: Function "Methods" of interface "Some" not implemented')
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001493
1494 # Check different order of members in class and interface works.
1495 lines =<< trim END
1496 vim9script
1497
1498 interface Result
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001499 public this.label: string
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001500 this.errpos: number
1501 endinterface
1502
1503 # order of members is opposite of interface
1504 class Failure implements Result
1505 this.errpos: number = 42
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001506 public this.label: string = 'label'
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001507 endclass
1508
1509 def Test()
1510 var result: Result = Failure.new()
1511
1512 assert_equal('label', result.label)
1513 assert_equal(42, result.errpos)
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001514
1515 result.label = 'different'
1516 assert_equal('different', result.label)
1517 assert_equal(42, result.errpos)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001518 enddef
1519
1520 Test()
1521 END
1522 v9.CheckScriptSuccess(lines)
Yegappan Lakshmananb1027282023-08-19 11:26:42 +02001523
1524 # Interface name after "extends" doesn't end in a space or NUL character
1525 lines =<< trim END
1526 vim9script
1527 interface A
1528 endinterface
1529 class B extends A"
1530 endclass
1531 END
1532 v9.CheckScriptFailure(lines, 'E1315:')
1533
1534 # Trailing characters after a class name
1535 lines =<< trim END
1536 vim9script
1537 class A bbb
1538 endclass
1539 END
1540 v9.CheckScriptFailure(lines, 'E488:')
1541
1542 # using "implements" with a non-existing class
1543 lines =<< trim END
1544 vim9script
1545 class A implements B
1546 endclass
1547 END
1548 v9.CheckScriptFailure(lines, 'E1346:')
1549
1550 # using "implements" with a regular class
1551 lines =<< trim END
1552 vim9script
1553 class A
1554 endclass
1555 class B implements A
1556 endclass
1557 END
1558 v9.CheckScriptFailure(lines, 'E1347:')
1559
1560 # using "implements" with a variable
1561 lines =<< trim END
1562 vim9script
1563 var T: number = 10
1564 class A implements T
1565 endclass
1566 END
1567 v9.CheckScriptFailure(lines, 'E1347:')
1568
1569 # all the class methods in an "interface" should be implemented
1570 lines =<< trim END
1571 vim9script
1572 interface A
1573 static def Foo()
1574 endinterface
1575 class B implements A
1576 endclass
1577 END
1578 v9.CheckScriptFailure(lines, 'E1349:')
Bram Moolenaar94674f22023-01-06 18:42:20 +00001579enddef
1580
Bram Moolenaard0200c82023-01-28 15:19:40 +00001581def Test_call_interface_method()
1582 var lines =<< trim END
1583 vim9script
1584 interface Base
1585 def Enter(): void
1586 endinterface
1587
1588 class Child implements Base
1589 def Enter(): void
1590 g:result ..= 'child'
1591 enddef
1592 endclass
1593
1594 def F(obj: Base)
1595 obj.Enter()
1596 enddef
1597
1598 g:result = ''
1599 F(Child.new())
1600 assert_equal('child', g:result)
1601 unlet g:result
1602 END
1603 v9.CheckScriptSuccess(lines)
1604
1605 lines =<< trim END
1606 vim9script
1607 class Base
1608 def Enter(): void
1609 g:result ..= 'base'
1610 enddef
1611 endclass
1612
1613 class Child extends Base
1614 def Enter(): void
1615 g:result ..= 'child'
1616 enddef
1617 endclass
1618
1619 def F(obj: Base)
1620 obj.Enter()
1621 enddef
1622
1623 g:result = ''
1624 F(Child.new())
1625 assert_equal('child', g:result)
1626 unlet g:result
1627 END
1628 v9.CheckScriptSuccess(lines)
Bram Moolenaarb8bebd02023-01-30 20:24:23 +00001629
Bram Moolenaar7a1bdae2023-02-04 15:45:27 +00001630 # method of interface returns a value
1631 lines =<< trim END
1632 vim9script
1633 interface Base
1634 def Enter(): string
1635 endinterface
1636
1637 class Child implements Base
1638 def Enter(): string
1639 g:result ..= 'child'
1640 return "/resource"
1641 enddef
1642 endclass
1643
1644 def F(obj: Base)
1645 var r = obj.Enter()
1646 g:result ..= r
1647 enddef
1648
1649 g:result = ''
1650 F(Child.new())
1651 assert_equal('child/resource', g:result)
1652 unlet g:result
1653 END
1654 v9.CheckScriptSuccess(lines)
1655
1656 lines =<< trim END
1657 vim9script
1658 class Base
1659 def Enter(): string
1660 return null_string
1661 enddef
1662 endclass
1663
1664 class Child extends Base
1665 def Enter(): string
1666 g:result ..= 'child'
1667 return "/resource"
1668 enddef
1669 endclass
1670
1671 def F(obj: Base)
1672 var r = obj.Enter()
1673 g:result ..= r
1674 enddef
1675
1676 g:result = ''
1677 F(Child.new())
1678 assert_equal('child/resource', g:result)
1679 unlet g:result
1680 END
1681 v9.CheckScriptSuccess(lines)
1682
1683
Bram Moolenaarb8bebd02023-01-30 20:24:23 +00001684 # No class that implements the interface.
1685 lines =<< trim END
1686 vim9script
1687
1688 interface IWithEE
1689 def Enter(): any
1690 def Exit(): void
1691 endinterface
1692
1693 def With1(ee: IWithEE, F: func)
1694 var r = ee.Enter()
1695 enddef
1696
1697 defcompile
1698 END
1699 v9.CheckScriptSuccess(lines)
Bram Moolenaard0200c82023-01-28 15:19:40 +00001700enddef
1701
Bram Moolenaareca2c5f2023-01-07 12:08:41 +00001702def Test_class_used_as_type()
1703 var lines =<< trim END
1704 vim9script
1705
1706 class Point
1707 this.x = 0
1708 this.y = 0
1709 endclass
1710
1711 var p: Point
1712 p = Point.new(2, 33)
1713 assert_equal(2, p.x)
1714 assert_equal(33, p.y)
1715 END
1716 v9.CheckScriptSuccess(lines)
1717
1718 lines =<< trim END
1719 vim9script
1720
1721 interface HasX
1722 this.x: number
1723 endinterface
1724
1725 class Point implements HasX
1726 this.x = 0
1727 this.y = 0
1728 endclass
1729
1730 var p: Point
1731 p = Point.new(2, 33)
1732 var hx = p
1733 assert_equal(2, hx.x)
1734 END
1735 v9.CheckScriptSuccess(lines)
1736
1737 lines =<< trim END
1738 vim9script
1739
1740 class Point
1741 this.x = 0
1742 this.y = 0
1743 endclass
1744
1745 var p: Point
1746 p = 'text'
1747 END
Bram Moolenaar6481acc2023-01-11 21:14:17 +00001748 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object<Point> but got string')
Bram Moolenaareca2c5f2023-01-07 12:08:41 +00001749enddef
1750
Bram Moolenaar83677162023-01-08 19:54:10 +00001751def Test_class_extends()
1752 var lines =<< trim END
1753 vim9script
1754 class Base
1755 this.one = 1
1756 def GetOne(): number
1757 return this.one
1758 enddef
1759 endclass
1760 class Child extends Base
1761 this.two = 2
1762 def GetTotal(): number
1763 return this.one + this.two
1764 enddef
1765 endclass
1766 var o = Child.new()
1767 assert_equal(1, o.one)
1768 assert_equal(2, o.two)
1769 assert_equal(1, o.GetOne())
1770 assert_equal(3, o.GetTotal())
1771 END
1772 v9.CheckScriptSuccess(lines)
1773
1774 lines =<< trim END
1775 vim9script
1776 class Base
1777 this.one = 1
1778 endclass
1779 class Child extends Base
1780 this.two = 2
1781 endclass
1782 var o = Child.new(3, 44)
1783 assert_equal(3, o.one)
1784 assert_equal(44, o.two)
1785 END
1786 v9.CheckScriptSuccess(lines)
1787
1788 lines =<< trim END
1789 vim9script
1790 class Base
1791 this.one = 1
1792 endclass
1793 class Child extends Base extends Base
1794 this.two = 2
1795 endclass
1796 END
1797 v9.CheckScriptFailure(lines, 'E1352: Duplicate "extends"')
1798
1799 lines =<< trim END
1800 vim9script
1801 class Child extends BaseClass
1802 this.two = 2
1803 endclass
1804 END
1805 v9.CheckScriptFailure(lines, 'E1353: Class name not found: BaseClass')
1806
1807 lines =<< trim END
1808 vim9script
1809 var SomeVar = 99
1810 class Child extends SomeVar
1811 this.two = 2
1812 endclass
1813 END
1814 v9.CheckScriptFailure(lines, 'E1354: Cannot extend SomeVar')
Bram Moolenaar58b40092023-01-11 15:59:05 +00001815
1816 lines =<< trim END
1817 vim9script
1818 class Base
1819 this.name: string
1820 def ToString(): string
1821 return this.name
1822 enddef
1823 endclass
1824
1825 class Child extends Base
1826 this.age: number
1827 def ToString(): string
1828 return super.ToString() .. ': ' .. this.age
1829 enddef
1830 endclass
1831
1832 var o = Child.new('John', 42)
1833 assert_equal('John: 42', o.ToString())
1834 END
1835 v9.CheckScriptSuccess(lines)
Bram Moolenaar6aa09372023-01-11 17:59:38 +00001836
1837 lines =<< trim END
1838 vim9script
1839 class Child
1840 this.age: number
1841 def ToString(): number
1842 return this.age
1843 enddef
1844 def ToString(): string
1845 return this.age
1846 enddef
1847 endclass
1848 END
1849 v9.CheckScriptFailure(lines, 'E1355: Duplicate function: ToString')
1850
1851 lines =<< trim END
1852 vim9script
1853 class Child
1854 this.age: number
1855 def ToString(): string
1856 return super .ToString() .. ': ' .. this.age
1857 enddef
1858 endclass
1859 var o = Child.new(42)
1860 echo o.ToString()
1861 END
1862 v9.CheckScriptFailure(lines, 'E1356:')
1863
1864 lines =<< trim END
1865 vim9script
1866 class Base
1867 this.name: string
1868 def ToString(): string
1869 return this.name
1870 enddef
1871 endclass
1872
1873 var age = 42
1874 def ToString(): string
1875 return super.ToString() .. ': ' .. age
1876 enddef
1877 echo ToString()
1878 END
1879 v9.CheckScriptFailure(lines, 'E1357:')
1880
1881 lines =<< trim END
1882 vim9script
1883 class Child
1884 this.age: number
1885 def ToString(): string
1886 return super.ToString() .. ': ' .. this.age
1887 enddef
1888 endclass
1889 var o = Child.new(42)
1890 echo o.ToString()
1891 END
1892 v9.CheckScriptFailure(lines, 'E1358:')
Bram Moolenaar6481acc2023-01-11 21:14:17 +00001893
1894 lines =<< trim END
1895 vim9script
1896 class Base
1897 this.name: string
1898 static def ToString(): string
1899 return 'Base class'
1900 enddef
1901 endclass
1902
1903 class Child extends Base
1904 this.age: number
1905 def ToString(): string
1906 return Base.ToString() .. ': ' .. this.age
1907 enddef
1908 endclass
1909
1910 var o = Child.new('John', 42)
1911 assert_equal('Base class: 42', o.ToString())
1912 END
1913 v9.CheckScriptSuccess(lines)
Bram Moolenaar4cae8452023-01-15 15:51:48 +00001914
1915 lines =<< trim END
1916 vim9script
1917 class Base
1918 this.value = 1
1919 def new(init: number)
1920 this.value = number + 1
1921 enddef
1922 endclass
1923 class Child extends Base
1924 def new()
1925 this.new(3)
1926 enddef
1927 endclass
1928 var c = Child.new()
1929 END
1930 v9.CheckScriptFailure(lines, 'E1325: Method not found on class "Child": new(')
Bram Moolenaarae3205a2023-01-15 20:49:00 +00001931
1932 # base class with more than one object member
1933 lines =<< trim END
1934 vim9script
1935
1936 class Result
1937 this.success: bool
1938 this.value: any = null
1939 endclass
1940
1941 class Success extends Result
1942 def new(this.value = v:none)
1943 this.success = true
1944 enddef
1945 endclass
1946
1947 var v = Success.new('asdf')
1948 assert_equal("object of Success {success: true, value: 'asdf'}", string(v))
1949 END
1950 v9.CheckScriptSuccess(lines)
Yegappan Lakshmananb1027282023-08-19 11:26:42 +02001951
1952 # class name after "extends" doesn't end in a space or NUL character
1953 lines =<< trim END
1954 vim9script
1955 class A
1956 endclass
1957 class B extends A"
1958 endclass
1959 END
1960 v9.CheckScriptFailure(lines, 'E1315:')
Bram Moolenaar83677162023-01-08 19:54:10 +00001961enddef
1962
Bram Moolenaar094cf9f2023-02-10 15:52:25 +00001963def Test_using_base_class()
1964 var lines =<< trim END
1965 vim9script
1966
1967 class BaseEE
1968 def Enter(): any
1969 return null
1970 enddef
1971 def Exit(resource: any): void
1972 enddef
1973 endclass
1974
1975 class ChildEE extends BaseEE
1976 def Enter(): any
1977 return 42
1978 enddef
1979
1980 def Exit(resource: number): void
1981 g:result ..= '/exit'
1982 enddef
1983 endclass
1984
1985 def With(ee: BaseEE)
1986 var r = ee.Enter()
1987 try
1988 g:result ..= r
1989 finally
1990 g:result ..= '/finally'
1991 ee.Exit(r)
1992 endtry
1993 enddef
1994
1995 g:result = ''
1996 With(ChildEE.new())
1997 assert_equal('42/finally/exit', g:result)
1998 END
1999 v9.CheckScriptSuccess(lines)
2000 unlet g:result
Ernie Rael114ec812023-06-04 18:11:35 +01002001
2002 # Using super, Child invokes Base method which has optional arg. #12471
2003 lines =<< trim END
2004 vim9script
2005
2006 class Base
2007 this.success: bool = false
2008 def Method(arg = 0)
2009 this.success = true
2010 enddef
2011 endclass
2012
2013 class Child extends Base
2014 def new()
2015 super.Method()
2016 enddef
2017 endclass
2018
2019 var obj = Child.new()
2020 assert_equal(true, obj.success)
2021 END
2022 v9.CheckScriptSuccess(lines)
Bram Moolenaar094cf9f2023-02-10 15:52:25 +00002023enddef
2024
2025
Bram Moolenaara86655a2023-01-12 17:06:27 +00002026def Test_class_import()
2027 var lines =<< trim END
2028 vim9script
2029 export class Animal
2030 this.kind: string
2031 this.name: string
2032 endclass
2033 END
2034 writefile(lines, 'Xanimal.vim', 'D')
2035
2036 lines =<< trim END
2037 vim9script
2038 import './Xanimal.vim' as animal
2039
2040 var a: animal.Animal
2041 a = animal.Animal.new('fish', 'Eric')
2042 assert_equal('fish', a.kind)
2043 assert_equal('Eric', a.name)
Bram Moolenaar40594002023-01-12 20:04:51 +00002044
2045 var b: animal.Animal = animal.Animal.new('cat', 'Garfield')
2046 assert_equal('cat', b.kind)
2047 assert_equal('Garfield', b.name)
Bram Moolenaara86655a2023-01-12 17:06:27 +00002048 END
2049 v9.CheckScriptSuccess(lines)
2050enddef
2051
Bram Moolenaar24a8d062023-01-14 13:12:06 +00002052def Test_abstract_class()
2053 var lines =<< trim END
2054 vim9script
2055 abstract class Base
2056 this.name: string
2057 endclass
2058 class Person extends Base
2059 this.age: number
2060 endclass
2061 var p: Base = Person.new('Peter', 42)
2062 assert_equal('Peter', p.name)
2063 assert_equal(42, p.age)
2064 END
2065 v9.CheckScriptSuccess(lines)
2066
2067 lines =<< trim END
2068 vim9script
2069 abstract class Base
2070 this.name: string
2071 endclass
2072 class Person extends Base
2073 this.age: number
2074 endclass
2075 var p = Base.new('Peter')
2076 END
2077 v9.CheckScriptFailure(lines, 'E1325: Method not found on class "Base": new(')
2078
2079 lines =<< trim END
2080 abstract class Base
2081 this.name: string
2082 endclass
2083 END
2084 v9.CheckScriptFailure(lines, 'E1316:')
Yegappan Lakshmananb1027282023-08-19 11:26:42 +02002085
2086 # Abstract class cannot have a "new" function
2087 lines =<< trim END
2088 vim9script
2089 abstract class Base
2090 def new()
2091 enddef
2092 endclass
2093 END
2094 v9.CheckScriptFailure(lines, 'E1359:')
Bram Moolenaar24a8d062023-01-14 13:12:06 +00002095enddef
2096
Bram Moolenaar486fc252023-01-18 14:51:07 +00002097def Test_closure_in_class()
2098 var lines =<< trim END
2099 vim9script
2100
2101 class Foo
2102 this.y: list<string> = ['B']
2103
2104 def new()
2105 g:result = filter(['A', 'B'], (_, v) => index(this.y, v) == -1)
2106 enddef
2107 endclass
2108
2109 Foo.new()
2110 assert_equal(['A'], g:result)
2111 END
2112 v9.CheckScriptSuccess(lines)
2113enddef
2114
Bram Moolenaar5ca05fa2023-06-10 16:45:13 +01002115def Test_call_constructor_from_legacy()
2116 var lines =<< trim END
2117 vim9script
2118
2119 var newCalled = 'false'
2120
2121 class A
2122 def new()
2123 newCalled = 'true'
2124 enddef
2125 endclass
2126
2127 export def F(options = {}): any
2128 return A
2129 enddef
2130
2131 g:p = F()
2132 legacy call p.new()
2133 assert_equal('true', newCalled)
2134 END
2135 v9.CheckScriptSuccess(lines)
2136enddef
2137
Bram Moolenaar8dbab1d2023-01-27 20:14:02 +00002138def Test_defer_with_object()
2139 var lines =<< trim END
2140 vim9script
2141
2142 class CWithEE
2143 def Enter()
2144 g:result ..= "entered/"
2145 enddef
2146 def Exit()
2147 g:result ..= "exited"
2148 enddef
2149 endclass
2150
2151 def With(ee: CWithEE, F: func)
2152 ee.Enter()
2153 defer ee.Exit()
2154 F()
2155 enddef
2156
2157 g:result = ''
2158 var obj = CWithEE.new()
2159 obj->With(() => {
2160 g:result ..= "called/"
2161 })
2162 assert_equal('entered/called/exited', g:result)
2163 END
2164 v9.CheckScriptSuccess(lines)
2165 unlet g:result
Bram Moolenaar313e4722023-02-08 20:55:27 +00002166
2167 lines =<< trim END
2168 vim9script
2169
2170 class BaseWithEE
2171 def Enter()
2172 g:result ..= "entered-base/"
2173 enddef
2174 def Exit()
2175 g:result ..= "exited-base"
2176 enddef
2177 endclass
2178
2179 class CWithEE extends BaseWithEE
2180 def Enter()
2181 g:result ..= "entered-child/"
2182 enddef
2183 def Exit()
2184 g:result ..= "exited-child"
2185 enddef
2186 endclass
2187
2188 def With(ee: BaseWithEE, F: func)
2189 ee.Enter()
2190 defer ee.Exit()
2191 F()
2192 enddef
2193
2194 g:result = ''
2195 var obj = CWithEE.new()
2196 obj->With(() => {
2197 g:result ..= "called/"
2198 })
2199 assert_equal('entered-child/called/exited-child', g:result)
2200 END
2201 v9.CheckScriptSuccess(lines)
2202 unlet g:result
Bram Moolenaar8dbab1d2023-01-27 20:14:02 +00002203enddef
2204
Yegappan Lakshmanan57a02cc2023-08-13 10:19:38 +02002205" The following test used to crash Vim (Github issue #12676)
2206def Test_extends_method_crashes_vim()
2207 var lines =<< trim END
2208 vim9script
2209
2210 class Observer
2211 endclass
2212
2213 class Property
2214 this.value: any
2215
2216 def Set(v: any)
2217 if v != this.value
2218 this.value = v
2219 endif
2220 enddef
2221
2222 def Register(observer: Observer)
2223 enddef
2224 endclass
2225
2226 class Bool extends Property
2227 this.value: bool
2228 endclass
2229
2230 def Observe(obj: Property, who: Observer)
2231 obj.Register(who)
2232 enddef
2233
2234 var p = Bool.new(false)
2235 var myObserver = Observer.new()
2236
2237 Observe(p, myObserver)
2238
2239 p.Set(true)
2240 END
2241 v9.CheckScriptSuccess(lines)
2242enddef
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002243
Yegappan Lakshmanan74cc13c2023-08-13 17:41:26 +02002244" Test for calling a method in a class that is extended
2245def Test_call_method_in_extended_class()
2246 var lines =<< trim END
2247 vim9script
2248
2249 var prop_init_called = false
2250 var prop_register_called = false
2251
2252 class Property
2253 def Init()
2254 prop_init_called = true
2255 enddef
2256
2257 def Register()
2258 prop_register_called = true
2259 enddef
2260 endclass
2261
2262 class Bool extends Property
2263 endclass
2264
2265 def Observe(obj: Property)
2266 obj.Register()
2267 enddef
2268
2269 var p = Property.new()
2270 Observe(p)
2271
2272 p.Init()
2273 assert_true(prop_init_called)
2274 assert_true(prop_register_called)
2275 END
2276 v9.CheckScriptSuccess(lines)
2277enddef
2278
Yegappan Lakshmanana456b122023-08-16 20:14:37 +02002279" Test for calling a method in the parent class that is extended partially.
2280" This used to fail with the 'E118: Too many arguments for function: Text' error
2281" message (Github issue #12524).
2282def Test_call_method_in_parent_class()
2283 var lines =<< trim END
2284 vim9script
2285
2286 class Widget
2287 this._lnum: number = 1
2288
2289 def SetY(lnum: number)
2290 this._lnum = lnum
2291 enddef
2292
2293 def Text(): string
2294 return ''
2295 enddef
2296 endclass
2297
2298 class Foo extends Widget
2299 def Text(): string
2300 return '<Foo>'
2301 enddef
2302 endclass
2303
2304 def Stack(w1: Widget, w2: Widget): list<Widget>
2305 w1.SetY(1)
2306 w2.SetY(2)
2307 return [w1, w2]
2308 enddef
2309
2310 var foo1 = Foo.new()
2311 var foo2 = Foo.new()
2312 var l = Stack(foo1, foo2)
2313 END
2314 v9.CheckScriptSuccess(lines)
2315enddef
2316
Yegappan Lakshmananb1027282023-08-19 11:26:42 +02002317" Test for calling methods from three levels of classes
2318def Test_multi_level_method_call()
2319 var lines =<< trim END
2320 vim9script
2321
2322 var A_func1: number = 0
2323 var A_func2: number = 0
2324 var A_func3: number = 0
2325 var B_func2: number = 0
2326 var B_func3: number = 0
2327 var C_func3: number = 0
2328
2329 class A
2330 def Func1()
2331 A_func1 += 1
2332 enddef
2333
2334 def Func2()
2335 A_func2 += 1
2336 enddef
2337
2338 def Func3()
2339 A_func3 += 1
2340 enddef
2341 endclass
2342
2343 class B extends A
2344 def Func2()
2345 B_func2 += 1
2346 enddef
2347
2348 def Func3()
2349 B_func3 += 1
2350 enddef
2351 endclass
2352
2353 class C extends B
2354 def Func3()
2355 C_func3 += 1
2356 enddef
2357 endclass
2358
2359 def A_CallFuncs(a: A)
2360 a.Func1()
2361 a.Func2()
2362 a.Func3()
2363 enddef
2364
2365 def B_CallFuncs(b: B)
2366 b.Func1()
2367 b.Func2()
2368 b.Func3()
2369 enddef
2370
2371 def C_CallFuncs(c: C)
2372 c.Func1()
2373 c.Func2()
2374 c.Func3()
2375 enddef
2376
2377 var cobj = C.new()
2378 A_CallFuncs(cobj)
2379 B_CallFuncs(cobj)
2380 C_CallFuncs(cobj)
2381 assert_equal(3, A_func1)
2382 assert_equal(0, A_func2)
2383 assert_equal(0, A_func3)
2384 assert_equal(3, B_func2)
2385 assert_equal(0, B_func3)
2386 assert_equal(3, C_func3)
2387 END
2388 v9.CheckScriptSuccess(lines)
2389enddef
2390
2391" Test for using members from three levels of classes
2392def Test_multi_level_member_access()
2393 var lines =<< trim END
2394 vim9script
2395
2396 class A
2397 this.val1: number = 0
2398 this.val2: number = 0
2399 this.val3: number = 0
2400 endclass
2401
2402 class B extends A
2403 this.val2: number = 0
2404 this.val3: number = 0
2405 endclass
2406
2407 class C extends B
2408 this.val3: number = 0
2409 endclass
2410
2411 def A_members(a: A)
2412 a.val1 += 1
2413 a.val2 += 1
2414 a.val3 += 1
2415 enddef
2416
2417 def B_members(b: B)
2418 b.val1 += 1
2419 b.val2 += 1
2420 b.val3 += 1
2421 enddef
2422
2423 def C_members(c: C)
2424 c.val1 += 1
2425 c.val2 += 1
2426 c.val3 += 1
2427 enddef
2428
2429 var cobj = C.new()
2430 A_members(cobj)
2431 B_members(cobj)
2432 C_members(cobj)
2433 assert_equal(3, cobj.val1)
2434 assert_equal(3, cobj.val2)
2435 assert_equal(3, cobj.val3)
2436 END
2437 v9.CheckScriptSuccess(lines)
2438enddef
2439
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002440" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker