From ac25e20b9f94505175841d9a8da7253f8996926d Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 28 Sep 2017 17:49:15 -0700 Subject: Kinda mostly working, except for closure vars like in lib/secrets.nom. --- lib/collections.nom | 163 ++++++++++++++++++++---------------------------- lib/control_flow.nom | 143 ++++++++++++++++++++---------------------- lib/metaprogramming.nom | 153 ++++++++++++++++++++++----------------------- lib/operators.nom | 89 +++++++++++++------------- lib/permissions.nom | 53 +++++++--------- lib/secrets.nom | 49 +++++++-------- lib/utils.nom | 108 +++++++++++++++++++------------- 7 files changed, 359 insertions(+), 399 deletions(-) (limited to 'lib') diff --git a/lib/collections.nom b/lib/collections.nom index c7cc10d..c976983 100644 --- a/lib/collections.nom +++ b/lib/collections.nom @@ -5,149 +5,122 @@ require "lib/operators.nom" # List/dict functions: # Indexing -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\[\%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 +parse: + %index st in %list; %index nd in %list; %index rd in %list + %index th in %list; %index in %list +..as: %list -> %index +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 -..=: - ".."|nomsu.utils.nth_to_last(\%list as lua\, \%index as lua\) +..to: "nomsu.utils.nth_to_last(\(%list as lua), \(%index as lua))" -macro [first in %list, first %list] =: - ".."|\%list as lua\[1] -macro [last in %list, last %list] =: - ".."|nomsu.utils.nth_to_last(\%list as lua\, 1) +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): ... -macro block [for %key -> %value in %dict %body] =: - assert ((%key's "type") == "Var") ".." - |For loop has the wrong type for the key variable. Expected Var, but got: \%key's "type"\ - assert ((%value's "type") == "Var") ".." - |For loop has the wrong type for the value variable. Expected Var, but got: \%value's "type"\ - ".." - |local vars = setmetatable({}, {__index=vars}) - |for k, v in pairs(\%dict as lua\) do - | \%key as lua\, \%value as lua\ = k, v - | \%body as lua\ - |end +compile (for %key -> %value in %dict %body) to block: ".." + |for k, v in pairs(\(%dict as lua)) do + | \(%key as lua), \(%value as lua) = k, v + | \(%body as lua statements) + |end # Membership testing -rule [%item is in %list, %list contains %item, %list has %item] =: +rule (%item is in %list; %list contains %item; %list has %item) =: for %key -> %value in %list: if (%key == %item): return (yes) return (no) -macro [%list has key %index, %list has index %index] =: ".." - |(\%list as lua\[\%index as lua\] ~= nil) -rule [..] - %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 +rule: + %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 == %item): return (no) return (yes) -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\[\%index as lua\] ~= nil) +compile (%list has key %index; %list has index %index) to: ".." + |(\(%list as lua)[\(%index as lua)] ~= nil) -macro [length of %list, size of %list, size %list, number of %list, len %list] =: - ".."|nomsu.utils.size(\%list as lua\) +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: "(\(%list as lua)[\(%index as lua)] ~= nil)" + +compile (length of %list; size of %list; size %list; number of %list; len %list) to: + "nomsu.utils.size(\(%list as lua))" # Chained lookup -macro [%list ->* %indices] =: +compile (%list ->* %indices) to: assert ((%indices's "type") == "List") ".." - |Expected List for chained lookup, not \%indices's "type"\ - %ret =: ".."|(\%list as lua\) + |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\) + %ret join=: "[\(%index as lua)]" + "\(%ret)" # Assignment -macro statement [..] - %list's %index = %new_value, %index st in %list = %new_value, %index nd in %list = %new_value - %index rd in %list = %new_value, %index th in %list = %new_value, %index in %list = %new_value +compile: + %list's %index = %new_value; %index st in %list = %new_value; %index nd in %list = %new_value + %index rd in %list = %new_value; %index th in %list = %new_value; %index in %list = %new_value %list -> %index = %new_value -..=: - assert ((%new_value's "type") == "Thunk") ".." +..to code: + assert ((%new_value's "type") == "Block") ".." |Dict assignment operation has the wrong type for the right hand side. - |Expected Thunk, but got \%new_value's "type"\. + |Expected Block, but got \(%new_value's "type"). |Maybe you used "=" instead of "=:"? - assert ((size of (%new_value ->*["value","value"])) == 1) ".." + assert ((size of (%new_value's "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\ + |Expected 1 value, but got \(repr %new_value) + %new_value =: %new_value ->* ["value",1] + "\(%list as lua)[\(%index as lua)] = \(%new_value as lua)" -macro [append %item to %list, add %item to %list] =: - ".."|table.insert(\%list as lua\, \%item as lua\) +compile (append %item to %list; add %item to %list) to: + "table.insert(\(%list as lua), \(%item as lua))" -rule [flatten %lists] =: +rule (flatten %lists) =: %flat =: [] for %list in %lists: for %item in %list: add %item to %flat %flat -rule [dict %items] =: +rule (dict %items) =: %dict =: [] for %pair in %items: %dict -> (first in %pair) =: last in %pair %dict -rule [entries in %dict] =: - lua block ".." - |local items = {} - |for k,v in pairs(vars.dict) do - | table.insert(items, {key=k,value=v}) - |end - |return items - -rule [keys in %dict] =: - lua block ".." - |local items = {} - |for k,v in pairs(vars.dict) do - | table.insert(items, k) - |end - |return items - -rule [values in %dict] =: - lua block ".." - |local items = {} - |for k,v in pairs(vars.dict) do - | table.insert(items, v) - |end - |return items +rule (entries in %dict) =: + %entries =: [] + for %k -> %v in %dict: + add (dict [["key",%k],["value",%v]]) to %entries + %entries + +rule (keys in %dict) =: + %keys =: [] + for %k -> %v in %dict: add %k to %keys + %keys + +rule (values in %dict) =: + %values =: [] + for %k -> %v in %dict: add %v to %values + %values # List Comprehension -macro [%expression for %var in %iterable] =: +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"\ + |List comprehension has the wrong type for the loop variable. Expected Var, but got: \(%var's "type") ".." |(function(game, vars) | local comprehension = {} - | 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\) do - | vars[''] = value - | comprehension[i] = \%expression as lua\ + | 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})) +parse (%expression for all %iterable) as: %expression for % in %iterable # TODO: maybe make a generator/coroutine? diff --git a/lib/control_flow.nom b/lib/control_flow.nom index 460d4dc..4e13a8c 100644 --- a/lib/control_flow.nom +++ b/lib/control_flow.nom @@ -3,73 +3,60 @@ require "lib/operators.nom" require "lib/utils.nom" # Conditionals -parse (if %condition %if_body) as lua code ".." - |if \(%condition) then - | \(lua expr "vars.if_body.value") +compile (if %condition %if_body) to code: ".." + |if \(%condition as lua) then + | \(%if_body as lua statements) |end -parse (if %condition %if_body else %else_body) as lua code ".." - |if \(%condition) then - | \(lua expr "vars.if_body.value") +compile (if %condition %if_body else %else_body) to code: ".." + |if \(%condition as lua) then + | \(%if_body as lua statements) |else - | \(lua expr "vars.else_body.value") + | \(%else_body as lua statements) |end # Return -parse (return) as lua code "do return end" -parse (return %return-value) as lua code "do return \(%return-value)" -parse (do %action) as lua expr ".." - |(\(%action))(nomsu, setmetatable({}, {__index=vars})) - +compile (return) to code: "do return end" +compile (return %return-value) to code: "do return \(%return-value as lua) end" # GOTOs -parse (-> %label) as lua code ".." +compile (-> %label) to code: ".." |::label_\(nomsu "var_to_lua_identifier" [%label]):: -parse (go to %label) as lua code ".." +compile (go to %label) to code: ".." |goto label_\(nomsu "var_to_lua_identifier" [%label]) # Loop control flow -parse (stop; stop loop; break) as lua code "break" -parse (stop for; stop for-loop; break for) as lua code "goto break_for" -parse (stop repeat; stop repeat-loop; break repeat) as lua code "goto break_repeat" -parse (stop %var; break %var) as lua code ".." +compile (stop; stop loop; break) to code: "break" +compile (stop for; stop for-loop; break for) to code: "goto break_for" +compile (stop repeat; stop repeat-loop; break repeat) to code: "goto break_repeat" +compile (stop %var; break %var) to code: ".." |goto break_\(nomsu "var_to_lua_identifier" [%var]) -parse (continue; continue loop) as lua code "continue" -parse (continue for; continue for-loop) as lua code "goto continue_for" -parse (continue repeat; continue repeat-loop) as lua code "goto continue_repeat" -parse (continue %var; go to next %var; on to the next %var) as lua code ".." +compile (continue; continue loop) to code: "continue" +compile (continue for; continue for-loop) to code: "goto continue_for" +compile (continue repeat; continue repeat-loop) to code: "goto continue_repeat" +compile (continue %var; go to next %var; on to the next %var) to code: ".." |goto continue_\(nomsu "var_to_lua_identifier" [%var]) # While loops -parse (repeat %body) as lua block ".." - |while true do - | \(lua expr "vars.body.value") - | ::continue_repeat:: - |end - |::break_repeat:: -parse (repeat while %condition %body) as lua block ".." +compile (repeat while %condition %body) to block: ".." |while \(%condition) do - | \(lua expr "vars.body.value") - | ::continue_repeat:: - |end - |::break_repeat:: -parse (repeat until %condition %body) as lua block ".." - |while not (\(%condition)) do - | \(lua expr "vars.body.value") + | \(%body as lua statements) | ::continue_repeat:: |end |::break_repeat:: +parse (repeat %body) as: repeat while (true) %body +parse (repeat until %condition %body) as: repeat while (not %condition) %body # Numeric range for loops -parse: +compile: for %var from %start to %stop by %step %body for %var from %start to %stop via %step %body -..as lua block ".." - |for i=\(%start),\(%stop),\(%step) do +..to block: ".." + |for i=\(%start as lua),\(%stop as lua),\(%step as lua) do # This trashes the loop variables, just like in Python. - | \(%var) = i - | \(lua expr "vars.body.value") + | \(%var as lua) = i + | \(%body as lua statements) | ::continue_for:: | ::continue_\(nomsu "var_to_lua_identifier" [%var]):: |end @@ -82,38 +69,39 @@ parse: ..as: for % from %start to %stop via %step %body parse (for all %start to %stop %body) as: for all %start to %stop via 1 %body -parse (for %var in %iterable %body) as lua block ".." - |for i,value in ipairs(\(%iterable)) do - # This trashes the loop variables, just like in Python. - | \(%var) = value - | \(lua expr "vars.body.value") - | ::continue_for:: - | ::continue_\(nomsu "var_to_lua_identifier" [%var]):: - |end - |::break_for:: - |::break_\(nomsu "var_to_lua_identifier" [%var]):: +compile (for %var in %iterable %body) to block: + ".." + |for i,value in ipairs(\(%iterable as lua)) do + # This trashes the loop variables, just like in Python. + | \(%var as lua) = value + | \(%body as lua statements) + | ::continue_for:: + | ::continue_\(nomsu "var_to_lua_identifier" [%var]):: + |end + |::break_for:: + |::break_\(nomsu "var_to_lua_identifier" [%var]):: parse (for all %iterable %body) as: for % in %iterable %body + # Switch statement/multi-branch if -parse (when %body) as lua block: +compile (when %body) to block: %result =: "" %fallthroughs =: [] - for %statement in (lua expr "vars.body.value.value"): - %func-call =: lua expr "vars.statement.value" - assert ((lua expr "vars['func-call'].type") == "FunctionCall") ".." + for %statement in (%body's "value"): + %func-call =: %statement's "value" + assert ((%func-call's "type") == "FunctionCall") ".." |Invalid format for 'when' statement. Only '*' blocks are allowed. - %tokens =: lua expr "vars['func-call'].value" - - %star =: lua expr "vars.tokens[1]" + %tokens =: %func-call's "value" + %star =: %tokens -> 1 assert (lua expr "vars.star and vars.star.type == 'Word' and vars.star.value == '*'") ".." |Invalid format for 'when' statement. Lines must begin with '*' - %condition =: lua expr "vars.tokens[2]" + %condition =: %tokens -> 2 assert %condition ".." |Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else" - %thunk =: lua expr "vars.tokens[3]" - if (%thunk == (nil)): + %action =: %tokens -> 3 + if (%action == (nil)): lua block "table.insert(vars.fallthroughs, vars.condition)" go to next %statement @@ -123,13 +111,14 @@ parse (when %body) as lua block: |do ..else: %condition =: %condition as lua - for all %fallthroughs: %condition join= " or \(%)" + for all %fallthroughs: + %condition join=: " or \(% as lua)" %result join=: ".." | |if \(%condition) then %result join=: ".." | - | \(lua expr "vars.thunk.value") + | \(%action as lua statements) | goto finished_when |end @@ -139,25 +128,24 @@ parse (when %body) as lua block: %result # Switch statement -parse (when %branch-value == ? %body) as lua block: +compile (when %branch-value == ? %body) to block: %result =: "local branch_value = \(%branch-value)" %fallthroughs =: [] - for %statement in (lua expr "vars.body.value.value"): - %func-call =: lua expr "vars.statement.value" - assert ((lua expr "vars['func-call'].type") == "FunctionCall") ".." + for %statement in (%body's "value"): + %func-call =: %statement's "value" + assert ((%func-call's "type") == "FunctionCall") ".." |Invalid format for 'when' statement. Only '*' blocks are allowed. - %tokens =: lua expr "vars['func-call'].value" - - %star =: lua expr "vars.tokens[1]" + %tokens =: %func-call's "value" + %star =: %tokens -> 1 assert (lua expr "vars.star and vars.star.type == 'Word' and vars.star.value == '*'") ".." |Invalid format for 'when' statement. Lines must begin with '*' - %condition =: lua expr "vars.tokens[2]" + %condition =: %tokens -> 2 assert %condition ".." |Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else" - %thunk =: lua expr "vars.tokens[3]" - if (%thunk == (nil)): + %action =: %tokens -> 3 + if (%action == (nil)): lua block "table.insert(vars.fallthroughs, vars.condition)" go to next %statement @@ -166,14 +154,15 @@ parse (when %branch-value == ? %body) as lua block: | |do ..else: - %condition =: "branch_value == (\(%condition))" - for all %fallthroughs: %condition join= " or (branch_value == \(%))" + %condition =: "branch_value == (\(%condition as lua))" + for all %fallthroughs: + %condition join=: " or (branch_value == \(% as lua))" %result join=: ".." | - |if \%condition\ then + |if \(%condition) then %result join=: ".." | - | \((lua expr "vars.thunk.value")) + | \(%action as lua statements) | goto finished_when |end diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom index 301d74b..7c643a9 100644 --- a/lib/metaprogramming.nom +++ b/lib/metaprogramming.nom @@ -2,80 +2,86 @@ This File contains rules for making rules and macros and some helper functions to make that easier. -# Nil +# Rule to make rules: lua code ".." - |nomsu:defmacro("nil", function(nomsu, vars) return "nil", nil end) - -# Macros: -lua code ".." - |local function parse_as(nomsu, vars) - | if vars.shorthand.type ~= "Block" then - | nomsu:error("Expected shorthand to be Block, but got "..vars.shorthand.type) - | end - | if vars.longhand.type ~= "Block" then - | nomsu:error("Expected longhand to be Block, but got "..vars.longhand.type) + |nomsu:def("escaped rule %rule_def = %body", function(nomsu, vars) + | local aliases = nomsu:typecheck(vars, "rule_def", "Block").value + | local body = nomsu:typecheck(vars, "body", "Block") + | local thunk = nomsu:tree_to_value({type="Thunk", value={type="Statements", value=body.value, src=body.src}, src=body.src}) + | local canonical = aliases[1] + | nomsu:def(canonical, thunk, body.src) + | local function rewriter(nomsu, vars) + | return nomsu:tree_to_lua(nomsu:replaced_vars(canonical, vars)) | end - | local template = vars.longhand - | local function parsing_as(nomsu, vars) - | local expanded = nomsu:replaced_vars(template, vars) - | local expr,statement = nomsu:tree_to_lua(expanded) - | return expr, statement + | for i=2,#aliases do + | nomsu:defmacro(aliases[i], rewriter, body.src) | end - | for _,call in ipairs(vars.shorthand.value) do - | nomsu:defmacro(call, parsing_as) - | end - |end - |nomsu:def("parse nomsu %shorthand as nomsu %longhand", parse_as) -parse nomsu \(parse %shorthand as %longhand) as nomsu \(parse nomsu \%shorthand as nomsu \%longhand) - -lua code ".." - |nomsu:defmacro("lua expr %code", function(nomsu, vars) - | return nomsu:tree_to_value(vars.code, vars), nil |end) +# Rule to make nomsu macros: +escaped rule \(escaped parse %shorthand as %longhand) = \: + lua code ".." + |local aliases = nomsu:typecheck(vars, "shorthand", "Block").value + |local template = nomsu:typecheck(vars, "longhand", "Block") + |local function parsing_as(nomsu, vars) + | local replacement = nomsu:replaced_vars(template, vars) + | return nomsu:tree_to_lua(replacement) + |end + |for _,call in ipairs(aliases) do + | nomsu:defmacro(call, parsing_as, template.src) + |end +escaped parse \(parse %shorthand as %longhand) as \: escaped parse \%shorthand as \%longhand +parse (rule %rule_def = %body) as: escaped rule \%rule_def = \%body -# Rule that lets you make new rules -lua code ".." - |nomsu:defmacro("rule %rule_def = %body", function(nomsu, vars) - | if vars.rule_def.type ~= "Block" then - | nomsu:error("Wrong type for rule definition, expected Block, but got "..vars.rule_def.type) - | end - | local thunk = nomsu:tree_to_lua({type="Thunk", value=vars.body, src=vars.body.src}) - | local fn_name = "fn_"..nomsu:var_to_lua_identifier(nomsu:get_stub(vars.rule_def.value[1])) - | local lua = ([[ +# Rule to make lua macros: +rule (escaped compile %macro_def to %body) =: + lua code ".." + |local aliases = nomsu:typecheck(vars, "macro_def", "Block").value + |local body = nomsu:typecheck(vars, "body", "Block") + |local thunk = nomsu:tree_to_value({type="Thunk", value={type="Statements", value=body.value, src=body.src}, src=body.src}) + |for _,alias in ipairs(aliases) do + | nomsu:defmacro(alias, thunk, body.src) + |end +rule (escaped compile %macro_def to code %body) =: + lua code ".." + |local aliases = nomsu:typecheck(vars, "macro_def", "Block").value + |local body = nomsu:typecheck(vars, "body", "Block") + |local thunk = nomsu:tree_to_value({type="Thunk", value={type="Statements", value=body.value, src=body.src}, src=body.src}) + |local thunk2 = function(nomsu, vars) return nil, thunk(nomsu, vars) end + |for _,alias in ipairs(aliases) do + | nomsu:defmacro(alias, thunk2) + |end +parse (compile %macro_def to %body) as: escaped compile \%macro_def to \%body +parse (compile %macro_def to code %body) as: escaped compile \%macro_def to code \%body +parse (compile %macro_def to block %body) as: escaped compile \%macro_def to code\: ".." |do - | local %s = %s - | for _,alias in ipairs(%s) do - | nomsu:def(alias, %s) - | end - |end]]):format(fn_name, thunk, nomsu:repr(vars.rule_def.value), fn_name) - | return nil, lua - |end) -parse (rule %rule_name) as: lua expr "nomsu.defs[(nomsu:get_stub(\(%rule_name).value[1]))]" - - -# Macro helper functions -rule (%tree as value) =: - lua expr "nomsu:tree_to_value(vars.tree, vars)" + | \(%body) + |end rule (%tree as lua) =: - lua expr "nomsu:tree_to_lua(vars.tree)" - - -parse (lua block %block) as: - lua code ".." - |do - | \(%block) - |end + lua expr "nomsu:tree_to_lua(\(%tree))" +rule (%tree as value) =: + lua expr "nomsu:tree_to_value(\(%tree), vars)" +compile (repr %obj) to: + "nomsu:repr(\(%obj as lua))" -parse (nomsu) as: lua expr "nomsu" -parse (nomsu's %key) as: - lua expr "nomsu['\(%key)']" -parse (nomsu %method %args) as: - lua expr "nomsu['\(%method)'](nomsu, unpack(\(%args)))" -parse (repr %) as: nomsu "repr" [%] -repr 5 +parse (lua block %block) as: lua code ".." + |do + | \(%block) + |end +rule (%tree as lua statement) =: + lua block ".." + |local _,statement = nomsu:tree_to_lua(\(%tree)) + |return statement +rule (%tree as lua statements) =: + lua block ".." + |local statements_tree = {type='Statements', value=\(%tree).value, src=\(%tree).src} + |local _,statements = nomsu:tree_to_lua(statements_tree) + |return 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)))" # Get the source code for a function rule (help %rule) =: @@ -89,7 +95,7 @@ rule (help %rule) =: |end # Compiler tools -rule (eval %code; run %code) =: nomsu "run" [%code] +parse (eval %code; run %code) as: nomsu "run" [%code] rule (source code from tree %tree) =: lua block ".." |local _,_,leading_space = vars.tree.src:find("\\n(%s*)%S") @@ -100,23 +106,10 @@ rule (source code from tree %tree) =: |else | return vars.tree.src:match(":%s*(%S.*)").."\\n" |end - parse (source code %body) as: source code from tree \%body -parse (parse tree %code) as: repr (nomsu "tree_to_str" [\%code]) - -parse (parse %code as lua code %lua) as: - parse nomsu \%code as nomsu: - nomsu "replaced_vars" [\(lua code %lua), lua expr "vars"] - -parse (parse %code as lua expr %lua) as: - parse nomsu \%code as nomsu: - nomsu "replaced_vars" [\(lua expr %lua), lua expr "vars"] - -parse (parse %code as lua block %lua) as: - parse nomsu \%code as nomsu: - nomsu "replaced_vars" [\(lua block %lua), lua expr "vars"] +parse (parse tree %code) as: nomsu "tree_to_str" [\%code] -parse (pass) as lua code: "" +parse (enable debugging) as: lua code "nomsu.debug = true" +parse (disable debugging) as: lua code "nomsu.debug = false" -pass diff --git a/lib/operators.nom b/lib/operators.nom index 4e7bd59..4d81806 100644 --- a/lib/operators.nom +++ b/lib/operators.nom @@ -1,15 +1,18 @@ require "lib/metaprogramming.nom" # Literals -parse (true; yes) as lua expr "true" -parse (false; no) as lua expr "false" -parse (nil; null) as lua expr "nil" -parse (inf; infinity) as lua expr "math.huge" -parse (nan; NaN; not a number) as lua expr "(0/0)" -parse (nop; pass) as lua code "" +compile (true; yes) to: "true" +compile (false; no) to: "false" +compile (nil; null) to: "nil" +compile (inf; infinity) to: "math.huge" +compile (nan; NaN; not a number) to: "(0/0)" +compile (pi; PI) to: "math.pi" +compile (tau; TAU) to: "(2*math.pi)" +compile (phi; PHI; golden ratio) to: "((1+math.sqrt(5))/2)" +compile (nop; pass) to code: "" # Ternary operator -parse (%if_expr if %condition else %else_expr) as lua expr ".." +compile (%if_expr if %condition else %else_expr) to: ".." |(function(nomsu, vars) # TODO: fix compiler bug that breaks this code if comments immediately follow ".." #.. Note: this uses a function instead of (condition and if_expr or else_expr) @@ -21,54 +24,46 @@ parse (%if_expr if %condition else %else_expr) as lua expr ".." | end |end)(nomsu, vars) +# Indexing: +compile (%obj's %key; %obj -> %key) to: "\(%obj as lua)[\(%key as lua)]" + # Variable assignment operator, and += type versions -lua block ".." - |local function assign(callback) - | return function(nomsu, vars, kind) - | if kind == "Expression" then - | nomsu:error("Cannot use an assignment operation as an expression value.") - | end - | if vars.var.type ~= "Var" then - | nomsu:error("Assignment operation has the wrong type for the left hand side. " - | .."Expected Var, but got: "..vars.var.type.."\\nMaybe you forgot a percent sign on the variable name?") - | end - | if vars.rhs.type ~= "Thunk" then - | nomsu:error("Assignment operation has the wrong type for the right hand side. " - | .."Expected Thunk, but got: "..vars.rhs.type.."\\nMaybe you used '=' instead of '=:'?") - | end - | if #vars.rhs.value.value > 1 then - | nomsu:error("Assignment operation should not have more than one value on the right hand side.") - | end - | return callback(nomsu:tree_to_lua(vars.var), - | nomsu:tree_to_lua(vars.rhs.value.value[1].value)), true - | end - |end - |nomsu:defmacro("%var = %rhs", assign(function(var,result) return var.." = "..result end)) - |nomsu:defmacro("%var += %rhs", assign(function(var,result) return var.." = "..var.." + "..result end)) - |nomsu:defmacro("%var -= %rhs", assign(function(var,result) return var.." = "..var.." - "..result end)) - |nomsu:defmacro("%var *= %rhs", assign(function(var,result) return var.." = "..var.." * "..result end)) - |nomsu:defmacro("%var /= %rhs", assign(function(var,result) return var.." = "..var.." / "..result end)) - |nomsu:defmacro("%var ^= %rhs", assign(function(var,result) return var.." = "..var.." ^ "..result end)) - |nomsu:defmacro("%var and= %rhs", assign(function(var,result) return var.." = "..var.." and "..result end)) - |nomsu:defmacro("%var or= %rhs", assign(function(var,result) return var.." = "..var.." or "..result end)) - |nomsu:defmacro("%var join= %rhs", assign(function(var,result) return var.." = "..var.." .. "..result end)) - |nomsu:defmacro("%var mod= %rhs", assign(function(var,result) return var.." = "..var.." % "..result end)) +compile (%var = %val) to code: "\(%var as lua) = \(%val as lua)" +compile (%var += %val) to code: "\(%var as lua) += \(%val as lua)" +compile (%var -= %val) to code: "\(%var as lua) -= \(%val as lua)" +compile (%var *= %val) to code: "\(%var as lua) *= \(%val as lua)" +compile (%var /= %val) to code: "\(%var as lua) /= \(%val as lua)" +compile (%var ^= %val) to code: "\(%var as lua) ^= \(%val as lua)" +compile (%var and= %val) to code: "\(%var as lua) = \(%var as lua) and\(%val as lua)" +compile (%var or= %val) to code: "\(%var as lua) = \(%var as lua) or \(%val as lua)" +compile (%var join= %val) to code: "\(%var as lua) = \(%var as lua) .. \(%val as lua)" +compile (%var mod= %val) to code: "\(%var as lua) = \(%var as lua) % \(%val as lua)" + +%x =: 5 # Binary Operators lua block ".." - |local binops = {"+","-","*","/","<","<=",">",">=","^",{"===","=="},{"!==","~="},"and","or",{"mod","%"}} + |local binops = {"-","/","<","<=",">",">=","^",{"===","=="},{"!==","~="},{"mod","%"}} |for _,op in ipairs(binops) do | local nomsu_alias = op | if type(op) == 'table' then | nomsu_alias, op = unpack(op) | end - | nomsu:defmacro("%a "..nomsu_alias.." %b", (function(nomsu, vars, kind) + | 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 +# TODO: implement OR, XOR, AND for multiple operands +compile (%a OR %b; %a | %b) to: "bit32.bor(\(%a as lua), \(%b as lua))" +compile (%a XOR %b) to: "bit32.bxor(\(%a as lua), \(%b as lua))" +compile (%a AND %b; %a & %b) to: "bit32.band(\(%a as lua), \(%b as lua))" +compile (NOT %; ~ %) to: "bit32.bnot(\(% as lua))" +compile (%x LSHIFT %shift; %x << %shift) to: "bit32.lshift(\(%x as lua), \(%shift as lua))" +compile (%x RSHIFT %shift) to: "bit32.rshift(\(%x as lua), \(%shift as lua))" +compile (%x ARSHIFT %shift; %x >> %shift) to: "bit32.arshift(\(%x as lua), \(%shift as lua))" # == and != do equivalence checking, rather than identity checking -parse (%a == %b) as lua expr "nomsu.utils.equivalent(\(%a), \(%b))" -parse (%a != %b) as lua expr "(not nomsu.utils.equivalent(\(%a), \(%b)))" +compile (%a == %b) to: "nomsu.utils.equivalent(\(%a as lua), \(%b as lua))" +compile (%a != %b) to: "(not nomsu.utils.equivalent(\(%a as lua), \(%b as lua)))" # Commutative Operators defined for up to 8 operands # TODO: work out solution for commutative operators using more clever macros @@ -77,10 +72,10 @@ lua block ".." |local comops = {"+","*","and","or"} |for _,_op in ipairs(comops) do | local op = _op - | local spec = "%1 "..op.." %2" - | for n=3,max_operands do + | local spec = "%1 " + | for n=2,max_operands do | spec = spec .." "..op.." %"..tostring(n) - | nomsu:defmacro(spec, (function(nomsu, vars, kind) + | nomsu:defmacro(spec, (function(nomsu, vars) | local bits = {} | for i=1,n do | table.insert(bits, (nomsu:tree_to_lua(vars[tostring(i)]))) @@ -125,5 +120,5 @@ lua block ".." |end # Unary operators -parse (- %a) as lua expr "-(\(%a))" -parse (not %a) as lua expr "not (\(%a))" +compile (- %) to: "-(\(% as lua))" +compile (not %) to: "not (\(% as lua))" diff --git a/lib/permissions.nom b/lib/permissions.nom index 3bb8f42..8d8b56d 100644 --- a/lib/permissions.nom +++ b/lib/permissions.nom @@ -4,43 +4,36 @@ require "lib/operators.nom" require "lib/collections.nom" # Permission functions -rule [restrict %rules to within %elite-rules] =: - say ".."|Restricting \%rules\ to within \%elite-rules\ - %rules =: keys in (nomsu "get_aliases" [%rules]) - %elite-rules =: keys in (nomsu "get_aliases" [%elite-rules]) +rule (restrict %rules to within %elite-rules) =: + say "Restricting \(%rules) to within \(%elite-rules)" for all (flatten [%elite-rules, %rules]): - assert ((nomsu's "defs") has key %it) ".."|Undefined function: \%it\ + assert ((nomsu's "defs") has key %) "Undefined function: \(%)" for all %rules: - assert (nomsu "check_permission" [%it]) ".." - |You do not have permission to restrict permissions for function: \%it\ - %foo =: dict (..) - [%it, yes] for %it in %elite-rules - ((nomsu's "defs")'s %it)'s "whiteset" =: %foo + assert (nomsu "check_permission" [%]) ".." + |You do not have permission to restrict permissions for function: \(%) + ((nomsu) ->* ["defs",%,"whiteset"]) =: + dict: [%, yes] for %it in %elite-rules -rule [allow %elite-rules to use %rules] =: - say ".."|Allowing \%elite-rules\ to use \%rules\ - %rules =: keys in (nomsu "get_aliases" [%rules]) - %elite-rules =: keys in (nomsu "get_aliases" [%elite-rules]) +rule (allow %elite-rules to use %rules) =: + say "Allowing \(%elite-rules) to use \(%rules)" for all (flatten [%elite-rules, %rules]): - assert ((nomsu's "defs") has key %it) ".."|Undefined function: \%it\ - for %fn in %rules: - assert (nomsu "check_permission" [%fn]) ".." - |You do not have permission to grant permissions for function: \%fn\ - %whiteset =: ((nomsu's "defs")'s %fn)'s "whiteset" - if (not %whiteset): on to the next %fn - for all %elite-rules: %whiteset's %it =: yes + assert ((nomsu's "defs") has key %) "Undefined function: \(%)" + for %rule in %rules: + assert (nomsu "check_permission" [%rule]) ".." + |You do not have permission to grant permissions for function: \(%rule) + %whiteset =: (nomsu) ->* ["defs",%rule,"whiteset"] + if (not %whiteset): go to next %rule + for all %elite-rules: %whiteset -> % = (yes) -rule [forbid %pleb-rules to use %rules] =: - say ".."|Forbidding \%pleb-rules\ to use \%rules\ - %rules =: keys in (nomsu "get_aliases" [%rules]) - %pleb-rules =: keys in (nomsu "get_aliases" [%pleb-rules]) +rule (forbid %pleb-rules to use %rules) =: + say "Forbidding \(%pleb-rules) to use \(%rules)" for all (flatten [%pleb-rules, %used]): - assert ((nomsu's "defs") has key %it) ".."|Undefined function: \%it\ + assert ((nomsu's "defs") has key %) "Undefined function: \(%)" for all %rules: - assert (nomsu "check_permission" [%it]) ".." + assert (nomsu "check_permission" [%]) ".." |You do not have permission to grant permissions for function: \%it\ - %whiteset =: ((nomsu's "defs")'s %it)'s "whiteset" + %whiteset =: (nomsu) ->* ["defs",%,"whiteset"] assert %whiteset ".." - |Cannot individually restrict permissions for \%it\ because it is currently + |Cannot individually restrict permissions for \(%) because it is currently |available to everyone. Perhaps you meant to use "restrict % to within %" instead? - for all %pleb-rules: %whiteset's %it =: nil + for all %pleb-rules: %whiteset's % = (nil) diff --git a/lib/secrets.nom b/lib/secrets.nom index 052ee6c..b6274ab 100644 --- a/lib/secrets.nom +++ b/lib/secrets.nom @@ -1,33 +1,30 @@ require "lib/core.nom" -macro block [with secrets %block] =: ".." +compile (with secrets %block) to block: ".." |local secrets = {} - |\(%block's "value") as lua\ - -macro block [with secrets as %secret_name %block] =: ".." - |local \%secret_name as value\ = {} - |\(%block's "value") as lua\ + |\(%block as lua statements) # Access the lua variable that should be within scope -macro [secrets] =: "secrets" +compile (secrets) to: "secrets" + +compile (secret %key; secret value of %key; secret value for %key) to: + assert ((%key's "type") == "Var") ".." + |Wrong type, expected Var, but got: \(%key's "type") + "secrets[\(repr (%key's "value"))]" + +compile (secret %key = %new_value) to code: + assert ((%key's "type") == "Var") ".." + |Wrong type, expected Var, but got: \(%key's "type") + "secrets[\(repr (%key's "value"))] = \(%new_value as lua)" -macro [secret %key, secret value of %key, secret value for %key] =: - if ((%key's "type") != "Var"): - error ".." - |Wrong type, expected Var, but got: \%key's "type"\ - ".."|secrets[\repr (%key's "value")\] +enable debugging +with secrets: + secret %foo = 5 + rule (plumb %) =: + secret %foo = % + rule (frop) =: + secret %foo -macro block [secret %key = %new_value] =: - lua block ".." - |if vars.key.type ~= "Var" then - | nomsu:error("Assignment operation has the wrong type for the left hand side. " - | .."Expected Var, but got: "..vars.key.type) - |end - |if vars.new_value.type ~= "Thunk" then - | nomsu:error("Assignment operation has the wrong type for the right hand side. " - | .."Expected Thunk, but got: "..vars.new_value.type.."\\nMaybe you used '=' instead of '=:'?") - |end - ".." - |local ret - |\lua expr "nomsu:tree_to_lua(vars.new_value.value)"\ - |secrets[\repr (%key's "value")\] = ret +say (frop) +pumb 99 +say (frop) diff --git a/lib/utils.nom b/lib/utils.nom index 11596f1..8f9cf1a 100644 --- a/lib/utils.nom +++ b/lib/utils.nom @@ -5,62 +5,82 @@ rule (error!; panic!; fail!; abort!) =: nomsu "error" [] rule (error %msg) =: nomsu "error"[%msg] -parse (assert %condition) as: lua code ".." - |if not (\(%condition)) then - | nomsu:error() +compile (assert %condition %msg) to code: ".." + |if not (\(%condition as lua)) then + | nomsu:error(\(%msg as lua)) |end -parse (assert %condition %msg) as: lua code ".." - |if not (\(%condition)) then - | nomsu:error(\(%msg)) - |end - -parse (show generated lua %block) as: lua code ".." - |nomsu:writeln(\(repr (nomsu "tree_to_lua" [%block]))) - +parse (assert %condition) as: assert %condition (nil) # String functions -rule (join %strs) =: - lua block ".." - |local str_bits = {} - |for i,bit in ipairs(vars.strs) do str_bits[i] = nomsu.utils.repr_if_not_string(bit) end - |return table.concat(str_bits) - rule (join %strs with glue %glue) =: lua block ".." |local str_bits = {} |for i,bit in ipairs(vars.strs) do str_bits[i] = nomsu.utils.repr_if_not_string(bit) end |return table.concat(str_bits, vars.glue) +parse (join %strs) as: join %strs with glue "" -parse (capitalize %str; %str capitalized) as: lua expr "(\(%str)):gsub('%l', string.upper, 1)" +compile (capitalize %str; %str capitalized) to: + "(\(%str as lua)):gsub('%l', string.upper, 1)" -parse (say %str) as: lua block ".." - |nomsu:writeln(nomsu.utils.repr_if_not_string(\(%str))) +compile (say %str) to: ".." + |nomsu:writeln(\(%str as lua)) # Number ranges -parse (%start to %stop) as: lua expr ".." - |nomsu.utils.range(\(%start), \(%stop)) -parse (%start to %stop by %step; %start to %stop via %step) as: lua expr ".." - |nomsu.utils.range(\(%start), \(%stop), \(%step)) +compile (%start to %stop by %step; %start to %stop via %step) to: ".." + |nomsu.utils.range(\(%start as lua), \(%stop as lua), \(%step as lua)) +parse (%start to %stop) as: %start to %stop by 1 -# Common utility functions -parse (random number; random; rand) as: lua expr "math.random()" -parse (random int %n; random integer %n; randint %n) as: lua expr "math.random(\(%n))" -parse (random from %low to %high; random number from %low to %high; rand %low %high) as: - lua expr "math.random(\(%low), \(%high))" +# Random functions +compile (random number; random; rand) to: "math.random()" +compile (random int %n; random integer %n; randint %n) to: "math.random(\(%n as lua))" +compile (random from %low to %high; random number from %low to %high; rand %low %high) to: + "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)]" -parse (sum of %items; sum %items) as: lua expr "nomsu.utils.sum(\(%items))" -parse (product of %items; product %items) as: lua expr "nomsu.utils.product(\(%items))" -parse (all of %items) as: lua expr "nomsu.utils.all(\(%items))" -parse (any of %items) as: lua expr "nomsu.utils.any(\(%items))" -# This is a rule, not a macro so we can use vars.items twice without running it twice. + lua expr "\(%elements)[math.random(#\(%elements))]" + +# Math functions +compile (abs %; absolute value of %; | % |) to: "math.abs(\(% as lua))" +compile (sqrt %; square root of %) to: "math.sqrt(\(% as lua))" +compile (sin %; sine %) to: "math.sin(\(% as lua))" +compile (cos %; cosine %) to: "math.cos(\(% as lua))" +compile (tan %; tangent %) to: "math.tan(\(% as lua))" +compile (asin %; arc sine %) to: "math.asin(\(% as lua))" +compile (acos %; arc cosine %) to: "math.acos(\(% as lua))" +compile (atan %; arc tangent %) to: "math.atan(\(% as lua))" +compile (atan2 %y %x) to: "math.atan2(\(%y as lua), \(%x as lua))" +compile (sinh %; hyperbolic sine %) to: "math.sinh(\(% as lua))" +compile (cosh %; hyperbolic cosine %) to: "math.cosh(\(% as lua))" +compile (tanh %; hyperbolic tangent %) to: "math.tanh(\(% as lua))" +compile (ceil %; ceiling %) to: "math.ceil(\(% as lua))" +compile (exp %; e^ %) to: "math.exp(\(% as lua))" +compile (log %; ln %; natural log %) to: "math.log(\(% as lua))" +compile (log % base %base) to: "math.log(\(% as lua), \(%base as lua))" +compile (floor %) to: "math.floor(\(% as lua))" +compile (round %; % rounded) to: "math.floor(\(% as lua) + .5)" +rule (%n rounded to the nearest %rounder) =: + lua expr "(\(%rounder))*math.floor(\(%n)/\(%rounder) + .5)" + +# Common utility functions +compile (sum of %items; sum %items) to: "nomsu.utils.sum(\(%items as lua))" +compile (product of %items; product %items) to: "nomsu.utils.product(\(%items as lua))" +compile (all of %items) to: "nomsu.utils.all(\(%items as lua))" +compile (any of %items) to: "nomsu.utils.any(\(%items as lua))" rule (avg of %items; average of %items) =: - lua expr "(nomsu.utils.sum(vars.items)/#vars.items)" -parse (min of %items; smallest of %items; lowest of %items) as: - lua expr "nomsu.utils.min(\(%items))" -parse (max of %items; biggest of %items; largest of %items; highest of %items) as: - lua expr "nomsu.utils.max(\(%items))" -parse (min of %items with respect to %keys) as: - lua expr "nomsu.utils.min(\(%items), \(%keys))" -parse (max of %items with respect to %keys) as: - lua expr "nomsu.utils.max(\(%items), \(%keys))" + lua expr "(nomsu.utils.sum(\(%items))/#\(%items))" +compile (min of %items; smallest of %items; lowest of %items) to: + "nomsu.utils.min(\(%items as lua))" +compile (max of %items; biggest of %items; largest of %items; highest of %items) to: + "nomsu.utils.max(\(%items as lua))" +compile (min of %items by %value_expr) to: + ".." + |nomsu.utils.min(\(%items as lua), function(item) + | local vars = setmetatable({['']=item}, {__index=vars}) + | return \(%value_expr as lua) + |end) +compile (max of %items by %value_expr) to: + ".." + |nomsu.utils.max(\(%items as lua), function(item) + | local vars = setmetatable({['']=item}, {__index=vars}) + | return \(%value_expr as lua) + |end) + -- cgit v1.2.3