From 1a713d0175d0705c48d036048c6109655904dc2d Mon Sep 17 00:00:00 2001 From: Mingun Date: Wed, 24 Jan 2018 23:12:13 +0500 Subject: [PATCH] Add some useful debug information to some exceptions (#475) * Add some useful debug information to some exceptions * Add guard for visitor functions preventing from cryptic errors due to incomplete visitors * Add guard for js generator for preventing from cryptic errors due to incarrect stack manipulations --- lib/compiler/passes/generate-js.js | 25 +++++++++++++++++++++---- lib/compiler/visitor.js | 10 +++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/compiler/passes/generate-js.js b/lib/compiler/passes/generate-js.js index 6a2747e..2c682d6 100644 --- a/lib/compiler/passes/generate-js.js +++ b/lib/compiler/passes/generate-js.js @@ -547,7 +547,10 @@ function generateJS( ast, options ) { "", " // istanbul ignore next", " default:", - " throw new Error(\"Invalid opcode: \" + bc[ip] + \".\");", + " throw new Error(", + " \"Rule #\" + index + \"" + ( options.trace ? " ('\" + peg$ruleNames[ index ] + \"')" : "" ) + ", position \" + ip + \": \"", + " + \"Invalid opcode \" + bc[ip] + \".\"", + " );", " }", " }", "", @@ -574,6 +577,9 @@ function generateJS( ast, options ) { function s( i ) { + // istanbul ignore next + if ( i < 0 ) throw new Error( "Rule '" + rule.name + "': Var stack underflow: attempt to use var at index " + i ); + return "s" + i; } // |stack[i]| of the abstract machine @@ -629,6 +635,7 @@ function generateJS( ast, options ) { function compileCondition( cond, argCount ) { + const pos = ip; const baseLength = argCount + 3; const thenLength = bc[ ip + baseLength - 2 ]; const elseLength = bc[ ip + baseLength - 1 ]; @@ -651,7 +658,9 @@ function generateJS( ast, options ) { if ( thenSp !== elseSp ) { throw new Error( - "Branches of a condition must move the stack pointer in the same way." + "Rule '" + rule.name + "', position " + pos + ": " + + "Branches of a condition can't move the stack pointer differently " + + "(before: " + baseSp + ", after then: " + thenSp + ", after else: " + elseSp + ")." ); } @@ -672,6 +681,7 @@ function generateJS( ast, options ) { function compileLoop( cond ) { + const pos = ip; const baseLength = 2; const bodyLength = bc[ ip + baseLength - 1 ]; const baseSp = stack.sp; @@ -685,7 +695,11 @@ function generateJS( ast, options ) { // istanbul ignore if if ( bodySp !== baseSp ) { - throw new Error( "Body of a loop can't move the stack pointer." ); + throw new Error( + "Rule '" + rule.name + "', position " + pos + ": " + + "Body of a loop can't move the stack pointer " + + "(before: " + baseSp + ", after: " + bodySp + ")." + ); } @@ -907,7 +921,10 @@ function generateJS( ast, options ) { // istanbul ignore next default: - throw new Error( "Invalid opcode: " + bc[ ip ] + "." ); + throw new Error( + "Rule '" + rule.name + "', position " + ip + ": " + + "Invalid opcode " + bc[ ip ] + "." + ); } diff --git a/lib/compiler/visitor.js b/lib/compiler/visitor.js index f92d452..18e8718 100644 --- a/lib/compiler/visitor.js +++ b/lib/compiler/visitor.js @@ -9,9 +9,17 @@ class ASTVisitor { // Will traverse the node, strictly assuming the visitor can handle the node type. visit( node ) { + // istanbul ignore next + if ( ! node ) throw new Error( "Visitor function called with no or `null` node" ); + + const func = this[ node.type ]; + + // istanbul ignore next + if ( ! func ) throw new Error( "Visitor function for node type '" + node.type + " not defined" ); + const args = __slice.call( arguments, 0 ); - return this[ node.type ].apply( this, args ); + return func.apply( this, args ); }