For C macros, I tend to use __FILE__ and __LINE__ alot. Does gambit have an equiv for this?
Thanks!
Afficher les réponses par date
On 1-May-09, at 5:38 PM, lowly coder wrote:
For C macros, I tend to use __FILE__ and __LINE__ alot. Does gambit have an equiv for this?
There's a builtin macro to get the current source file, which is called "this-source-file". Nothing is builtin to get the line, but you can get that in the following way:
(##define-syntax FILE (lambda (src) (if (not (##source? src)) (error "expected a source object") (let ((locat (##source-locat src))) (if (not locat) (error "location unknown") (let ((container (##locat-container locat)) (position (##locat-position locat))) (let ((path (##container->path container))) path)))))))
(##define-syntax LINE (lambda (src) (if (not (##source? src)) (error "expected a source object") (let ((locat (##source-locat src))) (if (not locat) (error "location unknown") (let ((position (##locat-position locat))) (let ((filepos (##position->filepos position))) (let ((line (##fixnum.+ (##filepos-line filepos) 1))) line))))))))
(pp (list (FILE) (LINE))) (pp (list (this-source-file) (LINE)))
;; prints: ;; ;; ("/u/feeley/test.scm" 25) ;; ("/u/feeley/test.scm" 26)
Marc
Let's see how much of this I can understand.
1) FILE & LINE are macros. 2) in (lambda (src <-- this variable here the src is linked to the reader/parser object, which is why we can query it for the current line / file number? 3) Why the ##'s
Thanks!
On Sat, May 2, 2009 at 8:23 PM, Marc Feeley feeley@iro.umontreal.ca wrote:
On 1-May-09, at 5:38 PM, lowly coder wrote:
For C macros, I tend to use __FILE__ and __LINE__ alot. Does gambit have
an equiv for this?
There's a builtin macro to get the current source file, which is called "this-source-file". Nothing is builtin to get the line, but you can get that in the following way:
(##define-syntax FILE (lambda (src) (if (not (##source? src)) (error "expected a source object") (let ((locat (##source-locat src))) (if (not locat) (error "location unknown") (let ((container (##locat-container locat)) (position (##locat-position locat))) (let ((path (##container->path container))) path)))))))
(##define-syntax LINE (lambda (src) (if (not (##source? src)) (error "expected a source object") (let ((locat (##source-locat src))) (if (not locat) (error "location unknown") (let ((position (##locat-position locat))) (let ((filepos (##position->filepos position))) (let ((line (##fixnum.+ (##filepos-line filepos) 1))) line))))))))
(pp (list (FILE) (LINE))) (pp (list (this-source-file) (LINE)))
;; prints: ;; ;; ("/u/feeley/test.scm" 25) ;; ("/u/feeley/test.scm" 26)
Marc
On 7-May-09, at 3:06 AM, lowly coder wrote:
Let's see how much of this I can understand.
- FILE & LINE are macros.
Yes.
- in (lambda (src <-- this variable here the src is linked to the reader/parser object, which is why we
can query it for the current line / file number?
Yes. The parameter is the "source object" corresponding to the macro call. What is a source object? Here's a simple way to find out how source objects are represented:
bash-3.2$ gsi Gambit v4.4.3
(define x #f) (##define-syntax foo (lambda (src) (set! x src) '(begin))) (foo (stuff) turkey) x
#(#(source1) (#(#(source1) foo (console) 65538) #(#(source1) (#(#(source1) stuff (console) 393218)) (console) 327682) #(#(source1) turkey (console) 851970)) (console) 2)
(##source? x)
#t
(##source-locat x)
#((console) 2)
(##source-code x)
(#(#(source1) foo (console) 65538) #(#(source1) (#(#(source1) stuff (console) 393218)) (console) 327682) #(#(source1) turkey (console) 851970))
(length (##source-code x))
3
(##source-code (car (##source-code x)))
foo
(##source-code (car (##source-code (cadr (##source-code x)))))
stuff
(##desourcify x)
(foo (stuff) turkey)
(##locat-container (##source-locat x))
(console)
(##locat-position (##source-locat x))
2
(##display-locat (##source-locat x) #t (current-output-port))
(console)@3.1
- Why the ##'s
All the ## names refer to internal functionality that should be used with great care, and is not meant for use by a casual user. The procedures typically don't do any type checking and the API may change at any point. The ## stresses these point in several ways:
1) It is easy to spot in code, so a simple "grep '##' *.scm" will find places in your code that are possibly unsafe or brittle (over versions of Gambit).
2) The ## prefix is "ugly" and may be a deterrent to using these names.
3) The "##" prefix on symbols is illegal in Scheme, so it is clear that by using these names you are definitely non-portable to other Schemes (it turns out that Chicken Scheme supports this extension, so ## is not completely non-portable anymore).
Marc
Your response to 2 was really enlightening.
More on 3:
~:$ cat test.scm (define source? 10) (define ##source? 10) (pp source?) (pp ##source?) ~:$ gsi test.scm 10 10
This surprised me a bit ... initially, intuitively, I had a notion that ##blah was a blah that had it's value hard coded internally in gambit (so that even if the user did weird things to his/her environment, I can still get the 'system functions').
In gambit, are ##-vars treated just like regular ##-vars ?
I see the ##'s pop up alot in the gambit internal *.scm 's, and sometimes, changing a "##blah" to a "blah" results in the code behaving differently (iirc when I was trying to get the debugger to output a 'stack trace').
On Thu, May 7, 2009 at 6:48 AM, Marc Feeley feeley@iro.umontreal.ca wrote:
On 7-May-09, at 3:06 AM, lowly coder wrote:
Let's see how much of this I can understand.
- FILE & LINE are macros.
Yes.
- in (lambda (src <-- this variable here
the src is linked to the reader/parser object, which is why we can query it for the current line / file number?
Yes. The parameter is the "source object" corresponding to the macro call. What is a source object? Here's a simple way to find out how source objects are represented:
bash-3.2$ gsi Gambit v4.4.3
(define x #f) (##define-syntax foo (lambda (src) (set! x src) '(begin))) (foo (stuff) turkey) x
#(#(source1) (#(#(source1) foo (console) 65538) #(#(source1) (#(#(source1) stuff (console) 393218)) (console) 327682) #(#(source1) turkey (console) 851970)) (console) 2)
(##source? x)
#t
(##source-locat x)
#((console) 2)
(##source-code x)
(#(#(source1) foo (console) 65538) #(#(source1) (#(#(source1) stuff (console) 393218)) (console) 327682) #(#(source1) turkey (console) 851970))
(length (##source-code x))
3
(##source-code (car (##source-code x)))
foo
(##source-code (car (##source-code (cadr (##source-code x)))))
stuff
(##desourcify x)
(foo (stuff) turkey)
(##locat-container (##source-locat x))
(console)
(##locat-position (##source-locat x))
2
(##display-locat (##source-locat x) #t (current-output-port))
(console)@3.1
- Why the ##'s
All the ## names refer to internal functionality that should be used with great care, and is not meant for use by a casual user. The procedures typically don't do any type checking and the API may change at any point. The ## stresses these point in several ways:
- It is easy to spot in code, so a simple "grep '##' *.scm" will find
places in your code that are possibly unsafe or brittle (over versions of Gambit).
The ## prefix is "ugly" and may be a deterrent to using these names.
The "##" prefix on symbols is illegal in Scheme, so it is clear that by
using these names you are definitely non-portable to other Schemes (it turns out that Chicken Scheme supports this extension, so ## is not completely non-portable anymore).
Marc
On 7-May-09, at 2:40 PM, lowly coder wrote:
Your response to 2 was really enlightening.
More on 3:
~:$ cat test.scm (define source? 10) (define ##source? 10) (pp source?) (pp ##source?) ~:$ gsi test.scm 10 10
This surprised me a bit ... initially, intuitively, I had a notion that ##blah was a blah that had it's value hard coded internally in gambit (so that even if the user did weird things to his/her environment, I can still get the 'system functions').
In gambit, are ##-vars treated just like regular ##-vars ?
Yes, ##car and car are two global variables.
But that is not the whole story because the compiler can be told, using a declaration, that it can assume that global variables are bound to their predefined value. So in the code
(let () (declare (standard-bindings)) (car (f x)))
the programmer is telling the compiler that it can assume that car is bound to the predefined car procedure. This allows the compiler to inline the car procedure. The code (once transformed by the compiler) becomes:
(let ((temp.0 (f x))) (if ('#<procedure #2 ##pair?> temp.0) ('#<procedure #3 ##car> temp.0) (car temp.0)))
So the logic of the car procedure, including the type test, is inlined at the location of the original call to car. Note that if the type test fails, the car procedure in the runtime library is called, and it will raise the appropriate exception (moreover the continuation of that exception will be the same continuation that was passed to the original call to car).
If the programmer wants the compiler to assume that the type check will succeed (i.e. the result of (f x) is always a pair) then the (not safe) declaration can be added:
(let () (declare (standard-bindings) (not safe)) (car (f x)))
After the compiler's transformations the code becomes:
('#<procedure #2 ##car> (f x))
Here only a call to the ##car primitive remains. This primitive will be inlined by the back-end of the compiler, which will generate a call to the ___CAR(obj) C macro defined in include/gambit.h . The ___CAR macro is defined like this:
#define ___CAR(obj)___PAIR_CAR(obj) #define ___PAIR_CAR(obj)(*(___BODY_AS(obj,___tPAIR)+___PAIR_CAR_OFS)) #define ___BODY_AS(obj,tag)(___UNTAG_AS(obj,tag)+___BODY_OFS) #define ___UNTAG_AS(obj,tag)___CAST(___WORD*,(obj)-(tag)) #define ___CAST(type,val)((type)(val)) #define ___tPAIR 3 #define ___PAIR_CAR_OFS 1 #define ___BODY_OFS 1 #define ___WORD int /* usually */
so in the end, the call to car has become the C code:
*((int*)(obj-3)+2)
which on many processor architectures, is a single machine instruction (because the C compiler combines the substraction and addition of the constants into a single offset).
Marc