aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-01-23 19:22:20 -0800
committerBruce Hill <bitbucket@bruce-hill.com>2018-01-23 19:22:45 -0800
commit6d11354b3f7226a9a417ae89f53de7a225434647 (patch)
tree280778d0b46b314083a93c35210e10a93f8b669f /lib
parent15dc0309c39981ff19dfdabd422e8f95fcc1a4b5 (diff)
Added implicit local declarations and new syntax of %var <- %value.
Diffstat (limited to 'lib')
-rw-r--r--lib/class.nom9
-rw-r--r--lib/collections.nom6
-rw-r--r--lib/control_flow.nom468
-rw-r--r--lib/metaprogramming.nom22
-rw-r--r--lib/operators.nom154
5 files changed, 357 insertions, 302 deletions
diff --git a/lib/class.nom b/lib/class.nom
index 06f55d8..b871798 100644
--- a/lib/class.nom
+++ b/lib/class.nom
@@ -12,7 +12,7 @@ compile [@%var] to
end
return "_me["..key_lua.."]";
-compile [set @%var = %val] to code
+compile [@%var <- %val] to code
lua> ".."
local val_lua = \(%val as lua);
local key_lua = repr(\%var.value);
@@ -26,11 +26,10 @@ compile [set @%var = %val] to code
return "_me["..key_lua.."] = "..val_lua..";";
compile [object %classname %class_body] to
- local [%methods, %class_identifier]
- set %class_identifier = (=lua "nomsu:var_to_lua_identifier(\(%classname as value)):sub(2,-1)")
+ %class_identifier <- (=lua "nomsu:var_to_lua_identifier(\(%classname as value)):sub(2,-1)")
if: %class_identifier is ""
- set %class_identifier = "class"
- set %methods = []
+ %class_identifier <- "class"
+ %methods <- []
for %line in (%class_body's "value")
if: (%line's "type") is "Comment"
do next %line
diff --git a/lib/collections.nom b/lib/collections.nom
index 90bd08c..10dae75 100644
--- a/lib/collections.nom
+++ b/lib/collections.nom
@@ -11,7 +11,7 @@ use "lib/operators.nom"
# Indexing
parse [..]
%index st in %list, %index nd in %list, %index rd in %list
- %index th in %list, %index in %list
+ %index th in %list
..as: %list -> %index
compile [..]
%index st to last in %list, %index nd to last in %list, %index rd to last in %list
@@ -51,7 +51,7 @@ compile [length of %list, size of %list, size %list, number of %list, len %list]
compile [%list ->* %indices] to
assume ((%indices's "type") is "List") or barf ".."
Expected List for chained lookup, not \(%indices's "type")
- set %ret = "\(%list as lua)"
+ %ret <- "\(%list as lua)"
for %index in (%indices's "value")
%ret join= "[\(%index as lua)]"
return "\%ret"
@@ -75,7 +75,7 @@ compile [remove index %index from %list] to
action [flatten %lists]
- set %flat = []
+ %flat <- []
for %list in %lists
for %item in %list
add %item to %flat
diff --git a/lib/control_flow.nom b/lib/control_flow.nom
index b05862c..7347a29 100644
--- a/lib/control_flow.nom
+++ b/lib/control_flow.nom
@@ -40,10 +40,9 @@ immediately
%when_false_expr unless %condition else %when_true_expr
%when_false_expr unless %condition then %when_true_expr
..to
- local %safe
#.. If %when_true_expr is guaranteed to be truthy, we can use Lua's idiomatic
equivalent of a conditional expression: (cond and if_true or if_false)
- if: {Text:yes, List:yes, Dict:yes, Number:yes}->(%when_true_expr's "type")
+ if: (%when_true_expr's "type") in {Text:yes, List:yes, Dict:yes, Number:yes}
return "(\(%condition as lua) and \(%when_true_expr as lua) or \(%when_false_expr as lua))"
..else
#.. Otherwise, need to do an anonymous inline function (yuck, too bad lua
@@ -58,9 +57,10 @@ immediately
end
end)()
+
# GOTOs
immediately
- compile [-> %label] to code ".."
+ compile [=== %label ===, --- %label ---] to code ".."
::label_\(nomsu "var_to_lua_identifier" [%label])::;
compile [go to %label] to code ".."
goto label_\(nomsu "var_to_lua_identifier" [%label]);
@@ -72,46 +72,77 @@ immediately
# Helper function
immediately
- action [tree %tree has function call %call]
- lua> ".."
- local target = (\%call).stub;
- for subtree,depth in coroutine.wrap(function() nomsu:walk_tree(\%tree); end) do
- if type(subtree) == 'table' and subtree.type == "FunctionCall"
- and subtree.stub == target then
- return true;
+ compile [for subtree %subtree where %condition in %tree %body] to code ".."
+ for \(%subtree as lua) in coroutine.wrap(function() nomsu:walk_tree(\(%tree as lua)) end) do
+ if type(\(%subtree as lua)) == 'table' and \(%subtree as lua).type then
+ if \(%condition as lua) then
+ \(%body as lua statements)
end
end
- return false;
+ end
# While loops
immediately
- compile [do next repeat-loop] to code "goto continue_repeat;"
- compile [stop repeat-loop] to code "goto stop_repeat;"
+ compile [do next repetition] to code "goto continue_repeat;"
+ compile [stop repeating] to code "goto stop_repeat;"
compile [repeat while %condition %body] to code
- set %continue_labels =
- "\n::continue_repeat::;"
- ..if (tree %body has function call \(do next repeat-loop)) else ""
- set %code = ".."
+ %continue_labels <- ""
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and ((%'s "stub") == "do next repetition")
+ ..in %body
+ %continue_labels <- "\n::continue_repeat::;"
+ stop
+ %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
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and ((%'s "stub") == "stop repeating")
+ ..in %body
+ %code <- ".."
+ do -- scope of "stop repeating" label
\%code
::stop_repeat::;
- end --while-loop label scope
+ end -- end of "stop repeating" label scope
+ %continue_labels <- "\n::continue_repeat::;"
+ stop
return %code
parse [repeat %body] as: repeat while (yes) %body
parse [repeat until %condition %body] as: repeat while (not %condition) %body
+ compile [..]
+ repeat %n times %body
+ ..to code
+ %continue_labels <- ""
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and ((%'s "stub") == "do next repetition")
+ ..in %body
+ %continue_labels <- "\n::continue_repeat::;"
+ stop
+ # This trashes the loop variables, just like in Python.
+ %code <- ".."
+ for i=1,\(%n as lua) do
+ \(%body as lua statements)\
+ ..\%continue_labels
+ end --numeric for-loop
+ %stop_labels <- ""
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and ((%'s "stub") == "stop repeating")
+ ..in %body
+ %code <- ".."
+ do -- scope of "stop repeating" label
+ \%code
+ ::stop_repeat::;
+ end -- end of "stop repeating" label scope
+ %continue_labels <- "\n::continue_repeat::;"
+ stop
+ return %code
+
# For loop control flow:
immediately
- 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]);
@@ -121,37 +152,42 @@ immediately
for %var from %start to %stop by %step %body
for %var from %start to %stop via %step %body
..to code
- local [%continue_labels, %code, %stop_labels, %loop_var, %loop_var_shim]
- set %continue_labels = ""
- if: tree %body has function call \(do next for-loop)
- %continue_labels join= "\n::continue_for::;"
- if: tree %body has function call (tree \(do next %) with {"":%var})
- %continue_labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;"
+ %continue_labels <- ""
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and
+ ((%'s "stub") == "do next %") and
+ ((3rd in (%'s "value"))'s "src") == (%var's "src")
+ ..in %body
+ %continue_labels <- "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;"
+ stop
+
if: (%var's "type") is "Var"
- set %loop_var = (%var as lua)
- set %loop_var_shim = ""
+ %loop_var <- (%var as lua)
+ %loop_var_shim <- ""
..else
- set %loop_var = "i"
- set %loop_var_shim = "\n\(%var as lua) = i;"
+ %loop_var <- "i"
+ %loop_var_shim <- "\n\(%var as lua) = i;"
# This trashes the loop variables, just like in Python.
- set %code = ".."
+ %code <- ".."
for \(%loop_var)=\(%start as lua),\(%stop as lua),\(%step as lua) do\
..\%loop_var_shim
\(%body as lua statements)\
..\%continue_labels
end --numeric for-loop
- set %stop_labels = ""
- if: tree %body has function call \(stop for-loop)
- %stop_labels join= "\n::stop_for::;"
- if: tree %body has function call (tree \(stop %) with {"":%var})
- %stop_labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;"
- return
- ".."
- do --for-loop label scope
- \%code\
- ..\%stop_labels
- end --for-loop label scope
- ..if (%stop_labels is not "") else %code
+
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and
+ ((%'s "stub") == "stop %") and
+ ((2nd in (%'s "value"))'s "src") == (%var's "src")
+ ..in %body
+ %code <- ".."
+ do -- scope for stopping for-loop
+ \%code
+ ::stop_\(nomsu "var_to_lua_identifier" [%var])::;
+ end -- end of scope for stopping for-loop
+ stop
+
+ return %code
immediately
parse [for %var from %start to %stop %body] as: for %var from %start to %stop via 1 %body
@@ -161,207 +197,209 @@ immediately
..as: for % from %start to %stop via %step %body
parse [for all %start to %stop %body] as: for all %start to %stop via 1 %body
+# For-each loop
immediately
compile [for %var in %iterable %body] to code
- local [%continue_labels, %code, %stop_labels, %loop_var, %loop_var_shim]
- set %continue_labels = ""
- if: tree %body has function call \(do next for-loop)
- %continue_labels join= "\n::continue_for::;"
- if: tree %body has function call (tree \(do next %) with {"":%var})
- %continue_labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;"
+ %continue_labels <- ""
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and
+ ((%'s "stub") == "do next %") and
+ ((3rd in (%'s "value"))'s "src") == (%var's "src")
+ ..in %body
+ %continue_labels <- "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;"
+ stop
if: (%var's "type") is "Var"
- set %loop_var = (%var as lua)
- set %loop_var_shim = ""
+ %loop_var <- (%var as lua)
+ %loop_var_shim <- ""
..else
- set %loop_var = "value"
- set %loop_var_shim = "\n\(%var as lua) = value;"
+ %loop_var <- "value"
+ %loop_var_shim <- "\n\(%var as lua) = value;"
# This trashes the loop variables, just like in Python.
- set %code = ".."
+ %code <- ".."
for i,\%loop_var in ipairs(\(%iterable as lua)) do\
..\%loop_var_shim
\(%body as lua statements)\
..\%continue_labels
end --foreach-loop
- set %stop_labels = ""
- if: tree %body has function call \(stop for-loop)
- %stop_labels join= "\n::stop_for::;"
- if: tree %body has function call (tree \(stop %) with {"":%var})
- %stop_labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;"
- if: %stop_labels is not ""
- set %code = ".."
- do --for-loop label scope
- \%code\%stop_labels
- end --for-loop label scope
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and
+ ((%'s "stub") == "stop %") and
+ ((2nd in (%'s "value"))'s "src") == (%var's "src")
+ ..in %body
+ %code <- ".."
+ do -- scope for stopping for-loop
+ \%code
+ ::stop_\(nomsu "var_to_lua_identifier" [%var])::;
+ end -- end of scope for stopping for-loop
+ stop
return %code
parse [for all %iterable %body] as: for % in %iterable %body
-immediately
- compile [..]
- repeat %n times %body, repeat %n x %body
- ..to code
- local [%continue_labels, %code, %stop_labels]
- set %continue_labels = ""
- if: tree %body has function call \(do next repeat-loop)
- %continue_labels join= "\n::continue_repeat::;"
- # This trashes the loop variables, just like in Python.
- set %code = ".."
- for i=1,\(%n as lua) do
- \(%body as lua statements)\
- ..\%continue_labels
- end --numeric for-loop
- set %stop_labels = ""
- if: tree %body has function call \(stop repeat-loop)
- %stop_labels join= "\n::stop_repeat::;"
- return
- ".."
- do --repeat-loop label scope
- \%code\
- ..\%stop_labels
- end --repeat-loop label scope
- ..if (%stop_labels is not "") else %code
-
# Dict iteration (lua's "pairs()")
immediately
compile [for %key = %value in %iterable %body] to code
- local [..]
- %continue_labels, %code, %stop_labels, %key_loop_var, %key_loop_var_shim,
- %value_loop_var, %value_loop_var_shim
- set %continue_labels = ""
- if: tree %body has function call \(do next for-loop)
- %continue_labels join= "\n::continue_for::;"
- if: tree %body has function call (tree \(do next %) with {"":%key})
- %continue_labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%key])::;"
- if: tree %body has function call (tree \(do next %) with {"":%value})
- %continue_labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%value])::;"
+ %continue_labels <- ""
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and
+ ((%'s "stub") == "do next %") and
+ ((3rd in (%'s "value"))'s "src") == (%key's "src")
+ ..in %body
+ <- %continue_labels + "\n::continue_\(nomsu "var_to_lua_identifier" [%key])::;"
+ stop
+
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and
+ ((%'s "stub") == "do next %") and
+ ((3rd in (%'s "value"))'s "src") == (%value's "src")
+ ..in %body
+ <- %continue_labels + "\n::continue_\(nomsu "var_to_lua_identifier" [%value])::;"
+ stop
+
if: (%key's "type") is "Var"
- set %key_loop_var = (%key as lua)
- set %key_loop_var_shim = ""
+ %key_loop_var <- (%key as lua)
+ %key_loop_var_shim <- ""
..else
- set %key_loop_var = "key"
- set %key_loop_var_shim = "\n\(%key as lua) = key;"
+ %key_loop_var <- "key"
+ %key_loop_var_shim <- "\n\(%key as lua) = key;"
if: (%value's "type") is "Var"
- set %value_loop_var = (%value as lua)
- set %value_loop_var_shim = ""
+ %value_loop_var <- (%value as lua)
+ %value_loop_var_shim <- ""
..else
- set %value_loop_var = "value"
- set %value_loop_var_shim = "\n\(%value as lua) = value;"
+ %value_loop_var <- "value"
+ %value_loop_var_shim <- "\n\(%value as lua) = value;"
# This trashes the loop variables, just like in Python.
- set %code = ".."
+ %code <- ".."
for \%key_loop_var,\%value_loop_var in pairs(\(%iterable as lua)) do\
..\%key_loop_var_shim\%value_loop_var_shim
\(%body as lua statements)\
..\%continue_labels
end --foreach-loop
- set %stop_labels = ""
- if: tree %body has function call \(stop for-loop)
- %stop_labels join= "\n::stop_for::;"
- if: tree %body has function call (tree \(stop %) with {"":%key})
- %stop_labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%key])::;"
- if: tree %body has function call (tree \(stop %) with {"":%value})
- %stop_labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%value])::;"
- return
- ".."
- do --for-loop label scope
- \%code\
- ..\%stop_labels
- end --for-loop label scope
- ..if (%stop_labels is not "") else %code
+ %stop_labels <- ""
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and
+ ((%'s "stub") == "stop %") and
+ ((2nd in (%'s "value"))'s "src") == (%key's "src")
+ ..in %body
+ <- %stop_labels + "\n::stop_\(nomsu "var_to_lua_identifier" [%key])::;"
+ stop
+
+ for subtree % where
+ ((%'s "type") = "FunctionCall") and
+ ((%'s "stub") == "stop %") and
+ ((2nd in (%'s "value"))'s "src") == (%value's "src")
+ ..in %body
+ <- %stop_labels + "\n::stop_\(nomsu "var_to_lua_identifier" [%value])::;"
+ stop
+
+ if: %stop_labels is not ""
+ %code <- ".."
+ do -- scope for stopping for % = % loop
+ \%code\%stop_labels
+ end
+ return %code
# Switch statement/multi-branch if
immediately
compile [when %body] to code
- local [%result, %fallthroughs, %first]
- set %result = ""
- set %fallthroughs = []
- set %first = (yes)
+ %result <- ""
+ %fallthroughs <- []
+ %is_first <- (yes)
for %func_call in (%body's "value")
- local [%tokens, %star, %condition, %action]
assume ((%func_call's "type") is "FunctionCall") or barf ".."
Invalid format for 'when' statement. Only '*' blocks are allowed.
- set %tokens = (%func_call's "value")
- set %star = (%tokens -> 1)
- assume (=lua "\%star and \%star.type == 'Word' and \%star.value == '*'") or barf ".."
- Invalid format for 'when' statement. Lines must begin with '*'
-
- set %condition = (%tokens -> 2)
- assume %condition or barf ".."
- Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
-
- set %action = (%tokens -> 3)
- if: %action is (nil)
- lua do> "table.insert(\%fallthroughs, \%condition)"
- do next %func_call
-
- if: =lua "\%condition.type == 'Word' and \%condition.value == 'else'"
- %result join= ".."
-
- else
- \(%action as lua statements)
- stop for-loop
- ..else
- set %condition = (%condition as lua)
- for all %fallthroughs
- %condition join= " or \(% as lua)"
- %result join= ".."
-
- \("if" if %first else "elseif") \%condition then
- \(%action as lua statements)
-
- set %fallthroughs = []
- set %first = (no)
+ with [..]
+ %tokens <- (%func_call's "value")
+ %star <- (1st in %tokens)
+ %condition <- (2nd in %tokens)
+ %action <- (3rd in %tokens)
+ ..
+ assume (=lua "\%star and \%star.type == 'Word' and \%star.value == '*'") or barf ".."
+ Invalid format for 'when' statement. Lines must begin with '*'
+ assume %condition or barf ".."
+ Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
+ if: %action is (nil)
+ lua do> "table.insert(\%fallthroughs, \%condition)"
+ do next %func_call
+
+ if: =lua "\%condition.type == 'Word' and \%condition.value == 'else'"
+
+ <- %result + ".."
+
+ else
+ \(%action as lua statements)
+ stop
+ ..else
+ %condition <- (%condition as lua)
+ for all %fallthroughs
+ <- %condition + " or \(% as lua)"
+ <- %result + ".."
+
+ \("if" if %is_first else "elseif") \%condition then
+ \(%action as lua statements)
+
+ %fallthroughs <- []
+ %is_first <- (no)
if: %result is not ""
- %result join= "\nend"
+ <- %result + "\nend"
return %result
# Switch statement
immediately
compile [when %branch_value = ? %body, when %branch_value is ? %body] to code
- set %result = ""
- set %fallthroughs = []
- set %first = (yes)
+ %result <- ""
+ %fallthroughs <- []
+ %is_first <- (yes)
+ %seen_else <- (no)
for %func_call in (%body's "value")
assume ((%func_call's "type") is "FunctionCall") or barf ".."
Invalid format for 'when' statement. Only '*' blocks are allowed.
- set %tokens = (%func_call's "value")
- set %star = (%tokens -> 1)
- assume (=lua "\%star and \%star.type == 'Word' and \%star.value == '*'") or barf ".."
- Invalid format for 'when' statement. Lines must begin with '*'
-
- set %condition = (%tokens -> 2)
- assume %condition or barf ".."
- Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
-
- set %action = (%tokens -> 3)
- if: %action is (nil)
- lua> "table.insert(\%fallthroughs, \%condition)"
- do next %func_call
-
- if: =lua "\%condition.type == 'Word' and \%condition.value == 'else'"
- %result join= ".."
-
- else
- \(%action as lua statements)
- stop for-loop
- ..else
- set %condition = "branch_value == (\(%condition as lua))"
- for all %fallthroughs
- %condition join= " or (branch_value == \(% as lua))"
- %result join= ".."
-
- \("if" if %first else "elseif") \%condition then
- \(%action as lua statements)
-
- set %fallthroughs = []
- set %first = (no)
+ %tokens <- (%func_call's "value")
+ with [%star<-(1st in %tokens), %condition<-(2nd in %tokens), %action<-(3rd in %tokens)]
+ assume (=lua "\%star and \%star.type == 'Word' and \%star.value == '*'") or barf ".."
+ Invalid format for 'when' statement. Lines must begin with '*'
+ assume %condition or barf ".."
+ Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
+ if: %action is (nil)
+ lua> "table.insert(\%fallthroughs, \%condition)"
+ do next %func_call
+
+ if: =lua "\%condition.type == 'Word' and \%condition.value == 'else'"
+ assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block"
+ <- %result + ".."
+
+ else
+ \(%action as lua statements)
+ end
+ %seen_else <- (yes)
+ ..else
+ assume (not %seen_else) or barf "'else' clause needs to be last in 'when % = ?' block"
+ %clause <- ""
+ if: ((%condition's "type") is "Text") or ((%condition's "type") is "Number")
+ %clause <- "branch_value == (\(%condition as lua))"
+ ..else
+ %clause <- "utils.equivalent(branch_value, \(%condition as lua))"
+ for all %fallthroughs
+ if: ((%'s "type") is "Text") or ((%'s "type") is "Number")
+ <- %clause + " or branch_value == (\(%condition as lua))"
+ ..else
+ <- %clause + " or utils.equivalent(branch_value, \(%condition as lua))"
+ <- %result + ".."
+
+ \("if" if %is_first else "elseif") \%clause then
+ \(%action as lua statements)
- if: %result is not ""
- set %result = ".."
- do --when % = ?
- local branch_value = \(%branch_value as lua);\
- ..\%result
- end
- end --when % = ?
+ %fallthroughs <- []
+ %is_first <- (no)
+
+ assume (%result is not "") or barf "No body for 'when % = ?' block!"
+ unless %seen_else
+ <- %result + "\nend"
+ %result <- ".."
+ do --when % = ?
+ local branch_value = \(%branch_value as lua);\
+ ..\%result
+ end --when % = ?
return %result
# Try/except
@@ -417,27 +455,3 @@ immediately
end
end
-immediately
- compile [with %assignments %action] to code
- local [%lua, %olds, %old_vals, %new_vals]
- set {%temp_vars:[], %old_vals:[], %new_vals:[]}
- for %i=%assignment in (%assignments' "value")
- set (%temp_vars->%i) = "temp\%i"
- set (%old_vals->%i) = ((%assignment's "dict_key") as lua)
- set (%new_vals->%i) = ((%assignment's "dict_value") as lua)
- return ".."
- do
- local \(join %temp_vars with ", ") = \(join %old_vals with ", ");
- \(join %old_vals with ", ") = \(join %new_vals with ", ");
- local fell_through = false;
- local ok, ret = pcall(function()
- do
- \(%action as lua statements)
- end
- fell_through = true;
- end);
- \(join %old_vals with ", ") = \(join %temp_vars with ", ");
- if not ok then error(ret, 0); end
- if not fell_through then return ret end
- end
-
diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom
index 5ff1ab3..eec99a0 100644
--- a/lib/metaprogramming.nom
+++ b/lib/metaprogramming.nom
@@ -21,7 +21,6 @@ immediately
return names, args;
else
local alias = nomsu:tree_to_value(spec);
- print("ALIAS!!! "..repr(alias).." from "..repr(spec));
local junk, arg_names, junk = nomsu:get_stub(alias);
local args = {};
for i, a in ipairs(arg_names) do args[i] = nomsu:var_to_lua_identifier(a); end
@@ -37,7 +36,10 @@ immediately
local names, args = nomsu:parse_spec(\%names);
names, args = repr(names), table.concat(args, ", ");
local body_lua = nomsu:tree_to_lua(\%body);
- body_lua = body_lua.statements or ("return "..body_lua.expr..";");
+ local body_code = body_lua.statements or ("return "..body_lua.expr..";");
+ if body_lua.locals and #body_lua.locals > 0 then
+ body_code = "local "..table.concat(body_lua.locals, ", ")..";\\n"..body_code;
+ end
local lua = ([[
do
local function compile_action(%s)
@@ -45,7 +47,7 @@ immediately
end
local function compile_action_wrapper(%s) return {expr=compile_action(%s)}; end
nomsu:define_compile_action(%s, %s, compile_action_wrapper, %s);
- end]]):format(args, body_lua, args, args, names, repr(\%names:get_line_no()),
+ end]]):format(args, body_code, args, args, names, repr(\%names:get_line_no()),
repr(("compile %s\\n..to %s"):format(\%names.src, \%body.src)));
return {statements=lua};
end, \(__src__ 1));
@@ -55,7 +57,10 @@ immediately
local names, args = nomsu:parse_spec(\%names);
names, args = repr(names), table.concat(args, ", ");
local body_lua = nomsu:tree_to_lua(\%body);
- body_lua = body_lua.statements or ("return "..body_lua.expr..";");
+ local body_code = body_lua.statements or ("return "..body_lua.expr..";");
+ if body_lua.locals and #body_lua.locals > 0 then
+ body_code = "local "..table.concat(body_lua.locals, ", ")..";\\n"..body_code;
+ end
local lua = ([[
do
local function compile_action(%s)
@@ -63,7 +68,7 @@ immediately
end
local function compile_action_wrapper(%s) return {statements=compile_action(%s)}; end
nomsu:define_compile_action(%s, %s, compile_action_wrapper, %s);
- end]]):format(args, body_lua, args, args, names, repr(\%names:get_line_no()),
+ end]]):format(args, body_code, args, args, names, repr(\%names:get_line_no()),
repr(("compile %s\\n..to code %s"):format(\%names.src, \%body.src)));
return {statements=lua};
end, \(__src__ 1));
@@ -75,12 +80,15 @@ immediately
local names, args = nomsu:parse_spec(\%names);
names, args = repr(names), table.concat(args, ", ");
local body_lua = nomsu:tree_to_lua(\%body);
- body_lua = body_lua.statements or ("return "..body_lua.expr..";");
+ local body_code = body_lua.statements or ("return "..body_lua.expr..";");
+ if body_lua.locals and #body_lua.locals > 0 then
+ body_code = "local "..table.concat(body_lua.locals, ", ")..";\\n"..body_code;
+ end
local src = nomsu:dedent(nomsu:source_code(0));
local def_lua = ([[
nomsu:define_action(%s, \(__line_no__), function(%s)
%s
- end, %s);]]):format(names, args, body_lua, repr(src));
+ end, %s);]]):format(names, args, body_code, repr(src));
return def_lua;
# Macro to make nomsu macros:
diff --git a/lib/operators.nom b/lib/operators.nom
index 91410be..4f43dfd 100644
--- a/lib/operators.nom
+++ b/lib/operators.nom
@@ -11,7 +11,10 @@ immediately
It's also critical to have parens around %obj, otherwise Lua is too dumb to
realize that {x=1}["x"] is the same as ({x=1})["x"] or that
{x=1}.x is the same as ({x=1}).x
- compile [%obj'%key, %obj's %key, %obj -> %key] to
+ compile [..]
+ %obj' %key, %obj's %key, %key in %obj, %key'th in %obj, %key of %obj,
+ %key st in %obj, %key nd in %obj, %key rd in %obj, %key th in %obj,
+ ..to
lua> ".."
local obj_lua = \(%obj as lua);
if not obj_lua:sub(-1,-1):match("[a-zA-Z)]") then
@@ -56,70 +59,101 @@ immediately
# Variable assignment operator, and += type versions
immediately
- compile [local %vars] to code
- lua> ".."
- local locals = \%vars.type == "List" and \%vars.value or {\%vars};
- local identifiers = {};
- for i,x in ipairs(locals) do
- identifiers[i] = nomsu:tree_to_lua(x).expr;
+ lua> ".."
+ nomsu:define_compile_action("%var <- %value", \(__line_no__), function(\%var, \%value)
+ local lua = {};
+ lua.statements = ("%s = %s;"):format(
+ assert(nomsu:tree_to_lua(\%var).expr, "Invalid target for assignment: "..\%var.src),
+ assert(nomsu:tree_to_lua(\%value).expr, "Invalid value for assignment: "..\%value.src));
+ if \%var.type == "Var" then
+ lua.locals = {nomsu:tree_to_lua(\%var).expr};
end
- return "local "..table.concat(identifiers, ", ");
- compile [set %var = %val] to code "\(%var as lua) = \(%val as lua);"
- compile [set %assignments] to code
- assume ((%assignments' "type") is "Dict") or barf "Expected Dict, but got \(%assignments' "type")"
- lua> ".."
- local lhs, rhs = {}, {};
- for i,entry in ipairs(\%assignments.value) do
- lhs[i] = nomsu:tree_to_lua(entry.dict_key).expr;
- rhs[i] = nomsu:tree_to_lua(entry.dict_value).expr;
+ return lua;
+ end, \(__src__ 1));
+ lua> ".."
+ nomsu:define_compile_action("with %assignments %body", \(__line_no__), function(\%assignments, \%body)
+ local body_lua = nomsu:tree_to_lua(\%body);
+ local declarations = "";
+ local leftover_locals = {};
+ for _, body_local in ipairs(body_lua.locals or {}) do
+ leftover_locals[body_local] = true;
+ end
+ assert(\%assignments.type == "List",
+ "Expected a List for the assignments part of 'with' statement, not "..\%assignments.src);
+ for i, item in ipairs(\%assignments.value) do
+ if item.type == "Var" then
+ local var = nomsu:tree_to_lua(item).expr;
+ leftover_locals[var] = nil;
+ declarations = declarations.."local "..var..";\\n ";
+ else
+ assert(item.type == "FunctionCall" and #item.value == 3 and item.value[2].src == "<-",
+ "'with' statement expects entries of the form: '%var <- %value', not: "..item.src);
+ local target, value = item.value[1], item.value[3];
+ if target.type == "Var" then
+ local var = nomsu:tree_to_lua(target).expr;
+ leftover_locals[var] = nil;
+ declarations = declarations..(("local %s = %s;\\n "):format(
+ var, assert(nomsu:tree_to_lua(value).expr, "Invalid value for assignment: "..value.src)));
+ else
+ declarations = declarations..(("%s = %s;\\n "):format(
+ assert(nomsu:tree_to_lua(target).expr, "Invalid target for assignment: "..target.src),
+ assert(nomsu:tree_to_lua(value).expr, "Invalid value for assignment: "..value.src)));
+ end
+ end
end
- return table.concat(lhs, ", ").." = "..table.concat(rhs, ", ")..";";
+ local code = ([[
+ do
+ %s%s
+ end]]):format(declarations, body_lua.statements or (body_lua.expr..";"));
+ return {statements=code, locals=utils.keys(leftover_locals)};
+ end, \(__src__ 1));
-# Update assignment operators
-compile [%var += %val] to code "\(%var as lua) = \(%var as lua) + \(%val as lua);"
-compile [%var -= %val] to code "\(%var as lua) = \(%var as lua) - \(%val as lua);"
-compile [%var *= %val] to code "\(%var as lua) = \(%var as lua) * \(%val as lua);"
-compile [%var /= %val] to code "\(%var as lua) = \(%var as lua) / \(%val as lua);"
-compile [%var ^= %val] to code "\(%var as lua) = \(%var as lua) ^ \(%val as lua);"
-compile [%var and= %val] to code "\(%var as lua) = \(%var as lua) and\(%val as lua);"
-compile [%var or= %val] to code "\(%var as lua) = \(%var as lua) or \(%val as lua);"
-compile [%var join= %val] to code "\(%var as lua) = \(%var as lua) .. \(%val as lua);"
-compile [wrap %var around %val] to code "\(%var as lua) = \(%var as lua) % \(%val as lua);"
+immediately
+ # Math Operators
+ compile [%x + %y] to "(\(%x as lua) + \(%y as lua))"
+ compile [%x - %y] to "(\(%x as lua) - \(%y as lua))"
+ compile [%x * %y] to "(\(%x as lua) * \(%y as lua))"
+ compile [%x / %y] to "(\(%x as lua) / \(%y as lua))"
+ compile [%x ^ %y] to "(\(%x as lua) ^ \(%y as lua))"
+ compile [%x wrapped around %y, %x mod %y] to "(\(%x as lua) % \(%y as lua))"
-# Math Operators
-compile [%x + %y] to "(\(%x as lua) + \(%y as lua))"
-compile [%x - %y] to "(\(%x as lua) - \(%y as lua))"
-compile [%x * %y] to "(\(%x as lua) * \(%y as lua))"
-compile [%x / %y] to "(\(%x as lua) / \(%y as lua))"
-compile [%x ^ %y] to "(\(%x as lua) ^ \(%y as lua))"
-compile [%x wrapped around %y, %x mod %y] to "(\(%x as lua) % \(%y as lua))"
+ # 3-part chained comparisons
+ # (uses a lambda to avoid re-evaluating middle value, while still being an expression)
+ parse [%x < %y < %z] as: =lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)"
+ parse [%x <= %y < %z] as: =lua "(function(x,y,z) return x <= y and y < z; end)(\%x,\%y,\%z)"
+ parse [%x < %y <= %z] as: =lua "(function(x,y,z) return x < y and y <= z; end)(\%x,\%y,\%z)"
+ parse [%x <= %y <= %z] as: =lua "(function(x,y,z) return x <= y and y <= z; end)(\%x,\%y,\%z)"
+ parse [%x > %y > %z] as: =lua "(function(x,y,z) return x > y and y > z; end)(\%x,\%y,\%z)"
+ parse [%x >= %y > %z] as: =lua "(function(x,y,z) return x >= y and y > z; end)(\%x,\%y,\%z)"
+ parse [%x > %y >= %z] as: =lua "(function(x,y,z) return x > y and y >= z; end)(\%x,\%y,\%z)"
+ parse [%x >= %y >= %z] as: =lua "(function(x,y,z) return x >= y and y >= z; end)(\%x,\%y,\%z)"
+ # TODO: optimize for common case where x,y,z are all either variables or number literals
-# 3-part chained comparisons
-# (uses a lambda to avoid re-evaluating middle value, while still being an expression)
-parse [%x < %y < %z] as: =lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)"
-parse [%x <= %y < %z] as: =lua "(function(x,y,z) return x <= y and y < z; end)(\%x,\%y,\%z)"
-parse [%x < %y <= %z] as: =lua "(function(x,y,z) return x < y and y <= z; end)(\%x,\%y,\%z)"
-parse [%x <= %y <= %z] as: =lua "(function(x,y,z) return x <= y and y <= z; end)(\%x,\%y,\%z)"
-parse [%x > %y > %z] as: =lua "(function(x,y,z) return x > y and y > z; end)(\%x,\%y,\%z)"
-parse [%x >= %y > %z] as: =lua "(function(x,y,z) return x >= y and y > z; end)(\%x,\%y,\%z)"
-parse [%x > %y >= %z] as: =lua "(function(x,y,z) return x > y and y >= z; end)(\%x,\%y,\%z)"
-parse [%x >= %y >= %z] as: =lua "(function(x,y,z) return x >= y and y >= z; end)(\%x,\%y,\%z)"
-# TODO: optimize for common case where x,y,z are all either variables or number literals
+ # Boolean Operators
+ compile [%x and %y] to "(\(%x as lua) and \(%y as lua))"
+ compile [%x or %y] to "(\(%x as lua) or \(%y as lua))"
-# Boolean Operators
-compile [%x and %y] to "(\(%x as lua) and \(%y as lua))"
-compile [%x or %y] to "(\(%x as lua) or \(%y as lua))"
+ # Bitwise Operators
+ compile [%a OR %b, %a | %b] to "bit32.bor(\(%a as lua), \(%b as lua))"
+ compile [%a XOR %b] to "bit32.bxor(\(%a as lua), \(%b as lua))"
+ compile [%a AND %b, %a & %b] to "bit32.band(\(%a as lua), \(%b as lua))"
+ compile [NOT %, ~ %] to "bit32.bnot(\(% as lua))"
+ compile [%x LSHIFT %shift, %x << %shift] to "bit32.lshift(\(%x as lua), \(%shift as lua))"
+ compile [%x RSHIFT %shift, %x >>> %shift] to "bit32.rshift(\(%x as lua), \(%shift as lua))"
+ compile [%x ARSHIFT %shift, %x >> %shift] to "bit32.arshift(\(%x as lua), \(%shift as lua))"
+ # TODO: implement OR, XOR, AND for multiple operands?
-# Bitwise Operators
-compile [%a OR %b, %a | %b] to "bit32.bor(\(%a as lua), \(%b as lua))"
-compile [%a XOR %b] to "bit32.bxor(\(%a as lua), \(%b as lua))"
-compile [%a AND %b, %a & %b] to "bit32.band(\(%a as lua), \(%b as lua))"
-compile [NOT %, ~ %] to "bit32.bnot(\(% as lua))"
-compile [%x LSHIFT %shift, %x << %shift] to "bit32.lshift(\(%x as lua), \(%shift as lua))"
-compile [%x RSHIFT %shift, %x >>> %shift] to "bit32.rshift(\(%x as lua), \(%shift as lua))"
-compile [%x ARSHIFT %shift, %x >> %shift] to "bit32.arshift(\(%x as lua), \(%shift as lua))"
-# TODO: implement OR, XOR, AND for multiple operands?
+ # Unary operators
+ compile [- %] to "(- \(% as lua))"
+ compile [not %] to "(not \(% as lua))"
-# Unary operators
-compile [- %] to "-(\(% as lua))"
-compile [not %] to "not (\(% as lua))"
+# Update operators
+immediately
+ parse [<- %var + %] as: %var <- (%var + %)
+ parse [<- %var - %] as: %var <- (%var - %)
+ parse [<- %var * %] as: %var <- (%var * %)
+ parse [<- %var / %] as: %var <- (%var / %)
+ parse [<- %var ^ %] as: %var <- (%var ^ %)
+ parse [<- %var and %] as: %var <- (%var and %)
+ parse [<- %var or %] as: %var <- (%var or %)
+ parse [wrap %var around %] as: "\(%var as lua) = \(%var as lua) % \(% as lua);"