Socket
Socket
Sign inDemoInstall

parsimmon

Package Overview
Dependencies
Maintainers
1
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

parsimmon - npm Package Compare versions

Comparing version 0.3.2 to 0.4.0

61

build/parsimmon.browser.js

@@ -118,18 +118,22 @@ var Parsimmon = (function(undefined) {

function parseError(stream, result) {
var expected = result.expected;
var i = result.furthest;
function assertParser(p) {
if (!(p instanceof Parser)) throw new Error('not a parser: '+p);
}
var formatError = Parsimmon.formatError = function(stream, error) {
var expected = error.expected;
var i = error.index;
if (i === stream.length) {
var message = 'expected ' + expected + ', got the end of the string';
return 'expected ' + expected + ', got the end of the string';
}
else {
var prefix = (i > 0 ? "'..." : "'");
var suffix = (stream.length - i > 12 ? "...'" : "'");
var message = 'expected ' + expected + ' at character ' + i + ', got '
+ prefix + stream.slice(i, i+12) + suffix;
}
throw new Error('Parse Error: ' + message + "\n parsing: '" + stream + "'");
}
var prefix = (i > 0 ? "'..." : "'");
var suffix = (stream.length - i > 12 ? "...'" : "'");
return (
'expected ' + expected + ' at character ' + i + ', got ' +
prefix + stream.slice(i, i+12) + suffix
);
};
_.init = function(body) { this._ = body; };

@@ -140,3 +144,10 @@

return result.status ? result.value : parseError(stream, result);
return result.status ? {
status: true,
value: result.value
} : {
status: false,
index: result.furthest,
expected: result.expected
};
};

@@ -150,12 +161,8 @@

_.then = function(next) {
var self = this;
if (typeof next === 'function') {
throw new Error('chaining features of .then are no longer supported');
}
return Parser(function(stream, i) {
var result = self._(stream, i);
if (!result.status) return result;
var nextParser = (next instanceof Parser ? next : next(result.value));
return furthestBacktrackFor(nextParser._(stream, result.index), result);
});
assertParser(next);
return seq(this, next).map(function(results) { return results[1]; });
};

@@ -416,5 +423,13 @@

//- Monad
_.chain = _.then;
_.chain = function(f) {
var self = this;
return Parser(function(stream, i) {
var result = self._(stream, i);
if (!result.status) return result;
var nextParser = f(result.value);
return furthestBacktrackFor(nextParser._(stream, result.index), result);
});
};
});
return Parsimmon;
})()

@@ -1,1 +0,1 @@

var Parsimmon=function(t){var r=function(t,r,n){return function e(u,a){if(a===n){a=u;u=Object}function i(){var t=this instanceof i?this:new s;t.init.apply(t,arguments);return t}function s(){}i.Bare=s;var f=s[t]=u[t];var c=s[t]=i[t]=i.p=new s;var o;c.constructor=i;i.extend=function(t){return e(i,t)};return(i.open=function(t){if(typeof t==="function"){t=t.call(i,c,f,i,u)}if(typeof t==="object"){for(o in t){if(r.call(t,o)){c[o]=t[o]}}}if(!("init"in c))c.init=u;return i})(a)}}("prototype",{}.hasOwnProperty);var n={};n.Parser=r(function(t,r,e){"use strict";function u(t,r){return{status:true,index:t,value:r,furthest:-1,expected:""}}function a(t,r){return{status:false,index:-1,value:null,furthest:t,expected:r}}function i(t,r){if(!r)return t;if(t.furthest>=r.furthest)return t;return{status:t.status,index:t.index,value:t.value,furthest:r.furthest,expected:r.expected}}function s(t,r){var n=r.expected;var e=r.furthest;if(e===t.length){var u="expected "+n+", got the end of the string"}else{var a=e>0?"'...":"'";var i=t.length-e>12?"...'":"'";var u="expected "+n+" at character "+e+", got "+a+t.slice(e,e+12)+i}throw new Error("Parse Error: "+u+"\n parsing: '"+t+"'")}t.init=function(t){this._=t};t.parse=function(t){var r=this.skip(_)._(t,0);return r.status?r.value:s(t,r)};t.or=function(t){return z(this,t)};t.then=function(t){var r=this;return e(function(n,u){var a=r._(n,u);if(!a.status)return a;var s=t instanceof e?t:t(a.value);return i(s._(n,a.index),a)})};t.many=function(){var t=this;return e(function(r,n){var e=[];var a;var s;for(;;){a=i(t._(r,n),a);if(a.status){n=a.index;e.push(a.value)}else{return i(u(n,e),a)}}})};t.times=function(t,r){if(arguments.length<2)r=t;var n=this;return e(function(e,a){var s=[];var f=a;var c;var o;for(var v=0;v<t;v+=1){c=n._(e,a);o=i(c,o);if(c.status){a=c.index;s.push(c.value)}else{return o}}for(;v<r;v+=1){c=n._(e,a);o=i(c,o);if(c.status){a=c.index;s.push(c.value)}else{break}}return i(u(a,s),o)})};t.result=function(t){return this.then(o(t))};t.atMost=function(t){return this.times(0,t)};t.atLeast=function(t){var r=this;return k(this.times(t),this.many()).map(function(t){return t[0].concat(t[1])})};t.map=function(t){var r=this;return e(function(n,e){var a=r._(n,e);if(!a.status)return a;return i(u(a.index,t(a.value)),a)})};t.skip=function(t){return k(this,t).map(function(t){return t[0]})};t.mark=function(){return k(E,this,E).map(function(t){return{start:t[0],value:t[1],end:t[2]}})};var f=n.string=function(t){var r=t.length;var n="'"+t+"'";return e(function(e,i){var s=e.slice(i,i+r);if(s===t){return u(i+r,s)}else{return a(i,n)}})};var c=n.regex=function(t){var r=RegExp("^(?:"+t.source+")",(""+t).slice((""+t).lastIndexOf("/")+1));return e(function(n,e){var i=r.exec(n.slice(e));if(i){var s=i[0];return u(e+s.length,s)}else{return a(e,t)}})};var o=n.succeed=function(t){return e(function(r,n){return u(n,t)})};var v=n.fail=function(t){return e(function(r,n){return a(n,t)})};var l=n.letter=c(/[a-z]/i);var h=n.letters=c(/[a-z]*/i);var p=n.digit=c(/[0-9]/);var d=n.digits=c(/[0-9]*/);var g=n.whitespace=c(/\s+/);var x=n.optWhitespace=c(/\s*/);var m=n.any=e(function(t,r){if(r>=t.length)return a(r,"any character");return u(r+1,t.charAt(r))});var y=n.all=e(function(t,r){return u(t.length,t.slice(r))});var _=n.eof=e(function(t,r){if(r<t.length)return a(r,"EOF");return u(r,null)});var w=n.lazy=function(t){var r=e(function(n,e){r._=t()._;return r._(n,e)});return r};var k=n.seq=function(){var t=[].slice.call(arguments);var r=t.length;return e(function(n,e){var a;var s=new Array(r);for(var f=0;f<r;f+=1){a=i(t[f]._(n,e),a);if(!a.status)return a;s[f]=a.value;e=a.index}return i(u(e,s),a)})};var z=n.alt=function(){var t=[].slice.call(arguments);var r=t.length;if(r===0)return v("zero alternates");return e(function(r,n){var e;for(var u=0;u<t.length;u+=1){e=i(t[u]._(r,n),e);if(e.status)return e}return e})};var E=n.index=e(function(t,r){return u(r,r)});t.concat=t.or;t.empty=v("empty");t.of=e.of=n.of=o;t.ap=function(t){return k(this,t).map(function(t){return t[0](t[1])})};t.chain=t.then});return n}();
var Parsimmon=function(t){var r=function(t,r,n){return function e(u,a){if(a===n){a=u;u=Object}function i(){var t=this instanceof i?this:new f;t.init.apply(t,arguments);return t}function f(){}i.Bare=f;var s=f[t]=u[t];var o=f[t]=i[t]=i.p=new f;var c;o.constructor=i;i.extend=function(t){return e(i,t)};return(i.open=function(t){if(typeof t==="function"){t=t.call(i,o,s,i,u)}if(typeof t==="object"){for(c in t){if(r.call(t,c)){o[c]=t[c]}}}if(!("init"in o))o.init=u;return i})(a)}}("prototype",{}.hasOwnProperty);var n={};n.Parser=r(function(t,r,e){"use strict";function u(t,r){return{status:true,index:t,value:r,furthest:-1,expected:""}}function a(t,r){return{status:false,index:-1,value:null,furthest:t,expected:r}}function i(t,r){if(!r)return t;if(t.furthest>=r.furthest)return t;return{status:t.status,index:t.index,value:t.value,furthest:r.furthest,expected:r.expected}}function f(t){if(!(t instanceof e))throw new Error("not a parser: "+t)}var s=n.formatError=function(t,r){var n=r.expected;var e=r.index;if(e===t.length){return"expected "+n+", got the end of the string"}var u=e>0?"'...":"'";var a=t.length-e>12?"...'":"'";return"expected "+n+" at character "+e+", got "+u+t.slice(e,e+12)+a};t.init=function(t){this._=t};t.parse=function(t){var r=this.skip(w)._(t,0);return r.status?{status:true,value:r.value}:{status:false,index:r.furthest,expected:r.expected}};t.or=function(t){return z(this,t)};t.then=function(t){if(typeof t==="function"){throw new Error("chaining features of .then are no longer supported")}f(t);return k(this,t).map(function(t){return t[1]})};t.many=function(){var t=this;return e(function(r,n){var e=[];var a;var f;for(;;){a=i(t._(r,n),a);if(a.status){n=a.index;e.push(a.value)}else{return i(u(n,e),a)}}})};t.times=function(t,r){if(arguments.length<2)r=t;var n=this;return e(function(e,a){var f=[];var s=a;var o;var c;for(var v=0;v<t;v+=1){o=n._(e,a);c=i(o,c);if(o.status){a=o.index;f.push(o.value)}else{return c}}for(;v<r;v+=1){o=n._(e,a);c=i(o,c);if(o.status){a=o.index;f.push(o.value)}else{break}}return i(u(a,f),c)})};t.result=function(t){return this.then(v(t))};t.atMost=function(t){return this.times(0,t)};t.atLeast=function(t){var r=this;return k(this.times(t),this.many()).map(function(t){return t[0].concat(t[1])})};t.map=function(t){var r=this;return e(function(n,e){var a=r._(n,e);if(!a.status)return a;return i(u(a.index,t(a.value)),a)})};t.skip=function(t){return k(this,t).map(function(t){return t[0]})};t.mark=function(){return k(O,this,O).map(function(t){return{start:t[0],value:t[1],end:t[2]}})};var o=n.string=function(t){var r=t.length;var n="'"+t+"'";return e(function(e,i){var f=e.slice(i,i+r);if(f===t){return u(i+r,f)}else{return a(i,n)}})};var c=n.regex=function(t){var r=RegExp("^(?:"+t.source+")",(""+t).slice((""+t).lastIndexOf("/")+1));return e(function(n,e){var i=r.exec(n.slice(e));if(i){var f=i[0];return u(e+f.length,f)}else{return a(e,t)}})};var v=n.succeed=function(t){return e(function(r,n){return u(n,t)})};var l=n.fail=function(t){return e(function(r,n){return a(n,t)})};var h=n.letter=c(/[a-z]/i);var p=n.letters=c(/[a-z]*/i);var d=n.digit=c(/[0-9]/);var x=n.digits=c(/[0-9]*/);var g=n.whitespace=c(/\s+/);var m=n.optWhitespace=c(/\s*/);var y=n.any=e(function(t,r){if(r>=t.length)return a(r,"any character");return u(r+1,t.charAt(r))});var _=n.all=e(function(t,r){return u(t.length,t.slice(r))});var w=n.eof=e(function(t,r){if(r<t.length)return a(r,"EOF");return u(r,null)});var E=n.lazy=function(t){var r=e(function(n,e){r._=t()._;return r._(n,e)});return r};var k=n.seq=function(){var t=[].slice.call(arguments);var r=t.length;return e(function(n,e){var a;var f=new Array(r);for(var s=0;s<r;s+=1){a=i(t[s]._(n,e),a);if(!a.status)return a;f[s]=a.value;e=a.index}return i(u(e,f),a)})};var z=n.alt=function(){var t=[].slice.call(arguments);var r=t.length;if(r===0)return l("zero alternates");return e(function(r,n){var e;for(var u=0;u<t.length;u+=1){e=i(t[u]._(r,n),e);if(e.status)return e}return e})};var O=n.index=e(function(t,r){return u(r,r)});t.concat=t.or;t.empty=l("empty");t.of=e.of=n.of=v;t.ap=function(t){return k(this,t).map(function(t){return t[0](t[1])})};t.chain=function(t){var r=this;return e(function(n,e){var u=r._(n,e);if(!u.status)return u;var a=t(u.value);return i(a._(n,u.index),u)})}});return n}();

