Comparing version 0.1.0 to 0.2.0
{ | ||
"name": "parsimmon", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "A monadic LL(infinity) parser combinator library", | ||
@@ -5,0 +5,0 @@ "keywords": ["parsing", "parse", "parser combinators"], |
@@ -18,4 +18,4 @@ [![Build Status](https://secure.travis-ci.org/jayferd/parsimmon.png)](http://travis-ci.org/jayferd/parsimmon) | ||
var id = regex(/^[a-z_]\w*/i); | ||
var number = regex(/^[0-9]+/).map(parseInt); | ||
var id = regex(/[a-z_]\w*/i); | ||
var number = regex(/[0-9]+/).map(parseInt); | ||
@@ -91,14 +91,18 @@ var atom = number.or(id); | ||
`"my-string"`, and will yield the same. | ||
- `Parsimmon.regex(/^myregex/)` is a parser that expects the stream | ||
to match the given regex. **Due to limitations in javascript's regex | ||
API, the regex must be anchored (with `^` at the beginning).** | ||
- `Parsimmon.regex(/myregex/)` is a parser that expects the stream | ||
to match the given regex. | ||
- `Parsimmon.succeed(result)` is a parser that doesn't consume any of | ||
the string, and yields `result`. | ||
- `Parsimmon.seq(parsers)` accepts an array of parsers that it expects to find in order, | ||
yielding an array of the results. | ||
- `Parsimmon.lazy(f)` accepts a function that returns a parser, which is evaluated the | ||
first time the parser is used. This is useful for referencing parsers that haven't yet | ||
been defined. | ||
- `Parsimmon.fail(message)` | ||
- `Parsimmon.letter` is equivalent to `Parsimmon.regex(/^[a-z]/i)` | ||
- `Parsimmon.letters` is equivalent to `Parsimmon.regex(/^[a-z]*/i)` | ||
- `Parsimmon.digit` is equivalent to `Parsimmon.regex(/^[0-9]/)` | ||
- `Parsimmon.digits` is equivalent to `Parsimmon.regex(/^[0-9]*/)` | ||
- `Parsimmon.whitespace` is equivalent to `Parsimmon.regex(/^\s+/)` | ||
- `Parsimmon.optWhitespace` is equivalent to `Parsimmon.regex(/^\s*/)` | ||
- `Parsimmon.letter` is equivalent to `Parsimmon.regex(/[a-z]/i)` | ||
- `Parsimmon.letters` is equivalent to `Parsimmon.regex(/[a-z]*/i)` | ||
- `Parsimmon.digit` is equivalent to `Parsimmon.regex(/[0-9]/)` | ||
- `Parsimmon.digits` is equivalent to `Parsimmon.regex(/[0-9]*/)` | ||
- `Parsimmon.whitespace` is equivalent to `Parsimmon.regex(/\s+/)` | ||
- `Parsimmon.optWhitespace` is equivalent to `Parsimmon.regex(/\s*/)` | ||
- `Parsimmon.any` consumes and yields the next character of the stream. | ||
@@ -105,0 +109,0 @@ - `Parsimmon.all` consumes and yields the entire remainder of the stream. |
@@ -86,9 +86,6 @@ var Parsimmon = {}; | ||
if (result.status) { | ||
var nextParser = (next instanceof Parser ? next : next(result.value)); | ||
return furthestBacktrackFor(nextParser._(stream, result.index), result); | ||
} | ||
else { | ||
return result; | ||
} | ||
if (!result.status) return result; | ||
var nextParser = (next instanceof Parser ? next : next(result.value)); | ||
return furthestBacktrackFor(nextParser._(stream, result.index), result); | ||
}); | ||
@@ -120,4 +117,3 @@ }; | ||
for (;;) { | ||
result = self._(stream, i); | ||
prevResult = furthestBacktrackFor(result, prevResult); | ||
result = furthestBacktrackFor(self._(stream, i), result); | ||
@@ -129,3 +125,3 @@ if (result.status) { | ||
else { | ||
return furthestBacktrackFor(makeSuccess(i, accum), prevResult); | ||
return furthestBacktrackFor(makeSuccess(i, accum), result); | ||
} | ||
@@ -199,6 +195,4 @@ } | ||
var self = this; | ||
return self.times(n).then(function(start) { | ||
return self.many().map(function(end) { | ||
return start.concat(end); | ||
}); | ||
return seq([this.times(n), this.many()]).map(function(results) { | ||
return results[0].concat(results[1]); | ||
}); | ||
@@ -208,18 +202,17 @@ }; | ||
_.map = function(fn) { | ||
return this.then(function(result) { return succeed(fn(result)); }); | ||
var self = this; | ||
return Parser(function(stream, i) { | ||
var result = self._(stream, i); | ||
if (!result.status) return result; | ||
return furthestBacktrackFor(makeSuccess(result.index, fn(result.value)), result); | ||
}); | ||
}; | ||
_.skip = function(two) { | ||
return this.then(function(result) { return two.result(result); }); | ||
_.skip = function(next) { | ||
return seq([this, next]).map(function(results) { return results[0]; }); | ||
}; | ||
// TODO: this would be better implemented with `seq` | ||
_.mark = function() { | ||
var self = this; | ||
return index.then(function(start) { | ||
return self.then(function(value) { | ||
return index.map(function(end) { | ||
return { start: start, value: value, end: end }; | ||
}); | ||
}); | ||
return seq([index, this, index]).map(function(results) { | ||
return { start: results[0], value: results[1], end: results[2] }; | ||
}); | ||
@@ -246,8 +239,6 @@ }; | ||
var regex = Parsimmon.regex = function(re) { | ||
if (re.source[0] !== '^') throw 'regex '+re+' must be anchored'; | ||
var anchored = RegExp('^(?:'+re.source+')', (''+re).slice((''+re).lastIndexOf('/')+1)); | ||
var expected = ''+re; | ||
return Parser(function(stream, i) { | ||
var match = re.exec(stream.slice(i)); | ||
var match = anchored.exec(stream.slice(i)); | ||
@@ -274,8 +265,8 @@ if (match) { | ||
var letter = Parsimmon.letter = regex(/^[a-z]/i); | ||
var letters = Parsimmon.letters = regex(/^[a-z]*/i); | ||
var digit = Parsimmon.digit = regex(/^[0-9]/); | ||
var digits = Parsimmon.digits = regex(/^[0-9]*/); | ||
var whitespace = Parsimmon.whitespace = regex(/^\s+/); | ||
var optWhitespace = Parsimmon.optWhitespace = regex(/^\s*/); | ||
var letter = Parsimmon.letter = regex(/[a-z]/i); | ||
var letters = Parsimmon.letters = regex(/[a-z]*/i); | ||
var digit = Parsimmon.digit = regex(/[0-9]/); | ||
var digits = Parsimmon.digits = regex(/[0-9]*/); | ||
var whitespace = Parsimmon.whitespace = regex(/\s+/); | ||
var optWhitespace = Parsimmon.optWhitespace = regex(/\s*/); | ||
@@ -298,2 +289,28 @@ var any = Parsimmon.any = Parser(function(stream, i) { | ||
var lazy = Parsimmon.lazy = function(f) { | ||
var parser = Parser(function(stream, i) { | ||
parser._ = f()._; | ||
return parser._(stream, i); | ||
}); | ||
return parser; | ||
}; | ||
// [Parser a] -> Parser [a] | ||
var seq = Parsimmon.seq = function(parsers) { | ||
return Parser(function(stream, i) { | ||
var result; | ||
var accum = new Array(parsers.length); | ||
for (var j = 0; j < parsers.length; j += 1) { | ||
result = furthestBacktrackFor(parsers[j]._(stream, i), result); | ||
if (!result.status) return result; | ||
accum[j] = result.value | ||
i = result.index; | ||
} | ||
return furthestBacktrackFor(makeSuccess(i, accum), result); | ||
}); | ||
} | ||
var index = Parsimmon.index = Parser(function(stream, i) { | ||
@@ -311,8 +328,5 @@ return makeSuccess(i, i); | ||
// TODO: this could be better implemented with `seq` | ||
_.ap = function(other) { | ||
return this.then(function(fn) { | ||
return other.then(function(val) { | ||
return fn(val); | ||
}); | ||
return seq([this, other]).map(function(results) { | ||
return results[0](results[1]); | ||
}); | ||
@@ -319,0 +333,0 @@ }; |
@@ -21,3 +21,3 @@ suite('parser', function() { | ||
test('Parsimmon.regex', function() { | ||
var parser = regex(/^[0-9]/); | ||
var parser = regex(/[0-9]/); | ||
@@ -27,4 +27,5 @@ assert.equal(parser.parse('1'), '1'); | ||
assert.throws(function() { parser.parse('x'); }, | ||
"Parse Error: expected /^[0-9]/ at character 0, got 'x'\n parsing: 'x'"); | ||
assert.throws(function() { regex(/./) }, 'must be anchored'); | ||
"Parse Error: expected /[0-9]/ at character 0, got 'x'\n parsing: 'x'"); | ||
assert.throws(function() { parser.parse('x0'); }, | ||
"Parse Error: expected /[0-9]/ at character 0, got 'x0'\n parsing: 'x0'"); | ||
}); | ||
@@ -31,0 +32,0 @@ |
974891
538
151