aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/how_do_i.nom2
-rw-r--r--lib/control_flow.nom179
-rw-r--r--lib/metaprogramming.nom1
-rwxr-xr-xnomsu.moon34
-rw-r--r--utils.lua12
-rw-r--r--utils.moon7
6 files changed, 140 insertions, 95 deletions
diff --git a/examples/how_do_i.nom b/examples/how_do_i.nom
index 4d667cf..9aa15c6 100644
--- a/examples/how_do_i.nom
+++ b/examples/how_do_i.nom
@@ -136,7 +136,7 @@ repeat:
say "repeat loop #\(%x)"
%x += 1
if (%x > 3):
- break
+ stop repeat-loop
# GOTOs:
do:
diff --git a/lib/control_flow.nom b/lib/control_flow.nom
index f0c0714..2c51c50 100644
--- a/lib/control_flow.nom
+++ b/lib/control_flow.nom
@@ -5,19 +5,19 @@ require "lib/utils.nom"
# Conditionals
compile [if %condition %if_body] to code: ".."
|if \(%condition as lua) then;
- | \(%if_body as lua statements)
- |end;
+ |\(%if_body as lua statements)
+ |end;--end if
compile [unless %condition %body] to code: ".."
|if not (\(%condition as lua)) then;
- | \(%body as lua statements)
- |end;
+ |\(%body as lua statements)
+ |end;--end if
compile [if %condition %if_body else %else_body, unless %condition %else_body else %if_body] to code: ".."
|if \(%condition as lua) then;
- | \(%if_body as lua statements)
+ |\(%if_body as lua statements)
|else;
- | \(%else_body as lua statements)
- |end;
+ |\(%else_body as lua statements)
+ |end;--end if
# Return
compile [return] to code: "do; return; end;"
@@ -29,47 +29,71 @@ compile [-> %label] to code: ".."
compile [go to %label] to code: ".."
|goto label_\(nomsu "var_to_lua_identifier" [%label]);
-# Loop control flow
-compile [stop, stop loop, break] to code: "break"
-compile [stop for, stop for-loop, break for] to code: "goto break_for"
-compile [stop repeat, stop repeat-loop, break repeat] to code: "goto break_repeat"
-compile [stop %var, break %var] to code: ".."
- |goto break_\(nomsu "var_to_lua_identifier" [%var]);
-
-compile [continue, continue loop] to code: "continue"
-compile [continue for, continue for-loop] to code: "goto continue_for"
-compile [continue repeat, continue repeat-loop] to code: "goto continue_repeat"
-compile [continue %var, go to next %var, on to the next %var] to code: ".."
- |goto continue_\(nomsu "var_to_lua_identifier" [%var]);
+rule [tree %tree has function call %call] =:
+ lua code ".."
+ |local target = (\(%call)).value;
+ |for subtree,_ in coroutine.wrap(function() nomsu:walk_tree(\(%tree)); end) do;
+ | if type(subtree) == 'table' and subtree.type == "FunctionCall"
+ | and nomsu.utils.equivalent(subtree.value, target, 2) then;
+ | return true;
+ | end;
+ |end;
+ |do; return false; end;
# While loops
-compile [repeat while %condition %body] to code: ".."
- |do;
- | while \(%condition as lua) do;
- | \(%body as lua statements)
- | ::continue_repeat::;
- | end;
- | ::break_repeat::;
- |end;
+compile [do next repeat-loop] to code: "goto continue_repeat;"
+compile [stop repeat-loop] to code: "goto stop_repeat;"
+compile [repeat while %condition %body] to code:
+ %continue-labels = (..)
+ "\n::continue_repeat::;" if (tree %body has function call \(do next repeat-loop)) else ""
+ %code = ".."
+ |while \(%condition as lua) do;
+ |\(%body as lua statements)\(%continue-labels)
+ |end;--while-loop
+ if (tree %body has function call \(stop repeat-loop)):
+ return ".."
+ |do;--while-loop label scope
+ |\(%code)
+ |::stop_repeat::;
+ |end;--while-loop label scope
+ return %code
parse [repeat %body] as: repeat while (true) %body
parse [repeat until %condition %body] as: repeat while (not %condition) %body
+# For loop control flow:
+compile [stop for-loop] to code: "goto stop_for;"
+compile [stop %var] to code: ".."
+ |goto stop_\(nomsu "var_to_lua_identifier" [%var]);
+compile [do next for-loop] to code: "goto continue_for;"
+compile [do next %var] to code: ".."
+ |goto continue_\(nomsu "var_to_lua_identifier" [%var]);
+
# Numeric range for loops
compile [..]
for %var from %start to %stop by %step %body
for %var from %start to %stop via %step %body
-..to code: ".."
- |do;
- | for i=\(%start as lua),\(%stop as lua),\(%step as lua) do;
- # This trashes the loop variables, just like in Python.
- | \(%var as lua) = i;
- | \(%body as lua statements)
- | ::continue_for::;
- | ::continue_\(nomsu "var_to_lua_identifier" [%var])::;
- | end;
- | ::break_for::;
- | ::break_\(nomsu "var_to_lua_identifier" [%var])::;
- |end;
+..to code:
+ %continue-labels = ""
+ if (tree %body has function call \(do next for-loop)):
+ %continue-labels join= "\n::continue_for::;"
+ if (tree %body has function call (nomsu "replaced_vars" [\(do next %), lua expr "{['']=\(%var)}"])):
+ %continue-labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;"
+ %code = ".."
+ |for i=\(%start as lua),\(%stop as lua),\(%step as lua) do;
+ # This trashes the loop variables, just like in Python.
+ |\(%var as lua) = i;
+ |\(%body as lua statements)\(%continue-labels)
+ |end;--numeric for-loop
+ %stop-labels = ""
+ if (tree %body has function call \(stop for-loop)):
+ %stop-labels join= "\n::stop_for::;"
+ if (tree %body has function call (nomsu "replaced_vars" [\(stop %), lua expr "{['']=\(%var)}"])):
+ %stop-labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;"
+ if (%stop-labels != ""): ".."
+ |do;--for-loop label scope
+ |\(%code)\(%stop-labels)
+ |end;--for-loop label scope
+ ..else: %code
parse [for %var from %start to %stop %body] as: for %var from %start to %stop via 1 %body
parse [..]
for all %start to %stop by %step %body
@@ -78,25 +102,35 @@ parse [..]
parse [for all %start to %stop %body] as: for all %start to %stop via 1 %body
compile [for %var in %iterable %body] to code:
- ".."
- |do;
- | for i,value in ipairs(\(%iterable as lua)) do;
+ %continue-labels = ""
+ if (tree %body has function call \(do next for-loop)):
+ %continue-labels join= "\n::continue_for::;"
+ if (tree %body has function call (nomsu "replaced_vars" [\(do next %), lua expr "{['']=\(%var)}"])):
+ %continue-labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;"
+ %code = ".."
+ |for i,value in ipairs(\(%iterable as lua)) do;
# This trashes the loop variables, just like in Python.
- | \(%var as lua) = value;
- | \(%body as lua statements)
- | ::continue_for::;
- | ::continue_\(nomsu "var_to_lua_identifier" [%var])::;
- | end;
- | ::break_for::;
- | ::break_\(nomsu "var_to_lua_identifier" [%var])::;
- |end;
+ |\(%var as lua) = value;
+ |\(%body as lua statements)\(%continue-labels)
+ |end;--foreach-loop
+ %stop-labels = ""
+ if (tree %body has function call \(stop for-loop)):
+ %stop-labels join= "\n::stop_for::;"
+ if (tree %body has function call (nomsu "replaced_vars" [\(stop %), lua expr "{['']=\(%var)}"])):
+ %stop-labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;"
+ if (%stop-labels != ""): ".."
+ |do;--for-loop label scope
+ |\(%code)\(%stop-labels)
+ |end;--for-loop label scope
+ ..else: %code
parse [for all %iterable %body] as: for % in %iterable %body
# Switch statement/multi-branch if
compile [when %body] to code:
- %result = "do;\n"
+ %result = ""
%fallthroughs = []
+ %first = (yes)
for %func-call in (%body's "value"):
assert ((%func-call's "type") == "FunctionCall") ".."
|Invalid format for 'when' statement. Only '*' blocks are allowed.
@@ -112,34 +146,35 @@ compile [when %body] to code:
%action = (%tokens -> 3)
if (%action == (nil)):
lua block "table.insert(vars.fallthroughs, vars.condition)"
- go to next %func-call
+ do next %func-call
if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"):
%result join= ".."
|
- |do;
+ |else;
+ |\(%action as lua statements)
+ stop for-loop
..else:
%condition = (%condition as lua)
for all %fallthroughs:
%condition join= " or \(% as lua)"
%result join= ".."
|
- |if \(%condition) then;
- %result join= ".."
- |
- | \(%action as lua statements)
- | goto finished_when;
- |end;
+ |\("if" if %first else "elseif") \(%condition) then;
+ |\(%action as lua statements)
%fallthroughs = []
+ %first = (no)
- %result join= "\n::finished_when::;\nend;"
+ if (%result != ""):
+ %result join= "\nend;"
%result
# Switch statement
compile [when %branch-value == ? %body] to code:
- %result = "do;\nlocal branch_value = \(%branch-value as lua)"
+ %result = ""
%fallthroughs = []
+ %first = (yes)
for %func-call in (%body's "value"):
assert ((%func-call's "type") == "FunctionCall") ".."
|Invalid format for 'when' statement. Only '*' blocks are allowed.
@@ -155,28 +190,32 @@ compile [when %branch-value == ? %body] to code:
%action = (%tokens -> 3)
if (%action == (nil)):
lua block "table.insert(vars.fallthroughs, vars.condition)"
- go to next %func-call
+ do next %func-call
if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"):
%result join= ".."
|
- |do;
+ |else;
+ |\(%action as lua statements)
+ stop for-loop
..else:
%condition = "branch_value == (\(%condition as lua))"
for all %fallthroughs:
%condition join= " or (branch_value == \(% as lua))"
%result join= ".."
|
- |if \(%condition) then;
- %result join= ".."
- |
- | \(%action as lua statements)
- | goto finished_when;
- |end;
+ |\("if" if %first else "elseif") \(%condition) then;
+ |\(%action as lua statements)
%fallthroughs = []
+ %first = (no)
- %result join= "\n::finished_when::;\nend;"
+ if (%result != ""):
+ %result = ".."
+ |do;--when == ?
+ |local branch_value = \(%branch-value as lua);\(%result)
+ |end;
+ |end;--when == ?
%result
# With statement
diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom
index 7630088..bf4d79a 100644
--- a/lib/metaprogramming.nom
+++ b/lib/metaprogramming.nom
@@ -110,4 +110,3 @@ parse [parse tree %code] as: nomsu "tree_to_str" [\%code]
parse [enable debugging] as: lua code "nomsu.debug = true"
parse [disable debugging] as: lua code "nomsu.debug = false"
-
diff --git a/nomsu.moon b/nomsu.moon
index d24b27c..435265f 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -329,10 +329,10 @@ class NomsuCompiler
@errorln "#{colored.red "Error occurred in statement:"}\n#{colored.bright colored.yellow statement.src}"
@error(expr)
code_for_statement = ([[
- return (function(nomsu, vars)
- %s
- return %s;
- end);]])\format(statements or "", expr or "ret")
+return (function(nomsu, vars)
+%s
+return %s;
+end);]])\format(statements or "", expr or "ret")
if @debug
@writeln "#{colored.bright "RUNNING LUA:"}\n#{colored.blue colored.bright(code_for_statement)}"
lua_thunk, err = load(code_for_statement)
@@ -342,7 +342,7 @@ class NomsuCompiler
n = n + 1
("\n%-3d|")\format(n)
code = "1 |"..code_for_statement\gsub("\n", fn)
- error("Failed to compile generated code:\n#{colored.bright colored.blue code}\n\n#{err}\n\nProduced by statement:\n#{colored.bright colored.yellow statement.src}")
+ error("Failed to compile generated code:\n#{colored.bright colored.blue colored.onblack code}\n\n#{err}\n\nProduced by statement:\n#{colored.bright colored.yellow statement.src}")
run_statement = lua_thunk!
ok,ret = pcall(run_statement, self, vars)
if expr then return_value = ret
@@ -350,16 +350,16 @@ class NomsuCompiler
@errorln "#{colored.red "Error occurred in statement:"}\n#{colored.yellow statement.src}"
@errorln debug.traceback!
@error(ret)
- insert buffer, "#{statements or ''}\n#{expr and "ret = #{expr}" or ''}"
+ insert buffer, "#{statements or ''}\n#{expr and "ret = #{expr};" or ''}"
if max_operations
debug.sethook!
lua_code = ([[
- return (function(nomsu, vars)
- local ret;
- %s
- return ret;
- end);]])\format(concat(buffer, "\n"))
+return (function(nomsu, vars)
+local ret;
+%s
+return ret;
+end);]])\format(concat(buffer, "\n"))
return return_value, lua_code, vars
tree_to_value: (tree, vars)=>
@@ -368,7 +368,7 @@ class NomsuCompiler
@writeln "#{colored.bright "RUNNING LUA TO GET VALUE:"}\n#{colored.blue colored.bright(code)}"
lua_thunk, err = load(code)
if not lua_thunk
- @error("Failed to compile generated code:\n#{colored.bright colored.blue code}\n\n#{colored.red err}")
+ @error("Failed to compile generated code:\n#{colored.bright colored.blue colored.onblack code}\n\n#{colored.red err}")
return (lua_thunk!)(self, vars or {})
tree_to_lua: (tree)=>
@@ -391,11 +391,11 @@ class NomsuCompiler
if statement then insert lua_bits, statement
if expr then insert lua_bits, "ret = #{expr};"
return ([[
- (function(nomsu, vars)
- local ret;
- %s
- return ret;
- end)]])\format(concat(lua_bits, "\n"))
+(function(nomsu, vars)
+local ret;
+%s
+return ret;
+end)]])\format(concat(lua_bits, "\n"))
when "FunctionCall"
stub = @get_stub(tree)
diff --git a/utils.lua b/utils.lua
index e8fca96..19ba20a 100644
--- a/utils.lua
+++ b/utils.lua
@@ -290,7 +290,10 @@ utils = {
end
return table.sort(list, comparison)
end,
- equivalent = function(x, y)
+ equivalent = function(x, y, depth)
+ if depth == nil then
+ depth = 1
+ end
if x == y then
return true
end
@@ -300,13 +303,16 @@ utils = {
if type(x) ~= 'table' then
return false
end
+ if depth == 0 then
+ return false
+ end
for k, v in pairs(x) do
- if y[k] ~= v then
+ if not (utils.equivalent(y[k], v, depth - 1)) then
return false
end
end
for k, v in pairs(y) do
- if x[k] ~= v then
+ if not (utils.equivalent(x[k], v, depth - 1)) then
return false
end
end
diff --git a/utils.moon b/utils.moon
index 9cceaac..7d1e39e 100644
--- a/utils.moon
+++ b/utils.moon
@@ -138,15 +138,16 @@ utils = {
comparison = if reverse then ((x,y)->(keyFn(x)>keyFn(y))) else ((x,y)->(keyFn(x)<keyFn(y)))
table.sort list, comparison
- equivalent: (x,y)->
+ equivalent: (x,y,depth=1)->
if x == y then return true
if type(x) != type(y) then return false
if type(x) != 'table' then return false
+ if depth == 0 then return false
for k,v in pairs(x)
- if y[k] != v
+ unless utils.equivalent(y[k], v, depth-1)
return false
for k,v in pairs(y)
- if x[k] != v
+ unless utils.equivalent(x[k], v, depth-1)
return false
return true