@@ -46,18 +46,22 @@ var P = require('pjs').P;

function parseError(stream, result) {
var expected = result.expected;
var i = result.furthest;
function assertParser(p) {
if (!(p instanceof Parser)) throw new Error('not a parser: '+p);
}
var formatError = Parsimmon.formatError = function(stream, error) {
var expected = error.expected;
var i = error.index;
if (i === stream.length) {
var message = 'expected ' + expected + ', got the end of the string';
return 'expected ' + expected + ', got the end of the string';
}
else {
var prefix = (i > 0 ? "'..." : "'");
var suffix = (stream.length - i > 12 ? "...'" : "'");
var message = 'expected ' + expected + ' at character ' + i + ', got '
+ prefix + stream.slice(i, i+12) + suffix;
}
throw new Error('Parse Error: ' + message + "\n parsing: '" + stream + "'");
}
var prefix = (i > 0 ? "'..." : "'");
var suffix = (stream.length - i > 12 ? "...'" : "'");
return (
'expected ' + expected + ' at character ' + i + ', got ' +
prefix + stream.slice(i, i+12) + suffix
);
};
_.init = function(body) { this._ = body; };

@@ -68,3 +72,10 @@

return result.status ? result.value : parseError(stream, result);
return result.status ? {
status: true,
value: result.value
} : {
status: false,
index: result.furthest,
expected: result.expected
};
};

@@ -78,12 +89,8 @@

_.then = function(next) {
var self = this;
if (typeof next === 'function') {
throw new Error('chaining features of .then are no longer supported');
}
return Parser(function(stream, i) {
var result = self._(stream, i);
if (!result.status) return result;
var nextParser = (next instanceof Parser ? next : next(result.value));
return furthestBacktrackFor(nextParser._(stream, result.index), result);
});
assertParser(next);
return seq(this, next).map(function(results) { return results[1]; });
};

