Merge pull request #500 from mnieper/syntax-case

Implement syntax-case
This commit is contained in:
Alex Shinn 2018-12-09 04:08:31 +08:00 committed by GitHub
commit 2c37dfedd3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 551 additions and 36 deletions

9
eval.c
View file

@ -384,6 +384,7 @@ static sexp sexp_make_macro (sexp ctx, sexp p, sexp e) {
sexp mac = sexp_alloc_type(ctx, macro, SEXP_MACRO);
sexp_macro_env(mac) = e;
sexp_macro_proc(mac) = p;
sexp_macro_aux(mac) = SEXP_FALSE;
return mac;
}
@ -397,10 +398,12 @@ sexp sexp_make_synclo_op (sexp ctx, sexp self, sexp_sint_t n, sexp env, sexp fv,
sexp_synclo_env(res) = sexp_synclo_env(expr);
sexp_synclo_free_vars(res) = sexp_synclo_free_vars(expr);
sexp_synclo_expr(res) = sexp_synclo_expr(expr);
sexp_synclo_rename(res) = sexp_synclo_rename(expr);
} else {
sexp_synclo_env(res) = env;
sexp_synclo_free_vars(res) = fv;
sexp_synclo_expr(res) = expr;
sexp_synclo_rename(res) = SEXP_FALSE;
}
return res;
}
@ -2165,9 +2168,9 @@ static struct sexp_core_form_struct core_forms[] = {
{SEXP_CORE_BEGIN, (sexp)"begin"},
{SEXP_CORE_QUOTE, (sexp)"quote"},
{SEXP_CORE_SYNTAX_QUOTE, (sexp)"syntax-quote"},
{SEXP_CORE_DEFINE_SYNTAX, (sexp)"define-syntax"},
{SEXP_CORE_LET_SYNTAX, (sexp)"let-syntax"},
{SEXP_CORE_LETREC_SYNTAX, (sexp)"letrec-syntax"},
{SEXP_CORE_DEFINE_SYNTAX, (sexp)"%define-syntax"},
{SEXP_CORE_LET_SYNTAX, (sexp)"%let-syntax"},
{SEXP_CORE_LETREC_SYNTAX, (sexp)"%letrec-syntax"},
};
sexp sexp_make_env_op (sexp ctx, sexp self, sexp_sint_t n) {

View file

@ -495,10 +495,10 @@ struct sexp_struct {
sexp bc, vars;
} procedure;
struct {
sexp proc, env, source;
sexp proc, env, source, aux;
} macro;
struct {
sexp env, free_vars, expr;
sexp env, free_vars, expr, rename;
} synclo;
struct {
sexp file;
@ -1134,10 +1134,12 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_macro_proc(x) (sexp_field(x, macro, SEXP_MACRO, proc))
#define sexp_macro_env(x) (sexp_field(x, macro, SEXP_MACRO, env))
#define sexp_macro_source(x) (sexp_field(x, macro, SEXP_MACRO, source))
#define sexp_macro_aux(x) (sexp_field(x, macro, SEXP_MACRO, aux))
#define sexp_synclo_env(x) (sexp_field(x, synclo, SEXP_SYNCLO, env))
#define sexp_synclo_free_vars(x) (sexp_field(x, synclo, SEXP_SYNCLO, free_vars))
#define sexp_synclo_expr(x) (sexp_field(x, synclo, SEXP_SYNCLO, expr))
#define sexp_synclo_rename(x) (sexp_field(x, synclo, SEXP_SYNCLO, rename))
#define sexp_core_code(x) (sexp_field(x, core, SEXP_CORE, code))
#define sexp_core_name(x) (sexp_field(x, core, SEXP_CORE, name))
@ -1389,6 +1391,10 @@ enum sexp_context_globals {
SEXP_G_QUASIQUOTE_SYMBOL,
SEXP_G_UNQUOTE_SYMBOL,
SEXP_G_UNQUOTE_SPLICING_SYMBOL,
SEXP_G_SYNTAX_SYMBOL,
SEXP_G_QUASISYNTAX_SYMBOL,
SEXP_G_UNSYNTAX_SYMBOL,
SEXP_G_UNSYNTAX_SPLICING_SYMBOL,
SEXP_G_EMPTY_VECTOR,
SEXP_G_CUR_IN_SYMBOL,
SEXP_G_CUR_OUT_SYMBOL,

View file

@ -72,7 +72,7 @@ sexp sexp_get_env_cell (sexp ctx, sexp self, sexp_sint_t n, sexp env, sexp id, s
id = sexp_synclo_expr(id);
}
cell = sexp_env_cell(ctx, env, id, 0);
if (!cell && createp)
if (!cell && sexp_truep(createp))
cell = sexp_env_cell_define(ctx, env, id, SEXP_UNDEF, NULL);
}
return cell ? cell : SEXP_FALSE;
@ -669,6 +669,7 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
sexp_define_accessors(ctx, env, SEXP_MACRO, 0, "macro-procedure", NULL);
sexp_define_accessors(ctx, env, SEXP_MACRO, 1, "macro-env", NULL);
sexp_define_accessors(ctx, env, SEXP_MACRO, 2, "macro-source", NULL);
sexp_define_accessors(ctx, env, SEXP_MACRO, 3, "macro-aux", "macro-aux-set!");
sexp_define_foreign(ctx, env, "procedure-code", 1, sexp_get_procedure_code);
sexp_define_foreign(ctx, env, "procedure-vars", 1, sexp_get_procedure_vars);
sexp_define_foreign(ctx, env, "procedure-arity", 1, sexp_get_procedure_arity);

View file

@ -222,6 +222,8 @@
;;> \item{\scheme{(macro-procedure f)} - the macro procedure}
;;> \item{\scheme{(macro-env f)} - the environment the macro was defined in}
;;> \item{\scheme{(macro-source f)} - the source location the macro was defined in}
;;> \item{\scheme{(macro-aux f)} - custom auxiliary data stored with the macro}
;;> \item{\scheme{(macro-aux-set! f x)}}
;;> ]
;;> \subsection{Bytecode Objects}

View file

@ -26,7 +26,7 @@
exception-kind exception-message exception-irritants exception-source
opcode-name opcode-num-params opcode-return-type opcode-param-type
opcode-class opcode-code opcode-data opcode-variadic?
macro-procedure macro-env macro-source
macro-procedure macro-env macro-source macro-aux macro-aux-set!
procedure-code procedure-vars procedure-name procedure-name-set!
procedure-arity procedure-variadic? procedure-flags
bytecode-name bytecode-literals bytecode-source

View file

@ -0,0 +1,50 @@
(define-library (chibi syntax-case-test)
(export run-tests)
(import (chibi)
(chibi syntax-case)
(chibi test))
(begin
(define (run-tests)
(test-begin "Syntax Case")
(test "syntax constant list"
'(+ 1 2)
#'(+ 1 2))
(test "pattern variable"
'foo
(syntax-case 'foo ()
(x #'x)))
(test "syntax-case pair"
'(a b)
(syntax-case '(a . b) ()
((x . y) #'(x y))))
(test "syntax-case var"
'a
(syntax-case '(a . b) (b)
((b . y) #f)
((x . b) #'x)))
(test "syntax-case simple ellipsis"
'(a b c)
(syntax-case '(a b c) ()
((a ...) #'(a ...))))
(test "syntax-case ellipsis with tail"
'(a b x c)
(syntax-case '(a b c) ()
((a ... b) #'(a ... x b))))
(test "syntax-case ellipsis with dotted tail"
'(a b x c y d)
(syntax-case '(a b c . d) ()
((a ... b . c) #'(a ... x b y c))))
(test "syntax-case nested ellipsis"
'((a b) (d e) c f)
(syntax-case '((a b c) (d e f)) ()
(((x ... y) ...) #'((x ...) ... y ...))))
(test-end))))

301
lib/chibi/syntax-case.scm Normal file
View file

@ -0,0 +1,301 @@
;; Written by Marc Nieper-Wißkirchen
;; TODO: make-variable-transformer and identifier-syntax.
;; TODO: make-synthetic-identifier should return a truly unique (that
;; is not free-identifier=? to any other) identifier.
;; TODO: Consecutive ellipses in syntax templates.
;; TODO: Write many more tests.
(define-syntax define-pattern-variable
(er-macro-transformer
(lambda (expr rename compare)
(let ((id (cadr expr))
(binding (cddr expr)))
(let ((mac (cdr (env-cell (current-usage-environment) id))))
(macro-aux-set! mac binding))
`(,(rename 'begin))))))
(define (make-pattern-variable pvar)
(lambda (expr)
(error "reference to pattern variable outside syntax" pvar)))
(define (pattern-variable x)
(let ((cell (env-cell (current-usage-environment) x)))
(and cell (macro? (cdr cell)) (macro-aux (cdr cell)))))
(define (rename id)
((current-renamer) id))
(define (ellipsis? id)
(free-identifier=? id (rename '...)))
(define bound-identifier=?
(lambda (x y)
(eq? x y)))
(define (syntax-transformer level)
(er-macro-transformer
(lambda (expr rename compare)
(let*-values (((out envs)
(gen-template (cadr expr) '() ellipsis? level)))
out))))
(define (syntax->datum stx)
(strip-syntactic-closures stx))
(define-syntax syntax (syntax-transformer #f))
(define-syntax quasisyntax (syntax-transformer 0))
(define-auxiliary-syntax unsyntax)
(define-auxiliary-syntax unsyntax-splicing)
(define (gen-template tmpl envs ell? level)
(cond
((pair? tmpl)
(cond
((and (identifier? (car tmpl))
(free-identifier=? (car tmpl) (rename 'unsyntax)))
(if (and level (zero? level))
(values (cadr tmpl) envs)
(let*-values (((out envs) (gen-template (cadr tmpl) envs ell? (and level (- level 1)))))
(values `(,(rename 'list) ,(gen-data (car tmpl)) ,out) envs))))
((and (identifier? (car tmpl))
(free-identifier=? (car tmpl) (rename 'quasisyntax)))
(let*-values (((out envs) (gen-template (cadr tmpl) envs ell? (and level (+ level 1)))))
(values `(,(rename 'list) ,(gen-data (car tmpl)) ,out) envs)))
((and (pair? (car tmpl))
(free-identifier=? (caar tmpl) (rename 'unsyntax)))
(if (and level (zero? level))
(let*-values (((out envs) (gen-template (cdr tmpl) envs ell? level)))
(values `(,(rename 'cons*) ,@(cdar tmpl) ,out) envs))
(let*-values (((out1 envs) (gen-template (cdar tmpl) envs ell? (and level (- level 1))))
((out2 envs) (gen-template (cdr tmpl) envs ell? level)))
(values `(,(rename 'cons) (,(rename 'cons) ,(gen-data (caar tmpl)) ,out1)
,out2) envs))))
((and (pair? (car tmpl))
(free-identifier=? (caar tmpl) (rename 'unsyntax-splicing)))
(if (and level (zero? level))
(let*-values (((out envs) (gen-template (cdr tmpl) envs ell? level)))
(values `(,(rename 'append) ,@(cdar tmpl) ,out) envs))
(let*-values (((out1 envs) (gen-template (cdar tmpl) envs ell? (and level (- level 1))))
((out2 envs) (gen-template (cdr tmpl) envs ell? level)))
(values `(,(rename 'cons) (,(rename 'cons) ,(gen-data (caar tmpl)) ,out1)
,out2) envs))))
((and (identifier? (car tmpl))
(ell? (car tmpl)))
(gen-template (cadr tmpl) envs (lambda (id) #f) level))
((and (pair? (cdr tmpl))
(identifier? (cadr tmpl))
(ell? (cadr tmpl)))
(let*-values (((out* envs)
(gen-template (cddr tmpl) envs ell? level))
((out envs)
(gen-template (car tmpl) (cons '() envs) ell? level)))
(if (null? (car envs))
(error "too many ellipses following syntax template" (car tmpl)))
(values `(,(rename 'fold-right) (,(rename 'lambda) (,@(car envs) ,(rename 'stx))
(,(rename 'cons) ,out ,(rename 'stx)))
,out* ,@(car envs))
(cdr envs))))
(else
(let*-values (((out1 envs)
(gen-template (car tmpl) envs ell? level))
((out2 envs)
(gen-template (cdr tmpl) envs ell? level)))
(values `(,(rename 'cons) ,out1 ,out2) envs)))))
((vector? tmpl)
(let*-values (((out envs)
(gen-template (vector->list tmpl) envs ell? level)))
(values `(,(rename 'list->vector) ,out) envs)))
((identifier? tmpl)
(cond ((ell? tmpl)
(error "misplaced ellipsis in syntax template" tmpl))
((pattern-variable tmpl) =>
(lambda (binding)
(values (car binding)
(update-envs tmpl (car binding) (cadr binding) envs))))
(else
(values (gen-data tmpl) envs))))
(else
(values `(,(rename 'quote) ,tmpl) envs))))
(define (gen-data id)
`((,(rename 'current-renamer))
(,(rename 'syntax-quote) ,id)))
(define (update-envs id x level envs)
(let loop ((level level) (envs envs))
(cond ((zero? level)
envs)
((null? envs)
(error "too few ellipses following syntax template" id))
(else
(let ((outer-envs (loop (- level 1) (cdr envs))))
(cond ((member x (car envs) bound-identifier=?)
envs)
(else
(cons (cons x (car envs))
outer-envs))))))))
(define-syntax syntax-case
(er-macro-transformer
(lambda (expr rename compare)
(let ((expr (cadr expr))
(lit* (car (cddr expr)))
(clause* (reverse (cdr (cddr expr))))
(error #'(error "syntax error" e)))
#`(let ((e #,expr))
#,(if (null? clause*)
error
#`(let ((fail (lambda () #,error)))
#,(let loop ((clause (car clause*))
(clause* (cdr clause*)))
(if (null? clause*)
(gen-clause lit* clause)
#`(let ((fail (lambda ()
#,(gen-clause lit* clause))))
#,(loop (car clause*) (cdr clause*))))))))))))
(define (gen-clause lit* clause)
(if (= 3 (length clause))
(gen-output lit* (car clause) (cadr clause) (car (cddr clause)))
(gen-output lit* (car clause) #t (cadr clause))))
(define (gen-output lit* pattern fender output-expr)
(let*-values (((matcher vars)
(gen-matcher #'e lit* pattern '())))
(matcher (lambda ()
#`(let-syntax #,(map (lambda (var)
#`(#,(car var)
(make-pattern-variable (syntax-quote #,(car var)))))
vars)
#,@(map (lambda (var)
#`(define-pattern-variable . #,var))
vars)
(if #,fender
#,output-expr
(fail)))))))
(define (gen-matcher e lit* pattern vars)
(cond ((pair? pattern)
(cond
((and (pair? (cdr pattern))
(identifier? (cadr pattern))
(ellipsis? (cadr pattern)))
(let* ((l (length+ (cddr pattern)))
(h (car (generate-temporaries '(#f))))
(t (car (generate-temporaries '(#f)))))
(let*-values (((head-matcher vars) (gen-map h lit* (car pattern) vars))
((tail-matcher vars) (gen-matcher* t lit* (cddr pattern) vars)))
(values (lambda (k)
#`(let ((n (length+ #,e)))
(if (and n (>= n #,l))
(let*-values (((#,h #,t) (split-at #,e (- n #,l))))
#,(head-matcher (lambda ()
(tail-matcher k))))
(fail))))
vars))))
(else
(let ((e1 (car (generate-temporaries '(#f))))
(e2 (car (generate-temporaries '(#f)))))
(let*-values (((car-matcher vars)
(gen-matcher e1 lit* (car pattern) vars))
((cdr-matcher vars)
(gen-matcher e2 lit* (cdr pattern) vars)))
(values (lambda (k)
#`(if (pair? #,e)
(let ((#,e1 (car #,e))
(#,e2 (cdr #,e)))
#,(car-matcher (lambda ()
(cdr-matcher k))))
(fail)))
vars))))))
((identifier? pattern)
(cond ((member pattern lit* free-identifier=?)
(values (lambda (k)
#`(if (free-identifier=? #'#,pattern #,e)
#,(k)
(fail)))
vars))
((ellipsis? pattern)
(error "misplaced ellipsis" pattern))
((free-identifier=? pattern #'_)
(values (lambda (k)
(k))
vars))
(else
(values (lambda (k)
(k))
(alist-cons pattern (list e 0) vars)))))
(else
(values (lambda (k)
#`(if (equal? (syntax->datum #,e) '#,pattern)
#,(k)
(fail)))
vars))))
(define (gen-map h lit* pattern vars)
(let*-values (((matcher inner-vars) (gen-matcher #'g lit* pattern '())))
(let ((loop (car (generate-temporaries '(#f))))
(g* (generate-temporaries inner-vars)))
(values (lambda (k)
#`(let #,loop ((#,h (reverse #,h))
#,@(map (lambda (g)
#`(#,g '()))
g*))
(if (null? #,h)
#,(k)
(let ((g (car #,h)))
#,(matcher (lambda ()
#`(#,loop (cdr #,h)
#,@(map (lambda (var g)
#`(cons #,(cadr var) #,g))
inner-vars g*))))))))
(fold (lambda (g var vars)
(alist-cons (car var) (list g (+ (cadr (cdr var)) 1)) vars))
vars g* inner-vars)))))
(define (gen-matcher* e lit* pattern* vars)
(let loop ((e e) (pattern* pattern*) (vars vars))
(cond ((null? pattern*)
(values (lambda (k)
#`(if (null? #,e)
#,(k)
(fail)))
vars))
((pair? pattern*)
(let ((e1 (car (generate-temporaries '(#f))))
(e2 (car (generate-temporaries '(#f)))))
(let*-values (((car-matcher vars)
(gen-matcher e1 lit* (car pattern*) vars))
((cdr-matcher vars)
(loop e2 (cdr pattern*) vars)))
(values (lambda (k)
#`(let ((#,e1 (car #,e))
(#,e2 (cdr #,e)))
#,(car-matcher (lambda ()
(cdr-matcher k)))))
vars))))
(else
(gen-matcher e lit* pattern* vars)))))
(define (make-synthetic-identifier id)
(close-syntax id (environment)))
(define (generate-temporaries l)
(map (lambda (x) (make-synthetic-identifier 't)) l))
(define-syntax with-syntax
(lambda (x)
(syntax-case x ()
((_ ((p e0) ...) e1 e2 ...)
#'(syntax-case (list e0 ...) ()
((p ...) (let () e1 e2 ...)))))))
(define (syntax-violation who message . form*)
(apply error message form*))
;; TODO: Move datum->syntax from init-7 here.

11
lib/chibi/syntax-case.sld Normal file
View file

@ -0,0 +1,11 @@
(define-library (chibi syntax-case)
(export ... _ free-identifier=? bound-identifier=? identifier?
syntax-case syntax quasisyntax unsyntax unsyntax-splicing
datum->syntax syntax->datum
generate-temporaries with-syntax syntax-violation)
(import (chibi)
(chibi ast)
(meta)
(srfi 1)
(srfi 11))
(include "syntax-case.scm"))

View file

@ -98,20 +98,15 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; syntax
(define sc-macro-transformer
(lambda (f)
(lambda (expr use-env mac-env)
(make-syntactic-closure mac-env '() (f expr use-env)))))
(current-renamer (lambda (x) x))
(define rsc-macro-transformer
(lambda (f)
(lambda (expr use-env mac-env)
(f expr mac-env))))
(define close-syntax
(lambda (form env)
(make-syntactic-closure env '() form)))
(define er-macro-transformer
(lambda (f)
(lambda (expr use-env mac-env)
((lambda (rename compare) (f expr rename compare))
(define make-renamer
(lambda (mac-env)
(define rename
((lambda (renames)
(lambda (identifier)
((lambda (cell)
@ -120,10 +115,61 @@
((lambda (name)
(set! renames (cons (cons identifier name) renames))
name)
(make-syntactic-closure mac-env '() identifier))))
((lambda (id)
(syntactic-closure-set-rename! id rename)
id)
(close-syntax identifier mac-env)))))
(assq identifier renames))))
'())
(lambda (x y) (identifier=? use-env x use-env y))))))
'()))
rename))
(define make-transformer
(lambda (transformer)
(lambda (expr use-env mac-env)
((lambda (old-use-env old-mac-env old-renamer)
(current-usage-environment use-env)
(current-transformer-environment mac-env)
(current-renamer (make-renamer mac-env))
((lambda (result)
(current-usage-environment old-use-env)
(current-transformer-environment old-mac-env)
(current-renamer old-renamer)
result)
(transformer expr)))
(current-usage-environment)
(current-transformer-environment)
(current-renamer)))))
(%define-syntax define-syntax
(lambda (expr use-env mac-env)
(list (close-syntax '%define-syntax mac-env)
(cadr expr)
(list (close-syntax 'make-transformer mac-env)
(car (cddr expr))))))
(define free-identifier=?
(lambda (x y)
((lambda (use-env cur-env)
(identifier=? (if use-env use-env cur-env) x
(if use-env use-env cur-env) y))
(current-usage-environment)
(current-environment))))
(define sc-macro-transformer
(lambda (f)
(lambda (expr)
(close-syntax (f expr (current-usage-environment))
(current-transformer-environment)))))
(define rsc-macro-transformer
(lambda (f)
(lambda (expr)
(f expr (current-transformer-environment)))))
(define er-macro-transformer
(lambda (f)
(lambda (expr)
(f expr (current-renamer) free-identifier=?))))
(define-syntax cond
(er-macro-transformer
@ -929,6 +975,45 @@
(lambda (expr rename compare)
(syntax-rules-transformer expr rename compare))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; let(rec)-syntax and datum->syntax
(define-syntax let-syntax
(syntax-rules ()
((let-syntax ((keyword transformer) ...) . body)
(%let-syntax ((keyword (make-transformer transformer)) ...) . body))))
(define-syntax letrec-syntax
(syntax-rules ()
((letrec-syntax ((keyword transformer) ...) . body)
(%letrec-syntax ((keyword (make-transformer transformer)) ...) . body))))
(define (symbol->identifier id symbol)
(cond
((symbol? id)
symbol)
((syntactic-closure-rename id)
=> (lambda (renamer)
(renamer symbol)))
(else
symbol)))
;; TODO: Handle cycles in datum.
(define (datum->syntax id datum)
(let loop ((datum datum))
(cond ((pair? datum)
(cons (loop (car datum))
(loop (cdr datum))))
((vector? datum)
(do ((res (make-vector (vector-length datum)))
(i 0 (+ i 1)))
((= i (vector-length datum)) res)
(vector-set! res i (loop (vector-ref datum i)))))
((symbol? datum)
(symbol->identifier id datum))
(else
datum))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; additional syntax

View file

@ -223,8 +223,8 @@
(module-env-set! mod (eval-module name mod)))
mod))
(define-syntax meta-begin begin)
(define-syntax meta-define define)
(%define-syntax meta-begin begin)
(%define-syntax meta-define define)
(define define-library-transformer
(er-macro-transformer

View file

@ -4,7 +4,7 @@
(for-each set-cdr! (car (cddr expr)) (cadr (cddr expr)))
(car (cdr expr)))))
(define-syntax syntax-parameterize
(%define-syntax syntax-parameterize
(lambda (expr use-env mac-env)
(let* ((_let (make-syntactic-closure mac-env '() 'let))
(_set! (make-syntactic-closure mac-env '() 'set!))
@ -21,7 +21,9 @@
(old (map cdr cells))
(new (map (lambda (transformer)
(make-macro
(eval (make-syntactic-closure use-env '() transformer))
(make-transformer
(eval
(make-syntactic-closure use-env '() transformer)))
use-env))
transformers)))
(for-each set-cdr! cells new)

View file

@ -370,6 +370,11 @@
((#\() (list->vector (read-one in)))
((#\') (read-char in) (list 'syntax (read-one in)))
((#\`) (read-char in) (list 'quasisyntax (read-one in)))
((#\,) (read-char in)
(let ((sym (if (eqv? #\@ (peek-char in))
(begin (read-char in) 'unsyntax-splicing)
'unsyntax)))
(list sym (read-one in))))
((#\t) (let ((s (read-name #f in)))
(or (string-ci=? s "t") (string-ci=? s "true")
(read-error "bad # syntax" s))))

View file

@ -10,11 +10,13 @@
(procs (cddr expr))
(make (car procs))
(make-name (if (eq? make #t)
(string->symbol (string-append "make-" name-str))
(datum->syntax name
(string->symbol (string-append "make-" name-str)))
(if (pair? make) (car make) make)))
(pred (cadr procs))
(pred-name (if (eq? pred #t)
(string->symbol (string-append name-str "?"))
(datum->syntax name
(string->symbol (string-append name-str "?")))
pred))
(fields (cddr procs))
(field-names (map (lambda (x) (if (pair? x) (car x) x)) fields))

View file

@ -1,5 +1,5 @@
(define-library (srfi 99 records syntactic)
(export define-record-type)
(import (chibi) (srfi 99 records inspection))
(import (chibi) (chibi syntax-case) (srfi 99 records inspection))
(include "syntactic.scm"))

View file

@ -110,6 +110,18 @@
(test 'mixed (breed-of felix))
(test '(and black white) (color-of felix))
;;; See issue #494.
(test-assert
(let-syntax
((foo
(syntax-rules ()
((foo)
(let ()
(define-record-type record
#t
#t)
(record? (make-record)))))))
(foo)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(let ()

View file

@ -38,6 +38,9 @@ _PARAM("current-output-port", _I(SEXP_OPORT)),
_PARAM("current-error-port", _I(SEXP_OPORT)),
_PARAM("current-exception-handler", _I(SEXP_PROCEDURE)),
_PARAM("interaction-environment", _I(SEXP_ENV)),
_PARAM("current-usage-environment", _I(SEXP_ENV)),
_PARAM("current-transformer-environment", _I(SEXP_ENV)),
_PARAM("current-renamer", _I(SEXP_PROCEDURE)),
_PARAM("command-line", SEXP_NULL),
_OP(SEXP_OPC_GETTER, SEXP_OP_CAR, 1, 0, _I(SEXP_OBJECT), _I(SEXP_PAIR), SEXP_FALSE, SEXP_FALSE, 0, "car", 0, NULL),
_OP(SEXP_OPC_SETTER, SEXP_OP_SET_CAR, 2, 0, SEXP_VOID, _I(SEXP_PAIR), _I(SEXP_OBJECT), SEXP_FALSE, 0, "set-car!", 0, NULL),
@ -45,6 +48,8 @@ _OP(SEXP_OPC_GETTER, SEXP_OP_CDR, 1, 0, _I(SEXP_OBJECT), _I(SEXP_PAIR), SEXP_FAL
_OP(SEXP_OPC_SETTER, SEXP_OP_SET_CDR, 2, 0, SEXP_VOID, _I(SEXP_PAIR), _I(SEXP_OBJECT), SEXP_FALSE, 0, "set-cdr!", 0, NULL),
_GETTER("pair-source", SEXP_PAIR, 2),
_SETTER("pair-source-set!", SEXP_PAIR, 2),
_GETTER("syntactic-closure-rename", SEXP_SYNCLO, 3),
_SETTER("syntactic-closure-set-rename!", SEXP_SYNCLO, 3),
_OP(SEXP_OPC_GETTER, SEXP_OP_VECTOR_REF, 2, 0, _I(SEXP_OBJECT), _I(SEXP_VECTOR), _I(SEXP_FIXNUM), SEXP_FALSE, 0, "vector-ref", 0, NULL),
_OP(SEXP_OPC_SETTER, SEXP_OP_VECTOR_SET, 3, 0, SEXP_VOID, _I(SEXP_VECTOR), _I(SEXP_FIXNUM), _I(SEXP_OBJECT), 0, "vector-set!", 0, NULL),
_OP(SEXP_OPC_GETTER, SEXP_OP_VECTOR_LENGTH, 1, 0, _I(SEXP_FIXNUM), _I(SEXP_VECTOR), SEXP_FALSE, SEXP_FALSE, 0, "vector-length", 0, NULL),

32
sexp.c
View file

@ -217,8 +217,8 @@ static struct sexp_type_struct _sexp_type_specs[] = {
{SEXP_FILENO, 0, 0, 0, 0, 0, sexp_sizeof(fileno), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"File-Descriptor", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, SEXP_FINALIZE_FILENON, SEXP_FINALIZE_FILENO},
{SEXP_EXCEPTION, sexp_offsetof(exception, kind), 5, 5, 0, 0, sexp_sizeof(exception), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Exception", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, NULL},
{SEXP_PROCEDURE, sexp_offsetof(procedure, bc), 2, 2, 0, 0, sexp_sizeof(procedure), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Procedure", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, NULL},
{SEXP_MACRO, sexp_offsetof(macro, proc), 3, 3, 0, 0, sexp_sizeof(macro), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Macro", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, NULL},
{SEXP_SYNCLO, sexp_offsetof(synclo, env), 3, 3, 0, 0, sexp_sizeof(synclo), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Sc", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, NULL},
{SEXP_MACRO, sexp_offsetof(macro, proc), 4, 4, 0, 0, sexp_sizeof(macro), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Macro", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, NULL},
{SEXP_SYNCLO, sexp_offsetof(synclo, env), 4, 4, 0, 0, sexp_sizeof(synclo), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Sc", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, NULL},
{SEXP_ENV, sexp_offsetof(env, parent), 3+SEXP_USE_RENAME_BINDINGS, 3+SEXP_USE_RENAME_BINDINGS, 0, 0, sexp_sizeof(env), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Environment", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, NULL},
{SEXP_BYTECODE, sexp_offsetof(bytecode, name), 3, 3, 0, 0, sexp_sizeof(bytecode), offsetof(struct sexp_struct, value.bytecode.length), 1, 0, 0, 0, 0, 0, 0, (sexp)"Bytecode", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, NULL},
{SEXP_CORE, sexp_offsetof(core, name), 1, 1, 0, 0, sexp_sizeof(core), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Core-Form", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, NULL},
@ -465,6 +465,10 @@ void sexp_init_context_globals (sexp ctx) {
sexp_global(ctx, SEXP_G_QUASIQUOTE_SYMBOL) = sexp_intern(ctx, "quasiquote", -1);
sexp_global(ctx, SEXP_G_UNQUOTE_SYMBOL) = sexp_intern(ctx, "unquote", -1);
sexp_global(ctx, SEXP_G_UNQUOTE_SPLICING_SYMBOL) = sexp_intern(ctx, "unquote-splicing", -1);
sexp_global(ctx, SEXP_G_SYNTAX_SYMBOL) = sexp_intern(ctx, "syntax", -1);
sexp_global(ctx, SEXP_G_QUASISYNTAX_SYMBOL) = sexp_intern(ctx, "quasisyntax", -1);
sexp_global(ctx, SEXP_G_UNSYNTAX_SYMBOL) = sexp_intern(ctx, "unsyntax", -1);
sexp_global(ctx, SEXP_G_UNSYNTAX_SPLICING_SYMBOL) = sexp_intern(ctx, "unsyntax-splicing", -1);
sexp_global(ctx, SEXP_G_CUR_IN_SYMBOL) = sexp_intern(ctx, "current-input-port", -1);
sexp_global(ctx, SEXP_G_CUR_OUT_SYMBOL) = sexp_intern(ctx, "current-output-port", -1);
sexp_global(ctx, SEXP_G_CUR_ERR_SYMBOL) = sexp_intern(ctx, "current-error-port", -1);
@ -2093,6 +2097,8 @@ sexp sexp_write_one (sexp ctx, sexp obj, sexp out) {
sexp_write(ctx, sexp_make_fixnum(obj), out);
sexp_write_char(ctx, ' ', out);
sexp_write(ctx, sexp_synclo_expr(obj), out);
sexp_write_char(ctx, ' ', out);
sexp_write(ctx, sexp_synclo_rename(obj), out);
sexp_write_char(ctx, '>', out);
break;
default:
@ -3168,6 +3174,28 @@ sexp sexp_read_raw (sexp ctx, sexp in, sexp *shares) {
res = sexp_list_to_vector(ctx, res);
}
break;
case '\'':
res = sexp_read_one(ctx, in, shares);
if (! sexp_exceptionp(res))
res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_SYNTAX_SYMBOL), res);
break;
case '`':
res = sexp_read_one(ctx, in, shares);
if (! sexp_exceptionp(res))
res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_QUASISYNTAX_SYMBOL), res);
break;
case ',':
if ((c1 = sexp_read_char(ctx, in)) == '@') {
res = sexp_read_one(ctx, in, shares);
if (! sexp_exceptionp(res))
res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_UNSYNTAX_SPLICING_SYMBOL), res);
} else {
sexp_push_char(ctx, c1, in);
res = sexp_read_one(ctx, in, shares);
if (! sexp_exceptionp(res))
res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_UNSYNTAX_SYMBOL), res);
}
break;
default:
res = sexp_read_error(ctx, "invalid char following '#'",
c1 == EOF ? SEXP_EOF : sexp_make_character(c1), in);

View file

@ -53,6 +53,7 @@
(rename (chibi show-test) (run-tests run-show-tests))
(rename (chibi show c-test) (run-tests run-show-c-tests))
(rename (chibi string-test) (run-tests run-string-tests))
(rename (chibi syntax-case-test) (run-tests run-syntax-case-tests))
(rename (chibi system-test) (run-tests run-system-tests))
(rename (chibi tar-test) (run-tests run-tar-tests))
;;(rename (chibi term ansi-test) (run-tests run-term-ansi-tests))
@ -109,6 +110,7 @@
(run-rsa-tests)
(run-scribble-tests)
(run-string-tests)
(run-syntax-case-tests)
(run-sha2-tests)
(run-show-tests)
(run-show-c-tests)