From 494840295673aef113a30d1d3241aeee2dd8be79 Mon Sep 17 00:00:00 2001 From: Alex MacCaw Date: Wed, 18 Apr 2012 00:17:58 -0700 Subject: [PATCH] add PEG parsers --- assets/javascripts/application.js | 4 +- assets/javascripts/parsers/color.module.js | 800 ++++++++++ assets/javascripts/parsers/color.pegjs | 50 + assets/javascripts/parsers/gradient.pegjs | 0 assets/javascripts/parsers/json.pegjs | 120 ++ assets/javascripts/parsers/shadow.pegjs | 49 + public/assets/application.js | 803 ++++++++++ public/assets/parsers/color.module.js | 861 ++++++++++ public/assets/parsers/color.pegjs | 50 + public/assets/parsers/gradient.pegjs | 0 public/assets/parsers/json.module.js | 1682 ++++++++++++++++++++ public/assets/parsers/json.pegjs | 120 ++ public/assets/parsers/shadow.peg | 0 public/assets/parsers/shadow.pegjs | 49 + 14 files changed, 4587 insertions(+), 1 deletion(-) create mode 100644 assets/javascripts/parsers/color.module.js create mode 100644 assets/javascripts/parsers/color.pegjs create mode 100644 assets/javascripts/parsers/gradient.pegjs create mode 100644 assets/javascripts/parsers/json.pegjs create mode 100644 assets/javascripts/parsers/shadow.pegjs create mode 100644 public/assets/parsers/color.module.js create mode 100644 public/assets/parsers/color.pegjs create mode 100644 public/assets/parsers/gradient.pegjs create mode 100644 public/assets/parsers/json.module.js create mode 100644 public/assets/parsers/json.pegjs create mode 100644 public/assets/parsers/shadow.peg create mode 100644 public/assets/parsers/shadow.pegjs diff --git a/assets/javascripts/application.js b/assets/javascripts/application.js index 764ceec..fb028da 100644 --- a/assets/javascripts/application.js +++ b/assets/javascripts/application.js @@ -6,5 +6,7 @@ //= require spine/relation //= require gfx //= require gfx/effects + //= require_tree ./lib -//= require_tree ./app \ No newline at end of file +//= require_tree ./app +//= require_tree ./parsers \ No newline at end of file diff --git a/assets/javascripts/parsers/color.module.js b/assets/javascripts/parsers/color.module.js new file mode 100644 index 0000000..c2f2678 --- /dev/null +++ b/assets/javascripts/parsers/color.module.js @@ -0,0 +1,800 @@ +module.exports = (function(){ + /* + * Generated by PEG.js 0.6.2. + * + * http://pegjs.majda.cz/ + */ + + function quote(s) { + /* + * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a + * string literal except for the closing quote character, backslash, + * carriage return, line separator, paragraph separator, and line feed. + * Any character may appear in the form of an escape sequence. + * + * For portability, we also escape escape all control and non-ASCII + * characters. Note that "\0" and "\v" escape sequences are not used + * because JSHint does not like the first and IE the second. + */ + return '"' + s + .replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing quote character + .replace(/\x08/g, '\\b') // backspace + .replace(/\t/g, '\\t') // horizontal tab + .replace(/\n/g, '\\n') // line feed + .replace(/\f/g, '\\f') // form feed + .replace(/\r/g, '\\r') // carriage return + .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + + '"'; + } + + var result = { + /* + * Parses the input with a generated parser. If the parsing is successfull, + * returns a value explicitly or implicitly specified by the grammar from + * which the parser was generated (see |PEG.buildParser|). If the parsing is + * unsuccessful, throws |PEG.parser.SyntaxError| describing the error. + */ + parse: function(input, startRule) { + var parseFunctions = { + "start": parse_start, + "hexcolor": parse_hexcolor, + "hexcolorlong": parse_hexcolorlong, + "hexcolorshort": parse_hexcolorshort, + "hex": parse_hex, + "rgba": parse_rgba, + "shortcut": parse_shortcut, + "elements": parse_elements + }; + + if (startRule !== undefined) { + if (parseFunctions[startRule] === undefined) { + throw new Error("Invalid rule name: " + quote(startRule) + "."); + } + } else { + startRule = "start"; + } + + var pos = 0; + var reportFailures = 0; + var rightmostFailuresPos = 0; + var rightmostFailuresExpected = []; + + function padLeft(input, padding, length) { + var result = input; + + var padLength = length - input.length; + for (var i = 0; i < padLength; i++) { + result = padding + result; + } + + return result; + } + + function escape(ch) { + var charCode = ch.charCodeAt(0); + var escapeChar; + var length; + + if (charCode <= 0xFF) { + escapeChar = 'x'; + length = 2; + } else { + escapeChar = 'u'; + length = 4; + } + + return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); + } + + function matchFailed(failure) { + if (pos < rightmostFailuresPos) { + return; + } + + if (pos > rightmostFailuresPos) { + rightmostFailuresPos = pos; + rightmostFailuresExpected = []; + } + + rightmostFailuresExpected.push(failure); + } + + function parse_start() { + var result0; + + result0 = parse_hexcolor(); + if (result0 === null) { + result0 = parse_rgba(); + if (result0 === null) { + result0 = parse_shortcut(); + } + } + return result0; + } + + function parse_hexcolor() { + var result0; + var pos0; + + reportFailures++; + pos0 = pos; + result0 = parse_hexcolorshort(); + if (result0 === null) { + result0 = parse_hexcolorlong(); + } + if (result0 !== null) { + result0 = (function(offset, hex) { + var r = parseInt(hex.substring(0, 2), 16); + var g = parseInt(hex.substring(2, 4), 16); + var b = parseInt(hex.substring(4, 6), 16); + + var Color = require("app/models/properties/color"); + return new Color(r, g, b); + })(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("hexcolor"); + } + return result0; + } + + function parse_hexcolorlong() { + var result0, result1, result2; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 35) { + result0 = "#"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"#\""); + } + } + if (result0 !== null) { + result1 = []; + result2 = parse_hex(); + while (result2 !== null) { + result1.push(result2); + result2 = parse_hex(); + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, hexes) { + return hexes.join(''); + })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_hexcolorshort() { + var result0, result1, result2, result3; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 35) { + result0 = "#"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"#\""); + } + } + if (result0 !== null) { + result1 = parse_hex(); + if (result1 !== null) { + result2 = parse_hex(); + if (result2 !== null) { + result3 = parse_hex(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, h1, h2, h3) { + return h1 + h1 + h2 + h2 + h3 + h3; + })(pos0, result0[1], result0[2], result0[3]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_hex() { + var result0; + + if (/^[0-9a-fA-F]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[0-9a-fA-F]"); + } + } + return result0; + } + + function parse_rgba() { + var result0, result1, result2; + var pos0, pos1; + + reportFailures++; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 4) === "rgb(") { + result0 = "rgb("; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"rgb(\""); + } + } + if (result0 !== null) { + result1 = parse_elements(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 41) { + result2 = ")"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + if (input.substr(pos, 5) === "rgba(") { + result0 = "rgba("; + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"rgba(\""); + } + } + if (result0 !== null) { + result1 = parse_elements(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 41) { + result2 = ")"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } + if (result0 !== null) { + result0 = (function(offset) { + elements = elements.map(function(i){ return parseFloat(i) }); + + var Color = require('app/models/properties/color'); + return new Color(elements[0], elements[1], elements[2], elements[3]); + })(pos0); + } + if (result0 === null) { + pos = pos0; + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("rgba"); + } + return result0; + } + + function parse_shortcut() { + var result0; + + reportFailures++; + if (input.substr(pos, 3) === "red") { + result0 = "red"; + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"red\""); + } + } + if (result0 === null) { + if (input.substr(pos, 3) === "tan") { + result0 = "tan"; + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"tan\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "grey") { + result0 = "grey"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"grey\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "gray") { + result0 = "gray"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"gray\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "lime") { + result0 = "lime"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"lime\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "navy") { + result0 = "navy"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"navy\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "blue") { + result0 = "blue"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"blue\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "teal") { + result0 = "teal"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"teal\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "aqua") { + result0 = "aqua"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"aqua\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "cyan") { + result0 = "cyan"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"cyan\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "gold") { + result0 = "gold"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"gold\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "peru") { + result0 = "peru"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"peru\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "pink") { + result0 = "pink"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"pink\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "plum") { + result0 = "plum"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"plum\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "snow") { + result0 = "snow"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"snow\""); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("shortcut"); + } + return result0; + } + + function parse_elements() { + var result0, result1, result2, result3, result4; + var pos0, pos1, pos2; + + pos0 = pos; + pos1 = pos; + result0 = []; + if (input.length > pos) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + while (result1 !== null) { + result0.push(result1); + if (input.length > pos) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + } + if (result0 !== null) { + result1 = []; + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result2 = ","; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result2 !== null) { + result3 = []; + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + while (result4 !== null) { + result3.push(result4); + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + } + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result2 = ","; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result2 !== null) { + result3 = []; + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + while (result4 !== null) { + result3.push(result4); + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + } + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, head, tail) { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][2]); + } + return result; + })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + + function cleanupExpected(expected) { + expected.sort(); + + var lastExpected = null; + var cleanExpected = []; + for (var i = 0; i < expected.length; i++) { + if (expected[i] !== lastExpected) { + cleanExpected.push(expected[i]); + lastExpected = expected[i]; + } + } + return cleanExpected; + } + + function computeErrorPosition() { + /* + * The first idea was to use |String.split| to break the input up to the + * error position along newlines and derive the line and column from + * there. However IE's |split| implementation is so broken that it was + * enough to prevent it. + */ + + var line = 1; + var column = 1; + var seenCR = false; + + for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) { + var ch = input.charAt(i); + if (ch === "\n") { + if (!seenCR) { line++; } + column = 1; + seenCR = false; + } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") { + line++; + column = 1; + seenCR = true; + } else { + column++; + seenCR = false; + } + } + + return { line: line, column: column }; + } + + + var result = parseFunctions[startRule](); + + /* + * The parser is now in one of the following three states: + * + * 1. The parser successfully parsed the whole input. + * + * - |result !== null| + * - |pos === input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 2. The parser successfully parsed only a part of the input. + * + * - |result !== null| + * - |pos < input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 3. The parser did not successfully parse any part of the input. + * + * - |result === null| + * - |pos === 0| + * - |rightmostFailuresExpected| contains at least one failure + * + * All code following this comment (including called functions) must + * handle these states. + */ + if (result === null || pos !== input.length) { + var offset = Math.max(pos, rightmostFailuresPos); + var found = offset < input.length ? input.charAt(offset) : null; + var errorPosition = computeErrorPosition(); + + throw new this.SyntaxError( + cleanupExpected(rightmostFailuresExpected), + found, + offset, + errorPosition.line, + errorPosition.column + ); + } + + return result; + }, + + /* Returns the parser source code. */ + toSource: function() { return this._source; } + }; + + /* Thrown when a parser encounters a syntax error. */ + + result.SyntaxError = function(expected, found, offset, line, column) { + function buildMessage(expected, found) { + var expectedHumanized, foundHumanized; + + switch (expected.length) { + case 0: + expectedHumanized = "end of input"; + break; + case 1: + expectedHumanized = expected[0]; + break; + default: + expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + + " or " + + expected[expected.length - 1]; + } + + foundHumanized = found ? quote(found) : "end of input"; + + return "Expected " + expectedHumanized + " but " + foundHumanized + " found."; + } + + this.name = "SyntaxError"; + this.expected = expected; + this.found = found; + this.message = buildMessage(expected, found); + this.offset = offset; + this.line = line; + this.column = column; + }; + + result.SyntaxError.prototype = Error.prototype; + + return result; +})(); diff --git a/assets/javascripts/parsers/color.pegjs b/assets/javascripts/parsers/color.pegjs new file mode 100644 index 0000000..3f3e5d5 --- /dev/null +++ b/assets/javascripts/parsers/color.pegjs @@ -0,0 +1,50 @@ +// CSS Color parser + +start + = hexcolor / rgba / shortcut + +hexcolor "hexcolor" + = hex:(hexcolorshort / hexcolorlong) { + var r = parseInt(hex.substring(0, 2), 16); + var g = parseInt(hex.substring(2, 4), 16); + var b = parseInt(hex.substring(4, 6), 16); + + var Color = require("app/models/properties/color"); + return new Color(r, g, b); + } + +hexcolorlong + = "#" (hexes:hex*) { + return hexes.join(''); + } + +hexcolorshort + = "#" h1:hex h2:hex h3:hex { + return h1 + h1 + h2 + h2 + h3 + h3; + } + +hex + = [0-9a-fA-F] + +rgba "rgba" + = ("rgb(" elements:elements ")" / "rgba(" elements:elements ")") { + elements = elements.map(function(i){ return parseFloat(i) }); + + var Color = require('app/models/properties/color'); + return new Color(elements[0], elements[1], elements[2], elements[3]); + } + +shortcut "shortcut" + = "red" / "tan" / "grey" / "gray" / "lime" / "navy" / "blue" / + "teal" / "aqua" / "cyan" / "gold" / "peru" / "pink" / "plum" / "snow" + +// Utilities + +elements + = head:.* tail:("," .*)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][2]); + } + return result; + } \ No newline at end of file diff --git a/assets/javascripts/parsers/gradient.pegjs b/assets/javascripts/parsers/gradient.pegjs new file mode 100644 index 0000000..e69de29 diff --git a/assets/javascripts/parsers/json.pegjs b/assets/javascripts/parsers/json.pegjs new file mode 100644 index 0000000..1fa492f --- /dev/null +++ b/assets/javascripts/parsers/json.pegjs @@ -0,0 +1,120 @@ +/* JSON parser based on the grammar described at http://json.org/. */ + +/* ===== Syntactical Elements ===== */ + +start + = _ object:object { return object; } + +object + = "{" _ "}" _ { return {}; } + / "{" _ members:members "}" _ { return members; } + +members + = head:pair tail:("," _ pair)* { + var result = {}; + result[head[0]] = head[1]; + for (var i = 0; i < tail.length; i++) { + result[tail[i][2][0]] = tail[i][2][1]; + } + return result; + } + +pair + = name:string ":" _ value:value { return [name, value]; } + +array + = "[" _ "]" _ { return []; } + / "[" _ elements:elements "]" _ { return elements; } + +elements + = head:value tail:("," _ value)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][2]); + } + return result; + } + +value + = string + / number + / object + / array + / "true" _ { return true; } + / "false" _ { return false; } + // FIXME: We can't return null here because that would mean parse failure. + / "null" _ { return "null"; } + +/* ===== Lexical Elements ===== */ + +string "string" + = '"' '"' _ { return ""; } + / '"' chars:chars '"' _ { return chars; } + +chars + = chars:char+ { return chars.join(""); } + +char + // In the original JSON grammar: "any-Unicode-character-except-"-or-\-or-control-character" + = [^"\\\0-\x1F\x7f] + / '\\"' { return '"'; } + / "\\\\" { return "\\"; } + / "\\/" { return "/"; } + / "\\b" { return "\b"; } + / "\\f" { return "\f"; } + / "\\n" { return "\n"; } + / "\\r" { return "\r"; } + / "\\t" { return "\t"; } + / "\\u" h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit { + return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4)); + } + +number "number" + = int_:int frac:frac exp:exp _ { return parseFloat(int_ + frac + exp); } + / int_:int frac:frac _ { return parseFloat(int_ + frac); } + / int_:int exp:exp _ { return parseFloat(int_ + exp); } + / int_:int _ { return parseFloat(int_); } + +int + = digit19:digit19 digits:digits { return digit19 + digits; } + / digit:digit + / "-" digit19:digit19 digits:digits { return "-" + digit19 + digits; } + / "-" digit:digit { return "-" + digit; } + +frac + = "." digits:digits { return "." + digits; } + +exp + = e:e digits:digits { return e + digits; } + +digits + = digits:digit+ { return digits.join(""); } + +e + = e:[eE] sign:[+-]? { return e + sign; } + +/* + * The following rules are not present in the original JSON gramar, but they are + * assumed to exist implicitly. + * + * FIXME: Define them according to ECMA-262, 5th ed. + */ + +digit + = [0-9] + +digit19 + = [1-9] + +hexDigit + = [0-9a-fA-F] + +/* ===== Whitespace ===== */ + +_ "whitespace" + = whitespace* + +// Whitespace is undefined in the original JSON grammar, so I assume a simple +// conventional definition consistent with ECMA-262, 5th ed. +whitespace + = [ \t\n\r] \ No newline at end of file diff --git a/assets/javascripts/parsers/shadow.pegjs b/assets/javascripts/parsers/shadow.pegjs new file mode 100644 index 0000000..b493451 --- /dev/null +++ b/assets/javascripts/parsers/shadow.pegjs @@ -0,0 +1,49 @@ +// CSS Shadow parser + +start + = inset:"inset"? color:color (values:px _ *) { + var Shadow = require('app/models/properties/shadow'); + var props = {}; + props.inset = !!inset; + props.x = values[0]; + props.y = values[1]; + props.blur = values[2]; + props.spread = values[3]; + return new Shadow(options); + } + +px + = number "px" + +number "number" + = int_:int frac:frac exp:exp _ { return parseFloat(int_ + frac + exp); } + / int_:int frac:frac _ { return parseFloat(int_ + frac); } + / int_:int exp:exp _ { return parseFloat(int_ + exp); } + / int_:int _ { return parseFloat(int_); } + +int + = digit19:digit19 digits:digits { return digit19 + digits; } + / digit:digit + / "-" digit19:digit19 digits:digits { return "-" + digit19 + digits; } + / "-" digit:digit { return "-" + digit; } + +frac + = "." digits:digits { return "." + digits; } + +exp + = e:e digits:digits { return e + digits; } + +digits + = digits:digit+ { return digits.join(""); } + +digit + = [0-9] + +digit19 + = [1-9] + +_ "whitespace" + = whitespace* + +whitespace + = [ \t\n\r] \ No newline at end of file diff --git a/public/assets/application.js b/public/assets/application.js index 88ecfe9..b57d295 100644 --- a/public/assets/application.js +++ b/public/assets/application.js @@ -18077,6 +18077,809 @@ this.require.define({"app/models/serialize":function(exports, require, module){( return __out.join(''); }; }).call(this); +this.require.define({"parsers/color":function(exports, require, module){module.exports = (function(){ + /* + * Generated by PEG.js 0.6.2. + * + * http://pegjs.majda.cz/ + */ + + function quote(s) { + /* + * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a + * string literal except for the closing quote character, backslash, + * carriage return, line separator, paragraph separator, and line feed. + * Any character may appear in the form of an escape sequence. + * + * For portability, we also escape escape all control and non-ASCII + * characters. Note that "\0" and "\v" escape sequences are not used + * because JSHint does not like the first and IE the second. + */ + return '"' + s + .replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing quote character + .replace(/\x08/g, '\\b') // backspace + .replace(/\t/g, '\\t') // horizontal tab + .replace(/\n/g, '\\n') // line feed + .replace(/\f/g, '\\f') // form feed + .replace(/\r/g, '\\r') // carriage return + .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + + '"'; + } + + var result = { + /* + * Parses the input with a generated parser. If the parsing is successfull, + * returns a value explicitly or implicitly specified by the grammar from + * which the parser was generated (see |PEG.buildParser|). If the parsing is + * unsuccessful, throws |PEG.parser.SyntaxError| describing the error. + */ + parse: function(input, startRule) { + var parseFunctions = { + "start": parse_start, + "hexcolor": parse_hexcolor, + "hexcolorlong": parse_hexcolorlong, + "hexcolorshort": parse_hexcolorshort, + "hex": parse_hex, + "rgba": parse_rgba, + "shortcut": parse_shortcut, + "elements": parse_elements + }; + + if (startRule !== undefined) { + if (parseFunctions[startRule] === undefined) { + throw new Error("Invalid rule name: " + quote(startRule) + "."); + } + } else { + startRule = "start"; + } + + var pos = 0; + var reportFailures = 0; + var rightmostFailuresPos = 0; + var rightmostFailuresExpected = []; + + function padLeft(input, padding, length) { + var result = input; + + var padLength = length - input.length; + for (var i = 0; i < padLength; i++) { + result = padding + result; + } + + return result; + } + + function escape(ch) { + var charCode = ch.charCodeAt(0); + var escapeChar; + var length; + + if (charCode <= 0xFF) { + escapeChar = 'x'; + length = 2; + } else { + escapeChar = 'u'; + length = 4; + } + + return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); + } + + function matchFailed(failure) { + if (pos < rightmostFailuresPos) { + return; + } + + if (pos > rightmostFailuresPos) { + rightmostFailuresPos = pos; + rightmostFailuresExpected = []; + } + + rightmostFailuresExpected.push(failure); + } + + function parse_start() { + var result0; + + result0 = parse_hexcolor(); + if (result0 === null) { + result0 = parse_rgba(); + if (result0 === null) { + result0 = parse_shortcut(); + } + } + return result0; + } + + function parse_hexcolor() { + var result0; + var pos0; + + reportFailures++; + pos0 = pos; + result0 = parse_hexcolorshort(); + if (result0 === null) { + result0 = parse_hexcolorlong(); + } + if (result0 !== null) { + result0 = (function(offset, hex) { + var r = parseInt(hex.substring(0, 2), 16); + var g = parseInt(hex.substring(2, 4), 16); + var b = parseInt(hex.substring(4, 6), 16); + + var Color = require("app/models/properties/color"); + return new Color(r, g, b); + })(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("hexcolor"); + } + return result0; + } + + function parse_hexcolorlong() { + var result0, result1, result2; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 35) { + result0 = "#"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"#\""); + } + } + if (result0 !== null) { + result1 = []; + result2 = parse_hex(); + while (result2 !== null) { + result1.push(result2); + result2 = parse_hex(); + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, hexes) { + return hexes.join(''); + })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_hexcolorshort() { + var result0, result1, result2, result3; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 35) { + result0 = "#"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"#\""); + } + } + if (result0 !== null) { + result1 = parse_hex(); + if (result1 !== null) { + result2 = parse_hex(); + if (result2 !== null) { + result3 = parse_hex(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, h1, h2, h3) { + return h1 + h1 + h2 + h2 + h3 + h3; + })(pos0, result0[1], result0[2], result0[3]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_hex() { + var result0; + + if (/^[0-9a-fA-F]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[0-9a-fA-F]"); + } + } + return result0; + } + + function parse_rgba() { + var result0, result1, result2; + var pos0, pos1; + + reportFailures++; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 4) === "rgb(") { + result0 = "rgb("; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"rgb(\""); + } + } + if (result0 !== null) { + result1 = parse_elements(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 41) { + result2 = ")"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + if (input.substr(pos, 5) === "rgba(") { + result0 = "rgba("; + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"rgba(\""); + } + } + if (result0 !== null) { + result1 = parse_elements(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 41) { + result2 = ")"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } + if (result0 !== null) { + result0 = (function(offset) { + elements = elements.map(function(i){ return parseFloat(i) }); + + var Color = require('app/models/properties/color'); + return new Color(elements[0], elements[1], elements[2], elements[3]); + })(pos0); + } + if (result0 === null) { + pos = pos0; + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("rgba"); + } + return result0; + } + + function parse_shortcut() { + var result0; + + reportFailures++; + if (input.substr(pos, 3) === "red") { + result0 = "red"; + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"red\""); + } + } + if (result0 === null) { + if (input.substr(pos, 3) === "tan") { + result0 = "tan"; + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"tan\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "grey") { + result0 = "grey"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"grey\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "gray") { + result0 = "gray"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"gray\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "lime") { + result0 = "lime"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"lime\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "navy") { + result0 = "navy"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"navy\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "blue") { + result0 = "blue"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"blue\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "teal") { + result0 = "teal"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"teal\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "aqua") { + result0 = "aqua"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"aqua\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "cyan") { + result0 = "cyan"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"cyan\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "gold") { + result0 = "gold"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"gold\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "peru") { + result0 = "peru"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"peru\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "pink") { + result0 = "pink"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"pink\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "plum") { + result0 = "plum"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"plum\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "snow") { + result0 = "snow"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"snow\""); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("shortcut"); + } + return result0; + } + + function parse_elements() { + var result0, result1, result2, result3, result4; + var pos0, pos1, pos2; + + pos0 = pos; + pos1 = pos; + result0 = []; + if (input.length > pos) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + while (result1 !== null) { + result0.push(result1); + if (input.length > pos) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + } + if (result0 !== null) { + result1 = []; + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result2 = ","; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result2 !== null) { + result3 = []; + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + while (result4 !== null) { + result3.push(result4); + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + } + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result2 = ","; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result2 !== null) { + result3 = []; + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + while (result4 !== null) { + result3.push(result4); + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + } + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, head, tail) { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][2]); + } + return result; + })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + + function cleanupExpected(expected) { + expected.sort(); + + var lastExpected = null; + var cleanExpected = []; + for (var i = 0; i < expected.length; i++) { + if (expected[i] !== lastExpected) { + cleanExpected.push(expected[i]); + lastExpected = expected[i]; + } + } + return cleanExpected; + } + + function computeErrorPosition() { + /* + * The first idea was to use |String.split| to break the input up to the + * error position along newlines and derive the line and column from + * there. However IE's |split| implementation is so broken that it was + * enough to prevent it. + */ + + var line = 1; + var column = 1; + var seenCR = false; + + for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) { + var ch = input.charAt(i); + if (ch === "\n") { + if (!seenCR) { line++; } + column = 1; + seenCR = false; + } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") { + line++; + column = 1; + seenCR = true; + } else { + column++; + seenCR = false; + } + } + + return { line: line, column: column }; + } + + + var result = parseFunctions[startRule](); + + /* + * The parser is now in one of the following three states: + * + * 1. The parser successfully parsed the whole input. + * + * - |result !== null| + * - |pos === input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 2. The parser successfully parsed only a part of the input. + * + * - |result !== null| + * - |pos < input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 3. The parser did not successfully parse any part of the input. + * + * - |result === null| + * - |pos === 0| + * - |rightmostFailuresExpected| contains at least one failure + * + * All code following this comment (including called functions) must + * handle these states. + */ + if (result === null || pos !== input.length) { + var offset = Math.max(pos, rightmostFailuresPos); + var found = offset < input.length ? input.charAt(offset) : null; + var errorPosition = computeErrorPosition(); + + throw new this.SyntaxError( + cleanupExpected(rightmostFailuresExpected), + found, + offset, + errorPosition.line, + errorPosition.column + ); + } + + return result; + }, + + /* Returns the parser source code. */ + toSource: function() { return this._source; } + }; + + /* Thrown when a parser encounters a syntax error. */ + + result.SyntaxError = function(expected, found, offset, line, column) { + function buildMessage(expected, found) { + var expectedHumanized, foundHumanized; + + switch (expected.length) { + case 0: + expectedHumanized = "end of input"; + break; + case 1: + expectedHumanized = expected[0]; + break; + default: + expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + + " or " + + expected[expected.length - 1]; + } + + foundHumanized = found ? quote(found) : "end of input"; + + return "Expected " + expectedHumanized + " but " + foundHumanized + " found."; + } + + this.name = "SyntaxError"; + this.expected = expected; + this.found = found; + this.message = buildMessage(expected, found); + this.offset = offset; + this.line = line; + this.column = column; + }; + + result.SyntaxError.prototype = Error.prototype; + + return result; +})(); +;}}); + + diff --git a/public/assets/parsers/color.module.js b/public/assets/parsers/color.module.js new file mode 100644 index 0000000..e2a6972 --- /dev/null +++ b/public/assets/parsers/color.module.js @@ -0,0 +1,861 @@ +(function() { + if (!this.require) { + var modules = {}, cache = {}; + + var require = function(name, root) { + var path = expand(root, name), indexPath = expand(path, './index'), module, fn; + module = cache[path] || cache[indexPath]; + if (module) { + return module; + } else if (fn = modules[path] || modules[path = indexPath]) { + module = {id: path, exports: {}}; + cache[path] = module.exports; + fn(module.exports, function(name) { + return require(name, dirname(path)); + }, module); + return cache[path] = module.exports; + } else { + throw 'module ' + name + ' not found'; + } + }; + + var expand = function(root, name) { + var results = [], parts, part; + // If path is relative + if (/^\.\.?(\/|$)/.test(name)) { + parts = [root, name].join('/').split('/'); + } else { + parts = name.split('/'); + } + for (var i = 0, length = parts.length; i < length; i++) { + part = parts[i]; + if (part == '..') { + results.pop(); + } else if (part != '.' && part != '') { + results.push(part); + } + } + return results.join('/'); + }; + + var dirname = function(path) { + return path.split('/').slice(0, -1).join('/'); + }; + + this.require = function(name) { + return require(name, ''); + }; + + this.require.define = function(bundle) { + for (var key in bundle) { + modules[key] = bundle[key]; + } + }; + + this.require.modules = modules; + this.require.cache = cache; + } + + return this.require; +}).call(this); +this.require.define({"parsers/color":function(exports, require, module){module.exports = (function(){ + /* + * Generated by PEG.js 0.6.2. + * + * http://pegjs.majda.cz/ + */ + + function quote(s) { + /* + * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a + * string literal except for the closing quote character, backslash, + * carriage return, line separator, paragraph separator, and line feed. + * Any character may appear in the form of an escape sequence. + * + * For portability, we also escape escape all control and non-ASCII + * characters. Note that "\0" and "\v" escape sequences are not used + * because JSHint does not like the first and IE the second. + */ + return '"' + s + .replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing quote character + .replace(/\x08/g, '\\b') // backspace + .replace(/\t/g, '\\t') // horizontal tab + .replace(/\n/g, '\\n') // line feed + .replace(/\f/g, '\\f') // form feed + .replace(/\r/g, '\\r') // carriage return + .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + + '"'; + } + + var result = { + /* + * Parses the input with a generated parser. If the parsing is successfull, + * returns a value explicitly or implicitly specified by the grammar from + * which the parser was generated (see |PEG.buildParser|). If the parsing is + * unsuccessful, throws |PEG.parser.SyntaxError| describing the error. + */ + parse: function(input, startRule) { + var parseFunctions = { + "start": parse_start, + "hexcolor": parse_hexcolor, + "hexcolorlong": parse_hexcolorlong, + "hexcolorshort": parse_hexcolorshort, + "hex": parse_hex, + "rgba": parse_rgba, + "shortcut": parse_shortcut, + "elements": parse_elements + }; + + if (startRule !== undefined) { + if (parseFunctions[startRule] === undefined) { + throw new Error("Invalid rule name: " + quote(startRule) + "."); + } + } else { + startRule = "start"; + } + + var pos = 0; + var reportFailures = 0; + var rightmostFailuresPos = 0; + var rightmostFailuresExpected = []; + + function padLeft(input, padding, length) { + var result = input; + + var padLength = length - input.length; + for (var i = 0; i < padLength; i++) { + result = padding + result; + } + + return result; + } + + function escape(ch) { + var charCode = ch.charCodeAt(0); + var escapeChar; + var length; + + if (charCode <= 0xFF) { + escapeChar = 'x'; + length = 2; + } else { + escapeChar = 'u'; + length = 4; + } + + return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); + } + + function matchFailed(failure) { + if (pos < rightmostFailuresPos) { + return; + } + + if (pos > rightmostFailuresPos) { + rightmostFailuresPos = pos; + rightmostFailuresExpected = []; + } + + rightmostFailuresExpected.push(failure); + } + + function parse_start() { + var result0; + + result0 = parse_hexcolor(); + if (result0 === null) { + result0 = parse_rgba(); + if (result0 === null) { + result0 = parse_shortcut(); + } + } + return result0; + } + + function parse_hexcolor() { + var result0; + var pos0; + + reportFailures++; + pos0 = pos; + result0 = parse_hexcolorshort(); + if (result0 === null) { + result0 = parse_hexcolorlong(); + } + if (result0 !== null) { + result0 = (function(offset, hex) { + var r = parseInt(hex.substring(0, 2), 16); + var g = parseInt(hex.substring(2, 4), 16); + var b = parseInt(hex.substring(4, 6), 16); + + var Color = require("app/models/properties/color"); + return new Color(r, g, b); + })(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("hexcolor"); + } + return result0; + } + + function parse_hexcolorlong() { + var result0, result1, result2; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 35) { + result0 = "#"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"#\""); + } + } + if (result0 !== null) { + result1 = []; + result2 = parse_hex(); + while (result2 !== null) { + result1.push(result2); + result2 = parse_hex(); + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, hexes) { + return hexes.join(''); + })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_hexcolorshort() { + var result0, result1, result2, result3; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 35) { + result0 = "#"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"#\""); + } + } + if (result0 !== null) { + result1 = parse_hex(); + if (result1 !== null) { + result2 = parse_hex(); + if (result2 !== null) { + result3 = parse_hex(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, h1, h2, h3) { + return h1 + h1 + h2 + h2 + h3 + h3; + })(pos0, result0[1], result0[2], result0[3]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_hex() { + var result0; + + if (/^[0-9a-fA-F]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[0-9a-fA-F]"); + } + } + return result0; + } + + function parse_rgba() { + var result0, result1, result2; + var pos0, pos1; + + reportFailures++; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 4) === "rgb(") { + result0 = "rgb("; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"rgb(\""); + } + } + if (result0 !== null) { + result1 = parse_elements(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 41) { + result2 = ")"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + if (input.substr(pos, 5) === "rgba(") { + result0 = "rgba("; + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"rgba(\""); + } + } + if (result0 !== null) { + result1 = parse_elements(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 41) { + result2 = ")"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } + if (result0 !== null) { + result0 = (function(offset) { + elements = elements.map(function(i){ return parseFloat(i) }); + + var Color = require('app/models/properties/color'); + return new Color(elements[0], elements[1], elements[2], elements[3]); + })(pos0); + } + if (result0 === null) { + pos = pos0; + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("rgba"); + } + return result0; + } + + function parse_shortcut() { + var result0; + + reportFailures++; + if (input.substr(pos, 3) === "red") { + result0 = "red"; + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"red\""); + } + } + if (result0 === null) { + if (input.substr(pos, 3) === "tan") { + result0 = "tan"; + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"tan\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "grey") { + result0 = "grey"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"grey\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "gray") { + result0 = "gray"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"gray\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "lime") { + result0 = "lime"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"lime\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "navy") { + result0 = "navy"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"navy\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "blue") { + result0 = "blue"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"blue\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "teal") { + result0 = "teal"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"teal\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "aqua") { + result0 = "aqua"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"aqua\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "cyan") { + result0 = "cyan"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"cyan\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "gold") { + result0 = "gold"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"gold\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "peru") { + result0 = "peru"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"peru\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "pink") { + result0 = "pink"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"pink\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "plum") { + result0 = "plum"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"plum\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4) === "snow") { + result0 = "snow"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"snow\""); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("shortcut"); + } + return result0; + } + + function parse_elements() { + var result0, result1, result2, result3, result4; + var pos0, pos1, pos2; + + pos0 = pos; + pos1 = pos; + result0 = []; + if (input.length > pos) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + while (result1 !== null) { + result0.push(result1); + if (input.length > pos) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + } + if (result0 !== null) { + result1 = []; + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result2 = ","; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result2 !== null) { + result3 = []; + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + while (result4 !== null) { + result3.push(result4); + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + } + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result2 = ","; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result2 !== null) { + result3 = []; + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + while (result4 !== null) { + result3.push(result4); + if (input.length > pos) { + result4 = input.charAt(pos); + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + } + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, head, tail) { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][2]); + } + return result; + })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + + function cleanupExpected(expected) { + expected.sort(); + + var lastExpected = null; + var cleanExpected = []; + for (var i = 0; i < expected.length; i++) { + if (expected[i] !== lastExpected) { + cleanExpected.push(expected[i]); + lastExpected = expected[i]; + } + } + return cleanExpected; + } + + function computeErrorPosition() { + /* + * The first idea was to use |String.split| to break the input up to the + * error position along newlines and derive the line and column from + * there. However IE's |split| implementation is so broken that it was + * enough to prevent it. + */ + + var line = 1; + var column = 1; + var seenCR = false; + + for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) { + var ch = input.charAt(i); + if (ch === "\n") { + if (!seenCR) { line++; } + column = 1; + seenCR = false; + } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") { + line++; + column = 1; + seenCR = true; + } else { + column++; + seenCR = false; + } + } + + return { line: line, column: column }; + } + + + var result = parseFunctions[startRule](); + + /* + * The parser is now in one of the following three states: + * + * 1. The parser successfully parsed the whole input. + * + * - |result !== null| + * - |pos === input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 2. The parser successfully parsed only a part of the input. + * + * - |result !== null| + * - |pos < input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 3. The parser did not successfully parse any part of the input. + * + * - |result === null| + * - |pos === 0| + * - |rightmostFailuresExpected| contains at least one failure + * + * All code following this comment (including called functions) must + * handle these states. + */ + if (result === null || pos !== input.length) { + var offset = Math.max(pos, rightmostFailuresPos); + var found = offset < input.length ? input.charAt(offset) : null; + var errorPosition = computeErrorPosition(); + + throw new this.SyntaxError( + cleanupExpected(rightmostFailuresExpected), + found, + offset, + errorPosition.line, + errorPosition.column + ); + } + + return result; + }, + + /* Returns the parser source code. */ + toSource: function() { return this._source; } + }; + + /* Thrown when a parser encounters a syntax error. */ + + result.SyntaxError = function(expected, found, offset, line, column) { + function buildMessage(expected, found) { + var expectedHumanized, foundHumanized; + + switch (expected.length) { + case 0: + expectedHumanized = "end of input"; + break; + case 1: + expectedHumanized = expected[0]; + break; + default: + expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + + " or " + + expected[expected.length - 1]; + } + + foundHumanized = found ? quote(found) : "end of input"; + + return "Expected " + expectedHumanized + " but " + foundHumanized + " found."; + } + + this.name = "SyntaxError"; + this.expected = expected; + this.found = found; + this.message = buildMessage(expected, found); + this.offset = offset; + this.line = line; + this.column = column; + }; + + result.SyntaxError.prototype = Error.prototype; + + return result; +})(); +;}}); diff --git a/public/assets/parsers/color.pegjs b/public/assets/parsers/color.pegjs new file mode 100644 index 0000000..3f3e5d5 --- /dev/null +++ b/public/assets/parsers/color.pegjs @@ -0,0 +1,50 @@ +// CSS Color parser + +start + = hexcolor / rgba / shortcut + +hexcolor "hexcolor" + = hex:(hexcolorshort / hexcolorlong) { + var r = parseInt(hex.substring(0, 2), 16); + var g = parseInt(hex.substring(2, 4), 16); + var b = parseInt(hex.substring(4, 6), 16); + + var Color = require("app/models/properties/color"); + return new Color(r, g, b); + } + +hexcolorlong + = "#" (hexes:hex*) { + return hexes.join(''); + } + +hexcolorshort + = "#" h1:hex h2:hex h3:hex { + return h1 + h1 + h2 + h2 + h3 + h3; + } + +hex + = [0-9a-fA-F] + +rgba "rgba" + = ("rgb(" elements:elements ")" / "rgba(" elements:elements ")") { + elements = elements.map(function(i){ return parseFloat(i) }); + + var Color = require('app/models/properties/color'); + return new Color(elements[0], elements[1], elements[2], elements[3]); + } + +shortcut "shortcut" + = "red" / "tan" / "grey" / "gray" / "lime" / "navy" / "blue" / + "teal" / "aqua" / "cyan" / "gold" / "peru" / "pink" / "plum" / "snow" + +// Utilities + +elements + = head:.* tail:("," .*)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][2]); + } + return result; + } \ No newline at end of file diff --git a/public/assets/parsers/gradient.pegjs b/public/assets/parsers/gradient.pegjs new file mode 100644 index 0000000..e69de29 diff --git a/public/assets/parsers/json.module.js b/public/assets/parsers/json.module.js new file mode 100644 index 0000000..7457364 --- /dev/null +++ b/public/assets/parsers/json.module.js @@ -0,0 +1,1682 @@ +(function() { + if (!this.require) { + var modules = {}, cache = {}; + + var require = function(name, root) { + var path = expand(root, name), indexPath = expand(path, './index'), module, fn; + module = cache[path] || cache[indexPath]; + if (module) { + return module; + } else if (fn = modules[path] || modules[path = indexPath]) { + module = {id: path, exports: {}}; + cache[path] = module.exports; + fn(module.exports, function(name) { + return require(name, dirname(path)); + }, module); + return cache[path] = module.exports; + } else { + throw 'module ' + name + ' not found'; + } + }; + + var expand = function(root, name) { + var results = [], parts, part; + // If path is relative + if (/^\.\.?(\/|$)/.test(name)) { + parts = [root, name].join('/').split('/'); + } else { + parts = name.split('/'); + } + for (var i = 0, length = parts.length; i < length; i++) { + part = parts[i]; + if (part == '..') { + results.pop(); + } else if (part != '.' && part != '') { + results.push(part); + } + } + return results.join('/'); + }; + + var dirname = function(path) { + return path.split('/').slice(0, -1).join('/'); + }; + + this.require = function(name) { + return require(name, ''); + }; + + this.require.define = function(bundle) { + for (var key in bundle) { + modules[key] = bundle[key]; + } + }; + + this.require.modules = modules; + this.require.cache = cache; + } + + return this.require; +}).call(this); +this.require.define({"parsers/json":function(exports, require, module){module.exports = (function(){ + /* + * Generated by PEG.js 0.6.2. + * + * http://pegjs.majda.cz/ + */ + + function quote(s) { + /* + * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a + * string literal except for the closing quote character, backslash, + * carriage return, line separator, paragraph separator, and line feed. + * Any character may appear in the form of an escape sequence. + * + * For portability, we also escape escape all control and non-ASCII + * characters. Note that "\0" and "\v" escape sequences are not used + * because JSHint does not like the first and IE the second. + */ + return '"' + s + .replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing quote character + .replace(/\x08/g, '\\b') // backspace + .replace(/\t/g, '\\t') // horizontal tab + .replace(/\n/g, '\\n') // line feed + .replace(/\f/g, '\\f') // form feed + .replace(/\r/g, '\\r') // carriage return + .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + + '"'; + } + + var result = { + /* + * Parses the input with a generated parser. If the parsing is successfull, + * returns a value explicitly or implicitly specified by the grammar from + * which the parser was generated (see |PEG.buildParser|). If the parsing is + * unsuccessful, throws |PEG.parser.SyntaxError| describing the error. + */ + parse: function(input, startRule) { + var parseFunctions = { + "start": parse_start, + "object": parse_object, + "members": parse_members, + "pair": parse_pair, + "array": parse_array, + "elements": parse_elements, + "value": parse_value, + "string": parse_string, + "chars": parse_chars, + "char": parse_char, + "number": parse_number, + "int": parse_int, + "frac": parse_frac, + "exp": parse_exp, + "digits": parse_digits, + "e": parse_e, + "digit": parse_digit, + "digit19": parse_digit19, + "hexDigit": parse_hexDigit, + "_": parse__, + "whitespace": parse_whitespace + }; + + if (startRule !== undefined) { + if (parseFunctions[startRule] === undefined) { + throw new Error("Invalid rule name: " + quote(startRule) + "."); + } + } else { + startRule = "start"; + } + + var pos = 0; + var reportFailures = 0; + var rightmostFailuresPos = 0; + var rightmostFailuresExpected = []; + + function padLeft(input, padding, length) { + var result = input; + + var padLength = length - input.length; + for (var i = 0; i < padLength; i++) { + result = padding + result; + } + + return result; + } + + function escape(ch) { + var charCode = ch.charCodeAt(0); + var escapeChar; + var length; + + if (charCode <= 0xFF) { + escapeChar = 'x'; + length = 2; + } else { + escapeChar = 'u'; + length = 4; + } + + return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); + } + + function matchFailed(failure) { + if (pos < rightmostFailuresPos) { + return; + } + + if (pos > rightmostFailuresPos) { + rightmostFailuresPos = pos; + rightmostFailuresExpected = []; + } + + rightmostFailuresExpected.push(failure); + } + + function parse_start() { + var result0, result1; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + result0 = parse__(); + if (result0 !== null) { + result1 = parse_object(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, object) { return object; })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_object() { + var result0, result1, result2, result3, result4; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 123) { + result0 = "{"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"{\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 125) { + result2 = "}"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"}\""); + } + } + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset) { return {}; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 123) { + result0 = "{"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"{\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result2 = parse_members(); + if (result2 !== null) { + if (input.charCodeAt(pos) === 125) { + result3 = "}"; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\"}\""); + } + } + if (result3 !== null) { + result4 = parse__(); + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, members) { return members; })(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + } + return result0; + } + + function parse_members() { + var result0, result1, result2, result3, result4; + var pos0, pos1, pos2; + + pos0 = pos; + pos1 = pos; + result0 = parse_pair(); + if (result0 !== null) { + result1 = []; + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result2 = ","; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + result4 = parse_pair(); + if (result4 !== null) { + result2 = [result2, result3, result4]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result2 = ","; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + result4 = parse_pair(); + if (result4 !== null) { + result2 = [result2, result3, result4]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, head, tail) { + var result = {}; + result[head[0]] = head[1]; + for (var i = 0; i < tail.length; i++) { + result[tail[i][2][0]] = tail[i][2][1]; + } + return result; + })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_pair() { + var result0, result1, result2, result3; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + result0 = parse_string(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse__(); + if (result2 !== null) { + result3 = parse_value(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, name, value) { return [name, value]; })(pos0, result0[0], result0[3]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_array() { + var result0, result1, result2, result3, result4; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 91) { + result0 = "["; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"[\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 93) { + result2 = "]"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"]\""); + } + } + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset) { return []; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 91) { + result0 = "["; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"[\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result2 = parse_elements(); + if (result2 !== null) { + if (input.charCodeAt(pos) === 93) { + result3 = "]"; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\"]\""); + } + } + if (result3 !== null) { + result4 = parse__(); + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, elements) { return elements; })(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + } + return result0; + } + + function parse_elements() { + var result0, result1, result2, result3, result4; + var pos0, pos1, pos2; + + pos0 = pos; + pos1 = pos; + result0 = parse_value(); + if (result0 !== null) { + result1 = []; + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result2 = ","; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + result4 = parse_value(); + if (result4 !== null) { + result2 = [result2, result3, result4]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result2 = ","; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + result4 = parse_value(); + if (result4 !== null) { + result2 = [result2, result3, result4]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, head, tail) { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][2]); + } + return result; + })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_value() { + var result0, result1; + var pos0, pos1; + + result0 = parse_string(); + if (result0 === null) { + result0 = parse_number(); + if (result0 === null) { + result0 = parse_object(); + if (result0 === null) { + result0 = parse_array(); + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 4) === "true") { + result0 = "true"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"true\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset) { return true; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 5) === "false") { + result0 = "false"; + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"false\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset) { return false; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 4) === "null") { + result0 = "null"; + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"null\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset) { return "null"; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + } + } + } + } + } + } + return result0; + } + + function parse_string() { + var result0, result1, result2, result3; + var pos0, pos1; + + reportFailures++; + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 34) { + result0 = "\""; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\"\""); + } + } + if (result0 !== null) { + if (input.charCodeAt(pos) === 34) { + result1 = "\""; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"\\\"\""); + } + } + if (result1 !== null) { + result2 = parse__(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset) { return ""; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 34) { + result0 = "\""; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\"\""); + } + } + if (result0 !== null) { + result1 = parse_chars(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 34) { + result2 = "\""; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"\\\"\""); + } + } + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, chars) { return chars; })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("string"); + } + return result0; + } + + function parse_chars() { + var result0, result1; + var pos0; + + pos0 = pos; + result1 = parse_char(); + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_char(); + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = (function(offset, chars) { return chars.join(""); })(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_char() { + var result0, result1, result2, result3, result4; + var pos0, pos1; + + if (/^[^"\\\0-\x1F]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[^\"\\\\\\0-\\x1F]"); + } + } + if (result0 === null) { + pos0 = pos; + if (input.substr(pos, 2) === "\\\"") { + result0 = "\\\""; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\\\\"\""); + } + } + if (result0 !== null) { + result0 = (function(offset) { return '"'; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + if (input.substr(pos, 2) === "\\\\") { + result0 = "\\\\"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\\\\\\""); + } + } + if (result0 !== null) { + result0 = (function(offset) { return "\\"; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + if (input.substr(pos, 2) === "\\/") { + result0 = "\\/"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\/\""); + } + } + if (result0 !== null) { + result0 = (function(offset) { return "/"; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + if (input.substr(pos, 2) === "\\b") { + result0 = "\\b"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\b\""); + } + } + if (result0 !== null) { + result0 = (function(offset) { return "\b"; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + if (input.substr(pos, 2) === "\\f") { + result0 = "\\f"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\f\""); + } + } + if (result0 !== null) { + result0 = (function(offset) { return "\f"; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + if (input.substr(pos, 2) === "\\n") { + result0 = "\\n"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\n\""); + } + } + if (result0 !== null) { + result0 = (function(offset) { return "\n"; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + if (input.substr(pos, 2) === "\\r") { + result0 = "\\r"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\r\""); + } + } + if (result0 !== null) { + result0 = (function(offset) { return "\r"; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + if (input.substr(pos, 2) === "\\t") { + result0 = "\\t"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\t\""); + } + } + if (result0 !== null) { + result0 = (function(offset) { return "\t"; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 2) === "\\u") { + result0 = "\\u"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\u\""); + } + } + if (result0 !== null) { + result1 = parse_hexDigit(); + if (result1 !== null) { + result2 = parse_hexDigit(); + if (result2 !== null) { + result3 = parse_hexDigit(); + if (result3 !== null) { + result4 = parse_hexDigit(); + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, h1, h2, h3, h4) { + return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4)); + })(pos0, result0[1], result0[2], result0[3], result0[4]); + } + if (result0 === null) { + pos = pos0; + } + } + } + } + } + } + } + } + } + } + return result0; + } + + function parse_number() { + var result0, result1, result2, result3; + var pos0, pos1; + + reportFailures++; + pos0 = pos; + pos1 = pos; + result0 = parse_int(); + if (result0 !== null) { + result1 = parse_frac(); + if (result1 !== null) { + result2 = parse_exp(); + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, int_, frac, exp) { return parseFloat(int_ + frac + exp); })(pos0, result0[0], result0[1], result0[2]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + result0 = parse_int(); + if (result0 !== null) { + result1 = parse_frac(); + if (result1 !== null) { + result2 = parse__(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, int_, frac) { return parseFloat(int_ + frac); })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + result0 = parse_int(); + if (result0 !== null) { + result1 = parse_exp(); + if (result1 !== null) { + result2 = parse__(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, int_, exp) { return parseFloat(int_ + exp); })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + result0 = parse_int(); + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, int_) { return parseFloat(int_); })(pos0, result0[0]); + } + if (result0 === null) { + pos = pos0; + } + } + } + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("number"); + } + return result0; + } + + function parse_int() { + var result0, result1, result2; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + result0 = parse_digit19(); + if (result0 !== null) { + result1 = parse_digits(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, digit19, digits) { return digit19 + digits; })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + result0 = parse_digit(); + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 45) { + result0 = "-"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result0 !== null) { + result1 = parse_digit19(); + if (result1 !== null) { + result2 = parse_digits(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, digit19, digits) { return "-" + digit19 + digits; })(pos0, result0[1], result0[2]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 45) { + result0 = "-"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result0 !== null) { + result1 = parse_digit(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, digit) { return "-" + digit; })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + } + } + } + return result0; + } + + function parse_frac() { + var result0, result1; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 46) { + result0 = "."; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result0 !== null) { + result1 = parse_digits(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, digits) { return "." + digits; })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_exp() { + var result0, result1; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + result0 = parse_e(); + if (result0 !== null) { + result1 = parse_digits(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, e, digits) { return e + digits; })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_digits() { + var result0, result1; + var pos0; + + pos0 = pos; + result1 = parse_digit(); + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_digit(); + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = (function(offset, digits) { return digits.join(""); })(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_e() { + var result0, result1; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (/^[eE]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[eE]"); + } + } + if (result0 !== null) { + if (/^[+\-]/.test(input.charAt(pos))) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("[+\\-]"); + } + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, e, sign) { return e + sign; })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + + function parse_digit() { + var result0; + + if (/^[0-9]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[0-9]"); + } + } + return result0; + } + + function parse_digit19() { + var result0; + + if (/^[1-9]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[1-9]"); + } + } + return result0; + } + + function parse_hexDigit() { + var result0; + + if (/^[0-9a-fA-F]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[0-9a-fA-F]"); + } + } + return result0; + } + + function parse__() { + var result0, result1; + + reportFailures++; + result0 = []; + result1 = parse_whitespace(); + while (result1 !== null) { + result0.push(result1); + result1 = parse_whitespace(); + } + reportFailures--; + if (reportFailures === 0 && result0 === null) { + matchFailed("whitespace"); + } + return result0; + } + + function parse_whitespace() { + var result0; + + if (/^[ \t\n\r]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[ \\t\\n\\r]"); + } + } + return result0; + } + + + function cleanupExpected(expected) { + expected.sort(); + + var lastExpected = null; + var cleanExpected = []; + for (var i = 0; i < expected.length; i++) { + if (expected[i] !== lastExpected) { + cleanExpected.push(expected[i]); + lastExpected = expected[i]; + } + } + return cleanExpected; + } + + function computeErrorPosition() { + /* + * The first idea was to use |String.split| to break the input up to the + * error position along newlines and derive the line and column from + * there. However IE's |split| implementation is so broken that it was + * enough to prevent it. + */ + + var line = 1; + var column = 1; + var seenCR = false; + + for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) { + var ch = input.charAt(i); + if (ch === "\n") { + if (!seenCR) { line++; } + column = 1; + seenCR = false; + } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") { + line++; + column = 1; + seenCR = true; + } else { + column++; + seenCR = false; + } + } + + return { line: line, column: column }; + } + + + var result = parseFunctions[startRule](); + + /* + * The parser is now in one of the following three states: + * + * 1. The parser successfully parsed the whole input. + * + * - |result !== null| + * - |pos === input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 2. The parser successfully parsed only a part of the input. + * + * - |result !== null| + * - |pos < input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 3. The parser did not successfully parse any part of the input. + * + * - |result === null| + * - |pos === 0| + * - |rightmostFailuresExpected| contains at least one failure + * + * All code following this comment (including called functions) must + * handle these states. + */ + if (result === null || pos !== input.length) { + var offset = Math.max(pos, rightmostFailuresPos); + var found = offset < input.length ? input.charAt(offset) : null; + var errorPosition = computeErrorPosition(); + + throw new this.SyntaxError( + cleanupExpected(rightmostFailuresExpected), + found, + offset, + errorPosition.line, + errorPosition.column + ); + } + + return result; + }, + + /* Returns the parser source code. */ + toSource: function() { return this._source; } + }; + + /* Thrown when a parser encounters a syntax error. */ + + result.SyntaxError = function(expected, found, offset, line, column) { + function buildMessage(expected, found) { + var expectedHumanized, foundHumanized; + + switch (expected.length) { + case 0: + expectedHumanized = "end of input"; + break; + case 1: + expectedHumanized = expected[0]; + break; + default: + expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + + " or " + + expected[expected.length - 1]; + } + + foundHumanized = found ? quote(found) : "end of input"; + + return "Expected " + expectedHumanized + " but " + foundHumanized + " found."; + } + + this.name = "SyntaxError"; + this.expected = expected; + this.found = found; + this.message = buildMessage(expected, found); + this.offset = offset; + this.line = line; + this.column = column; + }; + + result.SyntaxError.prototype = Error.prototype; + + return result; +})(); +;}}); diff --git a/public/assets/parsers/json.pegjs b/public/assets/parsers/json.pegjs new file mode 100644 index 0000000..1fa492f --- /dev/null +++ b/public/assets/parsers/json.pegjs @@ -0,0 +1,120 @@ +/* JSON parser based on the grammar described at http://json.org/. */ + +/* ===== Syntactical Elements ===== */ + +start + = _ object:object { return object; } + +object + = "{" _ "}" _ { return {}; } + / "{" _ members:members "}" _ { return members; } + +members + = head:pair tail:("," _ pair)* { + var result = {}; + result[head[0]] = head[1]; + for (var i = 0; i < tail.length; i++) { + result[tail[i][2][0]] = tail[i][2][1]; + } + return result; + } + +pair + = name:string ":" _ value:value { return [name, value]; } + +array + = "[" _ "]" _ { return []; } + / "[" _ elements:elements "]" _ { return elements; } + +elements + = head:value tail:("," _ value)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][2]); + } + return result; + } + +value + = string + / number + / object + / array + / "true" _ { return true; } + / "false" _ { return false; } + // FIXME: We can't return null here because that would mean parse failure. + / "null" _ { return "null"; } + +/* ===== Lexical Elements ===== */ + +string "string" + = '"' '"' _ { return ""; } + / '"' chars:chars '"' _ { return chars; } + +chars + = chars:char+ { return chars.join(""); } + +char + // In the original JSON grammar: "any-Unicode-character-except-"-or-\-or-control-character" + = [^"\\\0-\x1F\x7f] + / '\\"' { return '"'; } + / "\\\\" { return "\\"; } + / "\\/" { return "/"; } + / "\\b" { return "\b"; } + / "\\f" { return "\f"; } + / "\\n" { return "\n"; } + / "\\r" { return "\r"; } + / "\\t" { return "\t"; } + / "\\u" h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit { + return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4)); + } + +number "number" + = int_:int frac:frac exp:exp _ { return parseFloat(int_ + frac + exp); } + / int_:int frac:frac _ { return parseFloat(int_ + frac); } + / int_:int exp:exp _ { return parseFloat(int_ + exp); } + / int_:int _ { return parseFloat(int_); } + +int + = digit19:digit19 digits:digits { return digit19 + digits; } + / digit:digit + / "-" digit19:digit19 digits:digits { return "-" + digit19 + digits; } + / "-" digit:digit { return "-" + digit; } + +frac + = "." digits:digits { return "." + digits; } + +exp + = e:e digits:digits { return e + digits; } + +digits + = digits:digit+ { return digits.join(""); } + +e + = e:[eE] sign:[+-]? { return e + sign; } + +/* + * The following rules are not present in the original JSON gramar, but they are + * assumed to exist implicitly. + * + * FIXME: Define them according to ECMA-262, 5th ed. + */ + +digit + = [0-9] + +digit19 + = [1-9] + +hexDigit + = [0-9a-fA-F] + +/* ===== Whitespace ===== */ + +_ "whitespace" + = whitespace* + +// Whitespace is undefined in the original JSON grammar, so I assume a simple +// conventional definition consistent with ECMA-262, 5th ed. +whitespace + = [ \t\n\r] \ No newline at end of file diff --git a/public/assets/parsers/shadow.peg b/public/assets/parsers/shadow.peg new file mode 100644 index 0000000..e69de29 diff --git a/public/assets/parsers/shadow.pegjs b/public/assets/parsers/shadow.pegjs new file mode 100644 index 0000000..b493451 --- /dev/null +++ b/public/assets/parsers/shadow.pegjs @@ -0,0 +1,49 @@ +// CSS Shadow parser + +start + = inset:"inset"? color:color (values:px _ *) { + var Shadow = require('app/models/properties/shadow'); + var props = {}; + props.inset = !!inset; + props.x = values[0]; + props.y = values[1]; + props.blur = values[2]; + props.spread = values[3]; + return new Shadow(options); + } + +px + = number "px" + +number "number" + = int_:int frac:frac exp:exp _ { return parseFloat(int_ + frac + exp); } + / int_:int frac:frac _ { return parseFloat(int_ + frac); } + / int_:int exp:exp _ { return parseFloat(int_ + exp); } + / int_:int _ { return parseFloat(int_); } + +int + = digit19:digit19 digits:digits { return digit19 + digits; } + / digit:digit + / "-" digit19:digit19 digits:digits { return "-" + digit19 + digits; } + / "-" digit:digit { return "-" + digit; } + +frac + = "." digits:digits { return "." + digits; } + +exp + = e:e digits:digits { return e + digits; } + +digits + = digits:digit+ { return digits.join(""); } + +digit + = [0-9] + +digit19 + = [1-9] + +_ "whitespace" + = whitespace* + +whitespace + = [ \t\n\r] \ No newline at end of file