diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/collections.nom | 180 | ||||
| -rw-r--r-- | lib/control_flow.nom | 99 | ||||
| -rw-r--r-- | lib/math.nom | 46 | ||||
| -rw-r--r-- | lib/metaprogramming.nom | 30 | ||||
| -rw-r--r-- | lib/operators.nom | 69 | ||||
| -rw-r--r-- | lib/text.nom | 9 |
6 files changed, 242 insertions, 191 deletions
diff --git a/lib/collections.nom b/lib/collections.nom index c31bbee..ac1b019 100644 --- a/lib/collections.nom +++ b/lib/collections.nom @@ -9,68 +9,55 @@ use "lib/operators.nom" # List/dict functions: # Indexing -compile [..] - %index st to last in %list, %index nd to last in %list, %index rd to last in %list - %index th to last in %list -..to {expr:"utils.nth_to_last(\(%list as lua expr), \(%index as lua expr))"} +immediately + compile [..] + %index st to last in %list, %index nd to last in %list, %index rd to last in %list + %index th to last in %list + ..to {expr:"utils.nth_to_last(\(%list as lua expr), \(%index as lua expr))"} -parse [first in %list, first %list] as: 1 st in %list -parse [last in %list, last %list] as: 1 st to last in %list +immediately + parse [first in %list, first %list] as: 1 st in %list + parse [last in %list, last %list] as: 1 st to last in %list # Membership testing -action [%item is in %list, %list contains %item, %list has %item] - for %key = %value in %list - if (%key is %item): return (yes) - return (no) - -action [..] - %item isn't in %list, %item is not in %list - %list doesn't contain %item, %list does not contain %item - %list doesn't have %item, %list does not have %item -.. - for %key = %value in %list - if (%key is %item): return (no) - return (yes) - -# Note: it's important to have the space after "[" to prevent confusion if %index is a string -compile [%list has key %index, %list has index %index] to {..} - expr: ".." - ((\(%list as lua expr))[ \(%index as lua expr)] ~= nil) - -# Note: it's important to have the space after "[" to prevent confusion if %index is a string -compile [..] - %list doesn't have key %index, %list does not have key %index - %list doesn't have index %index, %list does not have index %index -..to {expr:"((\(%list as lua expr))[ \(%index as lua expr)] ~= nil)"} - -compile [length of %list, size of %list, size %list, number of %list, len %list] to - {expr:"utils.size(\(%list as lua expr))"} - -compile [append %item to %list, add %item to %list] to - {statements:"table.insert(\(%list as lua expr), \(%item as lua expr))"} - -compile [pop from %list, remove last from %list] to - {statements:"table.remove(\(%list as lua expr))"} +immediately + action [%item is in %list, %list contains %item, %list has %item] + for %key = %value in %list + if (%key is %item): return (yes) + return (no) + + action [..] + %item isn't in %list, %item is not in %list + %list doesn't contain %item, %list does not contain %item + %list doesn't have %item, %list does not have %item + .. + for %key = %value in %list + if (%key is %item): return (no) + return (yes) -compile [remove index %index from %list] to - {statements:"table.remove(\(%list as lua expr), \(%index as lua expr))"} +immediately + # Note: it's important to have the space after "[" to prevent confusion if %index is a string + compile [%list has key %index, %list has index %index] to {..} + expr: ".." + ((\(%list as lua expr))[ \(%index as lua expr)] ~= nil) + # Note: it's important to have the space after "[" to prevent confusion if %index is a string + compile [..] + %list doesn't have key %index, %list does not have key %index + %list doesn't have index %index, %list does not have index %index + ..to {expr:"((\(%list as lua expr))[ \(%index as lua expr)] == nil)"} -action [flatten %lists] - %flat <- [] - for %list in %lists - for %item in %list - add %item to %flat - return %flat + compile [length of %list, size of %list, size %list, number of %list, len %list] to + {expr:"utils.size(\(%list as lua expr))"} -action [entries in %dict] - [{key:%k, value:%v} for %k=%v in %dict] + compile [append %item to %list, add %item to %list] to + {statements:"table.insert(\(%list as lua expr), \(%item as lua expr))"} -action [keys in %dict] - [%k for %k=%v in %dict] + compile [pop from %list, remove last from %list] to + {statements:"table.remove(\(%list as lua expr))"} -action [values in %dict] - [%v for %k=%v in %dict] + compile [remove index %index from %list] to + {statements:"table.remove(\(%list as lua expr), \(%index as lua expr))"} # List Comprehension immediately @@ -98,7 +85,7 @@ immediately (function() local comprehension = {}; for \(%key as lua expr), \(%value as lua expr) in pairs(\(%iterable as lua expr)) do - comprehension[i] = \(%expression as lua expr) + table.insert(comprehension, \(%expression as lua expr)); end return comprehension; end)() @@ -136,38 +123,59 @@ immediately return comprehension; end)() +immediately + action [%lists flattened] + %flat <- [] + for %list in %lists + for %item in %list + add %item to %flat + return %flat + + parse [entries in %dict] as: {key:%k, value:%v} for %k = %v in %dict + parse [keys in %dict] as: %k for %k = %v in %dict + parse [values in %dict] as: %v for %k = %v in %dict + # Sorting: -compile [sort %items] to {statements:"table.sort(\(%items as lua expr))"} -compile [sort %items by %key_expr] to {..} - statements: ".." - utils.sort(\(%items as lua expr), function(\(\% as lua expr)) - return \(%key_expr as lua expr); - end) - -action [%items sorted] - %copy <- (% for all %items) - sort %copy - return %copy -action [%items sorted by %key] - %copy <- (% for all %items) - sort %copy by %key - return %copy - -action [unique %items] - [%k for %k=%v in (%=(yes) for all %items)] - -# Metatable stuff -compile [set %dict's metatable to %metatable] to {..} - statements: "setmetatable(\(%dict as lua expr), \(%metatable as lua expr));" - -compile [new counter] to {expr:"setmetatable({}, {__index=function() return 0; end})"} - -compile [new default dict] to {..} - expr: ".." - setmetatable({}, {__index=function(self, key) - t = {}; - self[key] = t; - return t; - end}) +immediately + compile [sort %items] to {statements:"table.sort(\(%items as lua expr))"} + compile [sort %items by %key_expr] to {..} + statements: ".." + utils.sort(\(%items as lua expr), function(\(\% as lua expr)) + return \(%key_expr as lua expr); + end) + +immediately + action [%items sorted, sorted %items] + %copy <- (% for all %items) + sort %copy + return %copy + action [%items sorted by %key] + %copy <- (% for all %items) + sort %copy by %key + return %copy + + action [unique %items] + %unique <- [] + %seen <- {} + for all %items + unless: % in %seen + add % to %unique + (% in %seen) <- (yes) + return %unique + +immediately + # Metatable stuff + compile [set %dict's metatable to %metatable] to {..} + statements: "setmetatable(\(%dict as lua expr), \(%metatable as lua expr));" + + compile [new counter] to {expr:"setmetatable({}, {__index=function() return 0; end})"} + + compile [new default dict] to {..} + expr: ".." + setmetatable({}, {__index=function(self, key) + t = {}; + self[key] = t; + return t; + end}) # TODO: maybe make a generator/coroutine? diff --git a/lib/control_flow.nom b/lib/control_flow.nom index a6f460a..cfaa7ad 100644 --- a/lib/control_flow.nom +++ b/lib/control_flow.nom @@ -70,9 +70,9 @@ immediately # GOTOs immediately compile [=== %label ===, --- %label ---, *** %label ***] to {..} - statements:"::label_\(nomsu "var_to_lua_identifier" [%label])::;" + statements:"::label_\(%label as lua identifier)::;" compile [go to %label] to {..} - statements:"goto label_\(nomsu "var_to_lua_identifier" [%label]);" + statements:"goto label_\(%label as lua identifier);" # Basic loop control immediately @@ -98,14 +98,14 @@ immediately # While loops immediately - compile [do next repetition] to {statements:"goto continue_repeat;"} + compile [do next repeat] to {statements:"goto continue_repeat;"} compile [stop repeating] to {statements:"goto stop_repeat;"} compile [repeat while %condition %body] to %body_lua <- (%body as lua) %body_statements <- ((%body_lua's "statements") or "\(%body_lua's "expr");") if %body has subtree % where - ((%'s "type") = "FunctionCall") and ((%'s "stub") is "do next repetition") - ..: <- %body_statments + "\n::continue_repeat::;" + ((%'s "type") = "FunctionCall") and ((%'s "stub") is "do next repeat") + ..: %body_statments +<- "\n::continue_repeat::;" %code <- ".." while \(%condition as lua expr) do \%body_statements @@ -128,8 +128,8 @@ immediately %body_lua <- (%body as lua) %body_statements <- ((%body_lua's "statements") or "\(%body_lua's "expr");") if %body has subtree % where - ((%'s "type") = "FunctionCall") and ((%'s "stub") is "do next repetition") - ..: <- %body_statements + "\n::continue_repeat::;" + ((%'s "type") = "FunctionCall") and ((%'s "stub") is "do next repeat") + ..: %body_statements +<- "\n::continue_repeat::;" %code <- ".." for i=1,\(%n as lua expr) do \%body_statements @@ -147,9 +147,9 @@ immediately # For loop control flow: immediately compile [stop %var] to {..} - statements:"goto stop_\(nomsu "var_to_lua_identifier" [%var]);" + statements:"goto stop_\(%var as lua identifier);" compile [do next %var] to {..} - statements:"goto continue_\(nomsu "var_to_lua_identifier" [%var]);" + statements:"goto continue_\(%var as lua identifier);" # Numeric range for loops immediately @@ -163,7 +163,7 @@ immediately ((%'s "type") = "FunctionCall") and ((%'s "stub") is "do next %") and ((3rd in (%'s "value"))'s "value") is (%var's "value") - ..: <- %body_statements + "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;" + ..: %body_statements +<- "\n::continue_\(%var as lua identifier)::;" # This uses Lua's approach of only allowing loop-scoped variables in a loop assume ((%var's "type") is "Var") or barf "Loop expected variable, not: \(%var's source code)" @@ -180,7 +180,7 @@ immediately %code <- ".." do -- scope for stopping for-loop \%code - ::stop_\(nomsu "var_to_lua_identifier" [%var])::; + ::stop_\(%var as lua identifier)::; end -- end of scope for stopping for-loop return {statements:%code, locals:%body_lua's "locals"} @@ -202,7 +202,7 @@ immediately ((%'s "type") = "FunctionCall") and ((%'s "stub") is "do next %") and ((3rd in (%'s "value"))'s "value") is (%var's "value") - ..: <- %body_statements + "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;" + ..: %body_statements +<- "\n::continue_\(%var as lua identifier)::;" # This uses Lua's approach of only allowing loop-scoped variables in a loop assume ((%var's "type") is "Var") or barf "Loop expected variable, not: \(%var's source code)" %code <- ".." @@ -217,7 +217,7 @@ immediately %code <- ".." do -- scope for stopping for-loop \%code - ::stop_\(nomsu "var_to_lua_identifier" [%var])::; + ::stop_\(%var as lua identifier)::; end -- end of scope for stopping for-loop return {statements:%code, locals:%body_lua's "locals"} @@ -232,13 +232,13 @@ immediately ((%'s "type") = "FunctionCall") and ((%'s "stub") is "do next %") and ((3rd in (%'s "value"))'s "value") is (%key's "value") - ..: <- %body_statements + "\n::continue_\(nomsu "var_to_lua_identifier" [%key])::;" + ..: %body_statements +<- "\n::continue_\(%key as lua identifier)::;" if %body has subtree % where ((%'s "type") = "FunctionCall") and ((%'s "stub") is "do next %") and ((3rd in (%'s "value"))'s "value") is (%value's "value") - ..: <- %body_statements + "\n::continue_\(nomsu "var_to_lua_identifier" [%value])::;" + ..: %body_statements +<- "\n::continue_\(%value as lua identifier)::;" # This uses Lua's approach of only allowing loop-scoped variables in a loop assume ((%key's "type") is "Var") or barf "Loop expected variable, not: \(%key's source code)" @@ -253,13 +253,13 @@ immediately ((%'s "type") = "FunctionCall") and ((%'s "stub") is "stop %") and ((2nd in (%'s "value"))'s "value") is (%key's "value") - ..: <- %stop_labels + "\n::stop_\(nomsu "var_to_lua_identifier" [%key])::;" + ..: %stop_labels +<- "\n::stop_\(%key as lua identifier)::;" if %body has subtree % where ((%'s "type") = "FunctionCall") and ((%'s "stub") is "stop %") and ((2nd in (%'s "value"))'s "value") is (%value's "value") - ..: <- %stop_labels + "\n::stop_\(nomsu "var_to_lua_identifier" [%value])::;" + ..: %stop_labels +<- "\n::stop_\(%value as lua identifier)::;" if: %stop_labels is not "" %code <- ".." @@ -290,7 +290,7 @@ immediately 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);" + lua> "table.insert(\%fallthroughs, \(%condition as lua expr));" do next %func_call %action <- (%action as lua) %action_statements <- ((%action's "statements") or "\(%action's "expr");") @@ -298,19 +298,19 @@ immediately lua> "table.insert(\%locals, \%local);" if: =lua "\%condition.type == 'Word' and \%condition.value == 'else'" - <- %code + ".." + assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block" + %code +<- ".." else \%action_statements %seen_else <- (yes) ..else assume (not %seen_else) or barf "'else' clause needs to be last in 'when' block" - %condition <- (%condition as lua expr) - for all %fallthroughs - <- %condition + " or \(% as lua)" - <- %code + ".." + lua> "table.insert(\%fallthroughs, \(%condition as lua expr));" + %condition_code <- (%fallthroughs joined with " or ") + %code +<- ".." - \("if" if %is_first else "elseif") \%condition then + \("if" if %is_first else "elseif") \%condition_code then \%action_statements %fallthroughs <- [] @@ -318,7 +318,7 @@ immediately assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block" if: %code is not "" - <- %code + "\nend" + %code +<- "\nend" lua> "utils.deduplicate(\%locals);" return {statements:%code, locals:%locals} @@ -340,7 +340,7 @@ immediately 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)" + lua> "table.insert(\%fallthroughs, \(%condition as lua expr))" do next %func_call %action <- (%action as lua) @@ -350,7 +350,7 @@ immediately if: =lua "\%condition.type == 'Word' and \%condition.value == 'else'" assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block" - <- %code + ".." + %code +<- ".." else \%action_statements @@ -358,17 +358,14 @@ immediately %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 expr))" - ..else - %clause <- "utils.equivalent(branch_value, \(%condition as lua expr))" - for all %fallthroughs + lua> "table.insert(\%fallthroughs, \(%condition as lua expr));" + for %i = % in %fallthroughs if: ((%'s "type") is "Text") or ((%'s "type") is "Number") - <- %clause + " or branch_value == (\(%condition as lua expr))" + (%i'th in %fallthroughs) <- "branch_value == \%" ..else - <- %clause + " or utils.equivalent(branch_value, \(%condition as lua expr))" - <- %code + ".." + (%i'th in %fallthroughs) <- "utils.equivalent(branch_value, \%)" + %clause <- (%fallthroughs joined with " or ") + %code +<- ".." \("if" if %is_first else "elseif") \%clause then \%action_statements @@ -379,7 +376,7 @@ immediately assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block" assume (%code is not "") or barf "No body for 'when % = ?' block!" unless %seen_else - <- %code + "\nend" + %code +<- "\nend" %code <- ".." do --when % = ? local branch_value = \(%branch_value as lua expr);\ @@ -391,14 +388,16 @@ immediately # Try/except immediately compile [..] - try %action and if it succeeds %success or if it fails %fallback - try %action and if it fails %fallback or if it succeeds %success + try %action and if it succeeds %success or if it barfs %fallback + try %action and if it barfs %fallback or if it succeeds %success ..to %locals <- [] - %action <- (%action as lua) + %action_lua <- (%action as lua) + %success_lua <- (%success as lua) + %fallback_lua <- (%fallback as lua) %fallback <- (%fallback as lua) - for %sub_locals in [%action's "locals", %success's "locals", %fallback's "locals"] - for %local in %sub_locals + for %block in [%action_lua, %success_lua, %fallback_lua] + for %local in ((%block's "locals") or []) lua> "table.insert(\%locals, \%local);" lua> "utils.deduplicate(\%locals);" return {..} @@ -407,26 +406,26 @@ immediately do local fell_through = false; local ok, ret = pcall(function() - \((%action's "statements") or "\(%action's "expr");") + \((%action_lua's "statements") or "\(%action_lua's "expr");") fell_through = true; end); if ok then - \((%success's "statements") or "\(%success's "expr");") + \((%success_lua's "statements") or "\(%success_lua's "expr");") end if not ok then - \((%fallback's "statements") or "\(%fallback's "expr");") + \((%fallback_lua's "statements") or "\(%fallback_lua's "expr");") elseif not fell_through then return ret; end end parse [try %action] as try %action and if it succeeds: do nothing - ..or if it fails: do nothing - parse [try %action and if it fails %fallback] as + ..or if it barfs: do nothing + parse [try %action and if it barfs %fallback] as try %action and if it succeeds: do nothing - ..or if it fails %fallback + ..or if it barfs %fallback parse [try %action and if it succeeds %success] as - try %action and if it succeeds %success or if it fails: do nothing + try %action and if it succeeds %success or if it barfs: do nothing # Do/finally: immediately @@ -441,7 +440,7 @@ immediately compile [do %action then always %final_action] to %action <- (%action as lua) - %final_action <- (%action as lua) + %final_action <- (%final_action as lua) %locals <- [] for %sub_locals in [%action's "locals", %final_action's "locals"] for %local in %sub_locals diff --git a/lib/math.nom b/lib/math.nom index ea1769a..13c6cc3 100644 --- a/lib/math.nom +++ b/lib/math.nom @@ -2,6 +2,8 @@ This file defines some common math literals and functions use "lib/metaprogramming.nom" +use "lib/text.nom" +use "lib/operators.nom" use "lib/control_flow.nom" # Literals: @@ -10,10 +12,10 @@ compile [not a number, NaN, nan] to {expr:"(0/0)"} compile [pi, Pi, PI] to {expr:"math.pi"} compile [tau, Tau, TAU] to {expr:"(2*math.pi)"} compile [golden ratio] to {expr:"((1+math.sqrt(5))/2)"} -compile [e] to {expr:"math.e"} +compile [e] to {expr:"math.exp(1)"} # Functions: -compile [% as number] to {expr:"tonumber(\(% as lua expr))"} +compile [% as a number] to {expr:"tonumber(\(% as lua expr))"} compile [absolute value %, | % |, abs %] to {expr:"math.abs(\(% as lua expr))"} compile [square root %, √%, sqrt %] to {expr:"math.sqrt(\(% as lua expr))"} compile [sine %, sin %] to {expr:"math.sin(\(% as lua expr))"} @@ -36,24 +38,32 @@ action [%n to the nearest %rounder] =lua "(\%rounder)*math.floor((\%n / \%rounder) + .5)" # Any/all/none -compile [all of %items, all %items] to {..} - expr: - "(\(joined ((% as lua expr) for all (%items' "value")) with " and "))" - ..if ((%items' "type") is "List") else "utils.all(\(%items as lua expr))" +compile [all of %items, all %items] to + unless: (%items' "type") is "List" + return {expr:"utils.all(\(%items as lua expr))"} + %clauses <- [] + for all (%items' "value"): lua> "table.insert(\%clauses, \(% as lua expr));" + return {expr:"(\(%clauses joined with " and "))"} parse [not all of %items, not all %items] as: not (all of %items) -compile [any of %items, any %items] to {..} - expr: - "(\(joined ((% as lua expr) for all (%items' "value")) with " or "))" - ..if ((%items' "type") is "List") else "utils.any(\(%items as lua expr))" +compile [any of %items, any %items] to + unless: (%items' "type") is "List" + return {expr:"utils.any(\(%items as lua expr))"} + %clauses <- [] + for all (%items' "value"): lua> "table.insert(\%clauses, \(% as lua expr));" + return {expr:"(\(%clauses joined with " or "))"} parse [none of %items, none %items] as: not (any of %items) -compile [sum of %items, sum %items] to {..} - expr: - "(\(joined ((% as lua expr) for all (%items' "value")) with " + "))" - ..if ((%items' "type") is "List") else "utils.sum(\(%items as lua expr))" -compile [product of %items, product %items] to {..} - expr: - "(\(joined ((% as lua expr) for all (%items' "value")) with " * "))" - ..if ((%items' "type") is "List") else "utils.product(\(%items as lua expr))" +compile [sum of %items, sum %items] to + unless: (%items' "type") is "List" + return {expr:"utils.sum(\(%items as lua expr))"} + %clauses <- [] + for all (%items' "value"): lua> "table.insert(\%clauses, \(% as lua expr));" + return {expr:"(\(%clauses joined with " + "))"} +compile [product of %items, product %items] to + unless: (%items' "type") is "List" + return {expr:"utils.product(\(%items as lua expr))"} + %clauses <- [] + for all (%items' "value"): lua> "table.insert(\%clauses, \(% as lua expr));" + return {expr:"(\(%clauses joined with " * "))"} action [avg of %items, average of %items] =lua "(utils.sum(\%items)/#\%items)" compile [min of %items, smallest of %items, lowest of %items] to {..} diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom index f80c144..8f2bde9 100644 --- a/lib/metaprogramming.nom +++ b/lib/metaprogramming.nom @@ -136,10 +136,9 @@ immediately compile [repr %obj] to {expr:"repr(\(%obj as lua expr))"} compile [type of %obj] to {expr:"type(\(%obj as lua expr))"} -compile [nomsu] to {expr:"nomsu"} - -compile [nomsu's %key] to {expr:"nomsu[\(%key as lua expr)]"} -compile [nomsu %method %args] to {expr:"nomsu[\(%method as lua expr)](nomsu, unpack(\(%args as lua expr)))"} +immediately + compile [nomsu] to {expr:"nomsu"} + compile [%var as lua identifier] to {expr:"nomsu:var_to_lua_identifier(\(%var as lua expr))"} action [action %names metadata] =lua "ACTION_METADATA[ACTIONS[\%names]]" @@ -155,9 +154,10 @@ action [help %action] end # Compiler tools -parse [run %code] as: nomsu "run" [%code] -parse [enable debugging] as: lua> "nomsu.debug = true" -parse [disable debugging] as: lua> "nomsu.debug = false" +immediately + compile [run %code] to {expr: "nomsu:run(\(%code as lua expr), '\(!! code location !!)')"} + parse [enable debugging] as: lua> "nomsu.debug = true;" + parse [disable debugging] as: lua> "nomsu.debug = false;" immediately compile [say %message] to @@ -177,12 +177,20 @@ immediately # Error functions immediately - compile [barf!] to {statements:"error(nil, 0);"} + compile [barf] to {statements:"error(nil, 0);"} compile [barf %msg] to {statements:"error(\(%msg as lua expr), 0);"} - compile [assume %condition] to {..} - statements:"if not \(%condition as lua expr) then error('Assumption failed: '..\%condition:get_src(), 0); end" + compile [assume %condition] to + lua> "local \%assumption = 'Assumption failed: '..\%condition:get_src();" + return {..} + statements:".." + if not \(%condition as lua expr) then + error(\(repr %assumption), 0); + end compile [assume %condition or barf %msg] to {..} - statements:"if not \(%condition as lua expr) then error(\(%msg as lua expr), 0); end" + statements:".." + if not \(%condition as lua expr) then + error(\(%msg as lua expr), 0); + end # Literals immediately diff --git a/lib/operators.nom b/lib/operators.nom index 8be0ea0..670e7b7 100644 --- a/lib/operators.nom +++ b/lib/operators.nom @@ -36,6 +36,7 @@ immediately compile [%x > %y] to {expr:"(\(%x as lua expr) > \(%y as lua expr))"} compile [%x <= %y] to {expr:"(\(%x as lua expr) <= \(%y as lua expr))"} compile [%x >= %y] to {expr:"(\(%x as lua expr) >= \(%y as lua expr))"} + # TODO: optimize case of [%x,%y] = [1,2] compile [%a is %b, %a = %b, %a == %b] to lua> ".." local safe = {Text=true, Number=true}; @@ -69,6 +70,30 @@ immediately locals: =lua "(\%var.type == 'Var' and {\%var_lua.expr} or nil)" immediately + # Simultaneous mutli-assignments like: x,y,z = 1,x,3; + compile [<- %assignments] to + %locals <- [] + %targets <- [] + %values <- [] + assume ((%assignments' "type") is "Dict") or barf ".." + Expected a Dict for the assignments part of '<- %' statement, not \(%assignments' source code) + lua> ".." + for i, item in ipairs(\%assignments.value) do + local target, value = item.dict_key, item.dict_value; + local target_lua = nomsu:tree_to_lua(target); + if not target_lua.expr then error("Invalid target for assignment: "..target:get_src()); end + local value_lua = nomsu:tree_to_lua(value); + if not value_lua.expr then error("Invalid value for assignment: "..value:get_src()); end + if target.type == "Var" then + table.insert(\%locals, target_lua.expr); + end + table.insert(\%targets, target_lua.expr); + table.insert(\%values, value_lua.expr); + end + utils.deduplicate(\%locals); + return {locals=\%locals, statements=(table.concat(\%targets, ", ").." = "..table.concat(\%values, ", ")..";")}; + +immediately compile [export %var <- %value] to %var_lua <- (%var as lua) assume (%var_lua's "expr") or barf "Invalid target for assignment: \(%var's source code)" @@ -76,6 +101,21 @@ immediately assume (%value_lua's "expr") or barf "Invalid value for assignment: \(%value's source code)" return {statements:"\(%var_lua's "expr") = \(%value_lua's "expr");"} + compile [exporting %exported %body] to + %body_lua <- (%body as lua) + %leftover_locals <- (=lua "{unpack(\%body_lua.locals or {})}") + assume ((%exported's "type") = "List") or barf ".." + Expected a List for the export part of 'exporting' statement, not \(%exported's source code) + lua> ".." + for i, item in ipairs(\%exported.value) do + if item.type ~= "Var" then + error("'exporting' statement expects Vars, not: "..item:get_src()); + end + local var = nomsu:tree_to_lua(item).expr; + utils.remove_from_list(\%leftover_locals, var); + end + return {locals:%leftover_locals, statements:=lua "\%body_lua.statements or (\%body_lua.expr..';')"} + compile [with %assignments %body] to %body_lua <- (%body as lua) %locals <- [] @@ -118,21 +158,6 @@ immediately %s end]]):format(locals_code, declaration_code, \%body_lua.statements or (\%body_lua.expr..";"))}; - compile [exporting %exported %body] to - %body_lua <- (%body as lua) - %leftover_locals <- (=lua "{unpack(\%body_lua.locals or {})}") - assume ((%exported's "type") = "List") or barf ".." - Expected a List for the export part of 'exporting' statement, not \(%exported's source code) - lua> ".." - for i, item in ipairs(\%exported.value) do - if item.type ~= "Var" then - error("'exporting' statement expects Vars, not: "..item:get_src()); - end - local var = nomsu:tree_to_lua(item).expr; - utils.remove_from_list(leftover_locals, var); - end - return {locals:%leftover_locals, statements:=lua "\%body_lua.statements or (\%body_lua.expr..';')"} - immediately # Math Operators compile [%x + %y] to {expr:"(\(%x as lua expr) + \(%y as lua expr))"} @@ -174,11 +199,11 @@ immediately # 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 [%var + <- %, %var +<- %] as: %var <- (%var + %) + parse [%var - <- %, %var -<- %] as: %var <- (%var - %) + parse [%var * <- %, %var *<- %] as: %var <- (%var * %) + parse [%var / <- %, %var /<- %] as: %var <- (%var / %) + parse [%var ^ <- %, %var ^<- %] as: %var <- (%var ^ %) + parse [%var and <- %] as: %var <- (%var and %) + parse [%var or <- %] as: %var <- (%var or %) parse [wrap %var around %] as: %var <- (%var wrapped around %) diff --git a/lib/text.nom b/lib/text.nom index cbd0b3f..cd424b9 100644 --- a/lib/text.nom +++ b/lib/text.nom @@ -13,14 +13,15 @@ action [%texts joined with %glue] parse [joined %texts, %texts joined] as: %texts joined with "" compile [capitalized %text, %text capitalized] to - {expr:"(\(%text as lua expr)):gsub('%l', string.upper, 1)"} + {expr:"((\(%text as lua expr)):gsub('%l', string.upper, 1))"} compile [%text with %sub instead of %patt, %text s/%patt/%sub] to {expr:"((\(%text as lua expr)):gsub(\(%patt as lua expr), \(%sub as lua expr)))"} -compile [indented %text, %text indented] to {expr:"\%text:gsub('\\n','\\n'..(' '))"} +# TODO: figure out whether indent/dedent should affect first line +compile [indented %text, %text indented] to {expr:"((\%text):gsub('\\n','\\n'..(' ')))"} compile [dedented %obj, %obj dedented] to {expr:"nomsu:dedent(\(%obj as lua expr))"} -compile [%text indented %n times] to {expr:"\%text:gsub('\\n','\\n'..(' '):rep(\%n))"} +compile [%text indented %n times] to {expr:"((\%text):gsub('\\n','\\n'..(' '):rep(\%n)))"} # Text literals lua> ".." @@ -31,7 +32,7 @@ lua> ".." }; for name, e in pairs(escapes) do local lua = "'"..e.."'"; - nomsu:define_compile_action(name, \(!! code location !!), function() return {expr=text}; end); + nomsu:define_compile_action(name, \(!! code location !!), function() return {expr=lua}; end); end local colors = { ["reset color"]="\\\\27[0m", bright="\\\\27[1m", dim="\\\\27[2m", underscore="\\\\27[4m", |