@@ -344,4 +351,12 @@

//- Monad
_.chain = _.then;
_.chain = function(f) {
var self = this;
return Parser(function(stream, i) {
var result = self._(stream, i);
if (!result.status) return result;
var nextParser = f(result.value);
return furthestBacktrackFor(nextParser._(stream, result.index), result);
});
};
});
module.exports = Parsimmon;
{
"name": "parsimmon",
"version": "0.3.2",
"version": "0.4.0",
"description": "A monadic LL(infinity) parser combinator library",

@@ -5,0 +5,0 @@ "keywords": ["parsing", "parse", "parser combinators"],

@@ -17,16 +17,19 @@ [![Build Status](https://secure.travis-ci.org/jayferd/parsimmon.png)](http://travis-ci.org/jayferd/parsimmon)

var optWhitespace = Parsimmon.optWhitespace;
var lazy = Parsimmon.lazy;
var id = regex(/[a-z_]\w*/i);
var number = regex(/[0-9]+/).map(parseInt);
function lexeme(p) { return p.skip(optWhitespace); }
var atom = number.or(id);
var lparen = lexeme(string('('));
var rparen = lexeme(string(')'));
var form = string('(').skip(optWhitespace).then(function() {
return expr.many().skip(string(')'));
});
var expr = lazy(function() { return form.or(atom) });
var expr = form.or(atom).skip(optWhitespace);
var number = lexeme(regex(/[0-9]+/).map(parseInt));
var id = lexeme(regex(/[a-z_]\w*/i));
expr.parse('3') // => 3
expr.parse('(add (mul 10 (add 3 4)) (add 7 8))')
var atom = number.or(id);
var form = lparen.then(expr.many()).skip(rparen);
expr.parse('3').value // => 3
expr.parse('(add (mul 10 (add 3 4)) (add 7 8))').value
// => ['add', ['mul', 10, ['add', 3, 4]], ['add', 7, 8]]

@@ -39,5 +42,3 @@ ```

of text, and the promise of either an object yielded by that action on
success or a message in case of failure. Under the hood, this is
represented by a function that takes a stream and calls one of two
callbacks with an error or a result. For example, `string('foo')`
success or a message in case of failure. For example, `string('foo')`
yields the string `'foo'` if the beginning of the stream is `'foo'`,

@@ -47,41 +48,25 @@ and otherwise fails.

The combinator method `.map` is used to transform the yielded value.
For example, `string('foo').map(function(x) { return x + 'bar'; })`
will yield `'foobar'` if the stream starts with `'foo'`. The parser
`digits.map(function(x) { return parseInt(x) * 2; })` will yield
the number 24 when it encounters the string '12'. The method
`.result` can be used to set a constant result.
For example,
The two core ways to combine parsers are `.then` and `.or`. The
method `.then` provides a way to decide how to continue the parse
based on the result of a previous parser. For a kind of contrived
example,
``` js
var sentence = regex(/[\w\s]+/).then(function(contents) {
var ending;
string('foo').map(function(x) { return x + 'bar'; })
```
if (contents.indexOf('bang') >= 0) {
ending = '!';
}
else {
ending = '.'
}
will yield `'foobar'` if the stream starts with `'foo'`. The parser
return string(ending).result(contents + ending);
});
sentence.parse('quick brown dogs and things.') // => 'quick brown dogs and things.'
sentence.parse('shebang.') // parse error: expected '!'
sentence.parse('shebang!') // => 'shebang!'
``` js
digits.map(function(x) { return parseInt(x) * 2; })
```
For the monad-loving crowd, `.then` is the `bind` operation on
the parser monad (much like Parsec). For others, this is very
similar to the Promises/A spec, implemented by jQuery's deferred
objects.
will yield the number 24 when it encounters the string '12'. The method
`.result` can be used to set a constant result.
The method `.or` allows a parser to continue by trying another parser
if it fails. So `string('a').or(string('b'))` will yield an `'a'` if
the stream starts with an `'a'`, and a `'b'` if the stream starts with
a `'b'`, and fail otherwise.
Calling `.parse(str)` on a parser parses the string, and returns an
object with a `status` flag, indicating whether the parse succeeded.
If it succeeded, the `value` attribute will contain the yielded value.
Otherwise, the `index` and `expected` attributes will contain the
index of the parse error, and a message indicating what was expected.
The error object can be passed along with the original source to
`Parsimmon.formatError(source, error)` to obtain a human-readable
error string.

@@ -99,5 +84,7 @@ ## Full API

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.alt(p1, p2, ... pn)` accepts a variable number of parsers,
and yields the value of the first one that succeeds, backtracking in between.
- `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)`

@@ -118,6 +105,8 @@ - `Parsimmon.letter` is equivalent to `Parsimmon.regex(/[a-z]/i)`

returns a new parser which tries `parser`, and if it fails uses `otherParser`.
- `parser.then(function(result) { return anotherParser; })`:
- `parser.chain(function(result) { return anotherParser; })`:
returns a new parser which tries `parser`, and on success calls the
given function with the result of the parse, which is expected to
return another parser.
return another parser, which will be tried next. This allows you
to dynamically decide how to continue the parse, which is impossible
with the other combinators.
- `parser.then(anotherParser)`:

@@ -148,2 +137,49 @@ expects `anotherParser` to follow `parser`, and yields the result

## Tips and patterns
These apply to most parsers for traditional langauges - it's possible
you may need to do something different for yours!
For most parsers, the following format is helpful:
1. define a `lexeme` function to skip all the stuff you don't care
about (whitespace, comments, etc). You may need multiple types of lexemes.
For example,
``` js
var ignore = whitespace.or(comment.many());
function lexeme(p) { return p.skip(ignore); }
```
1. Define all your lexemes first. These should yield native javascript values.
``` js
var lparen = lexeme(string('('));
var rparen = lexeme(string(')'));
var number = lexeme(regex(/[0-9]+/)).map(parseInt);
```
1. Forward-declare one or more top-level expressions with `lazy`,
referring to parsers that have not yet been defined. Generally, this
takes the form of a large `.alt()` call
``` js
var expr = lazy(function() { return Parsimmon.alt(p1, p2, ...); });
```
1. Then build your parsers from the inside out - these should return
AST nodes or other objects specific to your domain.
``` js
var p1 = ...
var p2 = ...
```
1. Finally, export your top-level parser. Remember to skip ignored
stuff at the beginning.
``` js
return ignore.then(expr.many());
```
### Fantasyland

@@ -150,0 +186,0 @@

@@ -45,18 +45,22 @@ var Parsimmon = {};

function parseError(stream, result) {
var expected = result.expected;
var i = result.furthest;
function assertParser(p) {
if (!(p instanceof Parser)) throw new Error('not a parser: '+p);
}
var formatError = Parsimmon.formatError = function(stream, error) {
var expected = error.expected;
var i = error.index;
if (i === stream.length) {
var message = 'expected ' + expected + ', got the end of the string';
return 'expected ' + expected + ', got the end of the string';
}
else {
var prefix = (i > 0 ? "'..." : "'");
var suffix = (stream.length - i > 12 ? "...'" : "'");
var message = 'expected ' + expected + ' at character ' + i + ', got '
+ prefix + stream.slice(i, i+12) + suffix;
}
throw new Error('Parse Error: ' + message + "\n parsing: '" + stream + "'");
}
var prefix = (i > 0 ? "'..." : "'");
var suffix = (stream.length - i > 12 ? "...'" : "'");
return (
'expected ' + expected + ' at character ' + i + ', got ' +
prefix + stream.slice(i, i+12) + suffix
);
};
_.init = function(body) { this._ = body; };

@@ -67,3 +71,10 @@

return result.status ? result.value : parseError(stream, result);
return result.status ? {
status: true,
value: result.value
} : {
status: false,
index: result.furthest,
expected: result.expected
};
};

@@ -77,12 +88,8 @@

_.then = function(next) {
var self = this;
if (typeof next === 'function') {
throw new Error('chaining features of .then are no longer supported');
}
return Parser(function(stream, i) {
var result = self._(stream, i);
if (!result.status) return result;
var nextParser = (next instanceof Parser ? next : next(result.value));
return furthestBacktrackFor(nextParser._(stream, result.index), result);
});
assertParser(next);
return seq(this, next).map(function(results) { return results[1]; });
};

@@ -343,3 +350,11 @@

//- Monad
_.chain = _.then;
_.chain = function(f) {
var self = this;
return Parser(function(stream, i) {
var result = self._(stream, i);
if (!result.status) return result;
var nextParser = f(result.value);
return furthestBacktrackFor(nextParser._(stream, result.index), result);
});
};
});

@@ -12,8 +12,19 @@ suite('parser', function() {

var index = Parsimmon.index;
var lazy = Parsimmon.lazy;
test('Parsimmon.string', function() {
var parser = string('x');
assert.equal(parser.parse('x'), 'x');
assert.throws(function() { parser.parse('y') },
"Parse Error: expected 'x' at character 0, got 'y'\n parsing: 'y'");
var res = parser.parse('x');
assert.ok(res.status);
assert.equal(res.value, 'x');
res = parser.parse('y')
assert.ok(!res.status)
assert.equal("'x'", res.expected);
assert.equal(0, res.index);
assert.equal(
"expected 'x' at character 0, got 'y'",
Parsimmon.formatError('y', res)
);
});

@@ -24,8 +35,14 @@

assert.equal(parser.parse('1'), '1');
assert.equal(parser.parse('4'), '4');
assert.throws(function() { parser.parse('x'); },
"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'");
assert.equal(parser.parse('1').value, '1');
assert.equal(parser.parse('4').value, '4');
assert.deepEqual(parser.parse('x0'), {
status: false,
index: 0,
expected: /[0-9]/
});
assert.deepEqual(parser.parse('0x'), {
status: false,
index: 1,
expected: 'EOF'
});
});

@@ -36,15 +53,22 @@

var parser = string('x').then(string('y'));
assert.equal(parser.parse('xy'), 'y');
assert.throws(function() { parser.parse('y'); },
"Parse Error: expected 'x' at character 0, got 'y'\n parsing: 'y'");
assert.throws(function() { parser.parse('xz'); },
"Parse Error: expected 'y' at character 1, got '...z'\n parsing: 'xz'");
assert.deepEqual(parser.parse('xy'), { status: true, value: 'y' });
assert.deepEqual(parser.parse('y'), {
status: false,
expected: "'x'",
index: 0
})
assert.deepEqual(parser.parse('xz'), {
status: false,
expected: "'y'",
index: 1
});
});
});
suite('chain', function() {
test('asserts that a parser is returned', function() {
var parser1 = letter.then(function() { return 'not a parser' });
var parser1 = letter.chain(function() { return 'not a parser' });
assert.throws(function() { parser1.parse('x'); });
var parser2 = letter.then('x');
assert.throws(function() { letter.parse('xx'); });
assert.throws(function() { letter.then('x'); });
});

@@ -54,3 +78,3 @@

var piped;
var parser = string('x').then(function(x) {
var parser = string('x').chain(function(x) {
piped = x;

@@ -60,5 +84,5 @@ return string('y');

assert.equal(parser.parse('xy'), 'y');
assert.deepEqual(parser.parse('xy'), { status: true, value: 'y'});
assert.equal(piped, 'x');
assert.throws(function() { parser.parse('x'); });
assert.ok(!parser.parse('x').status);
});

@@ -76,3 +100,3 @@ });

assert.equal(parser.parse('x'), 'y')
assert.deepEqual(parser.parse('x'), { status: true, value: 'y' });
assert.equal(piped, 'x');

@@ -84,11 +108,4 @@ });

