diff options
| author | Bruce Hill <bitbucket@bruce-hill.com> | 2018-01-23 19:22:20 -0800 |
|---|---|---|
| committer | Bruce Hill <bitbucket@bruce-hill.com> | 2018-01-23 19:22:45 -0800 |
| commit | 6d11354b3f7226a9a417ae89f53de7a225434647 (patch) | |
| tree | 280778d0b46b314083a93c35210e10a93f8b669f /lib/operators.nom | |
| parent | 15dc0309c39981ff19dfdabd422e8f95fcc1a4b5 (diff) | |
Added implicit local declarations and new syntax of %var <- %value.
Diffstat (limited to 'lib/operators.nom')
| -rw-r--r-- | lib/operators.nom | 154 |
1 files changed, 94 insertions, 60 deletions
diff --git a/lib/operators.nom b/lib/operators.nom index 91410be..4f43dfd 100644 --- a/lib/operators.nom +++ b/lib/operators.nom @@ -11,7 +11,10 @@ immediately It's also critical to have parens around %obj, otherwise Lua is too dumb to realize that {x=1}["x"] is the same as ({x=1})["x"] or that {x=1}.x is the same as ({x=1}).x - compile [%obj'%key, %obj's %key, %obj -> %key] to + compile [..] + %obj' %key, %obj's %key, %key in %obj, %key'th in %obj, %key of %obj, + %key st in %obj, %key nd in %obj, %key rd in %obj, %key th in %obj, + ..to lua> ".." local obj_lua = \(%obj as lua); if not obj_lua:sub(-1,-1):match("[a-zA-Z)]") then @@ -56,70 +59,101 @@ immediately # Variable assignment operator, and += type versions immediately - compile [local %vars] to code - lua> ".." - local locals = \%vars.type == "List" and \%vars.value or {\%vars}; - local identifiers = {}; - for i,x in ipairs(locals) do - identifiers[i] = nomsu:tree_to_lua(x).expr; + lua> ".." + nomsu:define_compile_action("%var <- %value", \(__line_no__), function(\%var, \%value) + local lua = {}; + lua.statements = ("%s = %s;"):format( + assert(nomsu:tree_to_lua(\%var).expr, "Invalid target for assignment: "..\%var.src), + assert(nomsu:tree_to_lua(\%value).expr, "Invalid value for assignment: "..\%value.src)); + if \%var.type == "Var" then + lua.locals = {nomsu:tree_to_lua(\%var).expr}; end - return "local "..table.concat(identifiers, ", "); - compile [set %var = %val] to code "\(%var as lua) = \(%val as lua);" - compile [set %assignments] to code - assume ((%assignments' "type") is "Dict") or barf "Expected Dict, but got \(%assignments' "type")" - lua> ".." - local lhs, rhs = {}, {}; - for i,entry in ipairs(\%assignments.value) do - lhs[i] = nomsu:tree_to_lua(entry.dict_key).expr; - rhs[i] = nomsu:tree_to_lua(entry.dict_value).expr; + return lua; + end, \(__src__ 1)); + lua> ".." + nomsu:define_compile_action("with %assignments %body", \(__line_no__), function(\%assignments, \%body) + local body_lua = nomsu:tree_to_lua(\%body); + local declarations = ""; + local leftover_locals = {}; + for _, body_local in ipairs(body_lua.locals or {}) do + leftover_locals[body_local] = true; + end + assert(\%assignments.type == "List", + "Expected a List for the assignments part of 'with' statement, not "..\%assignments.src); + for i, item in ipairs(\%assignments.value) do + if item.type == "Var" then + local var = nomsu:tree_to_lua(item).expr; + leftover_locals[var] = nil; + declarations = declarations.."local "..var..";\\n "; + else + assert(item.type == "FunctionCall" and #item.value == 3 and item.value[2].src == "<-", + "'with' statement expects entries of the form: '%var <- %value', not: "..item.src); + local target, value = item.value[1], item.value[3]; + if target.type == "Var" then + local var = nomsu:tree_to_lua(target).expr; + leftover_locals[var] = nil; + declarations = declarations..(("local %s = %s;\\n "):format( + var, assert(nomsu:tree_to_lua(value).expr, "Invalid value for assignment: "..value.src))); + else + declarations = declarations..(("%s = %s;\\n "):format( + assert(nomsu:tree_to_lua(target).expr, "Invalid target for assignment: "..target.src), + assert(nomsu:tree_to_lua(value).expr, "Invalid value for assignment: "..value.src))); + end + end end - return table.concat(lhs, ", ").." = "..table.concat(rhs, ", ")..";"; + local code = ([[ + do + %s%s + end]]):format(declarations, body_lua.statements or (body_lua.expr..";")); + return {statements=code, locals=utils.keys(leftover_locals)}; + end, \(__src__ 1)); -# Update assignment operators -compile [%var += %val] to code "\(%var as lua) = \(%var as lua) + \(%val as lua);" -compile [%var -= %val] to code "\(%var as lua) = \(%var as lua) - \(%val as lua);" -compile [%var *= %val] to code "\(%var as lua) = \(%var as lua) * \(%val as lua);" -compile [%var /= %val] to code "\(%var as lua) = \(%var as lua) / \(%val as lua);" -compile [%var ^= %val] to code "\(%var as lua) = \(%var as lua) ^ \(%val as lua);" -compile [%var and= %val] to code "\(%var as lua) = \(%var as lua) and\(%val as lua);" -compile [%var or= %val] to code "\(%var as lua) = \(%var as lua) or \(%val as lua);" -compile [%var join= %val] to code "\(%var as lua) = \(%var as lua) .. \(%val as lua);" -compile [wrap %var around %val] to code "\(%var as lua) = \(%var as lua) % \(%val as lua);" +immediately + # Math Operators + compile [%x + %y] to "(\(%x as lua) + \(%y as lua))" + compile [%x - %y] to "(\(%x as lua) - \(%y as lua))" + compile [%x * %y] to "(\(%x as lua) * \(%y as lua))" + compile [%x / %y] to "(\(%x as lua) / \(%y as lua))" + compile [%x ^ %y] to "(\(%x as lua) ^ \(%y as lua))" + compile [%x wrapped around %y, %x mod %y] to "(\(%x as lua) % \(%y as lua))" -# Math Operators -compile [%x + %y] to "(\(%x as lua) + \(%y as lua))" -compile [%x - %y] to "(\(%x as lua) - \(%y as lua))" -compile [%x * %y] to "(\(%x as lua) * \(%y as lua))" -compile [%x / %y] to "(\(%x as lua) / \(%y as lua))" -compile [%x ^ %y] to "(\(%x as lua) ^ \(%y as lua))" -compile [%x wrapped around %y, %x mod %y] to "(\(%x as lua) % \(%y as lua))" + # 3-part chained comparisons + # (uses a lambda to avoid re-evaluating middle value, while still being an expression) + parse [%x < %y < %z] as: =lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)" + parse [%x <= %y < %z] as: =lua "(function(x,y,z) return x <= y and y < z; end)(\%x,\%y,\%z)" + parse [%x < %y <= %z] as: =lua "(function(x,y,z) return x < y and y <= z; end)(\%x,\%y,\%z)" + parse [%x <= %y <= %z] as: =lua "(function(x,y,z) return x <= y and y <= z; end)(\%x,\%y,\%z)" + parse [%x > %y > %z] as: =lua "(function(x,y,z) return x > y and y > z; end)(\%x,\%y,\%z)" + parse [%x >= %y > %z] as: =lua "(function(x,y,z) return x >= y and y > z; end)(\%x,\%y,\%z)" + parse [%x > %y >= %z] as: =lua "(function(x,y,z) return x > y and y >= z; end)(\%x,\%y,\%z)" + parse [%x >= %y >= %z] as: =lua "(function(x,y,z) return x >= y and y >= z; end)(\%x,\%y,\%z)" + # TODO: optimize for common case where x,y,z are all either variables or number literals -# 3-part chained comparisons -# (uses a lambda to avoid re-evaluating middle value, while still being an expression) -parse [%x < %y < %z] as: =lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)" -parse [%x <= %y < %z] as: =lua "(function(x,y,z) return x <= y and y < z; end)(\%x,\%y,\%z)" -parse [%x < %y <= %z] as: =lua "(function(x,y,z) return x < y and y <= z; end)(\%x,\%y,\%z)" -parse [%x <= %y <= %z] as: =lua "(function(x,y,z) return x <= y and y <= z; end)(\%x,\%y,\%z)" -parse [%x > %y > %z] as: =lua "(function(x,y,z) return x > y and y > z; end)(\%x,\%y,\%z)" -parse [%x >= %y > %z] as: =lua "(function(x,y,z) return x >= y and y > z; end)(\%x,\%y,\%z)" -parse [%x > %y >= %z] as: =lua "(function(x,y,z) return x > y and y >= z; end)(\%x,\%y,\%z)" -parse [%x >= %y >= %z] as: =lua "(function(x,y,z) return x >= y and y >= z; end)(\%x,\%y,\%z)" -# TODO: optimize for common case where x,y,z are all either variables or number literals + # Boolean Operators + compile [%x and %y] to "(\(%x as lua) and \(%y as lua))" + compile [%x or %y] to "(\(%x as lua) or \(%y as lua))" -# Boolean Operators -compile [%x and %y] to "(\(%x as lua) and \(%y as lua))" -compile [%x or %y] to "(\(%x as lua) or \(%y as lua))" + # Bitwise Operators + compile [%a OR %b, %a | %b] to "bit32.bor(\(%a as lua), \(%b as lua))" + compile [%a XOR %b] to "bit32.bxor(\(%a as lua), \(%b as lua))" + compile [%a AND %b, %a & %b] to "bit32.band(\(%a as lua), \(%b as lua))" + compile [NOT %, ~ %] to "bit32.bnot(\(% as lua))" + compile [%x LSHIFT %shift, %x << %shift] to "bit32.lshift(\(%x as lua), \(%shift as lua))" + compile [%x RSHIFT %shift, %x >>> %shift] to "bit32.rshift(\(%x as lua), \(%shift as lua))" + compile [%x ARSHIFT %shift, %x >> %shift] to "bit32.arshift(\(%x as lua), \(%shift as lua))" + # TODO: implement OR, XOR, AND for multiple operands? -# Bitwise Operators -compile [%a OR %b, %a | %b] to "bit32.bor(\(%a as lua), \(%b as lua))" -compile [%a XOR %b] to "bit32.bxor(\(%a as lua), \(%b as lua))" -compile [%a AND %b, %a & %b] to "bit32.band(\(%a as lua), \(%b as lua))" -compile [NOT %, ~ %] to "bit32.bnot(\(% as lua))" -compile [%x LSHIFT %shift, %x << %shift] to "bit32.lshift(\(%x as lua), \(%shift as lua))" -compile [%x RSHIFT %shift, %x >>> %shift] to "bit32.rshift(\(%x as lua), \(%shift as lua))" -compile [%x ARSHIFT %shift, %x >> %shift] to "bit32.arshift(\(%x as lua), \(%shift as lua))" -# TODO: implement OR, XOR, AND for multiple operands? + # Unary operators + compile [- %] to "(- \(% as lua))" + compile [not %] to "(not \(% as lua))" -# Unary operators -compile [- %] to "-(\(% as lua))" -compile [not %] to "not (\(% as lua))" +# Update operators +immediately + parse [<- %var + %] as: %var <- (%var + %) + parse [<- %var - %] as: %var <- (%var - %) + parse [<- %var * %] as: %var <- (%var * %) + parse [<- %var / %] as: %var <- (%var / %) + parse [<- %var ^ %] as: %var <- (%var ^ %) + parse [<- %var and %] as: %var <- (%var and %) + parse [<- %var or %] as: %var <- (%var or %) + parse [wrap %var around %] as: "\(%var as lua) = \(%var as lua) % \(% as lua);" |
