convert rest of parse helpers to moonscript

This commit is contained in:
leaf corcoran 2015-02-28 16:01:52 -08:00
parent 72d496dd66
commit a1d9e39caa
3 changed files with 404 additions and 165 deletions

View File

@ -41,165 +41,24 @@ Num = Space * (Num / function(value) return {"number", value} end)
local Indent = parse_util.Indent
local Cut = parse_util.Cut
local ensure = parse_util.ensure
local function extract_line(str, start_pos)
str = str:sub(start_pos)
local m = str:match"^(.-)\n"
if m then return m end
return str:match"^.-$"
end
local function mark(name)
return function(...)
return {name, ...}
end
end
local function insert_pos(pos, value)
if type(value) == "table" then
value[-1] = pos
end
return value
end
local function pos(patt)
return (lpeg.Cp() * patt) / insert_pos
end
local function got(what)
return Cmt("", function(str, pos, ...)
local cap = {...}
print("++ got "..what, "["..extract_line(str, pos).."]")
return true
end)
end
local function flatten_or_mark(name)
return function(tbl)
if #tbl == 1 then return tbl[1] end
table.insert(tbl, 1, name)
return tbl
end
end
-- makes sure the last item in a chain is an index
local _chain_assignable = { index = true, dot = true, slice = true }
local function is_assignable(node)
if node == "..." then
return false
end
local t = ntype(node)
return t == "ref" or t == "self" or t == "value" or t == "self_class" or
t == "chain" and _chain_assignable[ntype(node[#node])] or
t == "table"
end
local function check_assignable(str, pos, value)
if is_assignable(value) then
return true, value
end
return false
end
local flatten_explist = flatten_or_mark"explist"
local function format_assign(lhs_exps, assign)
if not assign then
return flatten_explist(lhs_exps)
end
for _, assign_exp in ipairs(lhs_exps) do
if not is_assignable(assign_exp) then
error {assign_exp, "left hand expression is not assignable"}
end
end
local t = ntype(assign)
if t == "assign" then
return {"assign", lhs_exps, unpack(assign, 2)}
elseif t == "update" then
return {"update", lhs_exps[1], unpack(assign, 2)}
end
error "unknown assign expression"
end
-- the if statement only takes a single lhs, so we wrap in table to git to
-- "assign" tuple format
local function format_single_assign(lhs, assign)
if assign then
return format_assign({lhs}, assign)
end
return lhs
end
local function sym(chars)
return Space * chars
end
-- Like sym but doesn't accept whitespace in front
local function symx(chars)
return chars
end
local function simple_string(delim, allow_interpolation)
local inner = P('\\'..delim) + "\\\\" + (1 - P(delim))
if allow_interpolation then
local inter = symx"#{" * V"Exp" * sym"}"
inner = (C((inner - inter)^1) + inter / mark"interpolate")^0
else
inner = C(inner^0)
end
return C(symx(delim)) *
inner * sym(delim) / mark"string"
end
local function wrap_func_arg(value)
return {"call", {value}}
end
-- DOCME
local function flatten_func(callee, args)
if #args == 0 then return callee end
args = {"call", args}
if ntype(callee) == "chain" then
-- check for colon stub that needs arguments
if ntype(callee[#callee]) == "colon_stub" then
local stub = callee[#callee]
stub[1] = "colon"
table.insert(stub, args)
else
table.insert(callee, args)
end
return callee
end
return {"chain", callee, args}
end
local function flatten_string_chain(str, chain, args)
if not chain then return str end
return flatten_func({"chain", str, unpack(chain)}, args)
end
-- transforms a statement that has a line decorator
local function wrap_decorator(stm, dec)
if not dec then return stm end
return { "decorated", stm, dec }
end
local function check_lua_string(str, pos, right, left)
return #left == #right
end
-- :name in table literal
local function self_assign(name, pos)
return {{"key_literal", name}, {"ref", name, [-1] = pos}}
end
local extract_line = parse_util.extract_line
local mark = parse_util.mark
local pos = parse_util.pos
local got = parse_util.got
local flatten_or_mark = parse_util.flatten_or_mark
local is_assignable = parse_util.is_assignable
local check_assignable = parse_util.check_assignable
local format_assign = parse_util.format_assign
local format_single_assign = parse_util.format_single_assign
local sym = parse_util.sym
local symx = parse_util.symx
local simple_string = parse_util.simple_string
local wrap_func_arg = parse_util.wrap_func_arg
local flatten_func = parse_util.flatten_func
local flatten_string_chain = parse_util.flatten_string_chain
local wrap_decorator = parse_util.wrap_decorator
local check_lua_string = parse_util.check_lua_string
local self_assign = parse_util.self_assign
local err_msg = "Failed to parse:%s\n [%d] >> %s"

View File

@ -1,8 +1,14 @@
local P, C, S
local unpack
unpack = require("moonscript.util").unpack
local P, C, S, Cp, Cmt, V
do
local _obj_0 = require("lpeg")
P, C, S = _obj_0.P, _obj_0.C, _obj_0.S
P, C, S, Cp, Cmt, V = _obj_0.P, _obj_0.C, _obj_0.S, _obj_0.Cp, _obj_0.Cmt, _obj_0.V
end
local ntype
ntype = require("moonscript.types").ntype
local Space
Space = require("moonscript.parse.literals").Space
local Indent = C(S("\t ") ^ 0) / function(str)
do
local sum = 0
@ -24,8 +30,238 @@ local ensure
ensure = function(patt, finally)
return patt * finally + finally * Cut
end
local extract_line
extract_line = function(str, start_pos)
str = str:sub(start_pos)
do
local m = str:match("^(.-)\n")
if m then
return m
end
end
return str:match("^.-$")
end
local mark
mark = function(name)
return function(...)
return {
name,
...
}
end
end
local pos
pos = function(patt)
return (Cp() * patt) / function(pos, value)
if type(value) == "table" then
value[-1] = pos
end
return value
end
end
local got
got = function(what)
return Cmt("", function(str, pos)
print("++ got " .. tostring(what), "[" .. tostring(extract_line(str, pos)) .. "]")
return true
end)
end
local flatten_or_mark
flatten_or_mark = function(name)
return function(tbl)
if #tbl == 1 then
return tbl[1]
end
table.insert(tbl, 1, name)
return tbl
end
end
local is_assignable
do
local chain_assignable = {
index = true,
dot = true,
slice = true
}
is_assignable = function(node)
if node == "..." then
return false
end
local _exp_0 = ntype(node)
if "ref" == _exp_0 or "self" == _exp_0 or "value" == _exp_0 or "self_class" == _exp_0 or "table" == _exp_0 then
return true
elseif "chain" == _exp_0 then
return chain_assignable[ntype(node[#node])]
else
return false
end
end
end
local check_assignable
check_assignable = function(str, pos, value)
if is_assignable(value) then
return true, value
else
return false
end
end
local format_assign
do
local flatten_explist = flatten_or_mark("explist")
format_assign = function(lhs_exps, assign)
if not (assign) then
return flatten_explist(lhs_exps)
end
for _index_0 = 1, #lhs_exps do
local assign_exp = lhs_exps[_index_0]
if not (is_assignable(assign_exp)) then
error({
assign_exp,
"left hand expression is not assignable"
})
end
end
local t = ntype(assign)
local _exp_0 = t
if "assign" == _exp_0 then
return {
"assign",
lhs_exps,
unpack(assign, 2)
}
elseif "update" == _exp_0 then
return {
"update",
lhs_exps[1],
unpack(assign, 2)
}
else
return error("unknown assign expression: " .. tostring(t))
end
end
end
local format_single_assign
format_single_assign = function(lhs, assign)
if assign then
return format_assign({
lhs
}, assign)
else
return lhs
end
end
local sym
sym = function(chars)
return Space * chars
end
local symx
symx = function(chars)
return chars
end
local simple_string
simple_string = function(delim, allow_interpolation)
local inner = P("\\" .. tostring(delim)) + "\\\\" + (1 - P(delim))
if allow_interpolation then
local interp = symx('#{') * V("Exp") * sym('}')
inner = (C((inner - interp) ^ 1) + interp / mark("interpolate")) ^ 0
else
inner = C(inner ^ 0)
end
return C(symx(delim)) * inner * sym(delim) / mark("string")
end
local wrap_func_arg
wrap_func_arg = function(value)
return {
"call",
{
value
}
}
end
local flatten_func
flatten_func = function(callee, args)
if #args == 0 then
return callee
end
args = {
"call",
args
}
if ntype(callee) == "chain" then
local stub = callee[#callee]
if ntype(stub) == "colon_stub" then
stub[1] = "colon"
table.insert(stub, args)
else
table.insert(callee, args)
end
return callee
end
return {
"chain",
callee,
args
}
end
local flatten_string_chain
flatten_string_chain = function(str, chain, args)
if not (chain) then
return str
end
return flatten_func({
"chain",
str,
unpack(chain)
}, args)
end
local wrap_decorator
wrap_decorator = function(stm, dec)
if not (dec) then
return stm
end
return {
"decorated",
stm,
dec
}
end
local check_lua_string
check_lua_string = function(str, pos, right, left)
return #left == #right
end
local self_assign
self_assign = function(name, pos)
return {
{
"key_literal",
name
},
{
"ref",
name,
[-1] = pos
}
}
end
return {
Indent = Indent,
Cut = Cut,
ensure = ensure
ensure = ensure,
extract_line = extract_line,
mark = mark,
pos = pos,
flatten_or_mark = flatten_or_mark,
is_assignable = is_assignable,
check_assignable = check_assignable,
format_assign = format_assign,
format_single_assign = format_single_assign,
sym = sym,
symx = symx,
simple_string = simple_string,
wrap_func_arg = wrap_func_arg,
flatten_func = flatten_func,
flatten_string_chain = flatten_string_chain,
wrap_decorator = wrap_decorator,
check_lua_string = check_lua_string,
self_assign = self_assign
}

View File

@ -1,5 +1,8 @@
import P, C, S from require "lpeg"
import unpack from require "moonscript.util"
import P, C, S, Cp, Cmt, V from require "lpeg"
import ntype from require "moonscript.types"
import Space from require "moonscript.parse.literals"
-- captures an indentation, returns indent depth
Indent = C(S"\t "^0) / (str) ->
@ -18,6 +21,147 @@ Cut = P -> false
-- ensures finally runs regardless of whether pattern fails or passes
ensure = (patt, finally) ->
patt * finally + finally * Cut
patt * finally + finally * Cut
{ :Indent, :Cut, :ensure }
-- take rest of line from pos out of str
extract_line = (str, start_pos) ->
str = str\sub start_pos
if m = str\match "^(.-)\n"
return m
str\match "^.-$"
-- used to identify a capture with a label
mark = (name) ->
(...) -> {name, ...}
-- wraps pattern to capture pos into node
-- pos is the character offset from the buffer where the node was parsed from.
-- Used to generate error messages
pos = (patt) ->
(Cp! * patt) / (pos, value) ->
if type(value) == "table"
value[-1] = pos
value
-- generates a debug pattern that always succeeds and prints out where we are
-- in the buffer with a label
got = (what) ->
Cmt "", (str, pos) ->
print "++ got #{what}", "[#{extract_line str, pos}]"
true
-- converts 1 element array to its value, otherwise marks it
flatten_or_mark = (name) ->
(tbl) ->
return tbl[1] if #tbl == 1
table.insert tbl, 1, name
tbl
-- determines if node is able to be on left side of assignment
is_assignable = do
chain_assignable = { index: true, dot: true, slice: true }
(node) ->
return false if node == "..."
switch ntype node
when "ref", "self", "value", "self_class", "table"
true
when "chain"
chain_assignable[ntype node[#node]]
else
false
check_assignable = (str, pos, value) ->
if is_assignable value
true, value
else
false
-- joins the two parts of an assign parse into a single node
format_assign = do
flatten_explist = flatten_or_mark "explist"
(lhs_exps, assign) ->
unless assign
return flatten_explist lhs_exps
for assign_exp in *lhs_exps
unless is_assignable assign_exp
error {assign_exp, "left hand expression is not assignable"}
t = ntype assign
switch t
when "assign"
{"assign", lhs_exps, unpack assign, 2}
when "update"
{"update", lhs_exps[1], unpack assign, 2}
else
error "unknown assign expression: #{t}"
-- helper for if statement, which only has single lhs
format_single_assign = (lhs, assign) ->
if assign
format_assign {lhs}, assign
else
lhs
-- a symbol
sym = (chars) -> Space * chars
-- a symbole that doesn't accept whitespace before it
symx = (chars) -> chars
-- a constructor for quote delimited strings
simple_string = (delim, allow_interpolation) ->
inner = P("\\#{delim}") + "\\\\" + (1 - P delim)
inner = if allow_interpolation
interp = symx'#{' * V"Exp" * sym'}'
(C((inner - interp)^1) + interp / mark"interpolate")^0
else
C inner^0
C(symx(delim)) * inner * sym(delim) / mark"string"
-- wraps a single value in format needed to be passed as function arguments
wrap_func_arg = (value) -> {"call", {value}}
-- flatten out the parsed function node
flatten_func = (callee, args) ->
return callee if #args == 0
args = {"call", args}
if ntype(callee) == "chain"
-- check for colon stub needing arguments
stub = callee[#callee]
if ntype(stub) == "colon_stub"
stub[1] = "colon"
table.insert stub, args
else
table.insert callee, args
return callee
{"chain", callee, args}
flatten_string_chain = (str, chain, args) ->
return str unless chain
flatten_func {"chain", str, unpack chain}, args
-- constructor for decorator node
wrap_decorator = (stm, dec) ->
return stm unless dec
{"decorated", stm, dec}
check_lua_string = (str, pos, right, left) ->
#left == #right
-- constructor for :name self assignments in table literals
self_assign = (name, pos) ->
{{"key_literal", name}, {"ref", name, [-1]: pos}}
{ :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark,
:is_assignable, :check_assignable, :format_assign, :format_single_assign,
:sym, :symx, :simple_string, :wrap_func_arg, :flatten_func,
:flatten_string_chain, :wrap_decorator, :check_lua_string, :self_assign }