diff --git a/src/parsimmon.js b/src/parsimmon.js index cc0d766..12ae071 100644 --- a/src/parsimmon.js +++ b/src/parsimmon.js @@ -97,6 +97,15 @@ function bufferExists() { return typeof Buffer !== "undefined"; } +function setExists() { + if (Parsimmon._supportsSet !== undefined) { + return Parsimmon._supportsSet; + } + var exists = typeof Set !== "undefined"; + Parsimmon._supportsSet = exists; + return exists; +} + function ensureBuffer() { if (!bufferExists()) { throw new Error( @@ -388,6 +397,18 @@ function makeLineColumnIndex(input, i) { // Returns the sorted set union of two arrays of strings function union(xs, ys) { + // for newer browsers/node we can improve performance by using + // modern JS + if (setExists() && Array.from) { + // eslint-disable-next-line no-undef + var set = new Set(xs); + for (var y = 0; y < ys.length; y++) { + set.add(ys[y]); + } + var arr = Array.from(set); + arr.sort(); + return arr; + } var obj = {}; for (var i = 0; i < xs.length; i++) { obj[xs[i]] = true; diff --git a/test/.eslintrc b/test/.eslintrc index 7b7df31..4c7229e 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -5,6 +5,7 @@ }, "globals":{ "Parsimmon": true, - "assert": true + "assert": true, + "testSetScenario": true } } diff --git a/test/core/alt.test.js b/test/core/alt.test.js index 7bf90a2..5a4e3bf 100644 --- a/test/core/alt.test.js +++ b/test/core/alt.test.js @@ -1,37 +1,39 @@ "use strict"; -it("Parsimmon.alt", function() { - var toNode = function(nodeType) { - return function(value) { - return { type: nodeType, value: value }; +testSetScenario(function() { + it("Parsimmon.alt", function() { + var toNode = function(nodeType) { + return function(value) { + return { type: nodeType, value: value }; + }; }; - }; - var stringParser = Parsimmon.seq( - Parsimmon.string('"'), - Parsimmon.regexp(/[^"]*/), - Parsimmon.string('"') - ).map(toNode("string")); + var stringParser = Parsimmon.seq( + Parsimmon.string('"'), + Parsimmon.regexp(/[^"]*/), + Parsimmon.string('"') + ).map(toNode("string")); - var identifierParser = Parsimmon.regexp(/[a-zA-Z]*/).map( - toNode("identifier") - ); + var identifierParser = Parsimmon.regexp(/[a-zA-Z]*/).map( + toNode("identifier") + ); - var parser = Parsimmon.alt(stringParser, identifierParser); + var parser = Parsimmon.alt(stringParser, identifierParser); - assert.deepEqual(parser.parse('"a string, to be sure"').value, { - type: "string", - value: ['"', "a string, to be sure", '"'] - }); + assert.deepEqual(parser.parse('"a string, to be sure"').value, { + type: "string", + value: ['"', "a string, to be sure", '"'] + }); - assert.deepEqual(parser.parse("anIdentifier").value, { - type: "identifier", - value: "anIdentifier" - }); + assert.deepEqual(parser.parse("anIdentifier").value, { + type: "identifier", + value: "anIdentifier" + }); - assert.throws(function() { - Parsimmon.alt("not a parser"); - }); + assert.throws(function() { + Parsimmon.alt("not a parser"); + }); - assert.strictEqual(Parsimmon.alt().parse("").status, false); + assert.strictEqual(Parsimmon.alt().parse("").status, false); + }); }); diff --git a/test/core/chain.test.js b/test/core/chain.test.js index 69b06a3..d7655f9 100644 --- a/test/core/chain.test.js +++ b/test/core/chain.test.js @@ -1,28 +1,30 @@ "use strict"; -describe("chain", function() { - it("asserts that a parser is returned", function() { - var parser1 = Parsimmon.letter.chain(function() { - return "not a parser"; - }); - assert.throws(function() { - parser1.parse("x"); - }); +testSetScenario(function() { + describe("chain", function() { + it("asserts that a parser is returned", function() { + var parser1 = Parsimmon.letter.chain(function() { + return "not a parser"; + }); + assert.throws(function() { + parser1.parse("x"); + }); - assert.throws(function() { - Parsimmon.letter.then("x"); + assert.throws(function() { + Parsimmon.letter.then("x"); + }); }); - }); - it("with a function that returns a parser, continues with that parser", function() { - var piped; - var parser = Parsimmon.string("x").chain(function(x) { - piped = x; - return Parsimmon.string("y"); - }); + it("with a function that returns a parser, continues with that parser", function() { + var piped; + var parser = Parsimmon.string("x").chain(function(x) { + piped = x; + return Parsimmon.string("y"); + }); - assert.deepEqual(parser.parse("xy"), { status: true, value: "y" }); - assert.equal(piped, "x"); - assert.ok(!parser.parse("x").status); + assert.deepEqual(parser.parse("xy"), { status: true, value: "y" }); + assert.equal(piped, "x"); + assert.ok(!parser.parse("x").status); + }); }); }); diff --git a/test/core/createLanguage.test.js b/test/core/createLanguage.test.js index a083744..fe9a7d0 100644 --- a/test/core/createLanguage.test.js +++ b/test/core/createLanguage.test.js @@ -1,71 +1,73 @@ "use strict"; -describe("Parsimmon.createLanguage", function() { - before(function() { - Object.prototype.NASTY = "dont extend Object.prototype please"; - }); +testSetScenario(function() { + describe("Parsimmon.createLanguage", function() { + before(function() { + Object.prototype.NASTY = "dont extend Object.prototype please"; + }); - after(function() { - delete Object.prototype.NASTY; - }); + after(function() { + delete Object.prototype.NASTY; + }); - it("should return an object of parsers", function() { - var lang = Parsimmon.createLanguage({ - a: function() { - return Parsimmon.string("a"); - }, - b: function() { - return Parsimmon.string("b"); - } + it("should return an object of parsers", function() { + var lang = Parsimmon.createLanguage({ + a: function() { + return Parsimmon.string("a"); + }, + b: function() { + return Parsimmon.string("b"); + } + }); + assert.ok(Parsimmon.isParser(lang.a)); + assert.ok(Parsimmon.isParser(lang.b)); }); - assert.ok(Parsimmon.isParser(lang.a)); - assert.ok(Parsimmon.isParser(lang.b)); - }); - it("should allow direct recursion in parsers", function() { - var lang = Parsimmon.createLanguage({ - Parentheses: function(r) { - return Parsimmon.alt( - Parsimmon.string("()"), - Parsimmon.string("(") - .then(r.Parentheses) - .skip(Parsimmon.string(")")) - ); - } + it("should allow direct recursion in parsers", function() { + var lang = Parsimmon.createLanguage({ + Parentheses: function(r) { + return Parsimmon.alt( + Parsimmon.string("()"), + Parsimmon.string("(") + .then(r.Parentheses) + .skip(Parsimmon.string(")")) + ); + } + }); + lang.Parentheses.tryParse("(((())))"); }); - lang.Parentheses.tryParse("(((())))"); - }); - it("should ignore non-own properties", function() { - var obj = Object.create({ - foo: function() { - return Parsimmon.of(1); - } + it("should ignore non-own properties", function() { + var obj = Object.create({ + foo: function() { + return Parsimmon.of(1); + } + }); + var lang = Parsimmon.createLanguage(obj); + assert.strictEqual(lang.foo, undefined); }); - var lang = Parsimmon.createLanguage(obj); - assert.strictEqual(lang.foo, undefined); - }); - it("should allow indirect recursion in parsers", function() { - var lang = Parsimmon.createLanguage({ - Value: function(r) { - return Parsimmon.alt(r.Number, r.Symbol, r.List); - }, - Number: function() { - return Parsimmon.regexp(/[0-9]+/).map(Number); - }, - Symbol: function() { - return Parsimmon.regexp(/[a-z]+/); - }, - List: function(r) { - return Parsimmon.string("(") - .then(Parsimmon.sepBy(r.Value, r._)) - .skip(Parsimmon.string(")")); - }, - _: function() { - return Parsimmon.optWhitespace; - } + it("should allow indirect recursion in parsers", function() { + var lang = Parsimmon.createLanguage({ + Value: function(r) { + return Parsimmon.alt(r.Number, r.Symbol, r.List); + }, + Number: function() { + return Parsimmon.regexp(/[0-9]+/).map(Number); + }, + Symbol: function() { + return Parsimmon.regexp(/[a-z]+/); + }, + List: function(r) { + return Parsimmon.string("(") + .then(Parsimmon.sepBy(r.Value, r._)) + .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))"); }); }); diff --git a/test/core/many.test.js b/test/core/many.test.js index 2964768..1f502f8 100644 --- a/test/core/many.test.js +++ b/test/core/many.test.js @@ -1,34 +1,36 @@ "use strict"; -describe("many", function() { - it("simple case", function() { - var letters = Parsimmon.letter.many(); - 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); - }); - - it("followed by then", function() { - var parser = Parsimmon.string("x") - .many() - .then(Parsimmon.string("y")); - assert.equal(parser.parse("y").value, "y"); - assert.equal(parser.parse("xy").value, "y"); - assert.equal(parser.parse("xxxxxy").value, "y"); - }); - - it("throws on parsers that accept zero characters", function() { - var parser = Parsimmon.regexp(/a*/).many(); - assert.throws(function() { - parser.parse("a"); +testSetScenario(function() { + describe("many", function() { + it("simple case", function() { + var letters = Parsimmon.letter.many(); + 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); }); - assert.throws(function() { - parser.parse("b"); + + it("followed by then", function() { + var parser = Parsimmon.string("x") + .many() + .then(Parsimmon.string("y")); + assert.equal(parser.parse("y").value, "y"); + assert.equal(parser.parse("xy").value, "y"); + assert.equal(parser.parse("xxxxxy").value, "y"); }); - assert.throws(function() { - parser.parse(""); + + it("throws on parsers that accept zero characters", function() { + var parser = Parsimmon.regexp(/a*/).many(); + assert.throws(function() { + parser.parse("a"); + }); + assert.throws(function() { + parser.parse("b"); + }); + assert.throws(function() { + parser.parse(""); + }); }); }); }); diff --git a/test/core/map.test.js b/test/core/map.test.js index ab13fcd..ec8f4d2 100644 --- a/test/core/map.test.js +++ b/test/core/map.test.js @@ -1,19 +1,21 @@ "use strict"; -describe("map", function() { - it("with a function, pipes the value in and uses that return value", function() { - var piped; - var parser = Parsimmon.string("x").map(function(x) { - piped = x; - return "y"; +testSetScenario(function() { + describe("map", function() { + it("with a function, pipes the value in and uses that return value", function() { + var piped; + var parser = Parsimmon.string("x").map(function(x) { + piped = x; + return "y"; + }); + assert.deepEqual(parser.parse("x"), { status: true, value: "y" }); + assert.equal(piped, "x"); }); - assert.deepEqual(parser.parse("x"), { status: true, value: "y" }); - assert.equal(piped, "x"); - }); - it("asserts that a function was given", function() { - assert.throws(function() { - Parsimmon.string("x").map("not a function"); + it("asserts that a function was given", function() { + assert.throws(function() { + Parsimmon.string("x").map("not a function"); + }); }); }); }); diff --git a/test/core/misc.test.js b/test/core/misc.test.js index e745152..2aa7f1a 100644 --- a/test/core/misc.test.js +++ b/test/core/misc.test.js @@ -55,91 +55,93 @@ var whitespaces = whitespace.concat([ " \t \t " ]); -describe("(misc)", function() { - describe("Parsimmon.end", function() { - var newlineSequences = ["\n", "\r", "\r\n"]; +testSetScenario(function() { + describe("(misc)", function() { + describe("Parsimmon.end", function() { + var newlineSequences = ["\n", "\r", "\r\n"]; - it("should parse a newline", function() { - newlineSequences.forEach(function(c) { - assert.strictEqual(Parsimmon.end.tryParse(c), c); + it("should parse a newline", function() { + newlineSequences.forEach(function(c) { + assert.strictEqual(Parsimmon.end.tryParse(c), c); + }); + assert.strictEqual(Parsimmon.end.tryParse(""), null); }); - assert.strictEqual(Parsimmon.end.tryParse(""), null); - }); - it("should not parse the letter A", function() { - assert.deepStrictEqual(Parsimmon.end.parse("A"), { - status: false, - index: { offset: 0, line: 1, column: 1 }, - expected: ["EOF", "newline"] + it("should not parse the letter A", function() { + assert.deepStrictEqual(Parsimmon.end.parse("A"), { + status: false, + index: { offset: 0, line: 1, column: 1 }, + expected: ["EOF", "newline"] + }); }); }); - }); - ezTest({ - name: "Parsimmon.cr", - parser: Parsimmon.cr, - good: ["\r"], - bad: ["\n", "\r\n", ""] - }); + ezTest({ + name: "Parsimmon.cr", + parser: Parsimmon.cr, + good: ["\r"], + bad: ["\n", "\r\n", ""] + }); - ezTest({ - name: "Parsimmon.lf", - parser: Parsimmon.lf, - good: ["\n"], - bad: ["\r", "\r\n", ""] - }); + ezTest({ + name: "Parsimmon.lf", + parser: Parsimmon.lf, + good: ["\n"], + bad: ["\r", "\r\n", ""] + }); - ezTest({ - name: "Parsimmon.crlf", - parser: Parsimmon.crlf, - good: ["\r\n"], - bad: ["\r", "\n", ""] - }); + ezTest({ + name: "Parsimmon.crlf", + parser: Parsimmon.crlf, + good: ["\r\n"], + bad: ["\r", "\n", ""] + }); - describe("Parsimmon.digit", function() { - it("should parse exactly one 0-9 character", function() { - assert.strictEqual(Parsimmon.digit.tryParse("4"), "4"); + describe("Parsimmon.digit", function() { + it("should parse exactly one 0-9 character", function() { + assert.strictEqual(Parsimmon.digit.tryParse("4"), "4"); + }); + }); + ezTest({ + name: "Parsimmon.digit", + parser: Parsimmon.digit, + good: "0 1 2 3 4 5 6 7 8 9".split(" "), + bad: ["a", "", "-"] }); - }); - ezTest({ - name: "Parsimmon.digit", - parser: Parsimmon.digit, - good: "0 1 2 3 4 5 6 7 8 9".split(" "), - bad: ["a", "", "-"] - }); - ezTest({ - name: "Parsimmon.digits", - parser: Parsimmon.digits, - good: ["", "007", "420", "69", "1337", "666"], - bad: ["a", "-", "1 2 3 4", "-4", "0xcafe"] - }); + ezTest({ + name: "Parsimmon.digits", + parser: Parsimmon.digits, + good: ["", "007", "420", "69", "1337", "666"], + bad: ["a", "-", "1 2 3 4", "-4", "0xcafe"] + }); - ezTest({ - name: "Parsimmon.letter", - parser: Parsimmon.letter, - good: "a b Z c d e A G h z".split(" "), - bad: ["9", ".", "-", ""] - }); + ezTest({ + name: "Parsimmon.letter", + parser: Parsimmon.letter, + good: "a b Z c d e A G h z".split(" "), + bad: ["9", ".", "-", ""] + }); - ezTest({ - name: "Parsimmon.letters", - parser: Parsimmon.letters, - good: [""].concat("aAa bbbB Zzzz cc d e A G h z".split(" ")), - bad: ["9", ".", "-"] - }); + ezTest({ + name: "Parsimmon.letters", + parser: Parsimmon.letters, + good: [""].concat("aAa bbbB Zzzz cc d e A G h z".split(" ")), + bad: ["9", ".", "-"] + }); - ezTest({ - name: "Parsimmon.optWhitespace", - parser: Parsimmon.optWhitespace, - good: [""].concat(whitespace), - bad: ["a", "-", "1 2 3 4", "-4", "0xcafe"] - }); + ezTest({ + name: "Parsimmon.optWhitespace", + parser: Parsimmon.optWhitespace, + good: [""].concat(whitespace), + bad: ["a", "-", "1 2 3 4", "-4", "0xcafe"] + }); - ezTest({ - name: "Parsimmon.whitespace", - parser: Parsimmon.whitespace, - good: whitespaces, - bad: ["a", "", "-", "1 2 3 4", "-4", "0xcafe"] + ezTest({ + name: "Parsimmon.whitespace", + parser: Parsimmon.whitespace, + good: whitespaces, + bad: ["a", "", "-", "1 2 3 4", "-4", "0xcafe"] + }); }); }); diff --git a/test/core/seq.test.js b/test/core/seq.test.js index 719bdc9..e3b5258 100644 --- a/test/core/seq.test.js +++ b/test/core/seq.test.js @@ -1,43 +1,45 @@ "use strict"; -it("Parsimmon.seq", function() { - var parser = Parsimmon.seq( - Parsimmon.string("("), - Parsimmon.regexp(/[^)]/) - .many() - .map(function(xs) { - return xs.join(""); - }), - Parsimmon.string(")") - ); +testSetScenario(function() { + it("Parsimmon.seq", function() { + var parser = Parsimmon.seq( + Parsimmon.string("("), + Parsimmon.regexp(/[^)]/) + .many() + .map(function(xs) { + return xs.join(""); + }), + Parsimmon.string(")") + ); - assert.deepEqual(parser.parse("(string between parens)").value, [ - "(", - "string between parens", - ")" - ]); + assert.deepEqual(parser.parse("(string between parens)").value, [ + "(", + "string between parens", + ")" + ]); - assert.deepEqual(parser.parse("(string"), { - status: false, - index: { - offset: 7, - line: 1, - column: 8 - }, - expected: ["')'", "/[^)]/"] - }); + assert.deepEqual(parser.parse("(string"), { + status: false, + index: { + offset: 7, + line: 1, + column: 8 + }, + expected: ["')'", "/[^)]/"] + }); - assert.deepEqual(parser.parse("starts wrong (string between parens)"), { - status: false, - index: { - offset: 0, - line: 1, - column: 1 - }, - expected: ["'('"] - }); + assert.deepEqual(parser.parse("starts wrong (string between parens)"), { + status: false, + index: { + offset: 0, + line: 1, + column: 1 + }, + expected: ["'('"] + }); - assert.throws(function() { - Parsimmon.seq("not a parser"); + assert.throws(function() { + Parsimmon.seq("not a parser"); + }); }); }); diff --git a/test/core/seqObj.test.js b/test/core/seqObj.test.js index 5d76f99..2c0463c 100644 --- a/test/core/seqObj.test.js +++ b/test/core/seqObj.test.js @@ -1,84 +1,86 @@ "use strict"; -describe("Parsimmon.seqObj", function() { - it("does not accept duplicate keys", function() { - assert.throws(function() { - Parsimmon.seqObj( - ["a", Parsimmon.of(1)], - ["b", Parsimmon.of(2)], - ["a", Parsimmon.of(3)] - ); +testSetScenario(function() { + describe("Parsimmon.seqObj", function() { + it("does not accept duplicate keys", function() { + assert.throws(function() { + Parsimmon.seqObj( + ["a", Parsimmon.of(1)], + ["b", Parsimmon.of(2)], + ["a", Parsimmon.of(3)] + ); + }); }); - }); - it("requires at least one key", function() { - assert.throws(function() { - Parsimmon.seqObj(); + it("requires at least one key", function() { + assert.throws(function() { + Parsimmon.seqObj(); + }); }); - }); - it("every key is present in the result object", function() { - var parser = Parsimmon.seqObj( - ["a", Parsimmon.of(1)], - ["b", Parsimmon.of(2)], - ["c", Parsimmon.of(3)] - ); - var result = parser.tryParse(""); - assert.deepStrictEqual(result, { - a: 1, - b: 2, - c: 3 + it("every key is present in the result object", function() { + var parser = Parsimmon.seqObj( + ["a", Parsimmon.of(1)], + ["b", Parsimmon.of(2)], + ["c", Parsimmon.of(3)] + ); + var result = parser.tryParse(""); + assert.deepStrictEqual(result, { + a: 1, + b: 2, + c: 3 + }); }); - }); - - it("every parser is used", function() { - var parser = Parsimmon.seqObj( - ["a", Parsimmon.of(1)], - ["b", Parsimmon.of(2)], - ["c", Parsimmon.fail("oopsy")] - ); - var result = parser.parse(""); - assert.strictEqual(result.status, false); - }); - it("every parser is used", function() { - var parser = Parsimmon.seqObj( - Parsimmon.string("a"), - ["b", Parsimmon.string("b")], - Parsimmon.string("c"), - ["d", Parsimmon.string("d")], - Parsimmon.string("e") - ); - var result = parser.tryParse("abcde"); - assert.deepStrictEqual(result, { - b: "b", - d: "d" + it("every parser is used", function() { + var parser = Parsimmon.seqObj( + ["a", Parsimmon.of(1)], + ["b", Parsimmon.of(2)], + ["c", Parsimmon.fail("oopsy")] + ); + var result = parser.parse(""); + assert.strictEqual(result.status, false); }); - }); - it("named parser arrays are formed properly", function() { - assert.throws(function() { - Parsimmon.seqObj([]); - }); - assert.throws(function() { - Parsimmon.seqObj(["a", Parsimmon.of(1), "oops extra"]); - }); - assert.throws(function() { - Parsimmon.seqObj([123, Parsimmon.of(1)]); - }); - assert.throws(function() { - Parsimmon.seqObj(["cool", "potato"]); + it("every parser is used", function() { + var parser = Parsimmon.seqObj( + Parsimmon.string("a"), + ["b", Parsimmon.string("b")], + Parsimmon.string("c"), + ["d", Parsimmon.string("d")], + Parsimmon.string("e") + ); + var result = parser.tryParse("abcde"); + assert.deepStrictEqual(result, { + b: "b", + d: "d" + }); }); - assert.throws(function() { - Parsimmon.seqObj(0); + + it("named parser arrays are formed properly", function() { + assert.throws(function() { + Parsimmon.seqObj([]); + }); + assert.throws(function() { + Parsimmon.seqObj(["a", Parsimmon.of(1), "oops extra"]); + }); + assert.throws(function() { + Parsimmon.seqObj([123, Parsimmon.of(1)]); + }); + assert.throws(function() { + Parsimmon.seqObj(["cool", "potato"]); + }); + assert.throws(function() { + Parsimmon.seqObj(0); + }); }); - }); - it("accepts 'constructor' as a key", function() { - var parser = Parsimmon.seqObj(["constructor", Parsimmon.of(1)]); - var result = parser.tryParse(""); - assert.deepStrictEqual(result, { - constructor: 1 + it("accepts 'constructor' as a key", function() { + var parser = Parsimmon.seqObj(["constructor", Parsimmon.of(1)]); + var result = parser.tryParse(""); + assert.deepStrictEqual(result, { + constructor: 1 + }); }); }); }); diff --git a/test/core/skip.test.js b/test/core/skip.test.js index 8d767f9..288be8c 100644 --- a/test/core/skip.test.js +++ b/test/core/skip.test.js @@ -1,15 +1,17 @@ "use strict"; -describe("skip", function() { - it("uses the previous return value", function() { - var parser = Parsimmon.string("x").skip(Parsimmon.string("y")); - assert.deepStrictEqual(parser.parse("xy"), { status: true, value: "x" }); - assert.strictEqual(parser.parse("x").status, false); - }); +testSetScenario(function() { + describe("skip", function() { + it("uses the previous return value", function() { + var parser = Parsimmon.string("x").skip(Parsimmon.string("y")); + assert.deepStrictEqual(parser.parse("xy"), { status: true, value: "x" }); + assert.strictEqual(parser.parse("x").status, false); + }); - it("asserts that a parser was given", function() { - assert.throws(function() { - Parsimmon.string("x").skip("not a parser"); + it("asserts that a parser was given", function() { + assert.throws(function() { + Parsimmon.string("x").skip("not a parser"); + }); }); }); }); diff --git a/test/core/then.test.js b/test/core/then.test.js index db7bc2b..0e8c62c 100644 --- a/test/core/then.test.js +++ b/test/core/then.test.js @@ -1,32 +1,34 @@ "use strict"; -describe(".then", function() { - it("with a parser, uses the last return value", function() { - var parser = Parsimmon.string("x").then(Parsimmon.string("y")); - assert.deepEqual(parser.parse("xy"), { status: true, value: "y" }); - assert.deepEqual(parser.parse("y"), { - status: false, - expected: ["'x'"], - index: { - offset: 0, - line: 1, - column: 1 - } +testSetScenario(function() { + describe(".then", function() { + it("with a parser, uses the last return value", function() { + var parser = Parsimmon.string("x").then(Parsimmon.string("y")); + assert.deepEqual(parser.parse("xy"), { status: true, value: "y" }); + assert.deepEqual(parser.parse("y"), { + status: false, + expected: ["'x'"], + index: { + offset: 0, + line: 1, + column: 1 + } + }); + assert.deepEqual(parser.parse("xz"), { + status: false, + expected: ["'y'"], + index: { + offset: 1, + line: 1, + column: 2 + } + }); }); - assert.deepEqual(parser.parse("xz"), { - status: false, - expected: ["'y'"], - index: { - offset: 1, - line: 1, - column: 2 - } - }); - }); - it("errors when argument is not a parser", function() { - assert.throws(function() { - Parsimmon.string("x").then("not a parser"); + it("errors when argument is not a parser", function() { + assert.throws(function() { + Parsimmon.string("x").then("not a parser"); + }); }); }); }); diff --git a/test/core/tie.test.js b/test/core/tie.test.js index 934e7ec..3068554 100644 --- a/test/core/tie.test.js +++ b/test/core/tie.test.js @@ -1,38 +1,40 @@ "use strict"; -describe("parser.tie()", function() { - it("concatenates all the results", function() { - var parser = Parsimmon.seq( - Parsimmon.string("<| "), - Parsimmon.letter, - Parsimmon.digit, - Parsimmon.string(" |>") - ).tie(); - var text = "<| o7 |>"; - var result = parser.tryParse(text); - assert.strictEqual(result, text); - }); - - it("only accept array of string parsers", function() { - assert.throws(function() { - Parsimmon.of(1) - .tie() - .tryParse(""); - }); - assert.throws(function() { - Parsimmon.of([1]) - .tie() - .tryParse(""); +testSetScenario(function() { + describe("parser.tie()", function() { + it("concatenates all the results", function() { + var parser = Parsimmon.seq( + Parsimmon.string("<| "), + Parsimmon.letter, + Parsimmon.digit, + Parsimmon.string(" |>") + ).tie(); + var text = "<| o7 |>"; + var result = parser.tryParse(text); + assert.strictEqual(result, text); }); - assert.throws(function() { - Parsimmon.of(["1", 2]) - .tie() - .tryParse(""); - }); - assert.doesNotThrow(function() { - Parsimmon.of(["1"]) - .tie() - .tryParse(""); + + it("only accept array of string parsers", function() { + assert.throws(function() { + Parsimmon.of(1) + .tie() + .tryParse(""); + }); + assert.throws(function() { + Parsimmon.of([1]) + .tie() + .tryParse(""); + }); + assert.throws(function() { + Parsimmon.of(["1", 2]) + .tie() + .tryParse(""); + }); + assert.doesNotThrow(function() { + Parsimmon.of(["1"]) + .tie() + .tryParse(""); + }); }); }); }); diff --git a/test/core/tieWith.test.js b/test/core/tieWith.test.js index 4f70d75..484b92e 100644 --- a/test/core/tieWith.test.js +++ b/test/core/tieWith.test.js @@ -1,44 +1,46 @@ "use strict"; -describe("parser.tieWith()", function() { - it("handles empty args", function() { - var parser = Parsimmon.of([]).tieWith(""); - var result = parser.tryParse(""); - assert.strictEqual(result, ""); - }); - - it("concatenates all the results", function() { - var parser = Parsimmon.seq( - Parsimmon.string("<| "), - Parsimmon.letter, - Parsimmon.digit, - Parsimmon.string(" |>") - ).tieWith("+"); - var text = "<| o7 |>"; - var result = parser.tryParse(text); - assert.strictEqual(result, "<| +o+7+ |>"); - }); - - it("only accept array of string parsers", function() { - assert.throws(function() { - Parsimmon.of(1) - .tieWith("") - .tryParse(""); +testSetScenario(function() { + describe("parser.tieWith()", function() { + it("handles empty args", function() { + var parser = Parsimmon.of([]).tieWith(""); + var result = parser.tryParse(""); + assert.strictEqual(result, ""); }); - assert.throws(function() { - Parsimmon.of([1]) - .tieWith("") - .tryParse(""); - }); - assert.throws(function() { - Parsimmon.of(["1", 2]) - .tieWith("") - .tryParse(""); + + it("concatenates all the results", function() { + var parser = Parsimmon.seq( + Parsimmon.string("<| "), + Parsimmon.letter, + Parsimmon.digit, + Parsimmon.string(" |>") + ).tieWith("+"); + var text = "<| o7 |>"; + var result = parser.tryParse(text); + assert.strictEqual(result, "<| +o+7+ |>"); }); - assert.doesNotThrow(function() { - Parsimmon.of(["1"]) - .tieWith("") - .tryParse(""); + + it("only accept array of string parsers", function() { + assert.throws(function() { + Parsimmon.of(1) + .tieWith("") + .tryParse(""); + }); + assert.throws(function() { + Parsimmon.of([1]) + .tieWith("") + .tryParse(""); + }); + assert.throws(function() { + Parsimmon.of(["1", 2]) + .tieWith("") + .tryParse(""); + }); + assert.doesNotThrow(function() { + Parsimmon.of(["1"]) + .tieWith("") + .tryParse(""); + }); }); }); }); diff --git a/test/core/times.test.js b/test/core/times.test.js index 2b5cb5f..8762c3e 100644 --- a/test/core/times.test.js +++ b/test/core/times.test.js @@ -1,80 +1,82 @@ "use strict"; -describe("times", function() { - it("zero case", function() { - var zeroLetters = Parsimmon.letter.times(0); - assert.deepEqual(zeroLetters.parse("").value, []); - assert.ok(!zeroLetters.parse("x").status); - }); - - it("nonzero case", function() { - var threeLetters = Parsimmon.letter.times(3); - 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(Parsimmon.digit); - 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); - }); - - it("with a min and max", function() { - var someLetters = Parsimmon.letter.times(2, 4); - 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(Parsimmon.digit); - 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); - }); - - it("checks that argument types are correct", function() { - assert.throws(function() { - Parsimmon.string("x").times("not a number"); +testSetScenario(function() { + describe("times", function() { + it("zero case", function() { + var zeroLetters = Parsimmon.letter.times(0); + assert.deepEqual(zeroLetters.parse("").value, []); + assert.ok(!zeroLetters.parse("x").status); }); - assert.throws(function() { - Parsimmon.string("x").times(1, "not a number"); + + it("nonzero case", function() { + var threeLetters = Parsimmon.letter.times(3); + 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(Parsimmon.digit); + 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); }); - assert.throws(function() { - Parsimmon.string("x").atLeast("not a number"); + + it("with a min and max", function() { + var someLetters = Parsimmon.letter.times(2, 4); + 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(Parsimmon.digit); + 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); }); - assert.throws(function() { - Parsimmon.string("x").atMost("not a number"); + + it("checks that argument types are correct", function() { + assert.throws(function() { + Parsimmon.string("x").times("not a number"); + }); + assert.throws(function() { + Parsimmon.string("x").times(1, "not a number"); + }); + assert.throws(function() { + Parsimmon.string("x").atLeast("not a number"); + }); + assert.throws(function() { + Parsimmon.string("x").atMost("not a number"); + }); }); - }); - it("prefer longest branch in .times() too", function() { - var parser = Parsimmon.string("abc") - .then(Parsimmon.string("def")) - .or(Parsimmon.string("a")) - .times(3, 6); + it("prefer longest branch in .times() too", function() { + var parser = Parsimmon.string("abc") + .then(Parsimmon.string("def")) + .or(Parsimmon.string("a")) + .times(3, 6); - assert.deepEqual(parser.parse("aabcde"), { - status: false, - index: { - offset: 4, - line: 1, - column: 5 - }, - expected: ["'def'"] - }); + assert.deepEqual(parser.parse("aabcde"), { + status: false, + index: { + offset: 4, + line: 1, + column: 5 + }, + expected: ["'def'"] + }); - assert.deepEqual(parser.parse("aaaaabcde"), { - status: false, - index: { - offset: 7, - line: 1, - column: 8 - }, - expected: ["'def'"] + assert.deepEqual(parser.parse("aaaaabcde"), { + status: false, + index: { + offset: 7, + line: 1, + column: 8 + }, + expected: ["'def'"] + }); }); }); }); diff --git a/test/core/trim.test.js b/test/core/trim.test.js index 92f965f..1726ca2 100644 --- a/test/core/trim.test.js +++ b/test/core/trim.test.js @@ -1,9 +1,11 @@ "use strict"; -describe("parser.trim", function() { - it("should remove stuff from the begin and end", function() { - var parser = Parsimmon.letters.trim(Parsimmon.whitespace); - var value = parser.tryParse("\t\n NICE \t\t "); - assert.strictEqual(value, "NICE"); +testSetScenario(function() { + describe("parser.trim", function() { + it("should remove stuff from the begin and end", function() { + var parser = Parsimmon.letters.trim(Parsimmon.whitespace); + var value = parser.tryParse("\t\n NICE \t\t "); + assert.strictEqual(value, "NICE"); + }); }); }); diff --git a/test/core/tryParse.test.js b/test/core/tryParse.test.js index d58429a..73b6268 100644 --- a/test/core/tryParse.test.js +++ b/test/core/tryParse.test.js @@ -1,47 +1,49 @@ "use strict"; -describe(".tryParse", function() { - it("returns just the value", function() { - var x = 4; - assert.equal(Parsimmon.of(x).tryParse(""), x); - }); +testSetScenario(function() { + describe(".tryParse", function() { + it("returns just the value", function() { + var x = 4; + assert.equal(Parsimmon.of(x).tryParse(""), x); + }); - it("returns throws on a bad parse", function() { - assert.throws(function() { - Parsimmon.digit.tryParse("a"); + it("returns throws on a bad parse", function() { + assert.throws(function() { + Parsimmon.digit.tryParse("a"); + }); }); - }); - it("thrown error message is equal to formatError", function() { - var input = "a"; - var parser = Parsimmon.digit; - var result = parser.parse(input); - var errMsg = Parsimmon.formatError(input, result); - try { - parser.tryParse(input); - } catch (err) { - assert.equal(err.message, errMsg); - } - }); + it("thrown error message is equal to formatError", function() { + var input = "a"; + var parser = Parsimmon.digit; + var result = parser.parse(input); + var errMsg = Parsimmon.formatError(input, result); + try { + parser.tryParse(input); + } catch (err) { + assert.equal(err.message, errMsg); + } + }); - it("thrown error contains full result object", function() { - var input = "a"; - var parser = Parsimmon.digit; - var result = parser.parse(input); - try { - parser.tryParse(input); - } catch (err) { - assert.deepEqual(err.result, result); - } - }); + it("thrown error contains full result object", function() { + var input = "a"; + var parser = Parsimmon.digit; + var result = parser.parse(input); + try { + parser.tryParse(input); + } catch (err) { + assert.deepEqual(err.result, result); + } + }); - it("thrown error message is equal to formatError", function() { - var input = "a"; - var parser = Parsimmon.digit; - try { - parser.tryParse(input); - } catch (err) { - assert.deepEqual(err.result, parser.parse(input)); - } + it("thrown error message is equal to formatError", function() { + var input = "a"; + var parser = Parsimmon.digit; + try { + parser.tryParse(input); + } catch (err) { + assert.deepEqual(err.result, parser.parse(input)); + } + }); }); }); diff --git a/test/core/wrap.test.js b/test/core/wrap.test.js index fe634cf..415ce73 100644 --- a/test/core/wrap.test.js +++ b/test/core/wrap.test.js @@ -1,11 +1,13 @@ "use strict"; -describe("parser.wrap", function() { - it("should remove different stuff from the begin and end", function() { - var lParen = Parsimmon.string("("); - var rParen = Parsimmon.string(")"); - var parser = Parsimmon.letters.wrap(lParen, rParen); - var value = parser.tryParse("(heyyy)"); - assert.strictEqual(value, "heyyy"); +testSetScenario(function() { + describe("parser.wrap", function() { + it("should remove different stuff from the begin and end", function() { + var lParen = Parsimmon.string("("); + var rParen = Parsimmon.string(")"); + var parser = Parsimmon.letters.wrap(lParen, rParen); + var value = parser.tryParse("(heyyy)"); + assert.strictEqual(value, "heyyy"); + }); }); }); diff --git a/test/setup.js b/test/setup.js index 62a930d..037e0c6 100644 --- a/test/setup.js +++ b/test/setup.js @@ -28,3 +28,23 @@ globalThis.equivalentParsers = function equivalentParsers(p1, p2, inputs) { assert.deepEqual(p1.parse(inputs[i]), p2.parse(inputs[i])); } }; + +globalThis.testSetScenario = function testSetScenario(fn) { + describe("", function() { + fn(); + + if (typeof Set !== "undefined") { + describe("no Set", function() { + before(function() { + Parsimmon._supportsSet = false; + }); + + after(function() { + Parsimmon._supportsSet = undefined; + }); + + fn(); + }); + } + }); +};