Copyright © 1998, 2001 by Ian Horswill, see comment within this file.

Debugging GRL code

Debugging GRL code

Here are a few helpful hints for debugging your GRL code.

Errors generated by Scheme

There are mostly errors that occur at run-time, but they can also occur during compilation if either the compiler is broken, or it tries to constant fold a bad expression.  For example, if you say (define-signal foo (/ 7 0)), the compiler will realize that foo is a constant and try to compute its value at compile time by doing the division.  This will, of course, break.

Error: Exception
This generally means you called something with arguments of the wrong type.  If two lines appear after the error message, then the next line tells you what argument it didn't like and the line after that tells you the expression it was trying to evaluate.  If there's only one line, then it was the expression it was trying to evaluate.
Error: Undefined variable
Just what it sounds like: you referenced a variable you hadn't defined.  The next line tells you what the variable is and the line after that tells you what package it was supposed to be in.  Note that in some cases, this can be caused by arranging the definitions in a source file in the wrong order.  In general, you need to place definitions of signals before their uses.
Error: Rational division by zero
Your program divided by zero.  The next line tells you what number it tried to divide by zero.
Error: Stack overflow
This is a very rare error to get in GRL code, since it isn't recursive, but it means your program somehow went into an infinite recursion.
Interrupt: Keyboard
You typed control-C.  Type ,reset or ,pop to get out of the debugger unless you want to probe the stack.
Interrupt: Post-gc
Scheme ran out of memory.  This usually means something bad is happening.  Either you wrote an infinite recursion, wrote an infinite loop that kept allocating a bigger and bigger list, or possibly scheme itself got confused trying to call an error handler that generated an error itself.  There usually isn't a lot you can do if you get this.  Type ",reset" to get out of the error and hope that scheme is at least able to clean up the mess.
Warning: Invalid arguments
This is a type error caught by the scheme compiler. The next line is the expression being compiled and the other lines are the types the procedure expects and the types it's being passed, respectively.

Common compilation errors

Most compilation errors are straight-forward.  Here's a list of all but the most obscure or most obvious ones:

Errors you get while typing in or loading your code

Bad signal declaration
This means that your signal expression had some extra garbage at the end, for example, if you say something like:
     (define-signal foo (+ a b) bla bla bla)
it will complain that bla wasn't a valid declaration to add to a signal expression.
Function argument x to map-signals must be a procedure, signal-procedure, or transducer
This means you said something like (define-signal foo (x y)) where x wasn't something it knew how to treat as a procedure.  With very few exceptions, the operator in a signal expression (x, in this case) has to be a scheme procedure, a signal procedure, or a transducer.
One of this primitive procedure's arguments is invalid
You said something like (+ sin 7), which is a type error because sin is a procedure, not a number, and the system was able to catch it at load time rather than at compile time.
Unknown signal property x in declaration of signal
This means that your signal expression had some extra garbage at the end, for example, if you say something like:
     (define-signal foo (+ a b)
     (bla bleep))
it will complain that bla wasn't a valid signal property.
 

Type inference errors

