From cfee75b21b307b5d57c215cad5b1c089c91182fc Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 3 Jan 2018 00:52:01 -0800 Subject: Reworked {} a bit and added dicts to the core language. Did some more testing on string interpolations too. --- lib/collections.nom | 114 +++++++++++++++++++++++++----------------------- lib/control_flow.nom | 72 ++++++++++++++++++++++-------- lib/metaprogramming.nom | 2 + lib/operators.nom | 14 +++++- lib/scopes.nom | 2 +- lib/utils2.nom | 2 +- 6 files changed, 129 insertions(+), 77 deletions(-) (limited to 'lib') diff --git a/lib/collections.nom b/lib/collections.nom index 41710a6..b97c164 100644 --- a/lib/collections.nom +++ b/lib/collections.nom @@ -18,15 +18,6 @@ compile [..] parse [first in %list, first %list] as: 1 st in %list parse [last in %list, last %list] as: 1 st to last in %list -# Dict iteration convenience function. This could also be accomplished with: for all (entries in %dict): ... -compile [for %key = %value in %dict %body] to code: ".." - do - for k, v in pairs(\(%dict as lua)) do - \(%key as lua), \(%value as lua) = k, v; - \(%body as lua statements) - end - end - # Membership testing rule [%item is in %list, %list contains %item, %list has %item] =: for %key = %value in %list: @@ -60,7 +51,7 @@ compile [%list ->* %indices] to: %ret = "\(%list as lua)" for %index in (%indices's "value"): %ret join= "[\(%index as lua)]" - "\(%ret)" + "\%ret" # Assignment compile [..] @@ -87,43 +78,16 @@ rule [flatten %lists] =: add %item to %flat %flat -rule [dict from entries %items] =: +rule [dict %items] =: %dict = [] for %pair in %items: %dict -> (%pair -> 1) = (%pair -> 2) %dict -compile [dict %items, d %items] to: - if ((%items's "type") == "Thunk"): - %item_codes = [] - for %func_call in (%items's "value"): - assert ((%func_call's "type") == "FunctionCall") ".." - Invalid format for 'dict' expression. Only literals are allowed. - %tokens = (%func_call's "value") - %equals = (%tokens -> 2) - assert (=lua "#\(%tokens) == 3 and \(%equals) and \(%equals).type == 'Word' and \(%equals).value == '='") ".." - Invalid format for 'dict' expression. Lines must only have the "% = %" format, not \(%func_call's "src") - %key = (%tokens -> 1) - lua> ".." - if \(%key).type == "Word" and \(%key).value:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then - \(%key_code) = \(%key).value; - elseif \(%key).type == "Word" then - \(%key_code) = "["..nomsu:repr(\(%key).value).."]"; - else - \(\{%key_code = "[\((%key as lua))]"} as lua statements) - end - add "\(%key_code) = \((%tokens -> 3) as lua)" to %item_codes - return "{\(join %item_codes with glue ",\n")}" - ..else: - return (..) - (..) - nomsu "replaced_vars" [\(dict from entries %items), =lua "vars"] - ..as lua - rule [entries in %dict] =: %entries = [] for %k = %v in %dict: - add (dict {key = %k; value = %v}) to %entries + add {key=%k, value=%v} to %entries %entries rule [keys in %dict] =: @@ -137,20 +101,35 @@ rule [values in %dict] =: %values # List Comprehension -compile [%expression for %var in %iterable] to: - assert ((%var's "type") == "Var") ".." - List comprehension has the wrong type for the loop variable. Expected Var, but got: \(%var's "type") +compile [%expression for %item in %iterable] to: + assert ((%item's "type") == "Var") ".." + List comprehension has the wrong type for the loop variable. Expected Var, but got: \(%item's "type") ".." - (function(game, vars); + (function(nomsu, vars); local comprehension = {}; - for i,value in ipairs(\(%iterable as lua)) do; - \(%var as lua) = value; + for i,item in ipairs(\(%iterable as lua)) do; + \(%item as lua) = item; comprehension[i] = \(%expression as lua); end; return comprehension; - end)(game, setmetatable({}, {__index=vars})) + end)(nomsu, setmetatable({}, {__index=vars})) parse [%expression for all %iterable] as: %expression for % in %iterable +compile [%expression for %key = %value in %iterable] to: + assert ((%key's "type") == "Var") ".." + List comprehension has the wrong type for the key loop variable. Expected Var, but got: \(%key's "type") + assert ((%value's "type") == "Var") ".." + List comprehension has the wrong type for the value loop variable. Expected Var, but got: \(%value's "type") + ".." + (function(nomsu, vars); + local comprehension = {}; + for key,value in pairs(\(%iterable as lua)) do; + \(%key as lua), \(%value as lua) = key, value; + comprehension[i] = \(%expression as lua); + end; + return comprehension; + end)(nomsu, setmetatable({}, {__index=vars})) + rule [%items sorted] =: %copy = (% for all %items) sort %copy @@ -160,7 +139,7 @@ rule [%items sorted by %key] =: sort %copy by %key %copy rule [unique %items] =: - keys in (dict from entries ([%,yes] for all %items)) + keys in (dict ([%,yes] for all %items)) # Metatable stuff compile [counter] to: "setmetatable({}, {__index=function() return 0; end})" @@ -173,17 +152,42 @@ compile [default dict] to: ".." rule [chain %dict to %fallback] =: when (type of %fallback) == ?: * "table": - =lua "setmetatable(\(%dict), \(%fallback))" + =lua "setmetatable(\%dict, \%fallback)" * "function": - =lua "setmetatable(\(%dict), {__index=function(self, key) return (\(%fallback))(nomsu, {['']=key, self=self}); end})" + =lua "setmetatable(\%dict, {__index=function(self, key) return (\%fallback)(nomsu, {['']=key, self=self}); end})" * else: - =lua "setmetatable(\(%dict), {__index=function(self, key) return (\(%fallback)); end})" + =lua "setmetatable(\%dict, {__index=function(self, key) return (\%fallback); end})" # TODO: maybe make a generator/coroutine? -#.. Dict comprehensions can be accomplished okay by doing: - dict ([%'s "key", %'s "value"] for all (entries in %dict)) - or something similar -# TODO: fix compiler bugs -pass +# Dict comprehensions +compile [%key = %value for %item in %iterable] to: + assert ((%item's "type") == "Var") ".." + Dict comprehension has the wrong type for the loop variable. Expected Var, but got: \(%item's "type") + ".." + (function(nomsu, vars); + local comprehension = {}; + for i,value in ipairs(\(%iterable as lua)) do; + \(%item as lua) = value; + comprehension[\(%key as lua)] = \(%value as lua); + end; + return comprehension; + end)(nomsu, setmetatable({}, {__index=vars})) +parse [%key = %value for all %iterable] as: %key = %value for % in %iterable + +compile [%key = %value for %src_key = %src_value in %iterable] to: + assert ((%src_key's "type") == "Var") ".." + Dict comprehension has the wrong type for the key loop variable. Expected Var, but got: \(%src_key's "type") + assert ((%src_value's "type") == "Var") ".." + Dict comprehension has the wrong type for the value loop variable. Expected Var, but got: \(%src_value's "type") + ".." + (function(nomsu, vars); + local comprehension = {}; + for key,value in pairs(\(%iterable as lua)) do; + \(%src_key as lua), \(%src_value as lua) = key, value; + comprehension[\(%key as lua)] = \(%value as lua); + end; + return comprehension; + end)(nomsu, setmetatable({}, {__index=vars})) + diff --git a/lib/control_flow.nom b/lib/control_flow.nom index 7658ae1..825e1c2 100644 --- a/lib/control_flow.nom +++ b/lib/control_flow.nom @@ -31,8 +31,8 @@ compile [go to %label] to code: ".." rule [tree %tree has function call %call] =: lua> ".." - local target = (\(%call)).stub; - for subtree,_ in coroutine.wrap(function() nomsu:walk_tree(\(%tree)); end) do + local target = (\%call).stub; + for subtree,_ 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; @@ -48,12 +48,13 @@ compile [repeat while %condition %body] to code: "\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) + \(%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) + \%code ::stop_repeat::; end --while-loop label scope return %code @@ -76,22 +77,24 @@ compile [..] %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 "{['']=\(%var)}"])): + if (tree %body has function call (tree \(do next %) with {""=%var})): %continue_labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;" # This trashes the loop variables, just like in Python. %code = ".." for i=\(%start as lua),\(%stop as lua),\(%step as lua) do \(%var as lua) = i; - \(%body as lua statements)\(%continue_labels) + \(%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 "{['']=\(%var)}"])): + if (tree %body has function call (tree \(stop %) with {""=%var})): %stop_labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;" if (%stop_labels != ""): ".." do --for-loop label scope - \(%code)\(%stop_labels) + \%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 @@ -105,26 +108,56 @@ compile [for %var in %iterable %body] 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 "{['']=\(%var)}"])): + if (tree %body has function call (tree \(do next %) with {""=%var})): %continue_labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;" # This trashes the loop variables, just like in Python. %code = ".." for i,value in ipairs(\(%iterable as lua)) do \(%var as lua) = value; - \(%body as lua statements)\(%continue_labels) + \(%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 "{['']=\(%var)}"])): + if (tree %body has function call (tree \(stop %) with {""=%var})): %stop_labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;" if (%stop_labels != ""): ".." do --for-loop label scope - \(%code)\(%stop_labels) + \%code\%stop_labels end --for-loop label scope ..else: %code parse [for all %iterable %body] as: for % in %iterable %body +# Dict iteration (lua's "pairs()") +compile [for %key = %value in %iterable %body] 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 (tree \(do next %x) with {x=%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])::;" + # This trashes the loop variables, just like in Python. + %code = ".." + for key,value in ipairs(\(%iterable as lua)) do + \(%key as lua), \(%value as lua) = key, 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 (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])::;" + if (%stop_labels != ""): ".." + do --for-loop label scope + \%code\ + ..\%stop_labels + end --for-loop label scope + ..else: %code # Switch statement/multi-branch if compile [when %body] to code: @@ -160,7 +193,7 @@ compile [when %body] to code: %condition join= " or \(% as lua)" %result join= ".." - \("if" if %first else "elseif") \(%condition) then + \("if" if %first else "elseif") \%condition then \(%action as lua statements) %fallthroughs = [] @@ -204,7 +237,7 @@ compile [when %branch_value == ? %body] to code: %condition join= " or (branch_value == \(% as lua))" %result join= ".." - \("if" if %first else "elseif") \(%condition) then + \("if" if %first else "elseif") \%condition then \(%action as lua statements) %fallthroughs = [] @@ -213,7 +246,8 @@ compile [when %branch_value == ? %body] to code: if (%result != ""): %result = ".." do --when == ? - local branch_value = \(%branch_value as lua);\(%result) + local branch_value = \(%branch_value as lua);\ + ..\%result end end --when == ? %result @@ -239,11 +273,13 @@ compile [..] end end parse [try %action] as: - try %action and if it succeeds {pass} or if it fails {pass} + try %action and if it succeeds: pass + ..or if it fails: pass parse [try %action and if it fails %fallback] as: - try %action and if it succeeds {pass} or if it fails %fallback + try %action and if it succeeds: pass + ..or if it fails %fallback parse [try %action and if it succeeds %success] as: - try %action and if it succeeds %success or if it fails {pass} + try %action and if it succeeds %success or if it fails: pass # Do/finally: compile [do %action then always %final_action] to code: ".." diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom index e86b904..b4c1283 100644 --- a/lib/metaprogramming.nom +++ b/lib/metaprogramming.nom @@ -107,6 +107,8 @@ rule [%tree as lua statements] =: compile [nomsu] to: "nomsu" compile [nomsu's %key] to: "nomsu[\(%key as lua)]" compile [nomsu %method %args] to: "nomsu[\(%method as lua)](nomsu, unpack(\(%args as lua)))" +compile [tree %tree with %replacements] to: ".." + nomsu:replaced_vars(\(%tree as lua), \(%replacements as lua)) parse [rule %signature] as: (nomsu's "defs")->(nomsu "get_stub" [\%signature]) diff --git a/lib/operators.nom b/lib/operators.nom index 1fcb42a..198a8ff 100644 --- a/lib/operators.nom +++ b/lib/operators.nom @@ -32,7 +32,17 @@ compile [..] compile [%obj'%key, %obj's %key, %obj -> %key] to: "(\(%obj as lua))[\(%key as lua)]" # Variable assignment operator, and += type versions -compile [%var = %val] to code: "\(%var as lua) = \(%val as lua);" +compile [%var = %val] to code: + lua> ".." + if \%var.type == 'List' and \%val.type == 'List' then + local lhs = {}; + for i,x in ipairs(\%var.value) do lhs[i] = nomsu:tree_to_lua(x); end + local rhs = {}; + for i,x in ipairs(\%val.value) do rhs[i] = nomsu:tree_to_lua(x); end + return table.concat(lhs, ", ").." = "..table.concat(rhs, ", ")..";"; + else + return \(%var as lua).." = "..\(%val as lua)..";"; + end 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);" @@ -53,7 +63,7 @@ lua do> ".." end nomsu:defmacro("%a "..nomsu_alias.." %b", (function(nomsu, vars) return "("..nomsu:tree_to_lua(vars.a).." "..op.." "..nomsu:tree_to_lua(vars.b)..")"; - end), [["(\\(%a) ]]..op..[[ \\(%b))"]]); + end), [["(\\%a ]]..op..[[ \\(%b))"]]); end # TODO: implement OR, XOR, AND for multiple operands diff --git a/lib/scopes.nom b/lib/scopes.nom index 8555287..29a543c 100644 --- a/lib/scopes.nom +++ b/lib/scopes.nom @@ -21,7 +21,7 @@ parse [using %scoped do %actions] as: getmetatable(nomsu.defs["#vars"]).__newindex = getmetatable(nomsu.defs["#vars"]).__index; do %actions -parse [scoped %actions] as: using %actions do {pass} +parse [scoped %actions] as: using %actions do (:pass) rule [from %filename import %rules] =: using: diff --git a/lib/utils2.nom b/lib/utils2.nom index def8854..cdaf5fa 100644 --- a/lib/utils2.nom +++ b/lib/utils2.nom @@ -27,7 +27,7 @@ compile [with %assignments %action] to code: assert (=lua "vars.eq and vars.eq.type == 'Word' and vars.eq.value == '='") ".." Invalid format for 'with' statement. List entries must have the form %var = (value) %value = (%tokens -> 3) - add (d{i=%i; var=%var; value=%value}) to %data + add {i=%i, var=%var, value=%value} to %data %foo = (..) join (..) "local old_value\(%->"i") = \((%->"var") as lua); \((%->"var") as lua) = \((%->"value") as lua);" -- cgit v1.2.3