nomsu/lib/control_flow.nom
2017-09-24 20:20:27 -07:00

217 lines
8.1 KiB
Plaintext

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