(define (attach-docstring docstring proc)
(lambda args
(##first-argument docstring)
(apply proc args)))
(define docstring-closure (attach-docstring "" list))
(define (get-docstring proc)
(and (##closure? proc)
(eq? (##closure-code proc)
(##closure-code docstring-closure))
(##closure-ref proc 1)))
(define hello
(attach-docstring
"hello is a neat function"
(lambda (who)
(println "hello " who "!"))))
(pp (get-docstring car)) ;; prints #f
(pp (get-docstring hello)) ;; prints "hello is a neat function"
(hello "world")
some stuff I would be happy to work on:
Does anything there sound like its worth prioritizing? Does any of it not align with the goals of gambit?
@belmarca Here is are some quick instructions if you want to give the universal backend a try. The PHP and Java backends seem to have suffered from bit-rot, but the JavaScript, Python and Ruby backends seem to be still working on v4.9.0 . Here's how to compile a simple hello world. From the root of the Gambit source directory, after a successful "make":
% cd lib
% make _gambit.js
% make _gambit.py
% make _gambit.rb
% cd ..
This builds the Gambit runtime library for JavaScript, Python and Ruby. Then to compile a program for a specific backend you add the -target <BACKEND>
option when invoking gsc, where <BACKEND>
is js
, python
or ruby
. Here's an example for JavaScript:
% cat test.scm
(println "hello!")
% gsc/gsc -:=. -target js -exe test.scm
% ./test
hello!
Note that the file test
is a shell script that starts nodejs to run the script. The script for this program is 15Mbytes and almost 500K lines of JavaScript code! It's this big because all of the Gambit runtime library is included in the file test
. For example bignums and pretty-printing are available:
% cat test.scm
;; print sqrt of 2 to 50 decimal places
(pp (integer-sqrt (* 2 (expt 10 100))))
% gsc/gsc -:=. -target js -exe test.scm
% ./test
141421356237309504880168872420969807856967187537694
One way to get a smaller footprint it to write you own runtime library. Here's a minimal runtime library for JavaScript that only defines the console.log
procedure:
% cat test.scm
(console.log "hello!")
% cat rts.scm
(declare (extended-bindings) (not safe))
(define (console.log str)
(##inline-host-statement
"console.log(g_scm2host(@1@));"
str))
;; run each linked module (except for this file)
(let ((module-descrs (##vector-ref ##program-descr 0)))
(let loop ((i 1))
(if (##fx< i (##vector-length module-descrs))
(begin
((##vector-ref (##vector-ref module-descrs i) 1))
(loop (##fx+ i 1))))))
% gsc/gsc -:=. -target js -c rts.scm
% gsc/gsc -:=. -target js -link -l rts.js test.scm
% cat test_.js test.js rts.js > app.js
% node app.js
hello!
% wc app.js
768 2238 18107 app.js
It is much smaller at 768 lines of code. Although you get a minimal runtime library, this may be a good approach to use Scheme code in a Web page with a minimal footprint.
The Gambit runtime library (in the lib directory) must also be compiled for your target platform. The C code generated by the Gambit compiler for your app must then be linked with the Gambit runtime library. A good way to understand the required low-level steps is to pass the -verbose
option to gsc. It will show the invocations of the C compiler. For example, if "app.scm" contains your program:
% gsc -exe -verbose app.scm
Parsing:
"expr"
Compiling:
Dumping:
#<primitive app#>
Compilation finished.
gcc -O1 -Wno-unused -Wno-write-strings -Wdisabled-optimization -fwrapv -fno-strict-aliasing -fno-math-errno -fomit-frame-pointer -fPIC -fno-common -D___SINGLE_HOST -I"/Library/Gambit/v4.9.0/include" -c -o "app.o" app.c
gcc -O1 -Wno-unused -Wno-write-strings -Wdisabled-optimization -fwrapv -fno-strict-aliasing -fno-math-errno -fomit-frame-pointer -fPIC -fno-common -D___SINGLE_HOST -I"/Library/Gambit/v4.9.0/include" -c -o "app_.o" app_.c
gcc -Wno-unused -Wno-write-strings -Wdisabled-optimization -fwrapv -fno-strict-aliasing -fno-math-errno -fomit-frame-pointer -fPIC -fno-common -D___SINGLE_HOST -I"/Library/Gambit/v4.9.0/include" -o "app" app_.o app.o "/Library/Gambit/v4.9.0/lib/libgambit.a"
As you can see the last step links the executable with libgambit.a, the Gambit runtime library. It is the Gambit runtime library that contains the GC and the interface to the operating system (for file I/O, networking, time, etc).
--enable-ansi-c
configure option that forces the Gambit runtime system to only use (and be linked to) functions provided by ANSI-C (https://www.cs.auckland.ac.nz/references/unix/digital/AQTLTBTE/DOCU_085.HTM). This is pretty "bare-bones" as it will disable many features (such as networking, subprocesses, etc) but it is a good approach to get started quickly. After that works, you can enable more advanced features to see which features work on the target platform (see include/config.h).
Hi! Is there a way to generate scheme objects out of C constant values? That's what I'm currently doing:
(define-macro (c-const-return name c-type c-value)
(let ((acstring (eval `(string-append "___return(" ,c-value ");" ))))
`(begin
(##define ,name #f)
(##set! ,name ((c-lambda () ,c-type ,acstring))))))
(c-const-return urE_KEYDOWN ur-stringhash "E_KEYDOWN") ;; const
(c-const-return urP_KEY int "KeyDown::P_KEY") ;; const too
This is somewhat cumbersome, the resulting routines -- a couple thousand in my humble case -- will never be optimized away by compiler.
It works well, but not fast and prone to code bloat. C #defines, enums and C++ const T values are well known at compile time .. is there a way to inject the relevant macros inside Gambit's C product ? e.g. something like (c-initialize " ___NEW_SCMOBJ(foobaz, int, KeyDown::P_KEY);")
or even better a (define foobaz (c-import int "KeyDown::P_KeY"))
?
Sorry if I am asking something obvious and thanks for all the fish!
gcc -Iinclude -o a.out lib/main.o lib/setup.o lib/mem.o lib/os_setup.o lib/os_base.o lib/os_thread.o lib/os_time.o lib/os_shell.o lib/os_files.o lib/os_dyn.o lib/os_tty.o lib/os_io.o lib/c_intf.o lib/actlog.o lib/_kernel.o lib/_system.o lib/_num.o lib/_std.o lib/_eval.o lib/_io.o lib/_nonstd.o lib/_thread.o lib/_repl.o lib/_gambit.o hw.c hw_.c
C_COMPILE_TO_EXE="$C_COMPILER -Iinclude -o $EXE_NAME"
gambiteer on master
Speed up implementation of SRFI… (compare)
feeley on master
Universal backend: add URL whit… (compare)