blob: 2cd3bdd1b2fac9fbfabfbf4d977dab054bddecc8 [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 Moolenaar4cae8452023-01-15 15:51:48 +0000256def Test_assignment_with_operator()
257 var lines =<< trim END
258 vim9script
259
260 class Foo
261 this.x: number
262
263 def Add(n: number)
264 this.x += n
265 enddef
266 endclass
267
268 var f = Foo.new(3)
269 f.Add(17)
270 assert_equal(20, f.x)
271 END
272 v9.CheckScriptSuccess(lines)
273enddef
274
Bram Moolenaarf4508042023-01-15 16:54:57 +0000275def Test_list_of_objects()
276 var lines =<< trim END
277 vim9script
278
279 class Foo
280 def Add()
281 enddef
282 endclass
283
284 def ProcessList(fooList: list<Foo>)
285 for foo in fooList
286 foo.Add()
287 endfor
288 enddef
289
290 var l: list<Foo> = [Foo.new()]
291 ProcessList(l)
292 END
293 v9.CheckScriptSuccess(lines)
294enddef
295
Bram Moolenaar912bfee2023-01-15 20:18:55 +0000296def Test_expr_after_using_object()
297 var lines =<< trim END
298 vim9script
299
300 class Something
301 this.label: string = ''
302 endclass
303
304 def Foo(): Something
305 var v = Something.new()
306 echo 'in Foo(): ' .. typename(v)
307 return v
308 enddef
309
310 Foo()
311 END
312 v9.CheckScriptSuccess(lines)
313enddef
314
Bram Moolenaar65b0d162022-12-13 18:43:22 +0000315def Test_class_default_new()
316 var lines =<< trim END
317 vim9script
318
319 class TextPosition
320 this.lnum: number = 1
321 this.col: number = 1
322 endclass
323
324 var pos = TextPosition.new()
325 assert_equal(1, pos.lnum)
326 assert_equal(1, pos.col)
327
328 pos = TextPosition.new(v:none, v:none)
329 assert_equal(1, pos.lnum)
330 assert_equal(1, pos.col)
331
332 pos = TextPosition.new(3, 22)
333 assert_equal(3, pos.lnum)
334 assert_equal(22, pos.col)
335
336 pos = TextPosition.new(v:none, 33)
337 assert_equal(1, pos.lnum)
338 assert_equal(33, pos.col)
339 END
340 v9.CheckScriptSuccess(lines)
341
342 lines =<< trim END
343 vim9script
344 class Person
345 this.name: string
346 this.age: number = 42
347 this.education: string = "unknown"
348
349 def new(this.name, this.age = v:none, this.education = v:none)
350 enddef
351 endclass
352
353 var piet = Person.new("Piet")
354 assert_equal("Piet", piet.name)
355 assert_equal(42, piet.age)
356 assert_equal("unknown", piet.education)
357
358 var chris = Person.new("Chris", 4, "none")
359 assert_equal("Chris", chris.name)
360 assert_equal(4, chris.age)
361 assert_equal("none", chris.education)
362 END
363 v9.CheckScriptSuccess(lines)
Bram Moolenaar74e12742022-12-13 21:14:28 +0000364
365 lines =<< trim END
366 vim9script
367 class Person
368 this.name: string
369 this.age: number = 42
370 this.education: string = "unknown"
371
372 def new(this.name, this.age = v:none, this.education = v:none)
373 enddef
374 endclass
375
376 var missing = Person.new()
377 END
378 v9.CheckScriptFailure(lines, 'E119:')
Bram Moolenaar65b0d162022-12-13 18:43:22 +0000379enddef
380
Bram Moolenaar74e12742022-12-13 21:14:28 +0000381def Test_class_object_member_inits()
382 var lines =<< trim END
383 vim9script
384 class TextPosition
385 this.lnum: number
386 this.col = 1
387 this.addcol: number = 2
388 endclass
389
390 var pos = TextPosition.new()
391 assert_equal(0, pos.lnum)
392 assert_equal(1, pos.col)
393 assert_equal(2, pos.addcol)
394 END
395 v9.CheckScriptSuccess(lines)
396
397 lines =<< trim END
398 vim9script
399 class TextPosition
400 this.lnum
401 this.col = 1
402 endclass
403 END
404 v9.CheckScriptFailure(lines, 'E1022:')
405
406 lines =<< trim END
407 vim9script
408 class TextPosition
409 this.lnum = v:none
410 this.col = 1
411 endclass
412 END
413 v9.CheckScriptFailure(lines, 'E1330:')
414enddef
415
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000416def Test_class_object_member_access()
417 var lines =<< trim END
418 vim9script
419 class Triple
420 this._one = 1
421 this.two = 2
422 public this.three = 3
423
424 def GetOne(): number
425 return this._one
426 enddef
427 endclass
428
429 var trip = Triple.new()
430 assert_equal(1, trip.GetOne())
431 assert_equal(2, trip.two)
432 assert_equal(3, trip.three)
433 assert_fails('echo trip._one', 'E1333')
434
435 assert_fails('trip._one = 11', 'E1333')
436 assert_fails('trip.two = 22', 'E1335')
437 trip.three = 33
438 assert_equal(33, trip.three)
Bram Moolenaard505d172022-12-18 21:42:55 +0000439
440 assert_fails('trip.four = 4', 'E1334')
441 END
442 v9.CheckScriptSuccess(lines)
Bram Moolenaar590162c2022-12-24 21:24:06 +0000443
444 lines =<< trim END
445 vim9script
446
447 class MyCar
448 this.make: string
Bram Moolenaar574950d2023-01-03 19:08:50 +0000449 this.age = 5
Bram Moolenaar590162c2022-12-24 21:24:06 +0000450
451 def new(make_arg: string)
452 this.make = make_arg
453 enddef
454
455 def GetMake(): string
456 return $"make = {this.make}"
457 enddef
Bram Moolenaar574950d2023-01-03 19:08:50 +0000458 def GetAge(): number
459 return this.age
460 enddef
Bram Moolenaar590162c2022-12-24 21:24:06 +0000461 endclass
462
463 var c = MyCar.new("abc")
464 assert_equal('make = abc', c.GetMake())
465
466 c = MyCar.new("def")
467 assert_equal('make = def', c.GetMake())
468
469 var c2 = MyCar.new("123")
470 assert_equal('make = 123', c2.GetMake())
Bram Moolenaar574950d2023-01-03 19:08:50 +0000471
472 def CheckCar()
473 assert_equal("make = def", c.GetMake())
474 assert_equal(5, c.GetAge())
475 enddef
476 CheckCar()
Bram Moolenaar590162c2022-12-24 21:24:06 +0000477 END
478 v9.CheckScriptSuccess(lines)
Bram Moolenaar6ef54712022-12-25 19:31:36 +0000479
480 lines =<< trim END
481 vim9script
482
483 class MyCar
484 this.make: string
485
486 def new(make_arg: string)
487 this.make = make_arg
488 enddef
489 endclass
490
491 var c = MyCar.new("abc")
492 var c = MyCar.new("def")
493 END
494 v9.CheckScriptFailure(lines, 'E1041:')
Bram Moolenaarb149d222023-01-24 13:03:37 +0000495
496 lines =<< trim END
497 vim9script
498
499 class Foo
500 this.x: list<number> = []
501
502 def Add(n: number): any
503 this.x->add(n)
504 return this
505 enddef
506 endclass
507
508 echo Foo.new().Add(1).Add(2).x
509 echo Foo.new().Add(1).Add(2)
510 .x
511 echo Foo.new().Add(1)
512 .Add(2).x
513 echo Foo.new()
514 .Add(1).Add(2).x
515 echo Foo.new()
516 .Add(1)
517 .Add(2)
518 .x
519 END
520 v9.CheckScriptSuccess(lines)
Bram Moolenaard505d172022-12-18 21:42:55 +0000521enddef
522
Bram Moolenaarbcf31ec2023-01-02 20:32:24 +0000523def Test_class_object_compare()
524 var class_lines =<< trim END
525 vim9script
526 class Item
527 this.nr = 0
528 this.name = 'xx'
529 endclass
530 END
531
532 # used at the script level and in a compiled function
533 var test_lines =<< trim END
534 var i1 = Item.new()
535 assert_equal(i1, i1)
536 assert_true(i1 is i1)
537 var i2 = Item.new()
538 assert_equal(i1, i2)
539 assert_false(i1 is i2)
540 var i3 = Item.new(0, 'xx')
541 assert_equal(i1, i3)
542
543 var io1 = Item.new(1, 'xx')
544 assert_notequal(i1, io1)
545 var io2 = Item.new(0, 'yy')
546 assert_notequal(i1, io2)
547 END
548
549 v9.CheckScriptSuccess(class_lines + test_lines)
Bram Moolenaar46ab9252023-01-03 14:01:21 +0000550 v9.CheckScriptSuccess(
551 class_lines + ['def Test()'] + test_lines + ['enddef', 'Test()'])
Bram Moolenaarbcf31ec2023-01-02 20:32:24 +0000552
553 for op in ['>', '>=', '<', '<=', '=~', '!~']
554 var op_lines = [
555 'var i1 = Item.new()',
556 'var i2 = Item.new()',
557 'echo i1 ' .. op .. ' i2',
558 ]
559 v9.CheckScriptFailure(class_lines + op_lines, 'E1153: Invalid operation for object')
Bram Moolenaar46ab9252023-01-03 14:01:21 +0000560 v9.CheckScriptFailure(class_lines
561 + ['def Test()'] + op_lines + ['enddef', 'Test()'], 'E1153: Invalid operation for object')
Bram Moolenaarbcf31ec2023-01-02 20:32:24 +0000562 endfor
563enddef
564
Bram Moolenaar6481acc2023-01-11 21:14:17 +0000565def Test_object_type()
566 var lines =<< trim END
567 vim9script
568
569 class One
570 this.one = 1
571 endclass
572 class Two
573 this.two = 2
574 endclass
575 class TwoMore extends Two
576 this.more = 9
577 endclass
578
579 var o: One = One.new()
580 var t: Two = Two.new()
581 var m: TwoMore = TwoMore.new()
582 var tm: Two = TwoMore.new()
583
584 t = m
585 END
586 v9.CheckScriptSuccess(lines)
587
588 lines =<< trim END
589 vim9script
590
591 class One
592 this.one = 1
593 endclass
594 class Two
595 this.two = 2
596 endclass
597
598 var o: One = Two.new()
599 END
600 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object<One> but got object<Two>')
Bram Moolenaara94bd9d2023-01-12 15:01:32 +0000601
602 lines =<< trim END
603 vim9script
604
605 interface One
606 def GetMember(): number
607 endinterface
608 class Two implements One
609 this.one = 1
610 def GetMember(): number
611 return this.one
612 enddef
613 endclass
614
615 var o: One = Two.new(5)
616 assert_equal(5, o.GetMember())
617 END
618 v9.CheckScriptSuccess(lines)
Bram Moolenaar450c7a92023-01-16 16:39:37 +0000619
620 lines =<< trim END
621 vim9script
622
623 class Num
624 this.n: number = 0
625 endclass
626
627 def Ref(name: string): func(Num): Num
628 return (arg: Num): Num => {
629 return eval(name)(arg)
630 }
631 enddef
632
633 const Fn = Ref('Double')
634 var Double = (m: Num): Num => Num.new(m.n * 2)
635
636 echo Fn(Num.new(4))
637 END
638 v9.CheckScriptSuccess(lines)
Bram Moolenaar6481acc2023-01-11 21:14:17 +0000639enddef
640
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000641def Test_class_member()
642 # check access rules
Bram Moolenaard505d172022-12-18 21:42:55 +0000643 var lines =<< trim END
644 vim9script
645 class TextPos
646 this.lnum = 1
647 this.col = 1
648 static counter = 0
Bram Moolenaar9f2d97e2022-12-31 19:01:02 +0000649 static _secret = 7
650 public static anybody = 42
Bram Moolenaard505d172022-12-18 21:42:55 +0000651
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000652 static def AddToCounter(nr: number)
Bram Moolenaard505d172022-12-18 21:42:55 +0000653 counter += nr
654 enddef
655 endclass
656
657 assert_equal(0, TextPos.counter)
658 TextPos.AddToCounter(3)
659 assert_equal(3, TextPos.counter)
Bram Moolenaarf54cedd2022-12-23 17:56:27 +0000660 assert_fails('echo TextPos.noSuchMember', 'E1338:')
Bram Moolenaar94722c52023-01-28 19:19:03 +0000661
Bram Moolenaar3259ff32023-01-04 18:54:09 +0000662 def GetCounter(): number
663 return TextPos.counter
664 enddef
665 assert_equal(3, GetCounter())
Bram Moolenaard505d172022-12-18 21:42:55 +0000666
Bram Moolenaarf54cedd2022-12-23 17:56:27 +0000667 assert_fails('TextPos.noSuchMember = 2', 'E1337:')
Bram Moolenaar9f2d97e2022-12-31 19:01:02 +0000668 assert_fails('TextPos.counter = 5', 'E1335:')
669 assert_fails('TextPos.counter += 5', 'E1335:')
670
671 assert_fails('echo TextPos._secret', 'E1333:')
672 assert_fails('TextPos._secret = 8', 'E1333:')
673
674 assert_equal(42, TextPos.anybody)
675 TextPos.anybody = 12
676 assert_equal(12, TextPos.anybody)
677 TextPos.anybody += 5
678 assert_equal(17, TextPos.anybody)
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000679 END
680 v9.CheckScriptSuccess(lines)
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000681
Bram Moolenaar4cae8452023-01-15 15:51:48 +0000682 # example in the help
683 lines =<< trim END
684 vim9script
685 class OtherThing
686 this.size: number
687 static totalSize: number
688
689 def new(this.size)
690 totalSize += this.size
691 enddef
692 endclass
693 assert_equal(0, OtherThing.totalSize)
694 var to3 = OtherThing.new(3)
695 assert_equal(3, OtherThing.totalSize)
696 var to7 = OtherThing.new(7)
697 assert_equal(10, OtherThing.totalSize)
698 END
699 v9.CheckScriptSuccess(lines)
700
Bram Moolenaar62a69232023-01-24 15:07:04 +0000701 # access private member in lambda
702 lines =<< trim END
703 vim9script
704
705 class Foo
706 this._x: number = 0
707
708 def Add(n: number): number
709 const F = (): number => this._x + n
710 return F()
711 enddef
712 endclass
713
714 var foo = Foo.new()
715 assert_equal(5, foo.Add(5))
716 END
717 v9.CheckScriptSuccess(lines)
718
Bram Moolenaar6acf7572023-01-01 19:53:30 +0000719 # check shadowing
720 lines =<< trim END
721 vim9script
722
723 class Some
724 static count = 0
725 def Method(count: number)
726 echo count
727 enddef
728 endclass
729
730 var s = Some.new()
731 s.Method(7)
732 END
733 v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: count')
734
735 lines =<< trim END
736 vim9script
737
738 class Some
739 static count = 0
740 def Method(arg: number)
741 var count = 3
742 echo arg count
743 enddef
744 endclass
745
746 var s = Some.new()
747 s.Method(7)
748 END
749 v9.CheckScriptFailure(lines, 'E1341: Variable already declared in the class: count')
Bram Moolenaar3d473ee2022-12-14 20:59:32 +0000750enddef
751
Bram Moolenaarcf760d52023-01-05 13:16:04 +0000752func Test_class_garbagecollect()
753 let lines =<< trim END
754 vim9script
755
756 class Point
757 this.p = [2, 3]
758 static pl = ['a', 'b']
759 static pd = {a: 'a', b: 'b'}
760 endclass
761
762 echo Point.pl Point.pd
763 call test_garbagecollect_now()
764 echo Point.pl Point.pd
765 END
766 call v9.CheckScriptSuccess(lines)
767endfunc
768
Bram Moolenaar6bafdd42023-01-01 12:58:33 +0000769def Test_class_function()
770 var lines =<< trim END
771 vim9script
772 class Value
773 this.value = 0
774 static objects = 0
775
776 def new(v: number)
777 this.value = v
778 ++objects
779 enddef
780
781 static def GetCount(): number
782 return objects
783 enddef
784 endclass
785
786 assert_equal(0, Value.GetCount())
787 var v1 = Value.new(2)
788 assert_equal(1, Value.GetCount())
789 var v2 = Value.new(7)
790 assert_equal(2, Value.GetCount())
791 END
792 v9.CheckScriptSuccess(lines)
793enddef
794
Bram Moolenaar91c9d6d2022-12-14 17:30:37 +0000795def Test_class_object_to_string()
796 var lines =<< trim END
797 vim9script
798 class TextPosition
799 this.lnum = 1
800 this.col = 22
801 endclass
802
803 assert_equal("class TextPosition", string(TextPosition))
804
805 var pos = TextPosition.new()
806 assert_equal("object of TextPosition {lnum: 1, col: 22}", string(pos))
807 END
808 v9.CheckScriptSuccess(lines)
809enddef
Bram Moolenaar74e12742022-12-13 21:14:28 +0000810
Bram Moolenaar554d0312023-01-05 19:59:18 +0000811def Test_interface_basics()
812 var lines =<< trim END
813 vim9script
814 interface Something
815 this.value: string
816 static count: number
817 def GetCount(): number
818 endinterface
819 END
820 v9.CheckScriptSuccess(lines)
821
822 lines =<< trim END
823 interface SomethingWrong
824 static count = 7
825 endinterface
826 END
827 v9.CheckScriptFailure(lines, 'E1342:')
828
829 lines =<< trim END
830 vim9script
831
832 interface Some
833 static count: number
834 def Method(count: number)
835 endinterface
836 END
Bram Moolenaard40f00c2023-01-13 17:36:49 +0000837 v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: count')
838
839 lines =<< trim END
840 vim9script
841
842 interface Some
843 this.value: number
844 def Method(value: number)
845 endinterface
846 END
847 v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: value')
Bram Moolenaar554d0312023-01-05 19:59:18 +0000848
849 lines =<< trim END
850 vim9script
851 interface somethingWrong
852 static count = 7
853 endinterface
854 END
855 v9.CheckScriptFailure(lines, 'E1343: Interface name must start with an uppercase letter: somethingWrong')
856
857 lines =<< trim END
858 vim9script
859 interface SomethingWrong
860 this.value: string
861 static count = 7
862 def GetCount(): number
863 endinterface
864 END
865 v9.CheckScriptFailure(lines, 'E1344:')
866
867 lines =<< trim END
868 vim9script
869 interface SomethingWrong
870 this.value: string
871 static count: number
872 def GetCount(): number
873 return 5
874 enddef
875 endinterface
876 END
877 v9.CheckScriptFailure(lines, 'E1345: Not a valid command in an interface: return 5')
Bram Moolenaar53f54e42023-01-26 20:36:56 +0000878
879 lines =<< trim END
880 vim9script
881 export interface EnterExit
882 def Enter(): void
883 def Exit(): void
884 endinterface
885 END
886 writefile(lines, 'XdefIntf.vim', 'D')
887
888 lines =<< trim END
889 vim9script
890 import './XdefIntf.vim' as defIntf
891 export def With(ee: defIntf.EnterExit, F: func)
892 ee.Enter()
893 try
894 F()
895 finally
896 ee.Exit()
897 endtry
898 enddef
899 END
900 v9.CheckScriptSuccess(lines)
Bram Moolenaar657aea72023-01-27 13:16:19 +0000901
902 var imported =<< trim END
903 vim9script
904 export abstract class EnterExit
905 def Enter(): void
906 enddef
907 def Exit(): void
908 enddef
909 endclass
910 END
911 writefile(imported, 'XdefIntf2.vim', 'D')
912
913 lines[1] = " import './XdefIntf2.vim' as defIntf"
914 v9.CheckScriptSuccess(lines)
Bram Moolenaar554d0312023-01-05 19:59:18 +0000915enddef
916
Bram Moolenaar94674f22023-01-06 18:42:20 +0000917def Test_class_implements_interface()
918 var lines =<< trim END
919 vim9script
920
921 interface Some
922 static count: number
923 def Method(nr: number)
924 endinterface
925
926 class SomeImpl implements Some
927 static count: number
928 def Method(nr: number)
929 echo nr
930 enddef
931 endclass
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000932
933 interface Another
934 this.member: string
935 endinterface
936
937 class SomeImpl implements Some, Another
938 this.member = 'abc'
939 static count: number
940 def Method(nr: number)
941 echo nr
942 enddef
943 endclass
944
Bram Moolenaar94674f22023-01-06 18:42:20 +0000945 END
946 v9.CheckScriptSuccess(lines)
947
948 lines =<< trim END
949 vim9script
950
951 interface Some
952 static counter: number
Bram Moolenaardf8f9472023-01-07 14:51:03 +0000953 endinterface
954
955 class SomeImpl implements Some implements Some
956 static count: number
957 endclass
958 END
959 v9.CheckScriptFailure(lines, 'E1350:')
960
961 lines =<< trim END
962 vim9script
963
964 interface Some
965 static counter: number
966 endinterface
967
968 class SomeImpl implements Some, Some
969 static count: number
970 endclass
971 END
972 v9.CheckScriptFailure(lines, 'E1351: Duplicate interface after "implements": Some')
973
974 lines =<< trim END
975 vim9script
976
977 interface Some
978 static counter: number
Bram Moolenaar94674f22023-01-06 18:42:20 +0000979 def Method(nr: number)
980 endinterface
981
982 class SomeImpl implements Some
983 static count: number
984 def Method(nr: number)
985 echo nr
986 enddef
987 endclass
988 END
989 v9.CheckScriptFailure(lines, 'E1348: Member "counter" of interface "Some" not implemented')
990
991 lines =<< trim END
992 vim9script
993
994 interface Some
995 static count: number
996 def Methods(nr: number)
997 endinterface
998
999 class SomeImpl implements Some
1000 static count: number
1001 def Method(nr: number)
1002 echo nr
1003 enddef
1004 endclass
1005 END
1006 v9.CheckScriptFailure(lines, 'E1349: Function "Methods" of interface "Some" not implemented')
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001007
1008 # Check different order of members in class and interface works.
1009 lines =<< trim END
1010 vim9script
1011
1012 interface Result
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001013 public this.label: string
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001014 this.errpos: number
1015 endinterface
1016
1017 # order of members is opposite of interface
1018 class Failure implements Result
1019 this.errpos: number = 42
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001020 public this.label: string = 'label'
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001021 endclass
1022
1023 def Test()
1024 var result: Result = Failure.new()
1025
1026 assert_equal('label', result.label)
1027 assert_equal(42, result.errpos)
Bram Moolenaarf7d1c6e2023-01-16 20:47:57 +00001028
1029 result.label = 'different'
1030 assert_equal('different', result.label)
1031 assert_equal(42, result.errpos)
Bram Moolenaar29ac5df2023-01-16 19:43:47 +00001032 enddef
1033
1034 Test()
1035 END
1036 v9.CheckScriptSuccess(lines)
Bram Moolenaar94674f22023-01-06 18:42:20 +00001037enddef
1038
Bram Moolenaard0200c82023-01-28 15:19:40 +00001039def Test_call_interface_method()
1040 var lines =<< trim END
1041 vim9script
1042 interface Base
1043 def Enter(): void
1044 endinterface
1045
1046 class Child implements Base
1047 def Enter(): void
1048 g:result ..= 'child'
1049 enddef
1050 endclass
1051
1052 def F(obj: Base)
1053 obj.Enter()
1054 enddef
1055
1056 g:result = ''
1057 F(Child.new())
1058 assert_equal('child', g:result)
1059 unlet g:result
1060 END
1061 v9.CheckScriptSuccess(lines)
1062
1063 lines =<< trim END
1064 vim9script
1065 class Base
1066 def Enter(): void
1067 g:result ..= 'base'
1068 enddef
1069 endclass
1070
1071 class Child extends Base
1072 def Enter(): void
1073 g:result ..= 'child'
1074 enddef
1075 endclass
1076
1077 def F(obj: Base)
1078 obj.Enter()
1079 enddef
1080
1081 g:result = ''
1082 F(Child.new())
1083 assert_equal('child', g:result)
1084 unlet g:result
1085 END
1086 v9.CheckScriptSuccess(lines)
Bram Moolenaarb8bebd02023-01-30 20:24:23 +00001087
Bram Moolenaar7a1bdae2023-02-04 15:45:27 +00001088 # method of interface returns a value
1089 lines =<< trim END
1090 vim9script
1091 interface Base
1092 def Enter(): string
1093 endinterface
1094
1095 class Child implements Base
1096 def Enter(): string
1097 g:result ..= 'child'
1098 return "/resource"
1099 enddef
1100 endclass
1101
1102 def F(obj: Base)
1103 var r = obj.Enter()
1104 g:result ..= r
1105 enddef
1106
1107 g:result = ''
1108 F(Child.new())
1109 assert_equal('child/resource', g:result)
1110 unlet g:result
1111 END
1112 v9.CheckScriptSuccess(lines)
1113
1114 lines =<< trim END
1115 vim9script
1116 class Base
1117 def Enter(): string
1118 return null_string
1119 enddef
1120 endclass
1121
1122 class Child extends Base
1123 def Enter(): string
1124 g:result ..= 'child'
1125 return "/resource"
1126 enddef
1127 endclass
1128
1129 def F(obj: Base)
1130 var r = obj.Enter()
1131 g:result ..= r
1132 enddef
1133
1134 g:result = ''
1135 F(Child.new())
1136 assert_equal('child/resource', g:result)
1137 unlet g:result
1138 END
1139 v9.CheckScriptSuccess(lines)
1140
1141
Bram Moolenaarb8bebd02023-01-30 20:24:23 +00001142 # No class that implements the interface.
1143 lines =<< trim END
1144 vim9script
1145
1146 interface IWithEE
1147 def Enter(): any
1148 def Exit(): void
1149 endinterface
1150
1151 def With1(ee: IWithEE, F: func)
1152 var r = ee.Enter()
1153 enddef
1154
1155 defcompile
1156 END
1157 v9.CheckScriptSuccess(lines)
Bram Moolenaard0200c82023-01-28 15:19:40 +00001158enddef
1159
Bram Moolenaareca2c5f2023-01-07 12:08:41 +00001160def Test_class_used_as_type()
1161 var lines =<< trim END
1162 vim9script
1163
1164 class Point
1165 this.x = 0
1166 this.y = 0
1167 endclass
1168
1169 var p: Point
1170 p = Point.new(2, 33)
1171 assert_equal(2, p.x)
1172 assert_equal(33, p.y)
1173 END
1174 v9.CheckScriptSuccess(lines)
1175
1176 lines =<< trim END
1177 vim9script
1178
1179 interface HasX
1180 this.x: number
1181 endinterface
1182
1183 class Point implements HasX
1184 this.x = 0
1185 this.y = 0
1186 endclass
1187
1188 var p: Point
1189 p = Point.new(2, 33)
1190 var hx = p
1191 assert_equal(2, hx.x)
1192 END
1193 v9.CheckScriptSuccess(lines)
1194
1195 lines =<< trim END
1196 vim9script
1197
1198 class Point
1199 this.x = 0
1200 this.y = 0
1201 endclass
1202
1203 var p: Point
1204 p = 'text'
1205 END
Bram Moolenaar6481acc2023-01-11 21:14:17 +00001206 v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object<Point> but got string')
Bram Moolenaareca2c5f2023-01-07 12:08:41 +00001207enddef
1208
Bram Moolenaar83677162023-01-08 19:54:10 +00001209def Test_class_extends()
1210 var lines =<< trim END
1211 vim9script
1212 class Base
1213 this.one = 1
1214 def GetOne(): number
1215 return this.one
1216 enddef
1217 endclass
1218 class Child extends Base
1219 this.two = 2
1220 def GetTotal(): number
1221 return this.one + this.two
1222 enddef
1223 endclass
1224 var o = Child.new()
1225 assert_equal(1, o.one)
1226 assert_equal(2, o.two)
1227 assert_equal(1, o.GetOne())
1228 assert_equal(3, o.GetTotal())
1229 END
1230 v9.CheckScriptSuccess(lines)
1231
1232 lines =<< trim END
1233 vim9script
1234 class Base
1235 this.one = 1
1236 endclass
1237 class Child extends Base
1238 this.two = 2
1239 endclass
1240 var o = Child.new(3, 44)
1241 assert_equal(3, o.one)
1242 assert_equal(44, o.two)
1243 END
1244 v9.CheckScriptSuccess(lines)
1245
1246 lines =<< trim END
1247 vim9script
1248 class Base
1249 this.one = 1
1250 endclass
1251 class Child extends Base extends Base
1252 this.two = 2
1253 endclass
1254 END
1255 v9.CheckScriptFailure(lines, 'E1352: Duplicate "extends"')
1256
1257 lines =<< trim END
1258 vim9script
1259 class Child extends BaseClass
1260 this.two = 2
1261 endclass
1262 END
1263 v9.CheckScriptFailure(lines, 'E1353: Class name not found: BaseClass')
1264
1265 lines =<< trim END
1266 vim9script
1267 var SomeVar = 99
1268 class Child extends SomeVar
1269 this.two = 2
1270 endclass
1271 END
1272 v9.CheckScriptFailure(lines, 'E1354: Cannot extend SomeVar')
Bram Moolenaar58b40092023-01-11 15:59:05 +00001273
1274 lines =<< trim END
1275 vim9script
1276 class Base
1277 this.name: string
1278 def ToString(): string
1279 return this.name
1280 enddef
1281 endclass
1282
1283 class Child extends Base
1284 this.age: number
1285 def ToString(): string
1286 return super.ToString() .. ': ' .. this.age
1287 enddef
1288 endclass
1289
1290 var o = Child.new('John', 42)
1291 assert_equal('John: 42', o.ToString())
1292 END
1293 v9.CheckScriptSuccess(lines)
Bram Moolenaar6aa09372023-01-11 17:59:38 +00001294
1295 lines =<< trim END
1296 vim9script
1297 class Child
1298 this.age: number
1299 def ToString(): number
1300 return this.age
1301 enddef
1302 def ToString(): string
1303 return this.age
1304 enddef
1305 endclass
1306 END
1307 v9.CheckScriptFailure(lines, 'E1355: Duplicate function: ToString')
1308
1309 lines =<< trim END
1310 vim9script
1311 class Child
1312 this.age: number
1313 def ToString(): string
1314 return super .ToString() .. ': ' .. this.age
1315 enddef
1316 endclass
1317 var o = Child.new(42)
1318 echo o.ToString()
1319 END
1320 v9.CheckScriptFailure(lines, 'E1356:')
1321
1322 lines =<< trim END
1323 vim9script
1324 class Base
1325 this.name: string
1326 def ToString(): string
1327 return this.name
1328 enddef
1329 endclass
1330
1331 var age = 42
1332 def ToString(): string
1333 return super.ToString() .. ': ' .. age
1334 enddef
1335 echo ToString()
1336 END
1337 v9.CheckScriptFailure(lines, 'E1357:')
1338
1339 lines =<< trim END
1340 vim9script
1341 class Child
1342 this.age: number
1343 def ToString(): string
1344 return super.ToString() .. ': ' .. this.age
1345 enddef
1346 endclass
1347 var o = Child.new(42)
1348 echo o.ToString()
1349 END
1350 v9.CheckScriptFailure(lines, 'E1358:')
Bram Moolenaar6481acc2023-01-11 21:14:17 +00001351
1352 lines =<< trim END
1353 vim9script
1354 class Base
1355 this.name: string
1356 static def ToString(): string
1357 return 'Base class'
1358 enddef
1359 endclass
1360
1361 class Child extends Base
1362 this.age: number
1363 def ToString(): string
1364 return Base.ToString() .. ': ' .. this.age
1365 enddef
1366 endclass
1367
1368 var o = Child.new('John', 42)
1369 assert_equal('Base class: 42', o.ToString())
1370 END
1371 v9.CheckScriptSuccess(lines)
Bram Moolenaar4cae8452023-01-15 15:51:48 +00001372
1373 lines =<< trim END
1374 vim9script
1375 class Base
1376 this.value = 1
1377 def new(init: number)
1378 this.value = number + 1
1379 enddef
1380 endclass
1381 class Child extends Base
1382 def new()
1383 this.new(3)
1384 enddef
1385 endclass
1386 var c = Child.new()
1387 END
1388 v9.CheckScriptFailure(lines, 'E1325: Method not found on class "Child": new(')
Bram Moolenaarae3205a2023-01-15 20:49:00 +00001389
1390 # base class with more than one object member
1391 lines =<< trim END
1392 vim9script
1393
1394 class Result
1395 this.success: bool
1396 this.value: any = null
1397 endclass
1398
1399 class Success extends Result
1400 def new(this.value = v:none)
1401 this.success = true
1402 enddef
1403 endclass
1404
1405 var v = Success.new('asdf')
1406 assert_equal("object of Success {success: true, value: 'asdf'}", string(v))
1407 END
1408 v9.CheckScriptSuccess(lines)
Bram Moolenaar83677162023-01-08 19:54:10 +00001409enddef
1410
Bram Moolenaar094cf9f2023-02-10 15:52:25 +00001411def Test_using_base_class()
1412 var lines =<< trim END
1413 vim9script
1414
1415 class BaseEE
1416 def Enter(): any
1417 return null
1418 enddef
1419 def Exit(resource: any): void
1420 enddef
1421 endclass
1422
1423 class ChildEE extends BaseEE
1424 def Enter(): any
1425 return 42
1426 enddef
1427
1428 def Exit(resource: number): void
1429 g:result ..= '/exit'
1430 enddef
1431 endclass
1432
1433 def With(ee: BaseEE)
1434 var r = ee.Enter()
1435 try
1436 g:result ..= r
1437 finally
1438 g:result ..= '/finally'
1439 ee.Exit(r)
1440 endtry
1441 enddef
1442
1443 g:result = ''
1444 With(ChildEE.new())
1445 assert_equal('42/finally/exit', g:result)
1446 END
1447 v9.CheckScriptSuccess(lines)
1448 unlet g:result
1449enddef
1450
1451
Bram Moolenaara86655a2023-01-12 17:06:27 +00001452def Test_class_import()
1453 var lines =<< trim END
1454 vim9script
1455 export class Animal
1456 this.kind: string
1457 this.name: string
1458 endclass
1459 END
1460 writefile(lines, 'Xanimal.vim', 'D')
1461
1462 lines =<< trim END
1463 vim9script
1464 import './Xanimal.vim' as animal
1465
1466 var a: animal.Animal
1467 a = animal.Animal.new('fish', 'Eric')
1468 assert_equal('fish', a.kind)
1469 assert_equal('Eric', a.name)
Bram Moolenaar40594002023-01-12 20:04:51 +00001470
1471 var b: animal.Animal = animal.Animal.new('cat', 'Garfield')
1472 assert_equal('cat', b.kind)
1473 assert_equal('Garfield', b.name)
Bram Moolenaara86655a2023-01-12 17:06:27 +00001474 END
1475 v9.CheckScriptSuccess(lines)
1476enddef
1477
Bram Moolenaar24a8d062023-01-14 13:12:06 +00001478def Test_abstract_class()
1479 var lines =<< trim END
1480 vim9script
1481 abstract class Base
1482 this.name: string
1483 endclass
1484 class Person extends Base
1485 this.age: number
1486 endclass
1487 var p: Base = Person.new('Peter', 42)
1488 assert_equal('Peter', p.name)
1489 assert_equal(42, p.age)
1490 END
1491 v9.CheckScriptSuccess(lines)
1492
1493 lines =<< trim END
1494 vim9script
1495 abstract class Base
1496 this.name: string
1497 endclass
1498 class Person extends Base
1499 this.age: number
1500 endclass
1501 var p = Base.new('Peter')
1502 END
1503 v9.CheckScriptFailure(lines, 'E1325: Method not found on class "Base": new(')
1504
1505 lines =<< trim END
1506 abstract class Base
1507 this.name: string
1508 endclass
1509 END
1510 v9.CheckScriptFailure(lines, 'E1316:')
1511enddef
1512
Bram Moolenaar486fc252023-01-18 14:51:07 +00001513def Test_closure_in_class()
1514 var lines =<< trim END
1515 vim9script
1516
1517 class Foo
1518 this.y: list<string> = ['B']
1519
1520 def new()
1521 g:result = filter(['A', 'B'], (_, v) => index(this.y, v) == -1)
1522 enddef
1523 endclass
1524
1525 Foo.new()
1526 assert_equal(['A'], g:result)
1527 END
1528 v9.CheckScriptSuccess(lines)
1529enddef
1530
Bram Moolenaar8dbab1d2023-01-27 20:14:02 +00001531def Test_defer_with_object()
1532 var lines =<< trim END
1533 vim9script
1534
1535 class CWithEE
1536 def Enter()
1537 g:result ..= "entered/"
1538 enddef
1539 def Exit()
1540 g:result ..= "exited"
1541 enddef
1542 endclass
1543
1544 def With(ee: CWithEE, F: func)
1545 ee.Enter()
1546 defer ee.Exit()
1547 F()
1548 enddef
1549
1550 g:result = ''
1551 var obj = CWithEE.new()
1552 obj->With(() => {
1553 g:result ..= "called/"
1554 })
1555 assert_equal('entered/called/exited', g:result)
1556 END
1557 v9.CheckScriptSuccess(lines)
1558 unlet g:result
Bram Moolenaar313e4722023-02-08 20:55:27 +00001559
1560 lines =<< trim END
1561 vim9script
1562
1563 class BaseWithEE
1564 def Enter()
1565 g:result ..= "entered-base/"
1566 enddef
1567 def Exit()
1568 g:result ..= "exited-base"
1569 enddef
1570 endclass
1571
1572 class CWithEE extends BaseWithEE
1573 def Enter()
1574 g:result ..= "entered-child/"
1575 enddef
1576 def Exit()
1577 g:result ..= "exited-child"
1578 enddef
1579 endclass
1580
1581 def With(ee: BaseWithEE, F: func)
1582 ee.Enter()
1583 defer ee.Exit()
1584 F()
1585 enddef
1586
1587 g:result = ''
1588 var obj = CWithEE.new()
1589 obj->With(() => {
1590 g:result ..= "called/"
1591 })
1592 assert_equal('entered-child/called/exited-child', g:result)
1593 END
1594 v9.CheckScriptSuccess(lines)
1595 unlet g:result
Bram Moolenaar8dbab1d2023-01-27 20:14:02 +00001596enddef
1597
Bram Moolenaar00b28d62022-12-08 15:32:33 +00001598
1599" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker