Improvements to error messaging.
This commit is contained in:
parent
aa3401ab21
commit
e4ca1cace7
39
core.nom
39
core.nom
@ -17,7 +17,7 @@ rule "macro block %spec %body":
|
|||||||
| local spec, body = vars.spec, vars.body
|
| local spec, body = vars.spec, vars.body
|
||||||
| local wrapper = function(compiler, vars, kind)
|
| local wrapper = function(compiler, vars, kind)
|
||||||
| if kind == "Expression" then
|
| if kind == "Expression" then
|
||||||
| error("Macro: "..spec.." was defined to be a block, but is being used as an expression.")
|
| compiler:error("Macro: "..spec.." was defined to be a block, but is being used as an expression.")
|
||||||
| end
|
| end
|
||||||
| return body(compiler, vars, kind), true
|
| return body(compiler, vars, kind), true
|
||||||
| end
|
| end
|
||||||
@ -127,7 +127,7 @@ rule "do %action":
|
|||||||
macro block "if %condition %if_body":
|
macro block "if %condition %if_body":
|
||||||
concat [..]
|
concat [..]
|
||||||
"if ",%condition as lua expr," then"
|
"if ",%condition as lua expr," then"
|
||||||
"\n ",lua expr "vars.if_body.value.value" as lua block
|
"\n ",(lua expr "vars.if_body.value.value") as lua block
|
||||||
"\nend"
|
"\nend"
|
||||||
|
|
||||||
macro block "if %condition %if_body else %else_body":
|
macro block "if %condition %if_body else %else_body":
|
||||||
@ -195,7 +195,7 @@ macro ["%index st in %list", "%index nd in %list", "%index rd in %list", "%index
|
|||||||
macro ["%item is in %list", "%list contains %item"]:
|
macro ["%item is in %list", "%list contains %item"]:
|
||||||
concat ["(",%list as lua expr,"[",%index as lua expr,"] ~= nil)"]
|
concat ["(",%list as lua expr,"[",%index as lua expr,"] ~= nil)"]
|
||||||
|
|
||||||
macro ["length of %list", "size of %list"]:
|
macro ["length of %list", "size of %list", "number of %list"]:
|
||||||
concat ["#(",%list as lua expr,")"]
|
concat ["#(",%list as lua expr,")"]
|
||||||
|
|
||||||
rule "restrict %fn to within %whitelist":
|
rule "restrict %fn to within %whitelist":
|
||||||
@ -203,11 +203,16 @@ rule "restrict %fn to within %whitelist":
|
|||||||
|local fns = (type(vars.fn) == 'string') and {vars.fn} or vars.fn
|
|local fns = (type(vars.fn) == 'string') and {vars.fn} or vars.fn
|
||||||
|local whitelist = (type(vars.whitelist) == 'string') and {vars.whitelist} or vars.whitelist
|
|local whitelist = (type(vars.whitelist) == 'string') and {vars.whitelist} or vars.whitelist
|
||||||
|local whiteset = {}
|
|local whiteset = {}
|
||||||
|for _,w in ipairs(whitelist) do whiteset[w] = true end
|
|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
|
|for _,fn in ipairs(fns) do
|
||||||
| local fn_info = compiler.defs[fn]
|
| local fn_info = compiler.defs[fn]
|
||||||
| if fn_info == nil then
|
| if fn_info == nil then
|
||||||
| print("Undefined function: "..tostring(fn))
|
| compiler:error("Undefined function: "..tostring(fn))
|
||||||
| elseif not compiler:check_permission(fn) then
|
| elseif not compiler:check_permission(fn) then
|
||||||
| print("You do not have permission to restrict function: "..tostring(fn))
|
| print("You do not have permission to restrict function: "..tostring(fn))
|
||||||
| else
|
| else
|
||||||
@ -219,16 +224,23 @@ rule "allow %whitelist to use %fn":
|
|||||||
lua block ".."
|
lua block ".."
|
||||||
|local fns = (type(vars.fn) == 'string') and {vars.fn} or vars.fn
|
|local fns = (type(vars.fn) == 'string') and {vars.fn} or vars.fn
|
||||||
|local whitelist = (type(vars.whitelist) == 'string') and {vars.whitelist} or vars.whitelist
|
|local whitelist = (type(vars.whitelist) == 'string') and {vars.whitelist} or 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
|
|for _,fn in ipairs(fns) do
|
||||||
| local fn_info = compiler.defs[fn]
|
| local fn_info = compiler.defs[fn]
|
||||||
| if fn_info == nil then
|
| if fn_info == nil then
|
||||||
| print("Undefined function: "..tostring(fn))
|
| compiler:error("Undefined function: "..tostring(fn))
|
||||||
| elseif fn_info.whiteset == nil then
|
| elseif fn_info.whiteset == nil then
|
||||||
| print("Function is already allowed by everyone: "..tostring(fn))
|
| print("Function is already allowed by everyone: "..tostring(fn))
|
||||||
| elseif not compiler:check_permission(fn) then
|
| elseif not compiler:check_permission(fn) then
|
||||||
| print("You do not have permission to grant permissions for function: "..tostring(fn))
|
| print("You do not have permission to grant permissions for function: "..tostring(fn))
|
||||||
| else
|
| else
|
||||||
| for _,w in ipairs(whitelist) do fn_info.whiteset[w] = true end
|
| for _,w in ipairs(whitelist) do
|
||||||
|
| fn_info.whiteset[w] = true
|
||||||
|
| end
|
||||||
| end
|
| end
|
||||||
|end
|
|end
|
||||||
|
|
||||||
@ -236,10 +248,15 @@ rule "forbid %blacklist to use %fn":
|
|||||||
lua block ".."
|
lua block ".."
|
||||||
|local fns = (type(vars.fn) == 'string') and {vars.fn} or vars.fn
|
|local fns = (type(vars.fn) == 'string') and {vars.fn} or vars.fn
|
||||||
|local blacklist = (type(vars.blacklist) == 'string') and {vars.blacklist} or vars.blacklist
|
|local blacklist = (type(vars.blacklist) == 'string') and {vars.blacklist} or 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
|
|for _,fn in ipairs(fns) do
|
||||||
| local fn_info = compiler.defs[fn]
|
| local fn_info = compiler.defs[fn]
|
||||||
| if fn_info == nil then
|
| if fn_info == nil then
|
||||||
| print("Undefined function: "..tostring(fn))
|
| compiler:error("Undefined function: "..tostring(fn))
|
||||||
| elseif fn_info.whiteset == nil then
|
| elseif fn_info.whiteset == nil then
|
||||||
| print("Cannot remove items from a whitelist when there is no whitelist on function: "..tostring(fn))
|
| print("Cannot remove items from a whitelist when there is no whitelist on function: "..tostring(fn))
|
||||||
| elseif not compiler:check_permission(fn) then
|
| elseif not compiler:check_permission(fn) then
|
||||||
@ -248,3 +265,9 @@ rule "forbid %blacklist to use %fn":
|
|||||||
| for _,b in ipairs(blacklist) do fn_info.whiteset[b] = nil end
|
| for _,b in ipairs(blacklist) do fn_info.whiteset[b] = nil end
|
||||||
| end
|
| end
|
||||||
|end
|
|end
|
||||||
|
|
||||||
|
rule "error!":
|
||||||
|
lua block "compiler:error()"
|
||||||
|
|
||||||
|
rule "error %msg":
|
||||||
|
lua block "compiler:error(vars.msg)"
|
||||||
|
34
nomic.moon
34
nomic.moon
@ -93,11 +93,11 @@ class Compiler
|
|||||||
call: (fn_name,...)=>
|
call: (fn_name,...)=>
|
||||||
fn_info = @defs[fn_name]
|
fn_info = @defs[fn_name]
|
||||||
if fn_info == nil
|
if fn_info == nil
|
||||||
error "Attempt to call undefined function: #{fn_name}"
|
@error "Attempt to call undefined function: #{fn_name}"
|
||||||
if fn_info.is_macro
|
if fn_info.is_macro
|
||||||
error "Attempt to call macro at runtime: #{fn_name}"
|
@error "Attempt to call macro at runtime: #{fn_name}"
|
||||||
unless @check_permission(fn_name)
|
unless @check_permission(fn_name)
|
||||||
error "You do not have the authority to call: #{fn_name}"
|
@error "You do not have the authority to call: #{fn_name}"
|
||||||
table.insert @callstack, fn_name
|
table.insert @callstack, fn_name
|
||||||
{:fn, :arg_names} = fn_info
|
{:fn, :arg_names} = fn_info
|
||||||
args = {name, select(i,...) for i,name in ipairs(arg_names)}
|
args = {name, select(i,...) for i,name in ipairs(arg_names)}
|
||||||
@ -110,7 +110,7 @@ class Compiler
|
|||||||
check_permission: (fn_name)=>
|
check_permission: (fn_name)=>
|
||||||
fn_info = @defs[fn_name]
|
fn_info = @defs[fn_name]
|
||||||
if fn_info == nil
|
if fn_info == nil
|
||||||
error "Undefined function: #{fn_name}"
|
@error "Undefined function: #{fn_name}"
|
||||||
if fn_info.whiteset == nil then return true
|
if fn_info.whiteset == nil then return true
|
||||||
for caller in *@callstack
|
for caller in *@callstack
|
||||||
if fn_info.whiteset[caller]
|
if fn_info.whiteset[caller]
|
||||||
@ -135,7 +135,7 @@ class Compiler
|
|||||||
table.insert(invocations, invocation)
|
table.insert(invocations, invocation)
|
||||||
if arg_names
|
if arg_names
|
||||||
if not utils.equivalent(utils.set(arg_names), utils.set(_arg_names))
|
if not utils.equivalent(utils.set(arg_names), utils.set(_arg_names))
|
||||||
error("Conflicting argument names #{utils.repr(arg_names)} and #{utils.repr(_arg_names)} for #{utils.repr(text)}")
|
@error("Conflicting argument names #{utils.repr(arg_names)} and #{utils.repr(_arg_names)} for #{utils.repr(text)}")
|
||||||
else arg_names = _arg_names
|
else arg_names = _arg_names
|
||||||
return invocations, arg_names
|
return invocations, arg_names
|
||||||
|
|
||||||
@ -249,10 +249,13 @@ class Compiler
|
|||||||
for statement in *tree.value.body.value
|
for statement in *tree.value.body.value
|
||||||
code = to_lua(statement)
|
code = to_lua(statement)
|
||||||
-- Run the fuckers as we go
|
-- Run the fuckers as we go
|
||||||
lua_thunk, err = loadstring("return (function(compiler, vars)\n#{code}\nend)")
|
lua_thunk, err = load("return (function(compiler, vars)\n#{code}\nend)")
|
||||||
if not lua_thunk
|
if not lua_thunk
|
||||||
error("Failed to compile generated code:\n#{code}\n\n#{err}")
|
error("Failed to compile generated code:\n#{code}\n\n#{err}")
|
||||||
lua_thunk!(self, vars)
|
ok,err = pcall(lua_thunk)
|
||||||
|
if not ok then error(err)
|
||||||
|
ok,err = pcall(err, self, vars)
|
||||||
|
if not ok then @error(err)
|
||||||
add code
|
add code
|
||||||
add [[
|
add [[
|
||||||
return ret
|
return ret
|
||||||
@ -354,9 +357,9 @@ class Compiler
|
|||||||
run_macro: (tree, kind="Expression")=>
|
run_macro: (tree, kind="Expression")=>
|
||||||
name = @fn_name_from_tree(tree)
|
name = @fn_name_from_tree(tree)
|
||||||
unless @defs[name] and @defs[name].is_macro
|
unless @defs[name] and @defs[name].is_macro
|
||||||
error("Macro not found: #{name}")
|
@error("Macro not found: #{name}")
|
||||||
unless @check_permission(name)
|
unless @check_permission(name)
|
||||||
error "You do not have the authority to call: #{name}"
|
@error "You do not have the authority to call: #{name}"
|
||||||
{:fn, :arg_names} = @defs[name]
|
{:fn, :arg_names} = @defs[name]
|
||||||
args = [a for a in *tree.value when a.type != "Word"]
|
args = [a for a in *tree.value when a.type != "Word"]
|
||||||
args = {name,args[i] for i,name in ipairs(arg_names)}
|
args = {name,args[i] for i,name in ipairs(arg_names)}
|
||||||
@ -364,7 +367,7 @@ class Compiler
|
|||||||
ret, manual_mode = fn(self, args, kind)
|
ret, manual_mode = fn(self, args, kind)
|
||||||
table.remove @callstack
|
table.remove @callstack
|
||||||
if not ret
|
if not ret
|
||||||
error("No return value for macro: #{name}")
|
@error("No return value for macro: #{name}")
|
||||||
if kind == "Statement" and not manual_mode
|
if kind == "Statement" and not manual_mode
|
||||||
ret = "ret = "..ret
|
ret = "ret = "..ret
|
||||||
return ret
|
return ret
|
||||||
@ -450,6 +453,13 @@ class Compiler
|
|||||||
output\write(code)
|
output\write(code)
|
||||||
return code
|
return code
|
||||||
|
|
||||||
|
error: (...)=>
|
||||||
|
print(...)
|
||||||
|
print("Callstack:")
|
||||||
|
for i=#@callstack,1,-1
|
||||||
|
print " #{@callstack[i]}"
|
||||||
|
error!
|
||||||
|
|
||||||
test: (src, expected)=>
|
test: (src, expected)=>
|
||||||
i = 1
|
i = 1
|
||||||
while i != nil
|
while i != nil
|
||||||
@ -459,13 +469,13 @@ class Compiler
|
|||||||
i = stop
|
i = stop
|
||||||
start,stop = test\find"==="
|
start,stop = test\find"==="
|
||||||
if not start or not stop then
|
if not start or not stop then
|
||||||
error("WHERE'S THE ===? in:\n#{test}")
|
@error("WHERE'S THE ===? in:\n#{test}")
|
||||||
test_src, expected = test\sub(1,start-1), test\sub(stop+1,-1)
|
test_src, expected = test\sub(1,start-1), test\sub(stop+1,-1)
|
||||||
expected = expected\match'[\n]*(.*[^\n])'
|
expected = expected\match'[\n]*(.*[^\n])'
|
||||||
tree = @parse(test_src)
|
tree = @parse(test_src)
|
||||||
got = @stringify_tree(tree.value.body)
|
got = @stringify_tree(tree.value.body)
|
||||||
if got != expected
|
if got != expected
|
||||||
error"TEST FAILED!\nSource:\n#{test_src}\nExpected:\n#{expected}\n\nGot:\n#{got}"
|
@error"TEST FAILED!\nSource:\n#{test_src}\nExpected:\n#{expected}\n\nGot:\n#{got}"
|
||||||
|
|
||||||
|
|
||||||
initialize_core: =>
|
initialize_core: =>
|
||||||
|
Loading…
Reference in New Issue
Block a user