diff --git a/API.md b/API.md index 1420a6b..6d5df21 100644 --- a/API.md +++ b/API.md @@ -1,116 +1,116 @@ # Table of Contents - [Terminology](#terminology) - * [Yields](#yields) - * [Input](#input) - * [Consumes](#consumes) + - [Yields](#yields) + - [Input](#input) + - [Consumes](#consumes) - [Base parsers and parser generators](#base-parsers-and-parser-generators) - * [Parsimmon.createLanguage(parsers)](#parsimmoncreatelanguageparsers) - * [Parsimmon(fn)](#parsimmonfn) - * [Parsimmon.Parser(fn)](#parsimmonparserfn) - * [Parsimmon.makeSuccess(index, value)](#parsimmonmakesuccessindex-value) - * [Parsimmon.makeFailure(furthest, expectation)](#parsimmonmakefailurefurthest-expectation) - * [Parsimmon.isParser(obj)](#parsimmonisparserobj) - * [Parsimmon.string(string)](#parsimmonstringstring) - * [Parsimmon.oneOf(string)](#parsimmononeofstring) - * [Parsimmon.noneOf(string)](#parsimmonnoneofstring) - * [Parsimmon.range(begin, end)](#parsimmonrangebegin-end) - * [Parsimmon.regexp(regexp)](#parsimmonregexpregexp) - * [Parsimmon.regexp(regexp, group)](#parsimmonregexpregexp-group) - * [Parsimmon.regex](#parsimmonregex) - * [Parsimmon.notFollowedBy(parser)](#parsimmonnotfollowedbyparser) - * [Parsimmon.lookahead(parser)](#parsimmonlookaheadparser) - * [Parsimmon.lookahead(string)](#parsimmonlookaheadstring) - * [Parsimmon.lookahead(regexp)](#parsimmonlookaheadregexp) - * [Parsimmon.succeed(result)](#parsimmonsucceedresult) - * [Parsimmon.of(result)](#parsimmonofresult) - * [Parsimmon.formatError(string, error)](#parsimmonformaterrorstring-error) - * [Parsimmon.seq(p1, p2, ...pn)](#parsimmonseqp1-p2-pn) - * [Parsimmon.seqMap(p1, p2, ...pn, function(r1, r2, ...rn))](#parsimmonseqmapp1-p2-pn-functionr1-r2-rn) - * [Parsimmon.seqObj(...args)](#parsimmonseqobjargs) - * [Parsimmon.alt(p1, p2, ...pn)](#parsimmonaltp1-p2-pn) - * [Parsimmon.sepBy(content, separator)](#parsimmonsepbycontent-separator) - * [Parsimmon.sepBy1(content, separator)](#parsimmonsepby1content-separator) - * [Parsimmon.lazy(fn)](#parsimmonlazyfn) - * [Parsimmon.lazy(description, fn)](#parsimmonlazydescription-fn) - * [Parsimmon.fail(message)](#parsimmonfailmessage) - * [Parsimmon.letter](#parsimmonletter) - * [Parsimmon.letters](#parsimmonletters) - * [Parsimmon.digit](#parsimmondigit) - * [Parsimmon.digits](#parsimmondigits) - * [Parsimmon.whitespace](#parsimmonwhitespace) - * [Parsimmon.optWhitespace](#parsimmonoptwhitespace) - * [Parsimmon.cr](#parsimmoncr) - * [Parsimmon.lf](#parsimmonlf) - * [Parsimmon.crlf](#parsimmoncrlf) - * [Parsimmon.newline](#parsimmonnewline) - * [Parsimmon.end](#parsimmonend) - * [Parsimmon.any](#parsimmonany) - * [Parsimmon.all](#parsimmonall) - * [Parsimmon.eof](#parsimmoneof) - * [Parsimmon.index](#parsimmonindex) - * [Parsimmon.test(predicate)](#parsimmontestpredicate) - * [Parsimmon.takeWhile(predicate)](#parsimmontakewhilepredicate) - * [Parsimmon.custom(fn)](#parsimmoncustomfn) + - [Parsimmon.createLanguage(parsers)](#parsimmoncreatelanguageparsers) + - [Parsimmon(fn)](#parsimmonfn) + - [Parsimmon.Parser(fn)](#parsimmonparserfn) + - [Parsimmon.makeSuccess(index, value)](#parsimmonmakesuccessindex-value) + - [Parsimmon.makeFailure(furthest, expectation)](#parsimmonmakefailurefurthest-expectation) + - [Parsimmon.isParser(obj)](#parsimmonisparserobj) + - [Parsimmon.string(string)](#parsimmonstringstring) + - [Parsimmon.oneOf(string)](#parsimmononeofstring) + - [Parsimmon.noneOf(string)](#parsimmonnoneofstring) + - [Parsimmon.range(begin, end)](#parsimmonrangebegin-end) + - [Parsimmon.regexp(regexp)](#parsimmonregexpregexp) + - [Parsimmon.regexp(regexp, group)](#parsimmonregexpregexp-group) + - [Parsimmon.regex](#parsimmonregex) + - [Parsimmon.notFollowedBy(parser)](#parsimmonnotfollowedbyparser) + - [Parsimmon.lookahead(parser)](#parsimmonlookaheadparser) + - [Parsimmon.lookahead(string)](#parsimmonlookaheadstring) + - [Parsimmon.lookahead(regexp)](#parsimmonlookaheadregexp) + - [Parsimmon.succeed(result)](#parsimmonsucceedresult) + - [Parsimmon.of(result)](#parsimmonofresult) + - [Parsimmon.formatError(string, error)](#parsimmonformaterrorstring-error) + - [Parsimmon.seq(p1, p2, ...pn)](#parsimmonseqp1-p2-pn) + - [Parsimmon.seqMap(p1, p2, ...pn, function(r1, r2, ...rn))](#parsimmonseqmapp1-p2-pn-functionr1-r2-rn) + - [Parsimmon.seqObj(...args)](#parsimmonseqobjargs) + - [Parsimmon.alt(p1, p2, ...pn)](#parsimmonaltp1-p2-pn) + - [Parsimmon.sepBy(content, separator)](#parsimmonsepbycontent-separator) + - [Parsimmon.sepBy1(content, separator)](#parsimmonsepby1content-separator) + - [Parsimmon.lazy(fn)](#parsimmonlazyfn) + - [Parsimmon.lazy(description, fn)](#parsimmonlazydescription-fn) + - [Parsimmon.fail(message)](#parsimmonfailmessage) + - [Parsimmon.letter](#parsimmonletter) + - [Parsimmon.letters](#parsimmonletters) + - [Parsimmon.digit](#parsimmondigit) + - [Parsimmon.digits](#parsimmondigits) + - [Parsimmon.whitespace](#parsimmonwhitespace) + - [Parsimmon.optWhitespace](#parsimmonoptwhitespace) + - [Parsimmon.cr](#parsimmoncr) + - [Parsimmon.lf](#parsimmonlf) + - [Parsimmon.crlf](#parsimmoncrlf) + - [Parsimmon.newline](#parsimmonnewline) + - [Parsimmon.end](#parsimmonend) + - [Parsimmon.any](#parsimmonany) + - [Parsimmon.all](#parsimmonall) + - [Parsimmon.eof](#parsimmoneof) + - [Parsimmon.index](#parsimmonindex) + - [Parsimmon.test(predicate)](#parsimmontestpredicate) + - [Parsimmon.takeWhile(predicate)](#parsimmontakewhilepredicate) + - [Parsimmon.custom(fn)](#parsimmoncustomfn) - [Binary constructors](#binary-constructors) - * [Parsimmon.byte(int)](#parsimmonbyteint) - * [Parsimmon.bitSeq(alignments)](#parsimmonbitseqalignments) - * [Parsimmon.bitSeqObj(namedAlignments)](#parsimmonbitseqobjnamedalignments) + - [Parsimmon.byte(int)](#parsimmonbyteint) + - [Parsimmon.bitSeq(alignments)](#parsimmonbitseqalignments) + - [Parsimmon.bitSeqObj(namedAlignments)](#parsimmonbitseqobjnamedalignments) - [Parser methods](#parser-methods) - * [parser.parse(input)](#parserparseinput) - * [parser.tryParse(input)](#parsertryparseinput) - * [parser.or(otherParser)](#parserorotherparser) - * [parser.chain(newParserFunc)](#parserchainnewparserfunc) - * [parser.then(anotherParser)](#parserthenanotherparser) - * [parser.map(fn)](#parsermapfn) - * [parser.contramap(fn)](#parsercontramapfn) - * [parser.promap(fn)](#parserpromapfn) - * [parser.result(value)](#parserresultvalue) - * [parser.fallback(value)](#parserfallbackvalue) - * [parser.skip(otherParser)](#parserskipotherparser) - * [parser.trim(anotherParser)](#parsertrimanotherparser) - * [parser.wrap(before, after)](#parserwrapbefore-after) - * [parser.notFollowedBy(anotherParser)](#parsernotfollowedbyanotherparser) - * [parser.lookahead(anotherParser)](#parserlookaheadanotherparser) - * [parser.lookahead(string)](#parserlookaheadstring) - * [parser.lookahead(regexp)](#parserlookaheadregexp) - * [parser.assert(condition, message)](#parserassertcondition-message) - * [parser.tie()](#parsertie) - * [parser.many()](#parsermany) - * [parser.times(n)](#parsertimesn) - * [parser.times(min, max)](#parsertimesmin-max) - * [parser.atMost(n)](#parseratmostn) - * [parser.atLeast(n)](#parseratleastn) - * [parser.node(name)](#parsernodename) - * [parser.mark()](#parsermark) - * [parser.thru(wrapper)](#parserthruwrapper) - * [parser.desc(description)](#parserdescdescription) + - [parser.parse(input)](#parserparseinput) + - [parser.tryParse(input)](#parsertryparseinput) + - [parser.or(otherParser)](#parserorotherparser) + - [parser.chain(newParserFunc)](#parserchainnewparserfunc) + - [parser.then(anotherParser)](#parserthenanotherparser) + - [parser.map(fn)](#parsermapfn) + - [parser.contramap(fn)](#parsercontramapfn) + - [parser.promap(fn)](#parserpromapfn) + - [parser.result(value)](#parserresultvalue) + - [parser.fallback(value)](#parserfallbackvalue) + - [parser.skip(otherParser)](#parserskipotherparser) + - [parser.trim(anotherParser)](#parsertrimanotherparser) + - [parser.wrap(before, after)](#parserwrapbefore-after) + - [parser.notFollowedBy(anotherParser)](#parsernotfollowedbyanotherparser) + - [parser.lookahead(anotherParser)](#parserlookaheadanotherparser) + - [parser.lookahead(string)](#parserlookaheadstring) + - [parser.lookahead(regexp)](#parserlookaheadregexp) + - [parser.assert(condition, message)](#parserassertcondition-message) + - [parser.tie()](#parsertie) + - [parser.many()](#parsermany) + - [parser.times(n)](#parsertimesn) + - [parser.times(min, max)](#parsertimesmin-max) + - [parser.atMost(n)](#parseratmostn) + - [parser.atLeast(n)](#parseratleastn) + - [parser.node(name)](#parsernodename) + - [parser.mark()](#parsermark) + - [parser.thru(wrapper)](#parserthruwrapper) + - [parser.desc(description)](#parserdescdescription) - [FantasyLand support](#fantasyland-support) - * [Parsimmon.empty()](#parsimmonempty) - * [parser.empty()](#parserempty) - * [parser.concat(otherParser)](#parserconcatotherparser) - * [parser.ap(otherParser)](#parserapotherparser) - * [parser.sepBy(separator)](#parsersepbyseparator) - * [parser.sepBy1(separator)](#parsersepby1separator) - * [parser.chain(newParserFunc)](#parserchainnewparserfunc-1) - * [parser.of(result)](#parserofresult) + - [Parsimmon.empty()](#parsimmonempty) + - [parser.empty()](#parserempty) + - [parser.concat(otherParser)](#parserconcatotherparser) + - [parser.ap(otherParser)](#parserapotherparser) + - [parser.sepBy(separator)](#parsersepbyseparator) + - [parser.sepBy1(separator)](#parsersepby1separator) + - [parser.chain(newParserFunc)](#parserchainnewparserfunc-1) + - [parser.of(result)](#parserofresult) - [Tips](#tips) - * [Readability](#readability) - * [Side effects](#side-effects) + - [Readability](#readability) + - [Side effects](#side-effects) # Terminology ## Yields -When the documentation says a function *yields an array of strings*, it means the function returns a parser that when called with [`.parse`](#parserparseinput) will return an object containing the array of strings. +When the documentation says a function _yields an array of strings_, it means the function returns a parser that when called with [`.parse`](#parserparseinput) will return an object containing the array of strings. ## Input -The string passed to [`.parse`](#parserparseinput) is called the *input*. +The string passed to [`.parse`](#parserparseinput) is called the _input_. ## Consumes -A parser is said to *consume* the text that it parses, leaving only the unconsumed text for subsequent parsers to check. +A parser is said to _consume_ the text that it parses, leaving only the unconsumed text for subsequent parsers to check. # Base parsers and parser generators @@ -127,11 +127,7 @@ Example: ```js var Lang = Parsimmon.createLanguage({ Value: function(r) { - return Parsimmon.alt( - r.Number, - r.Symbol, - r.List - ); + return Parsimmon.alt(r.Number, r.Symbol, r.List); }, Number: function() { return Parsimmon.regexp(/[0-9]+/).map(Number); @@ -140,15 +136,15 @@ var Lang = Parsimmon.createLanguage({ return Parsimmon.regexp(/[a-z]+/); }, List: function(r) { - return Parsimmon.string('(') + return Parsimmon.string("(") .then(r.Value.sepBy(r._)) - .skip(Parsimmon.string(')')); + .skip(Parsimmon.string(")")); }, _: function() { return Parsimmon.optWhitespace; } }); -Lang.Value.tryParse('(list 1 2 foo (list nice 3 56 989 asdasdas))'); +Lang.Value.tryParse("(list 1 2 foo (list nice 3 56 989 asdasdas))"); ``` ## Parsimmon(fn) @@ -157,7 +153,7 @@ Lang.Value.tryParse('(list 1 2 foo (list nice 3 56 989 asdasdas))'); You can add a primitive parser (similar to the included ones) by using [`Parsimmon(fn)`](#parsimmonfn). This is an example of how to create a parser that matches any character except the one provided: -```javascript +```js function notChar(char) { return Parsimmon(function(input, i) { if (input.charAt(i) !== char) { @@ -170,13 +166,9 @@ function notChar(char) { This parser can then be used and composed the same way all the existing ones are used and composed, for example: -```javascript -var parser = - Parsimmon.seq( - Parsimmon.string('a'), - notChar('b').times(5) - ); -parser.parse('accccc'); +```js +var parser = Parsimmon.seq(Parsimmon.string("a"), notChar("b").times(5)); +parser.parse("accccc"); //=> {status: true, value: ['a', ['c', 'c', 'c', 'c', 'c']]} ``` @@ -190,7 +182,7 @@ To be used inside of [`Parsimmon(fn)`](#parsimmonfn). Generates an object descri ## Parsimmon.makeFailure(furthest, expectation) -To be used inside of [`Parsimmon(fn)`](#parsimmonfn). Generates an object describing how far the unsuccessful parse went (`index`), and what kind of syntax it expected to see (`expectation`). The expected value may also be an array of different values. See documentation for [`Parsimmon(fn)`](#parsimmonfn). +To be used inside of [`Parsimmon(fn)`](#parsimmonfn). Generates an object describing how far the unsuccessful parse went (`index`), and what kind of syntax it expected to see (`expectation`). The expected value may also be an array of different values. See documentation for [`Parsimmon(fn)`](#parsimmonfn). ## Parsimmon.isParser(obj) @@ -206,7 +198,7 @@ Returns a parser that looks for exactly one character from `string`, and yields ## Parsimmon.noneOf(string) -Returns a parser that looks for precisely one character *NOT* from `string`, and yields that character. +Returns a parser that looks for precisely one character _NOT_ from `string`, and yields that character. ## Parsimmon.range(begin, end) @@ -215,22 +207,18 @@ Parses a single character from `begin` to `end`, inclusive. Example: ```js -var firstChar = - Parsimmon.alt( - Parsimmon.range('a', 'z'), - Parsimmon.range('A', 'Z'), - Parsimmon.oneOf('_$'), - ); -var restChar = firstChar.or(Parsimmon.range('0', '9')); -var identifier = P.seq( - firstChar, - restChar.many().tie() -).tie(); - -identifier.tryParse('__name$cool10__'); +var firstChar = Parsimmon.alt( + Parsimmon.range("a", "z"), + Parsimmon.range("A", "Z"), + Parsimmon.oneOf("_$") +); +var restChar = firstChar.or(Parsimmon.range("0", "9")); +var identifier = P.seq(firstChar, restChar.many().tie()).tie(); + +identifier.tryParse("__name$cool10__"); // => '__name$cool10__' -identifier.tryParse('3d'); +identifier.tryParse("3d"); // => Error ``` @@ -256,7 +244,7 @@ This is an alias for [`Parsimmon.regexp`](#parsimmonregexpregexp). ## Parsimmon.notFollowedBy(parser) -Parses using `parser`, but does not consume what it parses. Yields `null` if the parser *does not match* the input. Otherwise, it fails. +Parses using `parser`, but does not consume what it parses. Yields `null` if the parser _does not match_ the input. Otherwise, it fails. ## Parsimmon.lookahead(parser) @@ -286,23 +274,22 @@ Takes the `string` passed to `parser.parse(string)` and the `error` returned fro Accepts any number of parsers and returns a new parser that expects them to match in order, yielding an array of all their results. - ## Parsimmon.seqMap(p1, p2, ...pn, function(r1, r2, ...rn)) Matches all parsers sequentially, and passes their results as the arguments to a function, yielding the return value of that function. Similar to calling [`Parsimmon.seq`](#parsimmonseqp1-p2-pn) and then [`.map`](#parsermapfn), but the values are not put in an array. Example: -```javascript +```js Parsimmon.seqMap( - Parsimmon.oneOf('abc'), - Parsimmon.oneOf('+-*'), - Parsimmon.oneOf('xyz'), + Parsimmon.oneOf("abc"), + Parsimmon.oneOf("+-*"), + Parsimmon.oneOf("xyz"), function(first, operator, second) { - console.log(first); // => 'a' + console.log(first); // => 'a' console.log(operator); // => '+' - console.log(second); // => 'x' + console.log(second); // => 'x' return [operator, first, second]; } -).parse('a+x') +).parse("a+x"); ``` ## Parsimmon.seqObj(...args) @@ -320,17 +307,16 @@ Example: ```js var _ = Parsimmon.optWhitespace; var identifier = Parsimmon.regexp(/[a-z_][a-z0-9_]*/i); -var lparen = Parsimmon.string('('); -var rparen = Parsimmon.string(')'); -var comma = Parsimmon.string(','); -var functionCall = - Parsimmon.seqObj( - ['function', identifier], - lparen, - ['arguments', identifier.trim(_).sepBy(comma)], - rparen - ); -functionCall.tryParse('foo(bar, baz, quux)'); +var lparen = Parsimmon.string("("); +var rparen = Parsimmon.string(")"); +var comma = Parsimmon.string(","); +var functionCall = Parsimmon.seqObj( + ["function", identifier], + lparen, + ["arguments", identifier.trim(_).sepBy(comma)], + rparen +); +functionCall.tryParse("foo(bar, baz, quux)"); // => { function: 'foo', // arguments: [ 'bar', 'baz', 'quux' ] } ``` @@ -344,17 +330,11 @@ Accepts any number of parsers, yielding the value of the first one that succeeds This means that the order of parsers matters. If two parsers match the same prefix, the **longer** of the two must come first. Example: -```javascript -Parsimmon.alt( - Parsimmon.string('ab'), - Parsimmon.string('a') -).parse('ab'); +```js +Parsimmon.alt(Parsimmon.string("ab"), Parsimmon.string("a")).parse("ab"); // => {status: true, value: 'ab'} -Parsimmon.alt( - Parsimmon.string('a'), - Parsimmon.string('ab') -).parse('ab'); +Parsimmon.alt(Parsimmon.string("a"), Parsimmon.string("ab")).parse("ab"); // => {status: false, ...} ``` @@ -374,19 +354,19 @@ See [`parser.sepBy1(separator)`](#parsersepby1separator). 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, and for implementing recursive parsers. Example: -```javascript +```js var Value = Parsimmon.lazy(function() { return Parsimmon.alt( - Parsimmon.string('X'), - Parsimmon.string('(') + Parsimmon.string("X"), + Parsimmon.string("(") .then(Value) - .skip(Parsimmon.string(')')) + .skip(Parsimmon.string(")")) ); }); -Value.parse('X'); // => {status: true, value: 'X'} -Value.parse('(X)'); // => {status: true, value: 'X'} -Value.parse('((X))'); // => {status: true, value: 'X'} +Value.parse("X"); // => {status: true, value: 'X'} +Value.parse("(X)"); // => {status: true, value: 'X'} +Value.parse("((X))"); // => {status: true, value: 'X'} ``` ## Parsimmon.lazy(description, fn) @@ -444,11 +424,7 @@ This parser checks for the "carriage return" character followed by the "line fee Equivalent to: ```js -Parsimmon.alt( - Parsimmon.crlf, - Parsimmon.lf, - Parsimmon.cr -).desc("newline") +Parsimmon.alt(Parsimmon.crlf, Parsimmon.lf, Parsimmon.cr).desc("newline"); ``` This flexible parser will match any kind of text file line ending. @@ -475,60 +451,60 @@ A parser that expects to be at the end of the input (zero characters left). A parser that consumes no input and yields an object an object representing the current offset into the parse: it has a 0-based character `offset` property and 1-based `line` and `column` properties. Example: -```javascript +```js Parsimmon.seqMap( - Parsimmon.oneOf('Q\n').many(), - Parsimmon.string('B'), + Parsimmon.oneOf("Q\n").many(), + Parsimmon.string("B"), Parsimmon.index, function(_prefix, B, index) { console.log(index.offset); // => 8 - console.log(index.line); // => 3 + console.log(index.line); // => 3 console.log(index.column); // => 5 return B; } -).parse('QQ\n\nQQQB'); +).parse("QQ\n\nQQQB"); ``` ## Parsimmon.test(predicate) Returns a parser that yield a single character if it passes the `predicate` function. Example: -```javascript +```js var SameUpperLower = Parsimmon.test(function(c) { return c.toUpperCase() === c.toLowerCase(); }); -SameUpperLower.parse('a'); // => {status: false, ...} -SameUpperLower.parse('-'); // => {status: true, ...} -SameUpperLower.parse(':'); // => {status: true, ...} +SameUpperLower.parse("a"); // => {status: false, ...} +SameUpperLower.parse("-"); // => {status: true, ...} +SameUpperLower.parse(":"); // => {status: true, ...} ``` ## Parsimmon.takeWhile(predicate) Returns a parser yield a string containing all the next characters that pass the `predicate`. Example: -```javascript -var CustomString = - Parsimmon.string('%') - .then(Parsimmon.any) - .chain(function(start) { - var end = { - '[': ']', - '(': ')', - '{': '}', - '<': '>' +```js +var CustomString = Parsimmon.string("%") + .then(Parsimmon.any) + .chain(function(start) { + var end = + { + "[": "]", + "(": ")", + "{": "}", + "<": ">" }[start] || start; - return Parsimmon.takeWhile(function(c) { - return c !== end; - }).skip(Parsimmon.string(end)); - }); + return Parsimmon.takeWhile(function(c) { + return c !== end; + }).skip(Parsimmon.string(end)); + }); -CustomString.parse('%:a string:'); // => {status: true, value: 'a string'} -CustomString.parse('%[a string]'); // => {status: true, value: 'a string'} -CustomString.parse('%{a string}'); // => {status: true, value: 'a string'} -CustomString.parse('%(a string)'); // => {status: true, value: 'a string'} -CustomString.parse('%'); // => {status: true, value: 'a string'} +CustomString.parse("%:a string:"); // => {status: true, value: 'a string'} +CustomString.parse("%[a string]"); // => {status: true, value: 'a string'} +CustomString.parse("%{a string}"); // => {status: true, value: 'a string'} +CustomString.parse("%(a string)"); // => {status: true, value: 'a string'} +CustomString.parse("%"); // => {status: true, value: 'a string'} ``` ## Parsimmon.custom(fn) @@ -537,7 +513,7 @@ CustomString.parse('%'); // => {status: true, value: 'a string'} 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: -```javascript +```js function notChar(char) { return Parsimmon.custom(function(success, failure) { return function(input, i) { @@ -552,13 +528,9 @@ function notChar(char) { This parser can then be used and composed the same way all the existing ones are used and composed, for example: -```javascript -var parser = - Parsimmon.seq( - Parsimmon.string('a'), - notChar('b').times(5) - ); -parser.parse('accccc'); +```js +var parser = Parsimmon.seq(Parsimmon.string("a"), notChar("b").times(5)); +parser.parse("accccc"); // => { status: true, value: ['a', ['c', 'c', 'c', 'c', 'c']] } ``` @@ -570,7 +542,7 @@ The `Parsimmon.Binary` constructors parse binary content using Node.js Buffers. Returns a parser that yields a byte (as a number) that matches the given input; similar to `Parsimmon.digit` and `Parsimmon.letter`. -```javascript +```js var parser = Parsimmon.Binary.byte(0x3f); parser.parse(Buffer.from([0x3f])); // => { status: true, value: 63 } @@ -578,9 +550,9 @@ parser.parse(Buffer.from([0x3f])); ## Parsimmon.buffer(length) -Returns a parser that will consume some of a buffer and present it as a raw buffer for further transformation. This buffer is cloned, so in case you use a destructive method, it will not corrupt the original input buffer. +Returns a parser that will consume some of a buffer and present it as a raw buffer for further transformation. This buffer is cloned, so in case you use a destructive method, it will not corrupt the original input buffer. -```javaScript +```js var parser = Parsimmon.Binary.buffer(2).skip(Parsimmon.any); parser.parse(Buffer.from([1, 2, 3])); // => { status: true, value: } @@ -590,9 +562,29 @@ parser.parse(Buffer.from([1, 2, 3])); Parse `length` bytes, and then decode with a particular `encoding`. -```javascript -var parser = Parsimmon.Binary.encodedString('utf8', 17); -parser.parse(Buffer.from([0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x21, 0x20, 0xf0, 0x9f, 0x98, 0x84])); +```js +var parser = Parsimmon.Binary.encodedString("utf8", 17); +parser.parse( + Buffer.from([ + 0x68, + 0x65, + 0x6c, + 0x6c, + 0x6f, + 0x20, + 0x74, + 0x68, + 0x65, + 0x72, + 0x65, + 0x21, + 0x20, + 0xf0, + 0x9f, + 0x98, + 0x84 + ]) +); // => { status: true, value: 'hello there! 😄' } ``` @@ -600,9 +592,9 @@ parser.parse(Buffer.from([0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x74, 0x68, 0x65, Parse an unsigned integer of 1 byte. -```javascript +```js var parser = Parsimmon.Binary.uint8; -parser.parse(Buffer.from([0xFF])); +parser.parse(Buffer.from([0xff])); // => { status: true, value: 255 } ``` @@ -610,17 +602,17 @@ parser.parse(Buffer.from([0xFF])); Parse a signed integer of 1 byte. -```javascript +```js var parser = Parsimmon.Binary.int8; -parser.parse(Buffer.from([0xFF])); +parser.parse(Buffer.from([0xff])); // => { status: true, value: -1 } ``` ## Parsimmon.uintBE(length) -Parse an unsigned integer (big-endian) of length bytes. Length cannot exceed 6. +Parse an unsigned integer (big-endian) of length bytes. Length cannot exceed 6. -```javascript +```js var parser = Parsimmon.Binary.uintBE(4); parser.parse(Buffer.from([1, 2, 3, 4])); // => { status: true, value: 16909060 } @@ -628,9 +620,9 @@ parser.parse(Buffer.from([1, 2, 3, 4])); ## Parsimmon.intBE(length) -Parse a signed integer (big-endian) of length bytes. Length cannot exceed 6. +Parse a signed integer (big-endian) of length bytes. Length cannot exceed 6. -```javascript +```js var parser = Parsimmon.Binary.intBE(4); parser.parse(Buffer.from([0xff, 2, 3, 4])); // => { status: true, value: -16645372 } @@ -638,9 +630,9 @@ parser.parse(Buffer.from([0xff, 2, 3, 4])); ## Parsimmon.uintLE(length) -Parse an unsigned integer (little-endian) of length bytes. Length cannot exceed 6. +Parse an unsigned integer (little-endian) of length bytes. Length cannot exceed 6. -```javascript +```js var parser = Parsimmon.Binary.uintLE(4); parser.parse(Buffer.from([1, 2, 3, 4])); // => { status: true, value: 67305985 } @@ -648,9 +640,9 @@ parser.parse(Buffer.from([1, 2, 3, 4])); ## Parsimmon.intLE(length) -Parse a signed integer (little-endian) of length bytes. Length cannot exceed 6. +Parse a signed integer (little-endian) of length bytes. Length cannot exceed 6. -```javascript +```js var parser = Parsimmon.Binary.intLE(4); parser.parse(Buffer.from([1, 2, 3, 0xff])); // => { status: true, value: -16580095 } @@ -660,9 +652,9 @@ parser.parse(Buffer.from([1, 2, 3, 0xff])); Parse an unsigned integer (big-endian) of 2 bytes. -```javascript +```js var parser = Parsimmon.Binary.uint16BE; -parser.parse(Buffer.from([0xFF, 0xFE])); +parser.parse(Buffer.from([0xff, 0xfe])); // => { status: true, value: 65534 } ``` @@ -670,9 +662,9 @@ parser.parse(Buffer.from([0xFF, 0xFE])); Parse a signed integer (big-endian) of 2 bytes. -```javascript +```js var parser = Parsimmon.Binary.int16BE; -parser.parse(Buffer.from([0xFF, 0xFE])); +parser.parse(Buffer.from([0xff, 0xfe])); // => { status: true, value: -2 } ``` @@ -680,9 +672,9 @@ parser.parse(Buffer.from([0xFF, 0xFE])); Parse an unsigned integer (little-endian) of 2 bytes. -```javascript +```js var parser = Parsimmon.Binary.uint16LE; -parser.parse(Buffer.from([0xFE, 0xFF])); +parser.parse(Buffer.from([0xfe, 0xff])); // => { status: true, value: 65534 } ``` @@ -690,9 +682,9 @@ parser.parse(Buffer.from([0xFE, 0xFF])); Parse a signed integer (little-endian) of 2 bytes. -```javascript +```js var parser = Parsimmon.Binary.int16LE; -parser.parse(Buffer.from([0xFE, 0xFF])); +parser.parse(Buffer.from([0xfe, 0xff])); // => { status: true, value: -2 } ``` @@ -700,9 +692,9 @@ parser.parse(Buffer.from([0xFE, 0xFF])); Parse an unsigned integer (big-endian) of 4 bytes. -```javascript +```js var parser = Parsimmon.Binary.uint32BE; -parser.parse(Buffer.from([0x00, 0x00, 0x00, 0xFF])); +parser.parse(Buffer.from([0x00, 0x00, 0x00, 0xff])); // => { status: true, value: 255 } ``` @@ -710,9 +702,9 @@ parser.parse(Buffer.from([0x00, 0x00, 0x00, 0xFF])); Parse an signed integer (big-endian) of 4 bytes. -```javascript +```js var parser = Parsimmon.Binary.int32BE; -parser.parse(Buffer.from([0xFF, 0xFF, 0xFF, 0xFE])); +parser.parse(Buffer.from([0xff, 0xff, 0xff, 0xfe])); // => { status: true, value: -2 } ``` @@ -720,9 +712,9 @@ parser.parse(Buffer.from([0xFF, 0xFF, 0xFF, 0xFE])); Parse an unsigned integer (little-endian) of 4 bytes. -```javascript +```js var parser = Parsimmon.Binary.uint32LE; -parser.parse(Buffer.from([0xFF, 0x00, 0x00, 0x00])); +parser.parse(Buffer.from([0xff, 0x00, 0x00, 0x00])); // => { status: true, value: 255 } ``` @@ -730,9 +722,9 @@ parser.parse(Buffer.from([0xFF, 0x00, 0x00, 0x00])); Parse an signed integer (little-endian) of 4 bytes. -```javascript +```js var parser = Parsimmon.Binary.int32LE; -parser.parse(Buffer.from([0xFE, 0xFF, 0xFF, 0xFF])); +parser.parse(Buffer.from([0xfe, 0xff, 0xff, 0xff])); // => { status: true, value: -2 } ``` @@ -740,7 +732,7 @@ parser.parse(Buffer.from([0xFE, 0xFF, 0xFF, 0xFF])); Parse a float (big-endian) of 4 bytes. -```javascript +```js var parser = Parsimmon.Binary.floatBE; parser.parse(Buffer.from([1, 2, 3, 4])); // => { status: true, value: 2.387939260590663e-38 } @@ -750,7 +742,7 @@ parser.parse(Buffer.from([1, 2, 3, 4])); Parse a float (little-endian) of 4 bytes. -```javascript +```js var parser = Parsimmon.Binary.floatLE; parser.parse(Buffer.from([1, 2, 3, 4])); // => { status: true, value: 1.539989614439558e-36 } @@ -760,7 +752,7 @@ parser.parse(Buffer.from([1, 2, 3, 4])); Parse a double (big-endian) of 8 bytes. -```javascript +```js var parser = Parsimmon.Binary.doubleBE; parser.parse(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8])); // => { status: true, value: 8.20788039913184e-304 } @@ -770,7 +762,7 @@ parser.parse(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8])); Parse a double (little-endian) of 8 bytes. -```javascript +```js var parser = Parsimmon.Binary.doubleLE; parser.parse(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8])); // => { status: true, value: 5.447603722011605e-270 } @@ -780,7 +772,7 @@ parser.parse(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8])); Parse a series of bits that do not have to be byte-aligned and consume them from a Buffer. The maximum number is 48 since more than 48 bits won't fit safely into a JavaScript number without losing precision. Also, the total of all bits in the sequence must be a multiple of 8 since parsing is still done at the byte level. -```javascript +```js var parser = Parsimmon.Binary.bitSeq([3, 5, 5, 3]); parser.parse(Buffer.from([0x04, 0xff])); //=> { status: true, value: [0, 4, 31, 7] } @@ -790,18 +782,13 @@ parser.parse(Buffer.from([0x04, 0xff])); Works like `Parsimmon.bitSeq` except each item in the array is either a number of bits or pair (array with length = 2) of name and bits. The bits are parsed in order and put into an object based on the name supplied. If there's no name for the bits, it will be parsed but discarded from the returned value. -```javascript -var parser = Parsimmon.Binary.bitSeqObj([ - ["a", 3], - 5, - ["b", 5], - ["c", 3] -]); -parser.parse(Buffer.from([0x04, 0xFF])); +```js +var parser = Parsimmon.Binary.bitSeqObj([["a", 3], 5, ["b", 5], ["c", 3]]); +parser.parse(Buffer.from([0x04, 0xff])); //=> { status: true, value: { a: 0, b: 31, c: 7 } } ``` -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +--- # Parser methods @@ -811,22 +798,21 @@ These methods are all called off of existing parsers, not from the `Parsimmon` o Apply `parser` on the provided string `input`, returning an object that contains the status and parsed result. -If the parser succeeds, `status` is set to *true*, and the value will be available in the `value` property. +If the parser succeeds, `status` is set to _true_, and the value will be available in the `value` property. -If the parser fails, `status` will be *false*. Further information on the error can be found at `index` and `expected`. `index` represents the furthest reached offset; it has a 0-based character `offset` and 1-based `line` and `column` properties. `expected` lists all tried parsers that were available at the offset, but the input couldn't continue with any of these. +If the parser fails, `status` will be _false_. Further information on the error can be found at `index` and `expected`. `index` represents the furthest reached offset; it has a 0-based character `offset` and 1-based `line` and `column` properties. `expected` lists all tried parsers that were available at the offset, but the input couldn't continue with any of these. -```javascript -var parser = - Parsimmon.alt( - // Use `parser.desc(string)` in order to have meaningful failure messages - Parsimmon.string('a').desc("'a' character"), - Parsimmon.string('b').desc("'b' character") - ); +```js +var parser = Parsimmon.alt( + // Use `parser.desc(string)` in order to have meaningful failure messages + Parsimmon.string("a").desc("'a' character"), + Parsimmon.string("b").desc("'b' character") +); -parser.parse('a'); +parser.parse("a"); // => {status: true, value: 'a'} -parser.parse('ccc'); +parser.parse("ccc"); // => {status: false, // index: {...}, // expected: ["'a' character", "'b' character"]} @@ -836,14 +822,14 @@ parser.parse('ccc'); Like `parser.parse(input)` but either returns the parsed value or throws an error on failure. The error object contains additional properties about the error. -```javascript +```js var parser = Parsimmon.letters.sepBy1(Parsimmon.whitespace); -parser.tryParse('foo bar baz'); +parser.tryParse("foo bar baz"); // => ['foo', 'bar', 'baz'] try { - parser.tryParse('123') + parser.tryParse("123"); } catch (err) { err.message; // => 'expected one of EOF, whitespace at line 1 column 1, got \'123\'' @@ -862,43 +848,42 @@ try { Returns a new parser which tries `parser`, and if it fails uses `otherParser`. Example: -```javascript -var numberPrefix = - Parsimmon.string('+') - .or(Parsimmon.string('-')) - .fallback(''); +```js +var numberPrefix = Parsimmon.string("+") + .or(Parsimmon.string("-")) + .fallback(""); -numberPrefix.parse('+'); // => {status: true, value: '+'} -numberPrefix.parse('-'); // => {status: true, value: '-'} -numberPrefix.parse(''); // => {status: true, value: ''} +numberPrefix.parse("+"); // => {status: true, value: '+'} +numberPrefix.parse("-"); // => {status: true, value: '-'} +numberPrefix.parse(""); // => {status: true, value: ''} ``` ## parser.chain(newParserFunc) Returns a new parser which tries `parser`, and on success calls the function `newParserFunc` with the result of the parse, which is expected to 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. Example: -```javascript -var CustomString = - Parsimmon.string('%') - .then(Parsimmon.any) - .chain(function(start) { - var end = { - '[': ']', - '(': ')', - '{': '}', - '<': '>' +```js +var CustomString = Parsimmon.string("%") + .then(Parsimmon.any) + .chain(function(start) { + var end = + { + "[": "]", + "(": ")", + "{": "}", + "<": ">" }[start] || start; - return Parsimmon.takeWhile(function(c) { - return c !== end; - }).skip(Parsimmon.string(end)); - }); + return Parsimmon.takeWhile(function(c) { + return c !== end; + }).skip(Parsimmon.string(end)); + }); -CustomString.parse('%:a string:'); // => {status: true, value: 'a string'} -CustomString.parse('%[a string]'); // => {status: true, value: 'a string'} -CustomString.parse('%{a string}'); // => {status: true, value: 'a string'} -CustomString.parse('%(a string)'); // => {status: true, value: 'a string'} -CustomString.parse('%'); // => {status: true, value: 'a string'} +CustomString.parse("%:a string:"); // => {status: true, value: 'a string'} +CustomString.parse("%[a string]"); // => {status: true, value: 'a string'} +CustomString.parse("%{a string}"); // => {status: true, value: 'a string'} +CustomString.parse("%(a string)"); // => {status: true, value: 'a string'} +CustomString.parse("%"); // => {status: true, value: 'a string'} ``` ## parser.then(anotherParser) @@ -906,51 +891,54 @@ CustomString.parse('%'); // => {status: true, value: 'a string'} Expects `anotherParser` to follow `parser`, and yields the result of `anotherParser`. -```javascript +```js var parserA = p1.then(p2); // is equivalent to... -var parserB = Parsimmon.seqMap(p1, p2, function(x1, x2) { return x2; }); +var parserB = Parsimmon.seqMap(p1, p2, function(x1, x2) { + return x2; +}); ``` ## parser.map(fn) Transforms the output of `parser` with the given function. Example: -```javascript -var pNum = - Parsimmon.regexp(/[0-9]+/) - .map(Number) - .map(function(x) { - return x + 1; - }); +```js +var pNum = Parsimmon.regexp(/[0-9]+/) + .map(Number) + .map(function(x) { + return x + 1; + }); -pNum.parse('9'); // => {status: true, value: 10} -pNum.parse('123'); // => {status: true, value: 124} -pNum.parse('3.1'); // => {status: true, value: 4.1} +pNum.parse("9"); // => {status: true, value: 10} +pNum.parse("123"); // => {status: true, value: 124} +pNum.parse("3.1"); // => {status: true, value: 4.1} ``` ## parser.contramap(fn) Transforms the input of `parser` with the given function. Example: -```javascript -var pNum = - Parsimmon.string('A') - .contramap(function(x) { - return x.toUpperCase(); - }); +```js +var pNum = Parsimmon.string("A").contramap(function(x) { + return x.toUpperCase(); +}); -pNum.parse('a'); // => {status: true, value: 'A'} -pNum.parse('A'); // => {status: true, value: 'A'} +pNum.parse("a"); // => {status: true, value: 'A'} +pNum.parse("A"); // => {status: true, value: 'A'} ``` -An important caveat of contramap is that it transforms the remaining input. This means that you cannot expect values after a contramap in general, like the following. -```javascript + +An important caveat of contramap is that it transforms the remaining input. This means that you cannot expect values after a contramap in general, like the following. + +```js Parsimmon.seq( - Parsimmon.string('a'), - Parsimmon.string('c').contramap(function(x) { + Parsimmon.string("a"), + Parsimmon.string("c").contramap(function(x) { return x.slice(1); }), - Parsimmon.string('d') -).tie().parse('abcd') //this will fail + Parsimmon.string("d") +) + .tie() + .parse("abcd"); //this will fail Parsimmon.seq( Parsimmon.string("a"), @@ -959,25 +947,29 @@ Parsimmon.seq( .contramap(function(x) { return x.slice(1); }) -).tie().parse('abcd') // => {status: true, value: 'acd'} +) + .tie() + .parse("abcd"); // => {status: true, value: 'acd'} ``` ## parser.promap(fn) Transforms the input and output of `parser` with the given functions. Example: -```javascript -var pNum = - Parsimmon.string('A') - .promap(function(x) { - return x.toUpperCase(); - }, function(x) { - return x.charCodeAt(0); - }); +```js +var pNum = Parsimmon.string("A").promap( + function(x) { + return x.toUpperCase(); + }, + function(x) { + return x.charCodeAt(0); + } +); -pNum.parse('a'); // => {status: true, value: 65} -pNum.parse('A'); // => {status: true, value: 65} +pNum.parse("a"); // => {status: true, value: 65} +pNum.parse("A"); // => {status: true, value: 65} ``` + The same caveat for contramap above applies to promap. ## parser.result(value) @@ -989,20 +981,21 @@ Returns a new parser with the same behavior, but which yields `value`. Equivalen Returns a new parser which tries `parser` and, if it fails, yields `value` without consuming any input. Equivalent to `parser.or(Parsimmon.of(value))`. ```js -var digitOrZero = Parsimmon.digit.fallback('0'); +var digitOrZero = Parsimmon.digit.fallback("0"); -digitOrZero.parse('4'); // => {status: true, value: '4'} -digitOrZero.parse(''); // => {status: true, value: '0'} +digitOrZero.parse("4"); // => {status: true, value: '4'} +digitOrZero.parse(""); // => {status: true, value: '0'} ``` ## parser.skip(otherParser) Expects `otherParser` after `parser`, but yields the value of `parser`. - -```javascript +```js var parserA = p1.skip(p2); // is equivalent to... -var parserB = Parsimmon.seqMap(p1, p2, function(x1, x2) { return x1; }); +var parserB = Parsimmon.seqMap(p1, p2, function(x1, x2) { + return x1; +}); ``` ## parser.trim(anotherParser) @@ -1015,30 +1008,26 @@ Example: Parsimmon.digits .map(Number) .trim(Parsimmon.optWhitespace) - .sepBy(Parsimmon.string(',')) - .tryParse(' 1, 2,3 , 4 ') + .sepBy(Parsimmon.string(",")) + .tryParse(" 1, 2,3 , 4 "); // => [1, 2, 3, 4] ``` It is equivalent to: ```js -anotherParser - .then(parser) - .skip(anotherParser) +anotherParser.then(parser).skip(anotherParser); ``` It is also equivalent to: ```js -Parsimmon.seqMap( - anotherParser, - parser, - anotherParser, - function(before, middle) { - return middle; - } -) +Parsimmon.seqMap(anotherParser, parser, anotherParser, function( + before, + middle +) { + return middle; +}); ``` ## parser.wrap(before, after) @@ -1050,30 +1039,23 @@ Example: ```js Parsimmon.letters .trim(Parsimmon.optWhitespace) - .wrap(Parsimmon.string('('), Parsimmon.string(')')) - .tryParse('( nice )') + .wrap(Parsimmon.string("("), Parsimmon.string(")")) + .tryParse("( nice )"); // => 'nice' ``` It is equivalent to: ```js -before - .then(parser) - .skip(after) +before.then(parser).skip(after); ``` It is also equivalent to: ```js -Parsimmon.seqMap( - before, - parser, - after, - function(before, middle) { - return middle; - } -) +Parsimmon.seqMap(before, parser, after, function(before, middle) { + return middle; +}); ``` ## parser.notFollowedBy(anotherParser) @@ -1097,15 +1079,11 @@ Returns a parser that wants the input to match `regexp`. Yields the same result Passes the result of `parser` to the function `condition`, which returns a boolean. If the the condition is false, returns a failed parse with the given `message`. Else is returns the original result of `parser`. ```js -var evenLengthNumber = - P.digits - .assert( - function(s) { - return s.length % 2 === 0; - }, - "even length number" - ) - .map(Number); +var evenLengthNumber = P.digits + .assert(function(s) { + return s.length % 2 === 0; + }, "even length number") + .map(Number); evenLengthNumber.parse("34"); // { status: true, value: 34 } @@ -1125,11 +1103,13 @@ Example: ```js var number = Parsimmon.seq( Parsimmon.digits, - Parsimmon.string('.'), + Parsimmon.string("."), Parsimmon.digits -).tieWith("").map(Number); +) + .tieWith("") + .map(Number); -number.tryParse('1.23'); +number.tryParse("1.23"); // => 1.23 ``` @@ -1151,7 +1131,7 @@ Note: `parser.tie()` is usually used after [`Parsimmon.seq(...parsers)`](#parsim Expects `parser` zero or more times, and yields an array of the results. -**NOTE:** If `parser` is capable of parsing an empty string (i.e. `parser.parse("")` succeeds) then [`parser.many()`](#parsermany) will throw an error. Otherwise [`parser.many()`](#parsermany) would get stuck in an infinite loop. +**NOTE:** If `parser` is capable of parsing an empty string (i.e. `parser.parse("")` succeeds) then [`parser.many()`](#parsermany) will throw an error. Otherwise [`parser.many()`](#parsermany) would get stuck in an infinite loop. ## parser.times(n) @@ -1176,11 +1156,10 @@ Yields an object with `name`, `value`, `start`, and `end` keys, where `value` is Example: -```javascript -var Identifier = - Parsimmon.regexp(/[a-z]+/).node('Identifier'); +```js +var Identifier = Parsimmon.regexp(/[a-z]+/).node("Identifier"); -Identifier.tryParse('hey'); +Identifier.tryParse("hey"); // => { name: 'Identifier', // value: 'hey', // start: { offset: 0, line: 1, column: 1 }, @@ -1191,11 +1170,10 @@ Identifier.tryParse('hey'); Yields an object with `start`, `value`, and `end` keys, where `value` is the original value yielded by the parser, and `start` and `end` are are objects with a 0-based `offset` and 1-based `line` and `column` properties that represent the position in the input that contained the parsed text. Works like this function: -```javascript -var Identifier = - Parsimmon.regexp(/[a-z]+/).mark(); +```js +var Identifier = Parsimmon.regexp(/[a-z]+/).mark(); -Identifier.tryParse('hey'); +Identifier.tryParse("hey"); // => { start: { offset: 0, line: 1, column: 1 }, // value: 'hey', // end: { offset: 3, line: 1, column: 4 } } @@ -1210,27 +1188,24 @@ Example: ```js function makeNode(name) { return function(parser) { - return Parsimmon.seqMap( - Parsimmon.index, - parser, - Parsimmon.index, - function(start, value, end) { - return Object.freeze({ - type: 'myLanguage.' + name, - value: value, - start: start, - end: end - }); - } - ); + return Parsimmon.seqMap(Parsimmon.index, parser, Parsimmon.index, function( + start, + value, + end + ) { + return Object.freeze({ + type: "myLanguage." + name, + value: value, + start: start, + end: end + }); + }); }; } -var Identifier = - Parsimmon.regexp(/[a-z]+/) - .thru(makeNode('Identifier')); +var Identifier = Parsimmon.regexp(/[a-z]+/).thru(makeNode("Identifier")); -Identifier.tryParse('hey'); +Identifier.tryParse("hey"); // => { type: 'myLanguage.Identifier', // value: 'hey', // start: { offset: 0, line: 1, column: 1 }, @@ -1240,41 +1215,38 @@ Identifier.tryParse('hey'); ## parser.desc(description) Returns a new parser whose failure message is `description`. For example, `string('x').desc('the letter x')` will indicate that -`'the letter x'` was expected. Alternatively, an array of failure messages can be passed, if the parser represents multiple -options. For example, `oneOf('abc').desc(['a', 'b', 'c'])` will indicate that any of 'a', 'b', or 'c' would be acceptable in +`'the letter x'` was expected. Alternatively, an array of failure messages can be passed, if the parser represents multiple +options. For example, `oneOf('abc').desc(['a', 'b', 'c'])` will indicate that any of 'a', 'b', or 'c' would be acceptable in this case. -It is important to only add descriptions to "low-level" parsers; things like numbers and strings. If you add a description to *every* parser you write then generated error messages will not be very helpful when simple syntax errors occur. +It is important to only add descriptions to "low-level" parsers; things like numbers and strings. If you add a description to _every_ parser you write then generated error messages will not be very helpful when simple syntax errors occur. -```javascript -var P = require('parsimmon'); +```js +var P = require("parsimmon"); -var pNumber = - P.regexp(/[0-9]+/).map(Number).desc('a number'); +var pNumber = P.regexp(/[0-9]+/) + .map(Number) + .desc("a number"); -var pPairNorm = - P.seq( - P.string('(').then(pNumber).skip(P.string(',')), - pNumber.skip(P.string(')')) - ); +var pPairNorm = P.seq( + P.string("(") + .then(pNumber) + .skip(P.string(",")), + pNumber.skip(P.string(")")) +); -var pPairDesc = - pPairNorm.desc('a pair'); +var pPairDesc = pPairNorm.desc("a pair"); -var badInputs = [ - '(1,2', - '1,2)', - '(1|2)', -]; +var badInputs = ["(1,2", "1,2)", "(1|2)"]; function report(name, parser, x) { - var expectations = parser.parse(x).expected.join(', '); - console.log(name + ' | Expected', expectations); + var expectations = parser.parse(x).expected.join(", "); + console.log(name + " | Expected", expectations); } badInputs.forEach(function(x) { - report('pPairNorm', pPairNorm, x); - report('pPairDesc', pPairDesc, x); + report("pPairNorm", pPairNorm, x); + report("pPairDesc", pPairDesc, x); }); ``` @@ -1309,12 +1281,10 @@ Equivalent to [`parser.or(otherParser)`](#parserorotherparser). Takes `parser` which returns a function and applies it to the parsed value of `otherParser`. -```javascript +```js Parsimmon.digit - .ap(Parsimmon.digit - .map(s => t => - Number(s) + Number(t))) - .parse("23"); + .ap(Parsimmon.digit.map(s => t => Number(s) + Number(t))) + .parse("23"); // => {status: true, value: 5} ``` @@ -1324,7 +1294,7 @@ Equivalent to `Parsimmon.sepBy(parser, separator)`. Expects zero or more matches for `parser`, separated by the parser `separator`, yielding an array. Example: -```javascript +```js Parsimmon.oneOf('abc') .sepBy(Parsimmon.string('|')) .parse('a|b|c|c|c|a'); @@ -1356,21 +1326,21 @@ Equivalent to [`Parsimmon.of(result)`](#parsimmonofresult). For the sake of readability in your own parsers, it's recommended to either create a shortcut for the Parsimmon library: -```javascript +```js var P = Parsimmon; var parser = P.digits.sepBy(P.whitespace); ``` Or to create shortcuts for the Parsimmon values you intend to use (when using Babel): -```javascript -import { digits, whitespace } from 'parsimmon'; +```js +import { digits, whitespace } from "parsimmon"; var parser = digits.sepBy(whitespace); ``` Because it can become quite wordy to repeat Parsimmon everywhere: -```javascript +```js var parser = Parsimmon.sepBy(Parsimmon.digits, Parsimmon.whitespace); ``` @@ -1378,29 +1348,30 @@ For clarity's sake, however, `Parsimmon` will refer to the Parsimmon library its ## Side effects -Do not perform [side effects](https://en.wikipedia.org/wiki/Side_effect_(computer_science)) parser actions. This is potentially unsafe, as Parsimmon will backtrack between parsers, but there's no way to undo your side effects. +Do not perform [side effects]() parser actions. This is potentially unsafe, as Parsimmon will backtrack between parsers, but there's no way to undo your side effects. Side effects include pushing to an array, modifying an object, `console.log`, reading data from outside sources (an array or object used to track things during parsing), or any random numbers. -Parsimmon expects that parsers and all [`.map`](#parsermapfn) statements do not perform side effects (i.e. they are *pure*). +Parsimmon expects that parsers and all [`.map`](#parsermapfn) statements do not perform side effects (i.e. they are _pure_). In this example, the parser `pVariable` is called twice on the same text because of [`Parsimmon.alt`](#parsimmonaltp1-p2-pn) backtracking, and has a side effect (pushing to an array) inside its [`.map`](#parsermapfn) method, so we get two items in the array instead of just one. ```js var x = 0; var variableNames = []; -var pVariable = - Parsimmon.regexp(/[a-z]+/i) - .map(function(name) { - variableNames.push(name); - return name; - }); -var pDeclaration = - Parsimmon.alt( - Parsimmon.string('var ').then(pVariable).then(Parsimmon.string('\n')), - Parsimmon.string('var ').then(pVariable).then(Parsimmon.string(';')) - ); -pDeclaration.parse('var gummyBear;'); +var pVariable = Parsimmon.regexp(/[a-z]+/i).map(function(name) { + variableNames.push(name); + return name; +}); +var pDeclaration = Parsimmon.alt( + Parsimmon.string("var ") + .then(pVariable) + .then(Parsimmon.string("\n")), + Parsimmon.string("var ") + .then(pVariable) + .then(Parsimmon.string(";")) +); +pDeclaration.parse("var gummyBear;"); console.log(variableNames); // => ['gummyBear', 'gummyBear'] ``` diff --git a/GUIDE.md b/GUIDE.md index 39963c2..0557d64 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -74,7 +74,9 @@ Only fail a parse if the rest of the document couldn't possibly make sense. const fastWhitespace = Parsimmon.regexp(/[ \t\r\n]*/); // Slow! Have to examine one character at a time and make an array -const slowWhitespace = Parsimmon.oneOf(" \t\r\n").many().tie(); +const slowWhitespace = Parsimmon.oneOf(" \t\r\n") + .many() + .tie(); ``` ## Negative constructions diff --git a/README.md b/README.md index 81e6e8c..35b16dc 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Parsimmon supports IE7 and newer browsers, along with [Node.js][]. It can be use ## Code of Conduct -Everyone is expected to abide by the [Contributor Covenant](CODE_OF_CONDUCT.md). Please send reports to . +Everyone is expected to abide by the [Contributor Covenant](CODE_OF_CONDUCT.md). Please send reports to .