blob: c268dde50eea7a1d5be3ea8397e92672c5afb57f [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 Moolenaar99a7c0d2023-02-21 19:55:14 +0000845def Test_class_defcompile()
846 var lines =<< trim END
847 vim9script
848
849 class C
850 def Fo(i: number): string
851 return i
852 enddef
853 endclass
854
855 defcompile C.Fo
856 END
857 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number')
858
859 lines =<< trim END
860 vim9script
861
862 class C
863 static def Fc(): number
864 return 'x'
865 enddef
866 endclass
867
868 defcompile C.Fc
869 END
870 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected number but got string')
871enddef
872
Bram Moolenaar91c9d6d2022-12-14 17:30:37 +0000873def Test_class_object_to_string()
874 var lines =<< trim END
875 vim9script
876 class TextPosition
877 this.lnum = 1
878 this.col = 22
879 endclass
880
881 assert_equal("class TextPosition", string(TextPosition))
882
883 var pos = TextPosition.new()
884 assert_equal("object of TextPosition {lnum: 1, col: 22}", string(pos))
885 END
886 v9.CheckScriptSuccess(lines)
887enddef
Bram Moolenaar74e12742022-12-13 21:14:28 +0000888
Bram Moolenaar554d0312023-01-05 19:59:18 +0000889def Test_interface_basics()
890 var lines =<< trim END
891 vim9script
892 interface Something
893 this.value: string
894 static count: number
895 def GetCount(): number
896 endinterface
897 END
898 v9.CheckScriptSuccess(lines)
899
900 lines =<< trim END
901 interface SomethingWrong
902 static count = 7
903 endinterface
904 END
905 v9.CheckScriptFailure(lines, 'E1342:')
906
907 lines =<< trim END
908 vim9script
909
910 interface Some
911 static count: number
912 def Method(count: number)
913 endinterface
914 END
Bram Moolenaard40f00c2023-01-13 17:36:49 +0000915 v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: count')
916
917 lines =<< trim END
918 vim9script
919
920 interface Some
921 this.value: number
922 def Method(value: number)
923 endinterface
924 END
925 v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: value')
Bram Moolenaar554d0312023-01-05 19:59:18 +0000926
927 lines =<< trim END
928 vim9script
929 interface somethingWrong
930 static count = 7
931 endinterface
932 END
933 v9.CheckScriptFailure(lines, 'E1343: Interface name must start with an uppercase letter: somethingWrong')
934
935 lines =<< trim END
936 vim9script
937 interface SomethingWrong
938 this.value: string
939 static count = 7
940 def GetCount(): number
941 endinterface
942 END
943 v9.CheckScriptFailure(lines, 'E1344:')
944
945 lines =<< trim END
946 vim9script
947 interface SomethingWrong
948 this.value: string
949 static count: number
950 def GetCount(): number
951 return 5
952 enddef
953 endinterface
954 END
955 v9.CheckScriptFailure(lines, 'E1345: Not a valid command in an interface: return 5')
Bram Moolenaar53f54e42023-01-26 20:36:56 +0000956
957 lines =<< trim END
958 vim9script
959 export interface EnterExit
960 def Enter(): void
961 def Exit(): void
962 endinterface
963 END
964 writefile(lines, 'XdefIntf.vim', 'D')
965
966 lines =<< trim END
967 vim9script
968 import './XdefIntf.vim' as defIntf
969 export def With(ee: defIntf.EnterExit, F: func)
970 ee.Enter()
971 try
972 F()
973 finally
974 ee.Exit()
975 endtry
976 enddef
977 END
978 v9.CheckScriptSuccess(lines)
Bram Moolenaar657aea72023-01-27 13:16:19 +0000979
980 var imported =<< trim END
981 vim9script
982 export abstract class EnterExit
983 def Enter(): void
984 enddef
985 def Exit(): void
986 enddef
987 endclass
988 END
989 writefile(imported, 'XdefIntf2.vim', 'D')
990
991 lines[1] = " import './XdefIntf2.vim' as defIntf"
992 v9.CheckScriptSuccess(lines)
Bram Moolenaar554d0312023-01-05 19:59:18 +0000993enddef
994
Bram Moolenaar94674f22023-01-06 18:42:20 +0000995def Test_class_implements_interface()
996 var lines =<< trim END
997 vim9script
998
999 interface Some
1000 static count: number
1001 def Method(nr: number)
1002 endinterface
1003
1004 class SomeImpl implements Some
1005 static count: number
1006 def Method(nr: number)
1007 echo nr
1008 enddef
1009 endclass
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001010
1011 interface Another
1012 this.member: string
1013 endinterface
1014
1015 class SomeImpl implements Some, Another
1016 this.member = 'abc'
1017 static count: number
1018 def Method(nr: number)
1019 echo nr
1020 enddef
1021 endclass
1022
Bram Moolenaar94674f22023-01-06 18:42:20 +00001023 END
1024 v9.CheckScriptSuccess(lines)
1025
1026 lines =<< trim END
1027 vim9script
1028
1029 interface Some
1030 static counter: number
Bram Moolenaardf8f9472023-01-07 14:51:03 +00001031 endinterface
1032
1033 class SomeImpl implements Some implements Some
1034 static count: number
1035 endclass
1036 END
1037 v9.CheckScriptFailure(lines, 'E1350:')
1038
1039 lines =<< trim END
1040 vim9script
1041
1042 interface Some
1043 static counter: number
1044 endinterface
1045
1046 class SomeImpl implements Some, Some
1047 static count: number
1048 endclass
1049 END
1050 v9.CheckScriptFailure(lines, 'E1351: Duplicate interface after "implements": Some')
1051
1052 lines =<< trim END
1053 vim9script
1054
1055 interface Some
1056 static counter: number
Bram Moolenaar94674f22023-01-06 18:42:20 +00001057 def Method(nr: number)
1058 endinterface
1059
1060 class SomeImpl implements Some
1061 static count: number
1062 def Method(nr: number)
1063 echo nr
1064 enddef
1065 endclass
1066 END
1067 v9.CheckScriptFailure(lines, 'E1348: Member "counter" of interface "Some" not implemented')
1068
1069 lines =<< trim END
1070 vim9script
1071
1072 interface Some
1073 static count: number
1074 def Methods(nr: number)
1075 endinterface
1076
1077 class SomeImpl implements Some
1078 static count: number
1079 def Method(nr: number)
1080 echo nr
1081 enddef
1082 endclass
1083 END
1084 v9.CheckScriptFailure(lines, 'E1349: Function "Methods" of interface "Some" not implemented')
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001085
1086 # Check different order of members in class and interface works.
1087 lines =<< trim END
1088 vim9script
1089
1090 interface Result
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001091 public this.label: string
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001092 this.errpos: number
1093 endinterface
1094
1095 # order of members is opposite of interface
1096 class Failure implements Result
1097 this.errpos: number = 42
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001098 public this.label: string = 'label'
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001099 endclass
1100
1101 def Test()
1102 var result: Result = Failure.new()
1103
1104 assert_equal('label', result.label)
1105 assert_equal(42, result.errpos)
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001106
1107 result.label = 'different'
1108 assert_equal('different', result.label)
1109 assert_equal(42, result.errpos)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001110 enddef
1111
1112 Test()
1113 END
1114 v9.CheckScriptSuccess(lines)
Bram Moolenaar94674f22023-01-06 18:42:20 +00001115enddef
1116
Bram Moolenaard0200c82023-01-28 15:19:40 +00001117def Test_call_interface_method()
1118 var lines =<< trim END
1119 vim9script
1120 interface Base
1121 def Enter(): void
1122 endinterface
1123
1124 class Child implements Base
1125 def Enter(): void
1126 g:result ..= 'child'
1127 enddef
1128 endclass
1129
1130 def F(obj: Base)
1131 obj.Enter()
1132 enddef
1133
1134 g:result = ''
1135 F(Child.new())
1136 assert_equal('child', g:result)
1137 unlet g:result
1138 END
1139 v9.CheckScriptSuccess(lines)
1140
1141 lines =<< trim END
1142 vim9script
1143 class Base
1144 def Enter(): void
1145 g:result ..= 'base'
1146 enddef
1147 endclass
1148
1149 class Child extends Base
1150 def Enter(): void
1151 g:result ..= 'child'
1152 enddef
1153 endclass
1154
1155 def F(obj: Base)
1156 obj.Enter()
1157 enddef
1158
1159 g:result = ''
1160 F(Child.new())
1161 assert_equal('child', g:result)
1162 unlet g:result
1163 END
1164 v9.CheckScriptSuccess(lines)
Bram Moolenaarb8bebd02023-01-30 20:24:23 +00001165
Bram Moolenaar7a1bdae2023-02-04 15:45:27 +00001166 # method of interface returns a value
1167 lines =<< trim END
1168 vim9script
1169 interface Base
1170 def Enter(): string
1171 endinterface
1172
1173 class Child implements Base
1174 def Enter(): string
1175 g:result ..= 'child'
1176 return "/resource"
1177 enddef
1178 endclass
1179
1180 def F(obj: Base)
1181 var r = obj.Enter()
1182 g:result ..= r
1183 enddef
1184
1185 g:result = ''
1186 F(Child.new())
1187 assert_equal('child/resource', g:result)
1188 unlet g:result
1189 END
1190 v9.CheckScriptSuccess(lines)
1191
1192 lines =<< trim END
1193 vim9script
1194 class Base
1195 def Enter(): string
1196 return null_string
1197 enddef
1198 endclass
1199
1200 class Child extends Base
1201 def Enter(): string
1202 g:result ..= 'child'
1203 return "/resource"
1204 enddef
1205 endclass
1206
1207 def F(obj: Base)
1208 var r = obj.Enter()
1209 g:result ..= r
1210 enddef
1211
1212 g:result = ''
1213 F(Child.new())
1214 assert_equal('child/resource', g:result)
1215 unlet g:result
1216 END
1217 v9.CheckScriptSuccess(lines)
1218
1219
Bram Moolenaarb8bebd02023-01-30 20:24:23 +00001220 # No class that implements the interface.
1221 lines =<< trim END
1222 vim9script
1223
1224 interface IWithEE
1225 def Enter(): any
1226 def Exit(): void
1227 endinterface
1228
1229 def With1(ee: IWithEE, F: func)
1230 var r = ee.Enter()
1231 enddef
1232
1233 defcompile
1234 END
1235 v9.CheckScriptSuccess(lines)
Bram Moolenaard0200c82023-01-28 15:19:40 +00001236enddef
1237
Bram Moolenaareca2c5f2023-01-07 12:08:41 +00001238def Test_class_used_as_type()
1239 var lines =<< trim END
1240 vim9script
1241
1242 class Point
1243 this.x = 0
1244 this.y = 0
1245 endclass
1246
1247 var p: Point
1248 p = Point.new(2, 33)
1249 assert_equal(2, p.x)
1250 assert_equal(33, p.y)
1251 END
1252 v9.CheckScriptSuccess(lines)
1253
1254 lines =<< trim END
1255 vim9script
1256
1257 interface HasX
1258 this.x: number
1259 endinterface
1260
1261 class Point implements HasX
1262 this.x = 0
1263 this.y = 0
1264 endclass
1265
1266 var p: Point
1267 p = Point.new(2, 33)
1268 var hx = p
1269 assert_equal(2, hx.x)
1270 END
1271 v9.CheckScriptSuccess(lines)
1272
1273 lines =<< trim END
1274 vim9script
1275
1276 class Point
1277 this.x = 0
1278 this.y = 0
1279 endclass
1280
1281 var p: Point
1282 p = 'text'
1283 END
Bram Moolenaar6481acc2023-01-11 21:14:17 +00001284 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object<Point> but got string')
Bram Moolenaareca2c5f2023-01-07 12:08:41 +00001285enddef
1286
Bram Moolenaar83677162023-01-08 19:54:10 +00001287def Test_class_extends()
1288 var lines =<< trim END
1289 vim9script
1290 class Base
1291 this.one = 1
1292 def GetOne(): number
1293 return this.one
1294 enddef
1295 endclass
1296 class Child extends Base
1297 this.two = 2
1298 def GetTotal(): number
1299 return this.one + this.two
1300 enddef
1301 endclass
1302 var o = Child.new()
1303 assert_equal(1, o.one)
1304 assert_equal(2, o.two)
1305 assert_equal(1, o.GetOne())
1306 assert_equal(3, o.GetTotal())
1307 END
1308 v9.CheckScriptSuccess(lines)
1309
1310 lines =<< trim END
1311 vim9script
1312 class Base
1313 this.one = 1
1314 endclass
1315 class Child extends Base
1316 this.two = 2
1317 endclass
1318 var o = Child.new(3, 44)
1319 assert_equal(3, o.one)
1320 assert_equal(44, o.two)
1321 END
1322 v9.CheckScriptSuccess(lines)
1323
1324 lines =<< trim END
1325 vim9script
1326 class Base
1327 this.one = 1
1328 endclass
1329 class Child extends Base extends Base
1330 this.two = 2
1331 endclass
1332 END
1333 v9.CheckScriptFailure(lines, 'E1352: Duplicate "extends"')
1334
1335 lines =<< trim END
1336 vim9script
1337 class Child extends BaseClass
1338 this.two = 2
1339 endclass
1340 END
1341 v9.CheckScriptFailure(lines, 'E1353: Class name not found: BaseClass')
1342
1343 lines =<< trim END
1344 vim9script
1345 var SomeVar = 99
1346 class Child extends SomeVar
1347 this.two = 2
1348 endclass
1349 END
1350 v9.CheckScriptFailure(lines, 'E1354: Cannot extend SomeVar')
Bram Moolenaar58b40092023-01-11 15:59:05 +00001351
1352 lines =<< trim END
1353 vim9script
1354 class Base
1355 this.name: string
1356 def ToString(): string
1357 return this.name
1358 enddef
1359 endclass
1360
1361 class Child extends Base
1362 this.age: number
1363 def ToString(): string
1364 return super.ToString() .. ': ' .. this.age
1365 enddef
1366 endclass
1367
1368 var o = Child.new('John', 42)
1369 assert_equal('John: 42', o.ToString())
1370 END
1371 v9.CheckScriptSuccess(lines)
Bram Moolenaar6aa09372023-01-11 17:59:38 +00001372
1373 lines =<< trim END
1374 vim9script
1375 class Child
1376 this.age: number
1377 def ToString(): number
1378 return this.age
1379 enddef
1380 def ToString(): string
1381 return this.age
1382 enddef
1383 endclass
1384 END
1385 v9.CheckScriptFailure(lines, 'E1355: Duplicate function: ToString')
1386
1387 lines =<< trim END
1388 vim9script
1389 class Child
1390 this.age: number
1391 def ToString(): string
1392 return super .ToString() .. ': ' .. this.age
1393 enddef
1394 endclass
1395 var o = Child.new(42)
1396 echo o.ToString()
1397 END
1398 v9.CheckScriptFailure(lines, 'E1356:')
1399
1400 lines =<< trim END
1401 vim9script
1402 class Base
1403 this.name: string
1404 def ToString(): string
1405 return this.name
1406 enddef
1407 endclass
1408
1409 var age = 42
1410 def ToString(): string
1411 return super.ToString() .. ': ' .. age
1412 enddef
1413 echo ToString()
1414 END
1415 v9.CheckScriptFailure(lines, 'E1357:')
1416
1417 lines =<< trim END
1418 vim9script
1419 class Child
1420 this.age: number
1421 def ToString(): string
1422 return super.ToString() .. ': ' .. this.age
1423 enddef
1424 endclass
1425 var o = Child.new(42)
1426 echo o.ToString()
1427 END
1428 v9.CheckScriptFailure(lines, 'E1358:')
Bram Moolenaar6481acc2023-01-11 21:14:17 +00001429
1430 lines =<< trim END
1431 vim9script
1432 class Base
1433 this.name: string
1434 static def ToString(): string
1435 return 'Base class'
1436 enddef
1437 endclass
1438
1439 class Child extends Base
1440 this.age: number
1441 def ToString(): string
1442 return Base.ToString() .. ': ' .. this.age
1443 enddef
1444 endclass
1445
1446 var o = Child.new('John', 42)
1447 assert_equal('Base class: 42', o.ToString())
1448 END
1449 v9.CheckScriptSuccess(lines)
Bram Moolenaar4cae8452023-01-15 15:51:48 +00001450
1451 lines =<< trim END
1452 vim9script
1453 class Base
1454 this.value = 1
1455 def new(init: number)
1456 this.value = number + 1
1457 enddef
1458 endclass
1459 class Child extends Base
1460 def new()
1461 this.new(3)
1462 enddef
1463 endclass
1464 var c = Child.new()
1465 END
1466 v9.CheckScriptFailure(lines, 'E1325: Method not found on class "Child": new(')
Bram Moolenaarae3205a2023-01-15 20:49:00 +00001467
1468 # base class with more than one object member
1469 lines =<< trim END
1470 vim9script
1471
1472 class Result
1473 this.success: bool
1474 this.value: any = null
1475 endclass
1476
1477 class Success extends Result
1478 def new(this.value = v:none)
1479 this.success = true
1480 enddef
1481 endclass
1482
1483 var v = Success.new('asdf')
1484 assert_equal("object of Success {success: true, value: 'asdf'}", string(v))
1485 END
1486 v9.CheckScriptSuccess(lines)
Bram Moolenaar83677162023-01-08 19:54:10 +00001487enddef
1488
Bram Moolenaar094cf9f2023-02-10 15:52:25 +00001489def Test_using_base_class()
1490 var lines =<< trim END
1491 vim9script
1492
1493 class BaseEE
1494 def Enter(): any
1495 return null
1496 enddef
1497 def Exit(resource: any): void
1498 enddef
1499 endclass
1500
1501 class ChildEE extends BaseEE
1502 def Enter(): any
1503 return 42
1504 enddef
1505
1506 def Exit(resource: number): void
1507 g:result ..= '/exit'
1508 enddef
1509 endclass
1510
1511 def With(ee: BaseEE)
1512 var r = ee.Enter()
1513 try
1514 g:result ..= r
1515 finally
1516 g:result ..= '/finally'
1517 ee.Exit(r)
1518 endtry
1519 enddef
1520
1521 g:result = ''
1522 With(ChildEE.new())
1523 assert_equal('42/finally/exit', g:result)
1524 END
1525 v9.CheckScriptSuccess(lines)
1526 unlet g:result
1527enddef
1528
1529
Bram Moolenaara86655a2023-01-12 17:06:27 +00001530def Test_class_import()
1531 var lines =<< trim END
1532 vim9script
1533 export class Animal
1534 this.kind: string
1535 this.name: string
1536 endclass
1537 END
1538 writefile(lines, 'Xanimal.vim', 'D')
1539
1540 lines =<< trim END
1541 vim9script
1542 import './Xanimal.vim' as animal
1543
1544 var a: animal.Animal
1545 a = animal.Animal.new('fish', 'Eric')
1546 assert_equal('fish', a.kind)
1547 assert_equal('Eric', a.name)
Bram Moolenaar40594002023-01-12 20:04:51 +00001548
1549 var b: animal.Animal = animal.Animal.new('cat', 'Garfield')
1550 assert_equal('cat', b.kind)
1551 assert_equal('Garfield', b.name)
Bram Moolenaara86655a2023-01-12 17:06:27 +00001552 END
1553 v9.CheckScriptSuccess(lines)
1554enddef
1555
Bram Moolenaar24a8d062023-01-14 13:12:06 +00001556def Test_abstract_class()
1557 var lines =<< trim END
1558 vim9script
1559 abstract class Base
1560 this.name: string
1561 endclass
1562 class Person extends Base
1563 this.age: number
1564 endclass
1565 var p: Base = Person.new('Peter', 42)
1566 assert_equal('Peter', p.name)
1567 assert_equal(42, p.age)
1568 END
1569 v9.CheckScriptSuccess(lines)
1570
1571 lines =<< trim END
1572 vim9script
1573 abstract class Base
1574 this.name: string
1575 endclass
1576 class Person extends Base
1577 this.age: number
1578 endclass
1579 var p = Base.new('Peter')
1580 END
1581 v9.CheckScriptFailure(lines, 'E1325: Method not found on class "Base": new(')
1582
1583 lines =<< trim END
1584 abstract class Base
1585 this.name: string
1586 endclass
1587 END
1588 v9.CheckScriptFailure(lines, 'E1316:')
1589enddef
1590
Bram Moolenaar486fc252023-01-18 14:51:07 +00001591def Test_closure_in_class()
1592 var lines =<< trim END
1593 vim9script
1594
1595 class Foo
1596 this.y: list<string> = ['B']
1597
1598 def new()
1599 g:result = filter(['A', 'B'], (_, v) => index(this.y, v) == -1)
1600 enddef
1601 endclass
1602
1603 Foo.new()
1604 assert_equal(['A'], g:result)
1605 END
1606 v9.CheckScriptSuccess(lines)
1607enddef
1608
Bram Moolenaar8dbab1d2023-01-27 20:14:02 +00001609def Test_defer_with_object()
1610 var lines =<< trim END
1611 vim9script
1612
1613 class CWithEE
1614 def Enter()
1615 g:result ..= "entered/"
1616 enddef
1617 def Exit()
1618 g:result ..= "exited"
1619 enddef
1620 endclass
1621
1622 def With(ee: CWithEE, F: func)
1623 ee.Enter()
1624 defer ee.Exit()
1625 F()
1626 enddef
1627
1628 g:result = ''
1629 var obj = CWithEE.new()
1630 obj->With(() => {
1631 g:result ..= "called/"
1632 })
1633 assert_equal('entered/called/exited', g:result)
1634 END
1635 v9.CheckScriptSuccess(lines)
1636 unlet g:result
Bram Moolenaar313e4722023-02-08 20:55:27 +00001637
1638 lines =<< trim END
1639 vim9script
1640
1641 class BaseWithEE
1642 def Enter()
1643 g:result ..= "entered-base/"
1644 enddef
1645 def Exit()
1646 g:result ..= "exited-base"
1647 enddef
1648 endclass
1649
1650 class CWithEE extends BaseWithEE
1651 def Enter()
1652 g:result ..= "entered-child/"
1653 enddef
1654 def Exit()
1655 g:result ..= "exited-child"
1656 enddef
1657 endclass
1658
1659 def With(ee: BaseWithEE, F: func)
1660 ee.Enter()
1661 defer ee.Exit()
1662 F()
1663 enddef
1664
1665 g:result = ''
1666 var obj = CWithEE.new()
1667 obj->With(() => {
1668 g:result ..= "called/"
1669 })
1670 assert_equal('entered-child/called/exited-child', g:result)
1671 END
1672 v9.CheckScriptSuccess(lines)
1673 unlet g:result
Bram Moolenaar8dbab1d2023-01-27 20:14:02 +00001674enddef
1675
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001676
1677" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker