From 4936446f1c7639bcac0625c77ed6f5ac2398db1a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 21 May 2011 15:26:46 -0700 Subject: [PATCH] funcall and indexing is good --- moonscript/compile.lua | 59 ++++++++++++++++++++++++++++++---------- moonscript/parse.lua | 48 +++++++++++++++++++++++--------- test.lua | 11 ++++++-- tests/inputs/first.moon | 5 ---- tests/inputs/syntax.moon | 50 ++++++++++++++++++++++++++++++++++ tests/outputs/first.lua | 1 - tests/outputs/syntax.lua | 27 ++++++++++++++++++ 7 files changed, 165 insertions(+), 36 deletions(-) delete mode 100644 tests/inputs/first.moon create mode 100644 tests/inputs/syntax.moon delete mode 100644 tests/outputs/first.lua create mode 100644 tests/outputs/syntax.lua diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 0014ba4..bfa24ed 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -9,42 +9,61 @@ require "util" -- end, _G) -- }) - local map, bind = util.map, util.bind local indent_char = " " +function ntype(node) + if type(node) ~= "table" then return "value" end + return node[1] +end + local compilers = { _indent = 0, ichar = function(self) return indent_char:rep(self._indent) end, - fncall = function(self, node) - local _, name, args = unpack(node) - return name .. self:args(args) + chain = function(self, node) + local callee = node[2] + local actions = {} + for i = 3,#node do + local t, arg = unpack(node[i]) + if t == "call" then + table.insert(actions, "("..table.concat(self:values(arg), ', ')..")") + elseif t == "index" then + table.insert(actions, "["..self:value(arg).."]") + else + error("Unknown chain action: "..t) + end + end + + local callee_value = self:value(callee) + if ntype(callee) == "exp" then + callee_value = "("..callee_value..")" + end + + return callee_value..table.concat(actions) end, + fndef = function(self, node) local _, args, block = unpack(node) - if #block == 1 then + if #block == 0 then + return "function() end" + elseif #block == 1 then return ("function(%s) %s end"):format( table.concat(args, ", "), self:value(block[1])) end return ("function(%s)\n%s\n%send"):format( table.concat(args, ", "), self:block(block, 1), self:ichar()) end, - args = function(self, node) - local values = {} - for _, v in ipairs(node) do - table.insert(values, self:value(v)) - end - return "(" .. table.concat(values, ", ") .. ")" - end, + ["if"] = function(self, node) local _, cond, block = unpack(node) return ("if %s then\n%s\n%send"):format( self:value(cond), self:block(block, 1), self:ichar()) end, + block = function(self, node, inc) if inc then self._indent = self._indent + inc end local lines = {} @@ -55,11 +74,12 @@ local compilers = { if inc then self._indent = self._indent - inc end return table.concat(lines, "\n") end, + assign = function(self, node) local _, names, values = unpack(node) - - return "local "..table.concat(names, ", ").." = "..table.concat(map(values, bind(self, "value")), ", ") + return "local "..table.concat(names, ", ").." = "..table.concat(self:values(values), ", ") end, + exp = function(self, node) local values = {} for i = 2, #node do @@ -67,6 +87,7 @@ local compilers = { end return table.concat(values, " ") end, + value = function(self, node) if type(node) == "table" then local op = unpack(node) @@ -74,6 +95,16 @@ local compilers = { end return node + end, + + -- a list of values + values = function(self, items, start) + start = start or 1 + local compiled = {} + for i = start,#items do + table.insert(compiled, self:value(items[i])) + end + return compiled end } diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 248069f..5dfbd1f 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -8,6 +8,8 @@ local compile = require"moonscript.compile" local dump = require"moonscript.dump" local data = require"moonscript.data" +local ntype = compile.ntype + local Stack = data.Stack local function count_indent(str) @@ -24,16 +26,16 @@ local C, Ct, Cmt = lpeg.C, lpeg.Ct, lpeg.Cmt local White = S" \t\n"^0 local Space = S" \t"^0 +local ASpace = S" \t"^1 local Break = S"\n" local Stop = Break + -1 local Indent = C(S"\t "^0) / count_indent -local _Name = C(R("az", "AZ", "__") * R("az", "AZ", "__")^0) -local Name = _Name * Space -local Num = C(R("09")^1) / tonumber * Space +local Name = Space * C(R("az", "AZ", "__") * R("az", "AZ", "__")^0) +local Num = Space * C(R("09")^1) / tonumber -local FactorOp = lpeg.C(S"+-") * Space -local TermOp = lpeg.C(S"*/%") * Space +local FactorOp = Space * lpeg.C(S"+-") +local TermOp = Space * lpeg.C(S"*/%") local function wrap(fn) local env = getfenv(fi) @@ -94,7 +96,7 @@ local build_grammar = wrap(function() local _indent = Stack(0) -- current indent - local last_pos = 0 -- used to keep track of error + local last_pos = 0 -- used to know where to report error local function check_indent(str, pos, indent) last_pos = pos return _indent:top() == indent @@ -115,19 +117,34 @@ local build_grammar = wrap(function() local keywords = {} local function key(word) keywords[word] = true - return word * Space + return Space * word end local function sym(chars) - return chars * Space + return Space * chars + end + + local function symx(chars) + return chars + end + + local function flatten_func(callee, args) + if #args == 0 then return callee end + + args = {"call", args} + if ntype(callee) == "chain" then + table.insert(callee, args) + return callee + end + + return {"chain", callee, args} end -- make sure name is not a keyword - local _Name = Cmt(Name, function(str, pos, name) + local Name = Cmt(Name, function(str, pos, name) if keywords[name] then return false end return true, name end) - local Name = _Name * Space local g = lpeg.P{ File, @@ -141,15 +158,20 @@ local build_grammar = wrap(function() InBlock = #Cmt(Indent, advance_indent) * Block * OutBlock, OutBlock = Cmt("", pop_indent), - FunCall = _Name * (sym"(" * Ct(ExpList^-1) * sym")" + Space * Ct(ExpList)) / mark"fncall", - If = key"if" * Exp * Body / mark"if", Assign = Ct(NameList) * sym"=" * Ct(ExpList) / mark"assign", Exp = Ct(Term * (FactorOp * Term)^0) / flatten_or_mark"exp", Term = Ct(Value * (TermOp * Value)^0) / flatten_or_mark"exp", - Value = Assign + FunLit + FunCall + Num + Name + TableLit, + + Value = Assign + FunLit + (FunCall + Callable) * Ct(ExpList^0) / flatten_func + Num, + + Callable = Name + Parens, + Parens = sym"(" * Exp * sym")", + + -- a plain function/index + FunCall = Callable * (symx"(" * Ct(ExpList^-1)/mark"call" * sym")" + symx"[" * Exp/mark"index" * sym"]")^1 / mark"chain", TableLit = sym"{" * Ct(ExpList^-1) * sym"}" / mark"list", diff --git a/test.lua b/test.lua index ed340cb..1d2260f 100755 --- a/test.lua +++ b/test.lua @@ -16,7 +16,7 @@ local function diff(a_fname, b_fname) return io.popen(diff_tool.." ".. a_fname.." "..b_fname, "r"):read("*a") end -local function input_name(name) return opts.in_dir .. "/" .. name end +local function input_name(name) return opts.in_dir.."/".. name end local function output_name(name) return opts.out_dir.."/"..name:match(opts.input_pattern)..opts.output_ext end @@ -28,7 +28,11 @@ local function run_file(name) local parse = require "moonscript.parse" local compile = require "moonscript.compile" - return compile.tree(parse.string(file_str)) + local tree, err = parse.string(file_str) + if not tree then + error("Compile error in "..name.."\n"..err) + end + return compile.tree(tree) end local function inputs(pattern) @@ -53,6 +57,7 @@ local actions = { end end, run = function(pattern) + local failed = false local tests_run, result = 0 for file in inputs(pattern) do tests_run = tests_run + 1 @@ -86,7 +91,7 @@ local actions = { print("No tests matching pattern:", pattern) end elseif tests_run == 1 then - print(result) + -- print(result) end end, list = function(pattern) diff --git a/tests/inputs/first.moon b/tests/inputs/first.moon deleted file mode 100644 index 5629476..0000000 --- a/tests/inputs/first.moon +++ /dev/null @@ -1,5 +0,0 @@ - - - -x = -> print what - diff --git a/tests/inputs/syntax.moon b/tests/inputs/syntax.moon new file mode 100644 index 0000000..a7c75f5 --- /dev/null +++ b/tests/inputs/syntax.moon @@ -0,0 +1,50 @@ + + +x = -> print what + + +-> + +-> -> -> +go to the barn + +open -> the -> door + +open -> + the door + hello = -> + my func + +h = -> hi + +eat ->, world + +a = 1 + 2* 3 / 6 + +a, bunch, go, here = another, world + +func arg1, arg2, another, arg3 + +here, we = () ->, yeah +the, different = () -> approach, yeah + +dad() +dad(lord) +hello(one,two)() +(5 + 5)(world) + +fun(a)(b) + +fun(a) b + +fun(a) b, bad hello + +hello world what are you doing here + + +what(the)[3243] world, yeck heck + +hairy[hands][are](gross) okay okay[world] + +(get[something] + 5)[years] + diff --git a/tests/outputs/first.lua b/tests/outputs/first.lua deleted file mode 100644 index 715b323..0000000 --- a/tests/outputs/first.lua +++ /dev/null @@ -1 +0,0 @@ -local x = function() print(what) end \ No newline at end of file diff --git a/tests/outputs/syntax.lua b/tests/outputs/syntax.lua new file mode 100644 index 0000000..c3e68bb --- /dev/null +++ b/tests/outputs/syntax.lua @@ -0,0 +1,27 @@ +local x = function() print(what) end +function() end +function() function() function() end end end +go(to(the(barn))) +open(function() the(function() door end) end) +open(function() + the(door) + local hello = function() my(func) end +end) +local h = function() hi end +eat(function() end, world) +local a = 1 + 2 * 3 / 6 +local a, bunch, go, here = another, world +func(arg(1, arg(2, another, arg(3)))) +local here, we = function() end, yeah +local the, different = function() approach end, yeah +dad() +dad(lord) +hello(one, two)() +(5 + 5)(world) +fun(a)(b) +fun(a)(b) +fun(a)(b, bad(hello)) +hello(world(what(are(you(doing(here)))))) +what(the)[3243](world, yeck(heck)) +hairy[hands][are](gross)(okay(okay[world])) +(get[something] + 5)[years] \ No newline at end of file