Last active
August 29, 2015 14:00
-
-
Save pohatu/11235241 to your computer and use it in GitHub Desktop.
FizzBuss.PEG.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* FizzBuzz as a PEG Parser | |
* This is the grammar to input to PEG.JS | |
* Output is a JS Parser that will recognize numbers and convert them to: | |
* "fizz" if multiples of 3, "buzz" if multiples of 5, and "fizzbuzz" if multiples of 3 and 5. | |
* Using predicates, I was able to get this to actually create fizz, buzz, and fizzbuzz tokens! Woo! Hoo! | |
*/ | |
start | |
= elements:(e:element delims? { return e;})+ {return elements;} | |
element | |
= fizzbuzz / fizz / buzz / integer | |
delims | |
= [ \n\t,;]+ { return " "} | |
integer "integer" | |
= digits:[0-9]+ { return parseInt(digits.join(""), 10);;} | |
fizzbuzz "fizzbuzz" | |
= (i:integer &{if(i%15===0){return true;}}) { return "fizzbuzz";} | |
buzz "buzz" | |
= (i:integer &{if(i%5===0){return true;}}) { return "buzz";} | |
fizz "fizz" | |
= (i:integer &{if(i%3===0){return true;}}) { return "fizz";} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = (function() { | |
/* | |
* Generated by PEG.js 0.8.0. | |
* | |
* http://pegjs.majda.cz/ | |
*/ | |
function peg$subclass(child, parent) { | |
function ctor() { this.constructor = child; } | |
ctor.prototype = parent.prototype; | |
child.prototype = new ctor(); | |
} | |
function SyntaxError(message, expected, found, offset, line, column) { | |
this.message = message; | |
this.expected = expected; | |
this.found = found; | |
this.offset = offset; | |
this.line = line; | |
this.column = column; | |
this.name = "SyntaxError"; | |
} | |
peg$subclass(SyntaxError, Error); | |
function parse(input) { | |
var options = arguments.length > 1 ? arguments[1] : {}, | |
peg$FAILED = {}, | |
peg$startRuleFunctions = { start: peg$parsestart }, | |
peg$startRuleFunction = peg$parsestart, | |
peg$c0 = [], | |
peg$c1 = peg$FAILED, | |
peg$c2 = null, | |
peg$c3 = function(e) { return e;}, | |
peg$c4 = function(elements) {return elements;}, | |
peg$c5 = /^[ \n\t,;]/, | |
peg$c6 = { type: "class", value: "[ \\n\\t,;]", description: "[ \\n\\t,;]" }, | |
peg$c7 = function() { return " "}, | |
peg$c8 = { type: "other", description: "integer" }, | |
peg$c9 = /^[0-9]/, | |
peg$c10 = { type: "class", value: "[0-9]", description: "[0-9]" }, | |
peg$c11 = function(digits) { return parseInt(digits.join(""), 10);;}, | |
peg$c12 = { type: "other", description: "fizzbuzz" }, | |
peg$c13 = function(i) {if(i%15===0){return true;}}, | |
peg$c14 = void 0, | |
peg$c15 = function(i) { return "fizzbuzz";}, | |
peg$c16 = { type: "other", description: "buzz" }, | |
peg$c17 = function(i) {if(i%5===0){return true;}}, | |
peg$c18 = function(i) { return "buzz";}, | |
peg$c19 = { type: "other", description: "fizz" }, | |
peg$c20 = function(i) {if(i%3===0){return true;}}, | |
peg$c21 = function(i) { return "fizz";}, | |
peg$currPos = 0, | |
peg$reportedPos = 0, | |
peg$cachedPos = 0, | |
peg$cachedPosDetails = { line: 1, column: 1, seenCR: false }, | |
peg$maxFailPos = 0, | |
peg$maxFailExpected = [], | |
peg$silentFails = 0, | |
peg$result; | |
if ("startRule" in options) { | |
if (!(options.startRule in peg$startRuleFunctions)) { | |
throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); | |
} | |
peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; | |
} | |
function text() { | |
return input.substring(peg$reportedPos, peg$currPos); | |
} | |
function offset() { | |
return peg$reportedPos; | |
} | |
function line() { | |
return peg$computePosDetails(peg$reportedPos).line; | |
} | |
function column() { | |
return peg$computePosDetails(peg$reportedPos).column; | |
} | |
function expected(description) { | |
throw peg$buildException( | |
null, | |
[{ type: "other", description: description }], | |
peg$reportedPos | |
); | |
} | |
function error(message) { | |
throw peg$buildException(message, null, peg$reportedPos); | |
} | |
function peg$computePosDetails(pos) { | |
function advance(details, startPos, endPos) { | |
var p, ch; | |
for (p = startPos; p < endPos; p++) { | |
ch = input.charAt(p); | |
if (ch === "\n") { | |
if (!details.seenCR) { details.line++; } | |
details.column = 1; | |
details.seenCR = false; | |
} else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") { | |
details.line++; | |
details.column = 1; | |
details.seenCR = true; | |
} else { | |
details.column++; | |
details.seenCR = false; | |
} | |
} | |
} | |
if (peg$cachedPos !== pos) { | |
if (peg$cachedPos > pos) { | |
peg$cachedPos = 0; | |
peg$cachedPosDetails = { line: 1, column: 1, seenCR: false }; | |
} | |
advance(peg$cachedPosDetails, peg$cachedPos, pos); | |
peg$cachedPos = pos; | |
} | |
return peg$cachedPosDetails; | |
} | |
function peg$fail(expected) { | |
if (peg$currPos < peg$maxFailPos) { return; } | |
if (peg$currPos > peg$maxFailPos) { | |
peg$maxFailPos = peg$currPos; | |
peg$maxFailExpected = []; | |
} | |
peg$maxFailExpected.push(expected); | |
} | |
function peg$buildException(message, expected, pos) { | |
function cleanupExpected(expected) { | |
var i = 1; | |
expected.sort(function(a, b) { | |
if (a.description < b.description) { | |
return -1; | |
} else if (a.description > b.description) { | |
return 1; | |
} else { | |
return 0; | |
} | |
}); | |
while (i < expected.length) { | |
if (expected[i - 1] === expected[i]) { | |
expected.splice(i, 1); | |
} else { | |
i++; | |
} | |
} | |
} | |
function buildMessage(expected, found) { | |
function stringEscape(s) { | |
function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); } | |
return s | |
.replace(/\\/g, '\\\\') | |
.replace(/"/g, '\\"') | |
.replace(/\x08/g, '\\b') | |
.replace(/\t/g, '\\t') | |
.replace(/\n/g, '\\n') | |
.replace(/\f/g, '\\f') | |
.replace(/\r/g, '\\r') | |
.replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) | |
.replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); }) | |
.replace(/[\u0180-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); }) | |
.replace(/[\u1080-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); }); | |
} | |
var expectedDescs = new Array(expected.length), | |
expectedDesc, foundDesc, i; | |
for (i = 0; i < expected.length; i++) { | |
expectedDescs[i] = expected[i].description; | |
} | |
expectedDesc = expected.length > 1 | |
? expectedDescs.slice(0, -1).join(", ") | |
+ " or " | |
+ expectedDescs[expected.length - 1] | |
: expectedDescs[0]; | |
foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input"; | |
return "Expected " + expectedDesc + " but " + foundDesc + " found."; | |
} | |
var posDetails = peg$computePosDetails(pos), | |
found = pos < input.length ? input.charAt(pos) : null; | |
if (expected !== null) { | |
cleanupExpected(expected); | |
} | |
return new SyntaxError( | |
message !== null ? message : buildMessage(expected, found), | |
expected, | |
found, | |
pos, | |
posDetails.line, | |
posDetails.column | |
); | |
} | |
function peg$parsestart() { | |
var s0, s1, s2, s3, s4; | |
s0 = peg$currPos; | |
s1 = []; | |
s2 = peg$currPos; | |
s3 = peg$parseelement(); | |
if (s3 !== peg$FAILED) { | |
s4 = peg$parsedelims(); | |
if (s4 === peg$FAILED) { | |
s4 = peg$c2; | |
} | |
if (s4 !== peg$FAILED) { | |
peg$reportedPos = s2; | |
s3 = peg$c3(s3); | |
s2 = s3; | |
} else { | |
peg$currPos = s2; | |
s2 = peg$c1; | |
} | |
} else { | |
peg$currPos = s2; | |
s2 = peg$c1; | |
} | |
if (s2 !== peg$FAILED) { | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
s2 = peg$currPos; | |
s3 = peg$parseelement(); | |
if (s3 !== peg$FAILED) { | |
s4 = peg$parsedelims(); | |
if (s4 === peg$FAILED) { | |
s4 = peg$c2; | |
} | |
if (s4 !== peg$FAILED) { | |
peg$reportedPos = s2; | |
s3 = peg$c3(s3); | |
s2 = s3; | |
} else { | |
peg$currPos = s2; | |
s2 = peg$c1; | |
} | |
} else { | |
peg$currPos = s2; | |
s2 = peg$c1; | |
} | |
} | |
} else { | |
s1 = peg$c1; | |
} | |
if (s1 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c4(s1); | |
} | |
s0 = s1; | |
return s0; | |
} | |
function peg$parseelement() { | |
var s0; | |
s0 = peg$parsefizzbuzz(); | |
if (s0 === peg$FAILED) { | |
s0 = peg$parsefizz(); | |
if (s0 === peg$FAILED) { | |
s0 = peg$parsebuzz(); | |
if (s0 === peg$FAILED) { | |
s0 = peg$parseinteger(); | |
} | |
} | |
} | |
return s0; | |
} | |
function peg$parsedelims() { | |
var s0, s1, s2; | |
s0 = peg$currPos; | |
s1 = []; | |
if (peg$c5.test(input.charAt(peg$currPos))) { | |
s2 = input.charAt(peg$currPos); | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c6); } | |
} | |
if (s2 !== peg$FAILED) { | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
if (peg$c5.test(input.charAt(peg$currPos))) { | |
s2 = input.charAt(peg$currPos); | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c6); } | |
} | |
} | |
} else { | |
s1 = peg$c1; | |
} | |
if (s1 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c7(); | |
} | |
s0 = s1; | |
return s0; | |
} | |
function peg$parseinteger() { | |
var s0, s1, s2; | |
peg$silentFails++; | |
s0 = peg$currPos; | |
s1 = []; | |
if (peg$c9.test(input.charAt(peg$currPos))) { | |
s2 = input.charAt(peg$currPos); | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c10); } | |
} | |
if (s2 !== peg$FAILED) { | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
if (peg$c9.test(input.charAt(peg$currPos))) { | |
s2 = input.charAt(peg$currPos); | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c10); } | |
} | |
} | |
} else { | |
s1 = peg$c1; | |
} | |
if (s1 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c11(s1); | |
} | |
s0 = s1; | |
peg$silentFails--; | |
if (s0 === peg$FAILED) { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c8); } | |
} | |
return s0; | |
} | |
function peg$parsefizzbuzz() { | |
var s0, s1, s2; | |
peg$silentFails++; | |
s0 = peg$currPos; | |
s1 = peg$parseinteger(); | |
if (s1 !== peg$FAILED) { | |
peg$reportedPos = peg$currPos; | |
s2 = peg$c13(s1); | |
if (s2) { | |
s2 = peg$c14; | |
} else { | |
s2 = peg$c1; | |
} | |
if (s2 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c15(s1); | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c1; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c1; | |
} | |
peg$silentFails--; | |
if (s0 === peg$FAILED) { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c12); } | |
} | |
return s0; | |
} | |
function peg$parsebuzz() { | |
var s0, s1, s2; | |
peg$silentFails++; | |
s0 = peg$currPos; | |
s1 = peg$parseinteger(); | |
if (s1 !== peg$FAILED) { | |
peg$reportedPos = peg$currPos; | |
s2 = peg$c17(s1); | |
if (s2) { | |
s2 = peg$c14; | |
} else { | |
s2 = peg$c1; | |
} | |
if (s2 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c18(s1); | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c1; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c1; | |
} | |
peg$silentFails--; | |
if (s0 === peg$FAILED) { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c16); } | |
} | |
return s0; | |
} | |
function peg$parsefizz() { | |
var s0, s1, s2; | |
peg$silentFails++; | |
s0 = peg$currPos; | |
s1 = peg$parseinteger(); | |
if (s1 !== peg$FAILED) { | |
peg$reportedPos = peg$currPos; | |
s2 = peg$c20(s1); | |
if (s2) { | |
s2 = peg$c14; | |
} else { | |
s2 = peg$c1; | |
} | |
if (s2 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c21(s1); | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c1; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c1; | |
} | |
peg$silentFails--; | |
if (s0 === peg$FAILED) { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c19); } | |
} | |
return s0; | |
} | |
peg$result = peg$startRuleFunction(); | |
if (peg$result !== peg$FAILED && peg$currPos === input.length) { | |
return peg$result; | |
} else { | |
if (peg$result !== peg$FAILED && peg$currPos < input.length) { | |
peg$fail({ type: "end", description: "end of input" }); | |
} | |
throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos); | |
} | |
} | |
return { | |
SyntaxError: SyntaxError, | |
parse: parse | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment