# assemble.test -- # # Test suite for the 'tcl::unsupported::assemble' command # # Copyright (c) 2010 by Ozgur Dogan Ugurlu. # Copyright (c) 2010 by Kevin B. Kenny. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: assemble.test,v 1.1.2.15 2010/10/28 19:40:13 kennykb Exp $ #----------------------------------------------------------------------------- # Commands covered: assemble if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2.2 namespace import -force ::tcltest::* } namespace eval tcl::unsupported {namespace export assemble} namespace import tcl::unsupported::assemble # Procedure to make code that fills the literal and local variable tables, # to force instructions to spill to four bytes. proc fillTables {} { set s {} set sep {} for {set i 0} {$i < 256} {incr i} { append s $sep [list set v$i literal$i] set sep \n } return $s } # assemble-1 - TclNRAssembleObjCmd test assemble-1.1 {wrong # args, direct eval} { -body { eval [list assemble] } -returnCodes error -result {wrong # args*} -match glob } test assemble-1.2 {wrong # args, direct eval} { -body { eval [list assemble too many] } -returnCodes error -result {wrong # args*} -match glob } test assemble-1.3 {error reporting, direct eval} { -body { list [catch { eval [list assemble { # bad opcode rubbish }] } result] $result $errorInfo } -match glob -result {1 {bad instruction "rubbish":*} {bad instruction "rubbish":* while executing "rubbish" ("assemble" body, line 3)*}} -cleanup {unset result} } test assemble-1.4 {simple direct eval} { -body { eval [list assemble {push {this is a test}}] } -result {this is a test} } # assemble-2 - CompileAssembleObj test assemble-2.1 {bytecode reuse, direct eval} { -body { set x {push "this is a test"} list [eval [list assemble $x]] \ [eval [list assemble $x]] } -result {{this is a test} {this is a test}} } test assemble-2.2 {bytecode discard, direct eval} { -body { set x {load value} proc p1 {x} { set value value1 assemble $x } proc p2 {x} { set a b set value value2 assemble $x } list [p1 $x] [p2 $x] } -result {value1 value2} -cleanup { unset x rename p1 {} rename p2 {} } } test assemble-2.3 {null script, direct eval} { -body { set x {} assemble $x } -result {} -cleanup {unset x} } # assemble-3 - TclCompileAssembleCmd test assemble-3.1 {wrong # args, compiled path} { -body { proc x {} { assemble } x } -returnCodes error -match glob -result {wrong # args:*} } test assemble-3.2 {wrong # args, compiled path} { -body { proc x {} { assemble too many } x } -returnCodes error -match glob -result {wrong # args:*} -cleanup { rename x {} } } # assemble-4 - TclAssembleCode mainline test assemble-4.1 {syntax error} { -body { proc x {} { assemble { {}extra } } list [catch x result] $result $::errorInfo } -cleanup { rename x {} unset result } -match glob -result {1 {extra characters after close-brace} {extra characters after close-brace while executing "{}extra " ("assemble" body, line 2)*}} } test assemble-4.2 {null command} { -body { proc x {} { assemble { push hello; pop;;push goodbye } } x } -result goodbye -cleanup { rename x {} } } # assemble-5 - GetNextOperand off-nominal cases test assemble-5.1 {unsupported expansion} { -body { proc x {y} { assemble { {*}$y } } list [catch {x {push hello}} result] $result $::errorCode } -result {1 {assembly code may not contain substitutions} {TCL ASSEM NOSUBST}} -cleanup { rename x {} unset result } } test assemble-5.2 {unsupported substitution} { -body { proc x {y} { assemble { $y } } list [catch {x {nop}} result] $result $::errorCode } -cleanup { rename x {} unset result } -result {1 {assembly code may not contain substitutions} {TCL ASSEM NOSUBST}} } test assemble-5.3 {unsupported substitution} { -body { proc x {} { assemble { [x] } } list [catch {x} result] $result $::errorCode } -result {1 {assembly code may not contain substitutions} {TCL ASSEM NOSUBST}} } test assemble-5.4 {backslash substitution} { -body { proc x {} { assemble { p\x75sh\ hello\ world } } x } -cleanup { rename x {} } -result {hello world} } # assemble-6 - ASSEM_PUSH test assemble-6.1 {push, wrong # args} { -body { assemble push } -returnCodes error -match glob -result {wrong # args*} } test assemble-6.2 {push, wrong # args} { -body { assemble {push too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-6.3 {push} { -body { eval [list assemble {push hello}] } -result hello } test assemble-6.4 {push4} { -body { proc x {} " [fillTables] assemble {push hello} " x } -cleanup { rename x {} } -result hello } # assemble-7 - ASSEM_1BYTE test assemble-7.1 {add, wrong # args} { -body { assemble {add excess} } -returnCodes error -match glob -result {wrong # args*} } test assemble-7.2 {add} { -body { assemble { push 2 push 2 add } } -result {4} } test assemble-7.3 {appendArrayStk} { -body { set a(b) {hello, } assemble { push a push b push world appendArrayStk } set a(b) } -result {hello, world} -cleanup {unset a} } test assemble-7.4 {appendStk} { -body { set a {hello, } assemble { push a push world appendStk } set a } -result {hello, world} -cleanup {unset a} } test assemble-7.5 {bitwise ops} { -body { list \ [assemble {push 0b1100; push 0b1010; bitand}] \ [assemble {push 0b1100; bitnot}] \ [assemble {push 0b1100; push 0b1010; bitor}] \ [assemble {push 0b1100; push 0b1010; bitxor}] } -result {8 -13 14 6} } test assemble-7.6 {div} { -body { assemble {push 999999; push 7; div} } -result 142857 } test assemble-7.7 {dup} { -body { assemble { push 1; dup; dup; add; dup; add; dup; add; add } } -result 9 } test assemble-7.8 {eq} { -body { list \ [assemble {push able; push baker; eq}] \ [assemble {push able; push able; eq}] } -result {0 1} } test assemble-7.9 {evalStk} { -body { assemble { push {concat test 7.3} evalStk } } -result {test 7.3} } test assemble-7.9a {evalStk, syntax} { -body { assemble { push {{}bad} evalStk } } -returnCodes error -result {extra characters after close-brace} } test assemble-7.9b {evalStk, backtrace} { -body { proc y {z} { error testing } proc x {} { assemble { push { # test error in evalStk y asd } evalStk } } list [catch x result] $result $errorInfo } -result {1 testing {testing while executing "error testing" (procedure "y" line 2) invoked from within "y asd"*}} -match glob -cleanup { rename y {} rename x {} } } test assemble-7.10 {existArrayStk} { -body { proc x {name key} { set a(b) c assemble { load name; load key; existArrayStk } } list [x a a] [x a b] [x b a] [x b b] } -result {0 1 0 0} -cleanup {rename x {}} } test assemble-7.11 {existStk} { -body { proc x {name} { set a b assemble { load name; existStk } } list [x a] [x b] } -result {1 0} -cleanup {rename x {}} } test assemble-7.12 {expon} { -body { assemble {push 3; push 4; expon} } -result 81 } test assemble-7.13 {exprStk} { -body { assemble { push {acos(-1)} exprStk } } -result 3.141592653589793 } test assemble-7.13a {exprStk, syntax} { -body { assemble { push {2+} exprStk } } -returnCodes error -result {missing operand at _@_ in expression "2+_@_"} } test assemble-7.13b {exprStk, backtrace} { -body { proc y {z} { error testing } proc x {} { assemble { push {[y asd]} exprStk } } list [catch x result] $result $errorInfo } -result {1 testing {testing while executing "error testing" (procedure "y" line 2) invoked from within "y asd"*}} -match glob -cleanup { rename y {} rename x {} } } test assemble-7.14 {ge gt le lt} { -body { proc x {a b} { list [assemble {load a; load b; ge}] \ [assemble {load a; load b; gt}] \ [assemble {load a; load b; le}] \ [assemble {load a; load b; lt}] } list [x 0 0] [x 0 1] [x 1 0] } -result {{1 0 1 0} {0 0 1 1} {1 1 0 0}} -cleanup {rename x {}} } test assemble-7.15 {incrArrayStk} { -body { proc x {} { set a(b) 5 assemble { push a; push b; push 7; incrArrayStk } } x } -result 12 -cleanup {rename x {}} } test assemble-7.16 {incrStk} { -body { proc x {} { set a 5 assemble { push a; push 7; incrStk } } x } -result 12 -cleanup {rename x {}} } test assemble-7.17 {land/lor} { -body { proc x {a b} { list \ [assemble {load a; load b; land}] \ [assemble {load a; load b; lor}] } list [x 0 0] [x 0 23] [x 35 0] [x 47 59] } -result {{0 0} {0 1} {0 1} {1 1}} -cleanup {rename x {}} } test assemble-7.18 {lappendArrayStk} { -body { proc x {} { set able(baker) charlie assemble { push able push baker push dog lappendArrayStk } } x } -result {charlie dog} -cleanup {rename x {}} } test assemble-7.19 {lappendStk} { -body { proc x {} { set able baker assemble { push able push charlie lappendStk } } x } -result {baker charlie} -cleanup {rename x {}} } test assemble-7.20 {listIndex} { -body { assemble { push {a b c d} push 2 listIndex } } -result c } test assemble-7.21 {listLength} { -body { assemble { push {a b c d} listLength } } -result 4 } test assemble-7.22 {loadArrayStk} { -body { proc x {} { set able(baker) charlie assemble { push able push baker loadArrayStk } } x } -result charlie -cleanup {rename x {}} } test assemble-7.23 {loadStk} { -body { proc x {} { set able baker assemble { push able loadStk } } x } -result baker -cleanup {rename x {}} } test assemble-7.24 {lsetList} { -body { proc x {} { set l {{a b} {c d} {e f} {g h}} assemble { push {2 1}; push i; load l; lsetList } } x } -result {{a b} {c d} {e i} {g h}} } test assemble-7.25 {lshift} { -body { assemble {push 16; push 4; lshift} } -result 256 } test assemble-7.26 {mod} { -body { assemble {push 123456; push 1000; mod} } -result 456 } test assemble-7.27 {mult} { -body { assemble {push 12345679; push 9; mult} } -result 111111111 } test assemble-7.28 {neq} { -body { list \ [assemble {push able; push baker; neq}] \ [assemble {push able; push able; neq}] } -result {1 0} } test assemble-7.29 {not} { -body { list \ [assemble {push 17; not}] \ [assemble {push 0; not}] } -result {0 1} } test assemble-7.30 {pop} { -body { assemble {push this; pop; push that} } -result that } test assemble-7.31 {rshift} { -body { assemble {push 257; push 4; rshift} } -result 16 } test assemble-7.32 {storeArrayStk} { -body { proc x {} { assemble { push able; push baker; push charlie; storeArrayStk } array get able } x } -result {baker charlie} -cleanup {rename x {}} } test assemble-7.33 {storeStk} { -body { proc x {} { assemble { push able; push baker; storeStk } set able } x } -result {baker} -cleanup {rename x {}} } test assemble-7,34 {strcmp} { -body { proc x {a b} { assemble { load a; load b; strcmp } } list [x able baker] [x baker able] [x baker baker] } -result {-1 1 0} -cleanup {rename x {}} } test assemble-7.35 {streq/strneq} { -body { proc x {a b} { list \ [assemble {load a; load b; streq}] \ [assemble {load a; load b; strneq}] } list [x able able] [x able baker] } -result {{1 0} {0 1}} -cleanup {rename x {}} } test assemble-7.36 {strindex} { -body { assemble {push testing; push 4; strindex} } -result i } test assemble-7.37 {strlen} { -body { assemble {push testing; strlen} } -result 7 } test assemble-7.38 {sub} { -body { assemble {push 42; push 17; sub} } -result 25 } test assemble-7.39 {tryCvtToNumeric} { -body { assemble { push 42; tryCvtToNumeric } } -result 42 } test assemble-7.41 {uminus} { -body { assemble { push 42; uminus } } -result -42 } test assemble-7.42 {uplus} { -body { assemble { push 42; uplus } } -result 42 } test assemble-7.43 {uplus} { -body { assemble { push NaN; uplus } } -returnCodes error -result {can't use non-numeric floating-point value as operand of "+"} } test assemble-7.43 {tryCvtToNumeric} { -body { assemble { push NaN; tryCvtToNumeric } } -returnCodes error -result {domain error: argument not in valid range} } test assemble-7.44 {listIn} { -body { assemble { push b; push {a b c}; listIn } } -result 1 } test assemble-7.45 {listNotIn} { -body { assemble { push d; push {a b c}; listNotIn } } -result 1 } test assemble-7.46 {nop} { -body { assemble { push x; nop; nop; nop} } -result x } # assemble-8 ASSEM_LVT and FindLocalVar test assemble-8.1 {load, wrong # args} { -body { assemble load } -returnCodes error -match glob -result {wrong # args*} } test assemble-8.2 {load, wrong # args} { -body { assemble {load too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-8.3 {nonlocal var} { -body { list [catch {assemble {load ::env}} result] $result $errorCode } -result {1 {variable "::env" is not local} {TCL ASSEM NONLOCAL ::env}} -cleanup {unset result} } test assemble-8.4 {bad context} { -body { set x 1 list [catch {assemble {load x}} result] $result $errorCode } -result {1 {cannot use this instruction to create a variable in a non-proc context} {TCL ASSEM LVT}} -cleanup {unset result} } test assemble-8.5 {bad context} { -body { namespace eval assem { set x 1 list [catch {assemble {load x}} result] $result $errorCode } } -result {1 {cannot use this instruction to create a variable in a non-proc context} {TCL ASSEM LVT}} -cleanup {namespace delete assem} } test assemble-8.6 {load1} { -body { proc x {a} { assemble { load a } } x able } -result able -cleanup {rename x {}} } test assemble-8.7 {load4} { -body { proc x {a} " [fillTables] set b \$a assemble {load b} " x able } -result able -cleanup {rename x {}} } test assemble-8.8 {loadArray1} { -body { proc x {} { set able(baker) charlie assemble { push baker loadArray able } } x } -result charlie -cleanup {rename x {}} } test assemble-8.9 {loadArray4} { -body " proc x {} { [fillTables] set able(baker) charlie assemble { push baker loadArray able } } x " -result charlie -cleanup {rename x {}} } test assemble-8.10 {append1} { -body { proc x {} { set y {hello, } assemble { push world; append y } } x } -result {hello, world} -cleanup {rename x {}} } test assemble-8.11 {append4} { -body { proc x {} " [fillTables] set y {hello, } assemble { push world; append y } " x } -result {hello, world} -cleanup {rename x {}} } test assemble-8.12 {appendArray1} { -body { proc x {} { set y(z) {hello, } assemble { push z; push world; appendArray y } } x } -result {hello, world} -cleanup {rename x {}} } test assemble-8.13 {appendArray4} { -body { proc x {} " [fillTables] set y(z) {hello, } assemble { push z; push world; appendArray y } " x } -result {hello, world} -cleanup {rename x {}} } test assemble-8.14 {lappend1} { -body { proc x {} { set y {hello,} assemble { push world; lappend y } } x } -result {hello, world} -cleanup {rename x {}} } test assemble-8.15 {lappend4} { -body { proc x {} " [fillTables] set y {hello,} assemble { push world; lappend y } " x } -result {hello, world} -cleanup {rename x {}} } test assemble-8.16 {lappendArray1} { -body { proc x {} { set y(z) {hello,} assemble { push z; push world; lappendArray y } } x } -result {hello, world} -cleanup {rename x {}} } test assemble-8.17 {lappendArray4} { -body { proc x {} " [fillTables] set y(z) {hello,} assemble { push z; push world; lappendArray y } " x } -result {hello, world} -cleanup {rename x {}} } test assemble-8.18 {store1} { -body { proc x {} { assemble { push test; store y } set y } x } -result {test} -cleanup {rename x {}} } test assemble-8.19 {store4} { -body { proc x {} " [fillTables] assemble { push test; store y } set y " x } -result test -cleanup {rename x {}} } test assemble-8.20 {storeArray1} { -body { proc x {} { assemble { push z; push test; storeArray y } set y(z) } x } -result test -cleanup {rename x {}} } test assemble-8.21 {storeArray4} { -body { proc x {} " [fillTables] assemble { push z; push test; storeArray y } " x } -result test -cleanup {rename x {}} } # assemble-9 - ASSEM_CONCAT1, GetIntegerOperand, CheckOneByte test assemble-9.1 {wrong # args} { -body {assemble concat} -result {wrong # args*} -match glob -returnCodes error } test assemble-9.2 {wrong # args} { -body {assemble {concat too many}} -result {wrong # args*} -match glob -returnCodes error } test assemble-9.3 {not a number} { -body {assemble {concat rubbish}} -result {expected integer but got "rubbish"} -returnCodes error } test assemble-9.4 {too small} { -body {assemble {concat -1}} -result {operand does not fit in one byte} -returnCodes error } test assemble-9.5 {too small} { -body {assemble {concat 256}} -result {operand does not fit in one byte} -returnCodes error } test assemble-9.6 {concat} { -body { assemble {push h; push e; push l; push l; push o; concat 5} } -result hello } test assemble-9.7 {concat} { -body { list [catch {assemble {concat 0}} result] $result $::errorCode } -result {1 {operand must be positive} {TCL ASSEM POSITIVE}} -cleanup {unset result} } # assemble-10 -- eval and expr test assemble-10.1 {eval - wrong # args} { -body { assemble {eval} } -returnCodes error -match glob -result {wrong # args*} } test assemble-10.2 {eval - wrong # args} { -body { assemble {eval too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-10.3 {eval} { -body { proc x {} { assemble { push 3 store n pop eval {expr {3*$n + 1}} push 1 add } } x } -result 11 -cleanup {rename x {}} } test assemble-10.4 {expr} { -body { proc x {} { assemble { push 3 store n pop expr {3*$n + 1} push 1 add } } x } -result 11 -cleanup {rename x {}} } test assemble-10.5 {eval and expr - nonsimple} { -body { proc x {} { assemble { eval "s\x65t n 3" pop expr "\x33*\$n + 1" push 1 add } } x } -result 11 -cleanup { rename x {} } } test assemble-10.6 {eval - noncompilable} { -body { list [catch {assemble {eval $x}} result] $result $::errorCode } -result {1 {assembly code may not contain substitutions} {TCL ASSEM NOSUBST}} } test assemble-10.7 {expr - noncompilable} { -body { list [catch {assemble {expr $x}} result] $result $::errorCode } -result {1 {assembly code may not contain substitutions} {TCL ASSEM NOSUBST}} } # assemble-11 - ASSEM_LVT4 (exist, existArray, dictAppend, dictLappend, # nsupvar, variable, upvar) test assemble-11.1 {exist - wrong # args} { -body { assemble {exist} } -returnCodes error -match glob -result {wrong # args*} } test assemble-11.2 {exist - wrong # args} { -body { assemble {exist too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-11.3 {nonlocal var} { -body { list [catch {assemble {exist ::env}} result] $result $errorCode } -result {1 {variable "::env" is not local} {TCL ASSEM NONLOCAL ::env}} -cleanup {unset result} } test assemble-11.4 {exist} { -body { proc x {} { set y z list [assemble {exist y}] \ [assemble {exist z}] } x } -result {1 0} -cleanup {rename x {}} } test assemble-11.5 {existArray} { -body { proc x {} { set a(b) c list [assemble {push b; existArray a}] \ [assemble {push c; existArray a}] \ [assemble {push a; existArray b}] } x } -result {1 0 0} -cleanup {rename x {}} } test assemble-11.6 {dictAppend} { -body { proc x {} { set dict {a 1 b 2 c 3} assemble {push b; push 22; dictAppend dict} } x } -result {a 1 b 222 c 3} -cleanup {rename x {}} } test assemble-11.7 {dictLappend} { -body { proc x {} { set dict {a 1 b 2 c 3} assemble {push b; push 2; dictLappend dict} } x } -result {a 1 b {2 2} c 3} -cleanup {rename x {}} } test assemble-11.8 {upvar} { -body { proc x {v} { assemble {push 1; load v; upvar w; pop; load w} } proc y {} { set z 123 x z } y } -result 123 -cleanup {rename x {}; rename y {}} } test assemble-11.9 {nsupvar} { -body { namespace eval q { variable v 123 } proc x {} { assemble {push q; push v; nsupvar y; pop; load y} } x } -result 123 -cleanup {namespace delete q; rename x {}} } test assemble-11.10 {variable} { -body { namespace eval q { namespace eval r {variable v 123}} proc x {} { assemble {push q::r::v; variable y; load y} } x } -result 123 -cleanup {namespace delete q; rename x {}} } # assemble-12 - ASSEM_LVT1 (incr and incrArray) test assemble-12.1 {incr - wrong # args} { -body { assemble {incr} } -returnCodes error -match glob -result {wrong # args*} } test assemble-12.2 {incr - wrong # args} { -body { assemble {incr too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-12.3 {incr nonlocal var} { -body { list [catch {assemble {incr ::env}} result] $result $errorCode } -result {1 {variable "::env" is not local} {TCL ASSEM NONLOCAL ::env}} -cleanup {unset result} } test assemble-12.4 {incr} { -body { proc x {} { set y 5 assemble {push 3; incr y} } x } -result 8 -cleanup {rename x {}} } test assemble-12.5 {incrArray} { -body { proc x {} { set a(b) 5 assemble {push b; push 3; incrArray a} } x } -result 8 -cleanup {rename x {}} } test assemble-12.6 {incr, stupid stack restriction} { -body { proc x {} " [fillTables] set y 5 assemble {push 3; incr y} " list [catch {x} result] $result $errorCode } -result {1 {operand does not fit in one byte} {TCL ASSEM 1BYTE}} -cleanup {unset result; rename x {}} } # assemble-13 -- ASSEM_LVT1_SINT1 - incrImm and incrArrayImm test assemble-13.1 {incrImm - wrong # args} { -body { assemble {incrImm x} } -returnCodes error -match glob -result {wrong # args*} } test assemble-13.2 {incrImm - wrong # args} { -body { assemble {incrImm too many args} } -returnCodes error -match glob -result {wrong # args*} } test assemble-13.3 {incrImm nonlocal var} { -body { list [catch {assemble {incrImm ::env 2}} result] $result $errorCode } -result {1 {variable "::env" is not local} {TCL ASSEM NONLOCAL ::env}} -cleanup {unset result} } test assemble-13.4 {incrImm not a number} { -body { proc x {} { assemble {incrImm x rubbish} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-13.5 {incrImm too big} { -body { proc x {} { assemble {incrImm x 0x80} } list [catch x result] $result $::errorCode } -result {1 {operand does not fit in one byte} {TCL ASSEM 1BYTE}} -cleanup {rename x {}; unset result} } test assemble-13.6 {incrImm too small} { -body { proc x {} { assemble {incrImm x -0x81} } list [catch x result] $result $::errorCode } -result {1 {operand does not fit in one byte} {TCL ASSEM 1BYTE}} -cleanup {rename x {}; unset result} } test assemble-13.7 {incrImm} { -body { proc x {} { set y 1 list [assemble {incrImm y -0x80}] [assemble {incrImm y 0x7f}] } x } -result {-127 0} -cleanup {rename x {}} } test assemble-13.8 {incrArrayImm} { -body { proc x {} { set a(b) 5 assemble {push b; incrArrayImm a 3} } x } -result 8 -cleanup {rename x {}} } test assemble-13.9 {incrImm, stupid stack restriction} { -body { proc x {} " [fillTables] set y 5 assemble {incrImm y 3} " list [catch {x} result] $result $errorCode } -result {1 {operand does not fit in one byte} {TCL ASSEM 1BYTE}} -cleanup {unset result; rename x {}} } # assemble-14 -- ASSEM_SINT1 (incrArrayStkImm and incrStkImm) test assemble-14.1 {incrStkImm - wrong # args} { -body { assemble {incrStkImm} } -returnCodes error -match glob -result {wrong # args*} } test assemble-14.2 {incrStkImm - wrong # args} { -body { assemble {incrStkImm too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-14.3 {incrStkImm not a number} { -body { proc x {} { assemble {incrStkImm rubbish} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-14.4 {incrStkImm too big} { -body { proc x {} { assemble {incrStkImm 0x80} } list [catch x result] $result $::errorCode } -result {1 {operand does not fit in one byte} {TCL ASSEM 1BYTE}} -cleanup {rename x {}; unset result} } test assemble-14.5 {incrStkImm too small} { -body { proc x {} { assemble {incrStkImm -0x81} } list [catch x result] $result $::errorCode } -result {1 {operand does not fit in one byte} {TCL ASSEM 1BYTE}} -cleanup {rename x {}; unset result} } test assemble-14.6 {incrStkImm} { -body { proc x {} { set y 1 list [assemble {push y; incrStkImm -0x80}] \ [assemble {push y; incrStkImm 0x7f}] } x } -result {-127 0} -cleanup {rename x {}} } test assemble-14.7 {incrArrayStkImm} { -body { proc x {} { set a(b) 5 assemble {push a; push b; incrArrayStkImm 3} } x } -result 8 -cleanup {rename x {}} } # assemble-15 - listIndexImm test assemble-15.1 {listIndexImm - wrong # args} { -body { assemble {listIndexImm} } -returnCodes error -match glob -result {wrong # args*} } test assemble-16.2 {listIndexImm - wrong # args} { -body { assemble {listIndexImm too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-16.3 {listIndexImm - bad substitution} { -body { list [catch {assemble {listIndexImm $foo}} result] $result $::errorCode } -result {1 {assembly code may not contain substitutions} {TCL ASSEM NOSUBST}} -cleanup {unset result} } test assemble-16.4 {listIndexImm - invalid index} { -body { assemble {listIndexImm rubbish} } -returnCodes error -match glob -result {bad index "rubbish"*} } test assemble-16.5 {listIndexImm} { -body { assemble {push {a b c}; listIndexImm 2} } -result c } test assemble-16.6 {listIndexImm} { -body { assemble {push {a b c}; listIndexImm end-1} } -result b } test assemble-16.6 {listIndexImm} { -body { assemble {push {a b c}; listIndexImm end} } -result c } # assemble-16 - invokeStk test assemble-16.1 {invokeStk - wrong # args} { -body { assemble {invokeStk} } -returnCodes error -match glob -result {wrong # args*} } test assemble-16.2 {invokeStk - wrong # args} { -body { assemble {invokeStk too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-16.3 {invokeStk - not a number} { -body { proc x {} { assemble {invokeStk rubbish} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-16.4 {invokeStk - no operands} { -body { proc x {} { assemble {invokeStk 0} } list [catch x result] $result $::errorCode } -result {1 {operand must be positive} {TCL ASSEM POSITIVE}} -cleanup {rename x {}; unset result} } test assemble-16.5 {invokeStk1} { -body { tcl::unsupported::assemble {push concat; push 1; push 2; invokeStk 3} } -result {1 2} } test assemble-16.6 {invokeStk4} { -body { proc x {n} { set code {push concat} set shouldbe {} for {set i 1} {$i < $n} {incr i} { append code \n {push a} $i lappend shouldbe a$i } append code \n {invokeStk} { } $n set is [assemble $code] expr {$is eq $shouldbe} } list [x 254] [x 255] [x 256] [x 257] } -result {1 1 1 1} -cleanup {rename x {}} } # assemble-17 -- jumps and labels test assemble-17.1 {label, wrong # args} { -body { assemble {label} } -returnCodes error -match glob -result {wrong # args*} } test assemble-17.2 {label, wrong # args} { -body { assemble {label too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-17.3 {label, bad subst} { -body { list [catch {assemble {label $foo}} result] $result $::errorCode } -result {1 {assembly code may not contain substitutions} {TCL ASSEM NOSUBST}} -cleanup {unset result} } test assemble-17.4 {duplicate label} { -body { list [catch {assemble {label foo; label foo}} result] \ $result $::errorCode } -result {1 {duplicate definition of label "foo"} {TCL ASSEM DUPLABEL foo}} } test assemble-17.5 {jump, wrong # args} { -body { assemble {jump} } -returnCodes error -match glob -result {wrong # args*} } test assemble-17.6 {jump, wrong # args} { -body { assemble {jump too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-17.7 {jump, bad subst} { -body { list [catch {assemble {jump $foo}} result] $result $::errorCode } -result {1 {assembly code may not contain substitutions} {TCL ASSEM NOSUBST}} -cleanup {unset result} } test assemble-17.8 {jump - ahead and back} { -body { assemble { jump three label one push a jump four label two push b jump six label three push c jump five label four push d jump two label five push e jump one label six push f concat 6 } } -result ceadbf } test assemble-17.9 {jump - resolve a label multiple times} { -body { proc x {} { set case 0 set result {} assemble { jump common label zero pop incrImm case 1 pop push a append result pop jump common label one pop incrImm case 1 pop push b append result pop jump common label common load case dup push 0 eq jumpTrue zero dup push 1 eq jumpTrue one dup push 2 eq jumpTrue two dup push 3 eq jumpTrue three label two pop incrImm case 1 pop push c append result pop jump common label three pop incrImm case 1 pop push d append result } } x } -result abcd -cleanup {rename x {}} } test assemble-17.10 {jump4 needed} { -body { assemble "push x; jump one; label two; [string repeat {dup; pop;} 128] jump three; label one; jump two; label three" } -result x } test assemble-17.11 {jumpTrue} { -body { proc x {y} { assemble { load y jumpTrue then push no jump else label then push yes label else } } list [x 0] [x 1] } -result {no yes} -cleanup {rename x {}} } test assemble-17.12 {jumpFalse} { -body { proc x {y} { assemble { load y jumpFalse then push no jump else label then push yes label else } } list [x 0] [x 1] } -result {yes no} -cleanup {rename x {}} } test assemble-17.13 {jump to undefined label} { -body { list [catch {assemble {jump nowhere}} result] $result $::errorCode } -result {1 {undefined label "nowhere"} {TCL ASSEM NOLABEL nowhere}} } test assemble-17.14 {jump to undefined label, line number correct?} { -body { catch {assemble {#1 #2 #3 jump nowhere #5 #6 }} set ::errorInfo } -match glob -result {*"assemble" body, line 4*} } test assemble-17.15 {multiple passes of code resizing} { -setup { set body { push - } for {set i 0} {$i < 14} {incr i} { append body "label a" $i \ "; push a; concat 2; nop; nop; jump b" \ $i \n } append body {label a14; push a; concat 2; push 1; jumpTrue b14} \n append body {label a15; push a; concat 2; push 0; jumpFalse b15} \n for {set i 0} {$i < 15} {incr i} { append body "label b" $i \ "; push b; concat 2; nop; nop; jump a" \ [expr {$i+1}] \n } append body {label c; push -; concat 2; nop; nop; nop; jump d} \n append body {label b15; push b; concat 2; nop; nop; jump c} \n append body {label d} proc x {} [list assemble $body] } -body { x } -cleanup { catch {unset body} catch {rename x {}} } -result -abababababababababababababababab- } # assemble-18 - lindexMulti test assemble-18.1 {lindexMulti - wrong # args} { -body { assemble {lindexMulti} } -returnCodes error -match glob -result {wrong # args*} } test assemble-18.2 {lindexMulti - wrong # args} { -body { assemble {lindexMulti too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-18.3 {lindexMulti - bad subst} { -body { assemble {lindexMulti $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-18.4 {lindexMulti - not a number} { -body { proc x {} { assemble {lindexMulti rubbish} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-18.5 {lindexMulti - bad operand count} { -body { proc x {} { assemble {lindexMulti 0} } list [catch x result] $result $::errorCode } -result {1 {operand must be positive} {TCL ASSEM POSITIVE}} -cleanup {rename x {}; unset result} } test assemble-18.6 {lindexMulti} { -body { assemble {push {{a b c} {d e f} {g h j}}; lindexMulti 1} } -result {{a b c} {d e f} {g h j}} } test assemble-18.7 {lindexMulti} { -body { assemble {push {{a b c} {d e f} {g h j}}; push 1; lindexMulti 2} } -result {d e f} } test assemble-18.8 {lindexMulti} { -body { assemble {push {{a b c} {d e f} {g h j}}; push 2; push 1; lindexMulti 3} } -result h } # assemble-19 - list test assemble-19.1 {list - wrong # args} { -body { assemble {list} } -returnCodes error -match glob -result {wrong # args*} } test assemble-19.2 {list - wrong # args} { -body { assemble {list too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-19.3 {list - bad subst} { -body { assemble {list $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-19.4 {list - not a number} { -body { proc x {} { assemble {list rubbish} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-19.5 {list - negative operand count} { -body { proc x {} { assemble {list -1} } list [catch x result] $result $::errorCode } -result {1 {operand must be nonnegative} {TCL ASSEM NONNEGATIVE}} -cleanup {rename x {}; unset result} } test assemble-19.6 {list - no args} { -body { assemble {list 0} } -result {} } test assemble-19.7 {list - 1 arg} { -body { assemble {push hello; list 1} } -result hello } test assemble-19.8 {list - 2 args} { -body { assemble {push hello; push world; list 2} } -result {hello world} } # assemble-20 - lsetFlat test assemble-20.1 {lsetFlat - wrong # args} { -body { assemble {lsetFlat} } -returnCodes error -match glob -result {wrong # args*} } test assemble-20.2 {lsetFlat - wrong # args} { -body { assemble {lsetFlat too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-20.3 {lsetFlat - bad subst} { -body { assemble {lsetFlat $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-20.4 {lsetFlat - not a number} { -body { proc x {} { assemble {lsetFlat rubbish} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-20.5 {lsetFlat - negative operand count} { -body { proc x {} { assemble {lsetFlat 1} } list [catch x result] $result $::errorCode } -result {1 {operand must be >=2} {TCL ASSEM OPERAND>=2}} -cleanup {rename x {}; unset result} } test assemble-20.6 {lsetFlat} { -body { assemble {push b; push a; lsetFlat 2} } -result b } test assemble-20.7 {lsetFlat} { -body { assemble {push 1; push d; push {a b c}; lsetFlat 3} } -result {a d c} } # assemble-21 - over test assemble-21.1 {over - wrong # args} { -body { assemble {over} } -returnCodes error -match glob -result {wrong # args*} } test assemble-21.2 {over - wrong # args} { -body { assemble {over too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-21.3 {over - bad subst} { -body { assemble {over $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-21.4 {over - not a number} { -body { proc x {} { assemble {over rubbish} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-21.5 {over - negative operand count} { -body { proc x {} { assemble {over -1} } list [catch x result] $result $::errorCode } -result {1 {operand must be nonnegative} {TCL ASSEM NONNEGATIVE}} -cleanup {rename x {}; unset result} } test assemble-21.6 {over} { -body { proc x {} { assemble { push 1 push 2 push 3 over 0 store x pop pop pop pop load x } } x } -result 3 -cleanup {rename x {}} } test assemble-21.7 {over} { -body { proc x {} { assemble { push 1 push 2 push 3 over 2 store x pop pop pop pop load x } } x } -result 1 -cleanup {rename x {}} } # assemble-22 - reverse test assemble-22.1 {reverse - wrong # args} { -body { assemble {reverse} } -returnCodes error -match glob -result {wrong # args*} } test assemble-22.2 {reverse - wrong # args} { -body { assemble {reverse too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-22.3 {reverse - bad subst} { -body { assemble {reverse $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-22.4 {reverse - not a number} { -body { proc x {} { assemble {reverse rubbish} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-22.5 {reverse - negative operand count} { -body { proc x {} { assemble {reverse -1} } list [catch x result] $result $::errorCode } -result {1 {operand must be nonnegative} {TCL ASSEM NONNEGATIVE}} -cleanup {rename x {}; unset result} } test assemble-22.6 {reverse - zero operand count} { -body { proc x {} { assemble {push 1; reverse 0} } x } -result 1 -cleanup {rename x {}} } test assemble-22.7 {reverse} { -body { proc x {} { assemble { push 1 push 2 push 3 reverse 1 store x pop pop pop load x } } x } -result 3 -cleanup {rename x {}} } test assemble-22.8 {reverse} { -body { proc x {} { assemble { push 1 push 2 push 3 reverse 3 store x pop pop pop load x } } x } -result 1 -cleanup {rename x {}} } # assemble-23 - ASSEM_BOOL (strmatch, unsetStk, unsetArrayStk) test assemble-23.1 {strmatch - wrong # args} { -body { assemble {strmatch} } -returnCodes error -match glob -result {wrong # args*} } test assemble-23.2 {strmatch - wrong # args} { -body { assemble {strmatch too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-23.3 {strmatch - bad subst} { -body { assemble {strmatch $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-23.4 {strmatch - not a boolean} { -body { proc x {} { assemble {strmatch rubbish} } x } -returnCodes error -result {expected boolean value but got "rubbish"} -cleanup {rename x {}} } test assemble-23.5 {strmatch} { -body { proc x {a b} { list [assemble {load a; load b; strmatch 0}] \ [assemble {load a; load b; strmatch 1}] } list [x foo*.grill fengbar.grill] [x foo*.grill foobar.grill] [x foo*.grill FOOBAR.GRILL] } -result {{0 0} {1 1} {0 1}} -cleanup {rename x {}} } test assemble-23.6 {unsetStk} { -body { proc x {} { set a {} assemble {push a; unsetStk false} info exists a } x } -result 0 -cleanup {rename x {}} } test assemble-23.7 {unsetStk} { -body { proc x {} { assemble {push a; unsetStk false} info exists a } x } -result 0 -cleanup {rename x {}} } test assemble-23.8 {unsetStk} { -body { proc x {} { assemble {push a; unsetStk true} info exists a } x } -returnCodes error -result {can't unset "a": no such variable} -cleanup {rename x {}} } test assemble-23.9 {unsetArrayStk} { -body { proc x {} { set a(b) {} assemble {push a; push b; unsetArrayStk false} info exists a(b) } x } -result 0 -cleanup {rename x {}} } test assemble-23.10 {unsetArrayStk} { -body { proc x {} { assemble {push a; push b; unsetArrayStk false} info exists a(b) } x } -result 0 -cleanup {rename x {}} } test assemble-23.11 {unsetArrayStk} { -body { proc x {} { assemble {push a; push b; unsetArrayStk true} info exists a(b) } x } -returnCodes error -result {can't unset "a(b)": no such variable} -cleanup {rename x {}} } # assemble-24 -- ASSEM_BOOL_LVT4 (unset; unsetArray) test assemble-24.1 {unset - wrong # args} { -body { assemble {unset one} } -returnCodes error -match glob -result {wrong # args*} } test assemble-24.2 {unset - wrong # args} { -body { assemble {unset too many args} } -returnCodes error -match glob -result {wrong # args*} } test assemble-24.3 {unset - bad subst -arg 1} { -body { assemble {unset $foo bar} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-24.4 {unset - not a boolean} { -body { proc x {} { assemble {unset rubbish trash} } x } -returnCodes error -result {expected boolean value but got "rubbish"} -cleanup {rename x {}} } test assemble-24.5 {unset - bad subst - arg 2} { -body { assemble {unset true $bar} } -returnCodes error -result {assembly code may not contain substitutions} } test assemble-24.6 {unset - nonlocal var} { -body { assemble {unset true ::foo::bar} } -returnCodes error -result {variable "::foo::bar" is not local} } test assemble-24.7 {unset} { -body { proc x {} { set a {} assemble {unset false a} info exists a } x } -result 0 -cleanup {rename x {}} } test assemble-24.8 {unset} { -body { proc x {} { assemble {unset false a} info exists a } x } -result 0 -cleanup {rename x {}} } test assemble-24.9 {unset} { -body { proc x {} { assemble {unset true a} info exists a } x } -returnCodes error -result {can't unset "a": no such variable} -cleanup {rename x {}} } test assemble-24.10 {unsetArray} { -body { proc x {} { set a(b) {} assemble {push b; unsetArray false a} info exists a(b) } x } -result 0 -cleanup {rename x {}} } test assemble-24.11 {unsetArray} { -body { proc x {} { assemble {push b; unsetArray false a} info exists a(b) } x } -result 0 -cleanup {rename x {}} } test assemble-24.12 {unsetArray} { -body { proc x {} { assemble {push b; unsetArray true a} info exists a(b) } x } -returnCodes error -result {can't unset "a(b)": no such variable} -cleanup {rename x {}} } # assemble-25 - dict get test assemble-25.1 {dict get - wrong # args} { -body { assemble {dictGet} } -returnCodes error -match glob -result {wrong # args*} } test assemble-25.2 {dict get - wrong # args} { -body { assemble {dictGet too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-25.3 {dictGet - bad subst} { -body { assemble {dictGet $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-25.4 {dict get - not a number} { -body { proc x {} { assemble {dictGet rubbish} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-25.5 {dictGet - negative operand count} { -body { proc x {} { assemble {dictGet 0} } list [catch x result] $result $::errorCode } -result {1 {operand must be positive} {TCL ASSEM POSITIVE}} -cleanup {rename x {}; unset result} } test assemble-25.6 {dictGet - 1 index} { -body { assemble {push {a 1 b 2}; push a; dictGet 1} } -result 1 } # assemble-26 - dict set test assemble-26.1 {dict set - wrong # args} { -body { assemble {dictSet 1} } -returnCodes error -match glob -result {wrong # args*} } test assemble-26.2 {dict get - wrong # args} { -body { assemble {dictSet too many args} } -returnCodes error -match glob -result {wrong # args*} } test assemble-26.3 {dictSet - bad subst} { -body { assemble {dictSet 1 $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-26.4 {dictSet - not a number} { -body { proc x {} { assemble {dictSet rubbish foo} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-26.5 {dictSet - zero operand count} { -body { proc x {} { assemble {dictSet 0 foo} } list [catch x result] $result $::errorCode } -result {1 {operand must be positive} {TCL ASSEM POSITIVE}} -cleanup {rename x {}; unset result} } test assemble-26.6 {dictSet - bad local} { -body { proc x {} { assemble {dictSet 1 ::foo::bar} } list [catch x result] $result $::errorCode } -result {1 {variable "::foo::bar" is not local} {TCL ASSEM NONLOCAL ::foo::bar}} -cleanup {rename x {}; unset result} } test assemble-26.7 {dictSet} { -body { proc x {} { set dict {a 1 b 2 c 3} assemble {push b; push 4; dictSet 1 dict} } x } -result {a 1 b 4 c 3} -cleanup {rename x {}} } # assemble-27 - dictUnset test assemble-27.1 {dictUnset - wrong # args} { -body { assemble {dictUnset 1} } -returnCodes error -match glob -result {wrong # args*} } test assemble-27.2 {dictUnset - wrong # args} { -body { assemble {dictUnset too many args} } -returnCodes error -match glob -result {wrong # args*} } test assemble-27.3 {dictUnset - bad subst} { -body { assemble {dictUnset 1 $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-27.4 {dictUnset - not a number} { -body { proc x {} { assemble {dictUnset rubbish foo} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-27.5 {dictUnset - zero operand count} { -body { proc x {} { assemble {dictUnset 0 foo} } list [catch x result] $result $::errorCode } -result {1 {operand must be positive} {TCL ASSEM POSITIVE}} -cleanup {rename x {}; unset result} } test assemble-27.6 {dictUnset - bad local} { -body { proc x {} { assemble {dictUnset 1 ::foo::bar} } list [catch x result] $result $::errorCode } -result {1 {variable "::foo::bar" is not local} {TCL ASSEM NONLOCAL ::foo::bar}} -cleanup {rename x {}; unset result} } test assemble-27.7 {dictUnset} { -body { proc x {} { set dict {a 1 b 2 c 3} assemble {push b; dictUnset 1 dict} } x } -result {a 1 c 3} -cleanup {rename x {}} } # assemble-28 - dictIncrImm test assemble-28.1 {dictIncrImm - wrong # args} { -body { assemble {dictIncrImm 1} } -returnCodes error -match glob -result {wrong # args*} } test assemble-28.2 {dictIncrImm - wrong # args} { -body { assemble {dictIncrImm too many args} } -returnCodes error -match glob -result {wrong # args*} } test assemble-28.3 {dictIncrImm - bad subst} { -body { assemble {dictIncrImm 1 $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-28.4 {dictIncrImm - not a number} { -body { proc x {} { assemble {dictIncrImm rubbish foo} } x } -returnCodes error -result {expected integer but got "rubbish"} -cleanup {rename x {}} } test assemble-28.5 {dictIncrImm - bad local} { -body { proc x {} { assemble {dictIncrImm 1 ::foo::bar} } list [catch x result] $result $::errorCode } -result {1 {variable "::foo::bar" is not local} {TCL ASSEM NONLOCAL ::foo::bar}} -cleanup {rename x {}; unset result} } test assemble-28.6 {dictIncrImm} { -body { proc x {} { set dict {a 1 b 2 c 3} assemble {push b; dictIncrImm 42 dict} } x } -result {a 1 b 44 c 3} -cleanup {rename x {}} } # assemble-29 - ASSEM_REGEXP test assemble-29.1 {regexp - wrong # args} { -body { assemble {regexp} } -returnCodes error -match glob -result {wrong # args*} } test assemble-29.2 {regexp - wrong # args} { -body { assemble {regexp too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-29.3 {regexp - bad subst} { -body { assemble {regexp $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-29.4 {regexp - not a boolean} { -body { proc x {} { assemble {regexp rubbish} } x } -returnCodes error -result {expected boolean value but got "rubbish"} -cleanup {rename x {}} } test assemble-29.5 {regexp} { -body { assemble {push br.*br; push abracadabra; regexp false} } -result 1 } test assemble-29.6 {regexp} { -body { assemble {push br.*br; push aBRacadabra; regexp false} } -result 0 } test assemble-29.7 {regexp} { -body { assemble {push br.*br; push aBRacadabra; regexp true} } -result 1 } # assemble-30 - Catches test assemble-30.1 {simplest possible catch} { -body { proc x {} { assemble { beginCatch @bad push error push testing invokeStk 2 pop push 0 jump @ok label @bad push 1; # should be pushReturnCode label @ok endCatch } } x } -result 1 -cleanup {rename x {}} } test assemble-30.2 {catch in external catch conntext} { -body { proc x {} { list [catch { assemble { beginCatch @bad push error push testing invokeStk 2 pop push 0 jump @ok label @bad pushReturnCode label @ok endCatch } } result] $result } x } -result {0 1} -cleanup {rename x {}} } test assemble-30.3 {embedded catches} { -body { proc x {} { list [catch { assemble { beginCatch @bad push error eval { list [catch {error whatever} result] $result } invokeStk 2 push 0 reverse 2 jump @done label @bad pushReturnCode pushResult label @done endCatch list 2 } } result2] $result2 } x } -result {0 {1 {1 whatever}}} -cleanup {rename x {}} } # assemble-31 - Jump tables test assemble-31.1 {jumpTable, wrong # args} { -body { assemble {jumpTable} } -returnCodes error -match glob -result {wrong # args*} } test assemble-31.2 {jumpTable, wrong # args} { -body { assemble {jumpTable too many} } -returnCodes error -match glob -result {wrong # args*} } test assemble-31.3 {jumpTable - bad subst} { -body { assemble {jumpTable $foo} } -returnCodes error -match glob -result {assembly code may not contain substitutions} } test assemble-31.4 {jumptable - not a list} { -body { assemble {jumpTable \{rubbish} } -returnCodes error -result {unmatched open brace in list} } test assemble-31.5 {jumpTable, badly structured} { -body { list [catch {assemble { # line 2 jumpTable {one two three};# line 3 }} result] \ $result $::errorCode $::errorInfo } -match glob -result {1 {jump table must have an even number of list elements} {TCL ASSEM BADJUMPTABLE} {jump table must have an even number of list elements*("assemble" body, line 3)*}} } test assemble-31.6 {jumpTable, missing symbol} { -body { list [catch {assemble { # line 2 jumpTable {1 a};# line 3 }} result] \ $result $::errorCode $::errorInfo } -match glob -result {1 {undefined label "a"} {TCL ASSEM NOLABEL a} {undefined label "a"*("assemble" body, line 3)*}} } test assemble-31.7 {jumptable, actual example} { -setup { proc x {} { set result {} for {set i 0} {$i < 5} {incr i} { lappend result [assemble { load i jumpTable {1 @one 2 @two 3 @three} push {none of the above} jump @done label @one push one jump @done label @two push two jump @done label @three push three label @done }] } set tcl_traceCompile 2 set result } } -body x -result {{none of the above} one two three {none of the above}} -cleanup {set tcl_traceCompile 0; rename x {}} } test assemble-40.1 {unbalanced stack} { -body { list \ [catch { assemble { push 3 dup mult push 4 dup mult pop expon } } result] $result $::errorInfo } -result {1 {stack underflow} {stack underflow in assembly code between lines 1 and end of assembly code*}} -match glob -returnCodes ok } test assemble-40.2 {unbalanced stack} {*}{ -body { list \ [catch { assemble { label a push {} label b pop label c pop label d push {} } } result] $result $::errorInfo } -result {1 {stack underflow} {stack underflow in assembly code between lines 7 and 9*}} -match glob -returnCodes ok } test assemble-41.1 {Inconsistent stack usage} {*}{ -body { proc x {y} { assemble { load y jumpFalse else push 0 jump then label else push 1 push 2 label then pop } } catch {x 1} set errorInfo } -match glob -result {inconsistent stack depths on two execution paths ("assemble" body, line 10)*} } test assemble-41.2 {Inconsistent stack, jumptable and default} { -body { proc x {y} { assemble { load y jumpTable {0 else} push 0 label else pop } } catch {x 1} set errorInfo } -match glob -result {inconsistent stack depths on two execution paths ("assemble" body, line 6)*} } test assemble-41.3 {Inconsistent stack, two legs of jumptable} { -body { proc x {y} { assemble { load y jumpTable {0 no 1 yes} label no push 0 label yes pop } } catch {x 1} set errorInfo } -match glob -result {inconsistent stack depths on two execution paths ("assemble" body, line 7)*} } test assemble-50.1 {Ulam's 3n+1 problem, TAL implementation} { -body { proc ulam {n} { assemble { load n; # max dup; # max n jump start; # max n label loop; # max n over 1; # max n max over 1; # max in max n ge; # man n max>=n jumpTrue skip; # max n reverse 2; # n max pop; # n dup; # n n label skip; # max n dup; # max n n push 2; # max n n 2 mod; # max n n%2 jumpTrue odd; # max n push 2; # max n 2 div; # max n/2 -> max n jump start; # max n label odd; # max n push 3; # max n 3 mult; # max 3*n push 1; # max 3*n 1 add; # max 3*n+1 label start; # max n dup; # max n n push 1; # max n n 1 neq; # max n n>1 jumpTrue loop; # max n pop; # max } } set result {} for {set i 1} {$i < 30} {incr i} { lappend result [ulam $i] } set result } -result {1 2 16 4 16 16 52 8 52 16 52 16 40 52 160 16 52 52 88 20 64 52 160 24 88 40 9232 52 88} } rename fillTables {} rename assemble {} ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: