diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2018-11-17 14:38:05 -0800 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2018-11-17 14:39:08 -0800 |
| commit | 7f47d4204039258cec78c767f489b7809b4257ff (patch) | |
| tree | c8533068b75ab453accfe1f688705e9e94c9e279 /core | |
| parent | 34a3dd22a4e132bd4e0fe3ce89831c3fe761d3d9 (diff) | |
In-progress (but working) overhaul of some elements including: function
calls, lib/thing.nom API, multi-assignments, varargs, etc.
Diffstat (limited to 'core')
| -rw-r--r-- | core/collections.nom | 2 | ||||
| -rw-r--r-- | core/control_flow.nom | 2 | ||||
| -rw-r--r-- | core/coroutines.nom | 33 | ||||
| -rw-r--r-- | core/id.nom | 2 | ||||
| -rw-r--r-- | core/math.nom | 8 | ||||
| -rw-r--r-- | core/metaprogramming.nom | 109 | ||||
| -rw-r--r-- | core/operators.nom | 120 | ||||
| -rw-r--r-- | core/text.nom | 2 |
8 files changed, 156 insertions, 122 deletions
diff --git a/core/collections.nom b/core/collections.nom index 82b5dfb..a586882 100644 --- a/core/collections.nom +++ b/core/collections.nom @@ -72,7 +72,7 @@ test: # Metatable stuff test: %t = {} - set %t's metatable to {__tostring: [%] -> "XXX"} + set %t's metatable to {__tostring: % -> "XXX"} assume ("\%t" == "XXX") (set %dict's metatable to %metatable) compiles to "\ diff --git a/core/control_flow.nom b/core/control_flow.nom index 964250e..9432a92 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -506,7 +506,7 @@ test: assume ((result of: return 99) == 99) # Inline thunk: -(result of %body) compiles to "\(what ([] -> %body) compiles to)()" +(result of %body) compiles to "\(what (-> %body) compiles to)()" test: %t = [1, [2, [[3], 4], 5, [[[6]]]]] %flat = [] diff --git a/core/coroutines.nom b/core/coroutines.nom index 7d17d63..0a625c2 100644 --- a/core/coroutines.nom +++ b/core/coroutines.nom @@ -3,29 +3,40 @@ This file defines the code that creates and manipulates coroutines use "core/metaprogramming.nom" +use "core/operators.nom" +use "core/control_flow.nom" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ test: - %nums = [] %co = (..) - coroutine: - -> 4 - -> 5 - repeat 3 times: -> 6 + ->: + yield 4 + yield 5 + repeat 3 times: yield 6 + %nums = [] for % in coroutine %co: %nums::add % assume (%nums == [4, 5, 6, 6, 6]) or barf "Coroutine iteration failed" -[coroutine %body, generator %body] all compile to "\ - ..(function() - \(%body as lua) - end)" -(-> %) compiles to "coroutine.yield(true, \((% as lua expr) if % else "nil"))" + %d = {x:0} + %co2 = (..) + coroutine: + %d.x += 1 + yield 1 + %d.x += 1 + yield + %d.x += 1 + repeat while ((coroutine status of %co2) != "dead"): + resume %co2 + assume %d.x == 3 + +(coroutine %body) parses as (coroutine from (-> %body)) + (for % in coroutine %co %body) compiles to "\ - ..for _junk,\(% as lua expr) in coroutine.wrap(\(%co as lua expr)) do + ..for \(% as lua expr) in coroutine_wrap(\(%co as lua expr)) do \(%body as lua) end" diff --git a/core/id.nom b/core/id.nom index 9cf5820..7de38f9 100644 --- a/core/id.nom +++ b/core/id.nom @@ -16,7 +16,7 @@ use "core/control_flow.nom" set %obj_by_id's metatable to {__mode: "v"} %id_by_obj = {} set %id_by_obj's metatable to {..} - __mode: "k", __index: [%self, %key] ->: + __mode: "k", __index: for (%self %key): if (%key == (nil)): return %self.%nil_surrogate diff --git a/core/math.nom b/core/math.nom index aa1d200..38fb984 100644 --- a/core/math.nom +++ b/core/math.nom @@ -70,7 +70,7 @@ externally [all of %items, all %items] all mean: return (no) return (yes) -[all of %items, all %items] all compile to: +#[all of %items, all %items] all compile to: unless (%items.type is "List"): return \(all of %items) @@ -89,7 +89,7 @@ externally [any of %items, any %items] all mean: return (yes) return (no) -[any of %items, any %items] all compile to: +#[any of %items, any %items] all compile to: unless (%items.type is "List"): return \(any of %items) @@ -110,7 +110,7 @@ externally [sum of %items, sum %items] all mean: %total += % return %total -[sum of %items, sum %items] all compile to: +#[sum of %items, sum %items] all compile to: unless (%items.type is "List"): return \(sum of %items) @@ -128,7 +128,7 @@ externally [product of %items, product %items] all mean: %prod *= % return %prod -[product of %items, product %items] all compile to: +#[product of %items, product %items] all compile to: unless (%items.type is "List"): return \(product of %items) diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 944dc34..165a814 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -3,7 +3,8 @@ This File contains actions for making actions and compile-time actions and some helper functions to make that easier. -lua> "NOMSU_CORE_VERSION = 10\nNOMSU_LIB_VERSION = 7" +lua> "NOMSU_CORE_VERSION = 11" +lua> "NOMSU_LIB_VERSION = 8" lua> "\ ..do local mangle_index = 0 @@ -21,23 +22,38 @@ lua> "\ lua> "\ ..compile.action["1 ->"] = function(compile, \%args, \%body) - local lua = LuaCode("(function(") - if SyntaxTree:is_instance(\%args) and \%args.type == "Action" then \%args = \%args:get_args() end - local lua_args = table.map(\%args, function(a) return SyntaxTree:is_instance(a) and compile(a):text(\ - ..) or a end) - lua:concat_append(lua_args, ", ") + if \%args and not \%body then \%args, \%body = {}, \%args end local body_lua = SyntaxTree:is_instance(\%body) and compile(\%body) or \%body if SyntaxTree:is_instance(\%body) and \%body.type ~= "Block" then body_lua:prepend("return ") end - body_lua:remove_free_vars(lua_args) + local lua = LuaCode("(function(") + if SyntaxTree:is_instance(\%args) and \%args.type == "Action" then \%args = \%args:get_args() + elseif SyntaxTree:is_instance(\%args) and \%args.type == "Var" then \%args = {\%args} end + for i, arg in ipairs(\%args) do + local arg_lua = SyntaxTree:is_instance(arg) and compile(arg):text() or arg + if arg_lua == "..." then + if i < #\%args then + compile_error_at(SyntaxTree:is_instance(arg) and arg or nil, + "Extra arguments must come last.", "Try removing any arguments after (*extra arguments*)") + end + elseif not arg_lua:is_lua_id() then + compile_error_at(SyntaxTree:is_instance(arg) and arg or nil, + "This does not compile to a Lua identifier, so it can't be used as a function argument.", + "This should probably be a Nomsu variable instead (like %x).") + end + lua:append(i > 1 and ", " or "", arg_lua) + body_lua:remove_free_vars({arg_lua}) + end body_lua:declare_locals() lua:append(")\\n ", body_lua, "\\nend)") return lua - end" + end + compile.action["->"] = compile.action["1 ->"] + compile.action["for"] = compile.action["1 ->"]" lua> "\ ..compile.action["what 1 compiles to"] = function(compile, \%action) local lua = LuaCode("compile.action[", \%action.stub:as_lua(), "](") - local lua_args = table.map(\%action:get_args(), function(a) return compile(a) end) + local lua_args = table.map(\%action:get_args(), compile) table.insert(lua_args, 1, "compile") lua:concat_append(lua_args, ", ") lua:append(")") @@ -100,17 +116,6 @@ lua> "\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -(call %fn with %args) compiles to: - lua> "\ - ..local lua = LuaCode(compile(\%fn), "(") - if \%args.type == 'List' then - lua:concat_append(table.map(\%args, function(a) return compile(a) end), ", ") - else - lua:append('unpack(', compile(\%args), ')') - end - lua:append(")") - return lua" - test: (foo %x) means "outer" with local [(foo %)'s meaning]: @@ -124,27 +129,36 @@ test: (%action means %body) compiles to: lua> "\ - ..local fn_name = \%action.stub:as_lua_id() - local \%args = \%action:get_args() - local lua = LuaCode(fn_name, " = ", \(what (%args -> %body) compiles to)) - lua:add_free_vars({fn_name}) + .. + local lua = LuaCode() + local fn_name = \%action.stub:as_lua_id() + if \%action.target then lua:append(compile(\%action.target), ".") + else lua:add_free_vars({fn_name}) end + lua:append(fn_name, " = ", \(what (%action -> %body) compiles to), ";") return lua" (%actions all mean %body) compiles to: lua> "\ ..local fn_name = \%actions[1].stub:as_lua_id() + local target = \%actions[1].target and compile(\%actions[1].target) or nil local \%args = List(\%actions[1]:get_args()) local lua = \(what (%actions.1 means %body) compiles to) for i=2,#\%actions do local alias = \%actions[i] local alias_name = alias.stub:as_lua_id() - lua:add_free_vars({alias_name}) local \%alias_args = List(alias:get_args()) - lua:append("\\n", alias_name, " = ") + lua:append("\\n") + if alias.target then + lua:append(compile(alias.target), ".") + else + lua:add_free_vars({alias_name}) + end + lua:append(alias_name, " = ") if \%args == \%alias_args then - lua:append(fn_name) + if target then lua:append(target, ".") end + lua:append(fn_name, ";") else - lua:append(\(what (%alias_args -> %actions.1) compiles to)) + lua:append(\(what (%alias_args -> %actions.1) compiles to), ";") end end return lua" @@ -182,11 +196,11 @@ test: %y = %tmp test: - set {%1: 1, %2: 2} + [%1, %2] = [1, 2] swap %1 and %2 assume ((%1 == 2) and (%2 == 1)) or barf "\ ..'parse % as %' failed on 'swap % and %'" - set {%tmp: 1, %tmp2: 2} + [%tmp, %tmp2] = [1, 2] swap %tmp and %tmp2 assume ((%tmp == 2) and (%tmp2 == 1)) or barf "\ ..'parse % as %' variable mangling failed." @@ -239,9 +253,15 @@ test: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [%action parses as %body] all parse as ([%action] all parse as %body) -(%tree as lua expr) compiles to "compile(\(=lua "compile(\%tree, true)"), true)" +#(%tree as lua expr) compiles to "compile(\(=lua "compile(\%tree, true)"), true)" +externally (%tree as lua expr) means: + lua> "\ + ..local tree_lua = compile(\%tree) + if \%tree.type == 'Block' then + tree_lua = LuaCode:from(\%tree.source, '(function()\n ', tree_lua, '\nend)()') + end + return tree_lua" -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ externally [%var as lua identifier, %var as lua id] all mean: lua> "\ @@ -256,7 +276,14 @@ externally [%var as lua identifier, %var as lua id] all mean: else error("Unknown type: "..tostring(\%var)) end" -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +test: + (num args (*extra arguments*)) means (select "#" (*extra arguments*)) + assume (num args 1 2 3) == 3 + (extra args (*extra arguments*)) means [*extra arguments*] + assume (extra args 1 2 3) == [1, 2, 3] + (third arg (*extra arguments*)) means (select 3 (*extra arguments*)) + assume (third arg 5 6 7 8) == 7 +(*extra arguments*) compiles to "..." (% is syntax tree) compiles to "SyntaxTree:is_instance(\(% as lua expr))" externally (% is %kind syntax tree) means (..) @@ -288,7 +315,7 @@ externally (%tree with vars %replacements) means (..) (%tree has subtree %match_tree) compiles to "\ ..(function() local match_tree = \(%match_tree as lua expr) - for subtree in coroutine.wrap(function() \(%tree as lua expr):map(coroutine.yield) end) do + for subtree in coroutine_wrap(function() \(%tree as lua expr):map(yield) end) do if subtree == match_tree then return true end end end)()" @@ -366,10 +393,20 @@ test: [compile %block, compiled %block, %block compiled] all compile to "\ ..compile(\(%block as lua))" +test: + (foo) means: return 100 200 300 + assume (select 2 (foo)) == 200 # Return statement is wrapped in a do..end block because Lua is unhappy if you put code after a return statement, unless you wrap it in a block. -(return %return_value) compiles to "\ - ..do return \(=lua "\%return_value and \(%return_value as lua expr) or ''") end" +(return (*extra arguments*)) compiles to: + lua> "\ + ..local lua = \(Lua "do return ") + for i=1,select('#',...) do + if i > 1 then lua:append(", ") end + lua:append(_1_as_lua((select(i, ...)))) + end + lua:append(" end") + return lua" # Literals (yes) compiles to "true" diff --git a/core/operators.nom b/core/operators.nom index cc86398..a7cb116 100644 --- a/core/operators.nom +++ b/core/operators.nom @@ -24,57 +24,58 @@ test: test: %x = 10 assume (%x == 10) - -# Variable assignment operator -(%var = %value) compiles to: - lua> "\ - ..local \%var_lua = \(%var as lua expr) - local \%value_lua = \(%value as lua expr) - local lua = LuaCode(\%var_lua, ' = ', \%value_lua, ';') - if \%var.type == 'Var' then - lua:add_free_vars({compile(\%var):text()}) - end - return lua" - -test: - set {%x: 10, %y: 20} + [%x, %y] = [10, 20] assume ((%x == 10) and (%y == 20)) or barf "mutli-assignment failed." - set {%x: %y, %y: %x} + [%x, %y] = [%y, %x] assume ((%y == 10) and (%x == 20)) or barf "swapping vars failed." + %vals = [4, 5] + [%x, %y] = (unpack %vals) + assume ((%x == 4) and (%y == 5)) or barf "unpacking failed" -# Simultaneous mutli-assignments like: x,y,z = 1,x,3; -# TODO: deprecate? -(set %assignments) compiles to: - assume (%assignments.type is "Dict") or barf "\ - ..Expected a Dict for the assignments part of '<- %' statement, not \%assignments" - +# Variable assignment operator +(%var = %value) compiles to: lua> "\ - ..local lhs, rhs = LuaCode(), LuaCode() - for i, item in ipairs(\%assignments) do - local \%target, \%value = item[1], item[2] - \%value = \%value:map(function(t) - if SyntaxTree:is_instance(t) and t.type == "Action" and t.stub == "?" then - return \%target + .. + local lua = LuaCode() + if \%var.type == "List" then + for i, \%assignment in ipairs(\%var) do + if i > 1 then lua:append(", ") end + local assignment_lua = \(%assignment as lua expr) + lua:append(assignment_lua) + if \%assignment.type == 'Var' then + lua:add_free_vars({assignment_lua:text()}) end - end) - local target_lua = \(%target as lua) - local value_lua = \(%value as lua) - if \%target.type == "Var" then - lhs:add_free_vars({target_lua:text()}) end - if i > 1 then - lhs:append(", ") - rhs:append(", ") + lua:append(' = ') + if \%value.type == "List" then + if #\%value ~= #\%var then + compile_error_at(\%value, + "This assignment has too "..(#\%value > #\%var and "many" or "few").." values.", + "Make sure it has the same number of values on the left and right hand side of the '=' operator.") + end + for i, \%val in ipairs(\%value) do + if i > 1 then lua:append(", ") end + local val_lua = \(%val as lua expr) + lua:append(val_lua) + end + lua:append(";") + else + lua:append(\(%value as lua expr), ';') end - lhs:append(target_lua) - rhs:append(value_lua) + else + local var_lua = \(%var as lua expr) + lua:append(var_lua) + if \%var.type == 'Var' then + lua:add_free_vars({var_lua:text()}) + end + lua:append(' = ', \(%value as lua expr), ';') end - return LuaCode(lhs, " = ", rhs, ";")" + return lua" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ test: - set {%foozle: "outer", %y: "outer"} + [%foozle, %y] = ["outer", "outer"] externally (set global x local y) means: external %foozle = "inner" %y = "inner" @@ -82,7 +83,7 @@ test: assume ((%foozle == "inner") and (%y == "outer")) or barf "external failed." (external %var = %value) compiles to "\(%var as lua) = \(%value as lua)" test: - set {%foozle: "outer", %y: "outer"} + [%foozle, %y] = ["outer", "outer"] externally (set global x local y) means: with external [%foozle]: %foozle = "inner" @@ -97,7 +98,7 @@ test: return %body_lua test: - set {%x: 1, %y: 2} + [%x, %y] = [1, 2] with {%z: nil, %x: 999}: %z = 999 assume (%z == 999) or barf "'with' failed." @@ -149,29 +150,14 @@ test: assume (%calls == 1) or barf "\ ..Three-way comparison evaluated middle value multiple times" -(%x < %y < %z) parses as (..) - call ([%a, %b, %c] -> ((%a < %b) and (%b < %c))) with [%x, %y, %z] - -(%x <= %y < %z) parses as (..) - call ([%a, %b, %c] -> ((%a <= %b) and (%b < %c))) with [%x, %y, %z] - -(%x < %y <= %z) parses as (..) - call ([%a, %b, %c] -> ((%a < %b) and (%b <= %c))) with [%x, %y, %z] - -(%x <= %y <= %z) parses as (..) - call ([%a, %b, %c] -> ((%a <= %b) and (%b <= %c))) with [%x, %y, %z] - -(%x > %y > %z) parses as (..) - call ([%a, %b, %c] -> ((%a > %b) and (%b > %c))) with [%x, %y, %z] - -(%x >= %y > %z) parses as (..) - call ([%a, %b, %c] -> ((%a >= %b) and (%b > %c))) with [%x, %y, %z] - -(%x > %y >= %z) parses as (..) - call ([%a, %b, %c] -> ((%a > %b) and (%b >= %c))) with [%x, %y, %z] - -(%x >= %y >= %z) parses as (..) - call ([%a, %b, %c] -> ((%a >= %b) and (%b >= %c))) with [%x, %y, %z] +(%x < %y < %z) parses as (((%a %b %c) -> ((%a < %b) and (%b < %c))) %x %y %z) +(%x <= %y < %z) parses as (((%a %b %c) -> ((%a <= %b) and (%b < %c))) %x %y %z) +(%x < %y <= %z) parses as (((%a %b %c) -> ((%a < %b) and (%b <= %c))) %x %y %z) +(%x <= %y <= %z) parses as (((%a %b %c) -> ((%a <= %b) and (%b <= %c))) %x %y %z) +(%x > %y > %z) parses as (((%a %b %c) -> ((%a > %b) and (%b > %c))) %x %y %z) +(%x >= %y > %z) parses as (((%a %b %c) -> ((%a >= %b) and (%b > %c))) %x %y %z) +(%x > %y >= %z) parses as (((%a %b %c) -> ((%a > %b) and (%b >= %c))) %x %y %z) +(%x >= %y >= %z) parses as (((%a %b %c) -> ((%a >= %b) and (%b >= %c))) %x %y %z) # TODO: optimize for common case where x,y,z are all either variables or number literals # Boolean Operators @@ -249,9 +235,9 @@ test: assume (%x == 4) or barf "*= failed" wrap %x around 3 assume (%x == 1) or barf "wrap around failed" -(%var += %) parses as (%var = (%var + %)) -(%var -= %) parses as (%var = (%var - %)) -(%var *= %) parses as (%var = (%var * %)) +(%var += %) parses as (%var = ((%var or 0) + %)) +(%var -= %) parses as (%var = ((%var or 0) - %)) +(%var *= %) parses as (%var = ((%var or 1) * %)) (%var /= %) parses as (%var = (%var / %)) (%var ^= %) parses as (%var = (%var ^ %)) (%var and= %) parses as (%var = (%var and %)) diff --git a/core/text.nom b/core/text.nom index 50a0ab5..62b6656 100644 --- a/core/text.nom +++ b/core/text.nom @@ -63,4 +63,4 @@ externally (%num as hex) means: for %name = %str in %escapes: with {%lua: Lua (quote %str)}: - %compile.action.%name = ([] -> %lua) + %compile.action.%name = (-> %lua) |
