1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
local tllexer = {}
local lpeg = require "lpeglabel"
lpeg.locale(lpeg)
local tlerror = require "tlerror"
function tllexer.try (pat, label)
return pat + lpeg.T(tlerror.labels[label])
end
local function setffp (s, i, t, n)
if not t.ffp or i > t.ffp then
t.ffp = i
t.list = {}
t.list[n] = true
t.expected = "'" .. n .. "'"
elseif i == t.ffp then
if not t.list[n] then
t.list[n] = true
t.expected = "'" .. n .. "', " .. t.expected
end
end
return false
end
local function updateffp (name)
return lpeg.Cmt(lpeg.Carg(1) * lpeg.Cc(name), setffp)
end
tllexer.Shebang = lpeg.P("#") * (lpeg.P(1) - lpeg.P("\n"))^0 * lpeg.P("\n")
local Space = lpeg.space^1
local Equals = lpeg.P("=")^0
local Open = "[" * lpeg.Cg(Equals, "init") * "[" * lpeg.P("\n")^-1
local Close = "]" * lpeg.C(Equals) * "]"
local CloseEQ = lpeg.Cmt(Close * lpeg.Cb("init"),
function (s, i, a, b) return a == b end)
local LongString = Open * (lpeg.P(1) - CloseEQ)^0 * tllexer.try(Close, "LongString") /
function (s, o) return s end
local LongStringCm1 = Open * (lpeg.P(1) - CloseEQ)^0 * Close /
function (s, o) return s end
local Comment = lpeg.Rec(lpeg.P"--" * #Open * (LongStringCm1 / function() return end + lpeg.T(tlerror.labels["LongString"])),
lpeg.T(tlerror.labels["LongComment"]), tlerror.labels["LongString"]) +
lpeg.P("--") * (lpeg.P(1) - lpeg.P("\n"))^0
tllexer.Skip = (Space + Comment)^0
local idStart = lpeg.alpha + lpeg.P("_")
local idRest = lpeg.alnum + lpeg.P("_")
local Keywords = lpeg.P("and") + "break" + "do" + "elseif" + "else" + "end" +
"false" + "for" + "function" + "goto" + "if" + "in" +
"local" + "nil" + "not" + "or" + "repeat" + "return" +
"then" + "true" + "until" + "while"
tllexer.Reserved = Keywords * -idRest
local Identifier = idStart * idRest^0
tllexer.Name = -tllexer.Reserved * Identifier * -idRest
function tllexer.token (pat, name)
return pat * tllexer.Skip + updateffp(name) * lpeg.P(false)
end
function tllexer.symb (str)
return tllexer.token(lpeg.P(str), str)
end
function tllexer.kw (str)
return tllexer.token(lpeg.P(str) * -idRest, str)
end
local Hex = (lpeg.P("0x") + lpeg.P("0X")) * tllexer.try(lpeg.xdigit^1, "Number")
local Expo = lpeg.S("eE") * lpeg.S("+-")^-1 * tllexer.try(lpeg.digit^1, "Number")
local Float = (((lpeg.digit^1 * lpeg.P(".") * lpeg.digit^0 * tllexer.try(-lpeg.P("."), "Number")) +
(lpeg.P(".") * lpeg.digit^1)) * Expo^-1) +
(lpeg.digit^1 * Expo)
local Int = lpeg.digit^1
tllexer.Number = Hex + Float + Int
local ShortString = lpeg.P('"') *
((lpeg.P('\\') * lpeg.P(1)) + (lpeg.P(1) - lpeg.P('"')))^0 *
tllexer.try(lpeg.P('"'), "String") +
lpeg.P("'") *
((lpeg.P("\\") * lpeg.P(1)) + (lpeg.P(1) - lpeg.P("'")))^0 *
tllexer.try(lpeg.P("'"), "String")
tllexer.String = LongString + ShortString
-- for error reporting
tllexer.OneWord = tllexer.Name +
tllexer.Number +
tllexer.String +
tllexer.Reserved +
lpeg.P("...") +
lpeg.P(1)
return tllexer
|