Consequent and alternate branches of if have different types
You said something like (if (< a b) 1 #f), where the "then" and "else" parts have different types.  You can do that in scheme but not in GRL.
Group type must have x field, but doesn't
That means your code tried to access the x component of a signal group but the group didn't have a component by that name.  Look at the compiler's subgoal stack to figure out what it had been expanding at the time.  That will tell you what procedure is broken.
Invalid argument type(s)
This means you applied a procedure or transducer to arguments of the wrong types.  The error message shows you what the types of the arguments were, in order, along with what types it was expecting.
Need to know the type of x, but can't determine it
This is actually generated by the partial evaluator when it's trying to optimize the intermediate code.  It generally means that the intermediate code variable x is defined in terms of some foreign procedure (generally from a source signal or from a transducer body) that the compiler hasn't heard of.  The solution is to look at the compiler's subgoal stack, find the procedure, and use define-external to tell the partial evaluator what it returns.
Not a numeric type
Not a Boolean type
Not an integer
Not a logical type
Not a list type
Not a vector type
Not an array type
This means you did something like (+ #f 7) where you apply a procedure to a nonsensical type.  It's essentially the same kind of error as invalid argument types(s), except that hte compiler knew a little more about what was going on.
Unable to infer type for a cyclic graph
This means you've defined a signal in terms of itself and so the compiler can't figure out what it's type is.  For example, if you define a to be b+1 and define b to be a+c-7, the compiler won't reject the code; it assumes that you mean that when updating, the new value of a should be set to the current value of b+1, and the new value of b should be set to the current value of a+c-7, but it isn't smart enough to determine whether a and b are floats or integers.  Since it's rare for someone to mean to define a signal in terms of itself, the solution to this problem is usually to find out why the signal mentioned in the error message is cyclic and fix it so that it isn't cyclic.  However, sometimes you really mean to make it cyclic.  In that case, you can fix it by adding either a type declaration, or preferably, an initial-value declaration, which both lets the compiler know the signal's type and also tells the compiler what to assume for the initial value of the signal.
Unknown type
You shouldn't get this unless you're doing something fancy.  It means that you used a constant someplace in your code that it couldn't determine the type of (e.g. some funky record structure).

Expansion errors

Argument to group selector must be a signal or list of signals
Not a signal group
Your code tried to take a component (group element) of a signal that wasn't a group to begin with.
Attempting to extract group component named x from a non-signal!
Tried to select the
x component of a signal, but it's not a group!
Your code tried to get a component of a group (either with select, or an accessor like x-of, rotate-of, etc.) but it wasn't a group
Calling signal as function with no function binding
This means your code tried to call a signal on another signal, as if the first signal were a function.  Don't do that, silly.  The "with no function binding" clause is there because you can in fact overload signals to behave as functions (using the as-function declaration).  This error message is only printed when you don't do the overloading but try to call the function as a signal anyway.
No handler for signal type
This means a signal procedure had a typecase expression in it and the signal it was looking at had a type that didn't match any of the clauses in the typecase expression.  Usually, it means that you're passing something of the wrong type into a signal procedure.  The offending signal is given as part of the error report.
Not a literal value
This means that either the argument of some procedure or signal procedure needed to be an actual number rather than an expression, but wasn't.
Signal has no property named x
This means that either your code or some code you called expected one of its arguments to have some property defined in its property list and it didn't.  This usually means you've passed the wrong kind of thing in as an argument.  For example, you can get this if you try to call something from within a plan that isn't really a plan or action.
This signal group has no x component
Your code tried to extract a component from a group that doesn't have a component by that name.  For example, if you call x-of on an rt-vector.

Other random errors

Beta reduction (i.e. lambda inlining) with arguments not implemented
This means you has a source signal or transducer body that said something like ((foo bar) baz).  You can do that in scheme, but GRL only allows it in very restricted cases.  However, most users never even try to write that anyway, so getting this error usually means that you had an extra set of parentheses around an expression in a transducer body, or else that you had a typo in the name of a macro, e.g. typing "ket" instead of "let", so that the compiler misinterprets the list of variables and values as a procedure call.
Can't reify signal group
This is hard to get, but it usually means you passed a group as an argument to a transducer or plan.  The compiler can't handle that.
Found signal in object code with no location assigned!
This is usually a bug in a plan, plan macro, or transducer.  It means that a plan or transducer expanded into some code that referenced a signal that (a) wasn't one of its arguments (don't ask how to do this ...) and (b) wasn't used elsewhere in the compilation.  If you get tell Ian and he'll help you track it down.
GRL doesn't know how to compile x
Unknown procedure object
This means you compiled a signal expression like (proc a b c) where proc was a real scheme procedure but it didn't happen to be a scheme procedure that the GRL compiler knew how to compile references to.  Use define-primitive to explain the procedure to GRL.
x isn't a real procedure
There are a bunch of primitives that GRL knows how to compile that aren't real scheme procedures that it makes sense to call.  These are mostly the array primitives.  Scheme doesn't support multidimensional arrays, so you can't actually call these primitives from scheme.
Invalid variable reference
This is an error message generated by Scheme, not by the GRL compiler.  It means that you used the name of a macro or other special form as the argument to a procedure rather than calling it properly.  For example, if you say (+ lambda 1).  This generally means one of two things:

Understanding more obscure compilation errors

When the compiler finds a problem with your code, it prints an error message and drops you in the debugger.  In addition to printing the error itself, the compiler will try to print a trace of what it was trying to do at the time, which is helpful for figuring out where the error is.  The phases of the compilation process are:

Debugging control systems is always hard because you can't exactly single-step them in the debugger - they have to keep running all the time.