Merge branch 'foreign-dev'

This commit is contained in:
Justin Ethier 2020-05-16 19:49:00 -04:00
commit 8a115df516
7 changed files with 494 additions and 59 deletions

View file

@ -78,6 +78,7 @@ install : libs install-libs install-includes install-bin
$(INSTALL) -m0644 scheme/cyclone/*.scm $(DESTDIR)$(DATADIR)/scheme/cyclone $(INSTALL) -m0644 scheme/cyclone/*.scm $(DESTDIR)$(DATADIR)/scheme/cyclone
$(INSTALL) -m0644 libs/cyclone/test.meta $(DESTDIR)$(DATADIR)/cyclone $(INSTALL) -m0644 libs/cyclone/test.meta $(DESTDIR)$(DATADIR)/cyclone
$(INSTALL) -m0644 libs/cyclone/match.meta $(DESTDIR)$(DATADIR)/cyclone $(INSTALL) -m0644 libs/cyclone/match.meta $(DESTDIR)$(DATADIR)/cyclone
$(INSTALL) -m0644 libs/cyclone/foreign.meta $(DESTDIR)$(DATADIR)/cyclone
$(INSTALL) -m0644 scheme/cyclone/*.o $(DESTDIR)$(DATADIR)/scheme/cyclone $(INSTALL) -m0644 scheme/cyclone/*.o $(DESTDIR)$(DATADIR)/scheme/cyclone
$(INSTALL) -m0755 scheme/cyclone/*.so $(DESTDIR)$(DATADIR)/scheme/cyclone $(INSTALL) -m0755 scheme/cyclone/*.so $(DESTDIR)$(DATADIR)/scheme/cyclone
$(INSTALL) -m0644 libs/cyclone/*.sld $(DESTDIR)$(DATADIR)/cyclone $(INSTALL) -m0644 libs/cyclone/*.sld $(DESTDIR)$(DATADIR)/cyclone
@ -271,6 +272,7 @@ bootstrap : icyc libs
cp scheme/cyclone/macros.c $(BOOTSTRAP_DIR)/scheme/cyclone cp scheme/cyclone/macros.c $(BOOTSTRAP_DIR)/scheme/cyclone
cp libs/cyclone/match.c $(BOOTSTRAP_DIR)/cyclone cp libs/cyclone/match.c $(BOOTSTRAP_DIR)/cyclone
cp libs/cyclone/match.meta $(BOOTSTRAP_DIR)/cyclone cp libs/cyclone/match.meta $(BOOTSTRAP_DIR)/cyclone
cp libs/cyclone/foreign.meta $(BOOTSTRAP_DIR)/cyclone
cp scheme/cyclone/pretty-print.c $(BOOTSTRAP_DIR)/scheme/cyclone cp scheme/cyclone/pretty-print.c $(BOOTSTRAP_DIR)/scheme/cyclone
cp scheme/cyclone/primitives.c $(BOOTSTRAP_DIR)/scheme/cyclone cp scheme/cyclone/primitives.c $(BOOTSTRAP_DIR)/scheme/cyclone
cp scheme/cyclone/transforms.c $(BOOTSTRAP_DIR)/scheme/cyclone cp scheme/cyclone/transforms.c $(BOOTSTRAP_DIR)/scheme/cyclone

View file

@ -57,6 +57,7 @@ Cyclone supports the following [Scheme Requests for Implementation (SRFI)](http:
These libraries are provided as Cyclone-specific extensions: These libraries are provided as Cyclone-specific extensions:
- [`cyclone concurrent`](api/cyclone/concurrent.md) - A helper library for writing concurrent code. - [`cyclone concurrent`](api/cyclone/concurrent.md) - A helper library for writing concurrent code.
- [`cyclone foreign`](api/cyclone/foreign.md) - Provides a convenient interface for integrating with C code.
- [`cyclone match`](api/cyclone/match.md) - A hygienic pattern matcher based on Alex Shinn's portable `match.scm`. - [`cyclone match`](api/cyclone/match.md) - A hygienic pattern matcher based on Alex Shinn's portable `match.scm`.
- [`cyclone test`](api/cyclone/test.md) - A unit testing framework ported from `(chibi test)`. - [`cyclone test`](api/cyclone/test.md) - A unit testing framework ported from `(chibi test)`.
- [`scheme cyclone array-list`](api/scheme/cyclone/array-list.md) - [`scheme cyclone array-list`](api/scheme/cyclone/array-list.md)

View file

@ -0,0 +1,72 @@
# Foreign Library
The `(cyclone foreign)` provides a convenient interface for integrating with C code. It is based in concept on the `(chicken foreign)` module from CHICKEN Scheme. Similarly to that module, this library manipulates the C code directly before it is compiled to a native binary. It is not possible to call these forms at runtime.
# Overview
- [`c-code`](#c-code)
- [`c-value`](#c-value)
- [`c-define`](#c-define)
- [`c-define-type`](#c-define-type)
## c-code
*Syntax*
(c-code CODE ...)
Insert C code directly into the compiled program. Each `CODE` parameter must be a string containing C code.
## c-value
*Syntax*
(c-value CODE TYPE)
Generate code that takes the C code specified by the string `CODE` and converts it to a Scheme object of type `TYPE`.
## c-define
*Syntax*
(c-define SCM-FUNC RETURN-TYPE C-FUNC TYPE ...)
Define a Scheme function `SCM-FUNC` returning an object of type `RETURN-TYPE`. The function will call C function specified by the string `C-FUNC` passed parameters of type specified by any `TYPE` arguments.
For example, to define a function that calls `strlen`:
(c-define scm-strlen int "strlen" string)
Note that these definitions are introduced at the top-level.
## c-define-type
*Syntax*
(c-define-type NAME TYPE (ARG-CONVERT (RET-CONVERT)))
Define a custom type with symbol `NAME` that is an alias of type `TYPE`. It is also possible to specify conversion functions `ARG-CONVERT` and `RET-CONVERT` to convert to/from this custom type.
EG, to define a type that consists of integers in Scheme and strings in C:
(c-define-type string-as-integer string number->string string->number)
# Type Specifiers
The following built-in specifiers may be used as a `TYPE` for forms in this module.
Scheme | C
------ | -
`int` | `int`
`integer` | `int`
`bool` | `int`
`char` | `int`
`string` | `char *`
`symbol` | `const char *`
`bytevector` | `char *`
`float` | `double`
`double` | `double`
`bignum` | `mp_int`
`opaque` | `void *`

282
libs/cyclone/foreign.sld Normal file
View file

@ -0,0 +1,282 @@
;;;; Cyclone Scheme
;;;; https://github.com/justinethier/cyclone
;;;;
;;;; Copyright (c) 2014-2019, Justin Ethier
;;;; All rights reserved.
;;;;
;;;; This module makes it easier to interface directly with C code using the FFI.
;;;;
(define-library (cyclone foreign)
(import
(scheme base)
(scheme eval)
(scheme cyclone util)
;(scheme write) ;; TODO: debugging only!
)
(export
c-code
c-value
c-define
c->scm
scm->c
c-define-type
)
(begin
;;
;;(eval `(define *foreign-types* (list)))
;; (c-define-type name type (pack (unpack)))
(define-syntax c-define-type
(er-macro-transformer
(lambda (expr rename compare)
(let ((name (cadr expr))
(type (cddr expr)))
;;
;; Custom foreign types are all stored within the global environment
;; used by `eval` at compile time. We play a few tricks using exception
;; handlers to check if variables are defined in that environment.
;;
(unless (eval '(with-handler (lambda X #f) *foreign-types*))
;(write "no foreign type table" (current-error-port))
;(newline (current-error-port))
(eval `(define *foreign-types* (make-hash-table))))
(eval `(hash-table-set! *foreign-types* (quote ,name) (quote ,type)))
#f))))
(define-syntax c-value
(er-macro-transformer
(lambda (expr rename compare)
(let* ((code-arg (cadr expr))
(type-arg (caddr expr))
(c-type (eval `(with-handler
(lambda X #f)
(hash-table-ref *foreign-types* (quote ,type-arg))
)))
(c-ret-convert #f)
)
(when c-type
;(write `(defined c type ,c-type) (current-error-port))
;(newline (current-error-port))
(set! type-arg (car c-type))
(if (= 3 (length c-type))
(set! c-ret-convert (caddr c-type))))
;(for-each
; (lambda (arg)
; (if (not (string? arg))
; (error "c-value" "Invalid argument: string expected, received " arg)))
; (cdr expr))
(if c-ret-convert
`((lambda () (,c-ret-convert (Cyc-foreign-value ,code-arg ,(symbol->string type-arg)))))
`((lambda () (Cyc-foreign-value ,code-arg ,(symbol->string type-arg))))
)
))))
(define-syntax c-code
(er-macro-transformer
(lambda (expr rename compare)
(for-each
(lambda (arg)
(if (not (string? arg))
(error "c-code" "Invalid argument: string expected, received " arg)))
(cdr expr))
`(Cyc-foreign-code ,@(cdr expr)))))
;; Unbox scheme object
;;
;; scm->c :: string -> symbol -> string
;;
;; Inputs:
;; - code - C variable used to reference the Scheme object
;; - type - Data type of the Scheme object
;; Returns:
;; - C code used to unbox the data
;(define (scm->c code type)
(define-syntax scm->c
(er-macro-transformer
(lambda (expr rename compare)
(let ((code (cadr expr))
(type (caddr expr)))
`(case ,type
((int integer)
(string-append "obj_obj2int(" ,code ")"))
((double float)
(string-append "double_value(" ,code ")"))
((bignum bigint)
(string-append "bignum_value(" ,code ")"))
((bool)
(string-append "(" ,code " == boolean_f)"))
((char)
(string-append "obj_obj2char(" ,code ")"))
((string)
(string-append "string_str(" ,code ")"))
((symbol)
(string-append "symbol_desc(" ,code ")"))
((bytevector)
(string-append "(((bytevector_type *)" ,code ")->data)"))
((opaque)
(string-append "opaque_ptr(" ,code ")"))
(else
(error "scm->c unable to convert scheme object of type " ,type)))))))
;; Box C object, basically the meat of (c-value)
;;
;; c->scm :: string -> symbol -> string
;;
;; Inputs:
;; - C expression
;; - Data type used to box the data
;; Returns:
;; - Allocation code?
;; - C code
(define-syntax c->scm
(er-macro-transformer
(lambda (expr rename compare)
(let ((code (cadr expr))
(type (caddr expr)))
`(case (if (string? ,type)
(string->symbol ,type)
,type)
((int integer)
(cons
""
(string-append "obj_int2obj(" ,code ")")))
((float double)
(let ((var (mangle (gensym 'var))))
(cons
(string-append
"make_double(" var ", " ,code ");")
(string-append "&" var)
)))
((bool)
(cons
""
(string-append "(" ,code " == 0 ? boolean_f : boolean_t)")))
((char)
(cons
""
(string-append "obj_char2obj(" ,code ")")))
((string)
(let ((var (mangle (gensym 'var))))
(cons
(string-append
"make_utf8_string(data," var ", " ,code ");")
(string-append "&" var)
)))
((bytevector)
(let ((var (mangle (gensym 'var))))
(cons
(string-append
"make_empty_bytevector(data," var ");"
var "->data = " ,code ";")
(string-append "&" var)
)))
((opaque)
(let ((var (mangle (gensym 'var))))
(cons
(string-append
"make_c_opaque(data," var ", " ,code ");")
(string-append "&" var)
)))
(else
(error "c->scm unable to convert C object of type " ,type)))))))
(define-syntax c-define
(er-macro-transformer
(lambda (expr rename compare)
(let* ((scm-fnc (cadr expr))
(scm-fnc-wrapper (gensym 'scm-fnc))
(c-fnc (cadddr expr))
(rv-type (caddr expr))
;; boolean - Are we returning a custom (user-defined) type?
(rv-cust-type (eval `(with-handler
(lambda X #f)
(hash-table-ref *foreign-types* (quote ,rv-type))
)))
;; boolean - Does the custom return type have a conversion function?
(rv-cust-convert
(if (and rv-cust-type (= 3 (length rv-cust-type)))
(caddr rv-cust-type)
#f))
(arg-types (cddddr expr))
(arg-cust-convert #f)
(arg-syms/unbox
(map
(lambda (type)
(let ((var (mangle (gensym 'arg)))
(arg-cust-type (eval `(with-handler
(lambda X #f)
(hash-table-ref *foreign-types* (quote ,type))
)))
)
(cons
var
(scm->c
var
(cond
(arg-cust-type
(if (> (length arg-cust-type) 1)
(set! arg-cust-convert #t))
(car arg-cust-type))
(else
type)))
;(string-append "string_str(" var ")")
)))
arg-types))
(returns
(c->scm
(string-append
c-fnc "(" (string-join (map cdr arg-syms/unbox) ",") ")")
(if rv-cust-type
(car rv-cust-type)
rv-type)))
(return-alloc (car returns))
(return-expr (cdr returns))
(args (string-append
"(void *data, int argc, closure _, object k "
(apply string-append
(map
(lambda (sym/unbox)
(string-append ", object " (car sym/unbox)))
arg-syms/unbox))
")"))
(body
(string-append
return-alloc
"return_closcall1(data, k, " return-expr ");"))
)
(cond
;; If there are any custom type conversion functions we need to create
;; a wrapper function in Scheme to perform those conversions
((or rv-cust-convert arg-cust-convert)
(if (not rv-cust-convert)
(set! rv-cust-convert 'begin))
(let ((arg-syms
(map
(lambda (type)
(let* ((sym (gensym 'arg))
(arg-cust-type (eval `(with-handler
(lambda X #f)
(hash-table-ref *foreign-types* (quote ,type)))))
(pass-arg
(if (and arg-cust-type
(> (length arg-cust-type) 1))
`(,(cadr arg-cust-type) ,sym)
sym)) )
(cons
sym ;; Arg
pass-arg)));; Passing arg to internal func
arg-types)))
`(begin
(define-c ,scm-fnc-wrapper ,args ,body)
(define (,scm-fnc ,@(map car arg-syms))
(,rv-cust-convert
(,scm-fnc-wrapper ,@(map cdr arg-syms)))))))
;; Simpler case, just define the function directly
(else
`(define-c ,scm-fnc ,args ,body)))
))))
)
)

57
libs/test-foreign.scm Normal file
View file

@ -0,0 +1,57 @@
;; Unit tests for the (cyclone foreign) module.
;;
(import
(scheme base)
(scheme write)
(cyclone test)
(cyclone foreign)
(scheme cyclone util)
(scheme cyclone pretty-print)
)
(define *my-global* #f)
(c-define-type my-string string)
(c-define-type my-integer integer)
(c-define-type my-integer-as-string integer string->number number->string)
(c-define-type string-as-integer string number->string string->number)
(test-group "foreign value"
(test 3 (c-value "1 + 2" integer))
(test 4 (c-value "2 + 2" my-integer))
(test "4" (c-value "2 + 2" my-integer-as-string))
(test "test" (c-value "\"test\"" string))
)
(test-group "foreign code"
(test #f *my-global*)
(c-code
"printf(\"test %d %d \\n\", 1, 2);"
"printf(\"test %d %d %d\\n\", 1, 2, 3);"
"__glo__85my_91global_85 = boolean_t;")
(test #t *my-global*)
(set! *my-global* 1)
(test 1 *my-global*)
)
;; Must be top-level
;TODO: support custom types (arg and ret) for c-define.
; Also need to be able to support arg/ret convert optional type arguments
; Would need to generate scheme wrappers to handle these conversions
(c-define scm-strlen my-integer "strlen" string)
(c-define scm-strlen-str my-integer-as-string "strlen" string)
;(c-define scm-strlen "int" "strlen" string)
(c-define scm-strlend double "strlen" string)
(c-define scm-strlen2 integer "strlen" my-string)
(c-define scm-strlen3 integer "strlen" string-as-integer)
(test-group "foreign lambda"
(test 15 (scm-strlen "testing 1, 2, 3"))
(test 15 (scm-strlen2 "testing 1, 2, 3"))
(test 15.0 (scm-strlend "testing 1, 2, 3"))
(test "15" (scm-strlen-str "testing 1, 2, 3"))
(test 3 (scm-strlen3 255))
)
(test-exit)

View file

@ -13,6 +13,7 @@
(scheme eval) (scheme eval)
(scheme inexact) (scheme inexact)
(scheme write) (scheme write)
(cyclone foreign)
(scheme cyclone primitives) (scheme cyclone primitives)
(scheme cyclone transforms) (scheme cyclone transforms)
(scheme cyclone ast) (scheme cyclone ast)
@ -283,12 +284,12 @@
;;; Compilation routines. ;;; Compilation routines.
;; Return generated code that also requests allocation of C variables on stack ;; Return generated code that also requests allocation of C variables on stack
(define (c-code/vars str cvars) (define (c:code/vars str cvars)
(list str (list str
cvars)) cvars))
;; Return generated code with no C variables allocated on the stack ;; Return generated code with no C variables allocated on the stack
(define (c-code str) (c-code/vars str (list))) (define (c:code str) (c:code/vars str (list)))
;; Append arg count to a C code pair ;; Append arg count to a C code pair
(define (c:tuple/args cp num-args) (define (c:tuple/args cp num-args)
@ -327,12 +328,12 @@
c-allocs)) c-allocs))
(define (c:append cp1 cp2) (define (c:append cp1 cp2)
(c-code/vars (c:code/vars
(string-append (c:body cp1) (c:body cp2)) (string-append (c:body cp1) (c:body cp2))
(append (c:allocs cp1) (c:allocs cp2)))) (append (c:allocs cp1) (c:allocs cp2))))
(define (c:append/prefix prefix cp1 cp2) (define (c:append/prefix prefix cp1 cp2)
(c-code/vars (c:code/vars
(string-append prefix (c:body cp1) (c:body cp2)) (string-append prefix (c:body cp1) (c:body cp2))
(append (c:allocs cp1) (c:allocs cp2)))) (append (c:allocs cp1) (c:allocs cp2))))
@ -390,7 +391,7 @@
((const? exp) (c-compile-const exp (alloca? ast-id trace) #f)) ;; TODO: OK to hardcode immutable to false here?? ((const? exp) (c-compile-const exp (alloca? ast-id trace) #f)) ;; TODO: OK to hardcode immutable to false here??
((prim? exp) ((prim? exp)
;; TODO: this needs to be more refined, probably w/a lookup table ;; TODO: this needs to be more refined, probably w/a lookup table
(c-code (string-append "primitive_" (mangle exp)))) (c:code (string-append "primitive_" (mangle exp))))
((ref? exp) (c-compile-ref exp)) ((ref? exp) (c-compile-ref exp))
((quote? exp) (c-compile-quote exp (alloca? ast-id trace))) ((quote? exp) (c-compile-quote exp (alloca? ast-id trace)))
((if? exp) (c-compile-if exp append-preamble cont ast-id trace cps?)) ((if? exp) (c-compile-if exp append-preamble cont ast-id trace cps?))
@ -436,7 +437,7 @@
(num-args 0) (num-args 0)
(create-cons (create-cons
(lambda (cvar a b) (lambda (cvar a b)
(c-code/vars (c:code/vars
(string-append (string-append
c-make-macro "(" cvar "," (c:body a) "," (c:body b) ");" c-make-macro "(" cvar "," (c:body a) "," (c:body b) ");"
(c-set-immutable-field cvar use-alloca immutable)) (c-set-immutable-field cvar use-alloca immutable))
@ -445,7 +446,7 @@
(lambda (args) (lambda (args)
(cond (cond
((null? args) ((null? args)
(c-code "NULL")) (c:code "NULL"))
((not (pair? args)) ((not (pair? args))
(c-compile-const args use-alloca immutable)) (c-compile-const args use-alloca immutable))
(else (else
@ -455,7 +456,7 @@
(c-compile-const (car args) use-alloca immutable) (c-compile-const (car args) use-alloca immutable)
(_c-compile-scalars (cdr args))))) (_c-compile-scalars (cdr args)))))
(set! num-args (+ 1 num-args)) (set! num-args (+ 1 num-args))
(c-code/vars (c:code/vars
(string-append addr-op cvar-name) (string-append addr-op cvar-name)
(append (append
(c:allocs cell) (c:allocs cell)
@ -484,7 +485,7 @@
(let ((idx-code (c-compile-const (vector-ref exp i) use-alloca immutable))) (let ((idx-code (c-compile-const (vector-ref exp i) use-alloca immutable)))
(loop (loop
(+ i 1) (+ i 1)
(c-code/vars (c:code/vars
;; The vector's C variable ;; The vector's C variable
(c:body code) (c:body code)
;; Allocations ;; Allocations
@ -498,7 +499,7 @@
";")))))))))) ";"))))))))))
(cond (cond
((zero? len) ((zero? len)
(c-code/vars (c:code/vars
(string-append addr-op cvar-name) ; Code is just the variable name (string-append addr-op cvar-name) ; Code is just the variable name
(list ; Allocate empty vector (list ; Allocate empty vector
(string-append (string-append
@ -506,7 +507,7 @@
(c-set-immutable-field cvar-name use-alloca immutable))))) (c-set-immutable-field cvar-name use-alloca immutable)))))
(else (else
(let ((code (let ((code
(c-code/vars (c:code/vars
(string-append addr-op cvar-name) ; Code body is just var name (string-append addr-op cvar-name) ; Code body is just var name
(list ; Allocate the vector (list ; Allocate the vector
(string-append (string-append
@ -532,7 +533,7 @@
(let ((byte-val (number->string (bytevector-u8-ref exp i)))) (let ((byte-val (number->string (bytevector-u8-ref exp i))))
(loop (loop
(+ i 1) (+ i 1)
(c-code/vars (c:code/vars
;; The bytevector's C variable ;; The bytevector's C variable
(c:body code) (c:body code)
;; Allocations ;; Allocations
@ -545,7 +546,7 @@
";")))))))))) ";"))))))))))
(cond (cond
((zero? len) ((zero? len)
(c-code/vars (c:code/vars
(string-append addr-op cvar-name) ; Code is just the variable name (string-append addr-op cvar-name) ; Code is just the variable name
(list ; Allocate empty vector (list ; Allocate empty vector
(string-append (string-append
@ -554,7 +555,7 @@
)))) ))))
(else (else
(let ((code (let ((code
(c-code/vars (c:code/vars
(string-append addr-op cvar-name) ; Code body is just var name (string-append addr-op cvar-name) ; Code body is just var name
(list ; Allocate the vector (list ; Allocate the vector
(string-append (string-append
@ -572,7 +573,7 @@
(use-alloca (use-alloca
(let ((tmp-name (mangle (gensym 'tmp))) (let ((tmp-name (mangle (gensym 'tmp)))
(blen (number->string (string-byte-length exp)))) (blen (number->string (string-byte-length exp))))
(c-code/vars (c:code/vars
(string-append "" cvar-name) ; Code is just the variable name (string-append "" cvar-name) ; Code is just the variable name
(list ; Allocate integer on the C stack (list ; Allocate integer on the C stack
(string-append (string-append
@ -595,7 +596,7 @@
use-alloca immutable) use-alloca immutable)
))))) )))))
(else (else
(c-code/vars (c:code/vars
(string-append "&" cvar-name) ; Code is just the variable name (string-append "&" cvar-name) ; Code is just the variable name
(list ; Allocate integer on the C stack (list ; Allocate integer on the C stack
(string-append (string-append
@ -623,7 +624,7 @@
(define (c-compile-const exp use-alloca immutable) (define (c-compile-const exp use-alloca immutable)
(cond (cond
((null? exp) ((null? exp)
(c-code "NULL")) (c:code "NULL"))
((pair? exp) ((pair? exp)
(c-compile-scalars exp use-alloca immutable)) (c-compile-scalars exp use-alloca immutable))
((vector? exp) ((vector? exp)
@ -635,7 +636,7 @@
(num2str (cond (num2str (cond
(else (else
(number->string exp))))) (number->string exp)))))
(c-code/vars (c:code/vars
(string-append "" cvar-name) ; Code is just the variable name (string-append "" cvar-name) ; Code is just the variable name
(list ; Allocate pointer on the C stack (list ; Allocate pointer on the C stack
(string-append (string-append
@ -656,14 +657,14 @@
(inum (num2str (imag-part exp))) (inum (num2str (imag-part exp)))
(addr-op (if use-alloca "" "&")) (addr-op (if use-alloca "" "&"))
(c-make-macro (if use-alloca "alloca_complex_num" "make_complex_num"))) (c-make-macro (if use-alloca "alloca_complex_num" "make_complex_num")))
(c-code/vars (c:code/vars
(string-append addr-op cvar-name) ; Code is just the variable name (string-append addr-op cvar-name) ; Code is just the variable name
(list ; Allocate on the C stack (list ; Allocate on the C stack
(string-append (string-append
c-make-macro "(" cvar-name ", " rnum ", " inum ");"))))) c-make-macro "(" cvar-name ", " rnum ", " inum ");")))))
((and (integer? exp) ((and (integer? exp)
(exact? exp)) (exact? exp))
(c-code (string-append "obj_int2obj(" (c:code (string-append "obj_int2obj("
(number->string exp) ")"))) (number->string exp) ")")))
((real? exp) ((real? exp)
(let ((cvar-name (mangle (gensym 'c))) (let ((cvar-name (mangle (gensym 'c)))
@ -676,22 +677,22 @@
(number->string exp)))) (number->string exp))))
(addr-op (if use-alloca "" "&")) (addr-op (if use-alloca "" "&"))
(c-make-macro (if use-alloca "alloca_double" "make_double"))) (c-make-macro (if use-alloca "alloca_double" "make_double")))
(c-code/vars (c:code/vars
(string-append addr-op cvar-name) ; Code is just the variable name (string-append addr-op cvar-name) ; Code is just the variable name
(list ; Allocate on the C stack (list ; Allocate on the C stack
(string-append (string-append
c-make-macro "(" cvar-name ", " num2str ");"))))) c-make-macro "(" cvar-name ", " num2str ");")))))
((boolean? exp) ((boolean? exp)
(c-code (string-append (c:code (string-append
(if exp "boolean_t" "boolean_f")))) (if exp "boolean_t" "boolean_f"))))
((char? exp) ((char? exp)
(c-code (string-append "obj_char2obj(" (c:code (string-append "obj_char2obj("
(number->string (char->integer exp)) ")"))) (number->string (char->integer exp)) ")")))
((string? exp) ((string? exp)
(c-compile-string exp use-alloca immutable)) (c-compile-string exp use-alloca immutable))
((symbol? exp) ((symbol? exp)
(allocate-symbol exp) (allocate-symbol exp)
(c-code (string-append "quote_" (mangle exp)))) (c:code (string-append "quote_" (mangle exp))))
(else (else
(error "unknown constant: " exp)))) (error "unknown constant: " exp))))
@ -783,7 +784,7 @@
(c-var-assign (c-var-assign
(lambda (type) (lambda (type)
(let ((cv-name (mangle (gensym 'c)))) (let ((cv-name (mangle (gensym 'c))))
(c-code/vars (c:code/vars
(string-append (string-append
(if (or (prim:cont? p) (if (or (prim:cont? p)
(equal? (prim/c-var-assign p) "object") (equal? (prim/c-var-assign p) "object")
@ -830,7 +831,7 @@
;; the logic ;; the logic
;; ;;
(let ((cv-name (mangle (gensym 'c)))) (let ((cv-name (mangle (gensym 'c))))
(c-code/vars (c:code/vars
(if (or (prim:allocates-object? p use-alloca?) (if (or (prim:allocates-object? p use-alloca?)
(prim->c-func-uses-alloca? p use-alloca?)) (prim->c-func-uses-alloca? p use-alloca?))
cv-name ; Already a pointer cv-name ; Already a pointer
@ -838,7 +839,7 @@
(list (list
(string-append c-func "(" cv-name tdata-comma tdata))))) (string-append c-func "(" cv-name tdata-comma tdata)))))
(else (else
(c-code/vars (c:code/vars
(string-append c-func "(" tdata tptr-comma tptr) (string-append c-func "(" tdata tptr-comma tptr)
(list tptr-decl)))))) (list tptr-decl))))))
@ -869,7 +870,7 @@
;; c-compile-ref : ref-exp -> string ;; c-compile-ref : ref-exp -> string
(define (c-compile-ref exp) (define (c-compile-ref exp)
(c-code (c:code
(if (member exp *global-syms*) (if (member exp *global-syms*)
(cgen:mangle-global exp) (cgen:mangle-global exp)
(mangle exp)))) (mangle exp))))
@ -882,7 +883,7 @@
(lambda (args append-preamble prefix cont) (lambda (args append-preamble prefix cont)
(cond (cond
((not (pair? args)) ((not (pair? args))
(c-code "")) (c:code ""))
(else (else
;; (trace:debug `(c-compile-args ,(car args))) ;; (trace:debug `(c-compile-args ,(car args)))
(let ((cp (c-compile-exp (car args) (let ((cp (c-compile-exp (car args)
@ -929,7 +930,7 @@
cps?)) cps?))
(num-cargs (c:num-args cgen))) (num-cargs (c:num-args cgen)))
(set-c-call-arity! num-cargs) (set-c-call-arity! num-cargs)
(c-code (c:code
(string-append (string-append
(c:allocs->str (c:allocs cgen)) (c:allocs->str (c:allocs cgen))
"return_direct" (number->string num-cargs) "return_direct" (number->string num-cargs)
@ -978,7 +979,7 @@
parent-args parent-args
cgen-lis)))) cgen-lis))))
;;(trace:info `(loop ,args ,(cadr args) ,cgen-lis ,parent-args)) ;;(trace:info `(loop ,args ,(cadr args) ,cgen-lis ,parent-args))
(c-code (c:code
(string-append (string-append
cgen-allocs ; (c:allocs->str (c:allocs cgen)) cgen-allocs ; (c:allocs->str (c:allocs cgen))
"\n" "\n"
@ -986,6 +987,18 @@
"\n" "\n"
"continue;")))) "continue;"))))
((eq? 'Cyc-foreign-code fun)
(c:code/vars
(string-append
"")
args))
((eq? 'Cyc-foreign-value fun)
(let ((kons (c->scm (car args) (cadr args))))
(c:code/vars
(cdr kons)
(list (car kons)))))
((prim? fun) ((prim? fun)
(let* ((c-fun (let* ((c-fun
(c-compile-prim fun cont ast-id)) (c-compile-prim fun cont ast-id))
@ -997,7 +1010,7 @@
(number->string num-args) (number->string num-args)
(if (> num-args 0) "," ""))) (if (> num-args 0) "," "")))
(c-args* (if (prim:arg-count? fun) (c-args* (if (prim:arg-count? fun)
(c:append (c-code num-args-str) c-args) (c:append (c:code num-args-str) c-args)
c-args))) c-args)))
;; Emit symbol when mutating global variables, so we can look ;; Emit symbol when mutating global variables, so we can look
;; up the cvar ;; up the cvar
@ -1016,7 +1029,7 @@
(if (prim/cvar? fun) (if (prim/cvar? fun)
;; Args need to go with alloc function ;; Args need to go with alloc function
(c-code/vars (c:code/vars
(c:body c-fun) (c:body c-fun)
(append (append
(c:allocs c-args*) ; fun alloc depends upon arg allocs (c:allocs c-args*) ; fun alloc depends upon arg allocs
@ -1042,12 +1055,12 @@
(and (prim:udf? fun) (and (prim:udf? fun)
(zero? num-args))) (zero? num-args)))
c-fun c-fun
(c:append c-fun (c-code ", ")))) (c:append c-fun (c:code ", "))))
c-args*) c-args*)
(c-code ")"))))) (c:code ")")))))
((equal? '%closure-ref fun) ((equal? '%closure-ref fun)
(c-code (apply string-append (list (c:code (apply string-append (list
(c-compile-closure-element-ref (c-compile-closure-element-ref
ast-id ast-id
(car args) (car args)
@ -1069,7 +1082,7 @@
(num-cargs (c:num-args cargs))) (num-cargs (c:num-args cargs)))
(cond (cond
((not cps?) ((not cps?)
(c-code (c:code
(string-append (string-append
(c:allocs->str (c:allocs cfun) "\n") (c:allocs->str (c:allocs cfun) "\n")
(c:allocs->str (c:allocs cargs) "\n") (c:allocs->str (c:allocs cargs) "\n")
@ -1125,7 +1138,7 @@
(string-append " " p " = " tmp "; ")) (string-append " " p " = " tmp "; "))
params tmp-params)))) params tmp-params))))
;; (trace:error `(JAE ,fun ,ast-id ,params ,args (c:num-args cargs))) ;; (trace:error `(JAE ,fun ,ast-id ,params ,args (c:num-args cargs)))
(c-code/vars (c:code/vars
(string-append (string-append
(c:allocs->str (c:allocs cfun) "\n") (c:allocs->str (c:allocs cfun) "\n")
(c:allocs->str (c:allocs cargs) "\n") (c:allocs->str (c:allocs cargs) "\n")
@ -1150,7 +1163,7 @@
(let* ((lid (ast:lambda-id wkf)) (let* ((lid (ast:lambda-id wkf))
(c-lambda-fnc-str (string-append "__lambda_" (number->string lid))) (c-lambda-fnc-str (string-append "__lambda_" (number->string lid)))
(c-lambda-fnc-gc-ret-str (string-append "__lambda_gc_ret_" (number->string lid)))) (c-lambda-fnc-gc-ret-str (string-append "__lambda_gc_ret_" (number->string lid))))
(c-code (c:code
(string-append (string-append
(c:allocs->str (c:allocs cfun) "\n") (c:allocs->str (c:allocs cfun) "\n")
(c:allocs->str (c:allocs cargs) "\n") (c:allocs->str (c:allocs cargs) "\n")
@ -1171,7 +1184,7 @@
((and wkf fnc) ((and wkf fnc)
(let* ((lid (ast:lambda-id wkf)) (let* ((lid (ast:lambda-id wkf))
(c-lambda-fnc-str (string-append "__lambda_" (number->string lid)))) (c-lambda-fnc-str (string-append "__lambda_" (number->string lid))))
(c-code (c:code
(string-append (string-append
(c:allocs->str (c:allocs cfun) "\n") (c:allocs->str (c:allocs cfun) "\n")
(c:allocs->str (c:allocs cargs) "\n") (c:allocs->str (c:allocs cargs) "\n")
@ -1184,7 +1197,7 @@
(c:body cargs) (c:body cargs)
");")))) ");"))))
(else (else
(c-code (c:code
(string-append (string-append
(c:allocs->str (c:allocs cfun) "\n") (c:allocs->str (c:allocs cfun) "\n")
(c:allocs->str (c:allocs cargs) "\n") (c:allocs->str (c:allocs cargs) "\n")
@ -1204,7 +1217,7 @@
(num-cargs (c:num-args cargs))) (num-cargs (c:num-args cargs)))
(cond (cond
((not cps?) ((not cps?)
(c-code (c:code
(string-append (string-append
(c:allocs->str (c:allocs cfun) "\n") (c:allocs->str (c:allocs cfun) "\n")
(c:allocs->str (c:allocs cargs) "\n") (c:allocs->str (c:allocs cargs) "\n")
@ -1224,7 +1237,7 @@
(let* ((lid (ast:lambda-id (closure->lam fun))) (let* ((lid (ast:lambda-id (closure->lam fun)))
(c-lambda-fnc-str (string-append "__lambda_" (number->string lid))) (c-lambda-fnc-str (string-append "__lambda_" (number->string lid)))
(c-lambda-fnc-gc-ret-str (string-append "__lambda_gc_ret_" (number->string lid)))) (c-lambda-fnc-gc-ret-str (string-append "__lambda_gc_ret_" (number->string lid))))
(c-code (c:code
(string-append (string-append
(c:allocs->str (c:allocs cfun) "\n") (c:allocs->str (c:allocs cfun) "\n")
(c:allocs->str (c:allocs cargs) "\n") (c:allocs->str (c:allocs cargs) "\n")
@ -1241,7 +1254,7 @@
((adbf:well-known fnc) ((adbf:well-known fnc)
(let* ((lid (ast:lambda-id (closure->lam fun))) (let* ((lid (ast:lambda-id (closure->lam fun)))
(c-lambda-fnc-str (string-append "__lambda_" (number->string lid)))) (c-lambda-fnc-str (string-append "__lambda_" (number->string lid))))
(c-code (c:code
(string-append (string-append
(c:allocs->str (c:allocs cfun) "\n") (c:allocs->str (c:allocs cfun) "\n")
(c:allocs->str (c:allocs cargs) "\n") (c:allocs->str (c:allocs cargs) "\n")
@ -1254,7 +1267,7 @@
(c:body cargs) (c:body cargs)
");")))) ");"))))
(else (else
(c-code (c:code
(string-append (string-append
(c:allocs->str (c:allocs cfun) "\n") (c:allocs->str (c:allocs cfun) "\n")
(c:allocs->str (c:allocs cargs) "\n") (c:allocs->str (c:allocs cargs) "\n")
@ -1271,25 +1284,25 @@
;; Join expressions; based on c:append ;; Join expressions; based on c:append
(let ((cp1 (if (ref? expr) (let ((cp1 (if (ref? expr)
;; Ignore lone ref to avoid C warning ;; Ignore lone ref to avoid C warning
(c-code/vars "" '()) (c:code/vars "" '())
(c-compile-exp expr append-preamble cont ast-id trace cps?))) (c-compile-exp expr append-preamble cont ast-id trace cps?)))
(cp2 acc)) (cp2 acc))
(c-code/vars (c:code/vars
(let ((cp1-body (c:body cp1))) (let ((cp1-body (c:body cp1)))
(if (zero? (string-length cp1-body)) (if (zero? (string-length cp1-body))
(c:body cp2) ; Ignore cp1 if necessary (c:body cp2) ; Ignore cp1 if necessary
(string-append cp1-body ";" (c:body cp2)))) (string-append cp1-body ";" (c:body cp2))))
(append (c:allocs cp1) (c:allocs cp2))))) (append (c:allocs cp1) (c:allocs cp2)))))
(c-code "") (c:code "")
args))) args)))
exps)) exps))
((equal? 'Cyc-local-set! fun) ((equal? 'Cyc-local-set! fun)
;:(trace:error `(JAE DEBUG Cyc-local-set ,exp)) ;:(trace:error `(JAE DEBUG Cyc-local-set ,exp))
(let ((val-exp (c-compile-exp (caddr exp) append-preamble cont ast-id trace cps?))) (let ((val-exp (c-compile-exp (caddr exp) append-preamble cont ast-id trace cps?)))
(c-code/vars (c:code/vars
(string-append (mangle (cadr exp)) " = " (c:body val-exp) ";") (string-append (mangle (cadr exp)) " = " (c:body val-exp) ";")
(c:allocs val-exp))) (c:allocs val-exp)))
;; (c-code (string-append (mangle (cadr exp)) " = " (mangle (caddr exp)) ";")) ;; (c:code (string-append (mangle (cadr exp)) " = " (mangle (caddr exp)) ";"))
) )
((equal? 'let fun) ((equal? 'let fun)
(let* ((vars/vals (cadr exp)) (let* ((vars/vals (cadr exp))
@ -1301,14 +1314,14 @@
(let ((cp1 (c-compile-exp (cadr var/val) append-preamble cont ast-id trace cps?)) (let ((cp1 (c-compile-exp (cadr var/val) append-preamble cont ast-id trace cps?))
(cp2 acc)) (cp2 acc))
(set-use-alloca! #f) ; Revert flag (set-use-alloca! #f) ; Revert flag
(c-code/vars (c:code/vars
(let ((cp1-body (c:body cp1))) (let ((cp1-body (c:body cp1)))
(string-append cp1-body ";" (c:body cp2))) (string-append cp1-body ";" (c:body cp2)))
(append (append
(list (string-append "object " (mangle (car var/val)) ";")) (list (string-append "object " (mangle (car var/val)) ";"))
(c:allocs cp1) (c:allocs cp1)
(c:allocs cp2))))) (c:allocs cp2)))))
(c-code "") (c:code "")
vars/vals)) vars/vals))
(body-exp (c-compile-exp (body-exp (c-compile-exp
body append-preamble cont ast-id trace cps?))) body append-preamble cont ast-id trace cps?)))
@ -1324,7 +1337,7 @@
(test (compile (if->condition exp))) (test (compile (if->condition exp)))
(then (compile (if->then exp))) (then (compile (if->then exp)))
(els (compile (if->else exp)))) (els (compile (if->else exp))))
(c-code (string-append (c:code (string-append
(c:allocs->str (c:allocs test) " ") (c:allocs->str (c:allocs test) " ")
"if( (boolean_f != " "if( (boolean_f != "
(c:body test) (c:body test)
@ -1392,7 +1405,7 @@
#f ; inline, so disable CPS on this pass #f ; inline, so disable CPS on this pass
))) )))
(c-code/vars "" (list "")))) (c:code/vars "" (list ""))))
(define (c-compile-raw-global-lambda exp append-preamble cont trace . cps?) (define (c-compile-raw-global-lambda exp append-preamble cont trace . cps?)
(let* ((precompiled-sym (let* ((precompiled-sym
@ -1434,14 +1447,14 @@
(define->var exp) (define->var exp)
#t ; (lambda? body) #t ; (lambda? body)
(let ((cv-name (mangle (gensym 'c)))) (let ((cv-name (mangle (gensym 'c))))
(c-code/vars (c:code/vars
(string-append "&" cv-name) (string-append "&" cv-name)
(list (list
(string-append "mclosure0(" cv-name ", (function_type)__lambda_" (string-append "mclosure0(" cv-name ", (function_type)__lambda_"
(number->string lid) ");" cv-name ".num_args = " (number->string lid) ");" cv-name ".num_args = "
(number->string num-args) (number->string num-args)
";"))))) ";")))))
(c-code/vars "" (list "")))) (c:code/vars "" (list ""))))
;; Symbol compilation ;; Symbol compilation
@ -1642,7 +1655,7 @@
(create-object (lambda () (create-object (lambda ()
;; JAE - this is fine, now need to handle other side (actually reading the value without a closure obj ;; JAE - this is fine, now need to handle other side (actually reading the value without a closure obj
;; (trace:error `(create-object free-vars ,free-vars ,(car free-vars))) ;; (trace:error `(create-object free-vars ,free-vars ,(car free-vars)))
(c-code/vars (c:code/vars
(car free-vars) (car free-vars)
(list)))) (list))))
(create-nclosure (lambda () (create-nclosure (lambda ()
@ -1700,7 +1713,7 @@
(use-obj-instead-of-closure? (use-obj-instead-of-closure?
(create-object)) (create-object))
(else (else
(c-code/vars (c:code/vars
(if (and use-alloca? (if (and use-alloca?
(> (length free-vars) 0)) (> (length free-vars) 0))
cv-name cv-name
@ -1806,7 +1819,7 @@
"") ; No varargs, skip "") ; No varargs, skip
(c:serialize (c:serialize
(c:append (c:append
(c-code (c:code
;; Only trace when entering initial defined function ;; Only trace when entering initial defined function
(cond (cond
(has-closure? (has-closure?

View file

@ -89,6 +89,8 @@
Cyc-stderr Cyc-stderr
Cyc-list Cyc-list
Cyc-if Cyc-if
Cyc-foreign-code
Cyc-foreign-value
Cyc-fast-plus Cyc-fast-plus
Cyc-fast-sub Cyc-fast-sub
Cyc-fast-mul Cyc-fast-mul
@ -238,6 +240,8 @@
(Cyc-stdin 0 0) (Cyc-stdin 0 0)
(Cyc-stderr 0 0) (Cyc-stderr 0 0)
(Cyc-if 3 3) (Cyc-if 3 3)
(Cyc-foreign-code 1 #f)
(Cyc-foreign-value 2 2)
(Cyc-fast-plus 2 2) (Cyc-fast-plus 2 2)
(Cyc-fast-sub 2 2) (Cyc-fast-sub 2 2)
(Cyc-fast-mul 2 2) (Cyc-fast-mul 2 2)
@ -529,6 +533,8 @@
((eq? p 'Cyc-stderr) "Cyc_stderr") ((eq? p 'Cyc-stderr) "Cyc_stderr")
((eq? p 'Cyc-list) "Cyc_list") ((eq? p 'Cyc-list) "Cyc_list")
((eq? p 'Cyc-if) "Cyc_if") ((eq? p 'Cyc-if) "Cyc_if")
((eq? p 'Cyc-foreign-code) "UNDEF")
((eq? p 'Cyc-foreign-value) "UNDEF")
((eq? p 'Cyc-fast-plus) "Cyc_fast_sum") ((eq? p 'Cyc-fast-plus) "Cyc_fast_sum")
((eq? p 'Cyc-fast-sub) "Cyc_fast_sub") ((eq? p 'Cyc-fast-sub) "Cyc_fast_sub")
((eq? p 'Cyc-fast-mul) "Cyc_fast_mul") ((eq? p 'Cyc-fast-mul) "Cyc_fast_mul")
@ -701,6 +707,8 @@
(or (or
(memq p '( (memq p '(
Cyc-list Cyc-list
Cyc-foreign-code
Cyc-foreign-value
Cyc-fast-plus Cyc-fast-plus
Cyc-fast-sub Cyc-fast-sub
Cyc-fast-mul Cyc-fast-mul