Comparing version 0.7.2 to 0.8.0
@@ -62,3 +62,3 @@ // This unsightly UMD-module header is here to make this code work without | ||
var expected = (result.furthest === last.furthest) | ||
? result.expected.concat(last.expected) | ||
? union(result.expected, last.expected) | ||
: last.expected; | ||
@@ -75,2 +75,32 @@ | ||
// Returns the sorted set union of two arrays of strings | ||
function union(xs, ys) { | ||
// Exit early if either array is empty (common case) | ||
var xn = xs.length; | ||
var yn = ys.length; | ||
if (xn === 0 && yn === 0) { | ||
return []; | ||
} else if (xn === 0) { | ||
return ys.slice().sort(); | ||
} else if (yn === 0) { | ||
return xs.slice().sort(); | ||
} | ||
// Two non-empty arrays: do the full algorithm | ||
var obj = {}; | ||
for (var i = 0; i < xn; i++) { | ||
obj[xs[i]] = true; | ||
} | ||
for (var i = 0; i < yn; i++) { | ||
obj[ys[i]] = true; | ||
} | ||
var keys = []; | ||
for (var k in obj) { | ||
if (obj.hasOwnProperty(k)) { | ||
keys.push(k); | ||
} | ||
} | ||
keys.sort(); | ||
return keys; | ||
} | ||
// For ensuring we have the right argument types | ||
@@ -77,0 +107,0 @@ function assertParser(p) { |
@@ -1,1 +0,1 @@ | ||
(function(t,n){if(typeof define==="function"&&define.amd){define([],n)}else if(typeof module==="object"&&module.exports){module.exports=n()}else{t.Parsimmon=n()}})(this,function(){"use strict";var t={};function n(t){if(!(this instanceof n))return new n(t);this._=t}t.Parser=n;var r=n.prototype;function e(t,n){return{status:true,index:t,value:n,furthest:-1,expected:[]}}function u(t,n){return{status:false,index:-1,value:null,furthest:t,expected:[n]}}function i(t,n){if(!n)return t;if(t.furthest>n.furthest)return t;var r=t.furthest===n.furthest?t.expected.concat(n.expected):n.expected;return{status:t.status,index:t.index,value:t.value,furthest:n.furthest,expected:r}}function a(t){if(!(t instanceof n))throw new Error("not a parser: "+t)}function f(t){if(typeof t!=="number")throw new Error("not a number: "+t)}function o(t){if(!(t instanceof RegExp))throw new Error("not a regex: "+t)}function c(t){if(typeof t!=="function")throw new Error("not a function: "+t)}function s(t){if(typeof t!=="string")throw new Error("not a string: "+t)}function l(t){if(t.length===1)return t[0];return"one of "+t.join(", ")}function v(t,n){var r=n.index;var e=r.offset;if(e===t.length)return", got the end of the stream";var u=e>0?"'...":"'";var i=t.length-e>12?"...'":"'";return" at line "+r.line+" column "+r.column+", got "+u+t.slice(e,e+12)+i}var h=t.formatError=function(t,n){return"expected "+l(n.expected)+v(t,n)};r.parse=function(t){if(typeof t!=="string"){throw new Error(".parse must be called with a string as its argument")}var n=this.skip(P)._(t,0);return n.status?{status:true,value:n.value}:{status:false,index:C(t,n.furthest),expected:n.expected}};var p=t.seq=function(){var t=[].slice.call(arguments);var r=t.length;for(var u=0;u<r;u+=1){a(t[u])}return n(function(n,u){var a;var f=new Array(r);for(var o=0;o<r;o+=1){a=i(t[o]._(n,u),a);if(!a.status)return a;f[o]=a.value;u=a.index}return i(e(u,f),a)})};var d=t.seqMap=function(){var t=[].slice.call(arguments);var n=t.pop();return p.apply(null,t).map(function(t){return n.apply(null,t)})};var g=t.custom=function(t){return n(t(e,u))};var x=t.alt=function(){var t=[].slice.call(arguments);var r=t.length;if(r===0)return O("zero alternates");for(var e=0;e<r;e+=1){a(t[e])}return n(function(n,r){var e;for(var u=0;u<t.length;u+=1){e=i(t[u]._(n,r),e);if(e.status)return e}return e})};var m=t.sepBy=function(n,r){return y(n,r).or(t.of([]))};var y=t.sepBy1=function(t,n){a(t);a(n);var r=n.then(t).many();return t.chain(function(t){return r.map(function(n){return[t].concat(n)})})};r.or=function(t){return x(this,t)};r.then=function(t){if(typeof t==="function"){throw new Error("chaining features of .then are no longer supported, use .chain instead")}a(t);return p(this,t).map(function(t){return t[1]})};r.many=function(){var t=this;return n(function(n,r){var u=[];var a;var f;for(;;){a=i(t._(n,r),a);if(a.status){r=a.index;u.push(a.value)}else{return i(e(r,u),a)}}})};r.times=function(t,r){if(arguments.length<2)r=t;var u=this;f(t);f(r);return n(function(n,a){var f=[];var o=a;var c;var s;for(var l=0;l<t;l+=1){c=u._(n,a);s=i(c,s);if(c.status){a=c.index;f.push(c.value)}else return s}for(;l<r;l+=1){c=u._(n,a);s=i(c,s);if(c.status){a=c.index;f.push(c.value)}else break}return i(e(a,f),s)})};r.result=function(t){return this.map(function(n){return t})};r.atMost=function(t){return this.times(0,t)};r.atLeast=function(t){var n=this;return d(this.times(t),this.many(),function(t,n){return t.concat(n)})};r.map=function(t){c(t);var r=this;return n(function(n,u){var a=r._(n,u);if(!a.status)return a;return i(e(a.index,t(a.value)),a)})};r.skip=function(t){return p(this,t).map(function(t){return t[0]})};r.mark=function(){return d(D,this,D,function(t,n,r){return{start:t,value:n,end:r}})};r.desc=function(t){var r=this;return n(function(n,e){var u=r._(n,e);if(!u.status)u.expected=[t];return u})};var w=t.string=function(t){var r=t.length;var i="'"+t+"'";s(t);return n(function(n,a){var f=n.slice(a,a+r);if(f===t){return e(a+r,f)}else{return u(a,i)}})};var _=t.regex=function(t,r){o(t);if(r)f(r);var i=RegExp("^(?:"+t.source+")",(""+t).slice((""+t).lastIndexOf("/")+1));var a=""+t;if(r==null)r=0;return n(function(t,n){var f=i.exec(t.slice(n));if(f){var o=f[0];var c=f[r];if(c!=null)return e(n+o.length,c)}return u(n,a)})};var E=t.succeed=function(t){return n(function(n,r){return e(r,t)})};var O=t.fail=function(t){return n(function(n,r){return u(r,t)})};var b=t.letter=_(/[a-z]/i).desc("a letter");var k=t.letters=_(/[a-z]*/i);var z=t.digit=_(/[0-9]/).desc("a digit");var A=t.digits=_(/[0-9]*/);var j=t.whitespace=_(/\s+/).desc("whitespace");var q=t.optWhitespace=_(/\s*/);var B=t.any=n(function(t,n){if(n>=t.length)return u(n,"any character");return e(n+1,t.charAt(n))});var M=t.all=n(function(t,n){return e(t.length,t.slice(n))});var P=t.eof=n(function(t,n){if(n<t.length)return u(n,"EOF");return e(n,null)});var R=t.test=function(t){c(t);return n(function(n,r){var i=n.charAt(r);if(r<n.length&&t(i)){return e(r+1,i)}else{return u(r,"a character matching "+t)}})};var W=t.oneOf=function(t){return R(function(n){return t.indexOf(n)>=0})};var F=t.noneOf=function(t){return R(function(n){return t.indexOf(n)<0})};var I=t.takeWhile=function(t){c(t);return n(function(n,r){var u=r;while(u<n.length&&t(n.charAt(u)))u+=1;return e(u,n.slice(r,u))})};var L=t.lazy=function(t,r){if(arguments.length<2){r=t;t=undefined}var e=n(function(t,n){e._=r()._;return e._(t,n)});if(t)e=e.desc(t);return e};var C=function(t,n){var r=t.slice(0,n).split("\n");var e=r.length;var u=r[r.length-1].length+1;return{offset:n,line:e,column:u}};var D=t.index=n(function(t,n){return e(n,C(t,n))});r.concat=r.or;r.empty=O("empty");r.of=n.of=t.of=E;r.ap=function(t){return d(this,t,function(t,n){return t(n)})};r.chain=function(t){var r=this;return n(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 t}); | ||
(function(r,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{r.Parsimmon=t()}})(this,function(){"use strict";var r={};function t(r){if(!(this instanceof t))return new t(r);this._=r}r.Parser=t;var n=t.prototype;function e(r,t){return{status:true,index:r,value:t,furthest:-1,expected:[]}}function u(r,t){return{status:false,index:-1,value:null,furthest:r,expected:[t]}}function i(r,t){if(!t)return r;if(r.furthest>t.furthest)return r;var n=r.furthest===t.furthest?a(r.expected,t.expected):t.expected;return{status:r.status,index:r.index,value:r.value,furthest:t.furthest,expected:n}}function a(r,t){var n=r.length;var e=t.length;if(n===0&&e===0){return[]}else if(n===0){return t.slice().sort()}else if(e===0){return r.slice().sort()}var u={};for(var i=0;i<n;i++){u[r[i]]=true}for(var i=0;i<e;i++){u[t[i]]=true}var a=[];for(var f in u){if(u.hasOwnProperty(f)){a.push(f)}}a.sort();return a}function f(r){if(!(r instanceof t))throw new Error("not a parser: "+r)}function o(r){if(typeof r!=="number")throw new Error("not a number: "+r)}function s(r){if(!(r instanceof RegExp))throw new Error("not a regex: "+r)}function c(r){if(typeof r!=="function")throw new Error("not a function: "+r)}function l(r){if(typeof r!=="string")throw new Error("not a string: "+r)}function v(r){if(r.length===1)return r[0];return"one of "+r.join(", ")}function h(r,t){var n=t.index;var e=n.offset;if(e===r.length)return", got the end of the stream";var u=e>0?"'...":"'";var i=r.length-e>12?"...'":"'";return" at line "+n.line+" column "+n.column+", got "+u+r.slice(e,e+12)+i}var p=r.formatError=function(r,t){return"expected "+v(t.expected)+h(r,t)};n.parse=function(r){if(typeof r!=="string"){throw new Error(".parse must be called with a string as its argument")}var t=this.skip(R)._(r,0);return t.status?{status:true,value:t.value}:{status:false,index:D(r,t.furthest),expected:t.expected}};var d=r.seq=function(){var r=[].slice.call(arguments);var n=r.length;for(var u=0;u<n;u+=1){f(r[u])}return t(function(t,u){var a;var f=new Array(n);for(var o=0;o<n;o+=1){a=i(r[o]._(t,u),a);if(!a.status)return a;f[o]=a.value;u=a.index}return i(e(u,f),a)})};var g=r.seqMap=function(){var r=[].slice.call(arguments);var t=r.pop();return d.apply(null,r).map(function(r){return t.apply(null,r)})};var x=r.custom=function(r){return t(r(e,u))};var m=r.alt=function(){var r=[].slice.call(arguments);var n=r.length;if(n===0)return b("zero alternates");for(var e=0;e<n;e+=1){f(r[e])}return t(function(t,n){var e;for(var u=0;u<r.length;u+=1){e=i(r[u]._(t,n),e);if(e.status)return e}return e})};var y=r.sepBy=function(t,n){return w(t,n).or(r.of([]))};var w=r.sepBy1=function(r,t){f(r);f(t);var n=t.then(r).many();return r.chain(function(r){return n.map(function(t){return[r].concat(t)})})};n.or=function(r){return m(this,r)};n.then=function(r){if(typeof r==="function"){throw new Error("chaining features of .then are no longer supported, use .chain instead")}f(r);return d(this,r).map(function(r){return r[1]})};n.many=function(){var r=this;return t(function(t,n){var u=[];var a;var f;for(;;){a=i(r._(t,n),a);if(a.status){n=a.index;u.push(a.value)}else{return i(e(n,u),a)}}})};n.times=function(r,n){if(arguments.length<2)n=r;var u=this;o(r);o(n);return t(function(t,a){var f=[];var o=a;var s;var c;for(var l=0;l<r;l+=1){s=u._(t,a);c=i(s,c);if(s.status){a=s.index;f.push(s.value)}else return c}for(;l<n;l+=1){s=u._(t,a);c=i(s,c);if(s.status){a=s.index;f.push(s.value)}else break}return i(e(a,f),c)})};n.result=function(r){return this.map(function(t){return r})};n.atMost=function(r){return this.times(0,r)};n.atLeast=function(r){var t=this;return g(this.times(r),this.many(),function(r,t){return r.concat(t)})};n.map=function(r){c(r);var n=this;return t(function(t,u){var a=n._(t,u);if(!a.status)return a;return i(e(a.index,r(a.value)),a)})};n.skip=function(r){return d(this,r).map(function(r){return r[0]})};n.mark=function(){return g(G,this,G,function(r,t,n){return{start:r,value:t,end:n}})};n.desc=function(r){var n=this;return t(function(t,e){var u=n._(t,e);if(!u.status)u.expected=[r];return u})};var _=r.string=function(r){var n=r.length;var i="'"+r+"'";l(r);return t(function(t,a){var f=t.slice(a,a+n);if(f===r){return e(a+n,f)}else{return u(a,i)}})};var E=r.regex=function(r,n){s(r);if(n)o(n);var i=RegExp("^(?:"+r.source+")",(""+r).slice((""+r).lastIndexOf("/")+1));var a=""+r;if(n==null)n=0;return t(function(r,t){var f=i.exec(r.slice(t));if(f){var o=f[0];var s=f[n];if(s!=null)return e(t+o.length,s)}return u(t,a)})};var O=r.succeed=function(r){return t(function(t,n){return e(n,r)})};var b=r.fail=function(r){return t(function(t,n){return u(n,r)})};var k=r.letter=E(/[a-z]/i).desc("a letter");var z=r.letters=E(/[a-z]*/i);var A=r.digit=E(/[0-9]/).desc("a digit");var P=r.digits=E(/[0-9]*/);var j=r.whitespace=E(/\s+/).desc("whitespace");var q=r.optWhitespace=E(/\s*/);var B=r.any=t(function(r,t){if(t>=r.length)return u(t,"any character");return e(t+1,r.charAt(t))});var M=r.all=t(function(r,t){return e(r.length,r.slice(t))});var R=r.eof=t(function(r,t){if(t<r.length)return u(t,"EOF");return e(t,null)});var W=r.test=function(r){c(r);return t(function(t,n){var i=t.charAt(n);if(n<t.length&&r(i)){return e(n+1,i)}else{return u(n,"a character matching "+r)}})};var F=r.oneOf=function(r){return W(function(t){return r.indexOf(t)>=0})};var I=r.noneOf=function(r){return W(function(t){return r.indexOf(t)<0})};var L=r.takeWhile=function(r){c(r);return t(function(t,n){var u=n;while(u<t.length&&r(t.charAt(u)))u+=1;return e(u,t.slice(n,u))})};var C=r.lazy=function(r,n){if(arguments.length<2){n=r;r=undefined}var e=t(function(r,t){e._=n()._;return e._(r,t)});if(r)e=e.desc(r);return e};var D=function(r,t){var n=r.slice(0,t).split("\n");var e=n.length;var u=n[n.length-1].length+1;return{offset:t,line:e,column:u}};var G=r.index=t(function(r,t){return e(t,D(r,t))});n.concat=n.or;n.empty=b("empty");n.of=t.of=r.of=O;n.ap=function(r){return g(this,r,function(r,t){return r(t)})};n.chain=function(r){var n=this;return t(function(t,e){var u=n._(t,e);if(!u.status)return u;var a=r(u.value);return i(a._(t,u.index),u)})};return r}); |
@@ -1,3 +0,9 @@ | ||
## version 0.7.2 (2016-06-??) | ||
## version 0.8.0 (2016-06-28) | ||
* The `.expected` array on parse results is now unique and sorted | ||
* Updated Mocha and Chai versions | ||
* Updated README a bit (mostly line wrapping stuff) | ||
## version 0.7.2 (2016-06-26) | ||
* No API changes | ||
@@ -4,0 +10,0 @@ * Switches to npm-based task running |
{ | ||
"name": "parsimmon", | ||
"version": "0.7.2", | ||
"version": "0.8.0", | ||
"description": "A monadic LL(infinity) parser combinator library", | ||
@@ -21,4 +21,4 @@ "keywords": [ | ||
"devDependencies": { | ||
"chai": "1.5.x", | ||
"mocha": "1.8.x", | ||
"chai": "^3.5.0", | ||
"mocha": "^2.5.3", | ||
"ncp": "^2.0.0", | ||
@@ -35,4 +35,4 @@ "rimraf": "^2.5.2", | ||
"prepublish": "npm run test && npm run clean && npm run build:browser && npm run build:browser.min", | ||
"test": "mocha -u tdd test/intro.js test/*.test.js" | ||
"test": "mocha --ui tdd --reporter dot test/intro.js test/*.test.js" | ||
} | ||
} |
@@ -11,3 +11,3 @@ [![Build Status](https://secure.travis-ci.org/jneen/parsimmon.png)](http://travis-ci.org/jneen/parsimmon) | ||
Parsimmon is a small library for writing big parsers made up of lots of little parsers. The API is inspired by parsec and Promises/A. | ||
Parsimmon is a small library for writing big parsers made up of lots of little parsers. The API is inspired by parsec and Promises/A. | ||
@@ -24,3 +24,5 @@ Parsimmon supports IE7 and newer browsers, along with Node.js. It can be used as a standard Node module through npm, or through `build/parsimmon.browser.js` directly in the browser through a script tag, where it exports a global variable called `Parsimmon`. | ||
function lexeme(p) { return p.skip(optWhitespace); } | ||
function lexeme(p) { | ||
return p.skip(optWhitespace); | ||
} | ||
@@ -30,6 +32,6 @@ var lparen = lexeme(string('(')); | ||
var expr = lazy('an s-expression', function() { return form.or(atom) }); | ||
var expr = lazy('an s-expression', function() { return form.or(atom); }); | ||
var number = lexeme(regex(/[0-9]+/).map(parseInt)); | ||
var id = lexeme(regex(/[a-z_]\w*/i)); | ||
var number = lexeme(regex(/[0-9]+/).map(Number)); | ||
var id = lexeme(regex(/[a-zA-Z_]\w*/)); | ||
@@ -39,5 +41,7 @@ var atom = number.or(id); | ||
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]] | ||
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]] | ||
``` | ||
@@ -47,10 +51,5 @@ | ||
A Parsimmon parser is an object that represents an action on a stream | ||
of text, and the promise of either an object yielded by that action on | ||
success or a message in case of failure. For example, `string('foo')` | ||
yields the string `'foo'` if the beginning of the stream is `'foo'`, | ||
and otherwise fails. | ||
A Parsimmon parser is an object that represents an action on a stream of text, and the promise of either an object yielded by that action on success or a message in case of failure. For example, `string('foo')` yields the string `'foo'` if the beginning of the stream is `'foo'`, and otherwise fails. | ||
The combinator method `.map` is used to transform the yielded value. | ||
For example, | ||
The combinator method `.map` is used to transform the yielded value. For example, | ||
@@ -61,3 +60,3 @@ ```javascript | ||
will yield `'foobar'` if the stream starts with `'foo'`. The parser | ||
will yield `'foobar'` if the stream starts with `'foo'`. The parser | ||
@@ -68,13 +67,8 @@ ```javascript | ||
will yield the number 24 when it encounters the string '12'. The method | ||
`.result` can be used to set a constant result. | ||
will yield the number 24 when it encounters the string '12'. The method `.result` can be used to set a constant result. | ||
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 (with `offset`, | ||
`line` and `column` properties), 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. | ||
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 (with `offset`, `line` and `column` properties), and a sorted, unique array of messages 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. | ||
## Full API | ||
@@ -103,8 +97,7 @@ | ||
and yields the value of the first one that succeeds, backtracking in between. | ||
- `Parsimmon.sepBy(content, separator)` accepts two parsers, and expects multiple | ||
`content`s, separated by `separator`s. Yields an array of `contents`. | ||
- `Parsimmon.sepBy(content, separator)` accepts two parsers, and expects multiple `content`s, separated by `separator`s. Yields an array of `contents`. | ||
- `Parsimmon.sepBy1(content, separator)` same as `Parsimmon.sepBy`, but expects | ||
`content` to succeed at least once. | ||
- `Parsimmon.lazy(f)` accepts a function that returns a parser, which is | ||
evaluated the first time the parser is used. This is useful for | ||
evaluated the first time the parser is used. This is useful for | ||
referencing parsers that haven't yet been defined, and for implementing | ||
@@ -114,3 +107,3 @@ recursive parsers. | ||
sets `desc` as the expected value (see `.desc()` below) | ||
- `Parsimmon.fail(message)` | ||
- `Parsimmon.fail(message)` returns a failing parser with the given message. | ||
- `Parsimmon.letter` is equivalent to `Parsimmon.regex(/[a-z]/i)` | ||
@@ -133,5 +126,3 @@ - `Parsimmon.letters` is equivalent to `Parsimmon.regex(/[a-z]*/i)` | ||
You can add a primitive parser (similar to the included ones) by using | ||
`Parsimmon.custom`. This is an example of how to create a parser that matches | ||
any character except the one provided: | ||
You can add a primitive parser (similar to the included ones) by using `Parsimmon.custom`. This is an example of how to create a parser that matches any character except the one provided: | ||
@@ -142,7 +133,7 @@ ```js | ||
return function(stream, i) { | ||
if (stream.charAt(i) !== char && stream.length <= i) { | ||
return success(i+1, stream.charAt(i)); | ||
if (stream.charAt(i) !== char && i <= stream.length) { | ||
return success(i + 1, stream.charAt(i)); | ||
} | ||
return failure(i, 'anything different than "' + char + '"'); | ||
} | ||
}; | ||
}); | ||
@@ -152,8 +143,8 @@ } | ||
This parser can then be used and composed the same way all the existing ones are | ||
used and composed, for example: | ||
This parser can then be used and composed the same way all the existing ones are used and composed, for example: | ||
```js | ||
var parser = seq(string('a'), notChar('b').times(5)); | ||
parser.parse('accccc'); | ||
var parser = Parsimmon.seq(Parsimmon.string('a'), notChar('b').times(5)); | ||
console.log(parser.parse('accccc')); | ||
//=> {status: true, value: ['a', ['c', 'c', 'c', 'c', 'c']]} | ||
``` | ||
@@ -167,3 +158,3 @@ | ||
given function with the result of the parse, which is expected to | ||
return another parser, which will be tried next. This allows you | ||
return another parser, which will be tried next. This allows you | ||
to dynamically decide how to continue the parse, which is impossible | ||
@@ -173,3 +164,3 @@ with the other combinators. | ||
expects `anotherParser` to follow `parser`, and yields the result | ||
of `anotherParser`. NB: the result of `parser` here is ignored. | ||
of `anotherParser`. NB: the result of `parser` here is ignored. | ||
- `parser.map(function(result) { return anotherResult; })`: | ||
@@ -190,5 +181,5 @@ transforms the output of `parser` with the given function. | ||
- `parser.atMost(n)`: | ||
expects `parser` at most `n` times. Yields an array of the results. | ||
expects `parser` at most `n` times. Yields an array of the results. | ||
- `parser.atLeast(n)`: | ||
expects `parser` at least `n` times. Yields an array of the results. | ||
expects `parser` at least `n` times. Yields an array of the results. | ||
- `parser.mark()` yields an object with `start`, `value`, and `end` keys, | ||
@@ -200,3 +191,3 @@ where `value` is the original value yielded by the parser, and `start` and | ||
- `parser.desc(description)` returns a new parser whose failure message is the passed | ||
description. For example, `string('x').desc('the letter x')` will indicate that | ||
description. For example, `string('x').desc('the letter x')` will indicate that | ||
'the letter x' was expected. | ||
@@ -206,4 +197,3 @@ | ||
These apply to most parsers for traditional languages - it's possible | ||
you may need to do something different for yours! | ||
These apply to most parsers for traditional languages - it's possible you may need to do something different for yours! | ||
@@ -213,3 +203,3 @@ 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. | ||
about (whitespace, comments, etc). You may need multiple types of lexemes. | ||
For example, | ||
@@ -222,3 +212,3 @@ | ||
1. Define all your lexemes first. These should yield native javascript values. | ||
1. Define all your lexemes first. These should yield native javascript values. | ||
@@ -232,3 +222,3 @@ ```javascript | ||
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 | ||
parsers that have not yet been defined. Generally, this takes the form of a | ||
large `.alt()` call | ||
@@ -251,3 +241,3 @@ | ||
1. Finally, export your top-level parser. Remember to skip ignored | ||
1. Finally, export your top-level parser. Remember to skip ignored | ||
stuff at the beginning. | ||
@@ -266,2 +256,2 @@ | ||
Parsimmon is also compatible with [fantasyland][]. It is a Semigroup, an Applicative Functor and a Monad. | ||
Parsimmon is also compatible with [fantasyland][]. It is a Semigroup, an Applicative Functor and a Monad. |
@@ -62,3 +62,3 @@ // This unsightly UMD-module header is here to make this code work without | ||
var expected = (result.furthest === last.furthest) | ||
? result.expected.concat(last.expected) | ||
? union(result.expected, last.expected) | ||
: last.expected; | ||
@@ -75,2 +75,32 @@ | ||
// Returns the sorted set union of two arrays of strings | ||
function union(xs, ys) { | ||
// Exit early if either array is empty (common case) | ||
var xn = xs.length; | ||
var yn = ys.length; | ||
if (xn === 0 && yn === 0) { | ||
return []; | ||
} else if (xn === 0) { | ||
return ys.slice().sort(); | ||
} else if (yn === 0) { | ||
return xs.slice().sort(); | ||
} | ||
// Two non-empty arrays: do the full algorithm | ||
var obj = {}; | ||
for (var i = 0; i < xn; i++) { | ||
obj[xs[i]] = true; | ||
} | ||
for (var i = 0; i < yn; i++) { | ||
obj[ys[i]] = true; | ||
} | ||
var keys = []; | ||
for (var k in obj) { | ||
if (obj.hasOwnProperty(k)) { | ||
keys.push(k); | ||
} | ||
} | ||
keys.sort(); | ||
return keys; | ||
} | ||
// For ensuring we have the right argument types | ||
@@ -77,0 +107,0 @@ function assertParser(p) { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
50031
942
236