require "lib/metaprogramming.nom" require "lib/operators.nom" require "lib/utils.nom" # Conditionals macro statement [if %condition %if_body] =: ".."|if \%condition as lua\ then | \(lua expr "vars.if_body.value") as lua\ |end macro statement [if %condition %if_body else %else_body] =: ".."|if \%condition as lua\ then | \(lua expr "vars.if_body.value") as lua\ |else | \(lua expr "vars.else_body.value") as lua\ |end # Return macro statement [return] =: "do return end" macro block [return %return-value] =: ".." |return \%return-value as lua\ macro [do %action] =: ".." |(\%action as lua\)(nomsu, setmetatable({}, {__index=vars})) # GOTOs macro statement [-> %label] =: ".." |::label_\nomsu "var_to_lua_identifier" [%label]\:: macro statement [go to %label] =: ".." |goto label_\nomsu "var_to_lua_identifier" [%label]\ # Loop control flow macro statement [stop, stop loop, break] =: "break" macro statement [stop for, stop for-loop, break for] =: "goto break_for" macro statement [stop repeat, stop repeat-loop, break repeat] =: "goto break_repeat" macro statement [stop %var, break %var] =: ".." |goto break_\nomsu "var_to_lua_identifier" [%var]\ macro statement [continue, continue loop] =: "continue" macro statement [continue for, continue for-loop] =: "goto continue_for" macro statement [continue repeat, continue repeat-loop] =: "goto continue_repeat" macro statement [continue %var, go to next %var, on to the next %var] =: ".." |goto continue_\nomsu "var_to_lua_identifier" [%var]\ # While loops macro block [repeat %body] =: ".."|while true do | \(lua expr "vars.body.value") as lua\ | ::continue_repeat:: |end |::break_repeat:: macro block [repeat while %condition %body] =: ".."|while \%condition as lua\ do | \(lua expr "vars.body.value") as lua\ | ::continue_repeat:: |end |::break_repeat:: macro block [repeat until %condition %body] =: ".."|while not (\%condition as lua\) do | \(lua expr "vars.body.value") as lua\ | ::continue_repeat:: |end |::break_repeat:: # Numeric range for loops macro block [for %var from %start to %stop by %step %body] =: %var-type =: lua expr "vars.var.type" assert (%var-type == "Var") ".." |For loop has the wrong type for the loop variable. Expected Var, but got: \%var-type\ # This trashes the loop variables, just like in Python. ".." |for i=\%start as lua\,\%stop as lua\,\%step as lua\ do | \%var as lua\ = i | \(lua expr "vars.body.value") as lua\ | ::continue_for:: | ::continue_\nomsu "var_to_lua_identifier" [%var]\:: |end |::break_for:: |::break_\nomsu "var_to_lua_identifier" [%var]\:: macro block [for %var from %start to %stop %body] =: %thunk =: :for %var from %start to %stop by 1 %body lua block ".." |for i,x in ipairs(vars.thunk.value) do | if x.type == 'Var' then vars.thunk.type == vars[x.value] end |end |return compiler:run_macro(vars.thunk, 'Statement') macro block [for all %start to %stop by %step %body] =: # This trashes the loop variables, just like in Python. ".." |for i=\%start as lua\,\%stop as lua\,\%step as lua\ do | vars[''] = i | \(lua expr "vars.body.value") as lua\ | ::continue_for:: | ::continue_\nomsu "var_to_lua_identifier" [%]\:: |end |::break_for:: |::break_\nomsu "var_to_lua_identifier" [%]\:: macro block [for %var from %start to %stop %body] =: %thunk =: :for %var from %start to %stop by 1 %body lua block ".." |for i,x in ipairs(vars.thunk.value) do | if x.type == 'Var' then vars.thunk.type == vars[x.value] end |end |return compiler:run_macro(vars.thunk, 'Statement') macro block [for %var in %iterable %body] =: %var-type =: lua expr "vars.var.type" assert (%var-type == "Var") ".." |For loop has the wrong type for the loop variable. Expected Var, but got: \%var-type\ # This trashes the loop variables, just like in Python. ".." |for i,value in ipairs(\%iterable as lua\) do | \%var as lua\ = value | \(lua expr "vars.body.value") as lua\ | ::continue_for:: | ::continue_\nomsu "var_to_lua_identifier" [%var]\:: |end |::break_for:: |::break_\nomsu "var_to_lua_identifier" [%var]\:: macro block [for all %iterable %body] =: pass # TODO: fix compiler bug # This trashes the loop variables, just like in Python. ".."|for i,value in ipairs(\%iterable as lua\) do | vars[''] = value | \(lua expr "vars.body.value") as lua\ | ::continue_for:: | ::continue_\nomsu "var_to_lua_identifier" [%]\:: |end |::break_for:: |::break_\nomsu "var_to_lua_identifier" [%]\:: # Switch statement/multi-branch if macro block [when %body] =: %result =: "" %fallthroughs =: [] for %statement in (lua expr "vars.body.value.value"): %func-call =: lua expr "vars.statement.value" assert ((lua expr "vars['func-call'].type") == "FunctionCall") ".." |Invalid format for 'when' statement. Only '*' blocks are allowed. %tokens =: lua expr "vars['func-call'].value" %star =: lua expr "vars.tokens[1]" assert (lua expr "vars.star and vars.star.type == 'Word' and vars.star.value == '*'") ".." |Invalid format for 'when' statement. Lines must begin with '*' %condition =: lua expr "vars.tokens[2]" assert %condition ".." |Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else" %thunk =: lua expr "vars.tokens[3]" if (%thunk == (nil)): lua block "table.insert(vars.fallthroughs, vars.condition)" go to next %statement if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"): %result join=: ".."| |do ..else: %condition =: %condition as lua for all %fallthroughs: %condition join=: ".."| or \% as lua\ %result join=: ".."| |if \%condition\ then %result join=: ".."| | \(lua expr "vars.thunk.value") as lua\ | goto finished_when |end %fallthroughs =: [] %result join=: "\n::finished_when::" %result # Switch statement macro block [when %branch-value == ? %body] =: %result =: ".."|local branch_value = \%branch-value as lua\ %fallthroughs =: [] for %statement in (lua expr "vars.body.value.value"): %func-call =: lua expr "vars.statement.value" assert ((lua expr "vars['func-call'].type") == "FunctionCall") ".." |Invalid format for 'when' statement. Only '*' blocks are allowed. %tokens =: lua expr "vars['func-call'].value" %star =: lua expr "vars.tokens[1]" assert (lua expr "vars.star and vars.star.type == 'Word' and vars.star.value == '*'") ".." |Invalid format for 'when' statement. Lines must begin with '*' %condition =: lua expr "vars.tokens[2]" assert %condition ".." |Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else" %thunk =: lua expr "vars.tokens[3]" if (%thunk == (nil)): lua block "table.insert(vars.fallthroughs, vars.condition)" go to next %statement if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"): %result join=: ".."| |do ..else: %condition =: ".."|branch_value == (\%condition as lua\) for all %fallthroughs: %condition join=: ".."| or (branch_value == \% as lua\) %result join=: ".."| |if \%condition\ then %result join=: ".."| | \(lua expr "vars.thunk.value") as lua\ | goto finished_when |end %fallthroughs =: [] %result join=: "\n::finished_when::" %result