test('returns a constant result', function() {
var myResult = 1;
var oneParser = string('x').result(1);
assert.equal(oneParser.parse('x'), 1);
var myFn = function() {};
var fnParser = string('x').result(myFn);
assert.equal(fnParser.parse('x'), myFn);
assert.deepEqual(oneParser.parse('x'), { status: true, value: 1 });
});

@@ -101,4 +118,4 @@ });

assert.equal(parser.parse('xy'), 'x');
assert.throws(function() { parser.parse('x'); });
assert.deepEqual(parser.parse('xy'), { status: true, value: 'x' });
assert.ok(!parser.parse('x').status);
});

@@ -111,23 +128,19 @@ });

assert.equal(parser.parse('x'), 'x');
assert.equal(parser.parse('y'), 'y');
assert.throws(function() { parser.parse('z') });
assert.equal(parser.parse('x').value, 'x');
assert.equal(parser.parse('y').value, 'y');
assert.ok(!parser.parse('z').status);
});
test('with then', function() {
test('with chain', function() {
var parser = string('\\')
.then(function() {
return string('y')
.chain(function(x) {
return string('y');
}).or(string('z'));
assert.equal(parser.parse('\\y'), 'y');
assert.equal(parser.parse('z'), 'z');
assert.throws(function() { parser.parse('\\z') });
assert.equal(parser.parse('\\y').value, 'y');
assert.equal(parser.parse('z').value, 'z');
assert.ok(!parser.parse('\\z').status);
});
});
function assertEqualArray(arr1, arr2) {
assert.equal(arr1.join(), arr2.join());
}
suite('many', function() {

@@ -137,7 +150,7 @@ test('simple case', function() {

assertEqualArray(letters.parse('x'), ['x']);
assertEqualArray(letters.parse('xyz'), ['x','y','z']);
assertEqualArray(letters.parse(''), []);
assert.throws(function() { letters.parse('1'); });
assert.throws(function() { letters.parse('xyz1'); });
assert.deepEqual(letters.parse('x').value, ['x']);
assert.deepEqual(letters.parse('xyz').value, ['x','y','z']);
assert.deepEqual(letters.parse('').value, []);
assert.ok(!letters.parse('1').status);
assert.ok(!letters.parse('xyz1').status);
});

@@ -148,5 +161,5 @@

assert.equal(parser.parse('y'), 'y');
assert.equal(parser.parse('xy'), 'y');
assert.equal(parser.parse('xxxxxy'), 'y');
assert.equal(parser.parse('y').value, 'y');
assert.equal(parser.parse('xy').value, 'y');
assert.equal(parser.parse('xxxxxy').value, 'y');
});

@@ -159,4 +172,4 @@ });

