1" Test the :disassemble command, and compilation as a side effect
2
3func NotCompiled()
4  echo "not"
5endfunc
6
7let s:scriptvar = 4
8let g:globalvar = 'g'
9
10def s:ScriptFuncLoad(arg: string)
11  let local = 1
12  buffers
13  echo arg
14  echo local
15  echo v:version
16  echo s:scriptvar
17  echo g:globalvar
18  echo &tabstop
19  echo $ENVVAR
20  echo @z
21enddef
22
23def Test_disassemble_load()
24  assert_fails('disass NoFunc', 'E1061:')
25  assert_fails('disass NotCompiled', 'E1062:')
26  assert_fails('disass', 'E471:')
27  assert_fails('disass [', 'E475:')
28  assert_fails('disass 234', 'E475:')
29  assert_fails('disass <XX>foo', 'E475:')
30
31  let res = execute('disass s:ScriptFuncLoad')
32  assert_match('<SNR>\d*_ScriptFuncLoad.*'
33        \ .. 'buffers.*'
34        \ .. ' EXEC \+buffers.*'
35        \ .. ' LOAD arg\[-1\].*'
36        \ .. ' LOAD $0.*'
37        \ .. ' LOADV v:version.*'
38        \ .. ' LOADS s:scriptvar from .*test_vim9_disassemble.vim.*'
39        \ .. ' LOADG g:globalvar.*'
40        \ .. ' LOADENV $ENVVAR.*'
41        \ .. ' LOADREG @z.*'
42        \, res)
43enddef
44
45def s:ScriptFuncPush()
46  let localbool = true
47  let localspec = v:none
48  let localblob = 0z1234
49  if has('float')
50    let localfloat = 1.234
51  endif
52enddef
53
54def Test_disassemble_push()
55  let res = execute('disass s:ScriptFuncPush')
56  assert_match('<SNR>\d*_ScriptFuncPush.*'
57        \ .. 'localbool = true.*'
58        \ .. ' PUSH v:true.*'
59        \ .. 'localspec = v:none.*'
60        \ .. ' PUSH v:none.*'
61        \ .. 'localblob = 0z1234.*'
62        \ .. ' PUSHBLOB 0z1234.*'
63        \, res)
64  if has('float')
65  assert_match('<SNR>\d*_ScriptFuncPush.*'
66        \ .. 'localfloat = 1.234.*'
67        \ .. ' PUSHF 1.234.*'
68        \, res)
69  endif
70enddef
71
72def s:ScriptFuncStore()
73  let localnr = 1
74  localnr = 2
75  let localstr = 'abc'
76  localstr = 'xyz'
77  v:char = 'abc'
78  s:scriptvar = 'sv'
79  g:globalvar = 'gv'
80  &tabstop = 8
81  $ENVVAR = 'ev'
82  @z = 'rv'
83enddef
84
85def Test_disassemble_store()
86  let res = execute('disass s:ScriptFuncStore')
87  assert_match('<SNR>\d*_ScriptFuncStore.*'
88        \ .. 'localnr = 2.*'
89        \ .. ' STORE 2 in $0.*'
90        \ .. 'localstr = ''xyz''.*'
91        \ .. ' STORE $1.*'
92        \ .. 'v:char = ''abc''.*'
93        \ .. 'STOREV v:char.*'
94        \ .. 's:scriptvar = ''sv''.*'
95        \ .. ' STORES s:scriptvar in .*test_vim9_disassemble.vim.*'
96        \ .. 'g:globalvar = ''gv''.*'
97        \ .. ' STOREG g:globalvar.*'
98        \ .. '&tabstop = 8.*'
99        \ .. ' STOREOPT &tabstop.*'
100        \ .. '$ENVVAR = ''ev''.*'
101        \ .. ' STOREENV $ENVVAR.*'
102        \ .. '@z = ''rv''.*'
103        \ .. ' STOREREG @z.*'
104        \, res)
105enddef
106
107def s:ScriptFuncTry()
108  try
109    echo 'yes'
110  catch /fail/
111    echo 'no'
112  finally
113    throw 'end'
114  endtry
115enddef
116
117def Test_disassemble_try()
118  let res = execute('disass s:ScriptFuncTry')
119  assert_match('<SNR>\d*_ScriptFuncTry.*'
120        \ .. 'try.*'
121        \ .. 'TRY catch -> \d\+, finally -> \d\+.*'
122        \ .. 'catch /fail/.*'
123        \ .. ' JUMP -> \d\+.*'
124        \ .. ' PUSH v:exception.*'
125        \ .. ' PUSHS "fail".*'
126        \ .. ' COMPARESTRING =\~.*'
127        \ .. ' JUMP_IF_FALSE -> \d\+.*'
128        \ .. ' CATCH.*'
129        \ .. 'finally.*'
130        \ .. ' PUSHS "end".*'
131        \ .. ' THROW.*'
132        \ .. 'endtry.*'
133        \ .. ' ENDTRY.*'
134        \, res)
135enddef
136
137def s:ScriptFuncNew()
138  let ll = [1, "two", 333]
139  let dd = #{one: 1, two: "val"}
140enddef
141
142def Test_disassemble_new()
143  let res = execute('disass s:ScriptFuncNew')
144  assert_match('<SNR>\d*_ScriptFuncNew.*'
145        \ .. 'let ll = \[1, "two", 333].*'
146        \ .. 'PUSHNR 1.*'
147        \ .. 'PUSHS "two".*'
148        \ .. 'PUSHNR 333.*'
149        \ .. 'NEWLIST size 3.*'
150        \ .. 'let dd = #{one: 1, two: "val"}.*'
151        \ .. 'PUSHS "one".*'
152        \ .. 'PUSHNR 1.*'
153        \ .. 'PUSHS "two".*'
154        \ .. 'PUSHS "val".*'
155        \ .. 'NEWDICT size 2.*'
156        \, res)
157enddef
158
159def FuncWithArg(arg)
160  echo arg
161enddef
162
163func UserFunc()
164  echo 'nothing'
165endfunc
166
167func UserFuncWithArg(arg)
168  echo a:arg
169endfunc
170
171def s:ScriptFuncCall(): string
172  changenr()
173  char2nr("abc")
174  Test_disassemble_new()
175  FuncWithArg(343)
176  ScriptFuncNew()
177  s:ScriptFuncNew()
178  UserFunc()
179  UserFuncWithArg("foo")
180  let FuncRef = function("UserFunc")
181  FuncRef()
182  let FuncRefWithArg = function("UserFuncWithArg")
183  FuncRefWithArg("bar")
184  return "yes"
185enddef
186
187def Test_disassemble_call()
188  let res = execute('disass s:ScriptFuncCall')
189  assert_match('<SNR>\d\+_ScriptFuncCall.*'
190        \ .. 'changenr().*'
191        \ .. ' BCALL changenr(argc 0).*'
192        \ .. 'char2nr("abc").*'
193        \ .. ' PUSHS "abc".*'
194        \ .. ' BCALL char2nr(argc 1).*'
195        \ .. 'Test_disassemble_new().*'
196        \ .. ' DCALL Test_disassemble_new(argc 0).*'
197        \ .. 'FuncWithArg(343).*'
198        \ .. ' PUSHNR 343.*'
199        \ .. ' DCALL FuncWithArg(argc 1).*'
200        \ .. 'ScriptFuncNew().*'
201        \ .. ' DCALL <SNR>\d\+_ScriptFuncNew(argc 0).*'
202        \ .. 's:ScriptFuncNew().*'
203        \ .. ' DCALL <SNR>\d\+_ScriptFuncNew(argc 0).*'
204        \ .. 'UserFunc().*'
205        \ .. ' UCALL UserFunc(argc 0).*'
206        \ .. 'UserFuncWithArg("foo").*'
207        \ .. ' PUSHS "foo".*'
208        \ .. ' UCALL UserFuncWithArg(argc 1).*'
209        \ .. 'let FuncRef = function("UserFunc").*'
210        \ .. 'FuncRef().*'
211        \ .. ' LOAD $\d.*'
212        \ .. ' PCALL (argc 0).*'
213        \ .. 'let FuncRefWithArg = function("UserFuncWithArg").*'
214        \ .. 'FuncRefWithArg("bar").*'
215        \ .. ' PUSHS "bar".*'
216        \ .. ' LOAD $\d.*'
217        \ .. ' PCALL (argc 1).*'
218        \ .. 'return "yes".*'
219        \ .. ' PUSHS "yes".*'
220        \ .. ' RETURN.*'
221        \, res)
222enddef
223
224
225def FuncWithDefault(arg: string = 'default'): string
226  return arg
227enddef
228
229def Test_disassemble_call_default()
230  let res = execute('disass FuncWithDefault')
231  assert_match('FuncWithDefault.*'
232        \ .. '\d PUSHS "default".*'
233        \ .. '\d STORE arg\[-1].*'
234        \ .. 'return arg.*'
235        \ .. '\d LOAD arg\[-1].*'
236        \ .. '\d RETURN.*'
237        \, res)
238enddef
239
240
241def HasEval()
242  if has("eval")
243    echo "yes"
244  else
245    echo "no"
246  endif
247enddef
248
249def HasNothing()
250  if has("nothing")
251    echo "yes"
252  else
253    echo "no"
254  endif
255enddef
256
257def HasSomething()
258  if has("nothing")
259    echo "nothing"
260  elseif has("something")
261    echo "something"
262  elseif has("eval")
263    echo "eval"
264  elseif has("less")
265    echo "less"
266  endif
267enddef
268
269def Test_disassemble_const_expr()
270  assert_equal("\nyes", execute('call HasEval()'))
271  let instr = execute('disassemble HasEval')
272  assert_match('HasEval.*'
273        \ .. 'if has("eval").*'
274        \ .. ' PUSHS "yes".*'
275        \, instr)
276  assert_notmatch('JUMP', instr)
277
278  assert_equal("\nno", execute('call HasNothing()'))
279  instr = execute('disassemble HasNothing')
280  assert_match('HasNothing.*'
281        \ .. 'if has("nothing").*'
282        \ .. 'else.*'
283        \ .. ' PUSHS "no".*'
284        \, instr)
285  assert_notmatch('PUSHS "yes"', instr)
286  assert_notmatch('JUMP', instr)
287
288  assert_equal("\neval", execute('call HasSomething()'))
289  instr = execute('disassemble HasSomething')
290  assert_match('HasSomething.*'
291        \ .. 'if has("nothing").*'
292        \ .. 'elseif has("something").*'
293        \ .. 'elseif has("eval").*'
294        \ .. ' PUSHS "eval".*'
295        \ .. 'elseif has("less").*'
296        \, instr)
297  assert_notmatch('PUSHS "nothing"', instr)
298  assert_notmatch('PUSHS "something"', instr)
299  assert_notmatch('PUSHS "less"', instr)
300  assert_notmatch('JUMP', instr)
301enddef
302
303def WithLambda(): string
304  let F = {a -> "X" .. a .. "X"}
305  return F("x")
306enddef
307
308def Test_disassemble_lambda()
309  assert_equal("XxX", WithLambda())
310  let instr = execute('disassemble WithLambda')
311  assert_match('WithLambda.*'
312        \ .. 'let F = {a -> "X" .. a .. "X"}.*'
313        \ .. ' FUNCREF <lambda>\d\+.*'
314        \ .. 'PUSHS "x".*'
315        \ .. ' LOAD $0.*'
316        \ .. ' PCALL (argc 1).*'
317        \ .. ' CHECKTYPE string stack\[-1].*'
318        \, instr)
319enddef
320
321def AndOr(arg): string
322  if arg == 1 && arg != 2 || arg == 4
323    return 'yes'
324  endif
325  return 'no'
326enddef
327
328def Test_disassemble_and_or()
329  assert_equal("yes", AndOr(1))
330  assert_equal("no", AndOr(2))
331  assert_equal("yes", AndOr(4))
332  let instr = execute('disassemble AndOr')
333  assert_match('AndOr.*'
334        \ .. 'if arg == 1 && arg != 2 || arg == 4.*'
335        \ .. '\d LOAD arg\[-1].*'
336        \ .. '\d PUSHNR 1.*'
337        \ .. '\d COMPAREANY ==.*'
338        \ .. '\d JUMP_AND_KEEP_IF_FALSE -> \d\+.*'
339        \ .. '\d LOAD arg\[-1].*'
340        \ .. '\d PUSHNR 2.*'
341        \ .. '\d COMPAREANY !=.*'
342        \ .. '\d JUMP_AND_KEEP_IF_TRUE -> \d\+.*'
343        \ .. '\d LOAD arg\[-1].*'
344        \ .. '\d PUSHNR 4.*'
345        \ .. '\d COMPAREANY ==.*'
346        \ .. '\d JUMP_IF_FALSE -> \d\+.*'
347        \, instr)
348enddef
349
350def ForLoop(): list<number>
351  let res: list<number>
352  for i in range(3)
353    res->add(i)
354  endfor
355  return res
356enddef
357
358def Test_disassemble_for_loop()
359  assert_equal([0, 1, 2], ForLoop())
360  let instr = execute('disassemble ForLoop')
361  assert_match('ForLoop.*'
362        \ .. 'let res: list<number>.*'
363        \ .. ' NEWLIST size 0.*'
364        \ .. '\d STORE $0.*'
365        \ .. 'for i in range(3).*'
366        \ .. '\d STORE -1 in $1.*'
367        \ .. '\d PUSHNR 3.*'
368        \ .. '\d BCALL range(argc 1).*'
369        \ .. '\d FOR $1 -> \d\+.*'
370        \ .. '\d STORE $2.*'
371        \ .. 'res->add(i).*'
372        \ .. '\d LOAD $0.*'
373        \ .. '\d LOAD $2.*'
374        \ .. '\d BCALL add(argc 2).*'
375        \ .. '\d DROP.*'
376        \ .. 'endfor.*'
377        \ .. '\d JUMP -> \d\+.*'
378        \ .. '\d DROP.*'
379        \, instr)
380enddef
381
382let g:number = 42
383
384def Computing()
385  let nr = 3
386  let nrres = nr + 7
387  nrres = nr - 7
388  nrres = nr * 7
389  nrres = nr / 7
390  nrres = nr % 7
391
392  let anyres = g:number + 7
393  anyres = g:number - 7
394  anyres = g:number * 7
395  anyres = g:number / 7
396  anyres = g:number % 7
397
398  if has('float')
399    let fl = 3.0
400    let flres = fl + 7.0
401    flres = fl - 7.0
402    flres = fl * 7.0
403    flres = fl / 7.0
404  endif
405enddef
406
407def Test_disassemble_computing()
408  let instr = execute('disassemble Computing')
409  assert_match('Computing.*'
410        \ .. 'let nr = 3.*'
411        \ .. '\d STORE 3 in $0.*'
412        \ .. 'let nrres = nr + 7.*'
413        \ .. '\d LOAD $0.*'
414        \ .. '\d PUSHNR 7.*'
415        \ .. '\d OPNR +.*'
416        \ .. '\d STORE $1.*'
417        \ .. 'nrres = nr - 7.*'
418        \ .. '\d OPNR -.*'
419        \ .. 'nrres = nr \* 7.*'
420        \ .. '\d OPNR \*.*'
421        \ .. 'nrres = nr / 7.*'
422        \ .. '\d OPNR /.*'
423        \ .. 'nrres = nr % 7.*'
424        \ .. '\d OPNR %.*'
425        \ .. 'let anyres = g:number + 7.*'
426        \ .. '\d LOADG g:number.*'
427        \ .. '\d PUSHNR 7.*'
428        \ .. '\d OPANY +.*'
429        \ .. '\d STORE $2.*'
430        \ .. 'anyres = g:number - 7.*'
431        \ .. '\d OPANY -.*'
432        \ .. 'anyres = g:number \* 7.*'
433        \ .. '\d OPANY \*.*'
434        \ .. 'anyres = g:number / 7.*'
435        \ .. '\d OPANY /.*'
436        \ .. 'anyres = g:number % 7.*'
437        \ .. '\d OPANY %.*'
438        \, instr)
439  if has('float')
440    assert_match('Computing.*'
441        \ .. 'let fl = 3.0.*'
442        \ .. '\d PUSHF 3.0.*'
443        \ .. '\d STORE $3.*'
444        \ .. 'let flres = fl + 7.0.*'
445        \ .. '\d LOAD $3.*'
446        \ .. '\d PUSHF 7.0.*'
447        \ .. '\d OPFLOAT +.*'
448        \ .. '\d STORE $4.*'
449        \ .. 'flres = fl - 7.0.*'
450        \ .. '\d OPFLOAT -.*'
451        \ .. 'flres = fl \* 7.0.*'
452        \ .. '\d OPFLOAT \*.*'
453        \ .. 'flres = fl / 7.0.*'
454        \ .. '\d OPFLOAT /.*'
455        \, instr)
456  endif
457enddef
458
459def AddListBlob()
460  let reslist = [1, 2] + [3, 4]
461  let resblob = 0z1122 + 0z3344
462enddef
463
464def Test_disassemble_add_list_blob()
465  let instr = execute('disassemble AddListBlob')
466  assert_match('AddListBlob.*'
467        \ .. 'let reslist = \[1, 2] + \[3, 4].*'
468        \ .. '\d PUSHNR 1.*'
469        \ .. '\d PUSHNR 2.*'
470        \ .. '\d NEWLIST size 2.*'
471        \ .. '\d PUSHNR 3.*'
472        \ .. '\d PUSHNR 4.*'
473        \ .. '\d NEWLIST size 2.*'
474        \ .. '\d ADDLIST.*'
475        \ .. '\d STORE $.*.*'
476        \ .. 'let resblob = 0z1122 + 0z3344.*'
477        \ .. '\d PUSHBLOB 0z1122.*'
478        \ .. '\d PUSHBLOB 0z3344.*'
479        \ .. '\d ADDBLOB.*'
480        \ .. '\d STORE $.*'
481        \, instr)
482enddef
483
484let g:aa = 'aa'
485def ConcatString(): string
486  let res = g:aa .. "bb"
487  return res
488enddef
489
490def Test_disassemble_concat()
491  let instr = execute('disassemble ConcatString')
492  assert_match('ConcatString.*'
493        \ .. 'let res = g:aa .. "bb".*'
494        \ .. '\d LOADG g:aa.*'
495        \ .. '\d PUSHS "bb".*'
496        \ .. '\d 2STRING stack\[-2].*'
497        \ .. '\d CONCAT.*'
498        \ .. '\d STORE $.*'
499        \, instr)
500  assert_equal('aabb', ConcatString())
501enddef
502
503def ListIndex(): number
504  let l = [1, 2, 3]
505  let res = l[1]
506  return res
507enddef
508
509def Test_disassemble_list_index()
510  let instr = execute('disassemble ListIndex')
511  assert_match('ListIndex.*'
512        \ .. 'let l = \[1, 2, 3].*'
513        \ .. '\d PUSHNR 1.*'
514        \ .. '\d PUSHNR 2.*'
515        \ .. '\d PUSHNR 3.*'
516        \ .. '\d NEWLIST size 3.*'
517        \ .. '\d STORE $0.*'
518        \ .. 'let res = l\[1].*'
519        \ .. '\d LOAD $0.*'
520        \ .. '\d PUSHNR 1.*'
521        \ .. '\d INDEX.*'
522        \ .. '\d STORE $1.*'
523        \, instr)
524  assert_equal(2, ListIndex())
525enddef
526
527def DictMember(): number
528  let d = #{item: 1}
529  let res = d.item
530  return res
531enddef
532
533def Test_disassemble_dict_member()
534  let instr = execute('disassemble DictMember')
535  assert_match('DictMember.*'
536        \ .. 'let d = #{item: 1}.*'
537        \ .. '\d PUSHS "item".*'
538        \ .. '\d PUSHNR 1.*'
539        \ .. '\d NEWDICT size 1.*'
540        \ .. '\d STORE $0.*'
541        \ .. 'let res = d.item.*'
542        \ .. '\d LOAD $0.*'
543        \ .. '\d MEMBER item.*'
544        \ .. '\d STORE $1.*'
545        \, instr)
546  call assert_equal(1, DictMember())
547enddef
548
549def NegateNumber(): number
550  let nr = 9
551  let plus = +nr
552  let res = -nr
553  return res
554enddef
555
556def Test_disassemble_negate_number()
557  let instr = execute('disassemble NegateNumber')
558  assert_match('NegateNumber.*'
559        \ .. 'let nr = 9.*'
560        \ .. '\d STORE 9 in $0.*'
561        \ .. 'let plus = +nr.*'
562        \ .. '\d LOAD $0.*'
563        \ .. '\d CHECKNR.*'
564        \ .. '\d STORE $1.*'
565        \ .. 'let res = -nr.*'
566        \ .. '\d LOAD $0.*'
567        \ .. '\d NEGATENR.*'
568        \ .. '\d STORE $2.*'
569        \, instr)
570  call assert_equal(-9, NegateNumber())
571enddef
572
573def InvertBool(): bool
574  let flag = true
575  let invert = !flag
576  let res = !!flag
577  return res
578enddef
579
580def Test_disassemble_invert_bool()
581  let instr = execute('disassemble InvertBool')
582  assert_match('InvertBool.*'
583        \ .. 'let flag = true.*'
584        \ .. '\d PUSH v:true.*'
585        \ .. '\d STORE $0.*'
586        \ .. 'let invert = !flag.*'
587        \ .. '\d LOAD $0.*'
588        \ .. '\d INVERT (!val).*'
589        \ .. '\d STORE $1.*'
590        \ .. 'let res = !!flag.*'
591        \ .. '\d LOAD $0.*'
592        \ .. '\d 2BOOL (!!val).*'
593        \ .. '\d STORE $2.*'
594        \, instr)
595  call assert_equal(true, InvertBool())
596enddef
597
598def Test_disassemble_compare()
599  " TODO: COMPAREFUNC
600  let cases = [
601        \ ['true == false', 'COMPAREBOOL =='],
602        \ ['true != false', 'COMPAREBOOL !='],
603        \ ['v:none == v:null', 'COMPARESPECIAL =='],
604        \ ['v:none != v:null', 'COMPARESPECIAL !='],
605        \
606        \ ['111 == 222', 'COMPARENR =='],
607        \ ['111 != 222', 'COMPARENR !='],
608        \ ['111 > 222', 'COMPARENR >'],
609        \ ['111 < 222', 'COMPARENR <'],
610        \ ['111 >= 222', 'COMPARENR >='],
611        \ ['111 <= 222', 'COMPARENR <='],
612        \ ['111 =~ 222', 'COMPARENR =\~'],
613        \ ['111 !~ 222', 'COMPARENR !\~'],
614        \
615        \ ['"xx" == "yy"', 'COMPARESTRING =='],
616        \ ['"xx" != "yy"', 'COMPARESTRING !='],
617        \ ['"xx" > "yy"', 'COMPARESTRING >'],
618        \ ['"xx" < "yy"', 'COMPARESTRING <'],
619        \ ['"xx" >= "yy"', 'COMPARESTRING >='],
620        \ ['"xx" <= "yy"', 'COMPARESTRING <='],
621        \ ['"xx" =~ "yy"', 'COMPARESTRING =\~'],
622        \ ['"xx" !~ "yy"', 'COMPARESTRING !\~'],
623        \ ['"xx" is "yy"', 'COMPARESTRING is'],
624        \ ['"xx" isnot "yy"', 'COMPARESTRING isnot'],
625        \
626        \ ['0z11 == 0z22', 'COMPAREBLOB =='],
627        \ ['0z11 != 0z22', 'COMPAREBLOB !='],
628        \ ['0z11 is 0z22', 'COMPAREBLOB is'],
629        \ ['0z11 isnot 0z22', 'COMPAREBLOB isnot'],
630        \
631        \ ['[1,2] == [3,4]', 'COMPARELIST =='],
632        \ ['[1,2] != [3,4]', 'COMPARELIST !='],
633        \ ['[1,2] is [3,4]', 'COMPARELIST is'],
634        \ ['[1,2] isnot [3,4]', 'COMPARELIST isnot'],
635        \
636        \ ['#{a:1} == #{x:2}', 'COMPAREDICT =='],
637        \ ['#{a:1} != #{x:2}', 'COMPAREDICT !='],
638        \ ['#{a:1} is #{x:2}', 'COMPAREDICT is'],
639        \ ['#{a:1} isnot #{x:2}', 'COMPAREDICT isnot'],
640        \
641        \ ['{->33} == {->44}', 'COMPAREPARTIAL =='],
642        \ ['{->33} != {->44}', 'COMPAREPARTIAL !='],
643        \ ['{->33} is {->44}', 'COMPAREPARTIAL is'],
644        \ ['{->33} isnot {->44}', 'COMPAREPARTIAL isnot'],
645        \
646        \ ['77 == g:xx', 'COMPAREANY =='],
647        \ ['77 != g:xx', 'COMPAREANY !='],
648        \ ['77 > g:xx', 'COMPAREANY >'],
649        \ ['77 < g:xx', 'COMPAREANY <'],
650        \ ['77 >= g:xx', 'COMPAREANY >='],
651        \ ['77 <= g:xx', 'COMPAREANY <='],
652        \ ['77 =~ g:xx', 'COMPAREANY =\~'],
653        \ ['77 !~ g:xx', 'COMPAREANY !\~'],
654        \ ['77 is g:xx', 'COMPAREANY is'],
655        \ ['77 isnot g:xx', 'COMPAREANY isnot'],
656        \ ]
657  if has('float')
658    cases->extend([
659        \ ['1.1 == 2.2', 'COMPAREFLOAT =='],
660        \ ['1.1 != 2.2', 'COMPAREFLOAT !='],
661        \ ['1.1 > 2.2', 'COMPAREFLOAT >'],
662        \ ['1.1 < 2.2', 'COMPAREFLOAT <'],
663        \ ['1.1 >= 2.2', 'COMPAREFLOAT >='],
664        \ ['1.1 <= 2.2', 'COMPAREFLOAT <='],
665        \ ['1.1 =~ 2.2', 'COMPAREFLOAT =\~'],
666        \ ['1.1 !~ 2.2', 'COMPAREFLOAT !\~'],
667        \ ])
668  endif
669
670  let nr = 1
671  for case in cases
672    writefile(['def TestCase' .. nr .. '()',
673             \ '  if ' .. case[0],
674             \ '    echo 42'
675             \ '  endif',
676             \ 'enddef'], 'Xdisassemble')
677    source Xdisassemble
678    let instr = execute('disassemble TestCase' .. nr)
679    assert_match('TestCase' .. nr .. '.*'
680        \ .. 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*'
681        \ .. '\d \(PUSH\|FUNCREF\).*'
682        \ .. '\d \(PUSH\|FUNCREF\|LOADG\).*'
683        \ .. '\d ' .. case[1] .. '.*'
684        \ .. '\d JUMP_IF_FALSE -> \d\+.*'
685        \, instr)
686
687    nr += 1
688  endfor
689
690  " delete('Xdisassemble')
691enddef
692
693" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
694