rufus-lua-moon 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|