match() shortened to just m(), now accepts strings as well as regexps.
I found myself writing a parser with lots of matches in sequence, and wanted something a bit smarter. This adds two bits of smarts: a shorter name and string handling makes something like @seq(m('{'), @string, m('}'))[1] much easier to read and debug.
This commit is contained in:
parent
3cffc3d44e
commit
3d7d9cfe69
|
@ -13,10 +13,10 @@ class Calc extends ReParse
|
||||||
expr: => @chainl @term, @addop
|
expr: => @chainl @term, @addop
|
||||||
term: => @chainl1 @factor, @mulop
|
term: => @chainl1 @factor, @mulop
|
||||||
factor: => @choice @group, @number
|
factor: => @choice @group, @number
|
||||||
group: => @between /^\(/, /^\)/, @expr
|
group: => @between '(', ')', @expr
|
||||||
number: => parseFloat @match(/^(\-?\d+(\.\d+)?)/)
|
number: => parseFloat @m(/^(\-?\d+(\.\d+)?)/)
|
||||||
mulop: => @OPS[@match(/^[\*\/]/)]
|
mulop: => @OPS[@m(/^[\*\/]/)]
|
||||||
addop: => @OPS[@match(/^[\+\-]/)]
|
addop: => @OPS[@m(/^[\+\-]/)]
|
||||||
|
|
||||||
parse: =>
|
parse: =>
|
||||||
super
|
super
|
||||||
|
|
|
@ -5,12 +5,12 @@ class EmailAddress extends ReParse
|
||||||
|
|
||||||
addressList: => @sepEndBy @address, /^\s*,\s*/
|
addressList: => @sepEndBy @address, /^\s*,\s*/
|
||||||
address: => @choice @namedAddress, @bareAddress
|
address: => @choice @namedAddress, @bareAddress
|
||||||
namedAddress: => @seq(@phrase, /^\s*</m, @bareAddress, /^>/)[2]
|
namedAddress: => @seq(@phrase, /^\s*</m, @bareAddress, '>')[2]
|
||||||
bareAddress: => @seq(@word, /^@/, @word).join ""
|
bareAddress: => @seq(@word, '@', @word).join ""
|
||||||
phrase: => @many @word
|
phrase: => @many @word
|
||||||
word: => @skip(/^\s+/).choice @quoted, @dottedAtom
|
word: => @skip(/^\s+/).choice @quoted, @dottedAtom
|
||||||
quoted: => @match /^"(?:\\.|[^"\r\n])+"/m
|
quoted: => @m /^"(?:\\.|[^"\r\n])+"/m
|
||||||
dottedAtom: => @match /^[!#\$%&'\*\+\-\/\w=\?\^`\{\|\}~]+(?:\.[!#\$%&'\*\+\-\/\w=\?\^`\{\|\}~]+)*/m
|
dottedAtom: => @m /^[!#\$%&'\*\+\-\/\w=\?\^`\{\|\}~]+(?:\.[!#\$%&'\*\+\-\/\w=\?\^`\{\|\}~]+)*/m
|
||||||
|
|
||||||
parse: =>
|
parse: =>
|
||||||
super
|
super
|
||||||
|
|
|
@ -10,16 +10,16 @@ class ReJSON extends ReParse
|
||||||
STRING = {"\"": 34, "\\": 92, "/": 47, 'b': 8, 'f': 12, 'n': 10, 'r': 13, 't': 9}
|
STRING = {"\"": 34, "\\": 92, "/": 47, 'b': 8, 'f': 12, 'n': 10, 'r': 13, 't': 9}
|
||||||
|
|
||||||
value: => @choice @literal, @string, @number, @array, @object
|
value: => @choice @literal, @string, @number, @array, @object
|
||||||
object: => @between(/^\{/, /^\}/, @members).reduce ((obj, pair) => obj[pair[0]] = pair[2]; obj), {}
|
object: => @between('{', '}', @members).reduce ((obj, pair) => obj[pair[0]] = pair[2]; obj), {}
|
||||||
members: => @sepBy @pair, /^,/
|
members: => @sepBy @pair, ','
|
||||||
pair: => @seq @string, /^:/, @value
|
pair: => @seq @string, ':', @value
|
||||||
array: => @between /^\[/, /^\]/, @elements
|
array: => @between '[', ']', @elements
|
||||||
elements: => @sepBy @value, /^,/
|
elements: => @sepBy @value, /^,/
|
||||||
literal: => LITERAL[@match(/^(true|false|null)/)]
|
literal: => LITERAL[@m(/^(true|false|null)/)]
|
||||||
number: => parseFloat @match(/^\-?\d+(?:\.\d+)?(?:[eE][\+\-]?\d+)?/)
|
number: => parseFloat @m(/^\-?\d+(?:\.\d+)?(?:[eE][\+\-]?\d+)?/)
|
||||||
|
|
||||||
string: =>
|
string: =>
|
||||||
chars = @match(/^"((?:\\["\\/bfnrt]|\\u[0-9a-fA-F]{4}|[^"\\])*)"/)
|
chars = @m(/^"((?:\\["\\/bfnrt]|\\u[0-9a-fA-F]{4}|[^"\\])*)"/)
|
||||||
chars.replace /\\(["\\/bfnrt])|\\u([0-9a-fA-F]{4})/g, (_, $1, $2) =>
|
chars.replace /\\(["\\/bfnrt])|\\u([0-9a-fA-F]{4})/g, (_, $1, $2) =>
|
||||||
String.fromCharCode (if $1 then STRING[$1] else parseInt($2, 16)) # "
|
String.fromCharCode (if $1 then STRING[$1] else parseInt($2, 16)) # "
|
||||||
|
|
||||||
|
@ -48,4 +48,3 @@ jsonparse = new ReJSON()
|
||||||
time "JSON", 1000, => JSON.parse input
|
time "JSON", 1000, => JSON.parse input
|
||||||
time "PEG.js", 1000, => peg.parse input
|
time "PEG.js", 1000, => peg.parse input
|
||||||
time "ReParse", 1000, => jsonparse.parse(input)
|
time "ReParse", 1000, => jsonparse.parse(input)
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,10 @@ exports.ReParse = class ReParse
|
||||||
# Execute a production, which could be a function or a RegExp.
|
# Execute a production, which could be a function or a RegExp.
|
||||||
|
|
||||||
produce: (method) =>
|
produce: (method) =>
|
||||||
val = if (method instanceof RegExp) then @match(method) else method.call(@)
|
val = if ((method instanceof RegExp) or (typeof method == 'string'))
|
||||||
|
@m(method)
|
||||||
|
else
|
||||||
|
method.call(@)
|
||||||
@skipWS() if @ignorews
|
@skipWS() if @ignorews
|
||||||
val
|
val
|
||||||
|
|
||||||
|
@ -75,7 +78,13 @@ exports.ReParse = class ReParse
|
||||||
#
|
#
|
||||||
# Note that the `return fail()` call eventually leads to a throw.
|
# Note that the `return fail()` call eventually leads to a throw.
|
||||||
|
|
||||||
match: (pattern, putback = false) =>
|
m: (pattern, putback = false) =>
|
||||||
|
if typeof pattern == 'string'
|
||||||
|
if @input.substr(0, pattern.length) == pattern
|
||||||
|
@input = @input.substr(pattern.length)
|
||||||
|
return pattern
|
||||||
|
return @fail()
|
||||||
|
|
||||||
probe = @input.match pattern
|
probe = @input.match pattern
|
||||||
return @fail() unless probe
|
return @fail() unless probe
|
||||||
@input = @input.substr (if probe[1]? and putback then probe[1].length else probe[0].length)
|
@input = @input.substr (if probe[1]? and putback then probe[1].length else probe[0].length)
|
||||||
|
@ -181,7 +190,7 @@ exports.ReParse = class ReParse
|
||||||
# will not skip carriage returns or linefeeds.
|
# will not skip carriage returns or linefeeds.
|
||||||
|
|
||||||
skipWS: =>
|
skipWS: =>
|
||||||
@match(/^\s*/)
|
@m(/^\s*/)
|
||||||
@
|
@
|
||||||
|
|
||||||
# Returns an array of `min` values produced by `method`.
|
# Returns an array of `min` values produced by `method`.
|
||||||
|
@ -292,4 +301,3 @@ exports.ReParse = class ReParse
|
||||||
# if there are zero productions.
|
# if there are zero productions.
|
||||||
|
|
||||||
chainl1: (method, op) => @chainl method, op, null, 1
|
chainl1: (method, op) => @chainl method, op, null, 1
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue