funcall and indexing is good

This commit is contained in:
leaf corcoran 2011-05-21 15:26:46 -07:00
parent eb0f05cc3c
commit 4936446f1c
7 changed files with 165 additions and 36 deletions

View File

@ -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
}

View File

@ -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",

View File

@ -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)

View File

@ -1,5 +0,0 @@
x = -> print what

50
tests/inputs/syntax.moon Normal file
View File

@ -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]

View File

@ -1 +0,0 @@
local x = function() print(what) end

27
tests/outputs/syntax.lua Normal file
View File

@ -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]