aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/control_flow.nom229
-rw-r--r--lib/metaprogramming.nom29
-rw-r--r--lib/operators.nom40
-rw-r--r--lib/utils.nom85
-rw-r--r--nomsu.lua263
-rwxr-xr-xnomsu.moon10
-rw-r--r--utils.lua3
7 files changed, 318 insertions, 341 deletions
diff --git a/lib/control_flow.nom b/lib/control_flow.nom
index b1df621..460d4dc 100644
--- a/lib/control_flow.nom
+++ b/lib/control_flow.nom
@@ -3,137 +3,99 @@ require "lib/operators.nom"
require "lib/utils.nom"
# Conditionals
-macro statement [if %condition %if_body] =:
- ".."|if \%condition as lua\ then
- | \(lua expr "vars.if_body.value") as lua\
- |end
-
-macro statement [if %condition %if_body else %else_body] =:
- ".."|if \%condition as lua\ then
- | \(lua expr "vars.if_body.value") as lua\
- |else
- | \(lua expr "vars.else_body.value") as lua\
- |end
+parse (if %condition %if_body) as lua code ".."
+ |if \(%condition) then
+ | \(lua expr "vars.if_body.value")
+ |end
+
+parse (if %condition %if_body else %else_body) as lua code ".."
+ |if \(%condition) then
+ | \(lua expr "vars.if_body.value")
+ |else
+ | \(lua expr "vars.else_body.value")
+ |end
# Return
-macro statement [return] =: "do return end"
-macro block [return %return-value] =: ".."
- |return \%return-value as lua\
-
-macro [do %action] =: ".."
- |(\%action as lua\)(nomsu, setmetatable({}, {__index=vars}))
+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}))
# GOTOs
-macro statement [-> %label] =: ".."
- |::label_\nomsu "var_to_lua_identifier" [%label]\::
-macro statement [go to %label] =: ".."
- |goto label_\nomsu "var_to_lua_identifier" [%label]\
+parse (-> %label) as lua code ".."
+ |::label_\(nomsu "var_to_lua_identifier" [%label])::
+parse (go to %label) as lua code ".."
+ |goto label_\(nomsu "var_to_lua_identifier" [%label])
# Loop control flow
-macro statement [stop, stop loop, break] =: "break"
-macro statement [stop for, stop for-loop, break for] =: "goto break_for"
-macro statement [stop repeat, stop repeat-loop, break repeat] =: "goto break_repeat"
-macro statement [stop %var, break %var] =: ".."
- |goto break_\nomsu "var_to_lua_identifier" [%var]\
-
-macro statement [continue, continue loop] =: "continue"
-macro statement [continue for, continue for-loop] =: "goto continue_for"
-macro statement [continue repeat, continue repeat-loop] =: "goto continue_repeat"
-macro statement [continue %var, go to next %var, on to the next %var] =: ".."
- |goto continue_\nomsu "var_to_lua_identifier" [%var]\
+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 ".."
+ |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 ".."
+ |goto continue_\(nomsu "var_to_lua_identifier" [%var])
# While loops
-macro block [repeat %body] =:
- ".."|while true do
- | \(lua expr "vars.body.value") as lua\
- | ::continue_repeat::
- |end
- |::break_repeat::
-macro block [repeat while %condition %body] =:
- ".."|while \%condition as lua\ do
- | \(lua expr "vars.body.value") as lua\
- | ::continue_repeat::
- |end
- |::break_repeat::
-macro block [repeat until %condition %body] =:
- ".."|while not (\%condition as lua\) do
- | \(lua expr "vars.body.value") as lua\
- | ::continue_repeat::
- |end
- |::break_repeat::
+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 ".."
+ |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")
+ | ::continue_repeat::
+ |end
+ |::break_repeat::
# Numeric range for loops
-macro block [for %var from %start to %stop by %step %body] =:
- %var-type =: lua expr "vars.var.type"
- assert (%var-type == "Var") ".."
- |For loop has the wrong type for the loop variable. Expected Var, but got: \%var-type\
- # This trashes the loop variables, just like in Python.
- ".."
- |for i=\%start as lua\,\%stop as lua\,\%step as lua\ do
- | \%var as lua\ = i
- | \(lua expr "vars.body.value") as lua\
- | ::continue_for::
- | ::continue_\nomsu "var_to_lua_identifier" [%var]\::
- |end
- |::break_for::
- |::break_\nomsu "var_to_lua_identifier" [%var]\::
-macro block [for %var from %start to %stop %body] =:
- %thunk =: :for %var from %start to %stop by 1 %body
- lua block ".."
- |for i,x in ipairs(vars.thunk.value) do
- | if x.type == 'Var' then vars.thunk.type == vars[x.value] end
- |end
- |return compiler:run_macro(vars.thunk, 'Statement')
-
-macro block [for all %start to %stop by %step %body] =:
- # This trashes the loop variables, just like in Python.
- ".."
- |for i=\%start as lua\,\%stop as lua\,\%step as lua\ do
- | vars[''] = i
- | \(lua expr "vars.body.value") as lua\
- | ::continue_for::
- | ::continue_\nomsu "var_to_lua_identifier" [%]\::
- |end
- |::break_for::
- |::break_\nomsu "var_to_lua_identifier" [%]\::
-macro block [for %var from %start to %stop %body] =:
- %thunk =: :for %var from %start to %stop by 1 %body
- lua block ".."
- |for i,x in ipairs(vars.thunk.value) do
- | if x.type == 'Var' then vars.thunk.type == vars[x.value] end
- |end
- |return compiler:run_macro(vars.thunk, 'Statement')
-
-macro block [for %var in %iterable %body] =:
- %var-type =: lua expr "vars.var.type"
- assert (%var-type == "Var") ".."
- |For loop has the wrong type for the loop variable. Expected Var, but got: \%var-type\
+parse:
+ 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
# This trashes the loop variables, just like in Python.
- ".."
- |for i,value in ipairs(\%iterable as lua\) do
- | \%var as lua\ = value
- | \(lua expr "vars.body.value") as lua\
- | ::continue_for::
- | ::continue_\nomsu "var_to_lua_identifier" [%var]\::
- |end
- |::break_for::
- |::break_\nomsu "var_to_lua_identifier" [%var]\::
-
-macro block [for all %iterable %body] =:
- pass # TODO: fix compiler bug
+ | \(%var) = i
+ | \(lua expr "vars.body.value")
+ | ::continue_for::
+ | ::continue_\(nomsu "var_to_lua_identifier" [%var])::
+ |end
+ |::break_for::
+ |::break_\(nomsu "var_to_lua_identifier" [%var])::
+parse (for %var from %start to %stop %body) as: for %var from %start to %stop via 1 %body
+parse:
+ for all %start to %stop by %step %body
+ for all %start to %stop via %step %body
+..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.
- ".."|for i,value in ipairs(\%iterable as lua\) do
- | vars[''] = value
- | \(lua expr "vars.body.value") as lua\
- | ::continue_for::
- | ::continue_\nomsu "var_to_lua_identifier" [%]\::
- |end
- |::break_for::
- |::break_\nomsu "var_to_lua_identifier" [%]\::
+ | \(%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])::
+parse (for all %iterable %body) as: for % in %iterable %body
# Switch statement/multi-branch if
-macro block [when %body] =:
+parse (when %body) as lua block:
%result =: ""
%fallthroughs =: []
for %statement in (lua expr "vars.body.value.value"):
@@ -156,15 +118,18 @@ macro block [when %body] =:
go to next %statement
if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"):
- %result join=: ".."|
+ %result join=: ".."
+ |
|do
..else:
%condition =: %condition as lua
- for all %fallthroughs: %condition join=: ".."| or \% as lua\
- %result join=: ".."|
- |if \%condition\ then
- %result join=: ".."|
- | \(lua expr "vars.thunk.value") as lua\
+ for all %fallthroughs: %condition join= " or \(%)"
+ %result join=: ".."
+ |
+ |if \(%condition) then
+ %result join=: ".."
+ |
+ | \(lua expr "vars.thunk.value")
| goto finished_when
|end
@@ -174,8 +139,8 @@ macro block [when %body] =:
%result
# Switch statement
-macro block [when %branch-value == ? %body] =:
- %result =: ".."|local branch_value = \%branch-value as lua\
+parse (when %branch-value == ? %body) as lua block:
+ %result =: "local branch_value = \(%branch-value)"
%fallthroughs =: []
for %statement in (lua expr "vars.body.value.value"):
%func-call =: lua expr "vars.statement.value"
@@ -197,15 +162,18 @@ macro block [when %branch-value == ? %body] =:
go to next %statement
if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"):
- %result join=: ".."|
+ %result join=: ".."
+ |
|do
..else:
- %condition =: ".."|branch_value == (\%condition as lua\)
- for all %fallthroughs: %condition join=: ".."| or (branch_value == \% as lua\)
- %result join=: ".."|
+ %condition =: "branch_value == (\(%condition))"
+ for all %fallthroughs: %condition join= " or (branch_value == \(%))"
+ %result join=: ".."
+ |
|if \%condition\ then
- %result join=: ".."|
- | \(lua expr "vars.thunk.value") as lua\
+ %result join=: ".."
+ |
+ | \((lua expr "vars.thunk.value"))
| goto finished_when
|end
@@ -213,4 +181,3 @@ macro block [when %branch-value == ? %body] =:
%result join=: "\n::finished_when::"
%result
-
diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom
index e60a235..301d74b 100644
--- a/lib/metaprogramming.nom
+++ b/lib/metaprogramming.nom
@@ -27,7 +27,6 @@ lua code ".."
|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)
-parse (foo %x) as (baz %x)
lua code ".."
|nomsu:defmacro("lua expr %code", function(nomsu, vars)
@@ -71,17 +70,12 @@ parse (lua block %block) as:
parse (nomsu) as: lua expr "nomsu"
parse (nomsu's %key) as:
- lua expr "nomsu[\(%key as lua)]"
+ lua expr "nomsu['\(%key)']"
parse (nomsu %method %args) as:
- lua block ".."
- |local args = {"nomsu"}
- |for _,arg in ipairs(vars.args.value) do
- | table.insert(args, nomsu:tree_to_lua(arg))
- |end
- |local method_name = nomsu:repr(nomsu:tree_to_value(vars.method, vars))
- ..with value ".."
- |("nomsu[%s](%s)"):format(method_name, table.concat(args, ", "))
+ lua expr "nomsu['\(%method)'](nomsu, unpack(\(%args)))"
parse (repr %) as: nomsu "repr" [%]
+repr 5
+
# Get the source code for a function
rule (help %rule) =:
@@ -111,3 +105,18 @@ 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 (pass) as lua code: ""
+
+pass
diff --git a/lib/operators.nom b/lib/operators.nom
index f2bb7c2..4e7bd59 100644
--- a/lib/operators.nom
+++ b/lib/operators.nom
@@ -1,25 +1,25 @@
require "lib/metaprogramming.nom"
# Literals
-macro [true, yes] =: "true"
-macro [false, no] =: "false"
-macro [nil, null] =: "nil"
-macro [inf, infinity] =: "math.huge"
-macro [nan, NaN, not a number] =: "(0/0)"
-macro statement [nop, pass] =: ""
+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 ""
# Ternary operator
-macro [%if_expr if %condition else %else_expr] =:
- pass # TODO: Fix compiler bug that doesn't parse right here
+parse (%if_expr if %condition else %else_expr) as lua expr ".."
+ |(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)
because that breaks if %if_expr is falsey.
- ".."|(function(nomsu, vars)
- | if \%condition as lua\ then
- | return \%if_expr as lua\
- | else
- | return \%else_expr as lua\
- | end
- |end)(nomsu, vars)
+ | if \(%condition) then
+ | return \(%if_expr)
+ | else
+ | return \(%else_expr)
+ | end
+ |end)(nomsu, vars)
# Variable assignment operator, and += type versions
lua block ".."
@@ -64,11 +64,11 @@ lua block ".."
| end
| nomsu:defmacro("%a "..nomsu_alias.." %b", (function(nomsu, vars, kind)
| return "("..nomsu:tree_to_lua(vars.a).." "..op.." "..nomsu:tree_to_lua(vars.b)..")"
- | end), [[".."|(\\%a as lua\\ ]]..op..[[ \\%b as lua\\)]])
+ | end), [["(\\(%a) ]]..op..[[ \\(%b))"]])
|end
# == and != do equivalence checking, rather than identity checking
-macro [%a == %b] =: ".."|nomsu.utils.equivalent(\%a as lua\, \%b as lua\)
-macro [%a != %b] =: ".."|(not nomsu.utils.equivalent(\%a as lua\, \%b as lua\))
+parse (%a == %b) as lua expr "nomsu.utils.equivalent(\(%a), \(%b))"
+parse (%a != %b) as lua expr "(not nomsu.utils.equivalent(\(%a), \(%b)))"
# Commutative Operators defined for up to 8 operands
# TODO: work out solution for commutative operators using more clever macros
@@ -125,5 +125,5 @@ lua block ".."
|end
# Unary operators
-macro [- %a] =: ".."|-(\%a as lua\)
-macro [not %a] =: ".."|not (\%a as lua\)
+parse (- %a) as lua expr "-(\(%a))"
+parse (not %a) as lua expr "not (\(%a))"
diff --git a/lib/utils.nom b/lib/utils.nom
index 1afc33a..11596f1 100644
--- a/lib/utils.nom
+++ b/lib/utils.nom
@@ -1,73 +1,66 @@
require "lib/metaprogramming.nom"
# Error functions
-rule [error!, panic!, fail!, abort!] =:
- nomsu "error"[]
-rule [error %msg] =:
+rule (error!; panic!; fail!; abort!) =:
+ nomsu "error" []
+rule (error %msg) =:
nomsu "error"[%msg]
-macro statement [assert %condition] =: ".."
- |if not (\%condition as lua\) then
+parse (assert %condition) as: lua code ".."
+ |if not (\(%condition)) then
| nomsu:error()
|end
-macro statement [assert %condition %msg] =: ".."
- |if not (\%condition as lua\) then
- | nomsu:error(\%msg as lua\)
+parse (assert %condition %msg) as: lua code ".."
+ |if not (\(%condition)) then
+ | nomsu:error(\(%msg))
|end
-macro statement [show generated lua %block] =: ".."
- |nomsu:writeln(\lua expr "nomsu:repr(nomsu:tree_to_lua(vars.block.value))"\)
+parse (show generated lua %block) as: lua code ".."
+ |nomsu:writeln(\(repr (nomsu "tree_to_lua" [%block])))
# String functions
-rule [join %strs] =:
+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] =:
+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)
-macro [capitalize %str, %str capitalized] =: ".."
- |(\%str as lua\):gsub("%l", string.upper, 1)
+parse (capitalize %str; %str capitalized) as: lua expr "(\(%str)):gsub('%l', string.upper, 1)"
-macro [repr %obj] =:
- ".."|nomsu:repr(\%obj as lua\)
-
-macro [%obj as string] =:
- ".."|nomsu.utils.repr_if_not_string(\%obj as lua\)
-
-macro [say %str] =:
- ".."|nomsu:writeln(nomsu.utils.repr_if_not_string(\%str as lua\))
+parse (say %str) as: lua block ".."
+ |nomsu:writeln(nomsu.utils.repr_if_not_string(\(%str)))
# Number ranges
-macro [%start to %stop] =: ".."
- |nomsu.utils.range(\%start as lua\, \%stop as lua\)
-macro [%start to %stop by %step, %start to %stop via %step] =: ".."
- |nomsu.utils.range(\%start as lua\, \%stop as lua\, \%step as lua\)
+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))
# Common utility functions
-macro [random number, random, rand] =: "math.random()"
-macro [random int %n, random integer %n, randint %n] =: ".."|math.random(\%n as lua\)
-macro [random from %low to %high, random number from %low to %high, rand %low %high] =: ".."
- |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)]
-macro [sum of %items, sum %items] =: ".."|nomsu.utils.sum(\%items as lua\)
-macro [product of %items, product %items] =: ".."|nomsu.utils.product(\%items as lua\)
-macro [all of %items] =: ".."|nomsu.utils.all(\%items as lua\)
-macro [any of %items] =: ".."|nomsu.utils.any(\%items as lua\)
+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))"
+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.
-rule [avg of %items, average of %items] =:
- lua expr ".."|(nomsu.utils.sum(vars.items)/#vars.items)
-macro [min of %items, smallest of %items, lowest of %items] =:
- ".."|nomsu.utils.min(\%items as lua\)
-macro [max of %items, biggest of %items, largest of %items, highest of %items] =:
- ".."|nomsu.utils.min(\%items as lua\)
-macro [min of %items with respect to %keys] =:
- ".."|nomsu.utils.min(\%items as lua\, \%keys as lua\)
-macro [max of %items with respect to %keys] =:
- ".."|nomsu.utils.max(\%items as lua\, \%keys 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))"
diff --git a/nomsu.lua b/nomsu.lua
index 9d79c3a..8bfb83e 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -7,10 +7,6 @@ do
local _obj_0 = table
insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat
end
-local pcall
-pcall = function(fn, ...)
- return true, fn(...)
-end
lpeg.setmaxstack(10000)
local P, V, S, Cg, C, Cp, B, Cmt
P, V, S, Cg, C, Cp, B, Cmt = lpeg.P, lpeg.V, lpeg.S, lpeg.Cg, lpeg.C, lpeg.Cp, lpeg.B, lpeg.Cmt
@@ -65,13 +61,13 @@ local nomsu = [=[ file <- ({ {| shebang?
inline_block <- ({ {| "(" inline_statements ")" |} }) -> Block
eol_block <- ({ {| ":" %ws? noeol_statements eol |} }) -> Block
indented_block <- ({ {| (":" / "(..)") indent
- statements
+ statements (nodent statements)*
(dedent / (({.+} ("" -> "Error while parsing block")) => error))
|} }) -> Block
- inline_nomsu <- ({ ("\" inline_block ) }) -> Nomsu
- eol_nomsu <- ({ ("\" eol_block ) }) -> Nomsu
- indented_nomsu <- ({ ("\" {indented_block} ) }) -> Nomsu
+ inline_nomsu <- ({ ("\" inline_expression) }) -> Nomsu
+ eol_nomsu <- ({ ("\" noeol_expression) }) -> Nomsu
+ indented_nomsu <- ({ ("\" expression) }) -> Nomsu
inline_expression <- number / variable / inline_string / inline_list / inline_block / inline_nomsu
noeol_expression <- indented_string / indented_block / indented_nomsu / indented_list / inline_expression
@@ -192,27 +188,15 @@ do
return self:write("\n")
end,
def = function(self, invocation, thunk, src)
- if type(invocation) ~= 'string' then
- self:error("Invocation should be string, not: " .. tostring(repr(invocation)))
- end
+ local stub, arg_names = self:get_stub(invocation)
+ assert(stub, "NO STUB FOUND: " .. tostring(repr(invocation)))
if self.debug then
- self:writeln("Defining rule: " .. tostring(repr(invocation)))
+ self:writeln("Defining rule: " .. tostring(repr(stub)) .. " with args " .. tostring(repr(arg_names)))
end
- local stub = invocation:gsub("'", " '"):gsub("%%%S+", "%%"):gsub("%s+", " ")
- local args
- do
- local _accum_0 = { }
- local _len_0 = 1
- for arg in invocation:gmatch("%%(%S[^%s']*)") do
- _accum_0[_len_0] = arg
- _len_0 = _len_0 + 1
- end
- args = _accum_0
- end
- for i = 1, #args - 1 do
- for j = i + 1, #args do
- if args[i] == args[j] then
- self:error("Duplicate argument in function def: " .. tostring(args[i]))
+ for i = 1, #arg_names - 1 do
+ for j = i + 1, #arg_names do
+ if arg_names[i] == arg_names[j] then
+ self:error("Duplicate argument in function " .. tostring(stub) .. ": '" .. tostring(arg_names[i]) .. "'")
end
end
end
@@ -220,11 +204,11 @@ do
local _with_0 = {
thunk = thunk,
invocation = invocation,
- args = args,
+ arg_names = arg_names,
src = src,
is_macro = false
}
- self.defs[invocation] = _with_0
+ self.defs[stub] = _with_0
local _ = nil
return _with_0
end
@@ -236,30 +220,31 @@ do
return _with_0
end
end,
- call = function(self, alias, ...)
- local def = self.defs[alias]
+ call = function(self, stub, ...)
+ local def = self.defs[stub]
if def == nil then
- self:error("Attempt to call undefined function: " .. tostring(alias))
+ self:error("Attempt to call undefined function: " .. tostring(stub))
end
if def.is_macro and self.callstack[#self.callstack] ~= "#macro" then
- self:error("Attempt to call macro at runtime: " .. tostring(alias) .. "\nThis can be caused by using a macro in a function that is defined before the macro.")
+ self:error("Attempt to call macro at runtime: " .. tostring(stub) .. "\nThis can be caused by using a macro in a function that is defined before the macro.")
end
if not (self:check_permission(def)) then
- self:error("You do not have the authority to call: " .. tostring(alias))
+ self:error("You do not have the authority to call: " .. tostring(stub))
end
- local thunk, args
- thunk, args = def.thunk, def.args
+ local thunk, arg_names
+ thunk, arg_names = def.thunk, def.arg_names
+ local args
do
local _tbl_0 = { }
- for i, name in ipairs(args) do
+ for i, name in ipairs(arg_names) do
_tbl_0[name] = select(i, ...)
end
args = _tbl_0
end
if self.debug then
- self:writeln("Calling " .. tostring(repr(alias)) .. " with args: " .. tostring(repr(args)))
+ self:writeln("Calling " .. tostring(repr(stub)) .. " with args: " .. tostring(repr(args)))
end
- insert(self.callstack, alias)
+ insert(self.callstack, stub)
local rets = {
thunk(self, args)
}
@@ -270,10 +255,9 @@ do
if kind == nil then
kind = "Expression"
end
- local args, alias
- alias, args = self:get_alias(tree)
+ local stub, args = self:get_stub(tree)
insert(self.callstack, "#macro")
- local expr, statement = self:call(alias, unpack(args))
+ local expr, statement = self:call(stub, unpack(args))
remove(self.callstack)
return expr, statement
end,
@@ -319,13 +303,17 @@ do
run = function(self, src, filename)
local tree = self:parse(src, filename)
assert(tree, "Tree failed to compile: " .. tostring(src))
- assert(tree.type == "File")
+ assert(tree.type == "File", "Attempt to run non-file: " .. tostring(tree.type))
local buffer = { }
local vars = { }
local return_value = nil
local _list_0 = tree.value
for _index_0 = 1, #_list_0 do
local statement = _list_0[_index_0]
+ if self.debug then
+ self:writeln("RUNNING TREE:")
+ self:print_tree(statement)
+ end
local ok, expr, statements = pcall(self.tree_to_lua, self, statement)
if not ok then
self:writeln("Error occurred in statement:\n" .. tostring(statement.src))
@@ -350,7 +338,7 @@ do
end
if not ok then
self:writeln("Error occurred in statement:\n" .. tostring(statement.src))
- self:error(return_value)
+ self:error(repr(return_value))
end
insert(buffer, tostring(statements or '') .. "\n" .. tostring(expr and "ret = " .. tostring(expr) or ''))
end
@@ -372,6 +360,7 @@ do
tree_to_lua = function(self, tree)
assert(tree, "No tree provided.")
if not tree.type then
+ self:writeln(debug.traceback())
self:error("Invalid tree: " .. tostring(repr(tree)))
end
local _exp_0 = tree.type
@@ -379,15 +368,12 @@ do
return error("Should not be converting File to lua through this function.")
elseif "Nomsu" == _exp_0 then
return repr(tree.value), nil
- elseif "Block" == _exp_0 then
+ elseif "Thunk" == _exp_0 then
local lua_bits = { }
- local _list_0 = tree.value
+ local _list_0 = tree.value.value
for _index_0 = 1, #_list_0 do
local arg = _list_0[_index_0]
local expr, statement = self:tree_to_lua(arg)
- if expr and not statement and #tree.value == 1 then
- return expr, nil
- end
if statement then
insert(lua_bits, statement)
end
@@ -395,18 +381,34 @@ do
insert(lua_bits, "ret = " .. tostring(expr))
end
end
- return ([[ function(nomsu, vars)
+ return ([[ (function(nomsu, vars)
local ret
%s
return ret
- end]]):format(concat(lua_bits, "\n"))
+ end)]]):format(concat(lua_bits, "\n"))
+ elseif "Block" == _exp_0 then
+ if #tree.value == 0 then
+ return "nil", nil
+ end
+ if #tree.value == 1 then
+ local expr, statement = self:tree_to_lua(tree.value[1])
+ if not statement then
+ return expr, nil
+ end
+ end
+ local thunk_lua = self:tree_to_lua({
+ type = "Thunk",
+ value = tree,
+ src = tree.src
+ })
+ return ("%s(nomsu, vars)"):format(thunk_lua), nil
elseif "FunctionCall" == _exp_0 then
- local alias = self:get_alias(tree)
- if self.defs[alias] and self.defs[alias].is_macro then
+ local stub = self:get_stub(tree)
+ if self.defs[stub] and self.defs[stub].is_macro then
return self:run_macro(tree, "Expression")
end
local args = {
- repr(alias)
+ repr(stub)
}
local _list_0 = tree.value
for _index_0 = 1, #_list_0 do
@@ -460,6 +462,9 @@ do
if string_buffer ~= "" then
insert(concat_parts, repr(string_buffer))
end
+ if #concat_parts == 0 then
+ return "''", nil
+ end
return "(" .. tostring(concat(concat_parts, "..")) .. ")", nil
elseif "List" == _exp_0 then
local items = { }
@@ -481,25 +486,49 @@ do
return self:error("Unknown/unimplemented thingy: " .. tostring(tree.type))
end
end,
- print_tree = function(self, tree, ind)
- if ind == nil then
- ind = ""
+ walk_tree = function(self, tree, depth)
+ if depth == nil then
+ depth = 0
end
+ coroutine.yield(tree, depth)
if type(tree) ~= 'table' or not tree.type then
- self:writeln(tostring(ind) .. tostring(repr(tree)))
return
end
- self:writeln(tostring(ind) .. tostring(tree.type) .. ":")
local _exp_0 = tree.type
- if "List" == _exp_0 or "File" == _exp_0 or "Block" == _exp_0 or "FunctionCall" == _exp_0 or "String" == _exp_0 then
+ if "List" == _exp_0 or "File" == _exp_0 or "Nomsu" == _exp_0 or "Block" == _exp_0 or "FunctionCall" == _exp_0 or "String" == _exp_0 then
local _list_0 = tree.value
for _index_0 = 1, #_list_0 do
local v = _list_0[_index_0]
- self:print_tree(v, ind .. " ")
+ self:walk_tree(v, depth + 1)
end
else
- return self:print_tree(tree.value, ind .. " ")
+ self:walk_tree(tree.value, depth + 1)
+ end
+ return nil
+ end,
+ print_tree = function(self, tree)
+ for node, depth in coroutine.wrap(function()
+ return self:walk_tree(tree)
+ end) do
+ if type(node) ~= 'table' or not node.type then
+ self:writeln((" "):rep(depth) .. repr(node))
+ else
+ self:writeln(tostring((" "):rep(depth)) .. tostring(node.type) .. ":")
+ end
+ end
+ end,
+ tree_to_str = function(self, tree)
+ local bits = { }
+ for node, depth in coroutine.wrap(function()
+ return self:walk_tree(tree)
+ end) do
+ if type(node) ~= 'table' or not node.type then
+ insert(bits, ((" "):rep(depth) .. repr(node)))
+ else
+ insert(bits, (tostring((" "):rep(depth)) .. tostring(node.type) .. ":"))
+ end
end
+ return concat(bits, "\n")
end,
replaced_vars = function(self, tree, vars)
if type(tree) ~= 'table' then
@@ -510,8 +539,8 @@ do
if vars[tree.value] then
tree = vars[tree.value]
end
- elseif "File" == _exp_0 or "Thunk" == _exp_0 or "Statement" == _exp_0 or "Block" == _exp_0 or "List" == _exp_0 or "FunctionCall" == _exp_0 or "String" == _exp_0 then
- local new_value = self:replaced_vars(tree.value)
+ elseif "File" == _exp_0 or "Nomsu" == _exp_0 or "Thunk" == _exp_0 or "Block" == _exp_0 or "List" == _exp_0 or "FunctionCall" == _exp_0 or "String" == _exp_0 then
+ local new_value = self:replaced_vars(tree.value, vars)
if new_value ~= tree.value then
do
local _tbl_0 = { }
@@ -526,7 +555,7 @@ do
local new_values = { }
local any_different = false
for k, v in pairs(tree) do
- new_values[k] = self:replaced_vars(v)
+ new_values[k] = self:replaced_vars(v, vars)
any_different = any_different or (new_values[k] ~= tree[k])
end
if any_different then
@@ -535,84 +564,47 @@ do
end
return tree
end,
- get_alias = function(self, x)
+ get_stub = function(self, x)
if not x then
- self:error("Nothing to get alias from")
+ self:error("Nothing to get stub from")
end
if type(x) == 'string' then
- local alias = x:gsub("'", " '"):gsub("%%%S+", "%%"):gsub("%s+", " ")
+ local stub = x:gsub("'", " '"):gsub("%%%S+", "%%"):gsub("%s+", " ")
local args
do
local _accum_0 = { }
local _len_0 = 1
- for arg in x:gmatch("%%(%S[^%s']*)") do
+ for arg in x:gmatch("%%([^%s']*)") do
_accum_0[_len_0] = arg
_len_0 = _len_0 + 1
end
args = _accum_0
end
- return alias, args
+ return stub, args
end
local _exp_0 = x.type
if "String" == _exp_0 then
- return self:get_alias(x.value)
- elseif "Statement" == _exp_0 then
- return self:get_alias(x.value)
+ return self:get_stub(x.value)
elseif "FunctionCall" == _exp_0 then
- local alias, args = { }, { }, { }
+ local stub, args = { }, { }, { }
local _list_0 = x.value
for _index_0 = 1, #_list_0 do
local token = _list_0[_index_0]
local _exp_1 = token.type
if "Word" == _exp_1 then
- insert(alias, token.value)
+ insert(stub, token.value)
elseif "Var" == _exp_1 then
- insert(alias, "%")
+ insert(stub, "%")
insert(args, token.value)
else
- insert(alias, "%")
+ insert(stub, "%")
insert(args, token)
end
end
- return concat(alias, " "), args
- end
- end,
- get_aliases = function(self, x)
- if not x then
- self:error("Nothing to get aliases from")
- end
- if type(x) == 'string' then
- local alias, args = self:get_alias(x)
- return {
- [alias] = args
- }
- end
- local _exp_0 = x.type
- if "String" == _exp_0 then
- return self:get_aliases({
- x.value
- })
- elseif "Statement" == _exp_0 then
- return self:get_aliases({
- x.value
- })
- elseif "FunctionCall" == _exp_0 then
- return self:get_aliases({
- x
- })
- elseif "List" == _exp_0 then
- x = x.value
+ return concat(stub, " "), args
elseif "Block" == _exp_0 then
- x = x.value
- end
- do
- local _with_0 = { }
- for _index_0 = 1, #x do
- local y = x[_index_0]
- local alias, args = self:get_alias(y)
- _with_0[alias] = args
- end
- return _with_0
+ self:writeln(debug.traceback())
+ return self:error("Please pass in a single line from a block, not the whole thing:\n" .. tostring(self:tree_to_str(x)))
end
end,
var_to_lua_identifier = function(self, var)
@@ -629,7 +621,9 @@ do
end,
error = function(self, ...)
self:writeln("ERROR!")
- self:writeln(...)
+ if select(1, ...) then
+ self:writeln(...)
+ end
self:writeln("Callstack:")
for i = #self.callstack, 1, -1 do
self:writeln(" " .. tostring(self.callstack[i]))
@@ -639,17 +633,22 @@ do
return error()
end,
initialize_core = function(self)
- self:defmacro("lua code %statements with value %value", function(self, vars)
- local inner_vars = setmetatable({ }, {
- __index = function(_, key)
- return "vars[" .. tostring(repr(key)) .. "]"
- end
- })
- local statements = self:tree_to_value(vars.statements, inner_vars)
- local value = self:tree_to_value(vars.value, inner_vars)
- return value, statements
- end)
- self:def("require %filename", function(self, vars)
+ local lua_code
+ lua_code = function(self, vars)
+ local inner_vars = vars
+ local lua = self:tree_to_value(vars.code, inner_vars)
+ return nil, lua
+ end
+ self:defmacro("lua code %code", lua_code)
+ local lua_value
+ lua_value = function(self, vars)
+ local inner_vars = vars
+ local lua = self:tree_to_value(vars.code, inner_vars)
+ return lua, nil
+ end
+ self:defmacro("lua value %code", lua_value)
+ local _require
+ _require = function(self, vars)
if not self.loaded_files[vars.filename] then
local file = io.open(vars.filename)
if not file then
@@ -658,14 +657,17 @@ do
self.loaded_files[vars.filename] = (self:run(file:read('*a'), vars.filename)) or true
end
return self.loaded_files[vars.filename]
- end)
- return self:def("run file %filename", function(self, vars)
+ end
+ self:def("require %filename", _require)
+ local run_file
+ run_file = function(self, vars)
local file = io.open(vars.filename)
if not file then
self:error("File does not exist: " .. tostring(vars.filename))
end
return self:run(file:read('*a'), vars.filename)
- end)
+ end
+ return self:def("run file %filename", run_file)
end
}
_base_0.__index = _base_0
@@ -726,7 +728,6 @@ do
end
if arg and arg[1] then
local c = NomsuCompiler()
- c.debug = true
local input = io.open(arg[1]):read("*a")
local _write = c.write
if arg[2] == "-" then
diff --git a/nomsu.moon b/nomsu.moon
index 497bda1..9ba3856 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -70,7 +70,7 @@ nomsu = [=[
inline_block <- ({ {| "(" inline_statements ")" |} }) -> Block
eol_block <- ({ {| ":" %ws? noeol_statements eol |} }) -> Block
indented_block <- ({ {| (":" / "(..)") indent
- statements
+ statements (nodent statements)*
(dedent / (({.+} ("" -> "Error while parsing block")) => error))
|} }) -> Block
@@ -329,6 +329,8 @@ class NomsuCompiler
end)]])\format(concat lua_bits, "\n")
when "Block"
+ if #tree.value == 0
+ return "nil",nil
if #tree.value == 1
expr,statement = @tree_to_lua tree.value[1]
if not statement
@@ -367,6 +369,8 @@ class NomsuCompiler
if string_buffer ~= ""
insert concat_parts, repr(string_buffer)
+ if #concat_parts == 0
+ return "''", nil
return "(#{concat(concat_parts, "..")})", nil
when "List"
@@ -502,13 +506,13 @@ class NomsuCompiler
initialize_core: =>
-- Sets up some core functionality
lua_code = (vars)=>
- inner_vars = setmetatable({}, {__index:(_,key)-> "vars[#{repr(key)}]"})
+ inner_vars = 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 = setmetatable({}, {__index:(_,key)-> "vars[#{repr(key)}]"})
+ inner_vars = vars--setmetatable({}, {__index:(_,key)-> "vars[#{repr(key)}]"})
lua = @tree_to_value(vars.code, inner_vars)
return lua, nil
@defmacro "lua value %code", lua_value
diff --git a/utils.lua b/utils.lua
index 84a0b54..2f6f25a 100644
--- a/utils.lua
+++ b/utils.lua
@@ -1,6 +1,9 @@
local utils
utils = {
is_list = function(t)
+ if type(t) ~= 'table' then
+ return false
+ end
local i = 1
for _ in pairs(t) do
if t[i] == nil then