diff --git a/README.md b/README.md index 9cd2ba0..d0e7b1d 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ which produces an output file which can be run with the command `lua output_file Example code can be found in the examples folder. -core.nom contains some *extremely* helpful and basic core functionality for the language, -written in the language itself, so I recommend adding `run file "core.nom"` to the top of +lib/core.nom contains some *extremely* helpful and basic core functionality for the language, +written in the language itself, so I recommend adding `require "lib/core.nom"` to the top of your files. There is a vim plugin for the language available in the [Vim Nomsu repository](https://bitbucket.org/squidarms/vim-nomsu/src). diff --git a/examples/parser_tests.nom b/examples/parser_tests.nom index b1eb23b..b91266e 100644 --- a/examples/parser_tests.nom +++ b/examples/parser_tests.nom @@ -1,4 +1,5 @@ require "lib/core.nom" +require "lib/testing.nom" test: say "foo" ..yields ".." @@ -148,12 +149,12 @@ test: z ..yields ".." |Call [if % % else %]: - | Var[x] + | Var["x"] | Thunk: | Call [x]! | Thunk: | Call [if % % else %]: - | Var[y] + | Var["y"] | Thunk: | Call [y]! | Thunk: @@ -169,6 +170,6 @@ test: %Brian's hat ..yields ".." |Call [% 's hat]: - | Var[Brian] + | Var["Brian"] say "All tests passed!" diff --git a/examples/sample_code.nom b/examples/sample_code.nom index e2b3a62..fe73ec7 100644 --- a/examples/sample_code.nom +++ b/examples/sample_code.nom @@ -78,7 +78,7 @@ if 1: yes if 1 (:yes) else (:no) -say (do: return: 5) +say (do: return 5) # Some variables rule [do %one also %two] =: @@ -88,7 +88,7 @@ rule [do %one also %two] =: do: say "one liner" ..also: say "another one liner" -say (do: return: "wow") +say (do: return "wow") say (1 + (-(2 * 3))) @@ -146,7 +146,7 @@ rule [dumsum %nums] =: %sum =: 0 for %n in %nums: %sum +=: %n - return: %sum + return %sum say (dumsum [1,2,3]) diff --git a/examples/sample_game.nom b/examples/sample_game.nom index 44b9d35..1f526e3 100644 --- a/examples/sample_game.nom +++ b/examples/sample_game.nom @@ -1,4 +1,5 @@ require "lib/core.nom" +require "lib/permissions.nom" require "lib/secrets.nom" require "lib/plurals.nom" @@ -101,8 +102,6 @@ with secrets: say ".." |Proposal: |\%src\ - say "foo" - macro block [propose %action] =: %source =: source code from tree %action diff --git a/examples/tutorial.nom b/examples/tutorial.nom index 306a0af..8739348 100644 --- a/examples/tutorial.nom +++ b/examples/tutorial.nom @@ -234,6 +234,7 @@ sing 9 bottles of beer say (5 + (4 * (- (1 + (6 + 2))))) # For convenience, +,*,"and", and "or" have been hand defined to work with up to 4 operands: 1 + 2 + 3 + 4 +say "Done with math." 1 * 2 * 3 * 4 1 and 2 and 3 and 4 1 or 2 or 3 or 4 @@ -245,6 +246,8 @@ any of [0,0,0,0,1,0,0] # And 3-operand chained inequality comparisons have been defined: 1 < 2 <= 3 +say "Done with math." + # Macros: # The "lua block %" and "lua expr %" macros can be used to write raw lua code: @@ -264,8 +267,8 @@ say ".."|The square root of 2 is \square root of 2\ # Macros can be defined as functions that take unprocessed syntax trees and return lua code # "macro block %" is for defining macros that produce blocks of code, not values macro block [unless %condition %body] =: ".." - |if not (\%condition as lua expr\) then - | \(lua expr "vars.body.value") as lua block\ + |if not (\%condition as lua\) then + | \(lua expr "vars.body.value") as lua\ |end unless (1 > 10): @@ -274,6 +277,6 @@ unless (1 > 10): # and "macro %" is for defining macros that produce an expression macro [%value as a boolean] =: ".." - |(not not (\%value as lua expr\)) + |(not not (\%value as lua\)) macro [yep] =: "true" diff --git a/lib/collections.nom b/lib/collections.nom index 3751d27..dbe2afa 100644 --- a/lib/collections.nom +++ b/lib/collections.nom @@ -9,18 +9,18 @@ macro [..] %list's %index, %index st in %list, %index nd in %list, %index rd in %list %index th in %list, %index in %list, %list -> %index ..=: - ".."|\%list as lua expr\[\%index as lua expr\] - ".."|\%list as lua expr\[\%index as lua expr\] + ".."|\%list as lua\[\%index as lua\] + ".."|\%list as lua\[\%index as lua\] macro [..] %index st to last in %list, %index nd to last in %list, %index rd to last in %list %index th to last in %list ..=: - ".."|compiler.utils.nth_to_last(\%list as lua expr\, \%index as lua expr\) + ".."|compiler.utils.nth_to_last(\%list as lua\, \%index as lua\) macro [first in %list, first %list] =: - ".."|\%list as lua expr\[1] + ".."|\%list as lua\[1] macro [last in %list, last %list] =: - ".."|compiler.utils.nth_to_last(\%list as lua expr\, 1) + ".."|compiler.utils.nth_to_last(\%list as lua\, 1) # Dict iteration convenience function. This could also be accomplished with: for all (entries in %dict): ... macro block [for %key -> %value in %dict %body] =: @@ -31,9 +31,9 @@ macro block [for %key -> %value in %dict %body] =: ".." |do | local vars = setmetatable({}, {__index=vars}) - | for k, v in pairs(\%dict as lua expr\) do - | \%key as lua expr\, \%value as lua expr\ = k, v - | \%body as lua block\ + | for k, v in pairs(\%dict as lua\) do + | \%key as lua\, \%value as lua\ = k, v + | \%body as lua\ | end |end @@ -43,7 +43,7 @@ rule [%item is in %list, %list contains %item, %list has %item] =: if (%key == %item): return (yes) return (no) macro [%list has key %index, %list has index %index] =: ".." - |(\%list as lua expr\[\%index as lua expr\] ~= nil) + |(\%list as lua\[\%index as lua\] ~= nil) rule [..] %item isn't in %list, %item is not in %list @@ -57,17 +57,19 @@ rule [..] macro [..] %list doesn't have key %index, %list does not have key %index %list doesn't have index %index, %list does not have index %index -..=: ".."|(\%list as lua expr\[\%index as lua expr\] ~= nil) +..=: ".."|(\%list as lua\[\%index as lua\] ~= nil) macro [length of %list, size of %list, number of %list, len %list] =: - ".."|#(\%list as lua expr\) + ".."|#(\%list as lua\) # Chained lookup macro [%list ->* %indices] =: - %ret =: %list as lua expr - for %index in %indices: - %ret join=: ".."|[\%index as lua expr\] - %ret + assert ((%indices's "type") == "List") ".." + |Expected List for chained lookup, not \%indices's "type"\ + %ret =: ".."|(\%list as lua\) + for %index in (%indices's "value"): + %ret join=: ".."|[\%index as lua\] + ".."|(\%ret\) # Assignment macro block [..] @@ -79,12 +81,15 @@ macro block [..] |Dict assignment operation has the wrong type for the right hand side. |Expected Thunk, but got \%new_value's "type"\. |Maybe you used "=" instead of "=:"? - if ((size of (%new_value ->*["value","value"])) > 1): - error ".."|Dict assignment operation has too many values on the right hand side. - ".."|\%list as lua expr\[\%index as lua expr\] = \(%new_value ->*["value","value",1]) as lua expr\ + assert ((size of (%new_value ->*["value","value"])) == 1) ".." + |Dict assignment operation has the wrong number of values on the right hand side. + |Expected 1 value, but got \repr %new_value\ + %new_value =: %new_value ->*["value","value",1] + if ((%new_value's "type") == "Statement"): %new_value =: %new_value's "value" + ".."|\%list as lua\[\%index as lua\] = \%new_value as lua\ macro [append %item to %list, add %item to %list] =: - ".."|table.insert(\%list as lua expr\, \%item as lua expr\) + ".."|table.insert(\%list as lua\, \%item as lua\) rule [flatten %lists] =: %flat =: [] @@ -96,8 +101,8 @@ rule [flatten %lists] =: rule [dict %items] =: %dict =: [] for %pair in %items: - lua block "vars.dict[vars.pair[1]] = vars.pair[2]" - return %dict + %dict -> (first in %pair) =: last in %pair + %dict rule [entries in %dict] =: lua block ".." @@ -114,18 +119,18 @@ macro [%expression for %var in %iterable] =: ".." |(function(game, vars) | local comprehension = {} - | for i,value in ipairs(\%iterable as lua expr\) do - | \%var as lua expr\ = value - | comprehension[i] = \%expression as lua expr\ + | for i,value in ipairs(\%iterable as lua\) do + | \%var as lua\ = value + | comprehension[i] = \%expression as lua\ | end | return comprehension |end)(game, setmetatable({}, {__index=vars})) macro [%expression for all %iterable] =: ".."|(function(game, vars) | local comprehension = {} - | for i,value in ipairs(\%iterable as lua expr\) do + | for i,value in ipairs(\%iterable as lua\) do | vars.it = value - | comprehension[i] = \%expression as lua expr\ + | comprehension[i] = \%expression as lua\ | end | return comprehension |end)(game, setmetatable({}, {__index=vars})) diff --git a/lib/control_flow.nom b/lib/control_flow.nom index e2caa2d..84bdb5c 100644 --- a/lib/control_flow.nom +++ b/lib/control_flow.nom @@ -3,121 +3,112 @@ require "lib/operators.nom" require "lib/utils.nom" # Conditionals -macro block [if %condition %if_body] =: - ".."|if \%condition as lua expr\ then - | \(lua expr "vars.if_body.value") as lua block\ +macro statement [if %condition %if_body] =: + ".."|if \%condition as lua\ then + | \(lua expr "vars.if_body.value") as lua\ |end -macro block [if %condition %if_body else %else_body] =: - ".."|if \%condition as lua expr\ then - | \(lua expr "vars.if_body.value") as lua block\ +macro statement [if %condition %if_body else %else_body] =: + ".."|if \%condition as lua\ then + | \(lua expr "vars.if_body.value") as lua\ |else - | \(lua expr "vars.else_body.value") as lua block\ + | \(lua expr "vars.else_body.value") as lua\ |end # Return macro block [return] =: "return nil" macro block [return %return-value] =: ".." - |do return \%return-value as lua expr\ end + |return \%return-value as lua\ macro [do %action] =: ".." - |(\%action as lua expr\)(compiler, setmetatable({}, {__index=vars})) + |(\%action as lua\)(compiler, setmetatable({}, {__index=vars})) # GOTOs -macro block [-> %label] =: ".." +macro statement [-> %label] =: ".." |::label_\compiler "var_to_lua_identifier" [%label]\:: -macro block [go to %label] =: ".." +macro statement [go to %label] =: ".." |goto label_\compiler "var_to_lua_identifier" [%label]\ # Loop control flow -macro block [break] =: "break" -macro block [break for] =: "goto break_for" -macro block [break for-all] =: "goto break_for_all" -macro block [break repeat] =: "goto break_repeat" -macro block [break repeat-until] =: "goto break_repeat_until" -macro block [break repeat-while] =: "goto break_repeat_while" -macro block [break %var, stop getting %var, no more %var] =: ".." +macro statement [break] =: "break" +macro statement [break for] =: "goto break_for" +macro statement [break for-all] =: "goto break_for_all" +macro statement [break repeat] =: "goto break_repeat" +macro statement [break repeat-until] =: "goto break_repeat_until" +macro statement [break repeat-while] =: "goto break_repeat_while" +macro statement [break %var, stop getting %var, no more %var] =: ".." |goto break_\compiler "var_to_lua_identifier" [%var]\ -macro block [continue] =: "continue" -macro block [continue for] =: "goto continue_for" -macro block [continue for-all] =: "goto continue_for_all" -macro block [continue repeat] =: "goto continue_repeat" -macro block [continue repeat-until] =: "goto continue_repeat_until" -macro block [continue repeat-while] =: "goto continue_repeat_while" -macro block [continue %var, go to next %var, on to the next %var] =: ".." +macro statement [continue] =: "continue" +macro statement [continue for] =: "goto continue_for" +macro statement [continue for-all] =: "goto continue_for_all" +macro statement [continue repeat] =: "goto continue_repeat" +macro statement [continue repeat-until] =: "goto continue_repeat_until" +macro statement [continue repeat-while] =: "goto continue_repeat_while" +macro statement [continue %var, go to next %var, on to the next %var] =: ".." |goto continue_\compiler "var_to_lua_identifier" [%var]\ # TODO: add labeled break/continue? # While loops macro block [repeat %body] =: - ".."|do - | while true do - | \(lua expr "vars.body.value") as lua block\ - | ::continue_repeat:: - | end - | ::break_repeat:: + ".."|while true do + | \(lua expr "vars.body.value") as lua\ + | ::continue_repeat:: |end + |::break_repeat:: macro block [repeat while %condition %body] =: - ".."|do - | while \%condition as lua expr\ do - | \(lua expr "vars.body.value") as lua block\ - | ::continue_repeat_while:: - | end - | ::break_repeat_while:: + ".."|while \%condition as lua\ do + | \(lua expr "vars.body.value") as lua\ + | ::continue_repeat_while:: |end + |::break_repeat_while:: macro block [repeat until %condition %body] =: - ".."|do - | while not (\%condition as lua expr\) do - | \(lua expr "vars.body.value") as lua block\ - | ::continue_repeat_until:: - | end - | ::break_repeat_until:: + ".."|while not (\%condition as lua\) do + | \(lua expr "vars.body.value") as lua\ + | ::continue_repeat_until:: |end + |::break_repeat_until:: # For loops macro block [for %var in %iterable %body] =: %var-type =: lua expr "vars.var.type" assert (%var-type == "Var") ".." |For loop has the wrong type for the loop variable. Expected Var, but got: \%var-type\ + # This trashes the loop variables, just like in Python. ".." - |do - | local vars = setmetatable({}, {__index=vars}) - | for i,value in ipairs(\%iterable as lua expr\) do - | \%var as lua expr\ = value - | \(lua expr "vars.body.value") as lua block\ - | ::continue_for:: - | ::continue_\compiler "var_to_lua_identifier" [%var]\:: - | end - | ::break_for:: - | ::break_\compiler "var_to_lua_identifier" [%var]\:: + |for i,value in ipairs(\%iterable as lua\) do + | \%var as lua\ = value + | \(lua expr "vars.body.value") as lua\ + | ::continue_for:: + | ::continue_\compiler "var_to_lua_identifier" [%var]\:: |end + |::break_for:: + |::break_\compiler "var_to_lua_identifier" [%var]\:: macro block [for all %iterable %body] =: - ".."|do - | local vars = setmetatable({}, {__index=vars}) - | for i,value in ipairs(\%iterable as lua expr\) do - | vars.it = value - | \(lua expr "vars.body.value") as lua block\ - | ::continue_for_all:: - | end - | ::break_for_all:: + pass # TODO: fix compiler bug + # This trashes the loop variables, just like in Python. + ".."|for i,value in ipairs(\%iterable as lua\) do + | vars.it = value + | \(lua expr "vars.body.value") as lua\ + | ::continue_for_all:: |end + |::break_for_all:: # Switch statement/multi-branch if macro block [when %body] =: %result =: "" for %statement in (lua expr "vars.body.value.value"): %func-call =: lua expr "vars.statement.value" - assert ((lua expr "vars['func-call'].type") != "FunctionCall") ".." + assert ((lua expr "vars['func-call'].type") == "FunctionCall") ".." |Invalid format for 'when' statement. Only '?' blocks are allowed. %tokens =: lua expr "vars['func-call'].value" %q =: lua expr "vars.tokens[1]" - assert (((lua expr "vars.q.type") != "Word") or ((lua expr "vars.q.value") != "?")) ".." + assert (((lua expr "vars.q.type") == "Word") and ((lua expr "vars.q.value") == "?")) ".." |Invalid format for 'when' statement. Lines must begin with '?' %thunk =: lua expr "vars.tokens[#vars.tokens]" - assert ((lua expr "vars.thunk.type") != "Thunk") ".." + assert ((lua expr "vars.thunk.type") == "Thunk") ".." |Invalid format for 'when' statement. Lines must have a body. %condition_bits =: [] for %i in (2 up to (lua expr "#vars.tokens")): @@ -128,7 +119,7 @@ macro block [when %body] =: | |do | local ret - | \(lua expr "vars.thunk.value") as lua block\ + | \(lua expr "vars.thunk.value") as lua\ | return ret |end ..else: @@ -141,9 +132,9 @@ macro block [when %body] =: ["value", %condition_bits] %result join=: ".." | - |if \%condition as lua expr\ then + |if \%condition as lua\ then | local ret - | \(lua expr "vars.thunk.value") as lua block\ + | \(lua expr "vars.thunk.value") as lua\ | return ret |end @@ -151,17 +142,17 @@ macro block [when %body] =: # Switch statement macro block [when %branch-value %body] =: - %result =: ".."|local branch_value = \%branch-value as lua expr\ + %result =: ".."|local branch_value = \%branch-value as lua\ for %statement in (lua expr "vars.body.value.value"): %func-call =: lua expr "vars.statement.value" - assert ((lua expr "vars['func-call'].type") != "FunctionCall") ".." + assert ((lua expr "vars['func-call'].type") == "FunctionCall") ".." |Invalid format for 'when' statement. Only == blocks are allowed. %tokens =: lua expr "vars['func-call'].value" %eq =: lua expr "vars.tokens[1]" - assert (((lua expr "vars.eq.type") != "Word") or ((lua expr "vars.eq.value") != "==")) ".." + assert (((lua expr "vars.eq.type") == "Word") and ((lua expr "vars.eq.value") == "==")) ".." |Invalid format for 'when' statement. Lines must begin with '==' %thunk =: lua expr "vars.tokens[#vars.tokens]" - assert ((lua expr "vars.thunk.type") != "Thunk") ".." + assert ((lua expr "vars.thunk.type") == "Thunk") ".." |Invalid format for 'when' statement. Lines must have a body. %condition_bits =: [] for %i in (2 up to (lua expr "#vars.tokens")): @@ -171,7 +162,7 @@ macro block [when %branch-value %body] =: | |do | local ret - | \(lua expr "vars.thunk.value") as lua block\ + | \(lua expr "vars.thunk.value") as lua\ | return ret |end ..else: @@ -184,9 +175,9 @@ macro block [when %branch-value %body] =: ["value", %condition_bits] %result join=: ".." | - |if compiler.utils.equivalent(branch_condition, \%condition as lua expr\) then + |if compiler.utils.equivalent(branch_condition, \%condition as lua\) then | local ret - | \(lua expr "vars.thunk.value") as lua block\ + | \(lua expr "vars.thunk.value") as lua\ | return ret |end %result diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom index d2f8fb6..3d29eb2 100644 --- a/lib/metaprogramming.nom +++ b/lib/metaprogramming.nom @@ -5,36 +5,42 @@ # Macros: -# macro block [macro block %spec = %user_macro] =: .. lua block ".." - |compiler:defmacro("macro block %spec = %user_macro", (function(compiler, vars, kind) + |local function make_fn(wrap_in_block) + | return function(compiler, vars, kind) # Do a minimal amount of pre-processing (get the spec and the source) - | local spec = compiler:get_invocations_from_definition(vars.spec, vars) - | spec = compiler.utils.repr(spec) - | local src = compiler.utils.repr(vars.user_macro.src) - | local user_macro = compiler:tree_to_lua(vars.user_macro) + | local spec = compiler:get_invocations_from_definition(vars.spec, vars) + | spec = compiler.utils.repr(spec) + | local src = compiler.utils.repr(vars.user_macro.src) + | local user_macro = compiler:tree_to_lua(vars.user_macro) # Then produce a block of code that creates the macro at runtime - | local lua = [[ - |compiler:defmacro(%s, (function(compiler, vars, kind) - | if kind == "Expression" then - | compiler:error("Macro "..%s.." was defined to be a block, but is being used as an expression") + | local lua = [[ + | compiler:defmacro(%s, (function(compiler, vars, kind) + | if kind == "Expression" then + | compiler:error("Macro "..%s.." was defined to be a block, but is being used as an expression") + | end + | local user_macro = %s + | local lua = user_macro(compiler, vars) + | %s + | return lua, true + | end), %s) + | ]] + | lua = lua:format(spec, compiler.utils.repr(spec), user_macro, + | wrap_in_block and [[lua = "do\\n "..lua.."\\nend"]] or "", src) + | return lua, true | end - | local user_macro = %s - | return ("do\\n"..user_macro(compiler, vars).."\\nend"), true - |end), %s) - |]] - | lua = lua:format(spec, compiler.utils.repr(spec), user_macro, src) - | return lua, true - |end), "N/A") + |end + |compiler:defmacro("macro statement %spec = %user_macro", make_fn(false), "N/A") + |compiler:defmacro("macro block %spec = %user_macro", make_fn(true), "N/A") macro block [macro %spec = %user_macro] =: ".."|compiler:defmacro( | \lua expr "compiler:get_invocations_from_definition(vars.spec, vars)"\, - | \lua expr "compiler:tree_to_lua(vars.user_macro, 'Expression')"\, + | \lua expr "compiler:tree_to_lua(vars.user_macro)"\, | \lua expr "compiler.utils.repr(vars.user_macro.src)"\) macro [compiler] =: "compiler" -macro [compiler's %key] =: ".."|compiler[\%key as lua expr\] +macro [compiler's %key] =: ".."|compiler[\%key as lua\] macro [compiler %method %args] =: lua block ".." |local args = {} @@ -59,7 +65,7 @@ macro [compiler utils %method %args] =: macro block [rule %spec = %body] =: ".." |compiler:def( | \compiler utils "repr" [compiler "get_invocations_from_definition" [%spec, lua expr "vars"]]\, - | \compiler "tree_to_lua" [%body, lua expr "vars"]\, + | \compiler "tree_to_lua" [%body]\, | \compiler utils "repr" [lua expr "vars.body.src"]\) # Get the source code for a function @@ -77,11 +83,8 @@ rule [help %invocation] =: rule [%tree as value] =: lua expr "compiler:tree_to_value(vars.tree, vars)" -rule [%tree as lua block] =: - lua expr "compiler:tree_to_lua(vars.tree, 'Statement')" - -rule [%tree as lua expr] =: - lua expr "compiler:tree_to_lua(vars.tree, 'Expression')" +rule [%tree as lua] =: + lua expr "compiler:tree_to_lua(vars.tree)" # Compiler tools rule [eval %code, run %code] =: compiler "run" [%code] diff --git a/lib/operators.nom b/lib/operators.nom index f6fea36..01289ef 100644 --- a/lib/operators.nom +++ b/lib/operators.nom @@ -12,10 +12,10 @@ macro [%if_expr if %condition else %else_expr] =: #.. Note: this uses a function instead of (condition and if_expr or else_expr) because that breaks if %if_expr is falsey. ".."|(function(compiler, vars) - | if \%condition as lua expr\ then - | return \%if_expr as lua expr\ + | if \%condition as lua\ then + | return \%if_expr as lua\ | else - | return \%else_expr as lua expr\ + | return \%else_expr as lua\ | end |end)(compiler, vars) @@ -37,8 +37,8 @@ lua block ".." | if #vars.rhs.value.value > 1 then | compiler:error("Assignment operation should not have more than one value on the right hand side.") | end - | return callback(compiler:tree_to_lua(vars.var, "Expression"), - | compiler:tree_to_lua(vars.rhs.value.value[1].value, "Expression")), true + | return callback(compiler:tree_to_lua(vars.var), + | compiler:tree_to_lua(vars.rhs.value.value[1].value)), true | end |end |compiler:defmacro("%var = %rhs", helper(function(var,result) return var.." = "..result end)) @@ -62,31 +62,31 @@ lua block ".." | end | compiler:defmacro("%a "..nomsu_alias.." %b", (function(compiler, vars, kind) | return "("..compiler:tree_to_lua(vars.a).." "..op.." "..compiler:tree_to_lua(vars.b)..")" - | end), [[".."|(\\%a as lua expr\\ ]]..op..[[ \\%b as lua expr\\)]]) + | end), [[".."|(\\%a as lua\\ ]]..op..[[ \\%b as lua\\)]]) |end # == and != do equivalence checking, rather than identity checking -macro [%a == %b] =: ".."|compiler.utils.equivalent(\%a as lua expr\, \%b as lua expr\) -macro [%a != %b] =: ".."|(not compiler.utils.equivalent(\%a as lua expr\, \%b as lua expr\)) +macro [%a == %b] =: ".."|compiler.utils.equivalent(\%a as lua\, \%b as lua\) +macro [%a != %b] =: ".."|(not compiler.utils.equivalent(\%a as lua\, \%b as lua\)) -# Commutative Operators defined for up to 10 operands +# Commutative Operators defined for up to 8 operands lua block ".." |local comops = {"+","*","and","or"} |for _,_op in ipairs(comops) do | local op = _op | local spec = "%1 "..op.." %2" - | for i=3,10 do - | spec = spec .. " %"..tostring(i) + | for n=3,8 do + | spec = spec .." "..op.." %"..tostring(n) | compiler:defmacro(spec, (function(compiler, vars, kind) | local bits = {} - | for _,v in ipairs(vars) do - | table.insert(bits, compiler:tree_to_lua(v)) + | for i=1,n do + | table.insert(bits, (compiler:tree_to_lua(vars[tostring(i)]))) | end | return "("..table.concat(bits, " "..op.." ")..")" | end)) | end |end -# Chained compairsions (e.g. x < y <= z < w) are defined up to 10 operands +# Chained compairsions (e.g. x < y <= z < w) are defined up to 8 operands lua block ".." |for _,chainers in ipairs{{"<","<="},{">",">="}} do | local function recurse(chain) @@ -109,8 +109,8 @@ lua block ".." | end | end) | end - # 9 operators == 10 operands, so don't continue any further - | if #chain >= 9 then return end + # 7 operators == 8 operands, so don't continue any further + | if #chain >= 7 then return end | for _,c in ipairs(chainers) do | table.insert(chain, c) | recurse(chain) @@ -121,5 +121,5 @@ lua block ".." |end # Unary operators -macro [- %a] =: ".."|-(\%a as lua expr\) -macro [not %a] =: ".."|not (\%a as lua expr\) +macro [- %a] =: ".."|-(\%a as lua\) +macro [not %a] =: ".."|not (\%a as lua\) diff --git a/lib/permissions.nom b/lib/permissions.nom index 4b6c428..fd55ec8 100644 --- a/lib/permissions.nom +++ b/lib/permissions.nom @@ -5,35 +5,40 @@ require "lib/collections.nom" # Permission functions rule [restrict %rules to within %elite-rules] =: + say ".."|Restricting \%rules\ to within \%elite-rules\ %rules =: compiler "get_invocations" [%rules] %elite-rules =: compiler "get_invocations" [%elite-rules] for all (flatten [%elite-rules, %rules]): - assert ((compiler's "defs") has %it) ".."|Undefined function: \%it\ + assert ((compiler's "defs") has key %it) ".."|Undefined function: \%it\ for all %rules: - assert (not (compiler "check_permission" [%it])) ".." + assert (compiler "check_permission" [%it]) ".." |You do not have permission to restrict permissions for function: \%it\ - ((compiler's "defs")'s %it)'s "whiteset" =: dict (..) - [%it, (yes)] for %it in %elite-rules + %foo =: dict (..) + [%it, yes] for %it in %elite-rules + say ".."|FFS: \%foo\ + ((compiler's "defs")'s %it)'s "whiteset" =: %foo rule [allow %elite-rules to use %rules] =: + say ".."|Allowing \%elite-rules\ to use \%rules\ %rules =: compiler "get_invocations" [%rules] %elite-rules =: compiler "get_invocations" [%elite-rules] for all (flatten [%elite-rules, %rules]): - assert ((compiler's "defs") has %it) ".."|Undefined function: \%it\ + assert ((compiler's "defs") has key %it) ".."|Undefined function: \%it\ for %fn in %rules: - assert (not (compiler "check_permission" [%fn])) ".." + assert (compiler "check_permission" [%fn]) ".." |You do not have permission to grant permissions for function: \%fn\ %whiteset =: ((compiler's "defs")'s %fn)'s "whiteset" if (not %whiteset): on to the next %fn for all %elite-rules: %whiteset's %it =: yes rule [forbid %pleb-rules to use %rules] =: + say ".."|Forbidding \%pleb-rules\ to use \%rules\ %rules =: compiler "get_invocations" [%rules] %pleb-rules =: compiler "get_invocations" [%pleb-rules] for all (flatten [%pleb-rules, %used]): - assert ((compiler's "defs") has %it) ".."|Undefined function: \%it\ + assert ((compiler's "defs") has key %it) ".."|Undefined function: \%it\ for all %rules: - assert (not (compiler "check_permission" [%it])) ".." + assert (compiler "check_permission" [%it]) ".." |You do not have permission to grant permissions for function: \%it\ %whiteset =: ((compiler's "defs")'s %it)'s "whiteset" assert %whiteset ".." diff --git a/lib/secrets.nom b/lib/secrets.nom index 4dd5a7a..60f7748 100644 --- a/lib/secrets.nom +++ b/lib/secrets.nom @@ -2,11 +2,11 @@ require "lib/core.nom" macro block [with secrets %block] =: ".." |local secrets = {} - |\(%block's "value") as lua block\ + |\(%block's "value") as lua\ macro block [with secrets as %secret_name %block] =: ".." |local \%secret_name as value\ = {} - |\(%block's "value") as lua block\ + |\(%block's "value") as lua\ # Access the lua variable that should be within scope macro [secrets] =: "secrets" @@ -29,6 +29,6 @@ macro block [secret %key = %new_value] =: |end ".."|do | local ret - | \lua expr "compiler:tree_to_lua(vars.new_value.value, 'Statement')"\ + | \lua expr "compiler:tree_to_lua(vars.new_value.value)"\ | secrets[\repr (%key's "value")\] = ret |end diff --git a/lib/testing.nom b/lib/testing.nom index 48b311f..94d9e8e 100644 --- a/lib/testing.nom +++ b/lib/testing.nom @@ -3,7 +3,7 @@ require "lib/metaprogramming.nom" # For unit testing macro block [test %code yields %expected] =: %generated =: lua expr "compiler.utils.repr(compiler:stringify_tree(vars.code.value))" - %expected =: %expected as lua expr + %expected =: %expected as lua if (%generated != %expected): say "Test failed!" say "Expected:" diff --git a/lib/utils.nom b/lib/utils.nom index 57b8dfc..ec35c15 100644 --- a/lib/utils.nom +++ b/lib/utils.nom @@ -6,16 +6,16 @@ rule [error!, panic!, fail!, abort!] =: rule [error %msg] =: compiler "error"[%msg] macro block [assert %condition] =: ".." - |if not (\%condition as lua expr\) then + |if not (\%condition as lua\) then | compiler:error() |end macro block [assert %condition %msg] =: ".." - |if not (\%condition as lua expr\) then - | compiler:error(\%msg as lua expr\) + |if not (\%condition as lua\) then + | compiler:error(\%msg as lua\) |end macro block [show generated lua %block] =: ".." - |compiler:writeln(\lua expr "compiler.utils.repr(compiler:tree_to_lua(vars.block.value, 'Statement'))"\) + |compiler:writeln(\lua expr "compiler.utils.repr(compiler:tree_to_lua(vars.block.value))"\) # String functions @@ -32,54 +32,54 @@ rule [join %strs with glue %glue] =: |return table.concat(str_bits, vars.glue) macro [capitalize %str, %str capitalized] =: ".." - |(\%str as lua expr\):gsub("%l", string.upper, 1) + |(\%str as lua\):gsub("%l", string.upper, 1) macro [repr %obj] =: - ".."|compiler.utils.repr(\%obj as lua expr\) + ".."|compiler.utils.repr(\%obj as lua\) macro [%obj as string] =: - ".."|compiler.utils.repr_if_not_string(\%obj as lua expr\) + ".."|compiler.utils.repr_if_not_string(\%obj as lua\) macro [say %str] =: - ".."|compiler:writeln(compiler.utils.repr_if_not_string(\%str as lua expr\)) + ".."|compiler:writeln(compiler.utils.repr_if_not_string(\%str as lua\)) # Number ranges macro [%start up to %stop] =: ".." - |compiler.utils.range(\%start as lua expr\, \%stop as lua expr\-1) + |compiler.utils.range(\%start as lua\, \%stop as lua\-1) macro [%start thru %stop, %start through %stop] =: ".." - |compiler.utils.range(\%start as lua expr\, \%stop as lua expr\) + |compiler.utils.range(\%start as lua\, \%stop as lua\) macro [%start down to %stop] =: ".." - |compiler.utils.range(\%start as lua expr\, \%stop as lua expr\+1,-1) + |compiler.utils.range(\%start as lua\, \%stop as lua\+1,-1) macro [%start down thru %stop, %start down through %stop] =: ".." - |compiler.utils.range(\%start as lua expr\, \%stop as lua expr\,-1) + |compiler.utils.range(\%start as lua\, \%stop as lua\,-1) macro [%start up to %stop via %step] =: ".." - |compiler.utils.range(\%start as lua expr\,\%stop as lua expr\-1,vars.step) + |compiler.utils.range(\%start as lua\,\%stop as lua\-1,vars.step) macro [%start thru %stop via %step, %start through %stop via %step] =: ".." - |compiler.utils.range(\%start as lua expr\,\%stop as lua expr\,vars.step) + |compiler.utils.range(\%start as lua\,\%stop as lua\,vars.step) macro [%start down to %stop via %step] =: ".." - |compiler.utils.range(\%start as lua expr\,\%stop as lua expr\+1,-vars.step) + |compiler.utils.range(\%start as lua\,\%stop as lua\+1,-vars.step) macro [%start down thru %stop via %step, %start down through %stop via %step] =: ".." - |compiler.utils.range(\%start as lua expr\,\%stop as lua expr\,-vars.step) + |compiler.utils.range(\%start as lua\,\%stop as lua\,-vars.step) # Common utility functions macro [random number, random, rand] =: "math.random()" -macro [random int %n, random integer %n, randint %n] =: ".."|math.random(\%n as lua expr\) +macro [random int %n, random integer %n, randint %n] =: ".."|math.random(\%n as lua\) macro [random from %low to %high, random number from %low to %high, rand %low %high] =: ".." - |math.random(\%low as lua expr\, \%high as lua expr\) + |math.random(\%low as lua\, \%high as lua\) rule [random choice from %elements, random choice %elements, random %elements] =: lua expr ".."|vars.elements[math.random(#vars.elements)] -macro [sum of %items, sum %items] =: ".."|compiler.utils.sum(\%items as lua expr\) -macro [product of %items, product %items] =: ".."|compiler.utils.product(\%items as lua expr\) -macro [all of %items] =: ".."|compiler.utils.all(\%items as lua expr\) -macro [any of %items] =: ".."|compiler.utils.any(\%items as lua expr\) +macro [sum of %items, sum %items] =: ".."|compiler.utils.sum(\%items as lua\) +macro [product of %items, product %items] =: ".."|compiler.utils.product(\%items as lua\) +macro [all of %items] =: ".."|compiler.utils.all(\%items as lua\) +macro [any of %items] =: ".."|compiler.utils.any(\%items as lua\) # This is a rule, not a macro so we can use vars.items twice without running it twice. rule [avg of %items, average of %items] =: lua expr ".."|(compiler.utils.sum(vars.items)/#vars.items) macro [min of %items, smallest of %items, lowest of %items] =: - ".."|compiler.utils.min(\%items as lua expr\) + ".."|compiler.utils.min(\%items as lua\) macro [max of %items, biggest of %items, largest of %items, highest of %items] =: - ".."|compiler.utils.min(\%items as lua expr\) + ".."|compiler.utils.min(\%items as lua\) macro [min of %items with respect to %keys] =: - ".."|compiler.utils.min(\%items as lua expr\, \%keys as lua expr\) + ".."|compiler.utils.min(\%items as lua\, \%keys as lua\) macro [max of %items with respect to %keys] =: - ".."|compiler.utils.max(\%items as lua expr\, \%keys as lua expr\) + ".."|compiler.utils.max(\%items as lua\, \%keys as lua\) diff --git a/nomsu.moon b/nomsu.moon index 549684f..c36dbb6 100755 --- a/nomsu.moon +++ b/nomsu.moon @@ -311,7 +311,7 @@ class NomsuCompiler error("Failed to compile generated code:\n#{code}\n\n#{err}") return (lua_thunk!)(self, vars or {}) - tree_to_lua: (tree, kind="Expression")=> + tree_to_lua: (tree)=> assert tree, "No tree provided." if not tree.type @error "Invalid tree: #{utils.repr(tree)}" @@ -319,8 +319,8 @@ class NomsuCompiler buffer = {} return_value = nil - to_lua = (t,kind)-> - ret = @tree_to_lua(t,kind) + to_lua = (t)-> + ret = @tree_to_lua(t) return ret add = (code)-> table.insert(buffer, code) @@ -462,10 +462,8 @@ class NomsuCompiler var_to_lua_identifier: (var)=> if var.type != "Var" @error("Tried to convert something that wasn't a Var into a lua identifier: it was not a Var, it was: "..label.type) - identifier = "var_" - for i=1,#var.value - identifier ..= ("%x")\format(string.byte(var.value, i)) - return identifier + "var"..(var.value\gsub "%W", (verboten)-> + if verboten == "_" then "__" else ("_%x")\format(verboten\byte!)) run_macro: (tree, kind="Expression")=> name = @fn_name_from_tree(tree)