aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2017-09-28 17:49:15 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2017-09-28 17:49:15 -0700
commitac25e20b9f94505175841d9a8da7253f8996926d (patch)
tree965a766f89b826f80a61569e1c7084e5e669558a
parent10d61df78bdbf002a3701e468b0a3c88be2cad03 (diff)
Kinda mostly working, except for closure vars like in lib/secrets.nom.
-rw-r--r--lib/collections.nom163
-rw-r--r--lib/control_flow.nom143
-rw-r--r--lib/metaprogramming.nom153
-rw-r--r--lib/operators.nom89
-rw-r--r--lib/permissions.nom53
-rw-r--r--lib/secrets.nom49
-rw-r--r--lib/utils.nom108
-rw-r--r--nomsu.lua142
-rwxr-xr-xnomsu.moon102
9 files changed, 529 insertions, 473 deletions
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)
+
diff --git a/nomsu.lua b/nomsu.lua
index 8bfb83e..549e4f7 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -2,6 +2,14 @@ local re = require('re')
local lpeg = require('lpeg')
local utils = require('utils')
local repr = utils.repr
+local colors = require('ansicolors')
+local colored = setmetatable({ }, {
+ __index = function(_, color)
+ return (function(msg)
+ return colors[color] .. msg .. colors.reset
+ end)
+ end
+})
local insert, remove, concat
do
local _obj_0 = table
@@ -191,7 +199,7 @@ do
local stub, arg_names = self:get_stub(invocation)
assert(stub, "NO STUB FOUND: " .. tostring(repr(invocation)))
if self.debug then
- self:writeln("Defining rule: " .. tostring(repr(stub)) .. " with args " .. tostring(repr(arg_names)))
+ self:writeln(tostring(colored.bright("DEFINING RULE:")) .. " " .. tostring(colored.underscore(colored.magenta(repr(stub)))) .. " " .. tostring(colored.bright("WITH ARGS")) .. " " .. tostring(colored.dim(repr(arg_names))))
end
for i = 1, #arg_names - 1 do
for j = i + 1, #arg_names do
@@ -242,7 +250,8 @@ do
args = _tbl_0
end
if self.debug then
- self:writeln("Calling " .. tostring(repr(stub)) .. " with args: " .. tostring(repr(args)))
+ self:write(tostring(colored.bright("CALLING")) .. " " .. tostring(colored.magenta(colored.underscore(stub))) .. " ")
+ self:writeln(tostring(colored.bright("WITH ARGS:")) .. " " .. tostring(colored.dim(repr(args))))
end
insert(self.callstack, stub)
local rets = {
@@ -255,7 +264,11 @@ do
if kind == nil then
kind = "Expression"
end
- local stub, args = self:get_stub(tree)
+ local stub, arg_names, args = self:get_stub(tree)
+ if self.debug then
+ self:write(tostring(colored.bright("RUNNING MACRO")) .. " " .. tostring(colored.underscore(colored.magenta(stub))) .. " ")
+ self:writeln(tostring(colored.bright("WITH ARGS:")) .. " " .. tostring(colored.dim(repr(args))))
+ end
insert(self.callstack, "#macro")
local expr, statement = self:call(stub, unpack(args))
remove(self.callstack)
@@ -284,7 +297,7 @@ do
end,
parse = function(self, str, filename)
if self.debug then
- self:writeln("PARSING:\n" .. tostring(str))
+ self:writeln(tostring(colored.bright("PARSING:")) .. "\n" .. tostring(str))
end
str = str:gsub("\r", "")
local old_indent_stack
@@ -311,12 +324,13 @@ do
for _index_0 = 1, #_list_0 do
local statement = _list_0[_index_0]
if self.debug then
- self:writeln("RUNNING TREE:")
+ self:writeln(tostring(colored.bright("RUNNING NOMSU:")) .. "\n" .. tostring(colored.bright(colored.yellow(statement.src))))
+ self:writeln(colored.bright("PARSED TO TREE:"))
self:print_tree(statement)
end
local ok, expr, statements = pcall(self.tree_to_lua, self, statement)
if not ok then
- self:writeln("Error occurred in statement:\n" .. tostring(statement.src))
+ self:writeln(tostring(colored.red("Error occurred in statement:")) .. "\n" .. tostring(colored.bright(colored.yellow(statement.src))))
self:error(expr)
end
local code_for_statement = ([[ return (function(nomsu, vars)
@@ -324,11 +338,11 @@ do
return %s
end)]]):format(statements or "", expr or "")
if self.debug then
- self:writeln("RUNNING LUA:\n" .. tostring(code_for_statement))
+ self:writeln(tostring(colored.bright("RUNNING LUA:")) .. "\n" .. tostring(colored.blue(colored.bright(code_for_statement))))
end
local lua_thunk, err = load(code_for_statement)
if not lua_thunk then
- error("Failed to compile generated code:\n" .. tostring(code_for_statement) .. "\n\n" .. tostring(err) .. "\n\nProduced by statement:\n" .. tostring(statement.src))
+ error("Failed to compile generated code:\n" .. tostring(colored.bright(colored.blue(code_for_statement))) .. "\n\n" .. tostring(err) .. "\n\nProduced by statement:\n" .. tostring(colored.bright(colored.yellow(statement.src))))
end
local run_statement = lua_thunk()
local ret
@@ -337,7 +351,7 @@ do
return_value = ret
end
if not ok then
- self:writeln("Error occurred in statement:\n" .. tostring(statement.src))
+ self:writeln(tostring(colored.red("Error occurred in statement:")) .. "\n" .. tostring(colored.yellow(statement.src)))
self:error(repr(return_value))
end
insert(buffer, tostring(statements or '') .. "\n" .. tostring(expr and "ret = " .. tostring(expr) or ''))
@@ -350,10 +364,13 @@ do
return return_value, lua_code
end,
tree_to_value = function(self, tree, vars)
- local code = "\n return (function(nomsu, vars)\nreturn " .. tostring(self:tree_to_lua(tree)) .. "\nend)"
+ local code = "return (function(nomsu, vars)\nreturn " .. tostring(self:tree_to_lua(tree)) .. "\nend)"
+ if self.debug then
+ self:writeln(tostring(colored.bright("RUNNING LUA TO GET VALUE:")) .. "\n" .. tostring(colored.blue(colored.bright(code))))
+ end
local lua_thunk, err = load(code)
if not lua_thunk then
- error("Failed to compile generated code:\n" .. tostring(code) .. "\n\n" .. tostring(err))
+ self:error("Failed to compile generated code:\n" .. tostring(colored.bright(colored.blue(code))) .. "\n\n" .. tostring(colored.red(err)))
end
return (lua_thunk())(self, vars or { })
end,
@@ -369,23 +386,12 @@ do
elseif "Nomsu" == _exp_0 then
return repr(tree.value), nil
elseif "Thunk" == _exp_0 then
- local lua_bits = { }
- local _list_0 = tree.value.value
- for _index_0 = 1, #_list_0 do
- local arg = _list_0[_index_0]
- local expr, statement = self:tree_to_lua(arg)
- if statement then
- insert(lua_bits, statement)
- end
- if expr then
- insert(lua_bits, "ret = " .. tostring(expr))
- end
- end
+ local _, body = self:tree_to_lua(tree.value)
return ([[ (function(nomsu, vars)
local ret
%s
return ret
- end)]]):format(concat(lua_bits, "\n"))
+ end)]]):format(body), nil
elseif "Block" == _exp_0 then
if #tree.value == 0 then
return "nil", nil
@@ -398,10 +404,28 @@ do
end
local thunk_lua = self:tree_to_lua({
type = "Thunk",
- value = tree,
+ value = {
+ type = "Statements",
+ value = tree.value,
+ src = tree.src
+ },
src = tree.src
})
return ("%s(nomsu, vars)"):format(thunk_lua), nil
+ elseif "Statements" == _exp_0 then
+ local lua_bits = { }
+ local _list_0 = tree.value
+ for _index_0 = 1, #_list_0 do
+ local arg = _list_0[_index_0]
+ local expr, statement = self:tree_to_lua(arg)
+ if statement then
+ insert(lua_bits, statement)
+ end
+ if expr then
+ insert(lua_bits, "ret = " .. tostring(expr))
+ end
+ end
+ return nil, concat(lua_bits, "\n")
elseif "FunctionCall" == _exp_0 then
local stub = self:get_stub(tree)
if self.defs[stub] and self.defs[stub].is_macro then
@@ -432,6 +456,10 @@ do
end
return self.__class:comma_separated_items("nomsu:call(", args, ")"), nil
elseif "String" == _exp_0 then
+ if self.debug then
+ self:writeln((colored.bright("STRING:")))
+ self:print_tree(tree)
+ end
local concat_parts = { }
local string_buffer = ""
local _list_0 = tree.value
@@ -449,6 +477,11 @@ do
string_buffer = ""
end
local expr, statement = self:tree_to_lua(bit)
+ if self.debug then
+ self:writeln((colored.bright("INTERP:")))
+ self:print_tree(bit)
+ self:writeln(tostring(colored.bright("EXPR:")) .. " " .. tostring(expr) .. ", " .. tostring(colored.bright("STATEMENT:")) .. " " .. tostring(statement))
+ end
if statement then
self:error("Cannot use [[" .. tostring(bit.src) .. "]] as a string interpolation value, since it's not an expression.")
end
@@ -464,8 +497,11 @@ do
end
if #concat_parts == 0 then
return "''", nil
+ elseif #concat_parts == 1 then
+ return concat_parts[1], nil
+ else
+ return "(" .. tostring(concat(concat_parts, "..")) .. ")", nil
end
- return "(" .. tostring(concat(concat_parts, "..")) .. ")", nil
elseif "List" == _exp_0 then
local items = { }
local _list_0 = tree.value
@@ -479,9 +515,9 @@ do
end
return self.__class:comma_separated_items("{", items, "}"), nil
elseif "Number" == _exp_0 then
- return repr(tree.value)
+ return repr(tree.value), nil
elseif "Var" == _exp_0 then
- return "vars[" .. tostring(repr(tree.value)) .. "]"
+ return "vars[" .. tostring(repr(tree.value)) .. "]", nil
else
return self:error("Unknown/unimplemented thingy: " .. tostring(tree.type))
end
@@ -495,7 +531,7 @@ do
return
end
local _exp_0 = tree.type
- if "List" == _exp_0 or "File" == _exp_0 or "Nomsu" == _exp_0 or "Block" == _exp_0 or "FunctionCall" == _exp_0 or "String" == _exp_0 then
+ if "List" == _exp_0 or "File" == _exp_0 or "Block" == _exp_0 or "FunctionCall" == _exp_0 or "String" == _exp_0 then
local _list_0 = tree.value
for _index_0 = 1, #_list_0 do
local v = _list_0[_index_0]
@@ -507,6 +543,7 @@ do
return nil
end,
print_tree = function(self, tree)
+ self:write(colors.bright .. colors.green)
for node, depth in coroutine.wrap(function()
return self:walk_tree(tree)
end) do
@@ -516,6 +553,7 @@ do
self:writeln(tostring((" "):rep(depth)) .. tostring(node.type) .. ":")
end
end
+ return self:write(colors.reset)
end,
tree_to_str = function(self, tree)
local bits = { }
@@ -536,7 +574,7 @@ do
end
local _exp_0 = tree.type
if "Var" == _exp_0 then
- if vars[tree.value] then
+ if vars[tree.value] ~= nil then
tree = vars[tree.value]
end
elseif "File" == _exp_0 or "Nomsu" == _exp_0 or "Thunk" == _exp_0 or "Block" == _exp_0 or "List" == _exp_0 or "FunctionCall" == _exp_0 or "String" == _exp_0 then
@@ -570,7 +608,7 @@ do
end
if type(x) == 'string' then
local stub = x:gsub("'", " '"):gsub("%%%S+", "%%"):gsub("%s+", " ")
- local args
+ local arg_names
do
local _accum_0 = { }
local _len_0 = 1
@@ -578,15 +616,15 @@ do
_accum_0[_len_0] = arg
_len_0 = _len_0 + 1
end
- args = _accum_0
+ arg_names = _accum_0
end
- return stub, args
+ return stub, arg_names
end
local _exp_0 = x.type
if "String" == _exp_0 then
return self:get_stub(x.value)
elseif "FunctionCall" == _exp_0 then
- local stub, args = { }, { }, { }
+ local stub, arg_names, args = { }, { }, { }
local _list_0 = x.value
for _index_0 = 1, #_list_0 do
local token = _list_0[_index_0]
@@ -595,13 +633,17 @@ do
insert(stub, token.value)
elseif "Var" == _exp_1 then
insert(stub, "%")
- insert(args, token.value)
+ if arg_names then
+ insert(arg_names, token.value)
+ end
+ insert(args, token)
else
insert(stub, "%")
+ arg_names = nil
insert(args, token)
end
end
- return concat(stub, " "), args
+ return concat(stub, " "), arg_names, args
elseif "Block" == _exp_0 then
self:writeln(debug.traceback())
return self:error("Please pass in a single line from a block, not the whole thing:\n" .. tostring(self:tree_to_str(x)))
@@ -632,21 +674,39 @@ do
self.callstack = { }
return error()
end,
+ typecheck = function(self, vars, varname, desired_type)
+ local x = vars[varname]
+ if type(x) == desired_type then
+ return x
+ end
+ if type(x) == 'table' and x.type == desired_type then
+ return x
+ end
+ return self:error("Invalid type for %" .. tostring(varname) .. ". Expected " .. tostring(desired_type) .. ", but got " .. tostring(x.type) .. ".")
+ end,
initialize_core = function(self)
local lua_code
lua_code = function(self, vars)
- local inner_vars = vars
+ local inner_vars = setmetatable({ }, {
+ __index = function(_, key)
+ return "vars[" .. tostring(repr(key)) .. "]"
+ end
+ })
local lua = self:tree_to_value(vars.code, inner_vars)
return nil, lua
end
self:defmacro("lua code %code", lua_code)
local lua_value
lua_value = function(self, vars)
- local inner_vars = vars
+ local inner_vars = setmetatable({ }, {
+ __index = function(_, key)
+ return "vars[" .. tostring(repr(key)) .. "]"
+ end
+ })
local lua = self:tree_to_value(vars.code, inner_vars)
return lua, nil
end
- self:defmacro("lua value %code", lua_value)
+ self:defmacro("lua expr %code", lua_value)
local _require
_require = function(self, vars)
if not self.loaded_files[vars.filename] then
@@ -744,7 +804,9 @@ if arg and arg[1] then
end
output:write(([[ local NomsuCompiler = require('nomsu')
local c = NomsuCompiler()
- local run = %s
+ local run = function(nomsu, vars)
+ %s
+ end
return run(c, {})
]]):format(code))
end
diff --git a/nomsu.moon b/nomsu.moon
index 9ba3856..217d576 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -15,6 +15,8 @@ re = require 're'
lpeg = require 'lpeg'
utils = require 'utils'
repr = utils.repr
+colors = require 'ansicolors'
+colored = setmetatable({}, {__index:(_,color)-> ((msg)-> colors[color]..msg..colors.reset)})
{:insert, :remove, :concat} = table
--pcall = (fn,...)-> true, fn(...)
@@ -189,7 +191,7 @@ class NomsuCompiler
def: (invocation, thunk, src)=>
stub, arg_names = @get_stub invocation
assert stub, "NO STUB FOUND: #{repr invocation}"
- if @debug then @writeln "Defining rule: #{repr stub} with args #{repr arg_names}"
+ 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
@@ -210,7 +212,8 @@ class NomsuCompiler
{:thunk, :arg_names} = def
args = {name, select(i,...) for i,name in ipairs(arg_names)}
if @debug
- @writeln "Calling #{repr stub} with args: #{repr(args)}"
+ @write "#{colored.bright "CALLING"} #{colored.magenta(colored.underscore stub)} "
+ @writeln "#{colored.bright "WITH ARGS:"} #{colored.dim repr(args)}"
insert @callstack, stub
-- TODO: optimize, but still allow multiple return values?
rets = {thunk(self,args)}
@@ -218,7 +221,10 @@ class NomsuCompiler
return unpack(rets)
run_macro: (tree, kind="Expression")=>
- stub,args = @get_stub tree
+ stub,arg_names,args = @get_stub tree
+ if @debug
+ @write "#{colored.bright "RUNNING MACRO"} #{colored.underscore colored.magenta(stub)} "
+ @writeln "#{colored.bright "WITH ARGS:"} #{colored.dim repr args}"
insert @callstack, "#macro"
expr, statement = @call(stub, unpack(args))
remove @callstack
@@ -240,7 +246,7 @@ class NomsuCompiler
parse: (str, filename)=>
if @debug
- @writeln("PARSING:\n#{str}")
+ @writeln("#{colored.bright "PARSING:"}\n#{str}")
str = str\gsub("\r","")
export indent_stack
old_indent_stack, indent_stack = indent_stack, {0}
@@ -262,11 +268,12 @@ class NomsuCompiler
return_value = nil
for statement in *tree.value
if @debug
- @writeln "RUNNING TREE:"
+ @writeln "#{colored.bright "RUNNING NOMSU:"}\n#{colored.bright colored.yellow statement.src}"
+ @writeln colored.bright("PARSED TO TREE:")
@print_tree statement
ok,expr,statements = pcall(@tree_to_lua, self, statement)
if not ok
- @writeln "Error occurred in statement:\n#{statement.src}"
+ @writeln "#{colored.red "Error occurred in statement:"}\n#{colored.bright colored.yellow statement.src}"
@error(expr)
code_for_statement = ([[
return (function(nomsu, vars)
@@ -274,15 +281,15 @@ class NomsuCompiler
return %s
end)]])\format(statements or "", expr or "")
if @debug
- @writeln "RUNNING LUA:\n#{code_for_statement}"
+ @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#{code_for_statement}\n\n#{err}\n\nProduced by statement:\n#{statement.src}")
+ 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}")
run_statement = lua_thunk!
ok,ret = pcall(run_statement, self, vars)
if expr then return_value = ret
if not ok
- @writeln "Error occurred in statement:\n#{statement.src}"
+ @writeln "#{colored.red "Error occurred in statement:"}\n#{colored.yellow statement.src}"
@error(repr return_value)
insert buffer, "#{statements or ''}\n#{expr and "ret = #{expr}" or ''}"
@@ -295,11 +302,12 @@ class NomsuCompiler
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)
if not lua_thunk
- error("Failed to compile generated code:\n#{code}\n\n#{err}")
+ @error("Failed to compile generated code:\n#{colored.bright colored.blue code}\n\n#{colored.red err}")
return (lua_thunk!)(self, vars or {})
tree_to_lua: (tree)=>
@@ -316,17 +324,13 @@ class NomsuCompiler
return repr(tree.value), nil
when "Thunk" -- This is not created by the parser, it's just a helper
- lua_bits = {}
- for arg in *tree.value.value
- expr,statement = @tree_to_lua arg
- if statement then insert lua_bits, statement
- if expr then insert lua_bits, "ret = #{expr}"
+ _,body = @tree_to_lua tree.value
return ([[
(function(nomsu, vars)
local ret
%s
return ret
- end)]])\format(concat lua_bits, "\n")
+ end)]])\format(body), nil
when "Block"
if #tree.value == 0
@@ -335,9 +339,17 @@ class NomsuCompiler
expr,statement = @tree_to_lua tree.value[1]
if not statement
return expr, nil
- thunk_lua = @tree_to_lua {type:"Thunk", value:tree, src:tree.src}
+ 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"
+ 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")
+
when "FunctionCall"
stub = @get_stub(tree)
if @defs[stub] and @defs[stub].is_macro
@@ -352,6 +364,9 @@ class NomsuCompiler
return @@comma_separated_items("nomsu:call(", args, ")"), nil
when "String"
+ if @debug
+ @writeln (colored.bright "STRING:")
+ @print_tree tree
concat_parts = {}
string_buffer = ""
for bit in *tree.value
@@ -362,6 +377,10 @@ class NomsuCompiler
insert concat_parts, repr(string_buffer)
string_buffer = ""
expr, statement = @tree_to_lua bit
+ if @debug
+ @writeln (colored.bright "INTERP:")
+ @print_tree bit
+ @writeln "#{colored.bright "EXPR:"} #{expr}, #{colored.bright "STATEMENT:"} #{statement}"
if statement
@error "Cannot use [[#{bit.src}]] as a string interpolation value, since it's not an expression."
insert concat_parts, "nomsu.utils.repr_if_not_string(#{expr})"
@@ -371,7 +390,9 @@ class NomsuCompiler
if #concat_parts == 0
return "''", nil
- return "(#{concat(concat_parts, "..")})", nil
+ elseif #concat_parts == 1
+ return concat_parts[1], nil
+ else return "(#{concat(concat_parts, "..")})", nil
when "List"
items = {}
@@ -383,10 +404,10 @@ class NomsuCompiler
return @@comma_separated_items("{", items, "}"), nil
when "Number"
- return repr(tree.value)
+ return repr(tree.value), nil
when "Var"
- return "vars[#{repr tree.value}]"
+ return "vars[#{repr tree.value}]", nil
else
@error("Unknown/unimplemented thingy: #{tree.type}")
@@ -396,18 +417,20 @@ class NomsuCompiler
if type(tree) != 'table' or not tree.type
return
switch tree.type
- when "List", "File", "Nomsu", "Block", "FunctionCall", "String"
+ when "List", "File", "Block", "FunctionCall", "String"
for v in *tree.value
@walk_tree(v, depth+1)
else @walk_tree(tree.value, depth+1)
return nil
print_tree: (tree)=>
+ @write colors.bright..colors.green
for node,depth in coroutine.wrap(-> @walk_tree tree)
if type(node) != 'table' or not node.type
@writeln((" ")\rep(depth)..repr(node))
else
@writeln("#{(" ")\rep(depth)}#{node.type}:")
+ @write colors.reset
tree_to_str: (tree)=>
bits = {}
@@ -439,7 +462,7 @@ class NomsuCompiler
if type(tree) != 'table' then return tree
switch tree.type
when "Var"
- if vars[tree.value]
+ if vars[tree.value] ~= nil
tree = vars[tree.value]
when "File", "Nomsu", "Thunk", "Block", "List", "FunctionCall", "String"
new_value = @replaced_vars tree.value, vars
@@ -463,23 +486,25 @@ class NomsuCompiler
-- (e.g. "say %msg") or function call (e.g. FunctionCall({Word("say"), Var("msg")))
if type(x) == 'string'
stub = x\gsub("'"," '")\gsub("%%%S+","%%")\gsub("%s+"," ")
- args = [arg for arg in x\gmatch("%%([^%s']*)")]
- return stub, args
+ arg_names = [arg for arg in x\gmatch("%%([^%s']*)")]
+ return stub, arg_names
switch x.type
when "String" then return @get_stub(x.value)
when "FunctionCall"
- stub, args = {}, {}, {}
+ stub, arg_names, args = {}, {}, {}
for token in *x.value
switch token.type
when "Word"
insert stub, token.value
when "Var"
insert stub, "%"
- insert args, token.value
+ if arg_names then insert arg_names, token.value
+ insert args, token
else
insert stub, "%"
+ arg_names = nil
insert args, token
- return concat(stub," "), args
+ 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}"
@@ -502,21 +527,28 @@ class NomsuCompiler
@writeln " <top level>"
@callstack = {}
error!
+
+ typecheck: (vars, varname, desired_type)=>
+ x = vars[varname]
+ if type(x) == desired_type then return x
+ if type(x) == 'table' and x.type == desired_type then return x
+ @error "Invalid type for %#{varname}. Expected #{desired_type}, but got #{x.type}."
initialize_core: =>
-- Sets up some core functionality
+ -- Uses named local functions to help out callstack readability
lua_code = (vars)=>
- inner_vars = vars-- setmetatable({}, {__index:(_,key)-> "vars[#{repr(key)}]"})
+ inner_vars = setmetatable({}, {__index:(_,key)-> "vars[#{repr(key)}]"})
lua = @tree_to_value(vars.code, inner_vars)
return nil, lua
@defmacro "lua code %code", lua_code
lua_value = (vars)=>
- inner_vars = vars--setmetatable({}, {__index:(_,key)-> "vars[#{repr(key)}]"})
+ inner_vars = setmetatable({}, {__index:(_,key)-> "vars[#{repr(key)}]"})
lua = @tree_to_value(vars.code, inner_vars)
return lua, nil
- @defmacro "lua value %code", lua_value
-
+ @defmacro "lua expr %code", lua_value
+
_require = (vars)=>
if not @loaded_files[vars.filename]
file = io.open(vars.filename)
@@ -553,7 +585,9 @@ if arg and arg[1]
output\write ([[
local NomsuCompiler = require('nomsu')
local c = NomsuCompiler()
- local run = %s
+ local run = function(nomsu, vars)
+ %s
+ end
return run(c, {})
]])\format(code)
--ProFi\stop()