assertEqualArray(zeroLetters.parse(''), []);
assert.throws(function() { zeroLetters.parse('x'); });
assert.deepEqual(zeroLetters.parse('').value, []);
assert.ok(!zeroLetters.parse('x').status);
});

@@ -167,11 +180,11 @@

assertEqualArray(threeLetters.parse('xyz'), ['x', 'y', 'z']);
assert.throws(function() { threeLetters.parse('xy'); });
assert.throws(function() { threeLetters.parse('xyzw'); });
assert.deepEqual(threeLetters.parse('xyz').value, ['x', 'y', 'z']);
assert.ok(!threeLetters.parse('xy').status);
assert.ok(!threeLetters.parse('xyzw').status);
var thenDigit = threeLetters.then(digit);
assert.equal(thenDigit.parse('xyz1'), '1');
assert.throws(function() { thenDigit.parse('xy1'); });
assert.throws(function() { thenDigit.parse('xyz'); });
assert.throws(function() { thenDigit.parse('xyzw'); });
assert.equal(thenDigit.parse('xyz1').value, '1');
assert.ok(!thenDigit.parse('xy1').status);
assert.ok(!thenDigit.parse('xyz').status);
assert.ok(!thenDigit.parse('xyzw').status);
});

@@ -182,16 +195,16 @@

