aboutsummaryrefslogtreecommitdiff
path: root/lib/core.nom
diff options
context:
space:
mode:
Diffstat (limited to 'lib/core.nom')
-rw-r--r--lib/core.nom689
1 files changed, 6 insertions, 683 deletions
diff --git a/lib/core.nom b/lib/core.nom
index f0cad0d..f00bd22 100644
--- a/lib/core.nom
+++ b/lib/core.nom
@@ -1,683 +1,6 @@
-# Rule for making rules
-lua block ".."
- |compiler:defmacro("rule %spec = %body", function(compiler, vars, kind)
- | if kind == "Expression" then
- | compiler:error("Cannot use rule definitions as an expression.")
- | end
- | local spec = compiler:get_invocations_from_definition(vars.spec, vars)
- | return ("compiler:def("..compiler.utils.repr(spec,true)..", "..compiler:tree_to_lua(vars.body, vars)..")"), true
- |end)
-
-rule [help %invocation] =:
- lua block ".."
- |local fn_info = compiler.defs[vars.invocation]
- |if not fn_info then
- | compiler:writeln("Function not found: "..compiler.utils.repr(vars.invocation, true))
- |else
- | compiler:writeln("rule "..compiler.utils.repr(fn_info.invocations).." ="..(fn_info.src or ":\\n <unknown source code>"))
- |end
-
-# Macros
-lua block ".."
- |local add_macro = function(compiler, vars, kind)
- | local spec = compiler:get_invocations_from_definition(vars.spec, vars)
- | local fn = compiler:tree_to_value(vars.body, vars)
- | compiler:defmacro(spec, fn, vars.body.src)
- | return "", true
- |end
- |compiler:defmacro("macro %spec = %body", add_macro)
- |
- |local add_macro_block = function(compiler, vars, kind)
- | local spec = compiler:get_invocations_from_definition(vars.spec, vars)
- | local fn = compiler:tree_to_value(vars.body, vars)
- | local wrapper = function(compiler, vars, kind)
- | if kind == "Expression" then
- | compiler:error("Macro: "..spec.." was defined to be a block, but is being used as an expression.")
- | end
- | return ("do\\n"..fn(compiler, vars, kind).."\\nend"), true
- | end
- | compiler:defmacro(spec, wrapper, vars.body.src)
- | return "", true
- |end
- |compiler:defmacro("macro block %spec = %body", add_macro_block)
-
-# Compiler tools
-rule [eval %code, run %code] =:
- lua expr "compiler:run(vars.code)"
-
-rule [source code from tree %tree] =:
- lua block ".."
- |local _,_,leading_space = vars.tree.src:find("\\n(%s*)%S")
- |if leading_space then
- | local chunk1, chunk2 = vars.tree.src:match(":%s*([^\\n]*)(\\n.*)")
- | chunk2 = chunk2:gsub("\\n"..leading_space, "\\n")
- | vars.source = chunk1..chunk2.."\\n"
- |else
- | vars.source = vars.tree.src:match(":%s*(%S.*)").."\\n"
- |end
-
- %source
-
-macro [source code %body] =:
- lua expr ".."
- |compiler.utils.repr(compiler:call("source code from tree %", vars.body), true)
-
-rule [run file %filename] =:
- lua block ".."
- |local file = io.open(vars.filename)
- |return compiler:run(file:read("*a"))
-
-# Error functions
-rule [error!] =:
- lua block ".."
- |table.remove(compiler.callstack)
- |compiler:error()
-
-rule [error %msg] =:
- lua block ".."
- |table.remove(compiler.callstack)
- |compiler:error(vars.msg)
-
-# TODO: Make useful
-macro [as lua %block] =:
- lua expr "compiler.utils.repr(compiler:tree_to_lua(vars.block.value, 'Statement'), true)"
-
-macro block [show generated lua %block] =:
- ".."|compiler:writeln(\lua expr "compiler.utils.repr(compiler:tree_to_lua(vars.block.value, 'Statement'), true)"\)
-
-# Macro helper functions
-rule [%tree as value] =:
- lua expr ".."
- |compiler:tree_to_value(vars.tree, vars)
-
-rule [%tree as lua block] =:
- lua block ".."
- |return compiler:tree_to_lua(vars.tree, 'Statement'), true
-
-rule [%tree as lua expr] =:
- lua expr ".."
- |compiler:tree_to_lua(vars.tree, 'Expression')
-
-# Moonscript!
-macro block [moonscript block %moonscript_code] =:
- lua block ".."
- |local parse, compile = require('moonscript.parse'), require('moonscript.compile')
- |local moon_code = compiler:tree_to_value(vars.moonscript_code, vars)
- |local tree, err = parse.string(moon_code)
- |if not tree then
- | compiler:error("Failed to parse moonscript: "..err)
- |end
- |local lua_code, err, pos = compile.tree(tree)
- |if not lua_code then
- | compiler:error(compile.format_error(err, pos, moon_code))
- |end
- |return "do\\n"..lua_code.."\\nend"
-
-macro [moonscript %moonscript_code] =:
- lua block ".."
- |local parse, compile = require('moonscript.parse'), require('moonscript.compile')
- |local moon_code = compiler:tree_to_value(vars.moonscript_code, vars)
- |local tree, err = parse.string(moon_code)
- |if not tree then
- | compiler:error("Failed to parse moonscript: "..err)
- |end
- |local lua_code, err, pos = compile.tree(tree)
- |if not lua_code then
- | compiler:error(compile.format_error(err, pos, moon_code))
- |end
- |return "(function(compiler, vars)\\n"..lua_code.."\\nend)(compiler, vars)"
-
-# String functions
-rule [join %strs] =:
- lua block ".."
- |local str_bits = {}
- |for i,bit in ipairs(vars.strs) do str_bits[i] = compiler.utils.repr(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] = compiler.utils.repr(bit) end
- |return table.concat(str_bits, vars.glue)
-
-rule [capitalize %str, %str capitalized] =:
- lua expr ".."|vars.str:gsub("%l", string.upper, 1)
-
-# Variable assignment
-#..
- macro block [%var = %value] =:
- lua block ".."
- |if vars.var.type ~= "Var" then
- | compiler:error("Assignment operation has the wrong type for the left hand side. "
- | .."Expected Var, but got: "..vars.var.type)
- |end
- ".."|\%var as lua expr\ = \%value as lua expr\
-
-lua block ".."
- |local function helper(callback)
- | return function(compiler, vars, kind)
- | if kind == "Expression" then
- | compiler:error("Cannot use an assignment operation as an expression value.")
- | end
- | if vars.var.type ~= "Var" then
- | compiler:error("Assignment operation has the wrong type for the left hand side. "
- | .."Expected Var, but got: "..vars.var.type)
- | end
- | if vars.rhs.type ~= "Thunk" then
- | compiler: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
- | return callback(compiler:tree_to_lua(vars.var, "Expression"),
- | compiler:tree_to_lua(vars.rhs.value.value[1].value, "Expression")), true
- | else
- | local ret = "do\\n local ret"
- | ret = ret .. "\\n "..compiler:tree_to_lua(vars.rhs.value, "Statement")
- | ret = ret .. "\\n "..callback(compiler:tree_to_lua(vars.var, "Expression"), "ret")
- | return (ret.."\\nend"), true
- | end
- | end
- |end
- |compiler:defmacro("%var = %rhs", helper(function(var,result) return var.." = "..result end))
- |compiler:defmacro("%var += %rhs", helper(function(var,result) return var.." = "..var.." + "..result end))
- |compiler:defmacro("%var -= %rhs", helper(function(var,result) return var.." = "..var.." - "..result end))
- |compiler:defmacro("%var *= %rhs", helper(function(var,result) return var.." = "..var.." * "..result end))
- |compiler:defmacro("%var /= %rhs", helper(function(var,result) return var.." = "..var.." / "..result end))
- |compiler:defmacro("%var ^= %rhs", helper(function(var,result) return var.." = "..var.." ^ "..result end))
- |compiler:defmacro("%var and= %rhs", helper(function(var,result) return var.." = "..var.." and "..result end))
- |compiler:defmacro("%var or= %rhs", helper(function(var,result) return var.." = "..var.." or "..result end))
- |compiler:defmacro("%var concat= %rhs", helper(function(var,result) return var.." = "..var.." .. "..result end))
- |compiler:defmacro("%var mod= %rhs", helper(function(var,result) return var.." = "..var.." % "..result end))
-
-# Operators
-macro [true, yes] =: "true"
-macro [false, no] =: "false"
-macro [nil, null] =: "nil"
-macro block [nop, pass] =: ""
-macro [%a + %b] =: ".."|(\%a as lua expr\ + \%b as lua expr\)
-macro [%a + %b + %c] =: ".."|(\%a as lua expr\ + \%b as lua expr\ + \%c as lua expr\)
-macro [%a + %b + %c + %d] =: ".."|(\%a as lua expr\ + \%b as lua expr\ + \%c as lua expr\ + \%d as lua expr\)
-macro [%a - %b] =: ".."|(\%a as lua expr\ - \%b as lua expr\)
-macro [%a * %b] =: ".."|(\%a as lua expr\ * \%b as lua expr\)
-macro [%a * %b * %c] =: ".."|(\%a as lua expr\ * \%b as lua expr\ * \%c as lua expr\)
-macro [%a * %b * %c * %d] =: ".."|(\%a as lua expr\ * \%b as lua expr\ * \%c as lua expr\ * \%d as lua expr\)
-macro [%a / %b] =: ".."|(\%a as lua expr\ / \%b as lua expr\)
-macro [%a === %b] =: ".."|(\%a as lua expr\ == \%b as lua expr\)
-macro [%a !== %b] =: ".."|(\%a as lua expr\ ~= \%b as lua expr\)
-macro [%a < %b] =: ".."|(\%a as lua expr\ < \%b as lua expr\)
-macro [%a < %b < %c] =: ".."|((\%a as lua expr\ < \%b as lua expr\) and (\%b as lua expr\ < \%c as lua expr\))
-macro [%a <= %b < %c] =: ".."|((\%a as lua expr\ <= \%b as lua expr\) and (\%b as lua expr\ < \%c as lua expr\))
-macro [%a <= %b <= %c] =: ".."|((\%a as lua expr\ <= \%b as lua expr\) and (\%b as lua expr\ <= \%c as lua expr\))
-macro [%a < %b <= %c] =: ".."|((\%a as lua expr\ < \%b as lua expr\) and (\%b as lua expr\ <= \%c as lua expr\))
-macro [%a > %b > %c] =: ".."|((\%a as lua expr\ > \%b as lua expr\) and (\%b as lua expr\ > \%c as lua expr\))
-macro [%a >= %b > %c] =: ".."|((\%a as lua expr\ >= \%b as lua expr\) and (\%b as lua expr\ > \%c as lua expr\))
-macro [%a >= %b >= %c] =: ".."|((\%a as lua expr\ >= \%b as lua expr\) and (\%b as lua expr\ >= \%c as lua expr\))
-macro [%a > %b >= %c] =: ".."|((\%a as lua expr\ > \%b as lua expr\) and (\%b as lua expr\ >= \%c as lua expr\))
-macro [%a <= %b] =: ".."|(\%a as lua expr\ <= \%b as lua expr\)
-macro [%a > %b] =: ".."|(\%a as lua expr\ > \%b as lua expr\)
-macro [%a >= %b] =: ".."|(\%a as lua expr\ >= \%b as lua expr\)
-macro [%a ^ %b] =: ".."|(\%a as lua expr\ ^ \%b as lua expr\)
-macro [%a and %b] =: ".."|(\%a as lua expr\ and \%b as lua expr\)
-macro [%a and %b and %c] =:
- ".."|(\%a as lua expr\ and \%b as lua expr\ and \%c as lua expr\)
-macro [%a and %b and %c and %d] =:
- ".."|(\%a as lua expr\ and \%b as lua expr\ and \%c as lua expr\ and \%d as lua expr\)
-macro [%a or %b] =: ".."|(\%a as lua expr\ or \%b as lua expr\)
-macro [%a or %b or %c] =:
- ".."|(\%a as lua expr\ or \%b as lua expr\ or \%c as lua expr\)
-macro [%a or %b or %c or %d] =:
- ".."|(\%a as lua expr\ or \%b as lua expr\ or \%c as lua expr\ or \%d as lua expr\)
-macro [%a mod %b] =: ".."|(\%a as lua expr\ mod \%b as lua expr\)
-macro [- %a] =: ".."|-(\%a as lua expr\)
-macro [not %a] =: ".."|not (\%a as lua expr\)
-
-rule [%a == %b] =:
- lua expr "((vars.a == vars.b) or compiler.utils.equivalent(vars.a, vars.b))"
-rule [%a != %b] =:
- lua expr "((vars.a ~= vars.b) or not compiler.utils.equivalent(vars.a, vars.b))"
-
-macro [repr %obj] =:
- ".."|compiler.utils.repr(\%obj as lua expr\, true)
-
-macro [say %str] =:
- ".."|compiler:writeln(compiler.utils.repr(\%str as lua expr\))
-
-# Control flow
-rule [do %action] =:
- lua expr "vars.action(compiler, setmetatable({}, {__index=vars}))"
-
-macro block [return %return_value] =:
- lua block ".."
- |if vars.return_value.type ~= "Thunk" then
- | compiler:error("Assignment operation has the wrong type for the right hand side. "
- | .."Expected Thunk, but got: "..vars.return_value.type.."\\nMaybe you used '=' instead of '=:'?")
- |end
- ".."|do
- | local ret
- | \lua expr "compiler:tree_to_lua(vars.return_value.value, 'Statement')"\
- | return ret
- |end
-
-macro block [return] =:
- "return nil"
-
-# Conditionals
-macro block [if %condition %if_body] =:
- ".."|if \%condition as lua expr\ then
- | \(lua expr "vars.if_body.value") as lua block\
- |end
-
-macro block [if %condition %if_body else %else_body] =:
- ".."|if \%condition as lua expr\ then
- | \(lua expr "vars.if_body.value") as lua block\
- |else
- | \(lua expr "vars.else_body.value") as lua block\
- |end
-
-# Ternary operator
-macro [%if_expr if %condition else %else_expr] =:
- ".."|(function(compiler, vars)
- | if \%condition as lua expr\ then
- | return \%if_expr as lua expr\
- | else
- | return \%else_expr as lua expr\
- | end
- |end)(compiler, vars)
-
-
-# Loop control flow
-macro block [break] =: "break"
-macro block [continue] =: "continue"
-# TODO: add labeled break/continue?
-
-# GOTOs
-lua block ".."
- |local function lua_label(label)
- | if label.type ~= "Var" then
- | compiler:error("Goto label has the wrong type for the label. Expected Var, but got: "..label.type)
- | end
- | local bits = "abcdefghijklmnop"
- | local lua_identifier = "label_"
- | for i=1,#label.value do
- | local byte = string.byte(label.value, i)
- | local low = byte % 16
- | local high = (byte - low) / 16
- | lua_identifier = lua_identifier .. bits:sub(low+1,low+1) .. bits:sub(high+1,high+1)
- | end
- | return lua_identifier
- |end
- |
- |compiler:defmacro("-> %label", function(compiler, vars, kind)
- | return "::"..lua_label(vars.label).."::", true
- |end)
- |compiler:defmacro("go to %label", function(compiler, vars, kind)
- | return "goto "..lua_label(vars.label), true
- |end)
-
-# While loops
-macro block [repeat %body] =:
- ".."|while true do
- | \(lua expr "vars.body.value") as lua block\
- |end
-macro block [repeat while %condition %body] =:
- ".."|while \%condition as lua expr\ do
- | \(lua expr "vars.body.value") as lua block\
- |end
-macro block [repeat until %condition %body] =:
- ".."|while not (\%condition as lua expr\) do
- | \(lua expr "vars.body.value") as lua block\
- |end
-
-# For loops
-macro block [for %var in %iterable %body] =:
- %var-type =: lua expr "vars.var.type"
- if (%var-type != "Var"):
- error ".."
- |For loop has the wrong type for the loop variable. Expected Var, but got: \%var-type\
- %var-code =: %var as lua expr
- ".."|local old_loopval = \%var-code\
- |for i,value in ipairs(\%iterable as lua expr\) do
- | \%var-code\ = value
- | \(lua expr "vars.body.value") as lua block\
- |end
- |\%var-code\ = old_loopval
-
-macro block [for all %iterable %body] =:
- ".."|local old_loopval = vars.it
- |for i,value in ipairs(\%iterable as lua expr\) do
- | vars.it = value
- | \(lua expr "vars.body.value") as lua block\
- |end
- |vars.it = old_loopval
-
-# Switch statement/multi-branch if
-macro block [when %body] =:
- %result =: ""
- for %statement in (lua expr "vars.body.value.value"):
- %func-call =: lua expr "vars.statement.value"
- if ((lua expr "vars['func-call'].type") != "FunctionCall"):
- error "Invalid format for 'when' statement. Only '?' blocks are allowed."
- %tokens =: lua expr "vars['func-call'].value"
- %q =: lua expr "vars.tokens[1]"
- if (((lua expr "vars.q.type") != "Word") or ((lua expr "vars.q.value") != "?")):
- error "Invalid format for 'when' statement. Lines must begin with '?'"
- %thunk =: lua expr "vars.tokens[#vars.tokens]"
- if ((lua expr "vars.thunk.type") != "Thunk"):
- error "Invalid format for 'when' statement. Lines must have a body."
- %condition_bits =: []
- for %i in (2 up to (lua expr "#vars.tokens")):
- lua block "table.insert(vars['condition_bits'], vars.tokens[vars.i])"
-
- if (lua expr "#vars.condition_bits == 0"):
- %result concat=: ".."
- |
- |do
- | local ret
- | \(lua expr "vars.thunk.value") as lua block\
- | return ret
- |end
- ..else:
- if (lua expr "#vars.condition_bits == 1 and vars.condition_bits[1].type ~= 'Word'"):
- %condition =: lua expr "vars.condition_bits[1]"
- ..else:
- %condition =: dict [..]
- ["type",lua expr "vars['func-call'].type"]
- ["src",lua expr "vars['func-call'].src"]
- ["value", %condition_bits]
- %result concat=: ".."
- |
- |if \%condition as lua expr\ then
- | local ret
- | \(lua expr "vars.thunk.value") as lua block\
- | return ret
- |end
-
- %result
-
-# Switch statement
-macro block [when %branch-value %body] =:
- %result =: ".."|local branch_value = \%branch-value as lua expr\
- for %statement in (lua expr "vars.body.value.value"):
- %func-call =: lua expr "vars.statement.value"
- if ((lua expr "vars['func-call'].type") != "FunctionCall"):
- error "Invalid format for 'when' statement. Only == blocks are allowed."
- %tokens =: lua expr "vars['func-call'].value"
- %eq =: lua expr "vars.tokens[1]"
- if (((lua expr "vars.eq.type") != "Word") or ((lua expr "vars.eq.value") != "==")):
- error "Invalid format for 'when' statement. Lines must begin with '=='"
- %thunk =: lua expr "vars.tokens[#vars.tokens]"
- if ((lua expr "vars.thunk.type") != "Thunk"):
- error "Invalid format for 'when' statement. Lines must have a body."
- %condition_bits =: []
- for %i in (2 up to (lua expr "#vars.tokens")):
- lua block "table.insert(vars.condition_bits, vars.tokens[vars.i])"
- if (lua expr "#vars.condition_bits == 0"):
- %result concat=: ".."
- |
- |do
- | local ret
- | \(lua expr "vars.thunk.value") as lua block\
- | return ret
- |end
- ..else:
- if (lua expr "#vars.condition_bits == 1 and vars.condition_bits[1].type ~= 'Word'"):
- %condition =: (lua expr "vars.condition_bits[1]")
- ..else:
- %condition =: dict [..]
- ["type",lua expr "vars['func-call'].type"]
- ["src",lua expr "vars['func-call'].src"]
- ["value", %condition_bits]
- %result concat=: ".."
- |
- |if compiler.utils.equivalent(branch_condition, \%condition as lua expr\) then
- | local ret
- | \(lua expr "vars.thunk.value") as lua block\
- | return ret
- |end
- %result
-
-# List Comprehension
-# TODO: maybe make this lazy, or a lazy version?
-macro [%expression for %var in %iterable] =:
- %var-type =: lua expr "vars.var.type"
- if (%var-type != "Var"):
- error ".."
- |List comprehension has the wrong type for the loop variable. Expected Var, but got: \%var-type\
- %var-code =: %var as lua expr
- ".."|(function(game, vars)
- | local comprehension = {}
- | for i,value in ipairs(\%iterable as lua expr\) do
- | \%var-code\ = value
- | comprehension[i] = \%expression as lua expr\
- | 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 expr\) do
- | vars.it = value
- | comprehension[i] = \%expression as lua expr\
- | end
- | return comprehension
- |end)(game, setmetatable({}, {__index=vars}))
-
-# Dict comprehension
-macro [%key -> %value for %var in %iterable] =:
- %var-type =: lua expr "vars.var.type"
- if (%var-type != "Var"):
- error ".."
- |Dict comprehension has the wrong type for the loop variable. Expected Var, but got: \%var-type\
- %var-code =: %var as lua expr
- ".."|(function(game, vars)
- | local comprehension = {}
- | for i,value in ipairs(\%iterable as lua expr\) do
- | \%var-code\ = value
- | comprehension[\%key as lua expr\] = \%value as lua expr\
- | end
- | return comprehension
- |end)(game, setmetatable({}, {__index=vars}))
-
-macro [%key -> %value for all %iterable] =:
- ".."|(function(game, vars)
- | local comprehension = {}
- | for i,value in ipairs(\%iterable as lua expr\) do
- | vars.it = value
- | comprehension[\%key as lua expr\] = \%value as lua expr\
- | end
- | return comprehension
- |end)(game, setmetatable({}, {__index=vars}))
-
-# Number ranges
-rule [%start up to %stop] =:
- lua expr "compiler.utils.range(vars.start,vars.stop-1)"
-
-rule [%start thru %stop, %start through %stop] =:
- lua expr "compiler.utils.range(vars.start,vars.stop)"
-
-rule [%start down to %stop] =:
- lua expr "compiler.utils.range(vars.start,vars.stop+1,-1)"
-
-rule [%start down thru %stop, %start down through %stop] =:
- lua expr "compiler.utils.range(vars.start,vars.stop,-1)"
-
-rule [%start up to %stop via %step] =:
- lua expr "compiler.utils.range(vars.start,vars.stop-1,vars.step)"
-
-rule [%start thru %stop via %step, %start through %stop via %step] =:
- lua expr "compiler.utils.range(vars.start,vars.stop,vars.step)"
-
-rule [%start down to %stop via %step] =:
- lua expr "compiler.utils.range(vars.start,vars.stop+1,-vars.step)"
-
-rule [%start down thru %stop via %step, %start down through %stop via %step] =:
- lua expr "compiler.utils.range(vars.start,vars.stop,-vars.step)"
-
-# Common utility functions
-rule [random number] =: lua expr "math.random()"
-rule [sum of %items] =: lua expr "compiler.utils.sum(vars.items)"
-rule [product of %items] =: lua expr "compiler.utils.product(vars.items)"
-rule [all of %items] =: lua expr "compiler.utils.all(vars.items)"
-rule [any of %items] =: lua expr "compiler.utils.any(vars.items)"
-rule [avg of %items, average of %items] =:
- lua expr "(compiler.utils.sum(vars.items)/#vars.items)"
-rule [min of %items, smallest of %items, lowest of %items] =:
- lua expr "compiler.utils.min(vars.items)"
-rule [max of %items, biggest of %items, largest of %items, highest of %items] =:
- lua expr "compiler.utils.min(vars.items)"
-
-rule [min of %items with respect to %keys] =:
- lua expr "compiler.utils.min(vars.items, vars.keys)"
-rule [max of %items with respect to %keys] =:
- lua expr "compiler.utils.max(vars.items, vars.keys)"
-
-# List/dict functions
-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 expr\[\%index as lua expr\]
- ".."|\%list as lua expr\[\%index as lua expr\]
-macro [first in %list] =:
- ".."|\%list as lua expr\[1]
-
-macro [..]
- %index st to last in %list, %index nd to last in %list, %index rd to last in %list
- %index th to last in %list
-..=:
- ".."|compiler.utils.nth_to_last(\%list as lua expr\, \%index as lua expr\)
-macro [last in %list] =:
- ".."|compiler.utils.nth_to_last(\%list as lua expr\, 1)
-
-macro block [..]
- %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
-..=:
- lua block ".."
- |if vars.new_value.type ~= "Thunk" then
- | compiler:error("Dict 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
- ".."|do
- | local ret
- | \lua expr "compiler:tree_to_lua(vars.new_value.value, 'Statement')"\
- | \%list as lua expr\[\%index as lua expr\] = ret
- |end
-
-macro [append %item to %list, add %item to %list] =:
- ".."|table.insert(\%list as lua expr\, \%item as lua expr\)
-
-rule [flatten %lists] =:
- %flat =: []
- for %list in %lists:
- for %item in %list:
- add %item to %flat
- %flat
-
-macro [%item is in %list, %list contains %item] =:
- ".."|(\%list as lua expr\[\%index as lua expr\] ~= nil)
-
-macro [length of %list, size of %list, number of %list] =:
- ".."|#(\%list as lua expr\)
-
-rule [dict %items] =:
- %dict =: []
- for %pair in %items:
- lua block "vars.dict[vars.pair[1]] = vars.pair[2]"
- return: %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
-
-# Permission functions
-rule [restrict %fn to within %whitelist] =:
- lua block ".."
- |local fns = compiler:get_invocations(vars.fn)
- |local whitelist = compiler:get_invocations(vars.whitelist)
- |local whiteset = {}
- |for _,w in ipairs(whitelist) do
- | if not compiler.defs[w] then
- | compiler:error("Undefined function: "..tostring(w))
- | else whiteset[w] = true
- | end
- |end
- |for _,fn in ipairs(fns) do
- | local fn_info = compiler.defs[fn]
- | if fn_info == nil then
- | compiler:error("Undefined function: "..tostring(fn))
- | elseif not compiler:check_permission(fn) then
- | compiler:writeln("You do not have permission to restrict function: "..tostring(fn))
- | else
- | compiler.defs[fn].whiteset = whiteset
- | end
- |end
-
-rule [allow %whitelist to use %fn] =:
- lua block ".."
- |local fns = compiler:get_invocations(vars.fn)
- |local whitelist = compiler:get_invocations(vars.whitelist)
- |for _,w in ipairs(whitelist) do
- | if not compiler.defs[w] then
- | compiler:error("Undefined function: "..tostring(w))
- | end
- |end
- |for _,fn in ipairs(fns) do
- | local fn_info = compiler.defs[fn]
- | if fn_info == nil then
- | compiler:error("Undefined function: "..tostring(fn))
- | elseif fn_info.whiteset == nil then
- | compiler:writeln("Function is already allowed by everyone: "..tostring(fn))
- | elseif not compiler:check_permission(fn) then
- | compiler:writeln("You do not have permission to grant permissions for function: "..tostring(fn))
- | else
- | for _,w in ipairs(whitelist) do
- | fn_info.whiteset[w] = true
- | end
- | end
- |end
-
-rule [forbid %blacklist to use %fn] =:
- lua block ".."
- |local fns = compiler:get_invocations(vars.fn)
- |local blacklist = compiler:get_invocations(vars.blacklist)
- |for _,b in ipairs(blacklist) do
- | if not compiler.defs[b] then
- | compiler:error("Undefined function: "..tostring(b))
- | end
- |end
- |for _,fn in ipairs(fns) do
- | local fn_info = compiler.defs[fn]
- | if fn_info == nil then
- | compiler:error("Undefined function: "..tostring(fn))
- | elseif fn_info.whiteset == nil then
- | compiler:writeln("Cannot remove items from a whitelist when there is no whitelist on function: "..tostring(fn))
- | elseif not compiler:check_permission(fn) then
- | compiler:writeln("You do not have permission to restrict function: "..tostring(fn))
- | else
- | for _,b in ipairs(blacklist) do fn_info.whiteset[b] = nil end
- | end
- |end
-
-# For unit testing
-macro [parse tree %code] =:
- lua expr "compiler.utils.repr(compiler:stringify_tree(vars.code.value), true)"
-
-macro block [test %code yields %expected] =:
- %generated =: lua expr "compiler.utils.repr(compiler:stringify_tree(vars.code.value), true)"
- %expected =: %expected as lua expr
- if (%generated != %expected):
- say "Test failed!"
- say "Expected:"
- say %expected
- say "But got:"
- say %generated
- error!
- return: ""
-
+require "lib/metaprogramming.nom"
+require "lib/utils.nom"
+require "lib/operators.nom"
+require "lib/control_flow.nom"
+require "lib/collections.nom"
+require "lib/permissions.nom"