From e7cb84b1d9049c1d3674fcb31e990d6af12e3360 Mon Sep 17 00:00:00 2001 From: knsv Date: Wed, 12 Nov 2014 07:35:44 +0100 Subject: [PATCH] =?UTF-8?q?Support=20for=20=C3=A5=C3=A4=C3=B6=20and=20minu?= =?UTF-8?q?s=20in=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gulpfile.js | 5 + src/init.js | 8 +- src/mermaid.html | 2 +- src/mermaid.js | 18 +- src/parser/flow.jison | 69 ++ src/parser/flow.js | 660 +++++++++++++++ src/parser/flow.spec.js | 22 + src/parser/mermaid.jison | 7 +- src/parser/mermaid.js | 38 +- src/parser/mermaid.spec.js | 21 +- src/parser/mermaid2.js | 743 +++++++++++++++++ src/parser/test.txt | 1573 ++++++++++++++++++++++++++++++++++++ test/test-main.js | 5 +- 13 files changed, 3134 insertions(+), 37 deletions(-) create mode 100644 src/parser/flow.jison create mode 100644 src/parser/flow.js create mode 100644 src/parser/flow.spec.js create mode 100644 src/parser/mermaid2.js create mode 100644 src/parser/test.txt diff --git a/gulpfile.js b/gulpfile.js index 7776e04ec..9cdac3ed2 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -11,4 +11,9 @@ gulp.task('jison2', function() { gulp.task('jison', shell.task([ 'jison src/parser/mermaid.jison -o src/parser/mermaid.js', 'source scripts/compileJison.sh' +])) + +gulp.task('jison2', shell.task([ + 'jison src/parser/flow.jison -o src/parser/flow.js', + 'source scripts/compileFlow.sh' ])) \ No newline at end of file diff --git a/src/init.js b/src/init.js index 8002fa2f1..484532a63 100644 --- a/src/init.js +++ b/src/init.js @@ -1,4 +1,4 @@ - +/* require.config({ // Karma serves files from '/base' baseUrl: './' @@ -7,4 +7,8 @@ require.config({ require(['mermaid'],function(mermaid){ mermaid.init(); -}); \ No newline at end of file +}); + + */ + +console.log('Init running'); \ No newline at end of file diff --git a/src/mermaid.html b/src/mermaid.html index 84e0e147f..21729901f 100644 --- a/src/mermaid.html +++ b/src/mermaid.html @@ -18,7 +18,7 @@ .node rect { stroke: #999; - fill: #fff; + fill: #f99; stroke-width: 1.5px; } diff --git a/src/mermaid.js b/src/mermaid.js index bd6d6a1a5..d2803d8b2 100644 --- a/src/mermaid.js +++ b/src/mermaid.js @@ -30,7 +30,7 @@ define('mermaid',['parser/graph','parser/mermaid'],function(graph,parser){ if(style === ''){ - style = graph.defaultStyle(); + //style = graph.defaultStyle(); } console.log('g.setNode("'+vertice.id+'", { label: "'+verticeText+'" });'); @@ -38,8 +38,7 @@ define('mermaid',['parser/graph','parser/mermaid'],function(graph,parser){ g.setNode(vertice.id, { label: verticeText,rx:5,ry:5,style:style }); }else{ if(vertice.type==='diamond'){ - //g.setNode(vertice.id, {shape: "house", label: verticeText,rx:0,ry:0,style: "fill:#ffa;stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;fill:#ffa;stroke: #666;" }); - g.setNode(vertice.id, {shape: "house", label: verticeText,rx:0,ry:0,style: style }); + g.setNode(vertice.id, {shape: "question", label: verticeText,rx:0,ry:0,style: style }); }else{ g.setNode(vertice.id, { label: verticeText,rx:0,ry:0,style:style }); } @@ -93,16 +92,11 @@ define('mermaid',['parser/graph','parser/mermaid'],function(graph,parser){ addVertices(vert,g); addEdges(edges,g); - /*g.nodes().forEach(function(v) { - var node = g.node(v); - // Round the corners of the nodes - node.rx = node.ry = 5; - }); -*/ // Create the renderer var render = new dagreD3.render(); -// Add our custom shape (a house) - render.shapes().house = function(parent, bbox, node) { + + // Add our custom shape + render.shapes().question = function(parent, bbox, node) { var w = bbox.width, h = bbox.height*3, points = [ @@ -115,6 +109,8 @@ define('mermaid',['parser/graph','parser/mermaid'],function(graph,parser){ .attr("points", points.map(function(d) { return d.x + "," + d.y; }).join(" ")) .style("fill", "#fff") .style("stroke", "#333") + .attr("rx", 5) + .attr("ry", 5) .attr("transform", "translate(" + (-w/2) + "," + (h * 2/4) + ")"); node.intersect = function(point) { return dagreD3.intersect.polygon(node, points, point); diff --git a/src/parser/flow.jison b/src/parser/flow.jison new file mode 100644 index 000000000..3b1faf083 --- /dev/null +++ b/src/parser/flow.jison @@ -0,0 +1,69 @@ +/* description: Parses end executes mathematical expressions. */ + +/* lexical grammar */ +%lex + +%% +"style" return 'STYLE'; +[a-zåäöæøA-ZÅÄÖÆØ]+ return 'ALPHA'; +\#[a-f0-9]+ return 'HEX'; +[0-9]+ return 'NUM'; +"px" return 'UNIT'; +"pt" return 'UNIT'; +"dot" return 'UNIT'; +":" return 'COLON'; +\- return 'MINUS'; +";" return ';'; +"," return 'COMMA'; +[x] return 'ARROW_CROSS'; +">" return 'ARROW_POINT'; +[o] return 'ARROW_CIRCLE'; +"|" return 'PIPE'; +"(" return 'PS'; +")" return 'PE'; +"[" return 'SQS'; +"]" return 'SQE'; +"{" return 'DIAMOND_START' +"}" return 'DIAMOND_STOP' +\s return 'SPACE'; +\n return 'NEWLINE'; +<> return 'EOF'; + +/lex + +/* operator associations and precedence */ + +%left '^' + +%start expressions + +%% /* language grammar */ + +expressions + : id EOF + {return $1;} + ; + +flow: id + {$$='key';} + | STYLE + {$$=$1;} + ; + +id: id MINUS word + {$$=$1+'-'+$3} + | word + {$$=$1} + ; + +word: ALPHA + {$$=$1} + ; + + + +%% +define('parser/flow',function(){ + console.log('bcs123'); + return parser; +}); \ No newline at end of file diff --git a/src/parser/flow.js b/src/parser/flow.js new file mode 100644 index 000000000..05d756170 --- /dev/null +++ b/src/parser/flow.js @@ -0,0 +1,660 @@ +/* parser generated by jison 0.4.15 */ +/* + Returns a Parser object of the following structure: + + Parser: { + yy: {} + } + + Parser.prototype: { + yy: {}, + trace: function(), + symbols_: {associative list: name ==> number}, + terminals_: {associative list: number ==> name}, + productions_: [...], + performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), + table: [...], + defaultActions: {...}, + parseError: function(str, hash), + parse: function(input), + + lexer: { + EOF: 1, + parseError: function(str, hash), + setInput: function(input), + input: function(), + unput: function(str), + more: function(), + less: function(n), + pastInput: function(), + upcomingInput: function(), + showPosition: function(), + test_match: function(regex_match_array, rule_index), + next: function(), + lex: function(), + begin: function(condition), + popState: function(), + _currentRules: function(), + topState: function(), + pushState: function(condition), + + options: { + ranges: boolean (optional: true ==> token location info will include a .range[] member) + flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) + backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) + }, + + performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), + rules: [...], + conditions: {associative list: name ==> set}, + } + } + + + token location info (@$, _$, etc.): { + first_line: n, + last_line: n, + first_column: n, + last_column: n, + range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) + } + + + the parseError function receives a 'hash' object with these members for lexer and parser errors: { + text: (matched text) + token: (the produced terminal token, if any) + line: (yylineno) + } + while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { + loc: (yylloc) + expected: (string describing the set of expected tokens) + recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) + } +*/ +var parser = (function(){ +var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,4],$V1=[5,8]; +var parser = {trace: function trace() { }, +yy: {}, +symbols_: {"error":2,"expressions":3,"id":4,"EOF":5,"flow":6,"STYLE":7,"MINUS":8,"word":9,"ALPHA":10,"$accept":0,"$end":1}, +terminals_: {2:"error",5:"EOF",7:"STYLE",8:"MINUS",10:"ALPHA"}, +productions_: [0,[3,2],[6,1],[6,1],[4,3],[4,1],[9,1]], +performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { +/* this == yyval */ + +var $0 = $$.length - 1; +switch (yystate) { +case 1: +return $$[$0-1]; +break; +case 2: +this.$='key'; +break; +case 3: +this.$=$$[$0]; +break; +case 4: +this.$=$$[$0-2]+'-'+$$[$0] +break; +case 5: case 6: +this.$=$$[$0] +break; +} +}, +table: [{3:1,4:2,9:3,10:$V0},{1:[3]},{5:[1,5],8:[1,6]},o($V1,[2,5]),o($V1,[2,6]),{1:[2,1]},{9:7,10:$V0},o($V1,[2,4])], +defaultActions: {5:[2,1]}, +parseError: function parseError(str, hash) { + if (hash.recoverable) { + this.trace(str); + } else { + throw new Error(str); + } +}, +parse: function parse(input) { + var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; + var args = lstack.slice.call(arguments, 1); + var lexer = Object.create(this.lexer); + var sharedState = { yy: {} }; + for (var k in this.yy) { + if (Object.prototype.hasOwnProperty.call(this.yy, k)) { + sharedState.yy[k] = this.yy[k]; + } + } + lexer.setInput(input, sharedState.yy); + sharedState.yy.lexer = lexer; + sharedState.yy.parser = this; + if (typeof lexer.yylloc == 'undefined') { + lexer.yylloc = {}; + } + var yyloc = lexer.yylloc; + lstack.push(yyloc); + var ranges = lexer.options && lexer.options.ranges; + if (typeof sharedState.yy.parseError === 'function') { + this.parseError = sharedState.yy.parseError; + } else { + this.parseError = Object.getPrototypeOf(this).parseError; + } + function popStack(n) { + stack.length = stack.length - 2 * n; + vstack.length = vstack.length - n; + lstack.length = lstack.length - n; + } + _token_stack: + function lex() { + var token; + token = lexer.lex() || EOF; + if (typeof token !== 'number') { + token = self.symbols_[token] || token; + } + return token; + } + var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; + while (true) { + state = stack[stack.length - 1]; + if (this.defaultActions[state]) { + action = this.defaultActions[state]; + } else { + if (symbol === null || typeof symbol == 'undefined') { + symbol = lex(); + } + action = table[state] && table[state][symbol]; + } + if (typeof action === 'undefined' || !action.length || !action[0]) { + var errStr = ''; + expected = []; + for (p in table[state]) { + if (this.terminals_[p] && p > TERROR) { + expected.push('\'' + this.terminals_[p] + '\''); + } + } + if (lexer.showPosition) { + errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; + } else { + errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); + } + console.log(errStr, { + text: lexer.match, + token: this.terminals_[symbol] || symbol, + line: lexer.yylineno, + loc: yyloc, + expected: expected + }); + } + if (action[0] instanceof Array && action.length > 1) { + throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); + } + switch (action[0]) { + case 1: + stack.push(symbol); + vstack.push(lexer.yytext); + lstack.push(lexer.yylloc); + stack.push(action[1]); + symbol = null; + if (!preErrorSymbol) { + yyleng = lexer.yyleng; + yytext = lexer.yytext; + yylineno = lexer.yylineno; + yyloc = lexer.yylloc; + if (recovering > 0) { + recovering--; + } + } else { + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + case 2: + len = this.productions_[action[1]][1]; + yyval.$ = vstack[vstack.length - len]; + yyval._$ = { + first_line: lstack[lstack.length - (len || 1)].first_line, + last_line: lstack[lstack.length - 1].last_line, + first_column: lstack[lstack.length - (len || 1)].first_column, + last_column: lstack[lstack.length - 1].last_column + }; + if (ranges) { + yyval._$.range = [ + lstack[lstack.length - (len || 1)].range[0], + lstack[lstack.length - 1].range[1] + ]; + } + r = this.performAction.apply(yyval, [ + yytext, + yyleng, + yylineno, + sharedState.yy, + action[1], + vstack, + lstack + ].concat(args)); + if (typeof r !== 'undefined') { + return r; + } + if (len) { + stack = stack.slice(0, -1 * len * 2); + vstack = vstack.slice(0, -1 * len); + lstack = lstack.slice(0, -1 * len); + } + stack.push(this.productions_[action[1]][0]); + vstack.push(yyval.$); + lstack.push(yyval._$); + newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; + stack.push(newState); + break; + case 3: + return true; + } + } + return true; +}}; + +define('parser/flow',function(){ + console.log('bcs123'); + return parser; +});/* generated by jison-lex 0.3.4 */ +var lexer = (function(){ +var lexer = ({ + +EOF:1, + +parseError:function parseError(str, hash) { + if (this.yy.parser) { + this.yy.parser.parseError(str, hash); + } else { + throw new Error(str); + } + }, + +// resets the lexer, sets new input +setInput:function (input, yy) { + this.yy = yy || this.yy || {}; + this._input = input; + this._more = this._backtrack = this.done = false; + this.yylineno = this.yyleng = 0; + this.yytext = this.matched = this.match = ''; + this.conditionStack = ['INITIAL']; + this.yylloc = { + first_line: 1, + first_column: 0, + last_line: 1, + last_column: 0 + }; + if (this.options.ranges) { + this.yylloc.range = [0,0]; + } + this.offset = 0; + return this; + }, + +// consumes and returns one char from the input +input:function () { + var ch = this._input[0]; + this.yytext += ch; + this.yyleng++; + this.offset++; + this.match += ch; + this.matched += ch; + var lines = ch.match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno++; + this.yylloc.last_line++; + } else { + this.yylloc.last_column++; + } + if (this.options.ranges) { + this.yylloc.range[1]++; + } + + this._input = this._input.slice(1); + return ch; + }, + +// unshifts one char (or a string) into the input +unput:function (ch) { + var len = ch.length; + var lines = ch.split(/(?:\r\n?|\n)/g); + + this._input = ch + this._input; + this.yytext = this.yytext.substr(0, this.yytext.length - len); + //this.yyleng -= len; + this.offset -= len; + var oldLines = this.match.split(/(?:\r\n?|\n)/g); + this.match = this.match.substr(0, this.match.length - 1); + this.matched = this.matched.substr(0, this.matched.length - 1); + + if (lines.length - 1) { + this.yylineno -= lines.length - 1; + } + var r = this.yylloc.range; + + this.yylloc = { + first_line: this.yylloc.first_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.first_column, + last_column: lines ? + (lines.length === oldLines.length ? this.yylloc.first_column : 0) + + oldLines[oldLines.length - lines.length].length - lines[0].length : + this.yylloc.first_column - len + }; + + if (this.options.ranges) { + this.yylloc.range = [r[0], r[0] + this.yyleng - len]; + } + this.yyleng = this.yytext.length; + return this; + }, + +// When called from action, caches matched text and appends it on next action +more:function () { + this._more = true; + return this; + }, + +// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead. +reject:function () { + if (this.options.backtrack_lexer) { + this._backtrack = true; + } else { + return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), { + text: "", + token: null, + line: this.yylineno + }); + + } + return this; + }, + +// retain first n characters of the match +less:function (n) { + this.unput(this.match.slice(n)); + }, + +// displays already matched input, i.e. for error messages +pastInput:function () { + var past = this.matched.substr(0, this.matched.length - this.match.length); + return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); + }, + +// displays upcoming input, i.e. for error messages +upcomingInput:function () { + var next = this.match; + if (next.length < 20) { + next += this._input.substr(0, 20-next.length); + } + return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); + }, + +// displays the character position where the lexing error occurred, i.e. for error messages +showPosition:function () { + var pre = this.pastInput(); + var c = new Array(pre.length + 1).join("-"); + return pre + this.upcomingInput() + "\n" + c + "^"; + }, + +// test the lexed token: return FALSE when not a match, otherwise return token +test_match:function (match, indexed_rule) { + var token, + lines, + backup; + + if (this.options.backtrack_lexer) { + // save context + backup = { + yylineno: this.yylineno, + yylloc: { + first_line: this.yylloc.first_line, + last_line: this.last_line, + first_column: this.yylloc.first_column, + last_column: this.yylloc.last_column + }, + yytext: this.yytext, + match: this.match, + matches: this.matches, + matched: this.matched, + yyleng: this.yyleng, + offset: this.offset, + _more: this._more, + _input: this._input, + yy: this.yy, + conditionStack: this.conditionStack.slice(0), + done: this.done + }; + if (this.options.ranges) { + backup.yylloc.range = this.yylloc.range.slice(0); + } + } + + lines = match[0].match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno += lines.length; + } + this.yylloc = { + first_line: this.yylloc.last_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.last_column, + last_column: lines ? + lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : + this.yylloc.last_column + match[0].length + }; + this.yytext += match[0]; + this.match += match[0]; + this.matches = match; + this.yyleng = this.yytext.length; + if (this.options.ranges) { + this.yylloc.range = [this.offset, this.offset += this.yyleng]; + } + this._more = false; + this._backtrack = false; + this._input = this._input.slice(match[0].length); + this.matched += match[0]; + token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); + if (this.done && this._input) { + this.done = false; + } + if (token) { + return token; + } else if (this._backtrack) { + // recover context + for (var k in backup) { + this[k] = backup[k]; + } + return false; // rule action called reject() implying the next rule should be tested instead. + } + return false; + }, + +// return next match in input +next:function () { + if (this.done) { + return this.EOF; + } + if (!this._input) { + this.done = true; + } + + var token, + match, + tempMatch, + index; + if (!this._more) { + this.yytext = ''; + this.match = ''; + } + var rules = this._currentRules(); + for (var i = 0; i < rules.length; i++) { + tempMatch = this._input.match(this.rules[rules[i]]); + if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { + match = tempMatch; + index = i; + if (this.options.backtrack_lexer) { + token = this.test_match(tempMatch, rules[i]); + if (token !== false) { + return token; + } else if (this._backtrack) { + match = false; + continue; // rule action called reject() implying a rule MISmatch. + } else { + // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) + return false; + } + } else if (!this.options.flex) { + break; + } + } + } + if (match) { + token = this.test_match(match, rules[index]); + if (token !== false) { + return token; + } + // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) + return false; + } + if (this._input === "") { + return this.EOF; + } else { + return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { + text: "", + token: null, + line: this.yylineno + }); + } + }, + +// return next match that has a token +lex:function lex() { + var r = this.next(); + if (r) { + return r; + } else { + return this.lex(); + } + }, + +// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) +begin:function begin(condition) { + this.conditionStack.push(condition); + }, + +// pop the previously active lexer condition state off the condition stack +popState:function popState() { + var n = this.conditionStack.length - 1; + if (n > 0) { + return this.conditionStack.pop(); + } else { + return this.conditionStack[0]; + } + }, + +// produce the lexer rule set which is active for the currently active lexer condition state +_currentRules:function _currentRules() { + if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { + return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; + } else { + return this.conditions["INITIAL"].rules; + } + }, + +// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available +topState:function topState(n) { + n = this.conditionStack.length - 1 - Math.abs(n || 0); + if (n >= 0) { + return this.conditionStack[n]; + } else { + return "INITIAL"; + } + }, + +// alias for begin(condition) +pushState:function pushState(condition) { + this.begin(condition); + }, + +// return the number of states currently on the stack +stateStackSize:function stateStackSize() { + return this.conditionStack.length; + }, +options: {}, +performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { +var YYSTATE=YY_START; +switch($avoiding_name_collisions) { +case 0:return 7; +break; +case 1:return 10; +break; +case 2:return 'HEX'; +break; +case 3:return 'NUM'; +break; +case 4:return 'UNIT'; +break; +case 5:return 'UNIT'; +break; +case 6:return 'UNIT'; +break; +case 7:return 'COLON'; +break; +case 8:return 8; +break; +case 9:return ';'; +break; +case 10:return 'COMMA'; +break; +case 11:return 'ARROW_CROSS'; +break; +case 12:return 'ARROW_POINT'; +break; +case 13:return 'ARROW_CIRCLE'; +break; +case 14:return 'PIPE'; +break; +case 15:return 'PS'; +break; +case 16:return 'PE'; +break; +case 17:return 'SQS'; +break; +case 18:return 'SQE'; +break; +case 19:return 'DIAMOND_START' +break; +case 20:return 'DIAMOND_STOP' +break; +case 21:return 'SPACE'; +break; +case 22:return 'NEWLINE'; +break; +case 23:return 5; +break; +} +}, +rules: [/^(?:style\b)/,/^(?:[a-zåäöæøA-ZÅÄÖÆØ]+)/,/^(?:#[a-f0-9]+)/,/^(?:[0-9]+)/,/^(?:px\b)/,/^(?:pt\b)/,/^(?:dot\b)/,/^(?::)/,/^(?:-)/,/^(?:;)/,/^(?:,)/,/^(?:[x])/,/^(?:>)/,/^(?:[o])/,/^(?:\|)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:\s)/,/^(?:\n)/,/^(?:$)/], +conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],"inclusive":true}} +}); +return lexer; +})(); +parser.lexer = lexer; +function Parser () { + this.yy = {}; +} +Parser.prototype = parser;parser.Parser = Parser; +return new Parser; +})(); + + +if (typeof require !== 'undefined' && typeof exports !== 'undefined') { +exports.parser = parser; +exports.Parser = parser.Parser; +exports.parse = function () { return parser.parse.apply(parser, arguments); }; +exports.main = function commonjsMain(args) { + if (!args[1]) { + console.log('Usage: '+args[0]+' FILE'); + process.exit(1); + } + var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8"); + return exports.parser.parse(source); +}; +if (typeof module !== 'undefined' && require.main === module) { + exports.main(process.argv.slice(1)); +} +} diff --git a/src/parser/flow.spec.js b/src/parser/flow.spec.js new file mode 100644 index 000000000..61d4e8ab0 --- /dev/null +++ b/src/parser/flow.spec.js @@ -0,0 +1,22 @@ +/** + * Created by knut on 14-11-03. + */ +define('parser/flow.spec',['parser/graph','parser/flow'],function(graph, p){ + + describe('when parsing ',function(){ + beforeEach(function(){ + graph.clear(); + p.yy = graph; + /*p.parse.parseError= function parseError(str, hash) { + console.log(str); + }*/ + }); + + it('should handle a nodes and edges',function(){ + var res = p.parse('apa-apa-åäö'); + console.log('Done parsing:' + res); + }); + }); + +}); + diff --git a/src/parser/mermaid.jison b/src/parser/mermaid.jison index d30c9ec8a..cd9fedf11 100644 --- a/src/parser/mermaid.jison +++ b/src/parser/mermaid.jison @@ -17,7 +17,7 @@ [x] return 'ARROW_CROSS'; ">" return 'ARROW_POINT'; [o] return 'ARROW_CIRCLE'; -[a-zA-Z]+ return 'ALPHA'; +[a-zåäöæøA-ZÅÄÖÆØ]+ return 'ALPHA'; "|" return 'PIPE'; "(" return 'PS'; ")" return 'PE'; @@ -78,7 +78,9 @@ vertex: ALPHA SQS text SQE ; // Characters and spaces text: ALPHA SPACE text - {$$ = $1 + ' ' +$3;} + {$$ = $1 + ' ' +$3;} + | ALPHA MINUS text + {$$ = $1 + '-' +$3;} | ALPHA SPACE {$$ = $1;} | ALPHA @@ -139,6 +141,5 @@ borderStyle: BORDER_STYLE %% define('parser/mermaid',function(){ - console.log('abc123'+parser.parseError); return parser; }); \ No newline at end of file diff --git a/src/parser/mermaid.js b/src/parser/mermaid.js index 5361c240e..7ffaa56f9 100644 --- a/src/parser/mermaid.js +++ b/src/parser/mermaid.js @@ -72,12 +72,12 @@ } */ var parser = (function(){ -var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,3],$V1=[1,7],$V2=[1,8],$V3=[8,12,23],$V4=[1,23],$V5=[8,18,20,22],$V6=[1,45],$V7=[1,40],$V8=[1,42],$V9=[1,41],$Va=[1,43],$Vb=[1,44],$Vc=[1,46],$Vd=[8,28],$Ve=[6,8,15,23,28,30,31,32,33]; +var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,3],$V1=[1,7],$V2=[1,8],$V3=[8,12,23],$V4=[1,23],$V5=[8,18,20,22],$V6=[1,46],$V7=[1,41],$V8=[1,43],$V9=[1,42],$Va=[1,44],$Vb=[1,45],$Vc=[1,47],$Vd=[8,28],$Ve=[6,8,15,23,28,30,31,32,33]; var parser = {trace: function trace() { }, yy: {}, symbols_: {"error":2,"expressions":3,"graph":4,"EOF":5,"SPACE":6,"edge":7,";":8,"styleStatement":9,"vertex":10,"link":11,"PIPE":12,"text":13,"STYLE":14,"ALPHA":15,"stylesOpt":16,"SQS":17,"SQE":18,"PS":19,"PE":20,"DIAMOND_START":21,"DIAMOND_STOP":22,"MINUS":23,"ARROW_POINT":24,"ARROW_CIRCLE":25,"ARROW_CROSS":26,"style":27,"COMMA":28,"styleComponent":29,"COLON":30,"NUM":31,"UNIT":32,"HEX":33,"colordef":34,"COLOR":35,"borderWidth":36,"borderStyle":37,"BORDER_STYLE":38,"$accept":0,"$end":1}, terminals_: {2:"error",5:"EOF",6:"SPACE",8:";",12:"PIPE",14:"STYLE",15:"ALPHA",17:"SQS",18:"SQE",19:"PS",20:"PE",21:"DIAMOND_START",22:"DIAMOND_STOP",23:"MINUS",24:"ARROW_POINT",25:"ARROW_CIRCLE",26:"ARROW_CROSS",28:"COMMA",30:"COLON",31:"NUM",32:"UNIT",33:"HEX",35:"COLOR",38:"BORDER_STYLE"}, -productions_: [0,[3,2],[4,2],[4,3],[4,2],[7,1],[7,5],[7,3],[7,1],[9,5],[10,4],[10,4],[10,4],[10,1],[13,3],[13,2],[13,1],[11,3],[11,3],[11,3],[11,3],[16,1],[16,3],[27,1],[27,2],[29,1],[29,1],[29,1],[29,1],[29,1],[29,1],[29,1],[34,1],[34,1],[36,2],[37,1]], +productions_: [0,[3,2],[4,2],[4,3],[4,2],[7,1],[7,5],[7,3],[7,1],[9,5],[10,4],[10,4],[10,4],[10,1],[13,3],[13,3],[13,2],[13,1],[11,3],[11,3],[11,3],[11,3],[16,1],[16,3],[27,1],[27,2],[29,1],[29,1],[29,1],[29,1],[29,1],[29,1],[29,1],[34,1],[34,1],[36,2],[37,1]], performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { /* this == yyval */ @@ -123,48 +123,51 @@ case 14: this.$ = $$[$0-2] + ' ' +$$[$0]; break; case 15: +this.$ = $$[$0-2] + '-' +$$[$0]; +break; +case 16: this.$ = $$[$0-1]; break; -case 16: case 35: +case 17: case 36: this.$ = $$[$0]; break; -case 17: +case 18: this.$ = {"type":"arrow"}; break; -case 18: +case 19: this.$ = {"type":"arrow_circle"}; break; -case 19: +case 20: this.$ = {"type":"arrow_cross"}; break; -case 20: +case 21: this.$ = {"type":"arrow_open"}; break; -case 21: +case 22: console.log('a:'+$$[$0]);this.$ = [$$[$0]] break; -case 22: +case 23: console.log('a3:'+$$[$0-2].length+','+$$[$0]);$$[$0-2].push($$[$0]);this.$ = $$[$0-2]; break; -case 23: +case 24: this.$=$$[$0]; break; -case 24: +case 25: console.log('b1:');this.$ = $$[$0-1] + $$[$0]; break; -case 25: case 26: case 27: case 28: case 29: case 30: case 31: +case 26: case 27: case 28: case 29: case 30: case 31: case 32: this.$=$$[$0] break; -case 32: case 33: +case 33: case 34: this.$ = yytext; break; -case 34: +case 35: this.$ = $$[$0-1]+''+$$[$0]; break; } }, -table: [{3:1,4:2,6:$V0,7:4,9:5,10:6,14:$V1,15:$V2},{1:[3]},{5:[1,9]},{4:10,6:$V0,7:4,9:5,10:6,14:$V1,15:$V2},{8:[1,11]},{8:[2,5]},{8:[2,8],11:12,23:[1,13]},{6:[1,14]},o($V3,[2,13],{17:[1,15],19:[1,16],21:[1,17]}),{1:[2,1]},{5:[2,2]},{4:18,5:[2,4],6:$V0,7:4,9:5,10:6,14:$V1,15:$V2},{10:19,15:$V2},{23:[1,20]},{15:[1,21]},{13:22,15:$V4},{13:24,15:$V4},{13:25,15:$V4},{5:[2,3]},{8:[2,7],12:[1,26]},{23:[1,30],24:[1,27],25:[1,28],26:[1,29]},{6:[1,31]},{18:[1,32]},o($V5,[2,16],{6:[1,33]}),{20:[1,34]},{22:[1,35]},{13:36,15:$V4},{15:[2,17]},{15:[2,18]},{15:[2,19]},{15:[2,20]},{6:$V6,15:$V7,16:37,23:$V8,27:38,29:39,30:$V9,31:$Va,32:$Vb,33:$Vc},o($V3,[2,10]),o($V5,[2,15],{13:47,15:$V4}),o($V3,[2,11]),o($V3,[2,12]),{8:[2,6]},{8:[2,9],28:[1,48]},o($Vd,[2,21],{29:49,6:$V6,15:$V7,23:$V8,30:$V9,31:$Va,32:$Vb,33:$Vc}),o($Ve,[2,23]),o($Ve,[2,25]),o($Ve,[2,26]),o($Ve,[2,27]),o($Ve,[2,28]),o($Ve,[2,29]),o($Ve,[2,30]),o($Ve,[2,31]),o($V5,[2,14]),{6:$V6,15:$V7,23:$V8,27:50,29:39,30:$V9,31:$Va,32:$Vb,33:$Vc},o($Ve,[2,24]),o($Vd,[2,22],{29:49,6:$V6,15:$V7,23:$V8,30:$V9,31:$Va,32:$Vb,33:$Vc})], -defaultActions: {5:[2,5],9:[2,1],10:[2,2],18:[2,3],27:[2,17],28:[2,18],29:[2,19],30:[2,20],36:[2,6]}, +table: [{3:1,4:2,6:$V0,7:4,9:5,10:6,14:$V1,15:$V2},{1:[3]},{5:[1,9]},{4:10,6:$V0,7:4,9:5,10:6,14:$V1,15:$V2},{8:[1,11]},{8:[2,5]},{8:[2,8],11:12,23:[1,13]},{6:[1,14]},o($V3,[2,13],{17:[1,15],19:[1,16],21:[1,17]}),{1:[2,1]},{5:[2,2]},{4:18,5:[2,4],6:$V0,7:4,9:5,10:6,14:$V1,15:$V2},{10:19,15:$V2},{23:[1,20]},{15:[1,21]},{13:22,15:$V4},{13:24,15:$V4},{13:25,15:$V4},{5:[2,3]},{8:[2,7],12:[1,26]},{23:[1,30],24:[1,27],25:[1,28],26:[1,29]},{6:[1,31]},{18:[1,32]},o($V5,[2,17],{6:[1,33],23:[1,34]}),{20:[1,35]},{22:[1,36]},{13:37,15:$V4},{15:[2,18]},{15:[2,19]},{15:[2,20]},{15:[2,21]},{6:$V6,15:$V7,16:38,23:$V8,27:39,29:40,30:$V9,31:$Va,32:$Vb,33:$Vc},o($V3,[2,10]),o($V5,[2,16],{13:48,15:$V4}),{13:49,15:$V4},o($V3,[2,11]),o($V3,[2,12]),{8:[2,6]},{8:[2,9],28:[1,50]},o($Vd,[2,22],{29:51,6:$V6,15:$V7,23:$V8,30:$V9,31:$Va,32:$Vb,33:$Vc}),o($Ve,[2,24]),o($Ve,[2,26]),o($Ve,[2,27]),o($Ve,[2,28]),o($Ve,[2,29]),o($Ve,[2,30]),o($Ve,[2,31]),o($Ve,[2,32]),o($V5,[2,14]),o($V5,[2,15]),{6:$V6,15:$V7,23:$V8,27:52,29:40,30:$V9,31:$Va,32:$Vb,33:$Vc},o($Ve,[2,25]),o($Vd,[2,23],{29:51,6:$V6,15:$V7,23:$V8,30:$V9,31:$Va,32:$Vb,33:$Vc})], +defaultActions: {5:[2,5],9:[2,1],10:[2,2],18:[2,3],27:[2,18],28:[2,19],29:[2,20],30:[2,21],37:[2,6]}, parseError: function parseError(str, hash) { if (hash.recoverable) { this.trace(str); @@ -311,7 +314,6 @@ parse: function parse(input) { }}; define('parser/mermaid',function(){ - console.log('abc123'+parser.parseError); return parser; });/* generated by jison-lex 0.3.4 */ var lexer = (function(){ @@ -691,7 +693,7 @@ case 23:return 5; break; } }, -rules: [/^(?:style\b)/,/^(?:#[a-f0-9]+)/,/^(?:[0-9]+)/,/^(?:px\b)/,/^(?:pt\b)/,/^(?:dot\b)/,/^(?::)/,/^(?:-)/,/^(?:;)/,/^(?:,)/,/^(?:[x])/,/^(?:>)/,/^(?:[o])/,/^(?:[a-zA-Z]+)/,/^(?:\|)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:\s)/,/^(?:\n)/,/^(?:$)/], +rules: [/^(?:style\b)/,/^(?:#[a-f0-9]+)/,/^(?:[0-9]+)/,/^(?:px\b)/,/^(?:pt\b)/,/^(?:dot\b)/,/^(?::)/,/^(?:-)/,/^(?:;)/,/^(?:,)/,/^(?:[x])/,/^(?:>)/,/^(?:[o])/,/^(?:[a-zåäöæøA-ZÅÄÖÆØ]+)/,/^(?:\|)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:\s)/,/^(?:\n)/,/^(?:$)/], conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],"inclusive":true}} }); return lexer; diff --git a/src/parser/mermaid.spec.js b/src/parser/mermaid.spec.js index 0e9a65ce8..7dea8b6b8 100644 --- a/src/parser/mermaid.spec.js +++ b/src/parser/mermaid.spec.js @@ -10,6 +10,7 @@ define('parser/mermaid.spec',['parser/graph','parser/mermaid'],function(graph, p /*p.parse.parseError= function parseError(str, hash) { console.log(str); }*/ + console.log('in mm spec'); }); it('should handle a nodes and edges',function(){ @@ -126,6 +127,25 @@ define('parser/mermaid.spec',['parser/graph','parser/mermaid'],function(graph, p expect(vert['A'].type).toBe('diamond'); expect(vert['A'].text).toBe('chimpansen hoppar'); }); + it('should handle text in vertices with space',function(){ + var res = p.parse('A-->C{Chimpansen hoppar};'); + + var vert = p.yy.getVertices(); + var edges = p.yy.getEdges(); + + expect(vert['C'].type).toBe('diamond'); + expect(vert['C'].text).toBe('Chimpansen hoppar'); + }); + + it('should handle text in vertices with åäö and minus',function(){ + var res = p.parse('A-->C{Chimpansen hoppar åäö-ÅÄÖ};'); + + var vert = p.yy.getVertices(); + var edges = p.yy.getEdges(); + + expect(vert['C'].type).toBe('diamond'); + expect(vert['C'].text).toBe('Chimpansen hoppar åäö-ÅÄÖ'); + }); it('should handle a single node',function(){ // Silly but syntactically correct @@ -196,7 +216,6 @@ define('parser/mermaid.spec',['parser/graph','parser/mermaid'],function(graph, p expect(vert['T'].styles[0]).toBe('background:#bbb'); expect(vert['T'].styles[1]).toBe('border:1px solid red'); }); - //console.log(p.parse('style S background:#aaa;\nstyle T background:#bbb,border:1px solid red;')); }); }); diff --git a/src/parser/mermaid2.js b/src/parser/mermaid2.js new file mode 100644 index 000000000..25c907b46 --- /dev/null +++ b/src/parser/mermaid2.js @@ -0,0 +1,743 @@ +/* parser generated by jison 0.4.15 */ +/* + Returns a Parser object of the following structure: + + Parser: { + yy: {} + } + + Parser.prototype: { + yy: {}, + trace: function(), + symbols_: {associative list: name ==> number}, + terminals_: {associative list: number ==> name}, + productions_: [...], + performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), + table: [...], + defaultActions: {...}, + parseError: function(str, hash), + parse: function(input), + + lexer: { + EOF: 1, + parseError: function(str, hash), + setInput: function(input), + input: function(), + unput: function(str), + more: function(), + less: function(n), + pastInput: function(), + upcomingInput: function(), + showPosition: function(), + test_match: function(regex_match_array, rule_index), + next: function(), + lex: function(), + begin: function(condition), + popState: function(), + _currentRules: function(), + topState: function(), + pushState: function(condition), + + options: { + ranges: boolean (optional: true ==> token location info will include a .range[] member) + flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) + backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) + }, + + performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), + rules: [...], + conditions: {associative list: name ==> set}, + } + } + + + token location info (@$, _$, etc.): { + first_line: n, + last_line: n, + first_column: n, + last_column: n, + range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) + } + + + the parseError function receives a 'hash' object with these members for lexer and parser errors: { + text: (matched text) + token: (the produced terminal token, if any) + line: (yylineno) + } + while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { + loc: (yylloc) + expected: (string describing the set of expected tokens) + recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) + } +*/ +var parser = (function(){ +var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,3],$V1=[1,6],$V2=[1,7],$V3=[8,11,22,23,24,25],$V4=[13,14],$V5=[1,24],$V6=[8,17,19,21]; +var parser = {trace: function trace() { }, +yy: {}, +symbols_: {"error":2,"expressions":3,"graph":4,"EOF":5,"SPACE":6,"edge":7,";":8,"vertex":9,"link":10,"PIPE":11,"text":12,"STYLE":13,"ALPHA":14,"stylesOpt":15,"SQS":16,"SQE":17,"PS":18,"PE":19,"DIAMOND_START":20,"DIAMOND_STOP":21,"ARROW_POINT":22,"ARROW_CIRCLE":23,"ARROW_CROSS":24,"ARROW_OPEN":25,"styles":26,"styledef":27,"COMMA":28,"BKG":29,"COLON":30,"colordef":31,"COL":32,"COLORDEF":33,"BORDER":34,"borderWidth":35,"borderStyle":36,"styledef3":37,"styles2":38,"styledef2":39,"NUM":40,"UNIT":41,"HEX":42,"COLOR":43,"BORDER_STYLE":44,"$accept":0,"$end":1}, +terminals_: {2:"error",5:"EOF",6:"SPACE",8:";",11:"PIPE",13:"STYLE",14:"ALPHA",16:"SQS",17:"SQE",18:"PS",19:"PE",20:"DIAMOND_START",21:"DIAMOND_STOP",22:"ARROW_POINT",23:"ARROW_CIRCLE",24:"ARROW_CROSS",25:"ARROW_OPEN",28:"COMMA",29:"BKG",30:"COLON",32:"COL",33:"COLORDEF",34:"BORDER",40:"NUM",41:"UNIT",42:"HEX",43:"COLOR",44:"BORDER_STYLE"}, +productions_: [0,[3,2],[4,2],[4,3],[4,2],[7,5],[7,3],[7,1],[9,5],[9,4],[9,4],[9,4],[9,1],[12,3],[12,2],[12,1],[10,1],[10,1],[10,1],[10,1],[26,1],[26,3],[27,3],[27,3],[27,7],[15,1],[38,1],[38,3],[39,3],[39,3],[39,7],[37,1],[37,1],[37,1],[37,1],[37,1],[31,1],[31,1],[35,2],[36,1]], +performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { +/* this == yyval */ + +var $0 = $$.length - 1; +switch (yystate) { +case 1: +return $$[$0-1]; +break; +case 2: case 3: + this.$ = $$[$0]; +break; +case 4: + this.$ = $$[$0-1]; +break; +case 5: + yy.addLink($$[$0-4],$$[$0-2],$$[$0-3],$$[$0]);this.$ = 'oy' +break; +case 6: + yy.addLink($$[$0-2],$$[$0],$$[$0-1]);this.$ = 'oy' +break; +case 7: +this.$ = 'yo'; +break; +case 8: +this.$ = $$[$0-4];yy.addVertex($$[$0-2],undefined,undefined,$$[$0]); +break; +case 9: +this.$ = $$[$0-3];yy.addVertex($$[$0-3],$$[$0-1],'square'); +break; +case 10: +this.$ = $$[$0-3];yy.addVertex($$[$0-3],$$[$0-1],'round'); +break; +case 11: +this.$ = $$[$0-3];yy.addVertex($$[$0-3],$$[$0-1],'diamond'); +break; +case 12: +this.$ = $$[$0];yy.addVertex($$[$0]); +break; +case 13: +this.$ = $$[$0-2] + ' ' +$$[$0]; +break; +case 14: +this.$ = $$[$0-1]; +break; +case 15: case 39: +this.$ = $$[$0]; +break; +case 16: +this.$ = {"type":"arrow"}; +break; +case 17: +this.$ = {"type":"arrow_circle"}; +break; +case 18: +this.$ = {"type":"arrow_cross"}; +break; +case 19: +this.$ = {"type":"arrow_open"}; +break; +case 20: case 26: +this.$ = [$$[$0]]; +break; +case 21: case 27: +$$[$0-2].push($$[$0]);this.$ = $$[$0-2]; +break; +case 22: case 28: +this.$={"background":$$[$0]} +break; +case 23: case 29: +this.$={"color":$$[$0]} +break; +case 24: case 30: +this.$={"border":$$[$0-4]+' '+$$[$0-2]+' '+$$[$0]} +break; +case 25: +this.$ = $yytext +break; +case 31: case 32: case 33: case 34: +this.$=$$[$0] +break; +case 35: +this.$=$yytext +break; +case 36: case 37: +this.$ = yytext; +break; +case 38: +this.$ = $$[$0-1]+''+$$[$0]; +break; +} +}, +table: [{3:1,4:2,6:$V0,7:4,9:5,13:$V1,14:$V2},{1:[3]},{5:[1,8]},{4:9,6:$V0,7:4,9:5,13:$V1,14:$V2},{8:[1,10]},{8:[2,7],10:11,22:[1,12],23:[1,13],24:[1,14],25:[1,15]},{6:[1,16]},o($V3,[2,12],{16:[1,17],18:[1,18],20:[1,19]}),{1:[2,1]},{5:[2,2]},{4:20,5:[2,4],6:$V0,7:4,9:5,13:$V1,14:$V2},{9:21,13:$V1,14:$V2},o($V4,[2,16]),o($V4,[2,17]),o($V4,[2,18]),o($V4,[2,19]),{14:[1,22]},{12:23,14:$V5},{12:25,14:$V5},{12:26,14:$V5},{5:[2,3]},{8:[2,6],11:[1,27]},{6:[1,28]},{17:[1,29]},o($V6,[2,15],{6:[1,30]}),{19:[1,31]},{21:[1,32]},{12:33,14:$V5},{6:[1,39],14:[1,36],15:34,37:35,40:[1,37],41:[1,38],42:[1,40]},o($V3,[2,9]),o($V6,[2,14],{12:41,14:$V5}),o($V3,[2,10]),o($V3,[2,11]),{8:[2,5]},o($V3,[2,8]),o($V3,[2,25]),o($V3,[2,31]),o($V3,[2,32]),o($V3,[2,33]),o($V3,[2,34]),o($V3,[2,35]),o($V6,[2,13])], +defaultActions: {8:[2,1],9:[2,2],20:[2,3],33:[2,5]}, +parseError: function parseError(str, hash) { + if (hash.recoverable) { + this.trace(str); + } else { + throw new Error(str); + } +}, +parse: function parse(input) { + var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; + var args = lstack.slice.call(arguments, 1); + var lexer = Object.create(this.lexer); + var sharedState = { yy: {} }; + for (var k in this.yy) { + if (Object.prototype.hasOwnProperty.call(this.yy, k)) { + sharedState.yy[k] = this.yy[k]; + } + } + lexer.setInput(input, sharedState.yy); + sharedState.yy.lexer = lexer; + sharedState.yy.parser = this; + if (typeof lexer.yylloc == 'undefined') { + lexer.yylloc = {}; + } + var yyloc = lexer.yylloc; + lstack.push(yyloc); + var ranges = lexer.options && lexer.options.ranges; + if (typeof sharedState.yy.parseError === 'function') { + this.parseError = sharedState.yy.parseError; + } else { + this.parseError = Object.getPrototypeOf(this).parseError; + } + function popStack(n) { + stack.length = stack.length - 2 * n; + vstack.length = vstack.length - n; + lstack.length = lstack.length - n; + } + _token_stack: + function lex() { + var token; + token = lexer.lex() || EOF; + if (typeof token !== 'number') { + token = self.symbols_[token] || token; + } + return token; + } + var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; + while (true) { + state = stack[stack.length - 1]; + if (this.defaultActions[state]) { + action = this.defaultActions[state]; + } else { + if (symbol === null || typeof symbol == 'undefined') { + symbol = lex(); + } + action = table[state] && table[state][symbol]; + } + if (typeof action === 'undefined' || !action.length || !action[0]) { + var errStr = ''; + expected = []; + for (p in table[state]) { + if (this.terminals_[p] && p > TERROR) { + expected.push('\'' + this.terminals_[p] + '\''); + } + } + if (lexer.showPosition) { + errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; + } else { + errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); + } + console.log(errStr, { + text: lexer.match, + token: this.terminals_[symbol] || symbol, + line: lexer.yylineno, + loc: yyloc, + expected: expected + }); + } + if (action[0] instanceof Array && action.length > 1) { + throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); + } + switch (action[0]) { + case 1: + stack.push(symbol); + vstack.push(lexer.yytext); + lstack.push(lexer.yylloc); + stack.push(action[1]); + symbol = null; + if (!preErrorSymbol) { + yyleng = lexer.yyleng; + yytext = lexer.yytext; + yylineno = lexer.yylineno; + yyloc = lexer.yylloc; + if (recovering > 0) { + recovering--; + } + } else { + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + case 2: + len = this.productions_[action[1]][1]; + yyval.$ = vstack[vstack.length - len]; + yyval._$ = { + first_line: lstack[lstack.length - (len || 1)].first_line, + last_line: lstack[lstack.length - 1].last_line, + first_column: lstack[lstack.length - (len || 1)].first_column, + last_column: lstack[lstack.length - 1].last_column + }; + if (ranges) { + yyval._$.range = [ + lstack[lstack.length - (len || 1)].range[0], + lstack[lstack.length - 1].range[1] + ]; + } + r = this.performAction.apply(yyval, [ + yytext, + yyleng, + yylineno, + sharedState.yy, + action[1], + vstack, + lstack + ].concat(args)); + if (typeof r !== 'undefined') { + return r; + } + if (len) { + stack = stack.slice(0, -1 * len * 2); + vstack = vstack.slice(0, -1 * len); + lstack = lstack.slice(0, -1 * len); + } + stack.push(this.productions_[action[1]][0]); + vstack.push(yyval.$); + lstack.push(yyval._$); + newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; + stack.push(newState); + break; + case 3: + return true; + } + } + return true; +}}; + +define('parser/mermaid',function(){ + console.log('abc123'+parser.parseError); + return parser; +});/* generated by jison-lex 0.3.4 */ +var lexer = (function(){ +var lexer = ({ + +EOF:1, + +parseError:function parseError(str, hash) { + if (this.yy.parser) { + this.yy.parser.parseError(str, hash); + } else { + throw new Error(str); + } + }, + +// resets the lexer, sets new input +setInput:function (input, yy) { + this.yy = yy || this.yy || {}; + this._input = input; + this._more = this._backtrack = this.done = false; + this.yylineno = this.yyleng = 0; + this.yytext = this.matched = this.match = ''; + this.conditionStack = ['INITIAL']; + this.yylloc = { + first_line: 1, + first_column: 0, + last_line: 1, + last_column: 0 + }; + if (this.options.ranges) { + this.yylloc.range = [0,0]; + } + this.offset = 0; + return this; + }, + +// consumes and returns one char from the input +input:function () { + var ch = this._input[0]; + this.yytext += ch; + this.yyleng++; + this.offset++; + this.match += ch; + this.matched += ch; + var lines = ch.match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno++; + this.yylloc.last_line++; + } else { + this.yylloc.last_column++; + } + if (this.options.ranges) { + this.yylloc.range[1]++; + } + + this._input = this._input.slice(1); + return ch; + }, + +// unshifts one char (or a string) into the input +unput:function (ch) { + var len = ch.length; + var lines = ch.split(/(?:\r\n?|\n)/g); + + this._input = ch + this._input; + this.yytext = this.yytext.substr(0, this.yytext.length - len); + //this.yyleng -= len; + this.offset -= len; + var oldLines = this.match.split(/(?:\r\n?|\n)/g); + this.match = this.match.substr(0, this.match.length - 1); + this.matched = this.matched.substr(0, this.matched.length - 1); + + if (lines.length - 1) { + this.yylineno -= lines.length - 1; + } + var r = this.yylloc.range; + + this.yylloc = { + first_line: this.yylloc.first_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.first_column, + last_column: lines ? + (lines.length === oldLines.length ? this.yylloc.first_column : 0) + + oldLines[oldLines.length - lines.length].length - lines[0].length : + this.yylloc.first_column - len + }; + + if (this.options.ranges) { + this.yylloc.range = [r[0], r[0] + this.yyleng - len]; + } + this.yyleng = this.yytext.length; + return this; + }, + +// When called from action, caches matched text and appends it on next action +more:function () { + this._more = true; + return this; + }, + +// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead. +reject:function () { + if (this.options.backtrack_lexer) { + this._backtrack = true; + } else { + return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), { + text: "", + token: null, + line: this.yylineno + }); + + } + return this; + }, + +// retain first n characters of the match +less:function (n) { + this.unput(this.match.slice(n)); + }, + +// displays already matched input, i.e. for error messages +pastInput:function () { + var past = this.matched.substr(0, this.matched.length - this.match.length); + return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); + }, + +// displays upcoming input, i.e. for error messages +upcomingInput:function () { + var next = this.match; + if (next.length < 20) { + next += this._input.substr(0, 20-next.length); + } + return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); + }, + +// displays the character position where the lexing error occurred, i.e. for error messages +showPosition:function () { + var pre = this.pastInput(); + var c = new Array(pre.length + 1).join("-"); + return pre + this.upcomingInput() + "\n" + c + "^"; + }, + +// test the lexed token: return FALSE when not a match, otherwise return token +test_match:function (match, indexed_rule) { + var token, + lines, + backup; + + if (this.options.backtrack_lexer) { + // save context + backup = { + yylineno: this.yylineno, + yylloc: { + first_line: this.yylloc.first_line, + last_line: this.last_line, + first_column: this.yylloc.first_column, + last_column: this.yylloc.last_column + }, + yytext: this.yytext, + match: this.match, + matches: this.matches, + matched: this.matched, + yyleng: this.yyleng, + offset: this.offset, + _more: this._more, + _input: this._input, + yy: this.yy, + conditionStack: this.conditionStack.slice(0), + done: this.done + }; + if (this.options.ranges) { + backup.yylloc.range = this.yylloc.range.slice(0); + } + } + + lines = match[0].match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno += lines.length; + } + this.yylloc = { + first_line: this.yylloc.last_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.last_column, + last_column: lines ? + lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : + this.yylloc.last_column + match[0].length + }; + this.yytext += match[0]; + this.match += match[0]; + this.matches = match; + this.yyleng = this.yytext.length; + if (this.options.ranges) { + this.yylloc.range = [this.offset, this.offset += this.yyleng]; + } + this._more = false; + this._backtrack = false; + this._input = this._input.slice(match[0].length); + this.matched += match[0]; + token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); + if (this.done && this._input) { + this.done = false; + } + if (token) { + return token; + } else if (this._backtrack) { + // recover context + for (var k in backup) { + this[k] = backup[k]; + } + return false; // rule action called reject() implying the next rule should be tested instead. + } + return false; + }, + +// return next match in input +next:function () { + if (this.done) { + return this.EOF; + } + if (!this._input) { + this.done = true; + } + + var token, + match, + tempMatch, + index; + if (!this._more) { + this.yytext = ''; + this.match = ''; + } + var rules = this._currentRules(); + for (var i = 0; i < rules.length; i++) { + tempMatch = this._input.match(this.rules[rules[i]]); + if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { + match = tempMatch; + index = i; + if (this.options.backtrack_lexer) { + token = this.test_match(tempMatch, rules[i]); + if (token !== false) { + return token; + } else if (this._backtrack) { + match = false; + continue; // rule action called reject() implying a rule MISmatch. + } else { + // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) + return false; + } + } else if (!this.options.flex) { + break; + } + } + } + if (match) { + token = this.test_match(match, rules[index]); + if (token !== false) { + return token; + } + // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) + return false; + } + if (this._input === "") { + return this.EOF; + } else { + return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { + text: "", + token: null, + line: this.yylineno + }); + } + }, + +// return next match that has a token +lex:function lex() { + var r = this.next(); + if (r) { + return r; + } else { + return this.lex(); + } + }, + +// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) +begin:function begin(condition) { + this.conditionStack.push(condition); + }, + +// pop the previously active lexer condition state off the condition stack +popState:function popState() { + var n = this.conditionStack.length - 1; + if (n > 0) { + return this.conditionStack.pop(); + } else { + return this.conditionStack[0]; + } + }, + +// produce the lexer rule set which is active for the currently active lexer condition state +_currentRules:function _currentRules() { + if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { + return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; + } else { + return this.conditions["INITIAL"].rules; + } + }, + +// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available +topState:function topState(n) { + n = this.conditionStack.length - 1 - Math.abs(n || 0); + if (n >= 0) { + return this.conditionStack[n]; + } else { + return "INITIAL"; + } + }, + +// alias for begin(condition) +pushState:function pushState(condition) { + this.begin(condition); + }, + +// return the number of states currently on the stack +stateStackSize:function stateStackSize() { + return this.conditionStack.length; + }, +options: {}, +performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { +var YYSTATE=YY_START; +switch($avoiding_name_collisions) { +case 0:return 13; +break; +case 1:return 43; +break; +case 2:return 43; +break; +case 3:return 43; +break; +case 4:return 42; +break; +case 5:return 40; +break; +case 6:return 34; +break; +case 7:return 44; +break; +case 8:return 44; +break; +case 9:return 44; +break; +case 10:return 41; +break; +case 11:return 41; +break; +case 12:return 41; +break; +case 13:return 30; +break; +case 14:return 8; +break; +case 15:return 28; +break; +case 16:return 24; +break; +case 17:return 22; +break; +case 18:return 23; +break; +case 19:return 25; +break; +case 20:return 14; +break; +case 21:return 11; +break; +case 22:return 18; +break; +case 23:return 19; +break; +case 24:return 16; +break; +case 25:return 17; +break; +case 26:return 20 +break; +case 27:return 21 +break; +case 28:return 6; +break; +case 29:return 'NEWLINE'; +break; +case 30:return 5; +break; +} +}, +rules: [/^(?:style\b)/,/^(?:red\b)/,/^(?:blue\b)/,/^(?:black\b)/,/^(?:#[a-f0-9]+)/,/^(?:[0-9]+)/,/^(?:border\b)/,/^(?:dotted\b)/,/^(?:dashed\b)/,/^(?:solid\b)/,/^(?:px\b)/,/^(?:pt\b)/,/^(?:dot\b)/,/^(?::)/,/^(?:;)/,/^(?:,)/,/^(?:--[x])/,/^(?:-->)/,/^(?:--[o])/,/^(?:---)/,/^(?:[a-zA-Z]+)/,/^(?:\|)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:\s)/,/^(?:\n)/,/^(?:$)/], +conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30],"inclusive":true}} +}); +return lexer; +})(); +parser.lexer = lexer; +function Parser () { + this.yy = {}; +} +Parser.prototype = parser;parser.Parser = Parser; +return new Parser; +})(); + + +if (typeof require !== 'undefined' && typeof exports !== 'undefined') { +exports.parser = parser; +exports.Parser = parser.Parser; +exports.parse = function () { return parser.parse.apply(parser, arguments); }; +exports.main = function commonjsMain(args) { + if (!args[1]) { + console.log('Usage: '+args[0]+' FILE'); + process.exit(1); + } + var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8"); + return exports.parser.parse(source); +}; +if (typeof module !== 'undefined' && require.main === module) { + exports.main(process.argv.slice(1)); +} +} diff --git a/src/parser/test.txt b/src/parser/test.txt new file mode 100644 index 000000000..2dba4f294 --- /dev/null +++ b/src/parser/test.txt @@ -0,0 +1,1573 @@ +grammar ECMAScript; + +options { + // Allow any char but \uFFFF (16 bit -1) + charVocabulary='\u0000'..'\uFFFE'; +} +/* this comes from section A.5 but is really the starting point, so +* it is present here. +*/ +program: + sourceElements EOF + ; + +/* A.1 Lexical Grammar */ + +sourceCharacter: + /* any unicode character */ + /* see section 6 */ + SOURCE_CHAR + ; + +inputElementDiv: + whiteSpace + | lineTerminator + | comment + | token + | divPunctuator + ; + +inputElementRegExp: + whiteSpace + | lineTerminator + | comment + | token + | regularExpressionLiteral + ; + +whiteSpace: + TAB + | VT + | FF + | SP + | NBSP + | USP + ; + +lineTerminator: + | LF + | CR + | LS + | PS + ; + +comment: + multiLineComment + | singleLineComment + ; + +multiLineComment: + '/*' multiLineCommentChars '*/' + ; + +multiLineCommentChars: + multiLineNotAsterikChar multiLineCommentChars + | ASTERISK postAsterikCommentChars + ; + +postAsterikCommentChars: + multiLineNotForwardSlashOrAsterikChar multiLineCommentChars + | ASTERISK postAsterikCommentChars + ; + +multiLineNotAsterikChar: + sourceCharacter /* but not ASTERISK */ + ; + +multiLineNotForwardSlashOrAsterikChar: + sourceCharacter /* but not FORWARD-SLASH or ASTERISK */ + ; + +singleLineComment: + '//' singleLineCommentChars + ; + +singleLineCommentChars: + singleLineCommentChar singleLineCommentChars + ; + +singleLineCommentChar: + sourceCharacter /* but not lineTerminator */ + ; + +token: + reservedWord + | identifier + /* syntactic predicate used to disambiguate between DOT on ALT 3 and ALT 5 */ + | (DOT decimalDigits)=> numericLiteral + /* syntactic predicate used to disambiguate between APOSTROPHE on ALT 4 and ALT 5 */ + | (APOSTROPHE (singleStringCharacters)? APOSTROPHE)=> stringLiteral + | punctuator + ; + +reservedWord: + keyword + | futureReservedWord + | nullLiteral + | booleanLiteral + ; + +keyword: + 'break' | 'case' | 'catch' | 'continue' | 'default' | 'delete' | 'do' + | 'else' | 'finally' | 'for' | 'function' | 'if' | 'in' | 'instanceof' + | 'new' | 'return' | 'switch' | 'this' | 'throw' | 'try' | 'typeof' + | 'var' | 'void' | 'while' | 'with' + ; + +futureReservedWord: + 'abstract' | 'boolean' | 'byte' | 'char' | 'class' | 'const' | 'debugger' | 'double' + | 'enum' | 'export' | 'extends' | 'final' | 'float' | 'goto' | 'implements' | 'import' + | 'int' | 'interface' | 'long' | 'native' | 'package' | 'private' | 'protected' | 'public' + | 'short' | 'static' | 'super' | 'synchronized' | 'throws' | 'transient' | 'volatile' + ; + +identifier: + identifierName /* but not reservedWord */ + ; + +identifierName: + /* + * left factorization: + * + * SPEC: + * identifierStart + * | identifierName identifierPart + * -> + * ((identifierStart)+ (identifierPart)?)+ + */ + identifierStart (identifierPart)* + ; + +identifierStart: + unicodeLetter + | DOLLAR + | UNDERSCORE + | unicodeEscapeSequence + ; + +identifierPart: + /* syntactic predicate to remove non-determinism upon alts 1 and 5 + * - always choose the identifierStart when possible + */ + (unicodeEscapeSequence identifierPart)=> identifierStart + | unicodeCombiningMark + | unicodeDigit + | unicodeConnectorPunctuation + | unicodeEscapeSequence + ; + +unicodeLetter: + /* any character in the unicode categories: + "uppercase letter (Lu)", + "lowercase letter (Li)", + "titlecase letter (Lt)", + "modifier letter (Lm)", + "other letter (lo)", + "letter number (NI)" */ + UNICODE_LETTER + ; + +unicodeCombiningMark: + /* any character in the unicode categories: + "non-spacing mark (Mn)" + "combining spacing mark (Mc)" + */ + UNICODE_NONSPACING_MARK + | UNICODE_COMBINING_MARK + ; + +unicodeDigit: + /* any character in the unicode category "decimal number (Nd)" */ + UNICODE_DIGIT + ; + +unicodeConnectorPunctuation: + /* any character in the unicode category "connector punctuation (Pc)" */ + UNICODE_CONNECTOR_PUNCTUATION + ; + +unicodeEscapeSequence: + '\\u' hexDigit hexDigit hexDigit hexDigit + ; + +hexDigit: + /* explicitly enumerated in grammar */ + HEXDIGIT + ; + +punctuator: + LBRACE | RBRACE | LPAREN | RPAREN | LBRACK | RBRACK + | DOT | SEMI | APOSTROPHE | LT | GT | LTEQ + | GTEQ | EQ2 | NOTEQ | EQ3 | NOTEQ2 + | PLUS | MINUS | STAR | PERCENT | PLUS2 | MINUS2 + | LSHIFT | RSHIFT | GT3 | AMPER | PIPE | CAROT + | EXCLAMATION | TILDE | AMPER2 | PIPE2 | QUESTION | COLON + | EQ | PLUSEQ | MINUSEQ | TIMESEQ | PERCENTEQ | LSHIFTEQ + | RSHIFTEQ | GT3EQ | AMPEREQ | PIPEEQ | CAROTEQ + ; + +divPunctuator: + DIVIDE + | DIVIDEEQ + ; + +literal: + nullLiteral + | booleanLiteral + | numericLiteral + | stringLiteral + ; + +nullLiteral: + 'null' + ; + +booleanLiteral: + 'true' + | 'false' + ; + + +numericLiteral: + decimalLiteral + | hexIntegerLiteral + ; + +decimalLiteral: + /* + * SPEC: + * decimalIntegerLiteral DOT (decimalDigits)? (exponentPart)? + * | DOT decimalDigits (exponentPart)? + * | decimalIntegerLiteral (exponentPart)? + * -> + */ + decimalIntegerLiteral decimalIntegerLiteralTail + | DOT decimalDigits (exponentPart)? + ; + +decimalIntegerLiteralTail: + /* this is necessary because of the way the grammar gets parsed */ + DOT (decimalDigits)? (exponentPart)? + | exponentPart + ; + +decimalIntegerLiteral: + ZERO + | NON_ZERO_DIGIT (decimalDigits)? + ; + +decimalDigits: + /* + * SPEC: + * decimalDigit + * | decimalDigits decimalDigit + * => + * (decimalDigits)+ + */ + (decimalDigit)+ + ; + +decimalDigit: + DIGIT /* grammar has each one explicitely listed */ + ; + +exponentIndicator: + EXPONENT_INDICATOR /* grammar has both e and E listed */ + ; + +signedInteger: + decimalDigits + | PLUS decimalDigits + | MINUS decimalDigits + ; + +hexIntegerLiteral: + /* + * SPEC: + * '0x' hexDigit + * | '0X' hexDigit + * | hexIntegerLiteral hexDigit + * -> + * ('0x'|'0X') (hexDigit)+ + */ + ('0x'|'0X') (hexDigit)+ + ; + +stringLiteral: + QUOTE (doubleStringCharacters)? QUOTE + | APOSTROPHE (singleStringCharacters)? APOSTROPHE + ; + +doubleStringCharacters: + doubleStringCharacter (doubleStringCharacters)? + ; + +singleStringCharacters: + singleStringCharacter (singleStringCharacters)? + ; + +doubleStringCharacter: + sourceCharacter /* but not double quote or backslash or line terminator */ + BSLASH escapeSequence + ; + +singleStringCharacter: + sourceCharacter /* but not single quote or backslash or line terminator */ + | BSLASH escapeSequence + ; + +escapeSequence: + characterEscapeSequence + | ZERO /* [lookahead not a member of decimalDigit] */ + | hexEscapeSequence + | unicodeEscapeSequence + ; + +characterEscapeSequence: + singleEscapeCharacter + | nonEscapeCharacter + ; + +singleEscapeCharacter: + APOSTROPHE | QUOTE | BSLASH | LOWER_B | LOWER_F | LOWER_N | LOWER_R | LOWER_T | LOWER_V + ; + +nonEscapeCharacter: + sourceCharacter /* but not escapeCharacter or lineTerminator */ + ; + +escapeCharacter: + singleEscapeCharacter + | decimalDigit + | LOWER_X + | LOWER_U + ; + +hexEscapeSequence: + LOWER_X hexDigit hexDigit + ; + +/* defined above +unicodeEscapeSequence: + LOWER_U hexDigit hexDigit hexDigit hexDigit + ;*/ + +regularExpressionLiteral: + SLASH regularExpressionBody SLASH regularExpressionFlags + ; + +regularExpressionBody: + regularExpressionFirstChar regularExpressionChars + ; + +regularExpressionChars: + /* [empty] */ + /* + * SPEC: regularExpressionChars regularExpressionChar + * ->: regularExpressionChar regularExpressionChars + */ + regularExpressionChar regularExpressionChars + ; + +regularExpressionFirstChar: + nonTerminator /* but not * or \ or / */ + | backslashSequence + ; + +regularExpressionChar: + nonTerminator /* but not * or \ or / */ + | backslashSequence + ; + +backslashSequence: + BSLASH nonTerminator + ; + +nonTerminator: + sourceCharacter /* but not lineTerminator */ + ; + +regularExpressionFlags: + /* + * SPEC: + * [empty] | regularExpressionFlags identifierPart + * -> + * (identifierPart|)* + */ + (identifierPart)* + ; + +/* A.2 Number Conversions */ + +stringNumericLiteral: + /* + * SPEC: + * (strWhiteSpace)? + * | (strWhiteSpace)? strNumericLiteral (strWhiteSpace)? + */ + (strWhiteSpace)? (strNumericLiteral (strWhiteSpace)?)? + ; + +strWhiteSpace: + strWhiteSpaceChar (strWhiteSpace)? + ; + +strWhiteSpaceChar: + TAB | SP | NBSP | FF | VT | CR | LF | LS | PS | USP + ; + +strNumericLiteral: + strDecimalLiteral + | hexIntegerLiteral + ; + +strDecimalLiteral: + strUnsignedDecimalLiteral + | PLUS strUnsignedDecimalLiteral + | MINUS strUnsignedDecimalLiteral + ; + +strUnsignedDecimalLiteral: + /* + * SPEC: + * 'Infinity' + * | decimalDigits DOT (decimalDigits)? (exponentPart)? + * | DOT decimalDigits (exponentPart)? + * | decimalDigits (exponentPart)? + */ + 'Infinity' + /* syntactic predicate used to remove nondet between ALTs 2 and 4 */ + | (decimalDigits DOT)=> decimalDigits DOT (decimalDigits)? (exponentPart)? + | DOT decimalDigits (exponentPart)? + | decimalDigits (exponentPart)? + ; + +/* defined above +decimalDigits: + decimalDigit + | decimalDigits decimalDigit + ;*/ + +/* decimalDigit: + DIGIT // grammar has them explicitly enumerated + ;*/ + +exponentPart: + exponentIndicator signedInteger + ; + +/* redefined above +exponentIndicator: + EXPONENT_INDICATOR + ;*/ + +/* redefined above +signedInteger: + decimalDigits + | PLUS decimalDigits + | MINUS decimalDigits + ;*/ + +/* redefined above +hexIntegerLiteral: + '0x' hexDigit + | '0X' hexDigit + | hexIntegerLiteral hexDigit + ;*/ + +/* redefined above +hexDigit: + HEXDIGIT // grammar has them explicitely enumerated + ; */ + +/* A.3 Expressions */ + +primaryExpression: + 'this' + | identifier + | literal + | arrayLiteral + | objectLiteral + | LPAREN expression RPAREN + ; + +arrayLiteral: + /* + * SPEC: + * LBRACK (elision)? RBRACK + * | LBRACK elementList RBRACK + * | LBRACK elementList COMMA (elision)? RBRACK + */ + LBRACK ( + (elision)? + | elementList (COMMA (elision)?)? + ) RBRACK + ; + +elementList: + /* + * SPEC: + * (elision)? assignmentExpression + * | elementList COMMA (elision)? assignmentExpression + */ + (elision)? assignmentExpression (elementListTail)* + ; + +elementListTail: + COMMA (elision)? assignmentExpression + ; + +elision: + /* + * SPEC: + * COMMA + * | elision COMMA + * -> + * (COMMA)+ + */ + (COMMA)+ + ; + +objectLiteral: + /* + * SPEC: + * LBRACE RBRACE + * | LBRACE propertyNameAndValueList RBRACE + */ + LBRACE (propertyNameAndValueList)? RBRACE + ; + +propertyNameAndValueList: + /* + * SPEC: + * propertyName COLON assignmentExpression + * | propertyNameAndValueList COMMA propertyName COLON assignmentExpression + */ + propertyName COLON assignmentExpression (propertyNameAndValueListTail)* + ; + +propertyNameAndValueListTail: + COMMA propertyName COLON assignmentExpression + ; + +propertyName: + identifier + | stringLiteral + | numericLiteral + ; + +memberExpression: + /* + * SPEC: + * primaryExpression + * | functionExpression + * | memberExpression LBRACK expression RBRACK + * | memberExpression DOT identifier + * | 'new' memberExpression arguments + * -> + */ + ( primaryExpression + | functionExpression + | 'new' memberExpression arguments + ) (memberExpressionTail)* + ; + +memberExpressionTail: + /* SPEC: not a part of formal grammar */ + LBRACK expression RBRACK + | DOT identifier + ; + +newExpression: + /* + * SPEC: + * memberExpression + * | 'new' newExpression + */ + /* syntactic predicate added to resolve between nondet in ALTs 1 and 2 */ + ('new' newExpression)=> 'new' newExpression + | memberExpression + ; + +callExpression: + /* + * SPEC: + * memberExpression arguments + * | callExpression arguments + * | callExpression LBRACK expression RBRACK + * | callExpression DOT identifier + */ + memberExpression arguments (callExpressionTail)* + ; + +callExpressionTail: + arguments + | LBRACK expression RBRACK + | DOT identifier + ; + +arguments: + /* + * SPEC: + * LPAREN RPAREN + * | LPAREN argumentList RPAREN + */ + LPAREN (argumentList)? RPAREN + ; + +argumentList: + /* + * SPEC: + * assignmentExpression + * | argumentList COMMA assignmentExpression + */ + assignmentExpression (argumentListTail)* + ; + +argumentListTail: + COMMA assignmentExpression + ; + +leftHandSideExpression: + /* + * SPEC: + * newExpression + * | callExpression + */ + ('new' newExpression)=> newExpression + | callExpression + ; + +postfixExpression: + /* + * SPEC: + * leftHandSideExpression + * | leftHandSideExpression / no line terminator here / PLUS2 + * | leftHandSideExpression / no line terminator here / MINUS2 + */ + leftHandSideExpression (PLUS2|MINUS2)? + ; + +unaryExpression: + postfixExpression + | 'delete' unaryExpression + | 'void' unaryExpression + | 'typeof' unaryExpression + | PLUS2 unaryExpression + | MINUS2 unaryExpression + | PLUS unaryExpression + | MINUS unaryExpression + | TILDE unaryExpression + | EXCLAMATION unaryExpression + ; + +multiplicativeExpression: + /* + * SPEC: + * unaryExpression + * | multiplicativeExpression ASTERISK unaryExpression + * | multiplicativeExpression DIVIDE unaryExpression + * | multiplicativeExpression PERCENT unaryExpression + */ + unaryExpression (multiplicativeExpressionTail)* + ; + +multiplicativeExpressionTail: + ASTERISK unaryExpression + | DIVIDE unaryExpression + | PERCENT unaryExpression + ; + +additiveExpression: + /* + * SPEC: + * multiplicativeExpression + * | additiveExpression PLUS multiplicativeExpression + * | additiveExpression MINUS multiplicativeExpression + */ + multiplicativeExpression (additiveExpressionTail)* + ; + +additiveExpressionTail: + PLUS multiplicativeExpression + | MINUS multiplicativeExpression + ; + +shiftExpression: + /* + * SPEC: + * additiveExpression + * | shiftExpression LSHIFT additiveExpression + * | shiftExpression RSHIFT additiveExpression + * | shiftExpression GT3 additiveExpression + */ + additiveExpression (shiftExpressionTail)* + ; + +shiftExpressionTail: + LSHIFT additiveExpression + | RSHIFT additiveExpression + | GT3 additiveExpression + ; + +relationalExpression: + /* + * SPEC: + * shiftExpression + * | relationalExpression LT shiftExpression + * | relationalExpression GT shiftExpression + * | relationalExpression LTEQ shiftExpression + * | relationalExpression GTEQ shiftExpression + * | relationalExpression 'instanceof' shiftExpression + * | relationalExpression 'in' shiftExpression + */ + shiftExpression (relationalExpressionTail)* + ; + +relationalExpressionTail: + LT shiftExpression + | GT shiftExpression + | LTEQ shiftExpression + | GTEQ shiftExpression + | 'instanceof' shiftExpression + | 'in' shiftExpression + ; + +relationalExpressionNoln: + shiftExpression + | relationalExpression (LT|GT|LTEQ|GTEQ|'instanceof') shiftExpression + ; + +equalityExpression: + /* + * SPEC: + * relationalExpression + * | equalityExpression (EQ2|NOTEQQ|EQ3|NOTEQQ2) relationalExpression + */ + relationalExpression (equalityExpressionTail)* + ; + +equalityExpressionTail: + (EQ2|NOTEQ|EQ3|NOTEQ2) relationalExpression + ; + +equalityExpressionNoln: + /* + * SPEC: + * relationalExpressionNoln + * | equalityExpressionNoln (EQ2|NOTEQQ|EQ3|NOTEQQ2) relationalExpressionNoln + */ + relationalExpressionNoln (equalityExpressionNolnTail)* + ; + +equalityExpressionNolnTail: + (EQ2|NOTEQ|EQ3|NOTEQ2) relationalExpressionNoln + ; + +bitwiseAndExpression: + /* + * SPEC: + * equalityExpression + * | bitwiseAndExpression AMPER equalityExpression + */ + equalityExpression (bitwiseAndExpressionTail)* + ; + +bitwiseAndExpressionTail: + AMPER equalityExpression + ; + +bitwiseAndExpressionNoln: + /* + * SPEC: + * equalityExpressionNoln + * | bitwiseAndExpressionNoln AMPER equalityExpressionNoln + */ + equalityExpressionNoln (bitwiseAndExpressionNolnTail)* + ; + +bitwiseAndExpressionNolnTail: + AMPER equalityExpressionNoln + ; + +bitwiseXorExpression: + /* + * SPEC: + * bitwiseAndExpression + * | bitwiseXorExpression CAROT bitwiseAndExpression + */ + bitwiseAndExpression (bitwiseXorExpressionTail)* + ; + +bitwiseXorExpressionTail: + CAROT bitwiseAndExpression + ; + +bitwiseXorExpressionNoln: + /* + * SPEC: + * bitwiseAndExpressionNoln + * | bitwiseXorExpressionNoln CAROT bitwiseAndExpressionNoln + */ + bitwiseAndExpressionNoln (bitwiseXorExpressionNolnTail)* + ; + +bitwiseXorExpressionNolnTail: + CAROT bitwiseAndExpressionNoln + ; + +bitwiseOrExpression: + /* + * SPEC: + * bitwiseXorExpression + * | bitwiseOrExpression PIPE bitwiseXorExpression + */ + bitwiseXorExpression (bitwiseOrExpressionTail)* + ; + +bitwiseOrExpressionTail: + PIPE bitwiseXorExpression + ; + +bitwiseOrExpressionNoln: + /* + * SPEC: + * bitwiseXorExpressionNoln + * | bitwiseOrExpressionNoln PIPE bitwiseXorExpressionNoln + */ + bitwiseXorExpressionNoln (bitwiseOrExpressionNolnTail)* + ; + +bitwiseOrExpressionNolnTail: + PIPE bitwiseOrExpressionNolnTail + ; + +logicalAndExpression: + bitwiseOrExpression + | logicalAndExpressionNoln AMPER2 bitwiseOrExpression + ; + +logicalAndExpressionNoln: + /* + * SPEC: + * bitwiseOrExpressionNoln + * | logicalAndExpressionNoln AMPER2 bitwiseOrExpressionNoln + */ + bitwiseOrExpressionNoln (logicalAndExpressionNolnTail)* + ; + +logicalAndExpressionNolnTail: + AMPER2 bitwiseOrExpressionNoln + ; + +logicalOrExpression: + /* + * SPEC: + * logicalAndExpression + * | logicalOrExpression '||' logicalAndExpression + */ + logicalAndExpression (logicalOrExpressionTail)* + ; + +logicalOrExpressionTail: + '||' logicalAndExpression + ; + +logicalOrExpressionNoln: + /* + * SPEC: + * logicalAndExpressionNoln + * | logicalOrExpressionNoln '||' logicalAndExpressionNoln + */ + logicalAndExpressionNoln (logicalOrExpressionNolnTail)* + ; + +logicalOrExpressionNolnTail: + '||' logicalAndExpressionNoln + ; + +conditionalExpression: + logicalOrExpression + | logicalOrExpression QUESTION assignmentExpression COLON assignmentExpression + ; + +conditionalExpressionNoln: + logicalOrExpressionNoln + | logicalOrExpressionNoln QUESTION assignmentExpressionNoln COLON assignmentExpressionNoln + ; + +assignmentExpression: + /* + * SPEC: + * conditionalExpression + * | leftHandSideExpression assignmentOperator assignmentExpression + */ + (leftHandSideExpression assignmentOperator) => + leftHandSideExpression assignmentOperator assignmentExpression + | conditionalExpression + ; + +assignmentExpressionNoln: + conditionalExpressionNoln + | leftHandSideExpression assignmentOperator assignmentExpressionNoln + ; + +assignmentOperator: + /* note that in the grammar these are listed out explicitely */ + EQ | TIMESEQ | DIVIDEEQ | PERCENTEQ | PLUSEQ | MINUSEQ | LSHIFTEQ | RSHIFTEQ + | GT3EQ | AMPEREQ | CAROTEQ | PIPEEQ + ; + +expression: + /* + * SPEC: + * assignmentExpression + * | expression COMMA assignmentExpression + */ + assignmentExpression (expressionTail)* + ; + +expressionTail: + COMMA assignmentExpression + ; + +expressionNoln: + /* + * SPEC: + * assignmentExpressionNoln + * | expressionNoln COMMA assignmentExpressionNoln + */ + assignmentExpressionNoln (expressionNolnTail)* + ; + +expressionNolnTail: + COMMA assignmentExpressionNoln + ; + +/* A.4 Statements */ + +statement: + block + | variableStatement + | emptyStatement + | expressionStatement + | ifStatement + | iterationStatement + | continueStatement + | breakStatement + | returnStatement + | withStatement + | labelledStatement + | switchStatement + | throwStatement + | tryStatement + ; + +block: + LBRACE (statementList)? RBRACE + ; + +statementList: + /* + * SPEC: + * statement + * | statementList statement + */ + (statement)+ + ; + +variableStatement: + 'var' variableDeclarationList SEMI + ; + +variableDeclarationList: + /* + * SPEC: + * variableDeclaration + * | variableDeclarationList COMMA variableDeclaration + */ + variableDeclaration (variableDeclarationTail)* + ; + +variableDeclarationTail: + COMMA variableDeclaration + ; + +variableDeclarationListNoln: + /* + * SPEC: + * variableDeclarationNoln + * | variableDeclarationListNoln COMMA variableDeclarationNoln + */ + variableDeclarationNoln (variableDeclarationListNolnTail)* + ; + +variableDeclarationListNolnTail: + COMMA variableDeclarationNoln + ; + +variableDeclaration: + identifier (initialiser)? + ; + +variableDeclarationNoln: + identifier (initialiserNoln)? + ; + +initialiser: + EQ assignmentExpression + ; + +initialiserNoln: + EQ assignmentExpressionNoln + ; + +emptyStatement: + ; + +expressionStatement: + /* [lookahead not a member of {{, function}} */ expression SEMI + ; + +ifStatement: + 'if' LPAREN expression RPAREN statement 'else' statement + | 'if' LPAREN expression RPAREN statement + ; + +iterationStatement: + 'do' statement 'while' LPAREN expression RPAREN SEMI + | 'while' LPAREN expression RPAREN statement + | 'for' LPAREN ( + (expressionNoln)? SEMI (expression)? SEMI (expression)? RPAREN statement + | 'var' variableDeclarationListNoln SEMI (expression)? SEMI (expression)? RPAREN statement + | leftHandSideExpression 'in' expression RPAREN statement + | 'var' variableDeclarationNoln 'in' expression RPAREN statement + ) + ; + +continueStatement: + 'continue' /* [ no line terminator here ] */ (identifier)? SEMI + ; + +breakStatement: + 'break' /* [ no line terminator here ] */ (identifier)? SEMI + ; + +returnStatement: + 'return' /* [no line terminator here] */ (expression)? SEMI + ; + +withStatement: + 'with' LPAREN expression RPAREN statement + ; + +switchStatement: + 'switch' LPAREN expression RPAREN caseBlock + ; + +caseBlock: + LBRACE (caseClauses)? RBRACE + | LBRACE (caseClauses)? defaultClause (caseClauses)? RBRACE + ; + +caseClauses: + /* + * SPEC: + * caseClause + * | caseClauses caseClause + */ + (caseClause)+ + ; + +caseClause: + 'case' expression COLON (statementList)? + ; + +defaultClause: + 'default' COLON (statementList)? + ; + +labelledStatement: + identifier COLON statement + ; + +throwStatement: + 'throw' /* [no line terminator here] */ expression SEMI + ; + +tryStatement: + 'try' block catch_ + | 'try' block finally_ + | 'try' block catch_ finally_ + ; + +catch_: + 'catch' LPAREN identifier RPAREN block + ; + +finally_: + 'finally' block + ; + +/* A.5 Functions and Programs */ + +functionDeclaration: + 'function' identifier LPAREN (formalParameterList)? LBRACE functionBody RBRACE + ; + +functionExpression: + 'function' (identifier)? LPAREN (formalParameterList)? LBRACE functionBody RBRACE + ; + +formalParameterList: + /* + * SPEC: + * identifier + * | formalParameterList COMMA identifier + */ + identifier (formalParameterListTail)* + ; + +formalParameterListTail: + COMMA identifier + ; + +functionBody: + sourceElements + ; + +/* +* program is actually the starting element for the grammar so I have commented +* out this one and then copied it to the very beginning as that is what the +* start really is. +*/ +/*program: + sourceElements + ;*/ + +sourceElements: + /* + * SPEC: + * sourceStatement + * | sourceElements sourceElement + */ + (sourceElement)+ + ; + +sourceElement: + statement + | functionDeclaration + ; + +/* A.6 URI character classes */ + +uri: + (uriCharacters)? + ; + +uriCharacters: + uriCharacter (uriCharacters)? + ; + +uriCharacter: + uriReserved + | uriUnescaped + | uriEscaped + ; + +uriReserved: + SEMI | SLASH | QUESTION | COLON | AT | AMPER | EQ | PLUS | DOLLAR | COMMA + ; + +uriUnescaped: + uriAlpha + | decimalDigit + | uriMark + ; + +uriEscaped: + PERCENT hexDigit hexDigit + ; + +uriAlpha: + ALPHA_CHARACTER /* consists of a-zA-Z */ + ; + +uriMark: + MINUS | UNDERSCORE | DOT | EXCLAMATION | TILDE | ASTERISK | APOSTROPHE | LPAREN | RPAREN + ; + +/* A.7 Regular Exrpessions */ + +patter: + disjunction + ; + +disjunction: + alternative + | alternative PIPE disjunction + ; + +alternative: + /* + * SPEC: + * -empty- + *| alternative term + */ + (term)* + ; + +term: + assertion + | atom + | atom quantifier + ; + +assertion: + CAROT + | DOLLAR + | '\\b' /* double check this - looks like a space in the manual? */ + | '\\B' /* double check this - looks like a space in the manual? */ + ; + +quantifier: + quantifierPrefix + | quantifierPrefix QUESTION + ; + +quantifierPrefix: + ASTERISK + | PLUS + | QUESTION + | LBRACE decimalDigits RBRACE + | LBRACE decimalDigits COMMA RBRACE + | LBRACE decimalDigits COMMA decimalDigits RBRACE + ; + +atom: + patternCharacter + | DOT + | BSLASH atomEscape + | characterClass + | LPAREN ((COLON|EQ|EXCLAMATION)? disjunction) RPAREN + ; + +patternCharacter: + sourceCharacter /* but not any of: + ^ $ \ . * + ? ( ) [ ] { } | + */ + ; + +atomEscape: + decimalEscape + | characterEscape + | characterClassEscape + ; + +characterEscape: + controlEscape + | LOWER_C controlLetter + | hexEscapeSequence + | unicodeEscapeSequence + | identityEscape + ; + +controlEscape: + CONTROL_ESCAPE_CHAR /* one of: fnrtv */ + ; + +controlLetter: + /* one of: a-z A-Z */ + LOWER_ALPHA_CHAR + | UPPER_ALPHA_CHAR + ; + +identityEscape: + sourceCharacter /* but not identifierPart */ + ; + +characterClassEscape: + 'd' | 'D' | 's' | 'S' | 'w' | 'W' + ; + +decimalEscape: + decimalIntegerLiteral /* lookahead not a member of decimalDigit */ + ; + +characterClass: + /* [ [lookahead not a member of {^}] ClassRanges ] + | [ ^ classRanges ] + */ + ; + +classRanges: + /* empty */ + | nonemptyClassRanges + ; + +nonemptyClassRanges: + classAtom + | classAtom nonemptyClassRangesNoDash + | classAtom MINUS classAtom classRanges + ; + +nonemptyClassRangesNoDash: + classAtom + | classAtomNoDash nonemptyClassRangesNoDash + | classAtomNoDash MINUS classAtom classRanges + ; + +classAtom: + MINUS + | classAtomNoDash + ; + +classAtomNoDash: + sourceCharacter /* but not one of: \ ] - */ + | BSLASH classEscape + ; + +classEscape: + decimalEscape + | LOWER_B + | characterEscape + | characterClassEscape + ; + + + +/* a few basic characters and other things that I am going to see */ + +SEMI: ';'; +MPER: '&'; +//DASH: '-'; +EQ: '='; +COMMA: ','; +SLASH: '/'; +BSLASH: '\\'; +LBRACK: '['; +RBRACK: ']'; +LBRACE: '{'; +RBRACE: '}'; +LPAREN: '('; +RPAREN: ')'; +APOSTROPHE: '\''; +QUOTE: '"'; +QUESTION: '?'; +COLON: ':'; +ASTERISK: '*'; +AT : '@'; +AMPER : '&'; +PLUS : '+'; +MINUS:'-'; +DOLLAR : '$'; +UNDERSCORE:'_'; +DOT : '.'; +LT : '<'; +GT : '>'; +LTEQ: '<='; +GTEQ : '>='; +EQ2 : '=='; +NOTEQ: '!='; +EQ3 : '==='; +NOTEQ2: '!=='; +STAR:'*'; +PERCENT : '%'; +PLUS2:'++'; +MINUS2:'--'; +LSHIFT:'<<'; +RSHIFT:'>>'; +GT3:'>>>'; +PIPE : '|'; +CAROT : '^'; +EXCLAMATION: '!'; +TILDE:'~'; +AMPER2:'&&'; +PIPE2 : '||'; +PLUSEQ:'+='; +MINUSEQ:'-='; +TIMESEQ:'*='; +PERCENTEQ:'%='; +LSHIFTEQ:'<<='; +RSHIFTEQ: '>>='; +GT3EQ : '>>>='; +AMPEREQ:'&='; +PIPEEQ : '|='; +CAROTEQ : '^='; +DIVIDE : '/'; +DIVIDEEQ: '/='; + +ZERO : '0'; +NON_ZERO_DIGIT + : ('1'..'9'); +DIGIT : ('0'..'9'); +EXPONENT_INDICATOR + : 'e'|'E'; + +CONTROL_ESCAPE_CHAR + : 'f'|'n'|'r'|'t'|'v'; /* one of: fnrtv */ + +LOWER_B: 'b'; +LOWER_C : 'c'; +LOWER_F: 'f'; +LOWER_N: 'n'; +LOWER_R: 'r'; +LOWER_T: 't'; +LOWER_V: 'v'; +LOWER_X: 'x'; +LOWER_U: 'u'; + +ALPHA_CHARACTER + : ('a'..'z')|('A'..'Z'); +LOWER_ALPHA_CHAR + : ('a'..'z'); + +UPPER_ALPHA_CHAR + : ('a'..'z'); + +WS: // ignore white space as it doesn't matter + ( ' ' | '\r' '\n' {newline();}| '\n' {newline();} | '\t' ) { $setType(Token.SKIP); } + ; + +SOURCE_CHAR: ('\u0000'..'\uFFFE'); +TAB: '\u0009'; +VT: '\u000b'; +FF: '\u000c'; +SP: '\u0020'; +NBSP: '\u00a0'; +USP: '\u1680' // OGHAM SPACE MARK + | '\u2000' // EN QUAD + | '\u2001' // EM QUAD + | '\u2002' // EN SPACE + | '\u2003' // EM SPACE + | '\u2004' // THREE-PER-EM SPACE + | '\u2005' // FOUR-PER-EM SPACE + | '\u2006' // SIX-PER-EM SPACE + | '\u2007' // FIGURE SPACE + | '\u2008' // PUNCTUATION SPACE + | '\u2009' // THIN SPACE + | '\u200A' // HAIR SPACE + | '\u200B' // ZERO WIDTH SPACE + | '\u202F' // NARROW NO-BREAK SPACE + | '\u3000' // IDEOGRAPHIC SPACE + ; + +LF: '\u000a'; // line feed +CR: '\u000d'; // carriage return +LS: '\u2028'; // line separator +PS: '\u2029'; // paragraph separator + +UNICODE_LETTER: + ('\u0041'..'\u005A') | ('\u0061'..'\u007A') | '\u00AA' | '\u00B5' + | '\u00BA' | ('\u00C0'..'\u00D6') | ('\u00D8'..'\u00F6') | ('\u00F8'..'\u021F') + | ('\u0222'..'\u0233') | ('\u0250'..'\u02AD') | ('\u02B0'..'\u02B8') | ('\u02BB'..'\u02C1') + | ('\u02D0'..'\u02D1') | ('\u02E0'..'\u02E4') | '\u02EE' | '\u037A' + | '\u0386' | ('\u0388'..'\u038A') | '\u038C' | ('\u038E'..'\u03A1') + | ('\u03A3'..'\u03CE') | ('\u03D0'..'\u03D7') | ('\u03DA'..'\u03F3') | ('\u0400'..'\u0481') + | ('\u048C'..'\u04C4') | ('\u04C7'..'\u04C8') | ('\u04CB'..'\u04CC') | ('\u04D0'..'\u04F5') + | ('\u04F8'..'\u04F9') | ('\u0531'..'\u0556') | '\u0559' |('\u0561'..'\u0587') + | ('\u05D0'..'\u05EA') | ('\u05F0'..'\u05F2') | ('\u0621'..'\u063A') |('\u0640'..'\u064A') + | ('\u0671'..'\u06D3') | '\u06D5' | ('\u06E5'..'\u06E6') |('\u06FA'..'\u06FC') + | '\u0710' | ('\u0712'..'\u072C') | ('\u0780'..'\u07A5') |('\u0905'..'\u0939') + | '\u093D' | '\u0950' | ('\u0958'..'\u0961') |('\u0985'..'\u098C') + | ('\u098F'..'\u0990') | ('\u0993'..'\u09A8') | ('\u09AA'..'\u09B0') | '\u09B2' + | ('\u09B6'..'\u09B9') | ('\u09DC'..'\u09DD') | ('\u09DF'..'\u09E1') |('\u09F0'..'\u09F1') + | ('\u0A05'..'\u0A0A') | ('\u0A0F'..'\u0A10') | ('\u0A13'..'\u0A28') |('\u0A2A'..'\u0A30') + | ('\u0A32'..'\u0A33') | ('\u0A35'..'\u0A36') | ('\u0A38'..'\u0A39') |('\u0A59'..'\u0A5C') + | '\u0A5E' | ('\u0A72'..'\u0A74') | ('\u0A85'..'\u0A8B') | '\u0A8D' + | ('\u0A8F'..'\u0A91') | ('\u0A93'..'\u0AA8') | ('\u0AAA'..'\u0AB0') |('\u0AB2'..'\u0AB3') + | ('\u0AB5'..'\u0AB9') | '\u0ABD' | '\u0AD0' | '\u0AE0' + | ('\u0B05'..'\u0B0C') | ('\u0B0F'..'\u0B10') | ('\u0B13'..'\u0B28') |('\u0B2A'..'\u0B30') + | ('\u0B32'..'\u0B33') | ('\u0B36'..'\u0B39') | '\u0B3D' |('\u0B5C'..'\u0B5D') + | ('\u0B5F'..'\u0B61') | ('\u0B85'..'\u0B8A') | ('\u0B8E'..'\u0B90') |('\u0B92'..'\u0B95') + | ('\u0B99'..'\u0B9A') | '\u0B9C' | ('\u0B9E'..'\u0B9F') |('\u0BA3'..'\u0BA4') + | ('\u0BA8'..'\u0BAA') | ('\u0BAE'..'\u0BB5') | ('\u0BB7'..'\u0BB9') |('\u0C05'..'\u0C0C') + | ('\u0C0E'..'\u0C10') | ('\u0C12'..'\u0C28') | ('\u0C2A'..'\u0C33') |('\u0C35'..'\u0C39') + | ('\u0C60'..'\u0C61') | ('\u0C85'..'\u0C8C') | ('\u0C8E'..'\u0C90') |('\u0C92'..'\u0CA8') + | ('\u0CAA'..'\u0CB3') | ('\u0CB5'..'\u0CB9') | '\u0CDE' |('\u0CE0'..'\u0CE1') + | ('\u0D05'..'\u0D0C') | ('\u0D0E'..'\u0D10') | ('\u0D12'..'\u0D28') |('\u0D2A'..'\u0D39') + | ('\u0D60'..'\u0D61') | ('\u0D85'..'\u0D96') | ('\u0D9A'..'\u0DB1') |('\u0DB3'..'\u0DBB') + | '\u0DBD' | ('\u0DC0'..'\u0DC6') | ('\u0E01'..'\u0E30') |('\u0E32'..'\u0E33') + | ('\u0E40'..'\u0E46') | ('\u0E81'..'\u0E82') | '\u0E84' |('\u0E87'..'\u0E88') + | '\u0E8A' | '\u0E8D' | ('\u0E94'..'\u0E97') |('\u0E99'..'\u0E9F') + | ('\u0EA1'..'\u0EA3') | '\u0EA5' | '\u0EA7' |('\u0EAA'..'\u0EAB') + | ('\u0EAD'..'\u0EB0') | ('\u0EB2'..'\u0EB3') | ('\u0EBD'..'\u0EC4') | '\u0EC6' + | ('\u0EDC'..'\u0EDD') | '\u0F00' | ('\u0F40'..'\u0F6A') |('\u0F88'..'\u0F8B') + | ('\u1000'..'\u1021') | ('\u1023'..'\u1027') | ('\u1029'..'\u102A') |('\u1050'..'\u1055') + | ('\u10A0'..'\u10C5') | ('\u10D0'..'\u10F6') | ('\u1100'..'\u1159') |('\u115F'..'\u11A2') + | ('\u11A8'..'\u11F9') | ('\u1200'..'\u1206') | ('\u1208'..'\u1246') | '\u1248' + | ('\u124A'..'\u124D') | ('\u1250'..'\u1256') | '\u1258' |('\u125A'..'\u125D') + | ('\u1260'..'\u1286') | '\u1288' | ('\u128A'..'\u128D') |('\u1290'..'\u12AE') + | '\u12B0' | ('\u12B2'..'\u12B5') | ('\u12B8'..'\u12BE') | '\u12C0' + | ('\u12C2'..'\u12C5') | ('\u12C8'..'\u12CE') | ('\u12D0'..'\u12D6') |('\u12D8'..'\u12EE') + | ('\u12F0'..'\u130E') | '\u1310' | ('\u1312'..'\u1315') |('\u1318'..'\u131E') + | ('\u1320'..'\u1346') | ('\u1348'..'\u135A') | ('\u13A0'..'\u13B0') |('\u13B1'..'\u13F4') + | ('\u1401'..'\u1676') | ('\u1681'..'\u169A') | ('\u16A0'..'\u16EA') |('\u1780'..'\u17B3') + | ('\u1820'..'\u1877') | ('\u1880'..'\u18A8') | ('\u1E00'..'\u1E9B') |('\u1EA0'..'\u1EE0') + | ('\u1EE1'..'\u1EF9') | ('\u1F00'..'\u1F15') | ('\u1F18'..'\u1F1D') |('\u1F20'..'\u1F39') + | ('\u1F3A'..'\u1F45') | ('\u1F48'..'\u1F4D') | ('\u1F50'..'\u1F57') | '\u1F59' + | '\u1F5B' | '\u1F5D' | ('\u1F5F'..'\u1F7D') | ('\u1F80'..'\u1FB4') + | ('\u1FB6'..'\u1FBC') | '\u1FBE' | ('\u1FC2'..'\u1FC4') | ('\u1FC6'..'\u1FCC') + | ('\u1FD0'..'\u1FD3') | ('\u1FD6'..'\u1FDB') | ('\u1FE0'..'\u1FEC') | ('\u1FF2'..'\u1FF4') + | ('\u1FF6'..'\u1FFC') | '\u207F' | '\u2102' | '\u2107' + | ('\u210A'..'\u2113') | '\u2115' | ('\u2119'..'\u211D') | '\u2124' + | '\u2126' | '\u2128' | ('\u212A'..'\u212D') | ('\u212F'..'\u2131') + | ('\u2133'..'\u2139') | ('\u2160'..'\u2183') | ('\u3005'..'\u3007') | ('\u3021'..'\u3029') + | ('\u3031'..'\u3035') | ('\u3038'..'\u303A') | ('\u3041'..'\u3094') | ('\u309D'..'\u309E') + | ('\u30A1'..'\u30FA') | ('\u30FC'..'\u30FE') | ('\u3105'..'\u312C') | ('\u3131'..'\u318E') + | ('\u31A0'..'\u31B7') | '\u3400' | '\u4DB5' | '\u4E00' + | '\u9FA5' | ('\uA000'..'\uA48C') | '\uAC00' | '\uD7A3' + | ('\uF900'..'\uFA2D') | ('\uFB00'..'\uFB06') | ('\uFB13'..'\uFB17') | '\uFB1D' + | ('\uFB1F'..'\uFB28') | ('\uFB2A'..'\uFB36') | ('\uFB38'..'\uFB3C') | '\uFB3E' + | ('\uFB40'..'\uFB41') | ('\uFB43'..'\uFB44') | ('\uFB46'..'\uFBB1') | ('\uFBD3'..'\uFD3D') + | ('\uFD50'..'\uFD8F') | ('\uFD92'..'\uFDC7') | ('\uFDF0'..'\uFDFB') | ('\uFE70'..'\uFE72') + | '\uFE74' | ('\uFE76'..'\uFEFC') | ('\uFF21'..'\uFF3A') | ('\uFF41'..'\uFF5A') + | ('\uFF66'..'\uFFBE') | ('\uFFC2'..'\uFFC7') | ('\uFFCA'..'\uFFCF') | ('\uFFD2'..'\uFFD7') + | ('\uFFDA'..'\uFFDC') + ; + +HEXDIGIT: ('0'..'9')|('a'..'f')|('A'..'F'); + +UNICODE_DIGIT: + ('\u0030'..'\u0039') | ('\u0660'..'\u0669') | ('\u06F0'..'\u06F9') | ('\u0966'..'\u096F') + | ('\u09E6'..'\u09EF') | ('\u0A66'..'\u0A6F') | ('\u0AE6'..'\u0AEF') | ('\u0B66'..'\u0B6F') + | ('\u0BE7'..'\u0BEF') | ('\u0C66'..'\u0C6F') | ('\u0CE6'..'\u0CEF') | ('\u0D66'..'\u0D6F') + | ('\u0E50'..'\u0E59') | ('\u0ED0'..'\u0ED9') | ('\u0F20'..'\u0F29') | ('\u1040'..'\u1049') + | ('\u1369'..'\u1371') | ('\u17E0'..'\u17E9') | ('\u1810'..'\u1819') | ('\uFF10'..'\uFF19') + ; + +UNICODE_NONSPACING_MARK + : ('\u0300'..'\u036F'); // And more... see: http://www.fileformat.info/info/unicode/category/Mn/list.htm + +UNICODE_COMBINING_MARK: // Appears to be bogus... see: http://www.fileformat.info/info/unicode/category/Mc/list.htm + ('\u0300'..'\u034E') | ('\u0360'..'\u0362') | ('\u0483'..'\u0486') | ('\u0591'..'\u05A1') + | ('\u05A3'..'\u05B9') | ('\u05BB'..'\u05BD') | '\u05BF' | ('\u05C1'..'\u05C2') + | '\u05C4' | ('\u064B'..'\u0655') | '\u0670' | ('\u06D6'..'\u06DC') + | ('\u06DF'..'\u06E4') | ('\u06E7'..'\u06E8') | ('\u06EA'..'\u06ED') | '\u0711' + | ('\u0730'..'\u074A') | ('\u07A6'..'\u07B0') | ('\u0901'..'\u0903') | '\u093C' + | ('\u093E'..'\u094D') | ('\u0951'..'\u0954') | ('\u0962'..'\u0963') | ('\u0981'..'\u0983') + | ('\u09BC'..'\u09C4') | ('\u09C7'..'\u09C8') | ('\u09CB'..'\u09CD') | '\u09D7' + | ('\u09E2'..'\u09E3') | '\u0A02' | '\u0A3C' | ('\u0A3E'..'\u0A42') + | ('\u0A47'..'\u0A48') | ('\u0A4B'..'\u0A4D') | ('\u0A70'..'\u0A71') | ('\u0A81'..'\u0A83') + | '\u0ABC' | ('\u0ABE'..'\u0AC5') | ('\u0AC7'..'\u0AC9') | ('\u0ACB'..'\u0ACD') + | ('\u0B01'..'\u0B03') | '\u0B3C' | ('\u0B3E'..'\u0B43') | ('\u0B47'..'\u0B48') + | ('\u0B4B'..'\u0B4D') | ('\u0B56'..'\u0B57') | ('\u0B82'..'\u0B83') | ('\u0BBE'..'\u0BC2') + | ('\u0BC6'..'\u0BC8') | ('\u0BCA'..'\u0BCD') | '\u0BD7' | ('\u0C01'..'\u0C03') + | ('\u0C3E'..'\u0C44') | ('\u0C46'..'\u0C48') | ('\u0C4A'..'\u0C4D') | ('\u0C55'..'\u0C56') + | ('\u0C82'..'\u0C83') | ('\u0CBE'..'\u0CC4') | ('\u0CC6'..'\u0CC8') | ('\u0CCA'..'\u0CCD') + | ('\u0CD5'..'\u0CD6') | ('\u0D02'..'\u0D03') | ('\u0D3E'..'\u0D43') | ('\u0D46'..'\u0D48') + | ('\u0D4A'..'\u0D4D') | '\u0D57' | ('\u0D82'..'\u0D83') | '\u0DCA' + | ('\u0DCF'..'\u0DD4') | '\u0DD6' | ('\u0DD8'..'\u0DDF') | ('\u0DF2'..'\u0DF3') + | '\u0E31' | ('\u0E34'..'\u0E3A') | ('\u0E47'..'\u0E4E') | '\u0EB1' + | ('\u0EB4'..'\u0EB9') | ('\u0EBB'..'\u0EBC') | ('\u0EC8'..'\u0ECD') | ('\u0F18'..'\u0F19') + | '\u0F35' | '\u0F37' | '\u0F39' | ('\u0F3E'..'\u0F3F') + | ('\u0F71'..'\u0F84') | ('\u0F86'..'\u0F87') | ('\u0F90'..'\u0F97') | ('\u0F99'..'\u0FBC') + | '\u0FC6' | ('\u102C'..'\u1032') | ('\u1036'..'\u1039') | ('\u1056'..'\u1059') + | ('\u17B4'..'\u17D3') | '\u18A9' | ('\u20D0'..'\u20DC') | '\u20E1' + | ('\u302A'..'\u302F') | ('\u3099'..'\u309A') | '\uFB1E' | ('\uFE20'..'\uFE23') + ; + +UNICODE_CONNECTOR_PUNCTUATION: + '\u005F' | ('\u203F'..'\u2040') | '\u30FB' | ('\uFE33'..'\uFE34') | ('\uFE4D'..'\uFE4F') + | '\uFF3F' | '\uFF65' + ; \ No newline at end of file diff --git a/test/test-main.js b/test/test-main.js index a67981c28..0ed0cb8f8 100644 --- a/test/test-main.js +++ b/test/test-main.js @@ -6,11 +6,14 @@ for (var file in window.__karma__.files) { if (window.__karma__.files.hasOwnProperty(file)) { if (/spec\.js$/.test(file)) { var file2 = file.substr(10,file.length-13); - console.log(file2); + console.log('Testing with: '+file2); + tests.push(file2); + // } } } +//tests.push('parser/flow.spec'); require.config({ // Karma serves files from '/base'