assertEqualArray(someLetters.parse('xy'), ['x', 'y']);
assertEqualArray(someLetters.parse('xyz'), ['x', 'y', 'z']);
assertEqualArray(someLetters.parse('xyzw'), ['x', 'y', 'z', 'w']);
assert.throws(function() { someLetters.parse('xyzwv'); });
assert.throws(function() { someLetters.parse('x'); });
assert.deepEqual(someLetters.parse('xy').value, ['x', 'y']);
assert.deepEqual(someLetters.parse('xyz').value, ['x', 'y', 'z']);
assert.deepEqual(someLetters.parse('xyzw').value, ['x', 'y', 'z', 'w']);
assert.ok(!someLetters.parse('xyzwv').status);
assert.ok(!someLetters.parse('x').status);
var thenDigit = someLetters.then(digit);
assert.equal(thenDigit.parse('xy1'), '1');
assert.equal(thenDigit.parse('xyz1'), '1');
assert.equal(thenDigit.parse('xyzw1'), '1');
assert.throws(function() { thenDigit.parse('xy'); });
assert.throws(function() { thenDigit.parse('xyzw'); });
assert.throws(function() { thenDigit.parse('xyzwv1'); });
assert.throws(function() { thenDigit.parse('x1'); });
assert.equal(thenDigit.parse('xy1').value, '1');
assert.equal(thenDigit.parse('xyz1').value, '1');
assert.equal(thenDigit.parse('xyzw1').value, '1');
assert.ok(!thenDigit.parse('xy').status);
assert.ok(!thenDigit.parse('xyzw').status);
assert.ok(!thenDigit.parse('xyzwv1').status);
assert.ok(!thenDigit.parse('x1').status);
});

@@ -201,7 +214,6 @@

var atMostTwo = letter.atMost(2);
debugger
assertEqualArray(atMostTwo.parse(''), []);
assertEqualArray(atMostTwo.parse('a'), ['a']);
assertEqualArray(atMostTwo.parse('ab'), ['a', 'b']);
assert.throws(function() { atMostTwo.parse('abc'); });
assert.deepEqual(atMostTwo.parse('').value, []);
assert.deepEqual(atMostTwo.parse('a').value, ['a']);
assert.deepEqual(atMostTwo.parse('ab').value, ['a', 'b']);
assert.ok(!atMostTwo.parse('abc').status);
});

@@ -212,5 +224,5 @@

assertEqualArray(atLeastTwo.parse('xy'), ['x', 'y']);
assertEqualArray(atLeastTwo.parse('xyzw'), ['x', 'y', 'z', 'w']);
assert.throws(function() { atLeastTwo.parse('x'); });
assert.deepEqual(atLeastTwo.parse('xy').value, ['x', 'y']);
assert.deepEqual(atLeastTwo.parse('xyzw').value, ['x', 'y', 'z', 'w']);
assert.ok(!atLeastTwo.parse('x').status);
});

@@ -224,9 +236,12 @@ });

test('use Parsimmon.fail to fail dynamically', function() {
var parser = any.then(function(ch) {
var parser = any.chain(function(ch) {
return fail('a character besides ' + ch);
}).or(string('x'));
assert.throws(function() { parser.parse('y'); },
"Parse Error: expected a character besides y, got the end of the string\n parsing: 'y'");
assert.equal(parser.parse('x'), 'x');
assert.deepEqual(parser.parse('y'), {
status: false,
index: 1,
expected: 'a character besides y'
});
assert.equal(parser.parse('x').value, 'x');
});

@@ -240,3 +255,3 @@

.then(string('+').or(string('*')))
.then(function(operator) {
.chain(function(operator) {
if (operator === allowedOperator) return succeed(operator);

@@ -249,10 +264,16 @@ else return fail(allowedOperator);

allowedOperator = '+';
assert.equal(parser.parse('x+y'), '+');
assert.throws(function() { parser.parse('x*y'); },
"Parse Error: expected + at character 2, got '...y'\n parsing: 'x*y'");
assert.equal(parser.parse('x+y').value, '+');
assert.deepEqual(parser.parse('x*y'), {
status: false,
index: 2,
expected: '+'
});
allowedOperator = '*';
assert.equal(parser.parse('x*y'), '*');
assert.throws(function() { parser.parse('x+y'); },
"Parse Error: expected * at character 2, got '...y'\n parsing: 'x+y'");
assert.equal(parser.parse('x*y').value, '*');
assert.deepEqual(parser.parse('x+y'), {
status: false,
index: 2,
expected: '*'
});
});

@@ -264,4 +285,4 @@ });

assert.equal(parser.parse(' '), ' ')
assert.equal(parser.parse('x'), 'default');
assert.equal(parser.parse(' ').value, ' ')
assert.equal(parser.parse('x').value, 'default');
});

