diff options
Diffstat (limited to 'lib/control_flow.nom')
| -rw-r--r-- | lib/control_flow.nom | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/lib/control_flow.nom b/lib/control_flow.nom new file mode 100644 index 0000000..e2caa2d --- /dev/null +++ b/lib/control_flow.nom @@ -0,0 +1,193 @@ +require "lib/metaprogramming.nom" +require "lib/operators.nom" +require "lib/utils.nom" + +# Conditionals +macro block [if %condition %if_body] =: + ".."|if \%condition as lua expr\ then + | \(lua expr "vars.if_body.value") as lua block\ + |end + +macro block [if %condition %if_body else %else_body] =: + ".."|if \%condition as lua expr\ then + | \(lua expr "vars.if_body.value") as lua block\ + |else + | \(lua expr "vars.else_body.value") as lua block\ + |end + +# Return +macro block [return] =: "return nil" +macro block [return %return-value] =: ".." + |do return \%return-value as lua expr\ end + +macro [do %action] =: ".." + |(\%action as lua expr\)(compiler, setmetatable({}, {__index=vars})) + + +# GOTOs +macro block [-> %label] =: ".." + |::label_\compiler "var_to_lua_identifier" [%label]\:: +macro block [go to %label] =: ".." + |goto label_\compiler "var_to_lua_identifier" [%label]\ + +# Loop control flow +macro block [break] =: "break" +macro block [break for] =: "goto break_for" +macro block [break for-all] =: "goto break_for_all" +macro block [break repeat] =: "goto break_repeat" +macro block [break repeat-until] =: "goto break_repeat_until" +macro block [break repeat-while] =: "goto break_repeat_while" +macro block [break %var, stop getting %var, no more %var] =: ".." + |goto break_\compiler "var_to_lua_identifier" [%var]\ + +macro block [continue] =: "continue" +macro block [continue for] =: "goto continue_for" +macro block [continue for-all] =: "goto continue_for_all" +macro block [continue repeat] =: "goto continue_repeat" +macro block [continue repeat-until] =: "goto continue_repeat_until" +macro block [continue repeat-while] =: "goto continue_repeat_while" +macro block [continue %var, go to next %var, on to the next %var] =: ".." + |goto continue_\compiler "var_to_lua_identifier" [%var]\ +# TODO: add labeled break/continue? + +# While loops +macro block [repeat %body] =: + ".."|do + | while true do + | \(lua expr "vars.body.value") as lua block\ + | ::continue_repeat:: + | end + | ::break_repeat:: + |end +macro block [repeat while %condition %body] =: + ".."|do + | while \%condition as lua expr\ do + | \(lua expr "vars.body.value") as lua block\ + | ::continue_repeat_while:: + | end + | ::break_repeat_while:: + |end +macro block [repeat until %condition %body] =: + ".."|do + | while not (\%condition as lua expr\) do + | \(lua expr "vars.body.value") as lua block\ + | ::continue_repeat_until:: + | end + | ::break_repeat_until:: + |end + +# For loops +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\ + ".." + |do + | local vars = setmetatable({}, {__index=vars}) + | for i,value in ipairs(\%iterable as lua expr\) do + | \%var as lua expr\ = value + | \(lua expr "vars.body.value") as lua block\ + | ::continue_for:: + | ::continue_\compiler "var_to_lua_identifier" [%var]\:: + | end + | ::break_for:: + | ::break_\compiler "var_to_lua_identifier" [%var]\:: + |end + +macro block [for all %iterable %body] =: + ".."|do + | local vars = setmetatable({}, {__index=vars}) + | for i,value in ipairs(\%iterable as lua expr\) do + | vars.it = value + | \(lua expr "vars.body.value") as lua block\ + | ::continue_for_all:: + | end + | ::break_for_all:: + |end + +# Switch statement/multi-branch if +macro block [when %body] =: + %result =: "" + 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" + %q =: lua expr "vars.tokens[1]" + assert (((lua expr "vars.q.type") != "Word") or ((lua expr "vars.q.value") != "?")) ".." + |Invalid format for 'when' statement. Lines must begin with '?' + %thunk =: lua expr "vars.tokens[#vars.tokens]" + assert ((lua expr "vars.thunk.type") != "Thunk") ".." + |Invalid format for 'when' statement. Lines must have a body. + %condition_bits =: [] + for %i in (2 up to (lua expr "#vars.tokens")): + lua block "table.insert(vars['condition_bits'], vars.tokens[vars.i])" + + if (lua expr "#vars.condition_bits == 0"): + %result join=: ".." + | + |do + | local ret + | \(lua expr "vars.thunk.value") as lua block\ + | return ret + |end + ..else: + if (lua expr "#vars.condition_bits == 1 and vars.condition_bits[1].type ~= 'Word'"): + %condition =: lua expr "vars.condition_bits[1]" + ..else: + %condition =: dict [..] + ["type",lua expr "vars['func-call'].type"] + ["src",lua expr "vars['func-call'].src"] + ["value", %condition_bits] + %result join=: ".." + | + |if \%condition as lua expr\ then + | local ret + | \(lua expr "vars.thunk.value") as lua block\ + | return ret + |end + + %result + +# Switch statement +macro block [when %branch-value %body] =: + %result =: ".."|local branch_value = \%branch-value as lua expr\ + 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" + %eq =: lua expr "vars.tokens[1]" + assert (((lua expr "vars.eq.type") != "Word") or ((lua expr "vars.eq.value") != "==")) ".." + |Invalid format for 'when' statement. Lines must begin with '==' + %thunk =: lua expr "vars.tokens[#vars.tokens]" + assert ((lua expr "vars.thunk.type") != "Thunk") ".." + |Invalid format for 'when' statement. Lines must have a body. + %condition_bits =: [] + for %i in (2 up to (lua expr "#vars.tokens")): + lua block "table.insert(vars.condition_bits, vars.tokens[vars.i])" + if (lua expr "#vars.condition_bits == 0"): + %result join=: ".." + | + |do + | local ret + | \(lua expr "vars.thunk.value") as lua block\ + | return ret + |end + ..else: + if (lua expr "#vars.condition_bits == 1 and vars.condition_bits[1].type ~= 'Word'"): + %condition =: (lua expr "vars.condition_bits[1]") + ..else: + %condition =: dict [..] + ["type",lua expr "vars['func-call'].type"] + ["src",lua expr "vars['func-call'].src"] + ["value", %condition_bits] + %result join=: ".." + | + |if compiler.utils.equivalent(branch_condition, \%condition as lua expr\) then + | local ret + | \(lua expr "vars.thunk.value") as lua block\ + | return ret + |end + %result + |
