(257 lines)
1 #!/usr/bin/env nomsu -V7.0.02 ###3 This file contains definitions of operators like "+" and "and".5 use "core/metaprogramming"7 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~9 test:10 assume (all [1 < 2, 2 > 1, 1 <= 2, 2 >= 1, 1 == 1, 1 != 2])12 ### Comparison Operators13 ($x < $y) compiles to "(\($x as lua expr) < \($y as lua expr))"14 ($x > $y) compiles to "(\($x as lua expr) > \($y as lua expr))"15 ($x <= $y) compiles to "(\($x as lua expr) <= \($y as lua expr))"16 ($x >= $y) compiles to "(\($x as lua expr) >= \($y as lua expr))"17 ($a == $b) compiles to "(\($a as lua expr) == \($b as lua expr))"18 [$a not= $b, $a != $b] all compile to "(\($a as lua expr) ~= \($b as lua expr))"20 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~22 test:23 $x = 1024 assume ($x == 10)25 [$x, $y] = [10, 20]26 unless (($x == 10) and ($y == 20)):27 fail "mutli-assignment failed."28 [$x, $y] = [$y, $x]29 unless (($y == 10) and ($x == 20)):30 fail "swapping vars failed."31 $vals = [4, 5]32 [$x, $y] = (unpack $vals)33 unless (($x == 4) and ($y == 5)):34 fail "unpacking failed"36 ### Variable assignment operator37 ($var = $value) compiles to:38 lua> ("39 local lua = LuaCode()40 if \$var.type == "List" then41 for i, \$assignment in ipairs(\$var) do42 if i > 1 then lua:add(", ") end43 local assignment_lua = \($assignment as lua expr)44 lua:add(assignment_lua)45 if \$assignment.type == 'Var' and \$assignment[1].type ~= "MethodCall" then46 lua:add_free_vars({assignment_lua:text()})47 end48 end49 lua:add(' = ')50 if \$value.type == "List" then51 if #\$value ~= #\$var then52 compile_error_at(\$value,53 "This assignment has too "..(#\$value > #\$var and "many" or "few").." values.",54 "Make sure it has the same number of values on the left and right hand side \55 ..of the '=' operator.")56 end57 for i, \$val in ipairs(\$value) do58 if i > 1 then lua:add(", ") end59 local val_lua = \($val as lua expr)60 lua:add(val_lua)61 end62 lua:add(";")63 else64 lua:add(\($value as lua expr), ';')65 end66 else67 local var_lua = \($var as lua expr)68 lua:add(var_lua)69 if \$var.type == 'Var' and \$var[1].type ~= "MethodCall" then70 lua:add_free_vars({var_lua:text()})71 end72 lua:add(' = ', \($value as lua expr), ';')73 end74 return lua75 ")77 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~79 test:80 [$x, $y] = [1, 2]81 with [$z, $x = 999]:82 assume $z == (nil)83 $z = 99984 unless ($z == 999):85 fail "'with' failed."87 unless ($x == 999):88 fail "'with' assignment failed."90 unless ($x == 1):91 fail "'with' scoping failed"93 unless ($z == (nil)):94 fail "'with' scoping failed"96 (with $assignments $body) compiles to:97 lua> ("98 local \$defs = LuaCode()99 for i, \$item in ipairs(\$assignments) do100 if i > 1 then \$defs:add("\\n") end101 local item_lua = \($item as lua)102 if \$item.type == 'Action' and \$item.stub == '1 =' then103 item_lua:remove_free_vars(item_lua.free_vars)104 end105 \$defs:add("local ", item_lua, ";")106 end107 ")109 return Lua ("110 do111 \$defs112 \($body as lua)113 end -- 'with' block114 ")116 ### Math Operators117 test:118 unless ((5 wrapped around 2) == 1):119 fail "mod not working"121 [$x wrapped around $y, $x mod $y, $x % $y] all compile to122 "((\($x as lua expr)) % (\($y as lua expr)))"124 ### 3-part chained comparisons125 ### (uses a lambda to avoid re-evaluating middle value, while still being an expression)126 test:127 $calls = 0128 (one) means:129 external:130 $calls = ($calls + 1)131 return 1133 unless (0 <= (one) <= 2):134 fail "Three-way chained comparison failed."136 unless ($calls == 1):137 fail "Three-way comparison evaluated middle value multiple times"139 ($x < $y < $z) parses as ((($a $b $c) -> (($a < $b) and ($b < $c))) $x $y $z)140 ($x <= $y < $z) parses as ((($a $b $c) -> (($a <= $b) and ($b < $c))) $x $y $z)141 ($x < $y <= $z) parses as ((($a $b $c) -> (($a < $b) and ($b <= $c))) $x $y $z)142 ($x <= $y <= $z) parses as ((($a $b $c) -> (($a <= $b) and ($b <= $c))) $x $y $z)143 ($x > $y > $z) parses as ((($a $b $c) -> (($a > $b) and ($b > $c))) $x $y $z)144 ($x >= $y > $z) parses as ((($a $b $c) -> (($a >= $b) and ($b > $c))) $x $y $z)145 ($x > $y >= $z) parses as ((($a $b $c) -> (($a > $b) and ($b >= $c))) $x $y $z)146 ($x >= $y >= $z) parses as ((($a $b $c) -> (($a >= $b) and ($b >= $c))) $x $y $z)148 ### TODO: optimize for common case where x,y,z are all either variables or number literals149 ### Boolean Operators150 test:151 (barfer) means (fail "short circuiting failed")152 assume (((no) and (barfer)) == (no))153 assume ((no) or (yes))154 assume ((yes) or (barfer))155 ($x and $y) compiles to "(\($x as lua expr) and \($y as lua expr))"156 ($x or $y) compiles to "(\($x as lua expr) or \($y as lua expr))"158 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~160 ### Bitwise Operators161 ### These can break if running the precompiled code from another Lua version:162 lua> ("163 if \(at compilation $(LUA VERSION)) ~= \$(LUA VERSION) then164 \(165 fail ("166 This code was precompiled with \(at compilation $(LUA VERSION)), but it is being run with \$(LUA VERSION)\167 ... This will cause problems with bitwise operations.168 ")169 )170 end171 ")173 ### TODO: implement OR, XOR, AND for multiple operands?174 test:175 assume (~(~5) == 5)176 assume ((1 | 4) == 5)177 assume ((1 ~ 3) == 2)178 assume ((1 & 3) == 1)179 assume ((1 << 2) == 4)180 assume ((4 >> 2) == 1)182 ### Lua 5.3 introduced bit operators like | and &. Use them when possible, otherwise183 fall back to bit.bor(), bit.band(), etc.184 lua> "if \((is jit) or ($(LUA API) == "Lua 5.2")) then"185 [NOT $, ~$] all compile to "Bit.bnot(\($ as lua expr))"186 [$x OR $y, $x | $y] all compile to187 "Bit.bor(\($x as lua expr), \($y as lua expr))"189 [$x XOR $y, $x ~ $y] all compile to190 "Bit.bxor(\($x as lua expr), \($y as lua expr))"192 [$x AND $y, $x & $y] all compile to193 "Bit.band(\($x as lua expr), \($y as lua expr))"195 [$x LSHIFT $shift, $x << $shift] all compile to196 "Bit.lshift(\($x as lua expr), \($shift as lua expr))"198 [$x RSHIFT $shift, $x >> $shift] all compile to199 "Bit.rshift(\($x as lua expr), \($shift as lua expr))"201 lua> "else"202 [NOT $, ~$] all compile to "(~(\($ as lua expr)))"203 [$x OR $y, $x | $y] all compile to "(\($x as lua expr) | \($y as lua expr))"204 [$x XOR $y, $x ~ $y] all compile to "(\($x as lua expr) ~ \($y as lua expr))"205 [$x AND $y, $x & $y] all compile to "(\($x as lua expr) & \($y as lua expr))"206 [$x LSHIFT $shift, $x << $shift] all compile to207 "(\($x as lua expr) << \($shift as lua expr))"209 [$x RSHIFT $shift, $x >> $shift] all compile to210 "(\($x as lua expr) >> \($shift as lua expr))"212 lua> "end"214 ### Unary operators215 test:216 assume ((- 5) == -5)217 assume ((not (yes)) == (no))218 -$ compiles to "(-(\($ as lua expr)))"219 (not $) compiles to "(not \($ as lua expr))"220 test:221 assume ((size of [1, 2, 3]) == 3)222 assume (#[1, 2, 3] == 3)224 ### Length225 [#$list, size of $list] all compile to:226 lua> ("227 local list_lua = \($list as lua expr)228 if list_lua:text() == "..." then229 return LuaCode("select('#', ...)")230 end231 return LuaCode("(#", list_lua, ")")232 ")233 ($list is empty) parses as (#$list == 0)235 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~237 ### Update operators238 test:239 $x = 1240 $x += 1241 unless ($x == 2):242 fail "+= failed"243 $x *= 2244 unless ($x == 4):245 fail "*= failed"246 wrap $x around 3247 unless ($x == 1):248 fail "wrap around failed"250 ($var += $) parses as ($var = (($var or 0) + $))251 ($var -= $) parses as ($var = (($var or 0) - $))252 ($var *= $) parses as ($var = (($var or 1) * $))253 ($var /= $) parses as ($var = ($var / $))254 ($var ^= $) parses as ($var = ($var ^ $))255 ($var and= $) parses as ($var = ($var and $))256 ($var or= $) parses as ($var = ($var or $))257 (wrap $var around $) parses as ($var = ($var wrapped around $))