mirror of
https://github.com/leafo/moonscript.git
synced 2025-01-09 00:04:22 +00:00
indentation parsing and if
This commit is contained in:
parent
ee8e51c339
commit
2f09192a6a
@ -5,6 +5,10 @@ require"util"
|
||||
require"lpeg"
|
||||
|
||||
require"moonscript.compile"
|
||||
require"moonscript.dump"
|
||||
require"moonscript.data"
|
||||
|
||||
local Stack = data.Stack
|
||||
|
||||
local function count_indent(str)
|
||||
local sum = 0
|
||||
@ -16,10 +20,11 @@ local function count_indent(str)
|
||||
end
|
||||
|
||||
local R, S, V, P = lpeg.R, lpeg.S, lpeg.V, lpeg.P
|
||||
local C, Ct = lpeg.C, lpeg.Ct
|
||||
local C, Ct, Cmt = lpeg.C, lpeg.Ct, lpeg.Cmt
|
||||
|
||||
local Space = S" \t"^0
|
||||
local Break = S"\n" + -1
|
||||
local Break = S"\n"
|
||||
local Stop = Break + -1
|
||||
local Indent = C(S"\t "^0) / count_indent
|
||||
local ArgDelim = "," * Space
|
||||
|
||||
@ -53,6 +58,14 @@ function mark(name)
|
||||
end
|
||||
end
|
||||
|
||||
function got(what)
|
||||
return function(...)
|
||||
print("got "..tostring(what))
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function flatten(tbl)
|
||||
if #tbl == 1 then
|
||||
return tbl[1]
|
||||
@ -61,7 +74,7 @@ function flatten(tbl)
|
||||
end
|
||||
|
||||
local build_grammar = wrap(function()
|
||||
local err_msg = "Failed to compile, line:\n [%d] >> %s"
|
||||
local err_msg = "Failed to compile, line:\n [%d] >> %s (%d)"
|
||||
local line = 1
|
||||
local function line_count(subject, pos, str)
|
||||
for _ in str:gmatch("\n") do
|
||||
@ -71,18 +84,48 @@ local build_grammar = wrap(function()
|
||||
return true
|
||||
end
|
||||
|
||||
local Space = lpeg.Cmt(Space, line_count)
|
||||
local Break = lpeg.Cmt(Break, line_count)
|
||||
local Space = Cmt(Space, line_count)
|
||||
local Break = Cmt(Break, line_count)
|
||||
|
||||
local _indent = Stack(0) -- current indent
|
||||
|
||||
local function check_indent(str, pos, indent)
|
||||
return _indent:top() == indent
|
||||
end
|
||||
|
||||
local function advance_indent(str, pos, indent)
|
||||
if indent > _indent:top() then
|
||||
_indent:push(indent)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function pop_indent(str, pos)
|
||||
if not _indent:pop() then error("unexpected outdent") end
|
||||
return true
|
||||
end
|
||||
|
||||
local keywords = {}
|
||||
local function key(word)
|
||||
keywords[word] = true
|
||||
return word * Space
|
||||
end
|
||||
|
||||
local g = lpeg.P{
|
||||
Block,
|
||||
Block = Ct(Line^0),
|
||||
Line = Ct(Funcall) * Break,
|
||||
Block = Ct((Line)^0),
|
||||
Line = Break + Cmt(Indent, check_indent) * (Ct(If) + Exp * Stop),
|
||||
InBlock = #Cmt(Indent, advance_indent) * Block * OutBlock,
|
||||
OutBlock = Cmt(P(""), pop_indent),
|
||||
|
||||
Funcall = Name * ArgList / mark"fncall",
|
||||
If = key"if" * Exp * Break * InBlock / mark "if",
|
||||
|
||||
ArgList = Ct(Exp * (ArgDelim * Exp)^0),
|
||||
Exp = Ct(Value * (FactorOp * Value)^0) / flatten,
|
||||
Value = Funcall + Num + Name
|
||||
}
|
||||
|
||||
return {
|
||||
_g = Space * g * Space * -1,
|
||||
match = function(self, str, ...)
|
||||
@ -95,7 +138,7 @@ local build_grammar = wrap(function()
|
||||
|
||||
local tree = self._g:match(str, ...)
|
||||
if not tree then
|
||||
return nil, err_msg:format(line, get_line(line))
|
||||
return nil, err_msg:format(line, get_line(line), _indent:top())
|
||||
end
|
||||
return tree
|
||||
end
|
||||
@ -105,20 +148,27 @@ end)
|
||||
|
||||
local grammar = build_grammar()
|
||||
|
||||
|
||||
|
||||
local program = [[
|
||||
if gogo bozango
|
||||
print hello_world
|
||||
if two_dads
|
||||
do something
|
||||
if yum
|
||||
heckyes 23
|
||||
|
||||
print 2
|
||||
|
||||
print dadas
|
||||
this is what a sentence does when you use it
|
||||
]]
|
||||
-- print hi + world + 2342
|
||||
-- print 23424
|
||||
-- ]]
|
||||
|
||||
|
||||
local tree, err = grammar:match(program)
|
||||
if not tree then error(err) end
|
||||
|
||||
print(util.dump(tree))
|
||||
-- print(compile.tree(tree))
|
||||
dump.tree(tree)
|
||||
print""
|
||||
print(compile.tree(tree))
|
||||
|
||||
local program2 = [[
|
||||
if something
|
||||
|
@ -2,13 +2,21 @@
|
||||
module("moonscript.compile", package.seeall)
|
||||
require "util"
|
||||
|
||||
-- this doesn't work
|
||||
-- setmetatable(_M, {
|
||||
-- __call = setfenv(function(self, ...)
|
||||
-- compile(...)
|
||||
-- end, _G)
|
||||
-- })
|
||||
|
||||
local indent_char = " "
|
||||
|
||||
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)
|
||||
@ -20,6 +28,21 @@ local compilers = {
|
||||
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 = {}
|
||||
local i = self:ichar()
|
||||
for _, ln in ipairs(node) do
|
||||
table.insert(lines, i..self:value(ln))
|
||||
end
|
||||
if inc then self._indent = self._indent - inc end
|
||||
return table.concat(lines, "\n")
|
||||
end,
|
||||
value = function(self, node)
|
||||
if type(node) == "table" then
|
||||
local op = unpack(node)
|
||||
@ -35,7 +58,7 @@ _M.tree = function(tree)
|
||||
for _, line in ipairs(tree) do
|
||||
local op = line[1]
|
||||
local fn = compilers[op]
|
||||
if not fn then error("Unknown op: "..op) end
|
||||
if not fn then error("Unknown op: "..tostring(op)) end
|
||||
table.insert(buff, compilers[op](compilers, line))
|
||||
end
|
||||
|
||||
|
31
moonscript/data.lua
Normal file
31
moonscript/data.lua
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
module("moonscript.data", package.seeall)
|
||||
|
||||
local stack_t = {}
|
||||
local _stack_mt = { __index = stack_t, __tostring = function(self)
|
||||
return "<Stack {"..table.concat(self, ", ").."}>"
|
||||
end}
|
||||
|
||||
function stack_t:pop()
|
||||
return table.remove(self)
|
||||
end
|
||||
|
||||
function stack_t:push(value)
|
||||
table.insert(self, value)
|
||||
return value
|
||||
end
|
||||
|
||||
function stack_t:top()
|
||||
return self[#self]
|
||||
end
|
||||
|
||||
function Stack(...)
|
||||
local self = setmetatable({}, _stack_mt)
|
||||
|
||||
for _, v in ipairs{...} do
|
||||
self:push(v)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
23
moonscript/dump.lua
Normal file
23
moonscript/dump.lua
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
module("moonscript.dump", package.seeall)
|
||||
|
||||
local function flat_value(op, depth)
|
||||
depth = depth or 1
|
||||
|
||||
if type(op) == "string" then return '"'..op..'"' end
|
||||
if type(op) ~= "table" then return tostring(op) end
|
||||
local items = {}
|
||||
for _, item in ipairs(op) do
|
||||
table.insert(items, flat_value(item, depth+1))
|
||||
end
|
||||
|
||||
return "{"..table.concat(items, ", ").."}"
|
||||
end
|
||||
|
||||
function tree(block, depth)
|
||||
depth = depth or 0
|
||||
for _, op in ipairs(block) do
|
||||
print(flat_value(op))
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user