aboutsummaryrefslogtreecommitdiff
path: root/lib
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 /lib
parent10d61df78bdbf002a3701e468b0a3c88be2cad03 (diff)
Kinda mostly working, except for closure vars like in lib/secrets.nom.
Diffstat (limited to 'lib')
-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
7 files changed, 359 insertions, 399 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)
+