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
This commit is contained in:
parent
0dab14d652
commit
1a713d0175
|
@ -547,7 +547,10 @@ function generateJS( ast, options ) {
|
||||||
"",
|
"",
|
||||||
" // istanbul ignore next",
|
" // istanbul ignore next",
|
||||||
" default:",
|
" 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 ) {
|
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;
|
return "s" + i;
|
||||||
|
|
||||||
} // |stack[i]| of the abstract machine
|
} // |stack[i]| of the abstract machine
|
||||||
|
@ -629,6 +635,7 @@ function generateJS( ast, options ) {
|
||||||
|
|
||||||
function compileCondition( cond, argCount ) {
|
function compileCondition( cond, argCount ) {
|
||||||
|
|
||||||
|
const pos = ip;
|
||||||
const baseLength = argCount + 3;
|
const baseLength = argCount + 3;
|
||||||
const thenLength = bc[ ip + baseLength - 2 ];
|
const thenLength = bc[ ip + baseLength - 2 ];
|
||||||
const elseLength = bc[ ip + baseLength - 1 ];
|
const elseLength = bc[ ip + baseLength - 1 ];
|
||||||
|
@ -651,7 +658,9 @@ function generateJS( ast, options ) {
|
||||||
if ( thenSp !== elseSp ) {
|
if ( thenSp !== elseSp ) {
|
||||||
|
|
||||||
throw new Error(
|
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 ) {
|
function compileLoop( cond ) {
|
||||||
|
|
||||||
|
const pos = ip;
|
||||||
const baseLength = 2;
|
const baseLength = 2;
|
||||||
const bodyLength = bc[ ip + baseLength - 1 ];
|
const bodyLength = bc[ ip + baseLength - 1 ];
|
||||||
const baseSp = stack.sp;
|
const baseSp = stack.sp;
|
||||||
|
@ -685,7 +695,11 @@ function generateJS( ast, options ) {
|
||||||
// istanbul ignore if
|
// istanbul ignore if
|
||||||
if ( bodySp !== baseSp ) {
|
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
|
// istanbul ignore next
|
||||||
default:
|
default:
|
||||||
throw new Error( "Invalid opcode: " + bc[ ip ] + "." );
|
throw new Error(
|
||||||
|
"Rule '" + rule.name + "', position " + ip + ": "
|
||||||
|
+ "Invalid opcode " + bc[ ip ] + "."
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,17 @@ class ASTVisitor {
|
||||||
// Will traverse the node, strictly assuming the visitor can handle the node type.
|
// Will traverse the node, strictly assuming the visitor can handle the node type.
|
||||||
visit( node ) {
|
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 );
|
const args = __slice.call( arguments, 0 );
|
||||||
|
|
||||||
return this[ node.type ].apply( this, args );
|
return func.apply( this, args );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue