diff options
| author | Sergio Queiroz <sqmedeiros@gmail.com> | 2016-07-01 14:57:39 -0300 |
|---|---|---|
| committer | Sergio Queiroz <sqmedeiros@gmail.com> | 2016-07-01 14:57:39 -0300 |
| commit | 7cd05bfaeea0fc1d269ace114d3225bffbd82940 (patch) | |
| tree | 955ed449edeed25506a3b47977840d642dad5026 | |
| parent | 6a3c4bfddcfaa0e1348aa2c3d9fb7135a4f330c8 (diff) | |
| download | lpeglabel-7cd05bfaeea0fc1d269ace114d3225bffbd82940.tar.gz lpeglabel-7cd05bfaeea0fc1d269ace114d3225bffbd82940.tar.bz2 lpeglabel-7cd05bfaeea0fc1d269ace114d3225bffbd82940.zip | |
Adding function 'calcline' to relabel and updating documentation/examples
| -rw-r--r-- | README.md | 201 | ||||
| -rw-r--r-- | examples/listId1.lua | 11 | ||||
| -rw-r--r-- | examples/listId2.lua | 32 | ||||
| -rw-r--r-- | examples/listIdCatch.lua | 35 | ||||
| -rw-r--r-- | examples/listIdRe1.lua | 35 | ||||
| -rw-r--r-- | examples/listIdRe2.lua | 30 | ||||
| -rw-r--r-- | relabel.lua | 11 |
7 files changed, 250 insertions, 105 deletions
| @@ -43,6 +43,9 @@ of the new functions provided by LpegLabel: | |||
| 43 | <tr><td><a href="#re-lc"><code>p1 /{l1, ..., ln} p2</code></a></td> | 43 | <tr><td><a href="#re-lc"><code>p1 /{l1, ..., ln} p2</code></a></td> |
| 44 | <td>Syntax of <em>relabel</em> module. Equivalent to <code>lpeg.Lc(p1, p2, l1, ..., ln)</code> | 44 | <td>Syntax of <em>relabel</em> module. Equivalent to <code>lpeg.Lc(p1, p2, l1, ..., ln)</code> |
| 45 | </td></tr> | 45 | </td></tr> |
| 46 | <tr><td><a href="#re-line"><code>relabel.calcline(subject, i)</code></a></td> | ||
| 47 | <td>Calculates line and column information regarding position <i>i</i> of the subject</code> | ||
| 48 | </td></tr> | ||
| 46 | <tr><td><a href="#re-setl"><code>relabel.setlabels (tlabel)</code></a></td> | 49 | <tr><td><a href="#re-setl"><code>relabel.setlabels (tlabel)</code></a></td> |
| 47 | <td>Allows to specicify a table with mnemonic labels. | 50 | <td>Allows to specicify a table with mnemonic labels. |
| 48 | </td></tr> | 51 | </td></tr> |
| @@ -92,6 +95,11 @@ but a single choice can not mix them. That is, the parser of `relabel` | |||
| 92 | module will not recognize a pattern as `p1 / p2 /{l1} p3`. | 95 | module will not recognize a pattern as `p1 / p2 /{l1} p3`. |
| 93 | 96 | ||
| 94 | 97 | ||
| 98 | #### <a name="re-line"></a><code>relabel.calcline (subject, i)</code> | ||
| 99 | |||
| 100 | Returns line and column information regarding position <i>i</i> of the subject. | ||
| 101 | |||
| 102 | |||
| 95 | #### <a name="re-setl"></a><code>relabel.setlabels (tlabel)</code> | 103 | #### <a name="re-setl"></a><code>relabel.setlabels (tlabel)</code> |
| 96 | 104 | ||
| 97 | Allows to specicify a table with labels. They keys of | 105 | Allows to specicify a table with labels. They keys of |
| @@ -101,22 +109,21 @@ and the associated values should be strings. | |||
| 101 | 109 | ||
| 102 | ### Examples | 110 | ### Examples |
| 103 | 111 | ||
| 104 | #### Throwing a label | 112 | Below there a few examples of usage of LPegLabel. |
| 113 | The code of these and of other examples is available | ||
| 114 | in the *examples* directory. | ||
| 115 | |||
| 116 | |||
| 117 | #### Matching a list of identifiers separated by commas | ||
| 105 | 118 | ||
| 106 | The following example defines a grammar that matches | 119 | The following example defines a grammar that matches |
| 107 | a list of identifiers separated by commas. A label | 120 | a list of identifiers separated by commas. A label |
| 108 | is thrown when there is an error matching an identifier | 121 | is thrown when there is an error matching an identifier |
| 109 | or a comma: | 122 | or a comma: |
| 110 | 123 | ||
| 111 | ```lua | 124 | ```lua |
| 112 | local m = require'lpeglabel' | 125 | local m = require'lpeglabel' |
| 113 | 126 | local re = require'relabel' | |
| 114 | local function calcline (s, i) | ||
| 115 | if i == 1 then return 1, 1 end | ||
| 116 | local rest, line = s:sub(1,i):gsub("[^\n]*\n", "") | ||
| 117 | local col = #rest | ||
| 118 | return 1 + line, col ~= 0 and col or 1 | ||
| 119 | end | ||
| 120 | 127 | ||
| 121 | local g = m.P{ | 128 | local g = m.P{ |
| 122 | "S", | 129 | "S", |
| @@ -130,7 +137,7 @@ local g = m.P{ | |||
| 130 | function mymatch (g, s) | 137 | function mymatch (g, s) |
| 131 | local r, e, sfail = g:match(s) | 138 | local r, e, sfail = g:match(s) |
| 132 | if not r then | 139 | if not r then |
| 133 | local line, col = calcline(s, #s - #sfail) | 140 | local line, col = re.calcline(s, #s - #sfail) |
| 134 | local msg = "Error at line " .. line .. " (col " .. col .. ")" | 141 | local msg = "Error at line " .. line .. " (col " .. col .. ")" |
| 135 | if e == 1 then | 142 | if e == 1 then |
| 136 | return r, msg .. ": expecting an identifier before '" .. sfail .. "'" | 143 | return r, msg .. ": expecting an identifier before '" .. sfail .. "'" |
| @@ -142,6 +149,61 @@ function mymatch (g, s) | |||
| 142 | end | 149 | end |
| 143 | return r | 150 | return r |
| 144 | end | 151 | end |
| 152 | |||
| 153 | print(mymatch(g, "one,two")) --> 8 | ||
| 154 | print(mymatch(g, "one two")) --> nil Error at line 1 (col 3): expecting ',' before ' two' | ||
| 155 | print(mymatch(g, "one,\n two,\nthree,")) --> nil Error at line 3 (col 6): expecting an identifier before '' | ||
| 156 | ``` | ||
| 157 | |||
| 158 | In this example we could think about writing rule <em>List</em> as follows: | ||
| 159 | ```lua | ||
| 160 | List = ((m.V"Comma" + m.T(2)) * (m.V"Id" + m.T(1)))^0, | ||
| 161 | ``` | ||
| 162 | |||
| 163 | but when matching this expression agains the end of input | ||
| 164 | we would get a failure whose associated label would be **2**, | ||
| 165 | and this would cause the failure of the *whole* repetition. | ||
| 166 | |||
| 167 | |||
| 168 | ##### Mnemonics instead of numbers | ||
| 169 | |||
| 170 | In the previous example we could have created a table | ||
| 171 | with the error messages to improve the readbility of the PEG. | ||
| 172 | Below we rewrite the previous grammar following this approach: | ||
| 173 | |||
| 174 | ```lua | ||
| 175 | local m = require'lpeglabel' | ||
| 176 | local re = require'relabel' | ||
| 177 | |||
| 178 | local terror = {} | ||
| 179 | |||
| 180 | local function newError(s) | ||
| 181 | table.insert(terror, s) | ||
| 182 | return #terror | ||
| 183 | end | ||
| 184 | |||
| 185 | local errUndef = newError("undefined") | ||
| 186 | local errId = newError("expecting an identifier") | ||
| 187 | local errComma = newError("expecting ','") | ||
| 188 | |||
| 189 | local g = m.P{ | ||
| 190 | "S", | ||
| 191 | S = m.V"Id" * m.V"List", | ||
| 192 | List = -m.P(1) + (m.V"Comma" + m.T(errComma)) * (m.V"Id" + m.T(errId)) * m.V"List", | ||
| 193 | Id = m.V"Sp" * m.R'az'^1, | ||
| 194 | Comma = m.V"Sp" * ",", | ||
| 195 | Sp = m.S" \n\t"^0, | ||
| 196 | } | ||
| 197 | |||
| 198 | function mymatch (g, s) | ||
| 199 | local r, e, sfail = g:match(s) | ||
| 200 | if not r then | ||
| 201 | local line, col = re.calcline(s, #s - #sfail) | ||
| 202 | local msg = "Error at line " .. line .. " (col " .. col .. "): " | ||
| 203 | return r, msg .. terror[e] .. " before '" .. sfail .. "'" | ||
| 204 | end | ||
| 205 | return r | ||
| 206 | end | ||
| 145 | 207 | ||
| 146 | print(mymatch(g, "one,two")) --> 8 | 208 | print(mymatch(g, "one,two")) --> 8 |
| 147 | print(mymatch(g, "one two")) --> nil Error at line 1 (col 3): expecting ',' before ' two' | 209 | print(mymatch(g, "one two")) --> nil Error at line 1 (col 3): expecting ',' before ' two' |
| @@ -149,6 +211,88 @@ print(mymatch(g, "one,\n two,\nthree,")) --> nil Error at line 3 (col 6): expec | |||
| 149 | ``` | 211 | ``` |
| 150 | 212 | ||
| 151 | 213 | ||
| 214 | ##### *relabel* syntax | ||
| 215 | |||
| 216 | Now we rewrite the previous example using the syntax | ||
| 217 | supported by *relabel*: | ||
| 218 | |||
| 219 | ```lua | ||
| 220 | local re = require 'relabel' | ||
| 221 | |||
| 222 | local g = re.compile[[ | ||
| 223 | S <- Id List | ||
| 224 | List <- !. / (',' / %{2}) (Id / %{1}) List | ||
| 225 | Id <- Sp [a-z]+ | ||
| 226 | Comma <- Sp ',' | ||
| 227 | Sp <- %s* | ||
| 228 | ]] | ||
| 229 | |||
| 230 | function mymatch (g, s) | ||
| 231 | local r, e, sfail = g:match(s) | ||
| 232 | if not r then | ||
| 233 | local line, col = re.calcline(s, #s - #sfail) | ||
| 234 | local msg = "Error at line " .. line .. " (col " .. col .. ")" | ||
| 235 | if e == 1 then | ||
| 236 | return r, msg .. ": expecting an identifier before '" .. sfail .. "'" | ||
| 237 | elseif e == 2 then | ||
| 238 | return r, msg .. ": expecting ',' before '" .. sfail .. "'" | ||
| 239 | else | ||
| 240 | return r, msg | ||
| 241 | end | ||
| 242 | end | ||
| 243 | return r | ||
| 244 | end | ||
| 245 | |||
| 246 | print(mymatch(g, "one,two")) --> 8 | ||
| 247 | print(mymatch(g, "one two")) --> nil Error at line 1 (col 3): expecting ',' before ' two' | ||
| 248 | print(mymatch(g, "one,\n two,\nthree,")) --> nil Error at line 3 (col 6): expecting an identifier before '' | ||
| 249 | ``` | ||
| 250 | |||
| 251 | With the help of function *setlabels* we can also rewrite the previous example to use | ||
| 252 | mnemonic labels instead of plain numbers: | ||
| 253 | |||
| 254 | ```lua | ||
| 255 | local re = require 'relabel' | ||
| 256 | |||
| 257 | local errinfo = { | ||
| 258 | {"errUndef", "undefined"}, | ||
| 259 | {"errId", "expecting an identifier"}, | ||
| 260 | {"errComma", "expecting ','"}, | ||
| 261 | } | ||
| 262 | |||
| 263 | local errmsgs = {} | ||
| 264 | local labels = {} | ||
| 265 | |||
| 266 | for i, err in ipairs(errinfo) do | ||
| 267 | errmsgs[i] = err[2] | ||
| 268 | labels[err[1]] = i | ||
| 269 | end | ||
| 270 | |||
| 271 | re.setlabels(labels) | ||
| 272 | |||
| 273 | local g = re.compile[[ | ||
| 274 | S <- Id List | ||
| 275 | List <- !. / (',' / %{errComma}) (Id / %{errId}) List | ||
| 276 | Id <- Sp [a-z]+ | ||
| 277 | Comma <- Sp ',' | ||
| 278 | Sp <- %s* | ||
| 279 | ]] | ||
| 280 | |||
| 281 | function mymatch (g, s) | ||
| 282 | local r, e, sfail = g:match(s) | ||
| 283 | if not r then | ||
| 284 | local line, col = re.calcline(s, #s - #sfail) | ||
| 285 | local msg = "Error at line " .. line .. " (col " .. col .. "): " | ||
| 286 | return r, msg .. errmsgs[e] .. " before '" .. sfail .. "'" | ||
| 287 | end | ||
| 288 | return r | ||
| 289 | end | ||
| 290 | |||
| 291 | print(mymatch(g, "one,two")) --> 8 | ||
| 292 | print(mymatch(g, "one two")) --> nil Error at line 1 (col 3): expecting ',' before ' two' | ||
| 293 | print(mymatch(g, "one,\n two,\nthree,")) --> nil Error at line 3 (col 6): expecting an identifier before '' | ||
| 294 | ``` | ||
| 295 | |||
| 152 | #### Arithmetic Expressions | 296 | #### Arithmetic Expressions |
| 153 | 297 | ||
| 154 | Here's an example of an LPegLabel grammar that make its own function called | 298 | Here's an example of an LPegLabel grammar that make its own function called |
| @@ -239,3 +383,40 @@ print(eval "-1+(1-(1*2))/2") | |||
| 239 | --> syntax error: no expression found (at index 1) | 383 | --> syntax error: no expression found (at index 1) |
| 240 | ``` | 384 | ``` |
| 241 | 385 | ||
| 386 | #### Catching labels | ||
| 387 | |||
| 388 | When a label is thrown, the grammar itself can handle this label | ||
| 389 | by using the labeled ordered choice. Below we rewrite the example | ||
| 390 | of the list of identifiers to show this feature: | ||
| 391 | |||
| 392 | |||
| 393 | ```lua | ||
| 394 | local m = require'lpeglabel' | ||
| 395 | |||
| 396 | local terror = {} | ||
| 397 | |||
| 398 | local function newError(s) | ||
| 399 | table.insert(terror, s) | ||
| 400 | return #terror | ||
| 401 | end | ||
| 402 | |||
| 403 | local errUndef = newError("undefined") | ||
| 404 | local errId = newError("expecting an identifier") | ||
| 405 | local errComma = newError("expecting ','") | ||
| 406 | |||
| 407 | local g = m.P{ | ||
| 408 | "S", | ||
| 409 | S = m.Lc(m.Lc(m.V"Id" * m.V"List", m.V"ErrId", errId), | ||
| 410 | m.V"ErrComma", errComma), | ||
| 411 | List = -m.P(1) + (m.V"Comma" + m.T(errComma)) * (m.V"Id" + m.T(errId)) * m.V"List", | ||
| 412 | Id = m.V"Sp" * m.R'az'^1, | ||
| 413 | Comma = m.V"Sp" * ",", | ||
| 414 | Sp = m.S" \n\t"^0, | ||
| 415 | ErrId = m.Cc(errId) / terror, | ||
| 416 | ErrComma = m.Cc(errComma) / terror | ||
| 417 | } | ||
| 418 | |||
| 419 | print(m.match(g, "one,two")) --> 8 | ||
| 420 | print(m.match(g, "one two")) --> expecting ',' | ||
| 421 | print(m.match(g, "one,\n two,\nthree,")) --> expecting an identifier | ||
| 422 | ``` | ||
diff --git a/examples/listId1.lua b/examples/listId1.lua index 12c0678..8976f5f 100644 --- a/examples/listId1.lua +++ b/examples/listId1.lua | |||
| @@ -1,11 +1,5 @@ | |||
| 1 | local m = require'lpeglabel' | 1 | local m = require'lpeglabel' |
| 2 | 2 | local re = require'relabel' | |
| 3 | local function calcline (s, i) | ||
| 4 | if i == 1 then return 1, 1 end | ||
| 5 | local rest, line = s:sub(1,i):gsub("[^\n]*\n", "") | ||
| 6 | local col = #rest | ||
| 7 | return 1 + line, col ~= 0 and col or 1 | ||
| 8 | end | ||
| 9 | 3 | ||
| 10 | local g = m.P{ | 4 | local g = m.P{ |
| 11 | "S", | 5 | "S", |
| @@ -19,7 +13,7 @@ local g = m.P{ | |||
| 19 | function mymatch (g, s) | 13 | function mymatch (g, s) |
| 20 | local r, e, sfail = g:match(s) | 14 | local r, e, sfail = g:match(s) |
| 21 | if not r then | 15 | if not r then |
| 22 | local line, col = calcline(s, #s - #sfail) | 16 | local line, col = re.calcline(s, #s - #sfail) |
| 23 | local msg = "Error at line " .. line .. " (col " .. col .. ")" | 17 | local msg = "Error at line " .. line .. " (col " .. col .. ")" |
| 24 | if e == 1 then | 18 | if e == 1 then |
| 25 | return r, msg .. ": expecting an identifier before '" .. sfail .. "'" | 19 | return r, msg .. ": expecting an identifier before '" .. sfail .. "'" |
| @@ -35,4 +29,3 @@ end | |||
| 35 | print(mymatch(g, "one,two")) | 29 | print(mymatch(g, "one,two")) |
| 36 | print(mymatch(g, "one two")) | 30 | print(mymatch(g, "one two")) |
| 37 | print(mymatch(g, "one,\n two,\nthree,")) | 31 | print(mymatch(g, "one,\n two,\nthree,")) |
| 38 | |||
diff --git a/examples/listId2.lua b/examples/listId2.lua index 48157f1..509fda4 100644 --- a/examples/listId2.lua +++ b/examples/listId2.lua | |||
| @@ -1,42 +1,36 @@ | |||
| 1 | local m = require'lpeglabel' | 1 | local m = require'lpeglabel' |
| 2 | local re = require'relabel' | ||
| 2 | 3 | ||
| 3 | local terror = {} | 4 | local terror = {} |
| 4 | 5 | ||
| 5 | local function newError(s) | 6 | local function newError(s) |
| 6 | table.insert(terror, s) | 7 | table.insert(terror, s) |
| 7 | return #terror | 8 | return #terror |
| 8 | end | 9 | end |
| 9 | 10 | ||
| 10 | local errUndef = newError("undefined") | 11 | local errUndef = newError("undefined") |
| 11 | local errId = newError("expecting an identifier") | 12 | local errId = newError("expecting an identifier") |
| 12 | local errComma = newError("expecting ','") | 13 | local errComma = newError("expecting ','") |
| 13 | 14 | ||
| 14 | local function calcline (s, i) | ||
| 15 | if i == 1 then return 1, 1 end | ||
| 16 | local rest, line = s:sub(1,i):gsub("[^\n]*\n", "") | ||
| 17 | local col = #rest | ||
| 18 | return 1 + line, col ~= 0 and col or 1 | ||
| 19 | end | ||
| 20 | |||
| 21 | local g = m.P{ | 15 | local g = m.P{ |
| 22 | "S", | 16 | "S", |
| 23 | S = m.V"Id" * m.V"List", | 17 | S = m.V"Id" * m.V"List", |
| 24 | List = -m.P(1) + (m.V"Comma" + m.T(errComma)) * (m.V"Id" + m.T(errId)) * m.V"List", | 18 | List = -m.P(1) + (m.V"Comma" + m.T(errComma)) * (m.V"Id" + m.T(errId)) * m.V"List", |
| 25 | Id = m.V"Sp" * m.R'az'^1, | 19 | Id = m.V"Sp" * m.R'az'^1, |
| 26 | Comma = m.V"Sp" * ",", | 20 | Comma = m.V"Sp" * ",", |
| 27 | Sp = m.S" \n\t"^0, | 21 | Sp = m.S" \n\t"^0, |
| 28 | } | 22 | } |
| 29 | 23 | ||
| 30 | function mymatch (g, s) | 24 | function mymatch (g, s) |
| 31 | local r, e, sfail = g:match(s) | 25 | local r, e, sfail = g:match(s) |
| 32 | if not r then | 26 | if not r then |
| 33 | local line, col = calcline(s, #s - #sfail) | 27 | local line, col = re.calcline(s, #s - #sfail) |
| 34 | local msg = "Error at line " .. line .. " (col " .. col .. "): " | 28 | local msg = "Error at line " .. line .. " (col " .. col .. "): " |
| 35 | return r, msg .. terror[e] .. " before '" .. sfail .. "'" | 29 | return r, msg .. terror[e] .. " before '" .. sfail .. "'" |
| 36 | end | 30 | end |
| 37 | return r | 31 | return r |
| 38 | end | 32 | end |
| 39 | 33 | ||
| 40 | print(mymatch(g, "one,two")) | 34 | print(mymatch(g, "one,two")) |
| 41 | print(mymatch(g, "one two")) | 35 | print(mymatch(g, "one two")) |
| 42 | print(mymatch(g, "one,\n two,\nthree,")) | 36 | print(mymatch(g, "one,\n two,\nthree,")) |
diff --git a/examples/listIdCatch.lua b/examples/listIdCatch.lua index 3cbc834..5ad6f2d 100644 --- a/examples/listIdCatch.lua +++ b/examples/listIdCatch.lua | |||
| @@ -3,43 +3,26 @@ local m = require'lpeglabel' | |||
| 3 | local terror = {} | 3 | local terror = {} |
| 4 | 4 | ||
| 5 | local function newError(s) | 5 | local function newError(s) |
| 6 | table.insert(terror, s) | 6 | table.insert(terror, s) |
| 7 | return #terror | 7 | return #terror |
| 8 | end | 8 | end |
| 9 | 9 | ||
| 10 | local errUndef = newError("undefined") | 10 | local errUndef = newError("undefined") |
| 11 | local errId = newError("expecting an identifier") | 11 | local errId = newError("expecting an identifier") |
| 12 | local errComma = newError("expecting ','") | 12 | local errComma = newError("expecting ','") |
| 13 | 13 | ||
| 14 | local function calcline (s, i) | ||
| 15 | if i == 1 then return 1, 1 end | ||
| 16 | local rest, line = s:sub(1,i):gsub("[^\n]*\n", "") | ||
| 17 | local col = #rest | ||
| 18 | return 1 + line, col ~= 0 and col or 1 | ||
| 19 | end | ||
| 20 | |||
| 21 | local g = m.P{ | 14 | local g = m.P{ |
| 22 | "S", | 15 | "S", |
| 23 | S = m.Lc(m.Lc(m.V"Id" * m.V"List", m.V"ErrId", errId), | 16 | S = m.Lc(m.Lc(m.V"Id" * m.V"List", m.V"ErrId", errId), |
| 24 | m.V"ErrComma", errComma), | 17 | m.V"ErrComma", errComma), |
| 25 | List = -m.P(1) + (m.V"Comma" + m.T(errComma)) * (m.V"Id" + m.T(errId)) * m.V"List", | 18 | List = -m.P(1) + (m.V"Comma" + m.T(errComma)) * (m.V"Id" + m.T(errId)) * m.V"List", |
| 26 | Id = m.V"Sp" * m.R'az'^1, | 19 | Id = m.V"Sp" * m.R'az'^1, |
| 27 | Comma = m.V"Sp" * ",", | 20 | Comma = m.V"Sp" * ",", |
| 28 | Sp = m.S" \n\t"^0, | 21 | Sp = m.S" \n\t"^0, |
| 29 | ErrId = m.Cc(errId) / terror, | 22 | ErrId = m.Cc(errId) / terror, |
| 30 | ErrComma = m.Cc(errComma) / terror | 23 | ErrComma = m.Cc(errComma) / terror |
| 31 | } | 24 | } |
| 32 | 25 | ||
| 33 | function mymatch (g, s) | 26 | print(m.match(g, "one,two")) |
| 34 | local r, e, sfail = g:match(s) | 27 | print(m.match(g, "one two")) |
| 35 | if not r then | 28 | print(m.match(g, "one,\n two,\nthree,")) |
| 36 | local line, col = calcline(s, #s - #sfail) | ||
| 37 | local msg = "Error at line " .. line .. " (col " .. col .. "): " | ||
| 38 | return r, msg .. terror[e] .. " before '" .. sfail .. "'" | ||
| 39 | end | ||
| 40 | return r | ||
| 41 | end | ||
| 42 | |||
| 43 | print(mymatch(g, "one,two")) | ||
| 44 | print(mymatch(g, "one two")) | ||
| 45 | print(mymatch(g, "one,\n two,\nthree,")) | ||
diff --git a/examples/listIdRe1.lua b/examples/listIdRe1.lua index 361e53f..d092566 100644 --- a/examples/listIdRe1.lua +++ b/examples/listIdRe1.lua | |||
| @@ -1,34 +1,27 @@ | |||
| 1 | local re = require 'relabel' | 1 | local re = require 'relabel' |
| 2 | 2 | ||
| 3 | local function calcline (s, i) | ||
| 4 | if i == 1 then return 1, 1 end | ||
| 5 | local rest, line = s:sub(1,i):gsub("[^\n]*\n", "") | ||
| 6 | local col = #rest | ||
| 7 | return 1 + line, col ~= 0 and col or 1 | ||
| 8 | end | ||
| 9 | |||
| 10 | local g = re.compile[[ | 3 | local g = re.compile[[ |
| 11 | S <- Id List | 4 | S <- Id List |
| 12 | List <- !. / (',' / %{2}) (Id / %{1}) List | 5 | List <- !. / (',' / %{2}) (Id / %{1}) List |
| 13 | Id <- Sp [a-z]+ | 6 | Id <- Sp [a-z]+ |
| 14 | Comma <- Sp ',' | 7 | Comma <- Sp ',' |
| 15 | Sp <- %s* | 8 | Sp <- %s* |
| 16 | ]] | 9 | ]] |
| 17 | 10 | ||
| 18 | function mymatch (g, s) | 11 | function mymatch (g, s) |
| 19 | local r, e, sfail = g:match(s) | 12 | local r, e, sfail = g:match(s) |
| 20 | if not r then | 13 | if not r then |
| 21 | local line, col = calcline(s, #s - #sfail) | 14 | local line, col = re.calcline(s, #s - #sfail) |
| 22 | local msg = "Error at line " .. line .. " (col " .. col .. ")" | 15 | local msg = "Error at line " .. line .. " (col " .. col .. ")" |
| 23 | if e == 1 then | 16 | if e == 1 then |
| 24 | return r, msg .. ": expecting an identifier before '" .. sfail .. "'" | 17 | return r, msg .. ": expecting an identifier before '" .. sfail .. "'" |
| 25 | elseif e == 2 then | 18 | elseif e == 2 then |
| 26 | return r, msg .. ": expecting ',' before '" .. sfail .. "'" | 19 | return r, msg .. ": expecting ',' before '" .. sfail .. "'" |
| 27 | else | 20 | else |
| 28 | return r, msg | 21 | return r, msg |
| 29 | end | 22 | end |
| 30 | end | 23 | end |
| 31 | return r | 24 | return r |
| 32 | end | 25 | end |
| 33 | 26 | ||
| 34 | print(mymatch(g, "one,two")) | 27 | print(mymatch(g, "one,two")) |
diff --git a/examples/listIdRe2.lua b/examples/listIdRe2.lua index ccb7ce5..fe30535 100644 --- a/examples/listIdRe2.lua +++ b/examples/listIdRe2.lua | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | local re = require 'relabel' | 1 | local re = require 'relabel' |
| 2 | 2 | ||
| 3 | local errinfo = { | 3 | local errinfo = { |
| 4 | {"errUndef", "undefined"}, | 4 | {"errUndef", "undefined"}, |
| 5 | {"errId", "expecting an identifier"}, | 5 | {"errId", "expecting an identifier"}, |
| 6 | {"errComma", "expecting ','"}, | 6 | {"errComma", "expecting ','"}, |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | local errmsgs = {} | 9 | local errmsgs = {} |
| @@ -16,30 +16,22 @@ end | |||
| 16 | 16 | ||
| 17 | re.setlabels(labels) | 17 | re.setlabels(labels) |
| 18 | 18 | ||
| 19 | local function calcline (s, i) | ||
| 20 | if i == 1 then return 1, 1 end | ||
| 21 | local rest, line = s:sub(1,i):gsub("[^\n]*\n", "") | ||
| 22 | local col = #rest | ||
| 23 | return 1 + line, col ~= 0 and col or 1 | ||
| 24 | end | ||
| 25 | |||
| 26 | |||
| 27 | local g = re.compile[[ | 19 | local g = re.compile[[ |
| 28 | S <- Id List | 20 | S <- Id List |
| 29 | List <- !. / (',' / %{errComma}) (Id / %{errId}) List | 21 | List <- !. / (',' / %{errComma}) (Id / %{errId}) List |
| 30 | Id <- Sp [a-z]+ | 22 | Id <- Sp [a-z]+ |
| 31 | Comma <- Sp ',' | 23 | Comma <- Sp ',' |
| 32 | Sp <- %s* | 24 | Sp <- %s* |
| 33 | ]] | 25 | ]] |
| 34 | 26 | ||
| 35 | function mymatch (g, s) | 27 | function mymatch (g, s) |
| 36 | local r, e, sfail = g:match(s) | 28 | local r, e, sfail = g:match(s) |
| 37 | if not r then | 29 | if not r then |
| 38 | local line, col = calcline(s, #s - #sfail) | 30 | local line, col = re.calcline(s, #s - #sfail) |
| 39 | local msg = "Error at line " .. line .. " (col " .. col .. "): " | 31 | local msg = "Error at line " .. line .. " (col " .. col .. "): " |
| 40 | return r, msg .. errmsgs[e] .. " before '" .. sfail .. "'" | 32 | return r, msg .. errmsgs[e] .. " before '" .. sfail .. "'" |
| 41 | end | 33 | end |
| 42 | return r | 34 | return r |
| 43 | end | 35 | end |
| 44 | 36 | ||
| 45 | print(mymatch(g, "one,two")) | 37 | print(mymatch(g, "one,two")) |
diff --git a/relabel.lua b/relabel.lua index 003a0d2..ff2e486 100644 --- a/relabel.lua +++ b/relabel.lua | |||
| @@ -433,6 +433,14 @@ local function setlabels (t) | |||
| 433 | tlabels = t | 433 | tlabels = t |
| 434 | end | 434 | end |
| 435 | 435 | ||
| 436 | local function calcline (s, i) | ||
| 437 | if i == 1 then return 1, 1 end | ||
| 438 | local rest, line = s:sub(1,i):gsub("[^\n]*\n", "") | ||
| 439 | local col = #rest | ||
| 440 | return 1 + line, col ~= 0 and col or 1 | ||
| 441 | end | ||
| 442 | |||
| 443 | |||
| 436 | -- exported names | 444 | -- exported names |
| 437 | local re = { | 445 | local re = { |
| 438 | compile = compile, | 446 | compile = compile, |
| @@ -440,7 +448,8 @@ local re = { | |||
| 440 | find = find, | 448 | find = find, |
| 441 | gsub = gsub, | 449 | gsub = gsub, |
| 442 | updatelocale = updatelocale, | 450 | updatelocale = updatelocale, |
| 443 | setlabels = setlabels | 451 | setlabels = setlabels, |
| 452 | calcline = calcline | ||
| 444 | } | 453 | } |
| 445 | 454 | ||
| 446 | if version == "Lua 5.1" then _G.re = re end | 455 | if version == "Lua 5.1" then _G.re = re end |
