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"lpeg"
|
||||||
|
|
||||||
require"moonscript.compile"
|
require"moonscript.compile"
|
||||||
|
require"moonscript.dump"
|
||||||
|
require"moonscript.data"
|
||||||
|
|
||||||
|
local Stack = data.Stack
|
||||||
|
|
||||||
local function count_indent(str)
|
local function count_indent(str)
|
||||||
local sum = 0
|
local sum = 0
|
||||||
@ -16,10 +20,11 @@ local function count_indent(str)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local R, S, V, P = lpeg.R, lpeg.S, lpeg.V, lpeg.P
|
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 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 Indent = C(S"\t "^0) / count_indent
|
||||||
local ArgDelim = "," * Space
|
local ArgDelim = "," * Space
|
||||||
|
|
||||||
@ -53,6 +58,14 @@ function mark(name)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function got(what)
|
||||||
|
return function(...)
|
||||||
|
print("got "..tostring(what))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function flatten(tbl)
|
function flatten(tbl)
|
||||||
if #tbl == 1 then
|
if #tbl == 1 then
|
||||||
return tbl[1]
|
return tbl[1]
|
||||||
@ -61,7 +74,7 @@ function flatten(tbl)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local build_grammar = wrap(function()
|
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 line = 1
|
||||||
local function line_count(subject, pos, str)
|
local function line_count(subject, pos, str)
|
||||||
for _ in str:gmatch("\n") do
|
for _ in str:gmatch("\n") do
|
||||||
@ -71,18 +84,48 @@ local build_grammar = wrap(function()
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local Space = lpeg.Cmt(Space, line_count)
|
local Space = Cmt(Space, line_count)
|
||||||
local Break = lpeg.Cmt(Break, 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{
|
local g = lpeg.P{
|
||||||
Block,
|
Block,
|
||||||
Block = Ct(Line^0),
|
Block = Ct((Line)^0),
|
||||||
Line = Ct(Funcall) * Break,
|
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",
|
Funcall = Name * ArgList / mark"fncall",
|
||||||
|
If = key"if" * Exp * Break * InBlock / mark "if",
|
||||||
|
|
||||||
ArgList = Ct(Exp * (ArgDelim * Exp)^0),
|
ArgList = Ct(Exp * (ArgDelim * Exp)^0),
|
||||||
Exp = Ct(Value * (FactorOp * Value)^0) / flatten,
|
Exp = Ct(Value * (FactorOp * Value)^0) / flatten,
|
||||||
Value = Funcall + Num + Name
|
Value = Funcall + Num + Name
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_g = Space * g * Space * -1,
|
_g = Space * g * Space * -1,
|
||||||
match = function(self, str, ...)
|
match = function(self, str, ...)
|
||||||
@ -95,7 +138,7 @@ local build_grammar = wrap(function()
|
|||||||
|
|
||||||
local tree = self._g:match(str, ...)
|
local tree = self._g:match(str, ...)
|
||||||
if not tree then
|
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
|
end
|
||||||
return tree
|
return tree
|
||||||
end
|
end
|
||||||
@ -105,20 +148,27 @@ end)
|
|||||||
|
|
||||||
local grammar = build_grammar()
|
local grammar = build_grammar()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local program = [[
|
local program = [[
|
||||||
if gogo bozango
|
if two_dads
|
||||||
print hello_world
|
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)
|
local tree, err = grammar:match(program)
|
||||||
if not tree then error(err) end
|
if not tree then error(err) end
|
||||||
|
|
||||||
print(util.dump(tree))
|
dump.tree(tree)
|
||||||
-- print(compile.tree(tree))
|
print""
|
||||||
|
print(compile.tree(tree))
|
||||||
|
|
||||||
local program2 = [[
|
local program2 = [[
|
||||||
if something
|
if something
|
||||||
|
@ -2,13 +2,21 @@
|
|||||||
module("moonscript.compile", package.seeall)
|
module("moonscript.compile", package.seeall)
|
||||||
require "util"
|
require "util"
|
||||||
|
|
||||||
|
-- this doesn't work
|
||||||
-- setmetatable(_M, {
|
-- setmetatable(_M, {
|
||||||
-- __call = setfenv(function(self, ...)
|
-- __call = setfenv(function(self, ...)
|
||||||
-- compile(...)
|
-- compile(...)
|
||||||
-- end, _G)
|
-- end, _G)
|
||||||
-- })
|
-- })
|
||||||
|
|
||||||
|
local indent_char = " "
|
||||||
|
|
||||||
local compilers = {
|
local compilers = {
|
||||||
|
_indent = 0,
|
||||||
|
ichar = function(self)
|
||||||
|
return indent_char:rep(self._indent)
|
||||||
|
end,
|
||||||
|
|
||||||
fncall = function(self, node)
|
fncall = function(self, node)
|
||||||
local _, name, args = unpack(node)
|
local _, name, args = unpack(node)
|
||||||
return name .. self:args(args)
|
return name .. self:args(args)
|
||||||
@ -20,6 +28,21 @@ local compilers = {
|
|||||||
end
|
end
|
||||||
return "(" .. table.concat(values, ", ") .. ")"
|
return "(" .. table.concat(values, ", ") .. ")"
|
||||||
end,
|
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)
|
value = function(self, node)
|
||||||
if type(node) == "table" then
|
if type(node) == "table" then
|
||||||
local op = unpack(node)
|
local op = unpack(node)
|
||||||
@ -35,7 +58,7 @@ _M.tree = function(tree)
|
|||||||
for _, line in ipairs(tree) do
|
for _, line in ipairs(tree) do
|
||||||
local op = line[1]
|
local op = line[1]
|
||||||
local fn = compilers[op]
|
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))
|
table.insert(buff, compilers[op](compilers, line))
|
||||||
end
|
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