@@ -345,12 +345,15 @@ function evalLC(term) {
345345 // term :: Tuple
346346 // isRight :: bool (indicating whether the term is left or right side of an Application)
347347 // isEvaluated :: bool (indicating whether the current term should be stored in the Env)
348+ // callstack :: [String] (History of var lookups, for better error messages)
348349 function runEval ( { term, env} , stack ) { // stack: [[term, isRight, isEvaluated]], term: LC term, env = Env { name => term }
350+ const callstack = [ ] ; // Does not persist between requests for arguments
349351 while ( ! ( term instanceof L ) || stack . length > 0 ) {
350352 if ( term instanceof V )
351353 if ( term . name === "()" )
352- { console . error ( ` eval: evaluating undefined inside definition of " ${ term . defName } "` ) ; throw new EvalError ; } // depend on verbosity here
354+ { printStackTrace ( " eval: evaluating undefined" , term , callstack ) ; throw new EvalError ; }
353355 else {
356+ callstack . push ( term . name ) ;
354357 const res = env . getValue ( term . name ) ;
355358 if ( ! res . env )
356359 term = res ;
@@ -407,6 +410,32 @@ function evalLC(term) {
407410 return runEval ( term , [ ] ) ;
408411}
409412
413+ // Print an error, with stack trace according to verbosity level
414+ function printStackTrace ( error , term , stack ) {
415+ if ( config . verbosity == "Calm" ) return ; // No error message for Calm
416+ else if ( config . verbosity == "Concise" )
417+ console . error ( `${ error } inside definition of <code>${ term . defName } </code>` ) ;
418+ else if ( config . verbosity == "Loquacious" ) {
419+ // Loquacious will provide a stack trace localised to the definition
420+ if ( stack . length == 0 || stack [ stack . length - 1 ] == term . defName )
421+ console . error ( `${ error } inside definition of <code>${ term . defName } </code>` ) ;
422+ else {
423+ const localStack = stack . slice ( stack . indexOf ( term . defName ) + 1 ) . reverse ( ) ;
424+ console . error ( `${ error } inside definition of <code>${ term . defName } </code>
425+ ${ localStack . map ( v => '\twhile evaluating <code>' + v + '</code>' ) . join ( '\n' ) } `)
426+ }
427+ } else if ( config . verbosity == "Verbose" ) {
428+ // Verbose will provide a full stack trace
429+ if ( stack . length == 0 )
430+ console . error ( `${ error } inside definition of <code>${ term . defName } </code>` ) ;
431+ else {
432+ const localStack = stack . reverse ( ) ;
433+ console . error ( `${ error } inside definition of <code>${ term . defName } </code>
434+ ${ localStack . map ( v => '\twhile evaluating <code>' + v + '</code>' ) . join ( '\n' ) } `)
435+ }
436+ }
437+ }
438+
410439Object . defineProperty ( Function . prototype , "valueOf" , { value : function valueOf ( ) { return toInt ( this ) ; } } ) ;
411440
412441exports . config = config ;
0 commit comments