1" Test the :disassemble command, and compilation as a side effect
2
3source check.vim
4
5func NotCompiled()
6  echo "not"
7endfunc
8
9let s:scriptvar = 4
10let g:globalvar = 'g'
11let b:buffervar = 'b'
12let w:windowvar = 'w'
13let t:tabpagevar = 't'
14
15def s:ScriptFuncLoad(arg: string)
16  let local = 1
17  buffers
18  echo arg
19  echo local
20  echo &lines
21  echo v:version
22  echo s:scriptvar
23  echo g:globalvar
24  echo get(g:, "global")
25  echo b:buffervar
26  echo get(b:, "buffer")
27  echo w:windowvar
28  echo get(w:, "window")
29  echo t:tabpagevar
30  echo get(t:, "tab")
31  echo &tabstop
32  echo $ENVVAR
33  echo @z
34enddef
35
36def Test_disassemble_load()
37  assert_fails('disass NoFunc', 'E1061:')
38  assert_fails('disass NotCompiled', 'E1062:')
39  assert_fails('disass', 'E471:')
40  assert_fails('disass [', 'E475:')
41  assert_fails('disass 234', 'E129:')
42  assert_fails('disass <XX>foo', 'E129:')
43
44  let res = execute('disass s:ScriptFuncLoad')
45  assert_match('<SNR>\d*_ScriptFuncLoad.*' ..
46        'buffers.*' ..
47        ' EXEC \+buffers.*' ..
48        ' LOAD arg\[-1\].*' ..
49        ' LOAD $0.*' ..
50        ' LOADOPT &lines.*' ..
51        ' LOADV v:version.*' ..
52        ' LOADS s:scriptvar from .*test_vim9_disassemble.vim.*' ..
53        ' LOADG g:globalvar.*' ..
54        'echo get(g:, "global")\_s*' ..
55        '\d\+ LOAD g:\_s*' ..
56        '\d\+ PUSHS "global"\_s*' ..
57        '\d\+ BCALL get(argc 2).*' ..
58        ' LOADB b:buffervar.*' ..
59        'echo get(b:, "buffer")\_s*' ..
60        '\d\+ LOAD b:\_s*' ..
61        '\d\+ PUSHS "buffer"\_s*' ..
62        '\d\+ BCALL get(argc 2).*' ..
63        ' LOADW w:windowvar.*' ..
64        'echo get(w:, "window")\_s*' ..
65        '\d\+ LOAD w:\_s*' ..
66        '\d\+ PUSHS "window"\_s*' ..
67        '\d\+ BCALL get(argc 2).*' ..
68        ' LOADT t:tabpagevar.*' ..
69        'echo get(t:, "tab")\_s*' ..
70        '\d\+ LOAD t:\_s*' ..
71        '\d\+ PUSHS "tab"\_s*' ..
72        '\d\+ BCALL get(argc 2).*' ..
73        ' LOADENV $ENVVAR.*' ..
74        ' LOADREG @z.*',
75        res)
76enddef
77
78def s:EditExpand()
79  let filename = "file"
80  let filenr = 123
81  edit the`=filename``=filenr`.txt
82enddef
83
84def Test_disassemble_exec_expr()
85  let res = execute('disass s:EditExpand')
86  assert_match('<SNR>\d*_EditExpand.*' ..
87        ' let filename = "file".*' ..
88        '\d PUSHS "file".*' ..
89        '\d STORE $0.*' ..
90        ' let filenr = 123.*' ..
91        '\d STORE 123 in $1.*' ..
92        ' edit the`=filename``=filenr`.txt.*' ..
93        '\d PUSHS "edit the".*' ..
94        '\d LOAD $0.*' ..
95        '\d LOAD $1.*' ..
96        '\d 2STRING stack\[-1\].*' ..
97        '\d PUSHS ".txt".*' ..
98        '\d EXECCONCAT 4.*' ..
99        '\d PUSHNR 0.*' ..
100        '\d RETURN',
101        res)
102enddef
103
104def s:ScriptFuncPush()
105  let localbool = true
106  let localspec = v:none
107  let localblob = 0z1234
108  if has('float')
109    let localfloat = 1.234
110  endif
111enddef
112
113def Test_disassemble_push()
114  let res = execute('disass s:ScriptFuncPush')
115  assert_match('<SNR>\d*_ScriptFuncPush.*' ..
116        'localbool = true.*' ..
117        ' PUSH v:true.*' ..
118        'localspec = v:none.*' ..
119        ' PUSH v:none.*' ..
120        'localblob = 0z1234.*' ..
121        ' PUSHBLOB 0z1234.*',
122        res)
123  if has('float')
124    assert_match('<SNR>\d*_ScriptFuncPush.*' ..
125          'localfloat = 1.234.*' ..
126          ' PUSHF 1.234.*',
127          res)
128  endif
129enddef
130
131def s:ScriptFuncStore()
132  let localnr = 1
133  localnr = 2
134  let localstr = 'abc'
135  localstr = 'xyz'
136  v:char = 'abc'
137  s:scriptvar = 'sv'
138  g:globalvar = 'gv'
139  b:buffervar = 'bv'
140  w:windowvar = 'wv'
141  t:tabpagevar = 'tv'
142  &tabstop = 8
143  $ENVVAR = 'ev'
144  @z = 'rv'
145enddef
146
147def Test_disassemble_store()
148  let res = execute('disass s:ScriptFuncStore')
149  assert_match('<SNR>\d*_ScriptFuncStore.*' ..
150        'let localnr = 1.*' ..
151        'localnr = 2.*' ..
152        ' STORE 2 in $0.*' ..
153        'let localstr = ''abc''.*' ..
154        'localstr = ''xyz''.*' ..
155        ' STORE $1.*' ..
156        'v:char = ''abc''.*' ..
157        'STOREV v:char.*' ..
158        's:scriptvar = ''sv''.*' ..
159        ' STORES s:scriptvar in .*test_vim9_disassemble.vim.*' ..
160        'g:globalvar = ''gv''.*' ..
161        ' STOREG g:globalvar.*' ..
162        'b:buffervar = ''bv''.*' ..
163        ' STOREB b:buffervar.*' ..
164        'w:windowvar = ''wv''.*' ..
165        ' STOREW w:windowvar.*' ..
166        't:tabpagevar = ''tv''.*' ..
167        ' STORET t:tabpagevar.*' ..
168        '&tabstop = 8.*' ..
169        ' STOREOPT &tabstop.*' ..
170        '$ENVVAR = ''ev''.*' ..
171        ' STOREENV $ENVVAR.*' ..
172        '@z = ''rv''.*' ..
173        ' STOREREG @z.*',
174        res)
175enddef
176
177def s:ScriptFuncStoreMember()
178  let locallist: list<number> = []
179  locallist[0] = 123
180  let localdict: dict<number> = {}
181  localdict["a"] = 456
182enddef
183
184def Test_disassemble_store_member()
185  let res = execute('disass s:ScriptFuncStoreMember')
186  assert_match('<SNR>\d*_ScriptFuncStoreMember\_s*' ..
187        'let locallist: list<number> = []\_s*' ..
188        '\d NEWLIST size 0\_s*' ..
189        '\d STORE $0\_s*' ..
190        'locallist\[0\] = 123\_s*' ..
191        '\d PUSHNR 123\_s*' ..
192        '\d PUSHNR 0\_s*' ..
193        '\d LOAD $0\_s*' ..
194        '\d STORELIST\_s*' ..
195        'let localdict: dict<number> = {}\_s*' ..
196        '\d NEWDICT size 0\_s*' ..
197        '\d STORE $1\_s*' ..
198        'localdict\["a"\] = 456\_s*' ..
199        '\d\+ PUSHNR 456\_s*' ..
200        '\d\+ PUSHS "a"\_s*' ..
201        '\d\+ LOAD $1\_s*' ..
202        '\d\+ STOREDICT\_s*' ..
203        '\d\+ PUSHNR 0\_s*' ..
204        '\d\+ RETURN',
205        res)
206enddef
207
208def s:ListAssign()
209  let x: string
210  let y: string
211  let l: list<any>
212  [x, y; l] = g:stringlist
213enddef
214
215def Test_disassemble_list_assign()
216  let res = execute('disass s:ListAssign')
217  assert_match('<SNR>\d*_ListAssign\_s*' ..
218        'let x: string\_s*' ..
219        '\d PUSHS "\[NULL\]"\_s*' ..
220        '\d STORE $0\_s*' ..
221        'let y: string\_s*' ..
222        '\d PUSHS "\[NULL\]"\_s*' ..
223        '\d STORE $1\_s*' ..
224        'let l: list<any>\_s*' ..
225        '\d NEWLIST size 0\_s*' ..
226        '\d STORE $2\_s*' ..
227        '\[x, y; l\] = g:stringlist\_s*' ..
228        '\d LOADG g:stringlist\_s*' ..
229        '\d CHECKTYPE list stack\[-1\]\_s*' ..
230        '\d CHECKLEN >= 2\_s*' ..
231        '\d\+ ITEM 0\_s*' ..
232        '\d\+ CHECKTYPE string stack\[-1\]\_s*' ..
233        '\d\+ STORE $0\_s*' ..
234        '\d\+ ITEM 1\_s*' ..
235        '\d\+ CHECKTYPE string stack\[-1\]\_s*' ..
236        '\d\+ STORE $1\_s*' ..
237        '\d\+ SLICE 2\_s*' ..
238        '\d\+ STORE $2\_s*' ..
239        '\d\+ PUSHNR 0\_s*' ..
240        '\d\+ RETURN',
241        res)
242enddef
243
244def s:ScriptFuncUnlet()
245  g:somevar = "value"
246  unlet g:somevar
247  unlet! g:somevar
248  unlet $SOMEVAR
249enddef
250
251def Test_disassemble_unlet()
252  let res = execute('disass s:ScriptFuncUnlet')
253  assert_match('<SNR>\d*_ScriptFuncUnlet\_s*' ..
254        'g:somevar = "value"\_s*' ..
255        '\d PUSHS "value"\_s*' ..
256        '\d STOREG g:somevar\_s*' ..
257        'unlet g:somevar\_s*' ..
258        '\d UNLET g:somevar\_s*' ..
259        'unlet! g:somevar\_s*' ..
260        '\d UNLET! g:somevar\_s*' ..
261        'unlet $SOMEVAR\_s*' ..
262        '\d UNLETENV $SOMEVAR\_s*',
263        res)
264enddef
265
266def s:ScriptFuncTry()
267  try
268    echo "yes"
269  catch /fail/
270    echo "no"
271  finally
272    throw "end"
273  endtry
274enddef
275
276def Test_disassemble_try()
277  let res = execute('disass s:ScriptFuncTry')
278  assert_match('<SNR>\d*_ScriptFuncTry\_s*' ..
279        'try\_s*' ..
280        '\d TRY catch -> \d\+, finally -> \d\+\_s*' ..
281        'echo "yes"\_s*' ..
282        '\d PUSHS "yes"\_s*' ..
283        '\d ECHO 1\_s*' ..
284        'catch /fail/\_s*' ..
285        '\d JUMP -> \d\+\_s*' ..
286        '\d PUSH v:exception\_s*' ..
287        '\d PUSHS "fail"\_s*' ..
288        '\d COMPARESTRING =\~\_s*' ..
289        '\d JUMP_IF_FALSE -> \d\+\_s*' ..
290        '\d CATCH\_s*' ..
291        'echo "no"\_s*' ..
292        '\d\+ PUSHS "no"\_s*' ..
293        '\d\+ ECHO 1\_s*' ..
294        'finally\_s*' ..
295        'throw "end"\_s*' ..
296        '\d\+ PUSHS "end"\_s*' ..
297        '\d\+ THROW\_s*' ..
298        'endtry\_s*' ..
299        '\d\+ ENDTRY',
300        res)
301enddef
302
303def s:ScriptFuncNew()
304  let ll = [1, "two", 333]
305  let dd = #{one: 1, two: "val"}
306enddef
307
308def Test_disassemble_new()
309  let res = execute('disass s:ScriptFuncNew')
310  assert_match('<SNR>\d*_ScriptFuncNew\_s*' ..
311        'let ll = \[1, "two", 333\]\_s*' ..
312        '\d PUSHNR 1\_s*' ..
313        '\d PUSHS "two"\_s*' ..
314        '\d PUSHNR 333\_s*' ..
315        '\d NEWLIST size 3\_s*' ..
316        '\d STORE $0\_s*' ..
317        'let dd = #{one: 1, two: "val"}\_s*' ..
318        '\d PUSHS "one"\_s*' ..
319        '\d PUSHNR 1\_s*' ..
320        '\d PUSHS "two"\_s*' ..
321        '\d PUSHS "val"\_s*' ..
322        '\d NEWDICT size 2\_s*',
323        res)
324enddef
325
326def FuncWithArg(arg: any)
327  echo arg
328enddef
329
330func UserFunc()
331  echo 'nothing'
332endfunc
333
334func UserFuncWithArg(arg)
335  echo a:arg
336endfunc
337
338def s:ScriptFuncCall(): string
339  changenr()
340  char2nr("abc")
341  Test_disassemble_new()
342  FuncWithArg(343)
343  ScriptFuncNew()
344  s:ScriptFuncNew()
345  UserFunc()
346  UserFuncWithArg("foo")
347  let FuncRef = function("UserFunc")
348  FuncRef()
349  let FuncRefWithArg = function("UserFuncWithArg")
350  FuncRefWithArg("bar")
351  return "yes"
352enddef
353
354def Test_disassemble_call()
355  let res = execute('disass s:ScriptFuncCall')
356  assert_match('<SNR>\d\+_ScriptFuncCall\_s*' ..
357        'changenr()\_s*' ..
358        '\d BCALL changenr(argc 0)\_s*' ..
359        '\d DROP\_s*' ..
360        'char2nr("abc")\_s*' ..
361        '\d PUSHS "abc"\_s*' ..
362        '\d BCALL char2nr(argc 1)\_s*' ..
363        '\d DROP\_s*' ..
364        'Test_disassemble_new()\_s*' ..
365        '\d DCALL Test_disassemble_new(argc 0)\_s*' ..
366        '\d DROP\_s*' ..
367        'FuncWithArg(343)\_s*' ..
368        '\d\+ PUSHNR 343\_s*' ..
369        '\d\+ DCALL FuncWithArg(argc 1)\_s*' ..
370        '\d\+ DROP\_s*' ..
371        'ScriptFuncNew()\_s*' ..
372        '\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' ..
373        '\d\+ DROP\_s*' ..
374        's:ScriptFuncNew()\_s*' ..
375        '\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' ..
376        '\d\+ DROP\_s*' ..
377        'UserFunc()\_s*' ..
378        '\d\+ UCALL UserFunc(argc 0)\_s*' ..
379        '\d\+ DROP\_s*' ..
380        'UserFuncWithArg("foo")\_s*' ..
381        '\d\+ PUSHS "foo"\_s*' ..
382        '\d\+ UCALL UserFuncWithArg(argc 1)\_s*' ..
383        '\d\+ DROP\_s*' ..
384        'let FuncRef = function("UserFunc")\_s*' ..
385        '\d\+ PUSHS "UserFunc"\_s*' ..
386        '\d\+ BCALL function(argc 1)\_s*' ..
387        '\d\+ STORE $0\_s*' ..
388        'FuncRef()\_s*' ..
389        '\d\+ LOAD $\d\_s*' ..
390        '\d\+ PCALL (argc 0)\_s*' ..
391        '\d\+ DROP\_s*' ..
392        'let FuncRefWithArg = function("UserFuncWithArg")\_s*' ..
393        '\d\+ PUSHS "UserFuncWithArg"\_s*' ..
394        '\d\+ BCALL function(argc 1)\_s*' ..
395        '\d\+ STORE $1\_s*' ..
396        'FuncRefWithArg("bar")\_s*' ..
397        '\d\+ PUSHS "bar"\_s*' ..
398        '\d\+ LOAD $\d\_s*' ..
399        '\d\+ PCALL (argc 1)\_s*' ..
400        '\d\+ DROP\_s*' ..
401        'return "yes"\_s*' ..
402        '\d\+ PUSHS "yes"\_s*' ..
403        '\d\+ RETURN',
404        res)
405enddef
406
407def s:CreateRefs()
408  let local = 'a'
409  def Append(arg: string)
410    local ..= arg
411  enddef
412  g:Append = Append
413  def Get(): string
414    return local
415  enddef
416  g:Get = Get
417enddef
418
419def Test_disassemble_closure()
420  CreateRefs()
421  let res = execute('disass g:Append')
422  assert_match('<lambda>\d\_s*' ..
423        'local ..= arg\_s*' ..
424        '\d LOADOUTER $0\_s*' ..
425        '\d LOAD arg\[-1\]\_s*' ..
426        '\d CONCAT\_s*' ..
427        '\d STOREOUTER $0\_s*' ..
428        '\d PUSHNR 0\_s*' ..
429        '\d RETURN',
430        res)
431
432  res = execute('disass g:Get')
433  assert_match('<lambda>\d\_s*' ..
434        'return local\_s*' ..
435        '\d LOADOUTER $0\_s*' ..
436        '\d RETURN',
437        res)
438
439  unlet g:Append
440  unlet g:Get
441enddef
442
443
444def EchoArg(arg: string): string
445  return arg
446enddef
447def RefThis(): func
448  return function('EchoArg')
449enddef
450def s:ScriptPCall()
451  RefThis()("text")
452enddef
453
454def Test_disassemble_pcall()
455  let res = execute('disass s:ScriptPCall')
456  assert_match('<SNR>\d\+_ScriptPCall\_s*' ..
457        'RefThis()("text")\_s*' ..
458        '\d DCALL RefThis(argc 0)\_s*' ..
459        '\d PUSHS "text"\_s*' ..
460        '\d PCALL top (argc 1)\_s*' ..
461        '\d PCALL end\_s*' ..
462        '\d DROP\_s*' ..
463        '\d PUSHNR 0\_s*' ..
464        '\d RETURN',
465        res)
466enddef
467
468
469def s:FuncWithForwardCall(): string
470  return g:DefinedLater("yes")
471enddef
472
473def DefinedLater(arg: string): string
474  return arg
475enddef
476
477def Test_disassemble_update_instr()
478  let res = execute('disass s:FuncWithForwardCall')
479  assert_match('FuncWithForwardCall\_s*' ..
480        'return g:DefinedLater("yes")\_s*' ..
481        '\d PUSHS "yes"\_s*' ..
482        '\d DCALL DefinedLater(argc 1)\_s*' ..
483        '\d RETURN',
484        res)
485
486  # Calling the function will change UCALL into the faster DCALL
487  assert_equal('yes', FuncWithForwardCall())
488
489  res = execute('disass s:FuncWithForwardCall')
490  assert_match('FuncWithForwardCall\_s*' ..
491        'return g:DefinedLater("yes")\_s*' ..
492        '\d PUSHS "yes"\_s*' ..
493        '\d DCALL DefinedLater(argc 1)\_s*' ..
494        '\d RETURN',
495        res)
496enddef
497
498
499def FuncWithDefault(arg: string = 'default'): string
500  return arg
501enddef
502
503def Test_disassemble_call_default()
504  let res = execute('disass FuncWithDefault')
505  assert_match('FuncWithDefault\_s*' ..
506        '\d PUSHS "default"\_s*' ..
507        '\d STORE arg\[-1]\_s*' ..
508        'return arg\_s*' ..
509        '\d LOAD arg\[-1]\_s*' ..
510        '\d RETURN',
511        res)
512enddef
513
514
515def HasEval()
516  if has("eval")
517    echo "yes"
518  else
519    echo "no"
520  endif
521enddef
522
523def HasNothing()
524  if has("nothing")
525    echo "yes"
526  else
527    echo "no"
528  endif
529enddef
530
531def HasSomething()
532  if has("nothing")
533    echo "nothing"
534  elseif has("something")
535    echo "something"
536  elseif has("eval")
537    echo "eval"
538  elseif has("less")
539    echo "less"
540  endif
541enddef
542
543def Test_disassemble_const_expr()
544  assert_equal("\nyes", execute('call HasEval()'))
545  let instr = execute('disassemble HasEval')
546  assert_match('HasEval\_s*' ..
547        'if has("eval")\_s*' ..
548        'echo "yes"\_s*' ..
549        '\d PUSHS "yes"\_s*' ..
550        '\d ECHO 1\_s*' ..
551        'else\_s*' ..
552        'echo "no"\_s*' ..
553        'endif\_s*',
554        instr)
555  assert_notmatch('JUMP', instr)
556
557  assert_equal("\nno", execute('call HasNothing()'))
558  instr = execute('disassemble HasNothing')
559  assert_match('HasNothing\_s*' ..
560        'if has("nothing")\_s*' ..
561        'echo "yes"\_s*' ..
562        'else\_s*' ..
563        'echo "no"\_s*' ..
564        '\d PUSHS "no"\_s*' ..
565        '\d ECHO 1\_s*' ..
566        'endif',
567        instr)
568  assert_notmatch('PUSHS "yes"', instr)
569  assert_notmatch('JUMP', instr)
570
571  assert_equal("\neval", execute('call HasSomething()'))
572  instr = execute('disassemble HasSomething')
573  assert_match('HasSomething.*' ..
574        'if has("nothing")\_s*' ..
575        'echo "nothing"\_s*' ..
576        'elseif has("something")\_s*' ..
577        'echo "something"\_s*' ..
578        'elseif has("eval")\_s*' ..
579        'echo "eval"\_s*' ..
580        '\d PUSHS "eval"\_s*' ..
581        '\d ECHO 1\_s*' ..
582        'elseif has("less").*' ..
583        'echo "less"\_s*' ..
584        'endif',
585        instr)
586  assert_notmatch('PUSHS "nothing"', instr)
587  assert_notmatch('PUSHS "something"', instr)
588  assert_notmatch('PUSHS "less"', instr)
589  assert_notmatch('JUMP', instr)
590enddef
591
592def ReturnInIf(): string
593  if g:cond
594    return "yes"
595  else
596    return "no"
597  endif
598enddef
599
600def Test_disassemble_return_in_if()
601  let instr = execute('disassemble ReturnInIf')
602  assert_match('ReturnInIf\_s*' ..
603        'if g:cond\_s*' ..
604        '0 LOADG g:cond\_s*' ..
605        '1 JUMP_IF_FALSE -> 4\_s*' ..
606        'return "yes"\_s*' ..
607        '2 PUSHS "yes"\_s*' ..
608        '3 RETURN\_s*' ..
609        'else\_s*' ..
610        ' return "no"\_s*' ..
611        '4 PUSHS "no"\_s*' ..
612        '5 RETURN$',
613        instr)
614enddef
615
616def WithFunc()
617  let Funky1: func
618  let Funky2: func = function("len")
619  let Party2: func = funcref("UserFunc")
620enddef
621
622def Test_disassemble_function()
623  let instr = execute('disassemble WithFunc')
624  assert_match('WithFunc\_s*' ..
625        'let Funky1: func\_s*' ..
626        '0 PUSHFUNC "\[none]"\_s*' ..
627        '1 STORE $0\_s*' ..
628        'let Funky2: func = function("len")\_s*' ..
629        '2 PUSHS "len"\_s*' ..
630        '3 BCALL function(argc 1)\_s*' ..
631        '4 STORE $1\_s*' ..
632        'let Party2: func = funcref("UserFunc")\_s*' ..
633        '\d PUSHS "UserFunc"\_s*' ..
634        '\d BCALL funcref(argc 1)\_s*' ..
635        '\d STORE $2\_s*' ..
636        '\d PUSHNR 0\_s*' ..
637        '\d RETURN',
638        instr)
639enddef
640
641if has('channel')
642  def WithChannel()
643    let job1: job
644    let job2: job = job_start("donothing")
645    let chan1: channel
646  enddef
647endif
648
649def Test_disassemble_channel()
650  CheckFeature channel
651
652  let instr = execute('disassemble WithChannel')
653  assert_match('WithChannel\_s*' ..
654        'let job1: job\_s*' ..
655        '\d PUSHJOB "no process"\_s*' ..
656        '\d STORE $0\_s*' ..
657        'let job2: job = job_start("donothing")\_s*' ..
658        '\d PUSHS "donothing"\_s*' ..
659        '\d BCALL job_start(argc 1)\_s*' ..
660        '\d STORE $1\_s*' ..
661        'let chan1: channel\_s*' ..
662        '\d PUSHCHANNEL 0\_s*' ..
663        '\d STORE $2\_s*' ..
664        '\d PUSHNR 0\_s*' ..
665        '\d RETURN',
666        instr)
667enddef
668
669def WithLambda(): string
670  let F = {a -> "X" .. a .. "X"}
671  return F("x")
672enddef
673
674def Test_disassemble_lambda()
675  assert_equal("XxX", WithLambda())
676  let instr = execute('disassemble WithLambda')
677  assert_match('WithLambda\_s*' ..
678        'let F = {a -> "X" .. a .. "X"}\_s*' ..
679        '\d FUNCREF <lambda>\d\+ $1\_s*' ..
680        '\d STORE $0\_s*' ..
681        'return F("x")\_s*' ..
682        '\d PUSHS "x"\_s*' ..
683        '\d LOAD $0\_s*' ..
684        '\d PCALL (argc 1)\_s*' ..
685        '\d RETURN',
686        instr)
687
688   let name = substitute(instr, '.*\(<lambda>\d\+\).*', '\1', '')
689   instr = execute('disassemble ' .. name)
690   assert_match('<lambda>\d\+\_s*' ..
691        'return "X" .. a .. "X"\_s*' ..
692        '\d PUSHS "X"\_s*' ..
693        '\d LOAD arg\[-1\]\_s*' ..
694        '\d 2STRING stack\[-1\]\_s*' ..
695        '\d CONCAT\_s*' ..
696        '\d PUSHS "X"\_s*' ..
697        '\d CONCAT\_s*' ..
698        '\d RETURN',
699        instr)
700enddef
701
702def AndOr(arg: any): string
703  if arg == 1 && arg != 2 || arg == 4
704    return 'yes'
705  endif
706  return 'no'
707enddef
708
709def Test_disassemble_and_or()
710  assert_equal("yes", AndOr(1))
711  assert_equal("no", AndOr(2))
712  assert_equal("yes", AndOr(4))
713  let instr = execute('disassemble AndOr')
714  assert_match('AndOr\_s*' ..
715        'if arg == 1 && arg != 2 || arg == 4\_s*' ..
716        '\d LOAD arg\[-1]\_s*' ..
717        '\d PUSHNR 1\_s*' ..
718        '\d COMPAREANY ==\_s*' ..
719        '\d JUMP_AND_KEEP_IF_FALSE -> \d\+\_s*' ..
720        '\d LOAD arg\[-1]\_s*' ..
721        '\d PUSHNR 2\_s*' ..
722        '\d COMPAREANY !=\_s*' ..
723        '\d JUMP_AND_KEEP_IF_TRUE -> \d\+\_s*' ..
724        '\d LOAD arg\[-1]\_s*' ..
725        '\d\+ PUSHNR 4\_s*' ..
726        '\d\+ COMPAREANY ==\_s*' ..
727        '\d\+ JUMP_IF_FALSE -> \d\+',
728        instr)
729enddef
730
731def ForLoop(): list<number>
732  let res: list<number>
733  for i in range(3)
734    res->add(i)
735  endfor
736  return res
737enddef
738
739def Test_disassemble_for_loop()
740  assert_equal([0, 1, 2], ForLoop())
741  let instr = execute('disassemble ForLoop')
742  assert_match('ForLoop\_s*' ..
743        'let res: list<number>\_s*' ..
744        '\d NEWLIST size 0\_s*' ..
745        '\d STORE $0\_s*' ..
746        'for i in range(3)\_s*' ..
747        '\d STORE -1 in $1\_s*' ..
748        '\d PUSHNR 3\_s*' ..
749        '\d BCALL range(argc 1)\_s*' ..
750        '\d FOR $1 -> \d\+\_s*' ..
751        '\d STORE $2\_s*' ..
752        'res->add(i)\_s*' ..
753        '\d LOAD $0\_s*' ..
754        '\d LOAD $2\_s*' ..
755        '\d\+ BCALL add(argc 2)\_s*' ..
756        '\d\+ DROP\_s*' ..
757        'endfor\_s*' ..
758        '\d\+ JUMP -> \d\+\_s*' ..
759        '\d\+ DROP',
760        instr)
761enddef
762
763def ForLoopEval(): string
764  let res = ""
765  for str in eval('["one", "two"]')
766    res ..= str
767  endfor
768  return res
769enddef
770
771def Test_disassemble_for_loop_eval()
772  assert_equal('onetwo', ForLoopEval())
773  let instr = execute('disassemble ForLoopEval')
774  assert_match('ForLoopEval\_s*' ..
775        'let res = ""\_s*' ..
776        '\d PUSHS ""\_s*' ..
777        '\d STORE $0\_s*' ..
778        'for str in eval(''\["one", "two"\]'')\_s*' ..
779        '\d STORE -1 in $1\_s*' ..
780        '\d PUSHS "\["one", "two"\]"\_s*' ..
781        '\d BCALL eval(argc 1)\_s*' ..
782        '\d CHECKTYPE list stack\[-1\]\_s*' ..
783        '\d FOR $1 -> \d\+\_s*' ..
784        '\d STORE $2\_s*' ..
785        'res ..= str\_s*' ..
786        '\d\+ LOAD $0\_s*' ..
787        '\d\+ LOAD $2\_s*' ..
788        '\d\+ CHECKTYPE string stack\[-1\]\_s*' ..
789        '\d\+ CONCAT\_s*' ..
790        '\d\+ STORE $0\_s*' ..
791        'endfor\_s*' ..
792        '\d\+ JUMP -> 6\_s*' ..
793        '\d\+ DROP\_s*' ..
794        'return res\_s*' ..
795        '\d\+ LOAD $0\_s*' ..
796        '\d\+ RETURN',
797        instr)
798enddef
799
800let g:number = 42
801
802def Computing()
803  let nr = 3
804  let nrres = nr + 7
805  nrres = nr - 7
806  nrres = nr * 7
807  nrres = nr / 7
808  nrres = nr % 7
809
810  let anyres = g:number + 7
811  anyres = g:number - 7
812  anyres = g:number * 7
813  anyres = g:number / 7
814  anyres = g:number % 7
815
816  if has('float')
817    let fl = 3.0
818    let flres = fl + 7.0
819    flres = fl - 7.0
820    flres = fl * 7.0
821    flres = fl / 7.0
822  endif
823enddef
824
825def Test_disassemble_computing()
826  let instr = execute('disassemble Computing')
827  assert_match('Computing.*' ..
828        'let nr = 3.*' ..
829        '\d STORE 3 in $0.*' ..
830        'let nrres = nr + 7.*' ..
831        '\d LOAD $0.*' ..
832        '\d PUSHNR 7.*' ..
833        '\d OPNR +.*' ..
834        '\d STORE $1.*' ..
835        'nrres = nr - 7.*' ..
836        '\d OPNR -.*' ..
837        'nrres = nr \* 7.*' ..
838        '\d OPNR \*.*' ..
839        'nrres = nr / 7.*' ..
840        '\d OPNR /.*' ..
841        'nrres = nr % 7.*' ..
842        '\d OPNR %.*' ..
843        'let anyres = g:number + 7.*' ..
844        '\d LOADG g:number.*' ..
845        '\d PUSHNR 7.*' ..
846        '\d OPANY +.*' ..
847        '\d STORE $2.*' ..
848        'anyres = g:number - 7.*' ..
849        '\d OPANY -.*' ..
850        'anyres = g:number \* 7.*' ..
851        '\d OPANY \*.*' ..
852        'anyres = g:number / 7.*' ..
853        '\d OPANY /.*' ..
854        'anyres = g:number % 7.*' ..
855        '\d OPANY %.*',
856        instr)
857  if has('float')
858    assert_match('Computing.*' ..
859        'let fl = 3.0.*' ..
860        '\d PUSHF 3.0.*' ..
861        '\d STORE $3.*' ..
862        'let flres = fl + 7.0.*' ..
863        '\d LOAD $3.*' ..
864        '\d PUSHF 7.0.*' ..
865        '\d OPFLOAT +.*' ..
866        '\d STORE $4.*' ..
867        'flres = fl - 7.0.*' ..
868        '\d OPFLOAT -.*' ..
869        'flres = fl \* 7.0.*' ..
870        '\d OPFLOAT \*.*' ..
871        'flres = fl / 7.0.*' ..
872        '\d OPFLOAT /.*',
873        instr)
874  endif
875enddef
876
877def AddListBlob()
878  let reslist = [1, 2] + [3, 4]
879  let resblob = 0z1122 + 0z3344
880enddef
881
882def Test_disassemble_add_list_blob()
883  let instr = execute('disassemble AddListBlob')
884  assert_match('AddListBlob.*' ..
885        'let reslist = \[1, 2] + \[3, 4].*' ..
886        '\d PUSHNR 1.*' ..
887        '\d PUSHNR 2.*' ..
888        '\d NEWLIST size 2.*' ..
889        '\d PUSHNR 3.*' ..
890        '\d PUSHNR 4.*' ..
891        '\d NEWLIST size 2.*' ..
892        '\d ADDLIST.*' ..
893        '\d STORE $.*.*' ..
894        'let resblob = 0z1122 + 0z3344.*' ..
895        '\d PUSHBLOB 0z1122.*' ..
896        '\d PUSHBLOB 0z3344.*' ..
897        '\d ADDBLOB.*' ..
898        '\d STORE $.*',
899        instr)
900enddef
901
902let g:aa = 'aa'
903def ConcatString(): string
904  let res = g:aa .. "bb"
905  return res
906enddef
907
908def Test_disassemble_concat()
909  let instr = execute('disassemble ConcatString')
910  assert_match('ConcatString.*' ..
911        'let res = g:aa .. "bb".*' ..
912        '\d LOADG g:aa.*' ..
913        '\d PUSHS "bb".*' ..
914        '\d 2STRING stack\[-2].*' ..
915        '\d CONCAT.*' ..
916        '\d STORE $.*',
917        instr)
918  assert_equal('aabb', ConcatString())
919enddef
920
921def StringIndex(): number
922  let s = "abcd"
923  let res = s[1]
924  return res
925enddef
926
927def Test_disassemble_string_index()
928  let instr = execute('disassemble StringIndex')
929  assert_match('StringIndex\_s*' ..
930        'let s = "abcd"\_s*' ..
931        '\d PUSHS "abcd"\_s*' ..
932        '\d STORE $0\_s*' ..
933        'let res = s\[1]\_s*' ..
934        '\d LOAD $0\_s*' ..
935        '\d PUSHNR 1\_s*' ..
936        '\d STRINDEX\_s*' ..
937        '\d STORE $1\_s*',
938        instr)
939  assert_equal('b', StringIndex())
940enddef
941
942def ListIndex(): number
943  let l = [1, 2, 3]
944  let res = l[1]
945  return res
946enddef
947
948def Test_disassemble_list_index()
949  let instr = execute('disassemble ListIndex')
950  assert_match('ListIndex\_s*' ..
951        'let l = \[1, 2, 3]\_s*' ..
952        '\d PUSHNR 1\_s*' ..
953        '\d PUSHNR 2\_s*' ..
954        '\d PUSHNR 3\_s*' ..
955        '\d NEWLIST size 3\_s*' ..
956        '\d STORE $0\_s*' ..
957        'let res = l\[1]\_s*' ..
958        '\d LOAD $0\_s*' ..
959        '\d PUSHNR 1\_s*' ..
960        '\d LISTINDEX\_s*' ..
961        '\d STORE $1\_s*',
962        instr)
963  assert_equal(2, ListIndex())
964enddef
965
966def DictMember(): number
967  let d = #{item: 1}
968  let res = d.item
969  res = d["item"]
970  return res
971enddef
972
973def Test_disassemble_dict_member()
974  let instr = execute('disassemble DictMember')
975  assert_match('DictMember\_s*' ..
976        'let d = #{item: 1}\_s*' ..
977        '\d PUSHS "item"\_s*' ..
978        '\d PUSHNR 1\_s*' ..
979        '\d NEWDICT size 1\_s*' ..
980        '\d STORE $0\_s*' ..
981        'let res = d.item\_s*' ..
982        '\d\+ LOAD $0\_s*' ..
983        '\d\+ MEMBER item\_s*' ..
984        '\d\+ STORE $1\_s*' ..
985        'res = d\["item"\]\_s*' ..
986        '\d\+ LOAD $0\_s*' ..
987        '\d\+ PUSHS "item"\_s*' ..
988        '\d\+ MEMBER\_s*' ..
989        '\d\+ STORE $1\_s*',
990        instr)
991  call assert_equal(1, DictMember())
992enddef
993
994def NegateNumber(): number
995  let nr = 9
996  let plus = +nr
997  let res = -nr
998  return res
999enddef
1000
1001def Test_disassemble_negate_number()
1002  let instr = execute('disassemble NegateNumber')
1003  assert_match('NegateNumber\_s*' ..
1004        'let nr = 9\_s*' ..
1005        '\d STORE 9 in $0\_s*' ..
1006        'let plus = +nr\_s*' ..
1007        '\d LOAD $0\_s*' ..
1008        '\d CHECKNR\_s*' ..
1009        '\d STORE $1\_s*' ..
1010        'let res = -nr\_s*' ..
1011        '\d LOAD $0\_s*' ..
1012        '\d NEGATENR\_s*' ..
1013        '\d STORE $2\_s*',
1014        instr)
1015  call assert_equal(-9, NegateNumber())
1016enddef
1017
1018def InvertBool(): bool
1019  let flag = true
1020  let invert = !flag
1021  let res = !!flag
1022  return res
1023enddef
1024
1025def Test_disassemble_invert_bool()
1026  let instr = execute('disassemble InvertBool')
1027  assert_match('InvertBool\_s*' ..
1028        'let flag = true\_s*' ..
1029        '\d PUSH v:true\_s*' ..
1030        '\d STORE $0\_s*' ..
1031        'let invert = !flag\_s*' ..
1032        '\d LOAD $0\_s*' ..
1033        '\d INVERT (!val)\_s*' ..
1034        '\d STORE $1\_s*' ..
1035        'let res = !!flag\_s*' ..
1036        '\d LOAD $0\_s*' ..
1037        '\d 2BOOL (!!val)\_s*' ..
1038        '\d STORE $2\_s*',
1039        instr)
1040  call assert_equal(true, InvertBool())
1041enddef
1042
1043def Test_disassemble_compare()
1044  let cases = [
1045        ['true == isFalse', 'COMPAREBOOL =='],
1046        ['true != isFalse', 'COMPAREBOOL !='],
1047        ['v:none == isNull', 'COMPARESPECIAL =='],
1048        ['v:none != isNull', 'COMPARESPECIAL !='],
1049
1050        ['111 == aNumber', 'COMPARENR =='],
1051        ['111 != aNumber', 'COMPARENR !='],
1052        ['111 > aNumber', 'COMPARENR >'],
1053        ['111 < aNumber', 'COMPARENR <'],
1054        ['111 >= aNumber', 'COMPARENR >='],
1055        ['111 <= aNumber', 'COMPARENR <='],
1056        ['111 =~ aNumber', 'COMPARENR =\~'],
1057        ['111 !~ aNumber', 'COMPARENR !\~'],
1058
1059        ['"xx" != aString', 'COMPARESTRING !='],
1060        ['"xx" > aString', 'COMPARESTRING >'],
1061        ['"xx" < aString', 'COMPARESTRING <'],
1062        ['"xx" >= aString', 'COMPARESTRING >='],
1063        ['"xx" <= aString', 'COMPARESTRING <='],
1064        ['"xx" =~ aString', 'COMPARESTRING =\~'],
1065        ['"xx" !~ aString', 'COMPARESTRING !\~'],
1066        ['"xx" is aString', 'COMPARESTRING is'],
1067        ['"xx" isnot aString', 'COMPARESTRING isnot'],
1068
1069        ['0z11 == aBlob', 'COMPAREBLOB =='],
1070        ['0z11 != aBlob', 'COMPAREBLOB !='],
1071        ['0z11 is aBlob', 'COMPAREBLOB is'],
1072        ['0z11 isnot aBlob', 'COMPAREBLOB isnot'],
1073
1074        ['[1, 2] == aList', 'COMPARELIST =='],
1075        ['[1, 2] != aList', 'COMPARELIST !='],
1076        ['[1, 2] is aList', 'COMPARELIST is'],
1077        ['[1, 2] isnot aList', 'COMPARELIST isnot'],
1078
1079        ['#{a: 1} == aDict', 'COMPAREDICT =='],
1080        ['#{a: 1} != aDict', 'COMPAREDICT !='],
1081        ['#{a: 1} is aDict', 'COMPAREDICT is'],
1082        ['#{a: 1} isnot aDict', 'COMPAREDICT isnot'],
1083
1084        ['{->33} == {->44}', 'COMPAREFUNC =='],
1085        ['{->33} != {->44}', 'COMPAREFUNC !='],
1086        ['{->33} is {->44}', 'COMPAREFUNC is'],
1087        ['{->33} isnot {->44}', 'COMPAREFUNC isnot'],
1088
1089        ['77 == g:xx', 'COMPAREANY =='],
1090        ['77 != g:xx', 'COMPAREANY !='],
1091        ['77 > g:xx', 'COMPAREANY >'],
1092        ['77 < g:xx', 'COMPAREANY <'],
1093        ['77 >= g:xx', 'COMPAREANY >='],
1094        ['77 <= g:xx', 'COMPAREANY <='],
1095        ['77 =~ g:xx', 'COMPAREANY =\~'],
1096        ['77 !~ g:xx', 'COMPAREANY !\~'],
1097        ['77 is g:xx', 'COMPAREANY is'],
1098        ['77 isnot g:xx', 'COMPAREANY isnot'],
1099        ]
1100  let floatDecl = ''
1101  if has('float')
1102    cases->extend([
1103        ['1.1 == aFloat', 'COMPAREFLOAT =='],
1104        ['1.1 != aFloat', 'COMPAREFLOAT !='],
1105        ['1.1 > aFloat', 'COMPAREFLOAT >'],
1106        ['1.1 < aFloat', 'COMPAREFLOAT <'],
1107        ['1.1 >= aFloat', 'COMPAREFLOAT >='],
1108        ['1.1 <= aFloat', 'COMPAREFLOAT <='],
1109        ['1.1 =~ aFloat', 'COMPAREFLOAT =\~'],
1110        ['1.1 !~ aFloat', 'COMPAREFLOAT !\~'],
1111        ])
1112    floatDecl = 'let aFloat = 2.2'
1113  endif
1114
1115  let nr = 1
1116  for case in cases
1117    # declare local variables to get a non-constant with the right type
1118    writefile(['def TestCase' .. nr .. '()',
1119             '  let isFalse = false',
1120             '  let isNull = v:null',
1121             '  let aNumber = 222',
1122             '  let aString = "yy"',
1123             '  let aBlob = 0z22',
1124             '  let aList = [3, 4]',
1125             '  let aDict = #{x: 2}',
1126             floatDecl,
1127             '  if ' .. case[0],
1128             '    echo 42'
1129             '  endif',
1130             'enddef'], 'Xdisassemble')
1131    source Xdisassemble
1132    let instr = execute('disassemble TestCase' .. nr)
1133    assert_match('TestCase' .. nr .. '.*' ..
1134        'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' ..
1135        '\d \(PUSH\|FUNCREF\).*' ..
1136        '\d \(PUSH\|FUNCREF\|LOAD\).*' ..
1137        '\d ' .. case[1] .. '.*' ..
1138        '\d JUMP_IF_FALSE -> \d\+.*',
1139        instr)
1140
1141    nr += 1
1142  endfor
1143
1144  delete('Xdisassemble')
1145enddef
1146
1147def Test_disassemble_compare_const()
1148  let cases = [
1149        ['"xx" == "yy"', false],
1150        ['"aa" == "aa"', true],
1151        ['has("eval") ? true : false', true],
1152        ['has("asdf") ? true : false', false],
1153        ]
1154
1155  let nr = 1
1156  for case in cases
1157    writefile(['def TestCase' .. nr .. '()',
1158             '  if ' .. case[0],
1159             '    echo 42'
1160             '  endif',
1161             'enddef'], 'Xdisassemble')
1162    source Xdisassemble
1163    let instr = execute('disassemble TestCase' .. nr)
1164    if case[1]
1165      # condition true, "echo 42" executed
1166      assert_match('TestCase' .. nr .. '.*' ..
1167          'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' ..
1168          '\d PUSHNR 42.*' ..
1169          '\d ECHO 1.*' ..
1170          '\d PUSHNR 0.*' ..
1171          '\d RETURN.*',
1172          instr)
1173    else
1174      # condition false, function just returns
1175      assert_match('TestCase' .. nr .. '.*' ..
1176          'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '[ \n]*' ..
1177          'echo 42[ \n]*' ..
1178          'endif[ \n]*' ..
1179          '\s*\d PUSHNR 0.*' ..
1180          '\d RETURN.*',
1181          instr)
1182    endif
1183
1184    nr += 1
1185  endfor
1186
1187  delete('Xdisassemble')
1188enddef
1189
1190def s:Execute()
1191  execute 'help vim9.txt'
1192  let cmd = 'help vim9.txt'
1193  execute cmd
1194  let tag = 'vim9.txt'
1195  execute 'help ' .. tag
1196enddef
1197
1198def Test_disassemble_execute()
1199  let res = execute('disass s:Execute')
1200  assert_match('\<SNR>\d*_Execute\_s*' ..
1201        "execute 'help vim9.txt'\\_s*" ..
1202        '\d PUSHS "help vim9.txt"\_s*' ..
1203        '\d EXECUTE 1\_s*' ..
1204        "let cmd = 'help vim9.txt'\\_s*" ..
1205        '\d PUSHS "help vim9.txt"\_s*' ..
1206        '\d STORE $0\_s*' ..
1207        'execute cmd\_s*' ..
1208        '\d LOAD $0\_s*' ..
1209        '\d EXECUTE 1\_s*' ..
1210        "let tag = 'vim9.txt'\\_s*" ..
1211        '\d PUSHS "vim9.txt"\_s*' ..
1212        '\d STORE $1\_s*' ..
1213        "execute 'help ' .. tag\\_s*" ..
1214        '\d\+ PUSHS "help "\_s*' ..
1215        '\d\+ LOAD $1\_s*' ..
1216        '\d\+ CONCAT\_s*' ..
1217        '\d\+ EXECUTE 1\_s*' ..
1218        '\d\+ PUSHNR 0\_s*' ..
1219        '\d\+ RETURN',
1220        res)
1221enddef
1222
1223def s:Echomsg()
1224  echomsg 'some' 'message'
1225  echoerr 'went' .. 'wrong'
1226enddef
1227
1228def Test_disassemble_echomsg()
1229  let res = execute('disass s:Echomsg')
1230  assert_match('\<SNR>\d*_Echomsg\_s*' ..
1231        "echomsg 'some' 'message'\\_s*" ..
1232        '\d PUSHS "some"\_s*' ..
1233        '\d PUSHS "message"\_s*' ..
1234        '\d ECHOMSG 2\_s*' ..
1235        "echoerr 'went' .. 'wrong'\\_s*" ..
1236        '\d PUSHS "wentwrong"\_s*' ..
1237        '\d ECHOERR 1\_s*' ..
1238        '\d PUSHNR 0\_s*' ..
1239        '\d RETURN',
1240        res)
1241enddef
1242
1243def SomeStringArg(arg: string)
1244  echo arg
1245enddef
1246
1247def SomeAnyArg(arg: any)
1248  echo arg
1249enddef
1250
1251def SomeStringArgAndReturn(arg: string): string
1252  return arg
1253enddef
1254
1255def Test_display_func()
1256  let res1 = execute('function SomeStringArg')
1257  assert_match('.* def SomeStringArg(arg: string)\_s*' ..
1258        '\d *echo arg.*' ..
1259        ' *enddef',
1260        res1)
1261
1262  let res2 = execute('function SomeAnyArg')
1263  assert_match('.* def SomeAnyArg(arg: any)\_s*' ..
1264        '\d *echo arg\_s*' ..
1265        ' *enddef',
1266        res2)
1267
1268  let res3 = execute('function SomeStringArgAndReturn')
1269  assert_match('.* def SomeStringArgAndReturn(arg: string): string\_s*' ..
1270        '\d *return arg\_s*' ..
1271        ' *enddef',
1272        res3)
1273enddef
1274
1275def Test_vim9script_forward_func()
1276  let lines =<< trim END
1277    vim9script
1278    def FuncOne(): string
1279      return FuncTwo()
1280    enddef
1281    def FuncTwo(): string
1282      return 'two'
1283    enddef
1284    g:res_FuncOne = execute('disass FuncOne')
1285  END
1286  writefile(lines, 'Xdisassemble')
1287  source Xdisassemble
1288
1289  # check that the first function calls the second with DCALL
1290  assert_match('\<SNR>\d*_FuncOne\_s*' ..
1291        'return FuncTwo()\_s*' ..
1292        '\d DCALL <SNR>\d\+_FuncTwo(argc 0)\_s*' ..
1293        '\d RETURN',
1294        g:res_FuncOne)
1295
1296  delete('Xdisassemble')
1297  unlet g:res_FuncOne
1298enddef
1299
1300def s:ConcatStrings(): string
1301  return 'one' .. 'two' .. 'three'
1302enddef
1303
1304def s:ComputeConst(): number
1305  return 2 + 3 * 4 / 6 + 7
1306enddef
1307
1308def s:ComputeConstParen(): number
1309  return ((2 + 4) * (8 / 2)) / (3 + 4)
1310enddef
1311
1312def Test_simplify_const_expr()
1313  let res = execute('disass s:ConcatStrings')
1314  assert_match('<SNR>\d*_ConcatStrings\_s*' ..
1315        "return 'one' .. 'two' .. 'three'\\_s*" ..
1316        '\d PUSHS "onetwothree"\_s*' ..
1317        '\d RETURN',
1318        res)
1319
1320  res = execute('disass s:ComputeConst')
1321  assert_match('<SNR>\d*_ComputeConst\_s*' ..
1322        'return 2 + 3 \* 4 / 6 + 7\_s*' ..
1323        '\d PUSHNR 11\_s*' ..
1324        '\d RETURN',
1325        res)
1326
1327  res = execute('disass s:ComputeConstParen')
1328  assert_match('<SNR>\d*_ComputeConstParen\_s*' ..
1329        'return ((2 + 4) \* (8 / 2)) / (3 + 4)\_s*' ..
1330        '\d PUSHNR 3\>\_s*' ..
1331        '\d RETURN',
1332        res)
1333enddef
1334
1335def s:CallAppend()
1336  eval "some text"->append(2)
1337enddef
1338
1339def Test_shuffle()
1340  let res = execute('disass s:CallAppend')
1341  assert_match('<SNR>\d*_CallAppend\_s*' ..
1342        'eval "some text"->append(2)\_s*' ..
1343        '\d PUSHS "some text"\_s*' ..
1344        '\d PUSHNR 2\_s*' ..
1345        '\d SHUFFLE 2 up 1\_s*' ..
1346        '\d BCALL append(argc 2)\_s*' ..
1347        '\d DROP\_s*' ..
1348        '\d PUSHNR 0\_s*' ..
1349        '\d RETURN',
1350        res)
1351enddef
1352
1353" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
1354