aboutsummaryrefslogtreecommitdiff
path: root/nomsu.moon
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 /nomsu.moon
parent10d61df78bdbf002a3701e468b0a3c88be2cad03 (diff)
Kinda mostly working, except for closure vars like in lib/secrets.nom.
Diffstat (limited to 'nomsu.moon')
-rwxr-xr-xnomsu.moon102
1 files changed, 68 insertions, 34 deletions
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()