From e07c25f563b85a4b6e0065c46464aa4880b2c2e1 Mon Sep 17 00:00:00 2001 From: Alexey Shamrin Date: Thu, 12 Apr 2012 18:57:47 +0400 Subject: [PATCH] pretty 'rule not defined' message; SyntaxNode.message now accept the message --- lib/compiledgrammar.js | 31 +++++++++++++++++++------------ lib/parser.js | 7 +++++-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/lib/compiledgrammar.js b/lib/compiledgrammar.js index 18cc543..31325f5 100644 --- a/lib/compiledgrammar.js +++ b/lib/compiledgrammar.js @@ -35,14 +35,15 @@ function CompiledGrammar(/*String*/ aGrammar) var tree = getLanguageParser().parse(aGrammar); - compileOpcodeTableFromRules(this.table, this.nameToUID, buildRulesFromSyntaxTree(tree)); + var r = buildRulesFromSyntaxTree(tree); + compileOpcodeTableFromRules(this.table, this.nameToUID, r.rules, r.firstUsageNodes) return this; } module.exports = CompiledGrammar; -function compileOpcodeTableFromRules(/*Array*/ table, /*Object*/ nameToUID, /*Object*/ rules) +function compileOpcodeTableFromRules(/*Array*/ table, /*Object*/ nameToUID, /*Object*/ rules, /*Object*/ firstUsageNodes) { table[0] = [0, "source", 1]; table.length = 1; @@ -102,8 +103,8 @@ function compileOpcodeTableFromRules(/*Array*/ table, /*Object*/ nameToUID, /*Ob return true; } - traverseRulesAnchoredAtName(rules, "start", process); - traverseRulesAnchoredAtName(rules, "%start", process); + traverseRulesAnchoredAtName(rules, firstUsageNodes, "start", process); + traverseRulesAnchoredAtName(rules, firstUsageNodes, "%start", process); var hasOwnProperty = Object.prototype.hasOwnProperty, remainingRules = { }; @@ -137,7 +138,7 @@ function compileOpcodeTableFromRules(/*Array*/ table, /*Object*/ nameToUID, /*Ob } } -function traverseRulesAnchoredAtName(/*Object*/ rules, /*String*/ aName, /*Function*/ process) +function traverseRulesAnchoredAtName(/*Object*/ rules, /*Object*/ firstUsageNodes, /*String*/ aName, /*Function*/ process) { var index = 0, stack = [aName]; @@ -148,7 +149,7 @@ function traverseRulesAnchoredAtName(/*Object*/ rules, /*String*/ aName, /*Funct rule = rules[hash]; if (!rule) - throw "Rule \"" + hash + "\" is not defined."; + throw firstUsageNodes[hash].message("Rule \"" + hash + "\" is not defined."); if (process(rule) === false) continue; @@ -163,14 +164,15 @@ function traverseRulesAnchoredAtName(/*Object*/ rules, /*String*/ aName, /*Funct function buildRulesFromSyntaxTree(/*SyntaxNode*/ aNode) { var rules = { }, - walker = { traversesTextNodes:false }; + walker = { traversesTextNodes:false }, + firstUsageNodes = { }; walker.exitedNode = function(aNode) { var builder = RULE_BUILDERS[aNode.name]; if (builder) - aNode.hash = builder(aNode, rules); + aNode.hash = builder(aNode, rules, firstUsageNodes); } aNode.traverse(walker); @@ -181,12 +183,12 @@ function buildRulesFromSyntaxTree(/*SyntaxNode*/ aNode) builder = RULE_BUILDERS["%" + name] || RULE_BUILDERS[name]; if (builder) - aNode.hash = builder(aNode, rules); + aNode.hash = builder(aNode, rules, firstUsageNodes); } aNode.traverse(walker); - return rules; + return {rules: rules, firstUsageNodes: firstUsageNodes}; } var RULE_BUILDERS = { }; @@ -289,9 +291,14 @@ RULE_BUILDERS["%ErrorChoiceExpression"] = function(aNode, rules) return hash; } -RULE_BUILDERS["Identifier"] = function(aNode, rules) +RULE_BUILDERS["Identifier"] = function(aNode, rules, firstUsageNodes) { - return aNode.innerText(); + var hash = aNode.innerText(); + + if(!firstUsageNodes[hash]) + firstUsageNodes[hash] = aNode; + + return hash; } RULE_BUILDERS["%Identifier"] = function(aNode, rules) diff --git a/lib/parser.js b/lib/parser.js index b8862bb..e356a7d 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -277,8 +277,11 @@ function SyntaxNode(/*String*/ aName, /*String*/ aSource, /*Number*/ aLocation, this.error = anErrorMessage; } -SyntaxNode.prototype.message = function() +SyntaxNode.prototype.message = function(error) { + if(!error) + error = this.error; + var source = this.source, lineNumber = 1, index = 0, @@ -302,7 +305,7 @@ SyntaxNode.prototype.message = function() message += (new Array(this.range.location - start + 1)).join(" "); message += (new Array(Math.min(range.length, line.length) + 1)).join("^") + "\n"; - message += "ERROR line " + lineNumber + ": " + this.error; + message += "ERROR line " + lineNumber + ": " + error; return message; }