@@ -271,5 +292,5 @@

var parser = regex(/^x*/).then(index);
assert.equal(parser.parse(''), 0);
assert.equal(parser.parse('xx'), 2);
assert.equal(parser.parse('xxxx'), 4);
assert.equal(parser.parse('').value, 0);
assert.equal(parser.parse('xx').value, 2);
assert.equal(parser.parse('xxxx').value, 4);
});

@@ -280,4 +301,4 @@

var parser = optWhitespace.then(ys).skip(optWhitespace);
assert.deepEqual(parser.parse(''), { start: 0, value: '', end: 0 });
assert.deepEqual(parser.parse(' yy '), { start: 1, value: 'yy', end: 3 });
assert.deepEqual(parser.parse('').value, { start: 0, value: '', end: 0 });
assert.deepEqual(parser.parse(' yy ').value, { start: 1, value: 'yy', end: 3 });
});

@@ -293,4 +314,7 @@

assert.throws(function() { parser.parse('abc'); },
"Parse Error: expected 'def', got the end of the string\n parsing: 'abc'");
assert.deepEqual(parser.parse('abc'), {
status: false,
index: 3,
expected: "'def'"
});
});

@@ -301,4 +325,7 @@

assert.throws(function() { parser.parse('abc'); },
"Parse Error: expected 'd', got the end of the string\n parsing: 'abc'");
assert.deepEqual(parser.parse('abc'), {
status: false,
index: 3,
expected: "'d'"
});
});

@@ -310,4 +337,7 @@

assert.throws(function() { parser.parse('abcdef'); },
"Parse Error: expected 'g', got the end of the string\n parsing: 'abcdef'");
assert.deepEqual(parser.parse('abcdef'), {
status: false,
index: 6,
expected: "'g'"
});
});

@@ -318,13 +348,22 @@ });

test('prefer longest branch even in a .many()', function() {
var list = lazy(function() {
return optWhitespace.then(atom.or(sexpr)).skip(optWhitespace).many();
});
var atom = regex(/^[^()\s]+/);
var sexpr = string('(').then(function() { return list; }).skip(string(')'));
var list = optWhitespace.then(atom.or(sexpr)).skip(optWhitespace).many();
var sexpr = string('(').then(list).skip(string(')'));
// assert.deepEqual(list.parse('(a b) (c ((() d)))'), [['a', 'b'], ['c', [[[], 'd']]]]);
assert.deepEqual(list.parse('(a b) (c ((() d)))').value,
[['a', 'b'], ['c', [[[], 'd']]]]);
assert.throws(function() { list.parse('(a b ()) c)'); },
"Parse Error: expected EOF at character 10, got '...)'\n parsing: '(a b ()) c)'");
assert.deepEqual(list.parse('(a b ()) c)'), {
status: false,
index: 10,
expected: 'EOF'
});
assert.throws(function() { list.parse('(a (b)) (() c'); },
"Parse Error: expected ')', got the end of the string\n parsing: '(a (b)) (() c'");
assert.deepEqual(list.parse('(a (b)) (() c'), {
status: false,
index: 13,
expected: "')'"
});
});

@@ -335,6 +374,10 @@

assert.deepEqual(parser.parse('aaabcdefaa'), ['a', 'a', 'def', 'a', 'a']);
assert.deepEqual(parser.parse('aaabcdefaa').value,
['a', 'a', 'def', 'a', 'a']);
assert.throws(function() { parser.parse('aaabcde'); },
"Parse Error: expected 'def' at character 5, got '...de'\n parsing: 'aaabcde'");
assert.deepEqual(parser.parse('aaabcde'), {
status: false,
index: 5,
expected: "'def'"
});
});

@@ -347,7 +390,13 @@ });

assert.throws(function() { parser.parse('aabcde'); },
"Parse Error: expected 'def' at character 4, got '...de'\n parsing: 'aabcde'");
assert.deepEqual(parser.parse('aabcde'), {
status: false,
index: 4,
expected: "'def'"
});
assert.throws(function() { parser.parse('aaaaabcde'); },
"Parse Error: expected 'def' at character 7, got '...de'\n parsing: 'aaaaabcde'");
assert.deepEqual(parser.parse('aaaaabcde'), {
status: false,
index: 7,
expected: "'def'"
});
});

@@ -354,0 +403,0 @@ });

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc