rufus-lua-moon 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +51 -0
- data/Rakefile +1 -0
- data/lib/rufus/lua/moon/version.rb +12 -0
- data/lib/rufus/lua/moon.rb +18 -0
- data/rufus-lua-moon.gemspec +25 -0
- data/vendor/lua/moon/all.moon +8 -0
- data/vendor/lua/moon/init.moon +136 -0
- data/vendor/lua/moonscript/compile/format.lua +55 -0
- data/vendor/lua/moonscript/compile/statement.lua +217 -0
- data/vendor/lua/moonscript/compile/value.lua +321 -0
- data/vendor/lua/moonscript/compile.lua +549 -0
- data/vendor/lua/moonscript/data.lua +87 -0
- data/vendor/lua/moonscript/dump.lua +42 -0
- data/vendor/lua/moonscript/errors.lua +65 -0
- data/vendor/lua/moonscript/init.lua +90 -0
- data/vendor/lua/moonscript/parse.lua +505 -0
- data/vendor/lua/moonscript/transform.lua +1174 -0
- data/vendor/lua/moonscript/types.lua +237 -0
- data/vendor/lua/moonscript/util.lua +101 -0
- data/vendor/lua/moonscript/version.lua +7 -0
- metadata +109 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
module("moonscript.data", package.seeall)
|
2
|
+
local concat = table.concat
|
3
|
+
Set = function(items)
|
4
|
+
local self = { }
|
5
|
+
local _list_0 = items
|
6
|
+
for _index_0 = 1, #_list_0 do
|
7
|
+
local key = _list_0[_index_0]
|
8
|
+
self[key] = true
|
9
|
+
end
|
10
|
+
return self
|
11
|
+
end
|
12
|
+
Stack = (function()
|
13
|
+
local _parent_0 = nil
|
14
|
+
local _base_0 = {
|
15
|
+
__tostring = function(self)
|
16
|
+
return "<Stack {" .. concat(self, ", ") .. "}>"
|
17
|
+
end,
|
18
|
+
pop = function(self)
|
19
|
+
return table.remove(self)
|
20
|
+
end,
|
21
|
+
push = function(self, value)
|
22
|
+
table.insert(self, value)
|
23
|
+
return value
|
24
|
+
end,
|
25
|
+
top = function(self)
|
26
|
+
return self[#self]
|
27
|
+
end
|
28
|
+
}
|
29
|
+
_base_0.__index = _base_0
|
30
|
+
if _parent_0 then
|
31
|
+
setmetatable(_base_0, _parent_0.__base)
|
32
|
+
end
|
33
|
+
local _class_0 = setmetatable({
|
34
|
+
__init = function(self, ...)
|
35
|
+
local _list_0 = {
|
36
|
+
...
|
37
|
+
}
|
38
|
+
for _index_0 = 1, #_list_0 do
|
39
|
+
local v = _list_0[_index_0]
|
40
|
+
self:push(v)
|
41
|
+
end
|
42
|
+
return nil
|
43
|
+
end,
|
44
|
+
__base = _base_0,
|
45
|
+
__name = "Stack",
|
46
|
+
__parent = _parent_0
|
47
|
+
}, {
|
48
|
+
__index = function(cls, name)
|
49
|
+
local val = rawget(_base_0, name)
|
50
|
+
if val == nil and _parent_0 then
|
51
|
+
return _parent_0[name]
|
52
|
+
else
|
53
|
+
return val
|
54
|
+
end
|
55
|
+
end,
|
56
|
+
__call = function(cls, ...)
|
57
|
+
local _self_0 = setmetatable({}, _base_0)
|
58
|
+
cls.__init(_self_0, ...)
|
59
|
+
return _self_0
|
60
|
+
end
|
61
|
+
})
|
62
|
+
_base_0.__class = _class_0
|
63
|
+
return _class_0
|
64
|
+
end)()
|
65
|
+
lua_keywords = Set({
|
66
|
+
'and',
|
67
|
+
'break',
|
68
|
+
'do',
|
69
|
+
'else',
|
70
|
+
'elseif',
|
71
|
+
'end',
|
72
|
+
'false',
|
73
|
+
'for',
|
74
|
+
'function',
|
75
|
+
'if',
|
76
|
+
'in',
|
77
|
+
'local',
|
78
|
+
'nil',
|
79
|
+
'not',
|
80
|
+
'or',
|
81
|
+
'repeat',
|
82
|
+
'return',
|
83
|
+
'then',
|
84
|
+
'true',
|
85
|
+
'until',
|
86
|
+
'while'
|
87
|
+
})
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module("moonscript.dump", package.seeall)
|
2
|
+
local flat_value
|
3
|
+
flat_value = function(op, depth)
|
4
|
+
if depth == nil then
|
5
|
+
depth = 1
|
6
|
+
end
|
7
|
+
if type(op) == "string" then
|
8
|
+
return '"' .. op .. '"'
|
9
|
+
end
|
10
|
+
if type(op) ~= "table" then
|
11
|
+
return tostring(op)
|
12
|
+
end
|
13
|
+
local items = (function()
|
14
|
+
local _accum_0 = { }
|
15
|
+
local _len_0 = 0
|
16
|
+
local _list_0 = op
|
17
|
+
for _index_0 = 1, #_list_0 do
|
18
|
+
local item = _list_0[_index_0]
|
19
|
+
_len_0 = _len_0 + 1
|
20
|
+
_accum_0[_len_0] = flat_value(item, depth + 1)
|
21
|
+
end
|
22
|
+
return _accum_0
|
23
|
+
end)()
|
24
|
+
local pos = op[-1]
|
25
|
+
return "{" .. (pos and "[" .. pos .. "] " or "") .. table.concat(items, ", ") .. "}"
|
26
|
+
end
|
27
|
+
value = function(op)
|
28
|
+
return flat_value(op)
|
29
|
+
end
|
30
|
+
tree = function(block)
|
31
|
+
return (function()
|
32
|
+
local _accum_0 = { }
|
33
|
+
local _len_0 = 0
|
34
|
+
local _list_0 = block
|
35
|
+
for _index_0 = 1, #_list_0 do
|
36
|
+
value = _list_0[_index_0]
|
37
|
+
_len_0 = _len_0 + 1
|
38
|
+
_accum_0[_len_0] = print(flat_value(value))
|
39
|
+
end
|
40
|
+
return _accum_0
|
41
|
+
end)()
|
42
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module("moonscript.errors", package.seeall)
|
2
|
+
local moon = require("moonscript")
|
3
|
+
local util = require("moonscript.util")
|
4
|
+
require("lpeg")
|
5
|
+
local concat, insert = table.concat, table.insert
|
6
|
+
local split, pos_to_line = util.split, util.pos_to_line
|
7
|
+
local lookup_line
|
8
|
+
lookup_line = function(fname, pos, cache)
|
9
|
+
if not cache[fname] then
|
10
|
+
do
|
11
|
+
local _with_0 = io.open(fname)
|
12
|
+
cache[fname] = _with_0:read("*a")
|
13
|
+
_with_0:close()
|
14
|
+
end
|
15
|
+
end
|
16
|
+
return pos_to_line(cache[fname], pos)
|
17
|
+
end
|
18
|
+
local reverse_line_number
|
19
|
+
reverse_line_number = function(fname, line_table, line_num, cache)
|
20
|
+
for i = line_num, 0, -1 do
|
21
|
+
if line_table[i] then
|
22
|
+
return lookup_line(fname, line_table[i], cache)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
return "unknown"
|
26
|
+
end
|
27
|
+
rewrite_traceback = function(text, err)
|
28
|
+
local line_tables = moon.line_tables
|
29
|
+
local V, S, Ct, C = lpeg.V, lpeg.S, lpeg.Ct, lpeg.C
|
30
|
+
local header_text = "stack traceback:"
|
31
|
+
local Header, Line = V("Header"), V("Line")
|
32
|
+
local Break = lpeg.S("\n")
|
33
|
+
local g = lpeg.P({
|
34
|
+
Header,
|
35
|
+
Header = header_text * Break * Ct(Line ^ 1),
|
36
|
+
Line = "\t" * C((1 - Break) ^ 0) * (Break + -1)
|
37
|
+
})
|
38
|
+
local cache = { }
|
39
|
+
local rewrite_single
|
40
|
+
rewrite_single = function(trace)
|
41
|
+
local fname, line, msg = trace:match('^%[string "(.-)"]:(%d+): (.*)$')
|
42
|
+
local tbl = line_tables[fname]
|
43
|
+
if fname and tbl then
|
44
|
+
return concat({
|
45
|
+
fname,
|
46
|
+
":",
|
47
|
+
reverse_line_number(fname, tbl, line, cache),
|
48
|
+
": ",
|
49
|
+
msg
|
50
|
+
})
|
51
|
+
else
|
52
|
+
return trace
|
53
|
+
end
|
54
|
+
end
|
55
|
+
err = rewrite_single(err)
|
56
|
+
local match = g:match(text)
|
57
|
+
for i, trace in ipairs(match) do
|
58
|
+
match[i] = rewrite_single(trace)
|
59
|
+
end
|
60
|
+
return concat({
|
61
|
+
"moon:" .. err,
|
62
|
+
header_text,
|
63
|
+
"\t" .. concat(match, "\n\t")
|
64
|
+
}, "\n")
|
65
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module("moonscript", package.seeall)
|
2
|
+
require("moonscript.compile")
|
3
|
+
require("moonscript.parse")
|
4
|
+
require("moonscript.util")
|
5
|
+
local concat, insert = table.concat, table.insert
|
6
|
+
local split, dump = util.split, util.dump
|
7
|
+
local lua = {
|
8
|
+
loadstring = loadstring
|
9
|
+
}
|
10
|
+
dirsep = "/"
|
11
|
+
line_tables = { }
|
12
|
+
local create_moonpath
|
13
|
+
create_moonpath = function(package_path)
|
14
|
+
local paths = split(package_path, ";")
|
15
|
+
for i, path in ipairs(paths) do
|
16
|
+
local p = path:match("^(.-)%.lua$")
|
17
|
+
if p then
|
18
|
+
paths[i] = p .. ".moon"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
return concat(paths, ";")
|
22
|
+
end
|
23
|
+
to_lua = function(text)
|
24
|
+
if "string" ~= type(text) then
|
25
|
+
local t = type(text)
|
26
|
+
error("expecting string (got " .. t .. ")", 2)
|
27
|
+
end
|
28
|
+
local tree, err = parse.string(text)
|
29
|
+
if not tree then
|
30
|
+
error(err, 2)
|
31
|
+
end
|
32
|
+
local code, ltable, pos = compile.tree(tree)
|
33
|
+
if not code then
|
34
|
+
error(compile.format_error(ltable, pos, text), 2)
|
35
|
+
end
|
36
|
+
return code, ltable
|
37
|
+
end
|
38
|
+
moon_loader = function(name)
|
39
|
+
local name_path = name:gsub("%.", dirsep)
|
40
|
+
local file, file_path = nil, nil
|
41
|
+
local _list_0 = split(package.moonpath, ";")
|
42
|
+
for _index_0 = 1, #_list_0 do
|
43
|
+
local path = _list_0[_index_0]
|
44
|
+
file_path = path:gsub("?", name_path)
|
45
|
+
file = io.open(file_path)
|
46
|
+
if file then
|
47
|
+
break
|
48
|
+
end
|
49
|
+
end
|
50
|
+
if file then
|
51
|
+
local text = file:read("*a")
|
52
|
+
return loadstring(text, file_path)
|
53
|
+
else
|
54
|
+
return nil, "Could not find moon file"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
if not package.moonpath then
|
58
|
+
package.moonpath = create_moonpath(package.path)
|
59
|
+
end
|
60
|
+
local init_loader
|
61
|
+
init_loader = function()
|
62
|
+
return insert(package.loaders, 2, moon_loader)
|
63
|
+
end
|
64
|
+
if not _G.moon_no_loader then
|
65
|
+
init_loader()
|
66
|
+
end
|
67
|
+
loadstring = function(str, chunk_name)
|
68
|
+
local passed, code, ltable = pcall(function()
|
69
|
+
return to_lua(str)
|
70
|
+
end)
|
71
|
+
if not passed then
|
72
|
+
error(chunk_name .. ": " .. code, 2)
|
73
|
+
end
|
74
|
+
if chunk_name then
|
75
|
+
line_tables[chunk_name] = ltable
|
76
|
+
end
|
77
|
+
return lua.loadstring(code, chunk_name or "=(moonscript.loadstring)")
|
78
|
+
end
|
79
|
+
loadfile = function(fname)
|
80
|
+
local file, err = io.open(fname)
|
81
|
+
if not file then
|
82
|
+
return nil, err
|
83
|
+
end
|
84
|
+
local text = assert(file:read("*a"))
|
85
|
+
return loadstring(text, fname)
|
86
|
+
end
|
87
|
+
dofile = function(fname)
|
88
|
+
local f = assert(loadfile(fname))
|
89
|
+
return f()
|
90
|
+
end
|
@@ -0,0 +1,505 @@
|
|
1
|
+
module("moonscript.parse", package.seeall)
|
2
|
+
|
3
|
+
local util = require"moonscript.util"
|
4
|
+
|
5
|
+
require"lpeg"
|
6
|
+
|
7
|
+
local data = require"moonscript.data"
|
8
|
+
local types = require"moonscript.types"
|
9
|
+
|
10
|
+
local ntype = types.ntype
|
11
|
+
|
12
|
+
local dump = util.dump
|
13
|
+
local trim = util.trim
|
14
|
+
|
15
|
+
local Stack = data.Stack
|
16
|
+
|
17
|
+
local function count_indent(str)
|
18
|
+
local sum = 0
|
19
|
+
for v in str:gmatch("[\t ]") do
|
20
|
+
if v == ' ' then sum = sum + 1 end
|
21
|
+
if v == '\t' then sum = sum + 4 end
|
22
|
+
end
|
23
|
+
return sum
|
24
|
+
end
|
25
|
+
|
26
|
+
local R, S, V, P = lpeg.R, lpeg.S, lpeg.V, lpeg.P
|
27
|
+
local C, Ct, Cmt, Cg, Cb, Cc = lpeg.C, lpeg.Ct, lpeg.Cmt, lpeg.Cg, lpeg.Cb, lpeg.Cc
|
28
|
+
|
29
|
+
lpeg.setmaxstack(10000)
|
30
|
+
|
31
|
+
local White = S" \t\r\n"^0
|
32
|
+
local _Space = S" \t"^0
|
33
|
+
local Break = P"\r"^-1 * P"\n"
|
34
|
+
local Stop = Break + -1
|
35
|
+
local Indent = C(S"\t "^0) / count_indent
|
36
|
+
|
37
|
+
local Comment = P"--" * (1 - S"\r\n")^0 * #Stop
|
38
|
+
local Space = _Space * Comment^-1
|
39
|
+
local SomeSpace = S" \t"^1 * Comment^-1
|
40
|
+
|
41
|
+
local SpaceBreak = Space * Break
|
42
|
+
local EmptyLine = SpaceBreak
|
43
|
+
|
44
|
+
local AlphaNum = R("az", "AZ", "09", "__")
|
45
|
+
|
46
|
+
local _Name = C(R("az", "AZ", "__") * AlphaNum^0)
|
47
|
+
local Name = Space * _Name
|
48
|
+
|
49
|
+
local Num = P"0x" * R("09", "af", "AF")^1 +
|
50
|
+
R"09"^1 * (P"." * R"09"^1)^-1 * (S"eE" * P"-"^-1 * R"09"^1)^-1
|
51
|
+
|
52
|
+
Num = Space * (Num / function(value) return {"number", value} end)
|
53
|
+
|
54
|
+
local FactorOp = Space * C(S"+-")
|
55
|
+
local TermOp = Space * C(S"*/%^")
|
56
|
+
|
57
|
+
local Shebang = P"#!" * P(1 - Stop)^0
|
58
|
+
|
59
|
+
-- can't have P(false) because it causes preceding patterns not to run
|
60
|
+
local Cut = P(function() return false end)
|
61
|
+
|
62
|
+
local function ensure(patt, finally)
|
63
|
+
return patt * finally + finally * Cut
|
64
|
+
end
|
65
|
+
|
66
|
+
-- auto declare Proper variables with lpeg.V
|
67
|
+
local function wrap_env(fn)
|
68
|
+
local env = getfenv(fn)
|
69
|
+
|
70
|
+
return setfenv(fn, setmetatable({}, {
|
71
|
+
__index = function(self, name)
|
72
|
+
local value = env[name]
|
73
|
+
if value ~= nil then return value end
|
74
|
+
|
75
|
+
if name:match"^[A-Z][A-Za-z0-9]*$" then
|
76
|
+
local v = V(name)
|
77
|
+
rawset(self, name, v)
|
78
|
+
return v
|
79
|
+
end
|
80
|
+
error("unknown variable referenced: "..name)
|
81
|
+
end
|
82
|
+
}))
|
83
|
+
end
|
84
|
+
|
85
|
+
function extract_line(str, start_pos)
|
86
|
+
str = str:sub(start_pos)
|
87
|
+
m = str:match"^(.-)\n"
|
88
|
+
if m then return m end
|
89
|
+
return str:match"^.-$"
|
90
|
+
end
|
91
|
+
|
92
|
+
local function mark(name)
|
93
|
+
return function(...)
|
94
|
+
return {name, ...}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
local function insert_pos(pos, value)
|
99
|
+
if type(value) == "table" then
|
100
|
+
value[-1] = pos
|
101
|
+
end
|
102
|
+
return value
|
103
|
+
end
|
104
|
+
|
105
|
+
local function pos(patt)
|
106
|
+
return (lpeg.Cp() * patt) / insert_pos
|
107
|
+
end
|
108
|
+
|
109
|
+
local function got(what)
|
110
|
+
return Cmt("", function(str, pos, ...)
|
111
|
+
local cap = {...}
|
112
|
+
print("++ got "..what, "["..extract_line(str, pos).."]")
|
113
|
+
return true
|
114
|
+
end)
|
115
|
+
end
|
116
|
+
|
117
|
+
local function flatten(tbl)
|
118
|
+
if #tbl == 1 then
|
119
|
+
return tbl[1]
|
120
|
+
end
|
121
|
+
return tbl
|
122
|
+
end
|
123
|
+
|
124
|
+
local function flatten_or_mark(name)
|
125
|
+
return function(tbl)
|
126
|
+
if #tbl == 1 then return tbl[1] end
|
127
|
+
table.insert(tbl, 1, name)
|
128
|
+
return tbl
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
-- makes sure the last item in a chain is an index
|
133
|
+
local _assignable = { index = true, dot = true, slice = true }
|
134
|
+
local function check_assignable(str, pos, value)
|
135
|
+
if ntype(value) == "chain" and _assignable[ntype(value[#value])]
|
136
|
+
or type(value) == "string"
|
137
|
+
then
|
138
|
+
return true, value
|
139
|
+
end
|
140
|
+
return false
|
141
|
+
end
|
142
|
+
|
143
|
+
local function sym(chars)
|
144
|
+
return Space * chars
|
145
|
+
end
|
146
|
+
|
147
|
+
local function symx(chars)
|
148
|
+
return chars
|
149
|
+
end
|
150
|
+
|
151
|
+
local function simple_string(delim, x)
|
152
|
+
return C(symx(delim)) * C((P('\\'..delim) +
|
153
|
+
"\\\\" +
|
154
|
+
(1 - S('\r\n'..delim)))^0) * sym(delim) / mark"string"
|
155
|
+
end
|
156
|
+
|
157
|
+
local function wrap_func_arg(value)
|
158
|
+
return {"call", {value}}
|
159
|
+
end
|
160
|
+
|
161
|
+
-- DOCME
|
162
|
+
local function flatten_func(callee, args)
|
163
|
+
if #args == 0 then return callee end
|
164
|
+
|
165
|
+
args = {"call", args}
|
166
|
+
if ntype(callee) == "chain" then
|
167
|
+
-- check for colon stub that needs arguments
|
168
|
+
if ntype(callee[#callee]) == "colon_stub" then
|
169
|
+
local stub = callee[#callee]
|
170
|
+
stub[1] = "colon"
|
171
|
+
table.insert(stub, args)
|
172
|
+
else
|
173
|
+
table.insert(callee, args)
|
174
|
+
end
|
175
|
+
|
176
|
+
return callee
|
177
|
+
end
|
178
|
+
|
179
|
+
return {"chain", callee, args}
|
180
|
+
end
|
181
|
+
|
182
|
+
-- wraps a statement that has a line decorator
|
183
|
+
local function wrap_decorator(stm, dec)
|
184
|
+
if not dec then return stm end
|
185
|
+
|
186
|
+
local arg = {stm, dec}
|
187
|
+
|
188
|
+
if dec[1] == "if" then
|
189
|
+
local _, cond, fail = unpack(dec)
|
190
|
+
if fail then fail = {"else", {fail}} end
|
191
|
+
stm = {"if", cond, {stm}, fail}
|
192
|
+
elseif dec[1] == "comprehension" then
|
193
|
+
local _, clauses = unpack(dec)
|
194
|
+
stm = {"comprehension", stm, clauses}
|
195
|
+
end
|
196
|
+
|
197
|
+
return stm
|
198
|
+
end
|
199
|
+
|
200
|
+
-- wrap if statement if there is a conditional decorator
|
201
|
+
local function wrap_if(stm, cond)
|
202
|
+
if cond then
|
203
|
+
local pass, fail = unpack(cond)
|
204
|
+
if fail then fail = {"else", {fail}} end
|
205
|
+
return {"if", cond[2], {stm}, fail}
|
206
|
+
end
|
207
|
+
return stm
|
208
|
+
end
|
209
|
+
|
210
|
+
local function check_lua_string(str, pos, right, left)
|
211
|
+
return #left == #right
|
212
|
+
end
|
213
|
+
|
214
|
+
-- :name in table literal
|
215
|
+
local function self_assign(name)
|
216
|
+
return {name, name}
|
217
|
+
end
|
218
|
+
|
219
|
+
local err_msg = "Failed to parse:\n [%d] >> %s (%d)"
|
220
|
+
|
221
|
+
local build_grammar = wrap_env(function()
|
222
|
+
local _indent = Stack(0) -- current indent
|
223
|
+
|
224
|
+
local last_pos = 0 -- used to know where to report error
|
225
|
+
local function check_indent(str, pos, indent)
|
226
|
+
last_pos = pos
|
227
|
+
return _indent:top() == indent
|
228
|
+
end
|
229
|
+
|
230
|
+
local function advance_indent(str, pos, indent)
|
231
|
+
local top = _indent:top()
|
232
|
+
if top ~= -1 and indent > _indent:top() then
|
233
|
+
_indent:push(indent)
|
234
|
+
return true
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
local function push_indent(str, pos, indent)
|
239
|
+
_indent:push(indent)
|
240
|
+
return true
|
241
|
+
end
|
242
|
+
|
243
|
+
local function pop_indent(str, pos)
|
244
|
+
if not _indent:pop() then error("unexpected outdent") end
|
245
|
+
return true
|
246
|
+
end
|
247
|
+
|
248
|
+
local keywords = {}
|
249
|
+
local function key(chars)
|
250
|
+
keywords[chars] = true
|
251
|
+
return Space * chars * -AlphaNum
|
252
|
+
end
|
253
|
+
|
254
|
+
local function op(word)
|
255
|
+
local patt = Space * C(word)
|
256
|
+
if word:match("^%w*$") then
|
257
|
+
keywords[word] = true
|
258
|
+
patt = patt * -AlphaNum
|
259
|
+
end
|
260
|
+
return patt
|
261
|
+
end
|
262
|
+
|
263
|
+
local SimpleName = Name -- for table key
|
264
|
+
|
265
|
+
-- make sure name is not a keyword
|
266
|
+
local Name = Cmt(Name, function(str, pos, name)
|
267
|
+
if keywords[name] then return false end
|
268
|
+
return true
|
269
|
+
end) / trim
|
270
|
+
|
271
|
+
local Name = sym"@" * Name / mark"self" + Name + Space * "..." / trim
|
272
|
+
|
273
|
+
local g = lpeg.P{
|
274
|
+
File,
|
275
|
+
File = Shebang^-1 * (Block + Ct""),
|
276
|
+
Block = Ct(Line * (Break^1 * Line)^0),
|
277
|
+
CheckIndent = Cmt(Indent, check_indent), -- validates line is in correct indent
|
278
|
+
Line = (CheckIndent * Statement + Space * #Stop),
|
279
|
+
|
280
|
+
Statement = (Import + While + With + For + ForEach + Switch + Return
|
281
|
+
+ ClassDecl + Export + BreakLoop + Ct(ExpList) / flatten_or_mark"explist" * Space) * ((
|
282
|
+
-- statement decorators
|
283
|
+
key"if" * Exp * (key"else" * Exp)^-1 * Space / mark"if" +
|
284
|
+
CompInner / mark"comprehension"
|
285
|
+
) * Space)^-1 / wrap_decorator,
|
286
|
+
|
287
|
+
Body = Space^-1 * Break * EmptyLine^0 * InBlock + Ct(Statement), -- either a statement, or an indented block
|
288
|
+
|
289
|
+
Advance = #Cmt(Indent, advance_indent), -- Advances the indent, gives back whitespace for CheckIndent
|
290
|
+
PushIndent = Cmt(Indent, push_indent),
|
291
|
+
PreventIndent = Cmt(Cc(-1), push_indent),
|
292
|
+
PopIndent = Cmt("", pop_indent),
|
293
|
+
InBlock = Advance * Block * PopIndent,
|
294
|
+
|
295
|
+
Import = key"import" * Ct(ImportNameList) * key"from" * Exp / mark"import",
|
296
|
+
ImportName = (sym"\\" * Ct(Cc"colon_stub" * Name) + Name),
|
297
|
+
ImportNameList = ImportName * (sym"," * ImportName)^0,
|
298
|
+
|
299
|
+
NameList = Name * (sym"," * Name)^0,
|
300
|
+
|
301
|
+
BreakLoop = Ct(key"break"/trim),
|
302
|
+
|
303
|
+
Return = key"return" * (ExpListLow/mark"explist" + C"") / mark"return",
|
304
|
+
|
305
|
+
With = key"with" * Exp * key"do"^-1 * Body / mark"with",
|
306
|
+
|
307
|
+
Switch = key"switch" * Exp * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch",
|
308
|
+
|
309
|
+
SwitchBlock = EmptyLine^0 * Advance * Ct(SwitchCase * (Break^1 * SwitchCase)^0 * (Break^1 * SwitchElse)^-1) * PopIndent,
|
310
|
+
SwitchCase = key"when" * Exp * key"then"^-1 * Body / mark"case",
|
311
|
+
SwitchElse = key"else" * Body / mark"else",
|
312
|
+
|
313
|
+
If = key"if" * Exp * key"then"^-1 * Body *
|
314
|
+
((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * Exp * key"then"^-1 * Body / mark"elseif")^0 *
|
315
|
+
((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"if",
|
316
|
+
|
317
|
+
While = key"while" * Exp * key"do"^-1 * Body / mark"while",
|
318
|
+
|
319
|
+
For = key"for" * (Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1)) *
|
320
|
+
key"do"^-1 * Body / mark"for",
|
321
|
+
|
322
|
+
ForEach = key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) * key"do"^-1 * Body / mark"foreach",
|
323
|
+
|
324
|
+
Comprehension = sym"[" * Exp * CompInner * sym"]" / mark"comprehension",
|
325
|
+
|
326
|
+
TblComprehension = sym"{" * Exp * (sym"," * Exp)^-1 * CompInner * sym"}" / mark"tblcomprehension",
|
327
|
+
|
328
|
+
CompInner = Ct(CompFor * CompClause^0),
|
329
|
+
CompFor = key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) / mark"for",
|
330
|
+
CompClause = CompFor + key"when" * Exp / mark"when",
|
331
|
+
|
332
|
+
Assign = Ct(AssignableList) * sym"=" * (Ct(With + If + Switch) + Ct(TableBlock + ExpListLow)) / mark"assign",
|
333
|
+
Update = Assignable * ((sym"..=" + sym"+=" + sym"-=" + sym"*=" + sym"/=" + sym"%=")/trim) * Exp / mark"update",
|
334
|
+
|
335
|
+
-- we can ignore precedence for now
|
336
|
+
OtherOps = op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<" + op">",
|
337
|
+
|
338
|
+
Assignable = Cmt(DotChain + Chain, check_assignable) + Name,
|
339
|
+
AssignableList = Assignable * (sym"," * Assignable)^0,
|
340
|
+
|
341
|
+
Exp = Ct(Value * ((OtherOps + FactorOp + TermOp) * Value)^0) / flatten_or_mark"exp",
|
342
|
+
|
343
|
+
-- Exp = Ct(Factor * (OtherOps * Factor)^0) / flatten_or_mark"exp",
|
344
|
+
-- Factor = Ct(Term * (FactorOp * Term)^0) / flatten_or_mark"exp",
|
345
|
+
-- Term = Ct(Value * (TermOp * Value)^0) / flatten_or_mark"exp",
|
346
|
+
|
347
|
+
SimpleValue =
|
348
|
+
If +
|
349
|
+
Switch +
|
350
|
+
With +
|
351
|
+
ForEach + For + While +
|
352
|
+
sym"-" * -SomeSpace * Exp / mark"minus" +
|
353
|
+
sym"#" * Exp / mark"length" +
|
354
|
+
key"not" * Exp / mark"not" +
|
355
|
+
TblComprehension +
|
356
|
+
TableLit +
|
357
|
+
Comprehension +
|
358
|
+
Assign + Update + FunLit + String +
|
359
|
+
Num,
|
360
|
+
|
361
|
+
ChainValue = -- a function call or an object access
|
362
|
+
((Chain + DotChain + Callable) * Ct(InvokeArgs^-1)) / flatten_func,
|
363
|
+
|
364
|
+
Value = pos(
|
365
|
+
SimpleValue +
|
366
|
+
Ct(KeyValueList) / mark"table" +
|
367
|
+
ChainValue),
|
368
|
+
|
369
|
+
SliceValue = SimpleValue + ChainValue,
|
370
|
+
|
371
|
+
String = Space * DoubleString + Space * SingleString + LuaString,
|
372
|
+
SingleString = simple_string("'"),
|
373
|
+
DoubleString = simple_string('"'),
|
374
|
+
|
375
|
+
LuaString = Cg(LuaStringOpen, "string_open") * Cb"string_open" * Break^-1 *
|
376
|
+
C((1 - Cmt(C(LuaStringClose) * Cb"string_open", check_lua_string))^0) *
|
377
|
+
C(LuaStringClose) / mark"string",
|
378
|
+
|
379
|
+
LuaStringOpen = sym"[" * P"="^0 * "[" / trim,
|
380
|
+
LuaStringClose = "]" * P"="^0 * "]",
|
381
|
+
|
382
|
+
Callable = Name + Parens / mark"parens",
|
383
|
+
Parens = sym"(" * Exp * sym")",
|
384
|
+
|
385
|
+
FnArgs = symx"(" * Ct(ExpList^-1) * sym")" + sym"!" * -P"=" * Ct"",
|
386
|
+
|
387
|
+
ChainTail = (ChainItem^1 * ColonSuffix^-1 + ColonSuffix),
|
388
|
+
|
389
|
+
-- a list of funcalls and indexs on a callable
|
390
|
+
Chain = Callable * (ChainItem^1 * ColonSuffix^-1 + ColonSuffix) / mark"chain",
|
391
|
+
|
392
|
+
-- shorthand dot call for use in with statement
|
393
|
+
DotChain =
|
394
|
+
(sym"." * Cc(-1) * (_Name / mark"dot") * ChainTail^-1) / mark"chain" +
|
395
|
+
(sym"\\" * Cc(-1) * (
|
396
|
+
(_Name * Invoke / mark"colon") * ChainTail^-1 +
|
397
|
+
(_Name / mark"colon_stub")
|
398
|
+
)) / mark"chain",
|
399
|
+
|
400
|
+
ChainItem =
|
401
|
+
Invoke +
|
402
|
+
Slice +
|
403
|
+
symx"[" * Exp/mark"index" * sym"]" +
|
404
|
+
symx"." * _Name/mark"dot" +
|
405
|
+
ColonCall,
|
406
|
+
|
407
|
+
Slice = symx"[" * (SliceValue + Cc(1)) * sym"," * (SliceValue + Cc"") *
|
408
|
+
(sym"," * SliceValue)^-1 *sym"]" / mark"slice",
|
409
|
+
|
410
|
+
ColonCall = symx"\\" * (_Name * Invoke) / mark"colon",
|
411
|
+
ColonSuffix = symx"\\" * _Name / mark"colon_stub",
|
412
|
+
|
413
|
+
Invoke = FnArgs/mark"call" +
|
414
|
+
SingleString / wrap_func_arg +
|
415
|
+
DoubleString / wrap_func_arg,
|
416
|
+
|
417
|
+
TableValue = KeyValue + Ct(Exp),
|
418
|
+
|
419
|
+
TableLit = sym"{" * Ct(
|
420
|
+
TableValueList^-1 * sym","^-1 *
|
421
|
+
(SpaceBreak * TableLitLine * (sym","^-1 * SpaceBreak * TableLitLine)^0 * sym","^-1)^-1
|
422
|
+
) * White * sym"}" / mark"table",
|
423
|
+
|
424
|
+
TableValueList = TableValue * (sym"," * TableValue)^0,
|
425
|
+
TableLitLine = PushIndent * ((TableValueList * PopIndent) + (PopIndent * Cut)) + Space,
|
426
|
+
|
427
|
+
-- the unbounded table
|
428
|
+
TableBlockInner = Ct(KeyValueLine * (SpaceBreak^1 * KeyValueLine)^0),
|
429
|
+
TableBlock = SpaceBreak^1 * Advance * ensure(TableBlockInner, PopIndent) / mark"table",
|
430
|
+
|
431
|
+
ClassDecl = key"class" * Name * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * ClassBlock / mark"class",
|
432
|
+
|
433
|
+
ClassBlock = SpaceBreak^1 * Advance *
|
434
|
+
Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent,
|
435
|
+
ClassLine = CheckIndent * ((
|
436
|
+
KeyValueList / mark"props" +
|
437
|
+
Exp / mark"stm"
|
438
|
+
) * sym","^-1),
|
439
|
+
|
440
|
+
Export = key"export" * (
|
441
|
+
Cc"class" * ClassDecl +
|
442
|
+
op"*" + op"^" +
|
443
|
+
Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export",
|
444
|
+
|
445
|
+
KeyValue = (sym":" * Name) / self_assign + Ct((SimpleName + sym"[" * Exp * sym"]") * symx":" * (Exp + TableBlock)),
|
446
|
+
KeyValueList = KeyValue * (sym"," * KeyValue)^0,
|
447
|
+
KeyValueLine = CheckIndent * KeyValueList * sym","^-1,
|
448
|
+
|
449
|
+
FnArgsDef = sym"(" * Ct(FnArgDefList^-1) *
|
450
|
+
(key"using" * Ct(NameList + Space * "nil") + Ct"") *
|
451
|
+
sym")" + Ct"" * Ct"",
|
452
|
+
|
453
|
+
FnArgDefList = FnArgDef * (sym"," * FnArgDef)^0,
|
454
|
+
FnArgDef = Ct(Name * (sym"=" * Exp)^-1),
|
455
|
+
|
456
|
+
FunLit = FnArgsDef *
|
457
|
+
(sym"->" * Cc"slim" + sym"=>" * Cc"fat") *
|
458
|
+
(Body + Ct"") / mark"fndef",
|
459
|
+
|
460
|
+
NameList = Name * (sym"," * Name)^0,
|
461
|
+
ExpList = Exp * (sym"," * Exp)^0,
|
462
|
+
ExpListLow = Exp * ((sym"," + sym";") * Exp)^0,
|
463
|
+
|
464
|
+
InvokeArgs = ExpList * (sym"," * (TableBlock + SpaceBreak * Advance * ArgBlock * TableBlock^-1) + TableBlock)^-1 + TableBlock,
|
465
|
+
ArgBlock = ArgLine * (sym"," * SpaceBreak * ArgLine)^0 * PopIndent,
|
466
|
+
ArgLine = CheckIndent * ExpList
|
467
|
+
}
|
468
|
+
|
469
|
+
return {
|
470
|
+
_g = White * g * White * -1,
|
471
|
+
match = function(self, str, ...)
|
472
|
+
|
473
|
+
local pos_to_line = function(pos)
|
474
|
+
return util.pos_to_line(str, pos)
|
475
|
+
end
|
476
|
+
|
477
|
+
local get_line = function(num)
|
478
|
+
return util.get_line(str, num)
|
479
|
+
end
|
480
|
+
|
481
|
+
local tree
|
482
|
+
local args = {...}
|
483
|
+
local pass, err = assert(pcall(function()
|
484
|
+
tree = self._g:match(str, unpack(args))
|
485
|
+
end))
|
486
|
+
|
487
|
+
if not tree then
|
488
|
+
local line_no = pos_to_line(last_pos)
|
489
|
+
local line_str = get_line(line_no) or ""
|
490
|
+
|
491
|
+
return nil, err_msg:format(line_no, trim(line_str), _indent:top())
|
492
|
+
end
|
493
|
+
return tree
|
494
|
+
end
|
495
|
+
}
|
496
|
+
|
497
|
+
end)
|
498
|
+
|
499
|
+
-- parse a string
|
500
|
+
-- returns tree, or nil and error message
|
501
|
+
function string(str)
|
502
|
+
local g = build_grammar()
|
503
|
+
return g:match(str)
|
504
|
+
end
|
505
|
+
|