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