From d1fe86683b75d29ef52495ad643ca6b064d6a5f5 Mon Sep 17 00:00:00 2001 From: David Majda Date: Fri, 3 Apr 2015 17:28:48 +0200 Subject: [PATCH] Improve location info in tracing events Replace |line|, |column|, and |offset| properties of tracing events with the |location| property. It contains an object similar to the one returned by the |location| function available in action code: { start: { offset: 23, line: 5, column: 6 }, end: { offset: 25, line: 5, column: 8 } } For the |rule.match| event, |start| refers to the position at the beginning of the matched input and |end| refers to the position after the end of the matched input. For |rule.enter| and |rule.fail| events, both |start| and |end| refer to the current position at the time the rule was entered. --- lib/compiler/passes/generate-javascript.js | 91 +++++++++++++--------- spec/api/generated-parser-api.spec.js | 82 ++++++++++--------- spec/api/pegjs-api.spec.js | 4 +- 3 files changed, 99 insertions(+), 78 deletions(-) diff --git a/lib/compiler/passes/generate-javascript.js b/lib/compiler/passes/generate-javascript.js index 300cf8a..e941806 100644 --- a/lib/compiler/passes/generate-javascript.js +++ b/lib/compiler/passes/generate-javascript.js @@ -44,9 +44,10 @@ function generateJavascript(ast, options) { if (options.trace) { parts.push([ - 'peg$trace({', - ' type: "rule.enter",', - ' rule: ' + ruleNameCode, + 'peg$tracer.trace({', + ' type: "rule.enter",', + ' rule: ' + ruleNameCode + ',', + ' location: peg$computeLocation(startPos, startPos)', '});', '' ].join('\n')); @@ -65,15 +66,17 @@ function generateJavascript(ast, options) { if (options.trace) { parts.push([ 'if (cached.result !== peg$FAILED) {', - ' peg$trace({', + ' peg$tracer.trace({', ' type: "rule.match",', ' rule: ' + ruleNameCode + ',', - ' result: cached.result', + ' result: cached.result,', + ' location: peg$computeLocation(startPos, peg$currPos)', ' });', '} else {', - ' peg$trace({', + ' peg$tracer.trace({', ' type: "rule.fail",', - ' rule: ' + ruleNameCode, + ' rule: ' + ruleNameCode + ',', + ' location: peg$computeLocation(startPos, startPos)', ' });', '}', '' @@ -104,15 +107,17 @@ function generateJavascript(ast, options) { parts.push([ '', 'if (' + resultCode + ' !== peg$FAILED) {', - ' peg$trace({', + ' peg$tracer.trace({', ' type: "rule.match",', ' rule: ' + ruleNameCode + ',', - ' result: ' + resultCode, + ' result: ' + resultCode + ',', + ' location: peg$computeLocation(startPos, peg$currPos)', ' });', '} else {', - ' peg$trace({', + ' peg$tracer.trace({', ' type: "rule.fail",', - ' rule: ' + ruleNameCode, + ' rule: ' + ruleNameCode + ',', + ' location: peg$computeLocation(startPos, startPos)', ' });', '}' ].join('\n')); @@ -202,15 +207,31 @@ function generateJavascript(ast, options) { '}', '', 'function peg$parseRule(index) {', - ' var bc = peg$bytecode[index],', - ' ip = 0,', - ' ips = [],', - ' end = bc.length,', - ' ends = [],', - ' stack = [],', - ' params, i;', ].join('\n')); + if (options.trace) { + parts.push([ + ' var bc = peg$bytecode[index],', + ' ip = 0,', + ' ips = [],', + ' end = bc.length,', + ' ends = [],', + ' stack = [],', + ' startPos = peg$currPos,', + ' params, i;', + ].join('\n')); + } else { + parts.push([ + ' var bc = peg$bytecode[index],', + ' ip = 0,', + ' ips = [],', + ' end = bc.length,', + ' ends = [],', + ' stack = [],', + ' params, i;', + ].join('\n')); + } + parts.push(indent2(generateRuleHeader('peg$ruleNames[index]', 'index'))); parts.push([ @@ -705,10 +726,18 @@ function generateJavascript(ast, options) { code = compile(rule.bytecode); - parts.push([ - 'function peg$parse' + rule.name + '() {', - ' var ' + arrays.map(arrays.range(0, stack.maxSp + 1), s).join(', ') + ';', - ].join('\n')); + parts.push('function peg$parse' + rule.name + '() {'); + + if (options.trace) { + parts.push([ + ' var ' + arrays.map(arrays.range(0, stack.maxSp + 1), s).join(', ') + ',', + ' startPos = peg$currPos;' + ].join('\n')); + } else { + parts.push( + ' var ' + arrays.map(arrays.range(0, stack.maxSp + 1), s).join(', ') + ';' + ); + } parts.push(indent2(generateRuleHeader( '"' + js.stringEscape(rule.name) + '"', @@ -782,7 +811,8 @@ function generateJavascript(ast, options) { ' }', '', ' console.log(', - ' event.line + ":" + event.column + " "', + ' event.location.start.line + ":" + event.location.start.column + "-"', + ' + event.location.end.line + ":" + event.location.end.column + " "', ' + pad(event.type, 10) + " "', ' + repeat(" ", that.indentLevel) + event.rule', ' );', @@ -1102,21 +1132,6 @@ function generateJavascript(ast, options) { '' ].join('\n')); - if (options.trace) { - parts.push([ - ' function peg$trace(event) {', - ' var posDetails = peg$computePosDetails(peg$currPos);', - '', - ' event.offset = peg$currPos;', - ' event.line = posDetails.line;', - ' event.column = posDetails.column;', - '', - ' peg$tracer.trace(event);', - ' }', - '', - ].join('\n')); - } - if (options.optimize === "size") { parts.push(indent4(generateInterpreter())); parts.push(''); diff --git a/spec/api/generated-parser-api.spec.js b/spec/api/generated-parser-api.spec.js index bc3fd70..71c930f 100644 --- a/spec/api/generated-parser-api.spec.js +++ b/spec/api/generated-parser-api.spec.js @@ -54,12 +54,12 @@ describe("generated parser API", function() { parser.parse("b"); - expect(console.log).toHaveBeenCalledWith("1:1 rule.enter start"); - expect(console.log).toHaveBeenCalledWith("1:1 rule.enter a"); - expect(console.log).toHaveBeenCalledWith("1:1 rule.fail a"); - expect(console.log).toHaveBeenCalledWith("1:1 rule.enter b"); - expect(console.log).toHaveBeenCalledWith("1:2 rule.match b"); - expect(console.log).toHaveBeenCalledWith("1:2 rule.match start"); + expect(console.log).toHaveBeenCalledWith("1:1-1:1 rule.enter start"); + expect(console.log).toHaveBeenCalledWith("1:1-1:1 rule.enter a"); + expect(console.log).toHaveBeenCalledWith("1:1-1:1 rule.fail a"); + expect(console.log).toHaveBeenCalledWith("1:1-1:1 rule.enter b"); + expect(console.log).toHaveBeenCalledWith("1:1-1:2 rule.match b"); + expect(console.log).toHaveBeenCalledWith("1:1-1:2 rule.match start"); }); }); @@ -73,48 +73,54 @@ describe("generated parser API", function() { parser.parse("b", { tracer: tracer }); expect(tracer.trace).toHaveBeenCalledWith({ - type: 'rule.enter', - rule: 'start', - offset: 0, - line: 1, - column: 1 + type: 'rule.enter', + rule: 'start', + location: { + start: { offset: 0, line: 1, column: 1 }, + end: { offset: 0, line: 1, column: 1 } + } }); expect(tracer.trace).toHaveBeenCalledWith({ - type: 'rule.enter', - rule: 'a', - offset: 0, - line: 1, - column: 1 + type: 'rule.enter', + rule: 'a', + location: { + start: { offset: 0, line: 1, column: 1 }, + end: { offset: 0, line: 1, column: 1 } + } }); expect(tracer.trace).toHaveBeenCalledWith({ - type: 'rule.fail', - rule: 'a', - offset: 0, - line: 1, - column: 1 + type: 'rule.fail', + rule: 'a', + location: { + start: { offset: 0, line: 1, column: 1 }, + end: { offset: 0, line: 1, column: 1 } + } }); expect(tracer.trace).toHaveBeenCalledWith({ - type: 'rule.enter', - rule: 'b', - offset: 0, - line: 1, - column: 1 + type: 'rule.enter', + rule: 'b', + location: { + start: { offset: 0, line: 1, column: 1 }, + end: { offset: 0, line: 1, column: 1 } + } }); expect(tracer.trace).toHaveBeenCalledWith({ - type: 'rule.match', - rule: 'b', - result: 'b', - offset: 1, - line: 1, - column: 2 + type: 'rule.match', + rule: 'b', + result: 'b', + location: { + start: { offset: 0, line: 1, column: 1 }, + end: { offset: 1, line: 1, column: 2 } + } }); expect(tracer.trace).toHaveBeenCalledWith({ - type: 'rule.match', - rule: 'start', - result: 'b', - offset: 1, - line: 1, - column: 2 + type: 'rule.match', + rule: 'start', + result: 'b', + location: { + start: { offset: 0, line: 1, column: 1 }, + end: { offset: 1, line: 1, column: 2 } + } }); }); }); diff --git a/spec/api/pegjs-api.spec.js b/spec/api/pegjs-api.spec.js index 2bcc21d..6c8a2c7 100644 --- a/spec/api/pegjs-api.spec.js +++ b/spec/api/pegjs-api.spec.js @@ -157,8 +157,8 @@ describe("PEG.js API", function() { parser.parse("a"); - expect(console.log).toHaveBeenCalledWith("1:1 rule.enter start"); - expect(console.log).toHaveBeenCalledWith("1:2 rule.match start"); + expect(console.log).toHaveBeenCalledWith("1:1-1:1 rule.enter start"); + expect(console.log).toHaveBeenCalledWith("1:1-1:2 rule.match start"); }); }); });