On 2011-05-25, at 8:58 AM, Oleg Parashchenko wrote:
Hello,
I can't understand why compiiler fails if "make-obj" function is re-defined (for example, using "(include-adt "_gvmadt.scm")"). A minimal example to reproduce:
$ export GAMBIT_SOURCE=....my local copy.... $ $GAMBIT_SOURCE/gsc/gsc -:~~lib=/home/olpa/p/scheme/gambit/lib Gambit v4.6.0
(define std-scm (string-append (getenv "GAMBIT_SOURCE") "/lib
/_std.scm"))
(compile-file-to-c std-scm)
"/home/olpa/p/scheme/gambit/lib/_std.c"
(pp c#make-obj)
(##lambda (val) (+ (* (enter-opnd val #f) 8) 5))
(define c#make-obj (##lambda (val) (+ (* (c#enter-opnd val #f)
- 5)))
(pp c#make-obj)
(lambda (val) (+ (* (c#enter-opnd val #f) 8) 5))
(compile-file-to-c std-scm)
*** ERROR IN c#schedule-gen-proc, "p/scheme/gambit/gsc/_front.sc m"@1215.19 -- Wrong number of arguments passed to procedure (c#make-obj) 1>
An obvious solution is not to re-define the function, but I'm curious: what happens? Why using an identical function leads to the error?
The problem is related to the "absent" object, which is used in the handling of optional parameters. Note that there is no direct way to generate the absent object. The following macro, defined in lib/_gambit#.scm, must be used:
(##define-macro (macro-absent-obj) `',(##type-cast -6 2))
In a function defined like
(lambda (a b #!optional (x (macro-absent-obj)) (y (macro-absent-obj))) ...)
the formal parameters x and y will be bound to the absent object when there is no corresponding actual parameter. The body of the function can then test (eq? x (macro-absent-obj)) to check if an actual parameter for x was passed or not.
The Gambit interpreter is implemented in Scheme, and the *interpretation* of a lambda expression will evaluate a compiled lambda expression. For the interpreted lambda expression (lambda (a) ...) the compiled lambda expression (lambda (#!optional (arg1 (macro-absent-obj)) . arg2-and-up) ...) is evaluated, in other words arg1 is optional and the remaining arguments if any are received in the list arg2-and-up. The body of the compiled lambda expression will check that the correct number of arguments was passed to the function with a test like:
(if (or (eq? arg1 (macro-absent-obj)) (not (null? arg2-and-up))) (error "wrong number of arguments") ...)
This all works well as long as the user never generates or observes the absent object.
The problem when you compile _std.scm is that the absent object is used as the default value for optional parameters of functions defined in that file. So if you redefine make-obj as an interpreted function like:
(define make-obj (lambda (a) ...))
and it is called during the compilation of _std.scm as (make-obj (make-absent-obj)), the interpreter will be confused and think no parameter was passed to make-obj.
Here's a REPL interaction to make this clearer:
% gsi Gambit v4.6.1
(##define-macro (macro-absent-obj) `',(##type-cast -6 2)) (define absent (macro-absent-obj)) (pp absent)
#<absent>
(list absent absent)
(#<absent> #<absent>)
(define (f a) (list a)) (f absent)
*** ERROR IN (console)@6.1 -- Wrong number of arguments passed to procedure (f)
That's why you find this redefinition of the absent object:
(define c#absent-object (string->symbol "#<absent>")) ; (##type-cast -6 2)
in the file gsc/igsc.scm , which is a script to be used when executing the compiler in the interpreter. I think that script is currently broken for other reasons, but that was the intent.
One sneaky way around the problem is to define make-obj like this
(define make-obj (lambda (val . dummy) ...)
This works because interpreted lambda expressions with a rest parameter are not implemented with the absent object. So if val is the absent object the interpreter will not think that no actual parameter was passed. For example:
% gsi Gambit v4.6.1
(##define-macro (macro-absent-obj) `',(##type-cast -6 2)) (define absent (macro-absent-obj)) (define make-obj (lambda (val . dummy) (list val dummy))) (make-obj absent)
(#<absent> ())
(define make-obj (lambda (val) (list val))) (make-obj absent)
*** ERROR IN (console)@6.1 -- Wrong number of arguments passed to procedure (make-obj) 1>
Marc