aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/control_flow.nom17
-rw-r--r--lib/operators.nom109
-rw-r--r--lib/scopes.nom38
-rw-r--r--lib/secrets.nom23
-rw-r--r--lib/utils.nom4
-rw-r--r--lib/utils2.nom25
-rw-r--r--nomsu.lua23
-rwxr-xr-xnomsu.moon17
8 files changed, 125 insertions, 131 deletions
diff --git a/lib/control_flow.nom b/lib/control_flow.nom
index 2ac6cff..72a2ad1 100644
--- a/lib/control_flow.nom
+++ b/lib/control_flow.nom
@@ -7,10 +7,11 @@ compile [if %condition %if_body] to code: ".."
if \(%condition as lua) then
\(%if_body as lua statements)
end --end if
-compile [unless %condition %body] to code: ".."
- if not (\(%condition as lua)) then
- \(%body as lua statements)
- end --end if
+parse [unless %condition %unless_body] as: if (not %condition) %unless_body
+parse [if %x == %y %if_body] as: if (%x == %y) %if_body
+parse [if %x != %y %if_body] as: if (%x != %y) %if_body
+parse [unless %x == %y %if_body] as: if (%x != %y) %if_body
+parse [unless %x != %y %if_body] as: if (%x == %y) %if_body
compile [if %condition %if_body else %else_body, unless %condition %else_body else %if_body] to code: ".."
if \(%condition as lua) then
@@ -18,6 +19,10 @@ compile [if %condition %if_body else %else_body, unless %condition %else_body el
else
\(%else_body as lua statements)
end --end if
+parse [if %x == %y %if_body else %else_body] as: if (%x == %y) %if_body else %else_body
+parse [if %x != %y %if_body else %else_body] as: if (%x != %y) %if_body else %else_body
+parse [unless %x == %y %if_body else %else_body] as: if (%x != %y) %if_body else %else_body
+parse [unless %x != %y %if_body else %else_body] as: if (%x == %y) %if_body else %else_body
# Return
compile [return] to code: "do return; end"
@@ -60,6 +65,10 @@ compile [repeat while %condition %body] to code:
return %code
parse [repeat %body] as: repeat while (true) %body
parse [repeat until %condition %body] as: repeat while (not %condition) %body
+parse [repeat while %x == %y %body] as: repeat while (%x == %y) %body
+parse [repeat while %x != %y %body] as: repeat while (%x != %y) %body
+parse [repeat until %x == %y %body] as: repeat while (%x != %y) %body
+parse [repeat until %x != %y %body] as: repeat while (%x == %y) %body
# For loop control flow:
compile [stop for-loop] to code: "goto stop_for;"
diff --git a/lib/operators.nom b/lib/operators.nom
index cdf41fe..8ea7aad 100644
--- a/lib/operators.nom
+++ b/lib/operators.nom
@@ -57,84 +57,51 @@ compile [%var or= %val] to code: "\(%var as lua) = \(%var as lua) or \(%val as l
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);"
-# Binary Operators
-lua do> ".."
- 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)
- return "("..nomsu:tree_to_lua(\%a).." "..op.." "..nomsu:tree_to_lua(\%b)..")";
- end), [["(\\%a ]]..op..[[ \\%b)"]]);
- end
+# Math Operators
+compile [%x + %y] to: "(\(%x as lua) + \(%y as lua))"
+compile [%x - %y] to: "(\(%x as lua) - \(%y as lua))"
+compile [%x * %y] to: "(\(%x as lua) * \(%y as lua))"
+compile [%x / %y] to: "(\(%x as lua) / \(%y as lua))"
+compile [%x ^ %y] to: "(\(%x as lua) ^ \(%y as lua))"
+compile [%x mod %y] to: "(\(%x as lua) % \(%y as lua))"
+
+# Comparison Operators
+compile [%x < %y] to: "(\(%x as lua) < \(%y as lua))"
+compile [%x > %y] to: "(\(%x as lua) > \(%y as lua))"
+compile [%x <= %y] to: "(\(%x as lua) <= \(%y as lua))"
+compile [%x >= %y] to: "(\(%x as lua) >= \(%y as lua))"
+# == and != do equivalence checking, rather than identity checking
+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)))"
+# For strict identity checking:
+compile [%x === %y] to: "(\(%x as lua) == \(%y as lua))"
+compile [%x !== %y] to: "(\(%x as lua) ~= \(%y as lua))"
+
+# 3-part chained comparisons
+# (uses a lambda to avoid re-evaluating middle value, while still being an expression)
+parse [%x < %y < %z] as: =lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)"
+parse [%x <= %y < %z] as: =lua "(function(x,y,z) return x <= y and y < z; end)(\%x,\%y,\%z)"
+parse [%x < %y <= %z] as: =lua "(function(x,y,z) return x < y and y <= z; end)(\%x,\%y,\%z)"
+parse [%x <= %y <= %z] as: =lua "(function(x,y,z) return x <= y and y <= z; end)(\%x,\%y,\%z)"
+parse [%x > %y > %z] as: =lua "(function(x,y,z) return x > y and y > z; end)(\%x,\%y,\%z)"
+parse [%x >= %y > %z] as: =lua "(function(x,y,z) return x >= y and y > z; end)(\%x,\%y,\%z)"
+parse [%x > %y >= %z] as: =lua "(function(x,y,z) return x > y and y >= z; end)(\%x,\%y,\%z)"
+parse [%x >= %y >= %z] as: =lua "(function(x,y,z) return x >= y and y >= z; end)(\%x,\%y,\%z)"
+# TODO: optimize for common case where x,y,z are all either variables or number literals
+
+# Boolean Operators
+compile [%x and %y] to: "(\(%x as lua) and \(%y as lua))"
+compile [%x or %y] to: "(\(%x as lua) or \(%y as lua))"
-# TODO: implement OR, XOR, AND for multiple operands
+# Bitwise Operators
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 RSHIFT %shift, %x >>> %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
-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
-lua do> ".."
- local max_operands = 8;
- local comops = {"+","*","and","or"};
- for _,_op in ipairs(comops) do
- local op = _op;
- local spec = "%1 ";
- for n=2,max_operands do
- spec = spec .." "..op.." %"..tostring(n);
- nomsu:defmacro(spec, (function(nomsu, vars)
- local bits = {};
- for i=1,n do
- table.insert(bits, (nomsu:tree_to_lua(vars[tostring(i)])));
- end
- return "("..table.concat(bits, " "..op.." ")..")";
- end));
- end
- end
-
-# Chained compairsions (e.g. x < y <= z) are defined up to 3 operands
-lua do> ".."
- local max_operands = 3;
- for _,chainers in ipairs({{"<","<="},{">",">="}}) do
- local function recurse(chainers, chain)
- -- The 1-op versions are already more efficiently defined, and a 0-op version doesnt make sense
- if #chain >= 2 then;
- local spec = "%1";
- for i,op in ipairs(chain) do
- spec = spec .. " "..op.." %"..tostring(i+1);
- end
- -- Chained comparisons need to be functions to avoid re-evaluating their arguments :
- nomsu:def(spec, function(nomsu, vars)
- for i,op in ipairs(chain) do
- local a, b, result = vars[tostring(i)], vars[tostring(i+1)];
- if op == "<" then; result = a < b;
- elseif op == "<=" then; result = a <= b;
- elseif op == ">" then; result = a > b;
- elseif op == ">=" then; result = a >= b; end
- -- Short circuit
- if not result then; return false; end
- end
- end);
- end
- if #chain + 1 >= max_operands then; return; end
- for _,c in ipairs(chainers) do
- table.insert(chain, c);
- recurse(chainers, chain);
- table.remove(chain);
- end
- end
- recurse(chainers, {});
- end
+# TODO: implement OR, XOR, AND for multiple operands?
# Unary operators
compile [- %] to: "-(\(% as lua))"
diff --git a/lib/scopes.nom b/lib/scopes.nom
index 29a543c..910b30e 100644
--- a/lib/scopes.nom
+++ b/lib/scopes.nom
@@ -1,6 +1,7 @@
require "lib/metaprogramming.nom"
require "lib/operators.nom"
require "lib/control_flow.nom"
+require "lib/collections.nom"
compile [<%var> = %value] to code: ".."
nomsu.defs['#vars'][\(repr (%var's "value"))] = \(%value as lua);
@@ -12,25 +13,30 @@ compile [str %] to: "tostring(\(% as lua))"
compile [scope] to: "nomsu.defs"
compile [parent scope] to: "getmetatable(nomsu.defs).__index"
-parse [using %scoped do %actions] as:
- %scope = (=lua "setmetatable({['#vars']=setmetatable({}, {__index=nomsu.defs['#vars']})}, {__index=nomsu.defs})")
- with (nomsu's "defs") = %scope:
- do %scoped
- lua> ".."
- getmetatable(nomsu.defs).__newindex = getmetatable(nomsu.defs).__index;
- getmetatable(nomsu.defs["#vars"]).__newindex = getmetatable(nomsu.defs["#vars"]).__index;
- do %actions
+compile [using %scoped do %actions] to code: ".."
+ do
+ local old_scope, old_vars = nomsu.defs, vars;
+ local use_vars = setmetatable({}, {__index=old_scope['#vars']});
+ local scope = setmetatable({['#vars']=use_vars}, {__index=old_scope});
+ nomsu.defs = scope;
+ local ok, ret = pcall(function(nomsu, vars)
+ local ret;
+ do
+ \(%scoped as lua statements)
+ end
+ getmetatable(scope).__newindex = old_scope;
+ getmetatable(use_vars).__newindex = old_vars;
+ do
+ \(%actions as lua statements)
+ end
+ return ret;
+ end, nomsu, use_vars);
+ nomsu.defs = old_scope;
+ if not ok then nomsu:error(ret); end
+ end
parse [scoped %actions] as: using %actions do (:pass)
-rule [from %filename import %rules] =:
- using:
- require %filename
- ..do:
- %srcs = ((%'s "src") for %_ = % in (parent scope))
- for %src in (unique %srcs):
- run %src
-
parse [wrap %signature with %body] as:
using:
run ((nomsu)->*["defs",nomsu "get_stub" [\%signature->*["value",1]],"src"])
diff --git a/lib/secrets.nom b/lib/secrets.nom
deleted file mode 100644
index 0b9b1b1..0000000
--- a/lib/secrets.nom
+++ /dev/null
@@ -1,23 +0,0 @@
-require "lib/core.nom"
-
-compile [with secrets %block] to code: ".."
- do
- local secrets = {};
- \(%block as lua statements)
- end
-
-# Access the lua variable that should be within scope
-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);"
-
-rule [rules about secrecy] =: ["with secrets %"]
-
diff --git a/lib/utils.nom b/lib/utils.nom
index e46326e..ddaac8d 100644
--- a/lib/utils.nom
+++ b/lib/utils.nom
@@ -73,10 +73,6 @@ compile [e] to: "math.e"
compile [golden ratio, phi] to: "((1 + math.sqrt(5)) / 2)"
# 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 "(nomsu.utils.sum(\%items)/#\%items)"
compile [min of %items, smallest of %items, lowest of %items] to:
diff --git a/lib/utils2.nom b/lib/utils2.nom
index 07ff008..89a0767 100644
--- a/lib/utils2.nom
+++ b/lib/utils2.nom
@@ -49,3 +49,28 @@ compile [with %assignments %action] to code:
end
parse [with %thing = %value %action] as: with [%thing = %value] %action
+# Any/all/none
+compile [all of %items, all %items] to:
+ if (%items' "type") == "List":
+ "(\(join ((% as lua) for all (%items' "value")) with glue " and "))"
+ ..else:
+ "nomsu.utils.all(\(%items as lua))"
+parse [not all of %items, not all %items] as: not (all of %items)
+compile [any of %items, any %items] to:
+ if (%items' "type") == "List":
+ "(\(join ((% as lua) for all (%items' "value")) with glue " or "))"
+ ..else:
+ "nomsu.utils.any(\(%items as lua))"
+parse [none of %items, none %items] as: not (any of %items)
+
+
+compile [sum of %items, sum %items] to:
+ if (%items' "type") == "List":
+ "(\(join ((% as lua) for all (%items' "value")) with glue " + "))"
+ ..else:
+ "nomsu.utils.sum(\(%items as lua))"
+compile [product of %items, product %items] to:
+ if (%items' "type") == "List":
+ "(\(join ((% as lua) for all (%items' "value")) with glue " * "))"
+ ..else:
+ "nomsu.utils.product(\(%items as lua))"
diff --git a/nomsu.lua b/nomsu.lua
index bb38efd..4fd20e8 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -846,16 +846,22 @@ end)]]):format(concat(lua_bits, "\n"))
local def = self.defs[tree.stub]
if def and def.is_macro then
local expr, statement = self:run_macro(tree)
- if def.whiteset then
- if expr then
- expr = "(nomsu:assert_permission(" .. tostring(repr(tree.stub)) .. ") and " .. tostring(expr) .. ")"
- end
- if statement then
- statement = "nomsu:assert_permission(" .. tostring(repr(tree.stub)) .. ");\n" .. statement
- end
- end
remove(self.compilestack)
return expr, statement
+ elseif not def and self.__class.math_patt:match(tree.stub) then
+ local bits = { }
+ local _list_0 = tree.value
+ for _index_0 = 1, #_list_0 do
+ local tok = _list_0[_index_0]
+ if tok.type == "Word" then
+ insert(bits, tok.value)
+ else
+ local expr, statement = self:tree_to_lua(tok, filename)
+ self:assert(statement == nil, "non-expression value inside math expression")
+ insert(bits, expr)
+ end
+ end
+ return "(" .. tostring(concat(bits, " ")) .. ")"
end
local args = {
repr(tree.stub),
@@ -1402,6 +1408,7 @@ end)]]):format(concat(lua_bits, "\n"))
_base_0.__class = _class_0
local self = _class_0
self.def_number = 0
+ self.math_patt = re.compile([[ "%" (" " [*/^+-] " %")+ ]])
self.unescape_string = function(self, str)
return Cs(((P("\\\\") / "\\") + (P("\\\"") / '"') + ESCAPE_CHAR + P(1)) ^ 0):match(str)
end
diff --git a/nomsu.moon b/nomsu.moon
index 13ff129..fd74879 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -533,6 +533,7 @@ end);]])\format(concat(buffer, "\n"))
else
error("Unsupported value_to_nomsu type: #{type(value)}")
+ @math_patt: re.compile [[ "%" (" " [*/^+-] " %")+ ]]
tree_to_lua: (tree, filename)=>
-- Return <lua code for value>, <additional lua code>
@assert tree, "No tree provided."
@@ -570,13 +571,19 @@ end)]])\format(concat(lua_bits, "\n"))
def = @defs[tree.stub]
if def and def.is_macro
expr, statement = @run_macro(tree)
- if def.whiteset
- if expr
- expr = "(nomsu:assert_permission(#{repr tree.stub}) and #{expr})"
- if statement
- statement = "nomsu:assert_permission(#{repr tree.stub});\n"..statement
remove @compilestack
return expr, statement
+ elseif not def and @@math_patt\match(tree.stub)
+ bits = {}
+ for tok in *tree.value
+ if tok.type == "Word"
+ insert bits, tok.value
+ else
+ expr, statement = @tree_to_lua(tok, filename)
+ @assert(statement == nil, "non-expression value inside math expression")
+ insert bits, expr
+ return "(#{concat bits, " "})"
+
args = {repr(tree.stub), repr(tree.line_no)}
local arg_names, escaped_args
if def