aboutsummaryrefslogtreecommitdiff
path: root/lib/control_flow.nom
diff options
context:
space:
mode:
Diffstat (limited to 'lib/control_flow.nom')
-rw-r--r--lib/control_flow.nom193
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
+