aboutsummaryrefslogtreecommitdiff
path: root/re.lua
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-02-20 10:13:46 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-02-20 10:13:46 -0300
commite08e5df853560de6482d84066a7accc6a18de545 (patch)
treeee19686bb35da90709a32ed24bf7855de1a3946a /re.lua
downloadlpeg-e08e5df853560de6482d84066a7accc6a18de545.tar.gz
lpeg-e08e5df853560de6482d84066a7accc6a18de545.tar.bz2
lpeg-e08e5df853560de6482d84066a7accc6a18de545.zip
Fist version of LPeg on GIT
LPeg repository is being moved to git. Past versions won't be moved; they are still available in RCS.
Diffstat (limited to 're.lua')
-rw-r--r--re.lua267
1 files changed, 267 insertions, 0 deletions
diff --git a/re.lua b/re.lua
new file mode 100644
index 0000000..6351929
--- /dev/null
+++ b/re.lua
@@ -0,0 +1,267 @@
1-- $Id: re.lua,v 1.46 2018/06/04 16:21:19 roberto Exp $
2
3-- imported functions and modules
4local tonumber, type, print, error = tonumber, type, print, error
5local setmetatable = setmetatable
6local m = require"lpeg"
7
8-- 'm' will be used to parse expressions, and 'mm' will be used to
9-- create expressions; that is, 're' runs on 'm', creating patterns
10-- on 'mm'
11local mm = m
12
13-- pattern's metatable
14local mt = getmetatable(mm.P(0))
15
16
17
18-- No more global accesses after this point
19local version = _VERSION
20if version == "Lua 5.2" then _ENV = nil end
21
22
23local any = m.P(1)
24
25
26-- Pre-defined names
27local Predef = { nl = m.P"\n" }
28
29
30local mem
31local fmem
32local gmem
33
34
35local function updatelocale ()
36 mm.locale(Predef)
37 Predef.a = Predef.alpha
38 Predef.c = Predef.cntrl
39 Predef.d = Predef.digit
40 Predef.g = Predef.graph
41 Predef.l = Predef.lower
42 Predef.p = Predef.punct
43 Predef.s = Predef.space
44 Predef.u = Predef.upper
45 Predef.w = Predef.alnum
46 Predef.x = Predef.xdigit
47 Predef.A = any - Predef.a
48 Predef.C = any - Predef.c
49 Predef.D = any - Predef.d
50 Predef.G = any - Predef.g
51 Predef.L = any - Predef.l
52 Predef.P = any - Predef.p
53 Predef.S = any - Predef.s
54 Predef.U = any - Predef.u
55 Predef.W = any - Predef.w
56 Predef.X = any - Predef.x
57 mem = {} -- restart memoization
58 fmem = {}
59 gmem = {}
60 local mt = {__mode = "v"}
61 setmetatable(mem, mt)
62 setmetatable(fmem, mt)
63 setmetatable(gmem, mt)
64end
65
66
67updatelocale()
68
69
70
71local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end)
72
73
74local function patt_error (s, i)
75 local msg = (#s < i + 20) and s:sub(i)
76 or s:sub(i,i+20) .. "..."
77 msg = ("pattern error near '%s'"):format(msg)
78 error(msg, 2)
79end
80
81local function mult (p, n)
82 local np = mm.P(true)
83 while n >= 1 do
84 if n%2 >= 1 then np = np * p end
85 p = p * p
86 n = n/2
87 end
88 return np
89end
90
91local function equalcap (s, i, c)
92 if type(c) ~= "string" then return nil end
93 local e = #c + i
94 if s:sub(i, e - 1) == c then return e else return nil end
95end
96
97
98local S = (Predef.space + "--" * (any - Predef.nl)^0)^0
99
100local name = m.R("AZ", "az", "__") * m.R("AZ", "az", "__", "09")^0
101
102local arrow = S * "<-"
103
104local seq_follow = m.P"/" + ")" + "}" + ":}" + "~}" + "|}" + (name * arrow) + -1
105
106name = m.C(name)
107
108
109-- a defined name only have meaning in a given environment
110local Def = name * m.Carg(1)
111
112
113local function getdef (id, defs)
114 local c = defs and defs[id]
115 if not c then error("undefined name: " .. id) end
116 return c
117end
118
119-- match a name and return a group of its corresponding definition
120-- and 'f' (to be folded in 'Suffix')
121local function defwithfunc (f)
122 return m.Cg(Def / getdef * m.Cc(f))
123end
124
125
126local num = m.C(m.R"09"^1) * S / tonumber
127
128local String = "'" * m.C((any - "'")^0) * "'" +
129 '"' * m.C((any - '"')^0) * '"'
130
131
132local defined = "%" * Def / function (c,Defs)
133 local cat = Defs and Defs[c] or Predef[c]
134 if not cat then error ("name '" .. c .. "' undefined") end
135 return cat
136end
137
138local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R
139
140local item = (defined + Range + m.C(any)) / m.P
141
142local Class =
143 "["
144 * (m.C(m.P"^"^-1)) -- optional complement symbol
145 * m.Cf(item * (item - "]")^0, mt.__add) /
146 function (c, p) return c == "^" and any - p or p end
147 * "]"
148
149local function adddef (t, k, exp)
150 if t[k] then
151 error("'"..k.."' already defined as a rule")
152 else
153 t[k] = exp
154 end
155 return t
156end
157
158local function firstdef (n, r) return adddef({n}, n, r) end
159
160
161local function NT (n, b)
162 if not b then
163 error("rule '"..n.."' used outside a grammar")
164 else return mm.V(n)
165 end
166end
167
168
169local exp = m.P{ "Exp",
170 Exp = S * ( m.V"Grammar"
171 + m.Cf(m.V"Seq" * ("/" * S * m.V"Seq")^0, mt.__add) );
172 Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix"^0 , mt.__mul)
173 * (#seq_follow + patt_error);
174 Prefix = "&" * S * m.V"Prefix" / mt.__len
175 + "!" * S * m.V"Prefix" / mt.__unm
176 + m.V"Suffix";
177 Suffix = m.Cf(m.V"Primary" * S *
178 ( ( m.P"+" * m.Cc(1, mt.__pow)
179 + m.P"*" * m.Cc(0, mt.__pow)
180 + m.P"?" * m.Cc(-1, mt.__pow)
181 + "^" * ( m.Cg(num * m.Cc(mult))
182 + m.Cg(m.C(m.S"+-" * m.R"09"^1) * m.Cc(mt.__pow))
183 )
184 + "->" * S * ( m.Cg((String + num) * m.Cc(mt.__div))
185 + m.P"{}" * m.Cc(nil, m.Ct)
186 + defwithfunc(mt.__div)
187 )
188 + "=>" * S * defwithfunc(m.Cmt)
189 + "~>" * S * defwithfunc(m.Cf)
190 ) * S
191 )^0, function (a,b,f) return f(a,b) end );
192 Primary = "(" * m.V"Exp" * ")"
193 + String / mm.P
194 + Class
195 + defined
196 + "{:" * (name * ":" + m.Cc(nil)) * m.V"Exp" * ":}" /
197 function (n, p) return mm.Cg(p, n) end
198 + "=" * name / function (n) return mm.Cmt(mm.Cb(n), equalcap) end
199 + m.P"{}" / mm.Cp
200 + "{~" * m.V"Exp" * "~}" / mm.Cs
201 + "{|" * m.V"Exp" * "|}" / mm.Ct
202 + "{" * m.V"Exp" * "}" / mm.C
203 + m.P"." * m.Cc(any)
204 + (name * -arrow + "<" * name * ">") * m.Cb("G") / NT;
205 Definition = name * arrow * m.V"Exp";
206 Grammar = m.Cg(m.Cc(true), "G") *
207 m.Cf(m.V"Definition" / firstdef * m.Cg(m.V"Definition")^0,
208 adddef) / mm.P
209}
210
211local pattern = S * m.Cg(m.Cc(false), "G") * exp / mm.P * (-any + patt_error)
212
213
214local function compile (p, defs)
215 if mm.type(p) == "pattern" then return p end -- already compiled
216 local cp = pattern:match(p, 1, defs)
217 if not cp then error("incorrect pattern", 3) end
218 return cp
219end
220
221local function match (s, p, i)
222 local cp = mem[p]
223 if not cp then
224 cp = compile(p)
225 mem[p] = cp
226 end
227 return cp:match(s, i or 1)
228end
229
230local function find (s, p, i)
231 local cp = fmem[p]
232 if not cp then
233 cp = compile(p) / 0
234 cp = mm.P{ mm.Cp() * cp * mm.Cp() + 1 * mm.V(1) }
235 fmem[p] = cp
236 end
237 local i, e = cp:match(s, i or 1)
238 if i then return i, e - 1
239 else return i
240 end
241end
242
243local function gsub (s, p, rep)
244 local g = gmem[p] or {} -- ensure gmem[p] is not collected while here
245 gmem[p] = g
246 local cp = g[rep]
247 if not cp then
248 cp = compile(p)
249 cp = mm.Cs((cp / rep + 1)^0)
250 g[rep] = cp
251 end
252 return cp:match(s)
253end
254
255
256-- exported names
257local re = {
258 compile = compile,
259 match = match,
260 find = find,
261 gsub = gsub,
262 updatelocale = updatelocale,
263}
264
265if version == "Lua 5.1" then _G.re = re end
266
267return re