aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/parser_tests.nom78
-rw-r--r--lib/collections.nom116
-rw-r--r--lib/control_flow.nom188
-rw-r--r--lib/metaprogramming.nom170
-rw-r--r--lib/moonscript.nom48
-rw-r--r--lib/operators.nom176
-rw-r--r--lib/permissions.nom26
-rw-r--r--lib/plurals.nom36
-rw-r--r--lib/secrets.nom16
-rw-r--r--lib/testing.nom88
-rw-r--r--lib/utils.nom84
-rwxr-xr-xnomsu.moon131
12 files changed, 541 insertions, 616 deletions
diff --git a/examples/parser_tests.nom b/examples/parser_tests.nom
index b91266e..25d7e99 100644
--- a/examples/parser_tests.nom
+++ b/examples/parser_tests.nom
@@ -3,28 +3,35 @@ require "lib/testing.nom"
test: say "foo"
..yields ".."
- |Call [say %]:
- | "foo"
+ |FunctionCall:
+ | Word:
+ | "say"
+ | String:
+ | "foo"
test: say (foo)
..yields ".."
- |Call [say %]:
- | Call [foo]!
+ |FunctionCall:
+ | Word:
+ | "say"
+ | FunctionCall:
+ | Word:
+ | "foo"
test:
- rule [fart] =: say "poot"
+ rule (fart) =: say "poot"
..yields ".."
|Call [rule % = %]:
| List:
- | Call [fart]!
- | Thunk:
+ | Call [fart]:
+ | Block:
| Call [say %]:
| "poot"
test: say (subexpressions work)
..yields ".."
|Call [say %]:
- | Call [subexpressions work]!
+ | Call [subexpressions work]:
test: say ["lists", "work"]
..yields ".."
@@ -33,9 +40,9 @@ test: say ["lists", "work"]
| "lists"
| "work"
-test (: say []) yields ".."
+test (say []) yields ".."
|Call [say %]:
- | <Empty List>
+ | List:
test:
say [..]
@@ -69,50 +76,50 @@ test:
..yields ".."
|Call [if % % else %]:
| 1
- | Thunk:
- | Call [yes]!
- | Thunk:
- | Call [no]!
+ | Block:
+ | Call [yes]:
+ | Block:
+ | Call [no]:
test:
- if 1 (: yes) else: no
+ if 1 (yes) else: no
..yields ".."
|Call [if % % else %]:
| 1
- | Thunk:
- | Call [yes]!
- | Thunk:
- | Call [no]!
+ | Block:
+ | Call [yes]:
+ | Block:
+ | Call [no]:
-test: say (do: return 5)
+test: say (do (return 5))
..yields ".."
|Call [say %]:
| Call [do %]:
- | Thunk:
+ | Block:
| Call [return %]:
| 5
test:
- say (..)
+ say:
fn call
..yields ".."
|Call [say %]:
- | Call [fn call]!
+ | Call [fn call]:
test:
do: say "one liner"
..also: say "another one liner"
..yields ".."
|Call [do % also %]:
- | Thunk:
+ | Block:
| Call [say %]:
| "one liner"
- | Thunk:
+ | Block:
| Call [say %]:
| "another one liner"
test:
- say (..)
+ say:
do:
say "hi"
return 5
@@ -120,7 +127,7 @@ test:
..yields ".."
|Call [say %]:
| Call [do %]:
- | Thunk:
+ | Block:
| Call [say %]:
| "hi"
| Call [return %]:
@@ -150,21 +157,21 @@ test:
..yields ".."
|Call [if % % else %]:
| Var["x"]
- | Thunk:
- | Call [x]!
- | Thunk:
+ | Block:
+ | Call [x]:
+ | Block:
| Call [if % % else %]:
| Var["y"]
- | Thunk:
- | Call [y]!
- | Thunk:
- | Call [z]!
+ | Block:
+ | Call [y]:
+ | Block:
+ | Call [z]:
test:
don't fuck this up
..yields ".."
- |Call [don 't fuck this up]!
+ |Call [don 't fuck this up]:
test:
%Brian's hat
@@ -173,3 +180,4 @@ test:
| Var["Brian"]
say "All tests passed!"
+
diff --git a/lib/collections.nom b/lib/collections.nom
index c976983..61ae71d 100644
--- a/lib/collections.nom
+++ b/lib/collections.nom
@@ -5,122 +5,116 @@ require "lib/operators.nom"
# List/dict functions:
# Indexing
-parse:
- %index st in %list; %index nd in %list; %index rd in %list
- %index th in %list; %index 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
+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
..to: "nomsu.utils.nth_to_last(\(%list as lua), \(%index as lua))"
-parse (first in %list; first %list) as: 1 st in %list
-parse (last in %list; last %list) as: 1 st to last in %list
+parse [first in %list, first %list] as: 1 st in %list
+parse [last in %list, last %list] as: 1 st to last in %list
# Dict iteration convenience function. This could also be accomplished with: for all (entries in %dict): ...
-compile (for %key -> %value in %dict %body) to block: ".."
- |for k, v in pairs(\(%dict as lua)) do
- | \(%key as lua), \(%value as lua) = k, v
- | \(%body as lua statements)
- |end
+compile [for %key -> %value in %dict %body] to code: ".."
+ |do;
+ | for k, v in pairs(\(%dict as lua)) do;
+ | \(%key as lua), \(%value as lua) = k, v;
+ | \(%body as lua statements)
+ | end;
+ |end;
# Membership testing
-rule (%item is in %list; %list contains %item; %list has %item) =:
+rule [%item is in %list, %list contains %item, %list has %item] =:
for %key -> %value in %list:
if (%key == %item): return (yes)
return (no)
-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)
-compile (%list has key %index; %list has index %index) to: ".."
- |(\(%list as lua)[\(%index as lua)] ~= nil)
+compile [%list has key %index, %list has index %index] to: ".."
+ |((\(%list as lua))[\(%index as lua)] ~= nil)
-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 [..]
+ %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:
+compile [length of %list, size of %list, size %list, number of %list, len %list] to:
"nomsu.utils.size(\(%list as lua))"
# Chained lookup
-compile (%list ->* %indices) to:
+compile [%list ->* %indices] to:
assert ((%indices's "type") == "List") ".."
|Expected List for chained lookup, not \(%indices's "type")
- %ret =: "\(%list as lua)"
+ %ret = "\(%list as lua)"
for %index in (%indices's "value"):
- %ret join=: "[\(%index as lua)]"
+ %ret join= "[\(%index as lua)]"
"\(%ret)"
# Assignment
-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
+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
..to code:
- assert ((%new_value's "type") == "Block") ".."
- |Dict assignment operation has the wrong type for the right hand side.
- |Expected Block, but got \(%new_value's "type").
- |Maybe you used "=" instead of "=:"?
- 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",1]
- "\(%list as lua)[\(%index as lua)] = \(%new_value as lua)"
-
-compile (append %item to %list; add %item to %list) to:
+ "(\(%list as lua))[\(%index as lua)] = \(%new_value as lua)"
+
+compile [append %item to %list, add %item to %list] to:
"table.insert(\(%list as lua), \(%item as lua))"
-rule (flatten %lists) =:
- %flat =: []
+rule [flatten %lists] =:
+ %flat = []
for %list in %lists:
for %item in %list:
add %item to %flat
%flat
-rule (dict %items) =:
- %dict =: []
+rule [dict %items] =:
+ %dict = []
for %pair in %items:
- %dict -> (first in %pair) =: last in %pair
+ %dict -> (%pair -> 1) = (%pair -> 2)
%dict
-rule (entries in %dict) =:
- %entries =: []
+rule [entries in %dict] =:
+ %entries = []
for %k -> %v in %dict:
add (dict [["key",%k],["value",%v]]) to %entries
%entries
-rule (keys in %dict) =:
- %keys =: []
+rule [keys in %dict] =:
+ %keys = []
for %k -> %v in %dict: add %k to %keys
%keys
-rule (values in %dict) =:
- %values =: []
+rule [values in %dict] =:
+ %values = []
for %k -> %v in %dict: add %v to %values
%values
# List Comprehension
-compile (%expression for %var in %iterable) to:
+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")
".."
- |(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
+ |(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}))
-parse (%expression for all %iterable) as: %expression for % in %iterable
+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 2ff764d..c4d6900 100644
--- a/lib/control_flow.nom
+++ b/lib/control_flow.nom
@@ -3,168 +3,174 @@ require "lib/operators.nom"
require "lib/utils.nom"
# Conditionals
-compile (if %condition %if_body) to code: ".."
- |if \(%condition as lua) then
+compile [if %condition %if_body] to code: ".."
+ |if \(%condition as lua) then;
| \(%if_body as lua statements)
- |end
+ |end;
-compile (if %condition %if_body else %else_body) to code: ".."
- |if \(%condition as lua) then
+compile [if %condition %if_body else %else_body] to code: ".."
+ |if \(%condition as lua) then;
| \(%if_body as lua statements)
- |else
+ |else;
| \(%else_body as lua statements)
- |end
+ |end;
# Return
-compile (return) to code: "do return end"
-compile (return %return-value) to code: "do return \(%return-value as lua) end"
+compile [return] to code: "do; return; end;"
+compile [return %return-value] to code: "do; return \(%return-value as lua); end;"
# GOTOs
-compile (-> %label) to code: ".."
- |::label_\(nomsu "var_to_lua_identifier" [%label])::
-compile (go to %label) to code: ".."
- |goto label_\(nomsu "var_to_lua_identifier" [%label])
+compile [-> %label] to code: ".."
+ |::label_\(nomsu "var_to_lua_identifier" [%label])::;
+compile [go to %label] to code: ".."
+ |goto label_\(nomsu "var_to_lua_identifier" [%label]);
# Loop control flow
-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])
-
-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])
+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]);
+
+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
-compile (repeat while %condition %body) to block: ".."
- |while \(%condition as lua) do
- | \(%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
+compile [repeat while %condition %body] to code: ".."
+ |do;
+ | while \(%condition as lua) do;
+ | \(%body as lua statements)
+ | ::continue_repeat::;
+ | end;
+ | ::break_repeat::;
+ |end;
+parse [repeat %body] as: repeat while (true) %body
+parse [repeat until %condition %body] as: repeat while (not %condition) %body
# Numeric range for loops
-compile:
+compile [..]
for %var from %start to %stop by %step %body
for %var from %start to %stop via %step %body
-..to block: ".."
- |for i=\(%start as lua),\(%stop as lua),\(%step as lua) do
+..to code: ".."
+ |do;
+ | for i=\(%start as lua),\(%stop as lua),\(%step as lua) do;
# This trashes the loop variables, just like in Python.
- | \(%var as lua) = i
- | \(%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 %var from %start to %stop %body) as: for %var from %start to %stop via 1 %body
-parse:
+ | \(%var as lua) = i;
+ | \(%body as lua statements)
+ | ::continue_for::;
+ | ::continue_\(nomsu "var_to_lua_identifier" [%var])::;
+ | end;
+ | ::break_for::;
+ | ::break_\(nomsu "var_to_lua_identifier" [%var])::;
+ |end;
+parse [for %var from %start to %stop %body] as: for %var from %start to %stop via 1 %body
+parse [..]
for all %start to %stop by %step %body
for all %start to %stop via %step %body
..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 all %start to %stop %body] as: for all %start to %stop via 1 %body
-compile (for %var in %iterable %body) to block:
+compile [for %var in %iterable %body] to code:
".."
- |for i,value in ipairs(\(%iterable as lua)) do
+ |do;
+ | 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
+ | \(%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])::;
+ |end;
+parse [for all %iterable %body] as: for % in %iterable %body
# Switch statement/multi-branch if
-compile (when %body) to block:
- %result =: ""
- %fallthroughs =: []
+compile [when %body] to code:
+ %result = "do;\n"
+ %fallthroughs = []
for %func-call in (%body's "value"):
assert ((%func-call's "type") == "FunctionCall") ".."
|Invalid format for 'when' statement. Only '*' blocks are allowed.
- %tokens =: %func-call's "value"
- %star =: %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 =: %tokens -> 2
+ %condition = (%tokens -> 2)
assert %condition ".."
|Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
- %action =: %tokens -> 3
+ %action = (%tokens -> 3)
if (%action == (nil)):
lua block "table.insert(vars.fallthroughs, vars.condition)"
go to next %func-call
if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"):
- %result join=: ".."
+ %result join= ".."
|
- |do
+ |do;
..else:
- %condition =: %condition as lua
+ %condition = (%condition as lua)
for all %fallthroughs:
- %condition join=: " or \(% as lua)"
- %result join=: ".."
+ %condition join= " or \(% as lua)"
+ %result join= ".."
|
- |if \(%condition) then
- %result join=: ".."
+ |if \(%condition) then;
+ %result join= ".."
|
| \(%action as lua statements)
- | goto finished_when
- |end
+ | goto finished_when;
+ |end;
- %fallthroughs =: []
+ %fallthroughs = []
- %result join=: "\n::finished_when::"
+ %result join= "\n::finished_when::;\nend;"
%result
# Switch statement
-compile (when %branch-value == ? %body) to block:
- %result =: "local branch_value = \(%branch-value as lua)"
- %fallthroughs =: []
+compile [when %branch-value == ? %body] to code:
+ %result = "do;\nlocal branch_value = \(%branch-value as lua)"
+ %fallthroughs = []
for %func-call in (%body's "value"):
assert ((%func-call's "type") == "FunctionCall") ".."
|Invalid format for 'when' statement. Only '*' blocks are allowed.
- %tokens =: %func-call's "value"
- %star =: %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 =: %tokens -> 2
+ %condition = (%tokens -> 2)
assert %condition ".."
|Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
- %action =: %tokens -> 3
+ %action = (%tokens -> 3)
if (%action == (nil)):
lua block "table.insert(vars.fallthroughs, vars.condition)"
go to next %func-call
if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"):
- %result join=: ".."
+ %result join= ".."
|
- |do
+ |do;
..else:
- %condition =: "branch_value == (\(%condition as lua))"
+ %condition = "branch_value == (\(%condition as lua))"
for all %fallthroughs:
- %condition join=: " or (branch_value == \(% as lua))"
- %result join=: ".."
+ %condition join= " or (branch_value == \(% as lua))"
+ %result join= ".."
|
- |if \(%condition) then
- %result join=: ".."
+ |if \(%condition) then;
+ %result join= ".."
|
| \(%action as lua statements)
- | goto finished_when
- |end
+ | goto finished_when;
+ |end;
- %fallthroughs =: []
+ %fallthroughs = []
- %result join=: "\n::finished_when::"
+ %result join= "\n::finished_when::;\nend;"
%result
diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom
index 4aa10e3..12144b4 100644
--- a/lib/metaprogramming.nom
+++ b/lib/metaprogramming.nom
@@ -4,127 +4,105 @@
# Rule to make rules:
lua code ".."
- |nomsu:defmacro("rule %rule_def = %body", function(nomsu, vars)
- | local aliases = nomsu:typecheck(vars, "rule_def", "Block").value
- | local canonical = aliases[1]
- | local body = nomsu:typecheck(vars, "body", "Block")
- | local thunk = nomsu:tree_to_lua({type="Thunk", value={type="Statements", value=body.value, src=body.src}, src=body.src})
- | local lua = ([[
+ |nomsu:defmacro("rule %signature = %body", (function(nomsu, vars)
+ | local signature = nomsu:typecheck(vars, "signature", "List").value;
+ | local body = nomsu:typecheck(vars, "body", "Thunk");
+ | return ([[
|nomsu:def(%s, %s, %s)
- |]]):format(nomsu:repr(canonical.src), thunk, nomsu:repr(body.src))
- | if #aliases > 1 then
- | lua = lua .. "\n" .. ([[
- |do
- | local aliased = %s
- | local src = %s
- | local function dealiaser(nomsu, vars)
- | return nomsu:tree_to_lua(nomsu:replaced_vars(aliased, vars))
- | end
- |]]):format(nomsu:repr(canonical), nomsu:repr(canonical.src))
- | for i=2,#aliases do
- | lua = lua .. ([[
- | nomsu:defmacro(%s, dealiaser, %s)
- |]]):format(nomsu:repr(aliases[i].src), nomsu:repr(canonical.src))
- | end
- | lua = lua .. [[
- |end]]
- | end
- | return nil, lua
- |end, "<source can be found in lib/metaprogramming.nom>")
+ |]]):format(nomsu:repr(signature), nomsu:tree_to_lua(body), nomsu:repr(body.src)), nil;
+ |end), "<source can be found in lib/metaprogramming.nom>");
# Rule to make nomsu macros:
-rule (escaped parse %shorthand as %longhand) =:
+rule [escaped parse %shorthand as %longhand] =:
lua code ".."
- |local aliases = nomsu:typecheck(vars, "shorthand", "Block").value
- |local template = nomsu:typecheck(vars, "longhand", "Block")
+ |local aliases = nomsu:typecheck(vars, "shorthand", "List").value;
+ |if #vars.longhand.value ~= 1 then;
+ | nomsu:error("Expected only 1 line to parse to, but got "..tostring(#vars.longhand.value));
+ |end;
+ |local template = nomsu:typecheck(vars, "longhand", "Thunk").value[1];
|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
+ | local replacement = nomsu:replaced_vars(template, vars);
+ | return nomsu:tree_to_lua(replacement);
+ |end;
+ |nomsu:defmacro(aliases, parsing_as, template.src);
+escaped parse \[parse %shorthand as %longhand] as \: escaped parse \%shorthand as \%longhand
# Rule to make lua macros:
-rule (escaped compile %macro_def to %body) =:
+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) =:
+ |local aliases = nomsu:typecheck(vars, "macro_def", "List").value;
+ |local body = nomsu:typecheck(vars, "body", "Thunk");
+ |local thunk = nomsu:tree_to_value(body);
+ |nomsu:defmacro(aliases, thunk, body.src);
+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
- | \(%body)
- |end
+ |local aliases = nomsu:typecheck(vars, "macro_def", "List").value;
+ |local body = nomsu:typecheck(vars, "body", "Thunk");
+ |local thunk = nomsu:tree_to_value(body);
+ |local thunk_wrapper = function(nomsu, vars) return nil, thunk(nomsu, vars); end;
+ |nomsu:defmacro(aliases, thunk_wrapper, body.src);
+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
-rule (do %) =: %
+rule [do %] =: %
-rule (%tree as lua) =:
+rule [%tree as lua] =:
lua expr "nomsu:tree_to_lua(\(%tree))"
-rule (%tree as value) =:
+rule [%tree as value] =:
lua expr "nomsu:tree_to_value(\(%tree), vars)"
-compile (repr %obj) to:
+compile [repr %obj] to:
"nomsu:repr(\(%obj as lua))"
-parse (lua block %block) as: lua code ".."
- |do
+parse [lua block %block] as: lua code ".."
+ |do;
| \(%block)
- |end
-rule (%tree as lua statement) =:
+ |end;
+rule [%tree as lua statement] =:
lua block ".."
- |local _,statement = nomsu:tree_to_lua(\(%tree))
- |return statement
-rule (%tree as lua statements) =:
+ |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
+ |local lua_bits = {};
+ |local statements = nomsu:typecheck(vars, "tree", "Thunk").value;
+ |for _,bit in ipairs(statements) do;
+ | local expr, statement = nomsu:tree_to_lua(bit);
+ | if statement then; table.insert(lua_bits, statement); end;
+ | if expr then; table.insert(lua_bits, "ret = "..expr..";"); end;
+ |end;
+ |return table.concat(lua_bits, "\\n");
-compile (nomsu) to: "nomsu"
-compile (nomsu's %key) to: "nomsu[\(%key as lua)]"
-compile (nomsu %method %args) to: "nomsu[\(%method as lua)](nomsu, unpack(\(%args as lua)))"
+compile [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) =:
+rule [help %rule] =:
lua block ".."
- |local fn_def = nomsu:get_fn_def(vars.rule)
- |if not fn_def then
- | nomsu:writeln("Rule not found: "..nomsu:repr(vars.rule))
- |else
- | nomsu:writeln("rule "..nomsu:repr(nomsu.utils.keys(fn_def.invocation))
- | .." ="..(fn_def.src or ":\\n <unknown source code>"))
- |end
+ |local fn_def = nomsu:get_fn_def(vars.rule);
+ |if not fn_def then;
+ | nomsu:writeln("Rule not found: "..nomsu:repr(vars.rule));
+ |else;
+ | nomsu:writeln("rule "..nomsu:repr(nomsu.utils.keys(fn_def.stub))
+ | .." ="..(fn_def.src or ":\\n <unknown source code>"));
+ |end;
# Compiler tools
-parse (eval %code; run %code) as: nomsu "run" [%code]
-rule (source code from tree %tree) =:
+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")
- |if leading_space then
- | local chunk1, chunk2 = vars.tree.src:match(":%s*([^\\n]*)(\\n.*)")
- | chunk2 = chunk2:gsub("\\n"..leading_space, "\\n")
- | return chunk1..chunk2.."\\n"
- |else
- | return vars.tree.src:match(":%s*(%S.*)").."\\n"
- |end
-parse (source code %body) as: source code from tree \%body
+ |local _,_,leading_space = vars.tree.src:find("\\n(%s*)%S");
+ |if leading_space then;
+ | local chunk1, chunk2 = vars.tree.src:match(":%s*([^\\n]*)(\\n.*)");
+ | chunk2 = chunk2:gsub("\\n"..leading_space, "\\n");
+ | return chunk1..chunk2.."\\n";
+ |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: nomsu "tree_to_str" [\%code]
+parse [parse tree %code] as: nomsu "tree_to_str" [\%code]
-parse (enable debugging) as: lua code "nomsu.debug = true"
-parse (disable debugging) as: lua code "nomsu.debug = false"
+parse [enable debugging] as: lua code "nomsu.debug = true"
+parse [disable debugging] as: lua code "nomsu.debug = false"
diff --git a/lib/moonscript.nom b/lib/moonscript.nom
index f5a18b5..9aa9575 100644
--- a/lib/moonscript.nom
+++ b/lib/moonscript.nom
@@ -1,30 +1,30 @@
require "lib/metaprogramming.nom"
# Moonscript!
-macro block [moonscript block %moonscript_code] =:
+parse [moonscript block %moonscript_code] as:
lua block ".."
- |local parse, compile = require('moonscript.parse'), require('moonscript.compile')
- |local moon_code = nomsu:tree_to_value(vars.moonscript_code, vars)
- |local tree, err = parse.string(moon_code)
- |if not tree then
- | nomsu:error("Failed to parse moonscript: "..err)
- |end
- |local lua_code, err, pos = compile.tree(tree)
- |if not lua_code then
- | nomsu:error(compile.format_error(err, pos, moon_code))
- |end
- |return "do\\n"..lua_code.."\\nend"
+ |local parse, compile = require('moonscript.parse'), require('moonscript.compile');
+ |local moon_code = nomsu:tree_to_value(vars.moonscript_code, vars);
+ |local tree, err = parse.string(moon_code);
+ |if not tree then;
+ | nomsu:error("Failed to parse moonscript: "..err);
+ |end;
+ |local lua_code, err, pos = compile.tree(tree);
+ |if not lua_code then;
+ | nomsu:error(compile.format_error(err, pos, moon_code));
+ |end;
+ |return "do\\n"..lua_code.."\\nend";
-macro [moonscript %moonscript_code] =:
+parse [moonscript %moonscript_code] as:
lua block ".."
- |local parse, compile = require('moonscript.parse'), require('moonscript.compile')
- |local moon_code = nomsu:tree_to_value(vars.moonscript_code, vars)
- |local tree, err = parse.string(moon_code)
- |if not tree then
- | nomsu:error("Failed to parse moonscript: "..err)
- |end
- |local lua_code, err, pos = compile.tree(tree)
- |if not lua_code then
- | nomsu:error(compile.format_error(err, pos, moon_code))
- |end
- |return "(function(nomsu, vars)\\n"..lua_code.."\\nend)(nomsu, vars)"
+ |local parse, compile = require('moonscript.parse'), require('moonscript.compile');
+ |local moon_code = nomsu:tree_to_value(vars.moonscript_code, vars);
+ |local tree, err = parse.string(moon_code);
+ |if not tree then;
+ | nomsu:error("Failed to parse moonscript: "..err);
+ |end;
+ |local lua_code, err, pos = compile.tree(tree);
+ |if not lua_code then;
+ | nomsu:error(compile.format_error(err, pos, moon_code));
+ |end;
+ |return "(function(nomsu, vars)\\n"..lua_code.."\\nend)(nomsu, vars)";
diff --git a/lib/operators.nom b/lib/operators.nom
index 7a926f3..c15298f 100644
--- a/lib/operators.nom
+++ b/lib/operators.nom
@@ -1,124 +1,122 @@
require "lib/metaprogramming.nom"
# Literals
-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: ""
+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
-compile (%if_expr if %condition else %else_expr) to: ".."
+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)
because that breaks if %if_expr is falsey.
- | if \(%condition) then
- | return \(%if_expr)
- | else
- | return \(%else_expr)
- | end
+ | if \(%condition) then;
+ | return \(%if_expr);
+ | else;
+ | return \(%else_expr);
+ | end;
|end)(nomsu, vars)
# Indexing:
-compile (%obj's %key; %obj -> %key) to: "\(%obj as lua)[\(%key as lua)]"
+compile [%obj's %key, %obj -> %key] to: "(\(%obj as lua))[\(%key as lua)]"
# Variable assignment operator, and += type versions
-compile (%var = %val) to code: "\(%var as lua) = \(%val as lua)"
-compile (%var += %val) to code: "\(%var as lua) = \(%var as lua) + \(%val as lua)"
-compile (%var -= %val) to code: "\(%var as lua) = \(%var as lua) - \(%val as lua)"
-compile (%var *= %val) to code: "\(%var as lua) = \(%var as lua) * \(%val as lua)"
-compile (%var /= %val) to code: "\(%var as lua) = \(%var as lua) / \(%val as lua)"
-compile (%var ^= %val) to code: "\(%var as lua) = \(%var as lua) ^ \(%val as lua)"
-compile (%var 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
+compile [%var = %val] to code: "\(%var as lua) = \(%val as lua);"
+compile [%var += %val] to code: "\(%var as lua) = \(%var as lua) + \(%val as lua);"
+compile [%var -= %val] to code: "\(%var as lua) = \(%var as lua) - \(%val as lua);"
+compile [%var *= %val] to code: "\(%var as lua) = \(%var as lua) * \(%val as lua);"
+compile [%var /= %val] to code: "\(%var as lua) = \(%var as lua) / \(%val as lua);"
+compile [%var ^= %val] to code: "\(%var as lua) = \(%var as lua) ^ \(%val as lua);"
+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);"
# Binary Operators
lua block ".."
- |local binops = {"-","/","<","<=",">",">=","^",{"===","=="},{"!==","~="},{"mod","%"}}
- |for _,op in ipairs(binops) do
- | local nomsu_alias = op
- | if type(op) == 'table' then
- | nomsu_alias, op = unpack(op)
- | end
+ |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(vars.a).." "..op.." "..nomsu:tree_to_lua(vars.b)..")"
- | end), [["(\\(%a) ]]..op..[[ \\(%b))"]])
- |end
+ | 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))"
+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
-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)))"
+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 block ".."
- |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)
+ |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
+ | 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 block ".."
- |local max_operands = 3
- |for _,chainers in ipairs({{"<","<="},{">",">="}}) 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
+ | 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[i], vars[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
+ | for i,op in ipairs(chain) do;
+ | local a, b, result = vars[i], vars[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
+ | 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;
# Unary operators
-compile (- %) to: "-(\(% as lua))"
-compile (not %) to: "not (\(% as lua))"
+compile [- %] to: "-(\(% as lua))"
+compile [not %] to: "not (\(% as lua))"
diff --git a/lib/permissions.nom b/lib/permissions.nom
index a65fb67..a2fffff 100644
--- a/lib/permissions.nom
+++ b/lib/permissions.nom
@@ -4,44 +4,44 @@ require "lib/operators.nom"
require "lib/collections.nom"
# Permission functions
-rule (standardize rules %rules) =:
+rule [standardize rules %rules] =:
if (lua expr "type(vars.rules) == 'string'"): %rules = [%rules]
(nomsu "get_stub" [%]) for all %rules
-rule (restrict %rules to within %elite-rules) =:
- %rules =: standardize rules %rules
- %elite-rules =: standardize rules %elite-rules
+rule [restrict %rules to within %elite-rules] =:
+ %rules = (standardize rules %rules)
+ %elite-rules = (standardize rules %elite-rules)
say "Restricting \(%rules) to within \(%elite-rules)"
for all (flatten [%elite-rules, %rules]):
assert ((nomsu's "defs") has key %) "Undefined function: \(%)"
for %rule in %rules:
assert (nomsu "check_permission" [%]) ".."
|You do not have permission to restrict permissions for function: \(%)
- ((nomsu) ->* ["defs",%rule,"whiteset"]) =:
+ ((nomsu) ->* ["defs",%rule,"whiteset"]) = (..)
dict: [%, yes] for all %elite-rules
-rule (allow %elite-rules to use %rules) =:
- %rules =: standardize rules %rules
- %elite-rules =: standardize rules %elite-rules
+rule [allow %elite-rules to use %rules] =:
+ %rules = (standardize rules %rules)
+ %elite-rules = (standardize rules %elite-rules)
say "Allowing \(%elite-rules) to use \(%rules)"
for all (flatten [%elite-rules, %rules]):
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"]
+ %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) =:
- %rules =: standardize rules %rules
- %pleb-rules =: standardize rules %pleb-rules
+rule [forbid %pleb-rules to use %rules] =:
+ %rules = (standardize rules %rules)
+ %pleb-rules = (standardize rules %pleb-rules)
say "Forbidding \(%pleb-rules) to use \(%rules)"
for all (flatten [%pleb-rules, %used]):
assert ((nomsu's "defs") has key %) "Undefined function: \(%)"
for all %rules:
assert (nomsu "check_permission" [%]) ".."
|You do not have permission to grant permissions for function: \(%)
- %whiteset =: (nomsu) ->* ["defs",%,"whiteset"]
+ %whiteset = ((nomsu) ->* ["defs",%,"whiteset"])
assert %whiteset ".."
|Cannot individually restrict permissions for \(%) because it is currently
|available to everyone. Perhaps you meant to use "restrict % to within %" instead?
diff --git a/lib/plurals.nom b/lib/plurals.nom
index d0cbcf0..347c2e7 100644
--- a/lib/plurals.nom
+++ b/lib/plurals.nom
@@ -4,32 +4,32 @@ require "lib/secrets.nom"
# Plurals
with secrets:
lua block ".."
- |local endings = setmetatable({x="es",c="es",s="es"}, {__index=function() return "s" end})
+ |local endings = setmetatable({x="es",c="es",s="es"}, {__index=function() return "s"; end});
|secrets.plurals = setmetatable({}, {__index=function(self,key)
- | return key..endings[key:sub(-1)]
- |end})
+ | return key..endings[key:sub(-1)];
+ |end});
|secrets.singulars = setmetatable({}, {__index=function(self,key)
- | if key:sub(-2) == "es" and rawget(endings, key:sub(-3,-3)) then return key:sub(1,-3) end
- | if key:sub(-1) == "s" then return key:sub(1,-2) end
- | return key
- |end})
+ | if key:sub(-2) == "es" and rawget(endings, key:sub(-3,-3)) then; return key:sub(1,-3); end;
+ | if key:sub(-1) == "s" then; return key:sub(1,-2); end;
+ | return key;
+ |end});
|secrets.canonicals = setmetatable({}, {__index=function(self,key)
- | if key:sub(-1) == "s" then return secrets.singulars[key] end
- | return key
- |end})
+ | if key:sub(-1) == "s" then; return secrets.singulars[key]; end;
+ | return key;
+ |end});
- rule (the plural of %singular is %plural) =:
- (secret %plurals)->%singular =: %plural
- (secret %singulars)->%plural =: %singular
- (secret %canonicals)->%plural =: %singular
+ rule [the plural of %singular is %plural] =:
+ (secret %plurals)->%singular = %plural
+ (secret %singulars)->%plural = %singular
+ (secret %canonicals)->%plural = %singular
- rule (singular %plural) =:
+ rule [singular %plural] =:
%plural in (secret %singulars)
- rule (plural %singular) =:
+ rule [plural %singular] =:
%singular in (secret %plurals)
- rule (canonicalize %item-name) =:
+ rule [canonicalize %item-name] =:
%item-name in (secret %canonicals)
- rule (rules that change plurals) =: ["the plural of % is %"]
+ rule [rules that change plurals] =: ["the plural of % is %"]
diff --git a/lib/secrets.nom b/lib/secrets.nom
index d63ec8c..4c3dca6 100644
--- a/lib/secrets.nom
+++ b/lib/secrets.nom
@@ -1,20 +1,22 @@
require "lib/core.nom"
-compile (with secrets %block) to block: ".."
- |local secrets = {}
- |\(%block as lua statements)
+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 [secrets] to: "secrets"
-compile (secret %key; secret value of %key; secret value for %key) to:
+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:
+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 %"]
+rule [rules about secrecy] =: ["with secrets %"]
diff --git a/lib/testing.nom b/lib/testing.nom
index 83d0108..336be38 100644
--- a/lib/testing.nom
+++ b/lib/testing.nom
@@ -1,83 +1,13 @@
require "lib/metaprogramming.nom"
# For unit testing
-macro block [test %code yields %expected] =:
-
-
- _yield_tree: (tree, indent_level=0)=>
- ind = (s) -> INDENT\rep(indent_level)..s
- switch tree.type
- when "File"
- coroutine.yield(ind"File:")
- @_yield_tree(tree.value.body, indent_level+1)
- when "Errors" then coroutine.yield(ind"Error:\n#{tree.value}")
- when "Block"
- for chunk in *tree.value
- @_yield_tree(chunk, indent_level)
- when "Thunk"
- coroutine.yield(ind"Thunk:")
- @_yield_tree(tree.value, indent_level+1)
- when "Statement" then @_yield_tree(tree.value, indent_level)
- when "FunctionCall"
- alias = @get_alias tree
- args = [a for a in *tree.value when a.type != "Word"]
- if #args == 0
- coroutine.yield(ind"Call [#{alias}]!")
- else
- coroutine.yield(ind"Call [#{alias}]:")
- for a in *args
- @_yield_tree(a, indent_level+1)
- when "String" then coroutine.yield(ind(repr(tree.value)))
- when "Longstring" then coroutine.yield(ind(repr(tree.value)))
- when "Number" then coroutine.yield(ind(tree.value))
- when "Var" then coroutine.yield ind"Var[#{repr(tree.value)}]"
- when "List"
- if #tree.value == 0
- coroutine.yield(ind("<Empty List>"))
- else
- coroutine.yield(ind"List:")
- for item in *tree.value
- @_yield_tree(item, indent_level+1)
- else error("Unknown/unimplemented thingy: #{tree.type}")
-
- print_tree:(tree)=>
- for line in coroutine.wrap(-> @_yield_tree(tree))
- @writeln(line)
-
- stringify_tree:(tree)=>
- result = {}
- for line in coroutine.wrap(-> @_yield_tree(tree))
- insert(result, line)
- return concat result, "\n"
-
- test: (src, filename, expected)=>
- i = 1
- while i != nil
- start,stop = src\find("\n\n", i)
-
- test = src\sub(i,start)
- i = stop
- start,stop = test\find"==="
- if not start or not stop then
- @error("WHERE'S THE ===? in:\n#{test}")
- test_src, expected = test\sub(1,start-1), test\sub(stop+1,-1)
- expected = expected\match'[\n]*(.*[^\n])'
- tree = @parse(test_src, filename)
- got = @stringify_tree(tree.value.body)
- if got != expected
- @error"TEST FAILED!\nSource:\n#{test_src}\nExpected:\n#{expected}\n\nGot:\n#{got}"
-
-
-
-
-
- %generated =: repr (nomsu "stringify_tree" [%code's "value"])
- %expected =: %expected as lua
+rule [test tree %generated == %expected] =:
if (%generated != %expected):
- say "Test failed!"
- say "Expected:"
- say %expected
- say "But got:"
- say %generated
- error!
- return ""
+ error ".."
+ |Test Failed!
+ |Expected:
+ |\(%expected)
+ |But got:
+ |\(%generated)
+parse [test %code yields %expected] as:
+ test tree (nomsu "tree_to_str" [\%code]) == %expected
diff --git a/lib/utils.nom b/lib/utils.nom
index 8f9cf1a..02d3732 100644
--- a/lib/utils.nom
+++ b/lib/utils.nom
@@ -1,83 +1,83 @@
require "lib/metaprogramming.nom"
# Error functions
-rule (error!; panic!; fail!; abort!) =:
+rule [error!, panic!, fail!, abort!] =:
nomsu "error" []
-rule (error %msg) =:
+rule [error %msg] =:
nomsu "error"[%msg]
-compile (assert %condition %msg) to code: ".."
+compile [assert %condition %msg] to code: ".."
|if not (\(%condition as lua)) then
| nomsu:error(\(%msg as lua))
|end
-parse (assert %condition) as: assert %condition (nil)
+parse [assert %condition] as: assert %condition (nil)
# String functions
-rule (join %strs with glue %glue) =:
+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 [join %strs] as: join %strs with glue ""
-compile (capitalize %str; %str capitalized) to:
+compile [capitalize %str, %str capitalized] to:
"(\(%str as lua)):gsub('%l', string.upper, 1)"
-compile (say %str) to: ".."
+compile [say %str] to: ".."
|nomsu:writeln(\(%str as lua))
# Number ranges
-compile (%start to %stop by %step; %start to %stop via %step) to: ".."
+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
+parse [%start to %stop] as: %start to %stop by 1
# 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:
+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) =:
+rule [random choice from %elements, random choice %elements, random %elements] =:
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) =:
+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) =:
+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(\(%items))/#\(%items))"
-compile (min of %items; smallest of %items; lowest of %items) to:
+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:
+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:
+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:
+compile [max of %items by %value_expr] to:
".."
|nomsu.utils.max(\(%items as lua), function(item)
| local vars = setmetatable({['']=item}, {__index=vars})
diff --git a/nomsu.moon b/nomsu.moon
index 80d000a..7f75496 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -50,7 +50,7 @@ check_nodent = (subject,end_pos,spaces)->
return end_pos
-- TYPES:
--- Number 1, "String", %Var, [List], (Block), \(Nomsu), FunctionCall, File
+-- Number 1, "String", %Var, [List], (expression), {Thunk}, \Nomsu, FunctionCall, File
nomsu = [=[
file <- ({ {| shebang?
@@ -69,20 +69,25 @@ nomsu = [=[
noeol_statement <- noeol_functioncall / noeol_expression
inline_statement <- inline_functioncall / inline_expression
- inline_block <- ({ {| "(" inline_statements ")" |} }) -> Block
- eol_block <- ({ {| ":" %ws? noeol_statements eol |} }) -> Block
- indented_block <- ({ {| (":" / "(..)") indent
+ inline_thunk <- ({ {| "{" inline_statements "}" |} }) -> Thunk
+ eol_thunk <- ({ {| ":" %ws? noeol_statements eol |} }) -> Thunk
+ indented_thunk <- ({ {| (":" / "{..}") indent
statements (nodent statements)*
- (dedent / (({.+} ("" -> "Error while parsing block")) => error))
- |} }) -> Block
+ (dedent / (({.+} ("" -> "Error while parsing thunk")) => error))
+ |} }) -> Thunk
inline_nomsu <- ({ ("\" inline_expression) }) -> Nomsu
eol_nomsu <- ({ ("\" noeol_expression) }) -> Nomsu
indented_nomsu <- ({ ("\" expression) }) -> Nomsu
- inline_expression <- number / variable / inline_string / inline_list / inline_block / inline_nomsu
- noeol_expression <- indented_string / indented_block / indented_nomsu / indented_list / inline_expression
- expression <- eol_block / eol_nomsu / noeol_expression
+ inline_expression <- number / variable / inline_string / inline_list / inline_nomsu
+ / inline_thunk / ("(" inline_statement ")")
+ noeol_expression <- indented_string / indented_nomsu / indented_list / indented_thunk
+ / ("(..)" indent
+ statement
+ (dedent / (({.+} ("" -> "Error while parsing indented expression"))))
+ ) / inline_expression
+ expression <- eol_thunk / eol_nomsu / noeol_expression
-- Function calls need at least one word in them
inline_functioncall <- ({ {|
@@ -107,7 +112,7 @@ nomsu = [=[
|} (dedent / (({.+} ("" -> "Error while parsing String")) => error))
}) -> String
indented_string_line <- "|" ({~ (("\\" -> "\") / (!string_interpolation [^%nl]))+ ~} / string_interpolation)*
- string_interpolation <- "\" (inline_block / indented_block / dotdot)
+ string_interpolation <- "\" ((noeol_expression dotdot?) / dotdot)
number <- ({ (("-"? (([0-9]+ "." [0-9]+) / ("." [0-9]+) / ([0-9]+)))-> tonumber) }) -> Number
@@ -189,16 +194,21 @@ class NomsuCompiler
@write(...)
@write("\n")
- def: (invocation, thunk, src)=>
- stub, arg_names = @get_stub invocation
- assert stub, "NO STUB FOUND: #{repr invocation}"
- if @debug then @writeln "#{colored.bright "DEFINING RULE:"} #{colored.underscore colored.magenta repr(stub)} #{colored.bright "WITH ARGS"} #{colored.dim repr(arg_names)}"
- for i=1,#arg_names-1 do for j=i+1,#arg_names
- if arg_names[i] == arg_names[j] then @error "Duplicate argument in function #{stub}: '#{arg_names[i]}'"
- with @defs[stub] = {:thunk, :invocation, :arg_names, :src, is_macro:false} do nil
-
- defmacro: (invocation, thunk, src)=>
- with @def(invocation, thunk, src) do .is_macro = true
+ def: (signature, thunk, src, is_macro=false)=>
+ assert type(thunk) == 'function', "Bad thunk: #{repr thunk}"
+ canonical_args = nil
+ for {stub, arg_names} in *@get_stubs(signature)
+ assert stub, "NO STUB FOUND: #{repr signature}"
+ if @debug then @writeln "#{colored.bright "DEFINING RULE:"} #{colored.underscore colored.magenta repr(stub)} #{colored.bright "WITH ARGS"} #{colored.dim repr(arg_names)}"
+ for i=1,#arg_names-1 do for j=i+1,#arg_names
+ if arg_names[i] == arg_names[j] then @error "Duplicate argument in function #{stub}: '#{arg_names[i]}'"
+ if canonical_args
+ assert utils.equivalent(utils.set(arg_names), canonical_args), "Mismatched args"
+ else canonical_args = utils.set(arg_names)
+ @defs[stub] = {:thunk, :stub, :arg_names, :src, :is_macro}
+
+ defmacro: (signature, thunk, src)=>
+ @def(signature, thunk, src, true)
call: (stub,...)=>
def = @defs[stub]
@@ -279,31 +289,37 @@ class NomsuCompiler
code_for_statement = ([[
return (function(nomsu, vars)
%s
- return %s
- end)]])\format(statements or "", expr or "")
+ return %s;
+ end);]])\format(statements or "", expr or "ret")
if @debug
@writeln "#{colored.bright "RUNNING LUA:"}\n#{colored.blue colored.bright(code_for_statement)}"
lua_thunk, err = load(code_for_statement)
if not lua_thunk
- error("Failed to compile generated code:\n#{colored.bright colored.blue code_for_statement}\n\n#{err}\n\nProduced by statement:\n#{colored.bright colored.yellow statement.src}")
+ n = 1
+ fn = ->
+ n = n + 1
+ ("\n%-3d|")\format(n)
+ code = "1 |"..code_for_statement\gsub("\n", fn)
+ error("Failed to compile generated code:\n#{colored.bright colored.blue code}\n\n#{err}\n\nProduced by statement:\n#{colored.bright colored.yellow statement.src}")
run_statement = lua_thunk!
ok,ret = pcall(run_statement, self, vars)
if expr then return_value = ret
if not ok
@writeln "#{colored.red "Error occurred in statement:"}\n#{colored.yellow statement.src}"
- @error(repr return_value)
+ @writeln debug.traceback!
+ @error(ret)
insert buffer, "#{statements or ''}\n#{expr and "ret = #{expr}" or ''}"
lua_code = ([[
- return function(nomsu, vars)
- local ret
+ return (function(nomsu, vars)
+ local ret;
%s
- return ret
- end]])\format(concat(buffer, "\n"))
+ return ret;
+ end);]])\format(concat(buffer, "\n"))
return return_value, lua_code
tree_to_value: (tree, vars)=>
- code = "return (function(nomsu, vars)\nreturn #{@tree_to_lua(tree)}\nend)"
+ code = "return (function(nomsu, vars)\nreturn #{@tree_to_lua(tree)};\nend);"
if @debug
@writeln "#{colored.bright "RUNNING LUA TO GET VALUE:"}\n#{colored.blue colored.bright(code)}"
lua_thunk, err = load(code)
@@ -324,32 +340,18 @@ class NomsuCompiler
when "Nomsu"
return repr(tree.value), nil
- when "Thunk" -- This is not created by the parser, it's just a helper
- _,body = @tree_to_lua tree.value
- return ([[
- (function(nomsu, vars)
- local ret
- %s
- return ret
- end)]])\format(body), nil
-
- when "Block"
- if #tree.value == 0
- return "nil",nil
- if #tree.value == 1
- expr,statement = @tree_to_lua tree.value[1]
- if not statement
- return expr, nil
- thunk_lua = @tree_to_lua {type:"Thunk", value:{type:"Statements", value:tree.value, src:tree.src}, src:tree.src}
- return ("%s(nomsu, vars)")\format(thunk_lua), nil
-
- when "Statements"
+ when "Thunk"
lua_bits = {}
for arg in *tree.value
expr,statement = @tree_to_lua arg
if statement then insert lua_bits, statement
- if expr then insert lua_bits, "ret = #{expr}"
- return nil, concat(lua_bits, "\n")
+ if expr then insert lua_bits, "ret = #{expr};"
+ return ([[
+ (function(nomsu, vars)
+ local ret;
+ %s
+ return ret;
+ end)]])\format(concat(lua_bits, "\n"))
when "FunctionCall"
stub = @get_stub(tree)
@@ -418,7 +420,7 @@ class NomsuCompiler
if type(tree) != 'table' or not tree.type
return
switch tree.type
- when "List", "File", "Block", "FunctionCall", "String"
+ when "List", "File", "Thunk", "FunctionCall", "String"
for v in *tree.value
@walk_tree(v, depth+1)
else @walk_tree(tree.value, depth+1)
@@ -465,7 +467,7 @@ class NomsuCompiler
when "Var"
if vars[tree.value] ~= nil
tree = vars[tree.value]
- when "File", "Nomsu", "Thunk", "Block", "List", "FunctionCall", "String"
+ when "File", "Nomsu", "Thunk", "List", "FunctionCall", "String"
new_value = @replaced_vars tree.value, vars
if new_value != tree.value
tree = {k,v for k,v in pairs(tree)}
@@ -506,9 +508,16 @@ class NomsuCompiler
arg_names = nil
insert args, token
return concat(stub," "), arg_names, args
- when "Block"
- @writeln debug.traceback!
- @error "Please pass in a single line from a block, not the whole thing:\n#{@tree_to_str x}"
+ else @error "Unsupported get stub type: #{x.type}"
+
+ get_stubs: (x)=>
+ if type(x) != 'table' then return {{@get_stub(x)}}
+ switch x.type
+ when nil
+ return [{@get_stub(i)} for i in *x]
+ when "List"
+ return [{@get_stub(i)} for i in *x.value]
+ return {{@get_stub(x)}}
var_to_lua_identifier: (var)=>
-- Converts arbitrary nomsu vars to valid lua identifiers by replacing illegal
@@ -584,12 +593,12 @@ if arg and arg[1]
io.output()
else io.open(arg[2], 'w')
output\write ([[
- local NomsuCompiler = require('nomsu')
- local c = NomsuCompiler()
- local run = function(nomsu, vars)
+ local NomsuCompiler = require('nomsu');
+ local c = NomsuCompiler();
+ local run = (function(nomsu, vars)
%s
- end
- return run(c, {})
+ end);
+ return run(c, {});
]])\format(code)
--ProFi\stop()
--ProFi\writeReport( 'MyProfilingReport.txt' )