code / nomsu

Lines6.6K Lua5.1K PEG1.3K make117
2 others 83
Markdown60 Bourne Again Shell23
(257 lines)
1 #!/usr/bin/env nomsu -V7.0.0
2 ###
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 Operators
13 ($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 = 10
24 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 operator
37 ($var = $value) compiles to:
38 lua> ("
39 local lua = LuaCode()
40 if \$var.type == "List" then
41 for i, \$assignment in ipairs(\$var) do
42 if i > 1 then lua:add(", ") end
43 local assignment_lua = \($assignment as lua expr)
44 lua:add(assignment_lua)
45 if \$assignment.type == 'Var' and \$assignment[1].type ~= "MethodCall" then
46 lua:add_free_vars({assignment_lua:text()})
47 end
48 end
49 lua:add(' = ')
50 if \$value.type == "List" then
51 if #\$value ~= #\$var then
52 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 end
57 for i, \$val in ipairs(\$value) do
58 if i > 1 then lua:add(", ") end
59 local val_lua = \($val as lua expr)
60 lua:add(val_lua)
61 end
62 lua:add(";")
63 else
64 lua:add(\($value as lua expr), ';')
65 end
66 else
67 local var_lua = \($var as lua expr)
68 lua:add(var_lua)
69 if \$var.type == 'Var' and \$var[1].type ~= "MethodCall" then
70 lua:add_free_vars({var_lua:text()})
71 end
72 lua:add(' = ', \($value as lua expr), ';')
73 end
74 return lua
75 ")
77 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79 test:
80 [$x, $y] = [1, 2]
81 with [$z, $x = 999]:
82 assume $z == (nil)
83 $z = 999
84 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) do
100 if i > 1 then \$defs:add("\\n") end
101 local item_lua = \($item as lua)
102 if \$item.type == 'Action' and \$item.stub == '1 =' then
103 item_lua:remove_free_vars(item_lua.free_vars)
104 end
105 \$defs:add("local ", item_lua, ";")
106 end
109 return Lua ("
111 \$defs
112 \($body as lua)
113 end -- 'with' block
116 ### Math Operators
117 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 to
122 "((\($x as lua expr)) % (\($y as lua expr)))"
124 ### 3-part chained comparisons
125 ### (uses a lambda to avoid re-evaluating middle value, while still being an expression)
126 test:
127 $calls = 0
128 (one) means:
129 external:
130 $calls = ($calls + 1)
131 return 1
133 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 literals
149 ### Boolean Operators
150 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 Operators
161 ### These can break if running the precompiled code from another Lua version:
162 lua> ("
163 if \(at compilation $(LUA VERSION)) ~= \$(LUA VERSION) then
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.
170 end
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, otherwise
183 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 to
187 "Bit.bor(\($x as lua expr), \($y as lua expr))"
189 [$x XOR $y, $x ~ $y] all compile to
190 "Bit.bxor(\($x as lua expr), \($y as lua expr))"
192 [$x AND $y, $x & $y] all compile to
193 "Bit.band(\($x as lua expr), \($y as lua expr))"
195 [$x LSHIFT $shift, $x << $shift] all compile to
196 "Bit.lshift(\($x as lua expr), \($shift as lua expr))"
198 [$x RSHIFT $shift, $x >> $shift] all compile to
199 "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 to
207 "(\($x as lua expr) << \($shift as lua expr))"
209 [$x RSHIFT $shift, $x >> $shift] all compile to
210 "(\($x as lua expr) >> \($shift as lua expr))"
212 lua> "end"
214 ### Unary operators
215 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 ### Length
225 [#$list, size of $list] all compile to:
226 lua> ("
227 local list_lua = \($list as lua expr)
228 if list_lua:text() == "..." then
229 return LuaCode("select('#', ...)")
230 end
231 return LuaCode("(#", list_lua, ")")
233 ($list is empty) parses as (#$list == 0)
235 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
237 ### Update operators
238 test:
239 $x = 1
240 $x += 1
241 unless ($x == 2):
242 fail "+= failed"
243 $x *= 2
244 unless ($x == 4):
245 fail "*= failed"
246 wrap $x around 3
247 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 $))