aboutsummaryrefslogtreecommitdiff
path: root/nomsu.moon
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2017-10-13 14:15:02 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2017-10-13 14:15:02 -0700
commit06d05ebeee5be2e922299291643b63ea5ab332fd (patch)
tree8d9dda8a6ff5614313857a23b21d582609ab2ec5 /nomsu.moon
parentc189be29bc7184771b02ce7ca1e0a63728db2ba8 (diff)
Tweaked macros to insert runtime checks, rather than compile-time.
Diffstat (limited to 'nomsu.moon')
-rwxr-xr-xnomsu.moon29
1 files changed, 24 insertions, 5 deletions
diff --git a/nomsu.moon b/nomsu.moon
index 7e45d0d..76818d3 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -228,8 +228,8 @@ class NomsuCompiler
-- I use a hash sign in "#macro" so it's guaranteed to not be a valid function name
if def.is_macro and @callstack[#@callstack] != "#macro"
@error "Attempt to call macro at runtime: #{stub}\nThis can be caused by using a macro in a function that is defined before the macro."
- unless @check_permission(def)
- @error "You do not have the authority to call: #{stub}"
+ unless def.is_macro
+ @assert_permission(stub)
{:thunk, :arg_names} = def
args = {name, select(i,...) for i,name in ipairs(arg_names)}
if @debug
@@ -241,7 +241,7 @@ class NomsuCompiler
remove @callstack
return unpack(rets)
- run_macro: (tree, kind="Expression")=>
+ run_macro: (tree)=>
stub,arg_names,args = @get_stub tree
if @debug
@write "#{colored.bright "RUNNING MACRO"} #{colored.underscore colored.magenta(stub)} "
@@ -251,6 +251,18 @@ class NomsuCompiler
remove @callstack
return expr, statement
+ assert_permission: (stub)=>
+ fn_def = @defs[stub]
+ unless fn_def
+ @error "Undefined function: #{fn_name}"
+ whiteset = fn_def.whiteset
+ if whiteset == nil then return true
+ -- TODO: maybe optimize this by making the callstack a Counter and using a
+ -- move-to-front optimization on the whitelist to check most likely candidates sooner
+ for caller in *@callstack
+ if whiteset[caller] then return true
+ @error "You do not have the authority to call: #{stub}"
+
check_permission: (fn_def)=>
if getmetatable(fn_def) != functiondef_mt
fn_name = fn_def
@@ -371,8 +383,15 @@ class NomsuCompiler
when "FunctionCall"
stub = @get_stub(tree)
- if @defs[stub] and @defs[stub].is_macro
- return @run_macro(tree, "Expression")
+ def = @defs[stub]
+ if def and def.is_macro
+ expr, statement = @run_macro(tree)
+ if def.whiteset
+ if expr
+ expr = "(nomsu:assert_permission(#{repr stub}) and #{expr})"
+ if statement
+ statement = "nomsu:assert_permission(#{repr stub});\n"..statement
+ return expr, statement
args = {repr(stub)}
for arg in *tree.value
if arg.type == 'Word' then continue