trying to get records up....WIP

This commit is contained in:
Jan Nieuwenhuizen 2016-07-23 14:39:33 +02:00
parent f61a6c2228
commit 5126e16e66
7 changed files with 293 additions and 235 deletions

View file

@ -33,16 +33,39 @@ mes.h: mes.c GNUmakefile
check: all check: all
./mes.test ./mes.test
./mes.test ./mes ./mes.test ./mes
cat scm.mes test.mes | ./mes cat scm.mes lib/srfi/srfi-0.scm test.mes | ./mes
run: all run: all
cat scm.mes test.mes | ./mes cat scm.mes test.mes | ./mes
syntax: all psyntax: all
cat scm.mes syntax.mes | ./mes cat scm.mes psyntax.mes psyntax.pp psyntax2.mes | ./mes
guile-syntax: syntax: all
guile -s syntax.mes cat scm.mes syntax.mes syntax-test.mes | ./mes
syntax.test: syntax.mes syntax-test.mes
cat $^ > $@
guile-syntax: syntax.test
guile -s $^
macro: all macro: all
cat scm.mes macro.mes | ./mes cat scm.mes macro.mes | ./mes
peg: all
cat scm.mes syntax.mes peg.mes peg/codegen.scm peg/string-peg.scm peg/simplify-tree.scm peg/using-parsers.scm peg/cache.scm peg-test.mes | ./mes
peg.test: peg/pmatch.scm peg.mes peg/codegen.scm peg/string-peg.scm peg/simplify-tree.scm peg/using-parsers.scm peg/cache.scm peg-test.mes
cat $^ | sed 's,\(;; Packages the results of a parser\),(when (guile?) (set! compile-peg-pattern (@@ (ice-9 peg codegen) compile-peg-pattern)))\n\1,' > $@
guile-peg: peg.test
# guile -s peg-test.mes
# @echo "======================================="
guile -s $^
clean:
rm -f mes environment.i mes.h peg.test syntax.test
record: all
cat scm.mes syntax.mes lib/record.mes lib/record.scm lib/srfi/srfi-9.scm record.mes |./mes

13
TODO
View file

@ -19,6 +19,19 @@ See bugs/
**** syntax-case **** syntax-case
** parse C using PEG ** parse C using PEG
http://piumarta.com/software/peg/ http://piumarta.com/software/peg/
** C grammar in lex/yacc
https://github.com/rabishah/Mini-C-Compiler-using-Flex-And-Yacc
https://www.lysator.liu.se/c/ANSI-C-grammar-y.html
http://www2.cs.uidaho.edu/~jeffery/courses/nmsu/370/cgram.y
https://github.com/ProgramLeague/C-Compilerp
*** parsing in scheme
ftp://ftp.cs.indiana.edu/pub/scheme-repository/code/lang/cgram-ll1
** Tiny C
https://en.wikipedia.org/wiki/Tiny_C_Compiler
** Sub C
http://www.t3x.org/subc/index.html
**
https://groups.google.com/forum/#!topic/comp.lang.lisp/VPuX0VsjTTE
** implement core primitives: DONE ** implement core primitives: DONE
begin begin
define define

View file

@ -1,96 +1,203 @@
; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
; Copyright (c) 1993-2004 by Richard Kelsey and Jonathan Rees. See file COPYING. ; Copyright (c) 1993-2004 by Richard Kelsey and Jonathan Rees. See file COPYING.
; This is file record.scm.
;;;; Records ;;;; Records
; This is completely vanilla Scheme code. Should work anywhere. ; Every record in the image is assumed to be made either by MAKE-RECORD-TYPE
; or by a procedure returned by record-constructor. A record-type is a
; record that describes a type of record. At the end of the file we create
; a record type that describes record types.
(define (make-record-type type-id field-names) ; We number the record types for debugging purposes.
(define unique (list type-id)) (define *record-type-uid* -1)
(define size (+ (length field-names) 1)) ; This is the record type that describes record types. It is set a the end
; of the file. Its first slot points to itself.
(define (constructor . names-option) (define *record-type* #f)
(let* ((names (if (null? names-option)
field-names
(car names-option)))
(number-of-inits (length names))
(indexes (map field-index names)))
(lambda field-values
(if (= (length field-values) number-of-inits)
(let ((record (make-vector size 'uninitialized)))
(vector-set! record 0 unique)
(for-each (lambda (index value)
(vector-set! record index value))
indexes
field-values)
record)
(error "wrong number of arguments to record constructor"
field-values type-id names)))))
(define (predicate obj) ; Make a record type from a name, used for printing and debugging, and
(and (vector? obj) ; a list of field names.
(= (vector-length obj) size) ;
(eq? (vector-ref obj 0) unique))) ; The VM references both the record type and the resumer, so their offsets
; should not be changed.
(define (accessor name) (define (make-record-type name field-names)
(let ((i (field-index name))) (set! *record-type-uid* (+ *record-type-uid* 1))
(lambda (record) (let ((r (make-record 7 (unspecific))))
(if (predicate record) ;Faster: (eq? (vector-ref record 0) unique) (record-set! r 0 *record-type*)
(vector-ref record i) (record-set! r 1 default-record-resumer)
(error "invalid argument to record accessor" (record-set! r 2 *record-type-uid*)
record type-id name))))) (record-set! r 3 name)
(record-set! r 4 field-names)
(record-set! r 5 (length field-names))
(record-set! r 6 (make-default-record-discloser name))
r))
(define (modifier name) (define (record-type? obj)
(let ((i (field-index name))) (and (record? obj)
(lambda (record new-value) (eq? (record-type obj) *record-type*)))
(if (predicate record) ;Faster: (eq? (vector-ref record 0) unique)
(vector-set! record i new-value)
(error "invalid argument to record modifier"
record type-id name)))))
(define (field-index name) ; The various fields in a record type.
(let loop ((l field-names) (i 1))
(if (null? l)
(error "bad field name" name)
(if (eq? name (car l))
i
(loop (cdr l) (+ i 1))))))
(define the-descriptor (define (record-type-resumer rt) (record-ref rt 1))
(lambda (request) (define (set-record-type-resumer! rt r) (record-set! rt 1 r))
(case request (define (record-type-uid rt) (record-ref rt 2))
((constructor) constructor) (define (record-type-name rt) (record-ref rt 3))
((predicate) predicate) (define (record-type-field-names rt) (record-ref rt 4))
((accessor) accessor) (define (record-type-number-of-fields rt) (record-ref rt 5))
((modifier) modifier) (define (record-type-discloser rt) (record-ref rt 6))
((name) type-id) (define (set-record-type-discloser! rt d) (record-set! rt 6 d))
((field-names) field-names))))
the-descriptor) ; This is a hack; it is read by the script that makes c/scheme48.h.
(define (record-constructor r-t . names-option) (define record-type-fields
(apply (r-t 'constructor) names-option)) '(resumer uid name field-names number-of-fields discloser))
(define (record-predicate r-t) ;----------------
(r-t 'predicate)) ; Given a record type and the name of a field, return the field's index.
(define (record-accessor r-t field-name) (define (record-field-index rt name)
((r-t 'accessor) field-name)) (let loop ((names (record-type-field-names rt))
(i 1))
(cond ((null? names)
(error "unknown field"
(record-type-name rt)
name))
((eq? name (car names))
i)
(else
(loop (cdr names) (+ i 1))))))
(define (record-modifier r-t field-name) ; Return procedure for contstruction records of type RT. NAMES is a list of
((r-t 'modifier) field-name)) ; field names which the constructor will take as arguments. Other fields are
; uninitialized.
(define (record-type-name r-t) (r-t 'name)) (define (record-constructor rt names)
(define (record-type-field-names r-t) (r-t 'field-names)) (let ((indexes (map (lambda (name)
(record-field-index rt name))
names))
(size (+ 1 (record-type-number-of-fields rt))))
(lambda args
(let ((r (make-record size (unspecific))))
(record-set! r 0 rt)
(let loop ((is indexes) (as args))
(if (null? as)
(if (null? is)
r
(error "too few arguments to record constructor"
rt names args))
(if (null? is)
(error "too many arguments to record constructor"
rt names args)
(begin (record-set! r (car is) (car as))
(loop (cdr is) (cdr as))))))))))
(define (record-type? r-t) ; Making accessors, modifiers, and predicates for record types.
(and (procedure? r-t)
(error "record-type? not implemented" r-t))) (define (record-accessor rt name)
(let ((index (record-field-index rt name))
(error-cruft `(record-accessor ,rt ',name)))
(lambda (r)
(if (eq? (record-type r) rt)
(record-ref r index)
(call-error "invalid record access" error-cruft r)))))
(define (record-modifier rt name)
(let ((index (record-field-index rt name))
(error-cruft `(record-modifier ,rt ',name)))
(lambda (r x)
(if (eq? (record-type r) rt)
(record-set! r index x)
(call-error "invalid record modification" error-cruft r x)))))
(define (record-predicate rt)
(lambda (x)
(and (record? x)
(eq? (record-type x) rt))))
;----------------
; A discloser is a procedure that takes a record of a particular type and
; returns a list whose head is a string or symbol and whose tail is other
; stuff.
;
; Set the discloser for record type RT.
(define (define-record-discloser rt proc)
(if (and (record-type? rt)
(procedure? proc))
(set-record-type-discloser! rt proc)
(call-error "invalid argument" define-record-discloser rt proc)))
; By default we just return the name of the record type.
(define (make-default-record-discloser record-type-name)
(lambda (r)
(list record-type-name)))
; DISCLOSE-RECORD calls the record's discloser procedure to obtain a list.
(define (disclose-record r)
(if (record? r)
(let ((rt (record-type r)))
(if (record-type? rt)
((record-type-discloser rt) r)
#f))
#f))
;----------------
; A resumer is a procedure that the VM calls on all records of a given
; type on startup.
;
; A resumer may be:
; #t -> do nothing on startup.
; #f -> records of this type do not survive a dump/resume; in images they
; are replaced by their first slot (so we make sure they have one)
; a one-argument procedure -> pass the record to this procedure
;
; Resumers are primarily intended for use by external code which keeps
; fields in records which do not survive a dump under their own power.
; For example, a record may contain a reference to a OS-dependent value.
;
; Resumers are called by the VM on startup.
(define (define-record-resumer rt resumer)
(if (and (record-type? rt)
(or (eq? #t resumer)
(and (eq? #f resumer)
(< 0 (record-type-number-of-fields rt)))
(procedure? resumer)))
(set-record-type-resumer! rt resumer)
(call-error "invalid argument" define-record-resumer rt resumer)))
; By default we leave records alone.
(define default-record-resumer
#t)
(define (initialize-records! resumer-records)
(if (vector? resumer-records)
(do ((i 0 (+ i 1)))
((= i (vector-length resumer-records)))
(resume-record (vector-ref resumer-records i)))))
(define (resume-record record)
((record-type-resumer (record-type record))
record))
;----------------
; Initializing *RECORD-TYPE* and making a type.
(set! *record-type*
(make-record-type 'record-type record-type-fields))
(record-set! *record-type* 0 *record-type*)
(define :record-type *record-type*)
(define-record-discloser :record-type
(lambda (rt)
(list 'record-type
(record-type-uid rt)
(record-type-name rt))))
(define (define-record-discloser r-t proc)
"ignoring define-record-discloser form")

View file

@ -1,160 +1,44 @@
; Copyright (c) 1993-2004 by Richard Kelsey and Jonathan Rees. See file COPYING. ;; Copyright (c) 1993 by Richard Kelsey and Jonathan Rees. See file COPYING.
;; There's no implicit name concatenation, so it can be defined
;; entirely using syntax-rules. Example:
;; (define-record-type foo type/foo
;; (make-foo x y)
;; foo? - predicate name is optional
;; (x foo-x)
;; (y foo-y)
;; (z foo-z set-foo-z!))
; This knows about the implementation of records and creates the various ;; Copyright (c) 1993-2004 by Richard Kelsey and Jonathan Rees. See file COPYING.
; accessors, mutators, etc. directly instead of calling the procedures
; from the record structure. This is done to allow the optional auto-inlining
; optimizer to inline the accessors, mutators, etc.
; LOOPHOLE is used to get a little compile-time type checking (in addition to
; the usual complete run-time checking).
(define-syntax define-record-type (define-syntax define-record-type
(syntax-rules () (syntax-rules ()
((define-record-type ?id ?type ((define-record-type id type
(?constructor ?arg ...) (constructor arg ...)
(?field . ?field-stuff) (field . field-stuff)
...) ...)
(begin (define ?type (make-record-type '?id '(?field ...))) (begin (define type (make-record-type 'id '(field ...)))
(define-constructor ?constructor ?type (define constructor (record-constructor type '(arg ...)))
((?arg :value) ...) (define-accessors type (field . field-stuff) ...)))
(?field ...)) ((define-record-type id type
(define-accessors ?type () (?field . ?field-stuff) ...))) (constructor arg ...)
((define-record-type ?id ?type pred
(?constructor ?arg ...) more ...)
?pred (begin (define-record-type id type
?more ...) (constructor arg ...)
(begin (define-record-type ?id ?type more ...)
(?constructor ?arg ...) (define pred (record-predicate type))))))
?more ...)
(define ?pred
(lambda (x)
(and (record? x)
(eq? ?type (record-ref x 0)))))))))
(define-syntax define-synchronized-record-type
(syntax-rules ()
((define-synchronized-record-type ?id ?type
(?constructor ?arg ...)
?pred
(?field . ?field-stuff)
...)
(define-synchronized-record-type ?id ?type
(?constructor ?arg ...)
(?field ...)
?pred
(?field . ?field-stuff)
...))
((define-synchronized-record-type ?id ?type
(?constructor ?arg ...)
(?sync-field ...)
?pred
(?field . ?field-stuff)
...)
(begin (define ?type (make-record-type '?id '(?field ...)))
(define-constructor ?constructor ?type
((?arg :value) ...)
(?field ...))
(define ?pred
(lambda (x)
(and (record? x)
(eq? ?type (record-ref x 0)))))
(define-accessors ?type (?sync-field ...)
(?field . ?field-stuff) ...)))))
; (define-constructor <id> <type> ((<arg> <arg-type>)*) (<field-name>*))
;
; Checks to see that there is an <arg> corresponding to every <field-name>.
(define-syntax define-constructor
(lambda (e r c)
(let ((%record (r 'record))
(%begin (r 'begin))
(%lambda (r 'lambda))
(%loophole (r 'loophole))
(%proc (r 'proc))
(%unspecific (r 'unspecific))
(name (cadr e))
(type (caddr e))
(args (map r (map car (cadddr e))))
(arg-types (map cadr (cadddr e)))
(fields (map r (caddr (cddr e)))))
(define (mem? name list)
(cond ((null? list) #f)
((c name (car list)) #t)
(else
(mem? name (cdr list)))))
(define (every? pred list)
(cond ((null? list) #t)
((pred (car list))
(every? pred (cdr list)))
(else #f)))
(if (every? (lambda (arg)
(mem? arg fields))
args)
`(define ,name
(,%loophole (,%proc ,arg-types ,type)
(,%lambda ,args
(,%record ,type . ,(map (lambda (field)
(if (mem? field args)
field
(list %unspecific)))
fields)))))
e)))
(record begin lambda loophole proc unspecific))
;; Straightforward version
(define-syntax define-accessors (define-syntax define-accessors
(lambda (e r c) (syntax-rules ()
(let ((%define-accessor (r 'define-accessor)) ((define-accessors type field-spec ...)
(%begin (r 'begin)) (begin (define-accessor type . field-spec) ...))))
(type (cadr e))
(sync-fields (caddr e))
(field-specs (cdddr e)))
(define (mem? name list)
(cond ((null? list) #f)
((c name (car list)) #t)
(else
(mem? name (cdr list)))))
(do ((i 1 (+ i 1))
(field-specs field-specs (cdr field-specs))
(ds '()
(cons `(,%define-accessor
,(mem? (caar field-specs)
sync-fields)
,type ,i ,@(cdar field-specs))
ds)))
((null? field-specs)
`(,%begin ,@ds)))))
(define-accessor begin))
(define-syntax define-accessor (define-syntax define-accessor
(syntax-rules () (syntax-rules ()
((define-accessor ?sync? ?type ?index ?accessor) ((define-accessor type field accessor)
(define ?accessor (define accessor (record-accessor type 'field)))
(loophole (proc (?type) :value) ((define-accessor type field accessor modifier)
(lambda (r) (begin (define accessor (record-accessor type 'field))
((ref-proc ?sync?) (loophole :record r) ?type ?index))))) (define modifier (record-modifier type 'field))))))
((define-accessor ?sync? ?type ?index ?accessor ?modifier)
(begin (define-accessor ?sync? ?type ?index ?accessor)
(define ?modifier
(loophole (proc (?type :value) :unspecific)
(lambda (r new)
((set-proc ?sync?)
(loophole :record r) ?type ?index new))))))
((define-accessor ?sync? ?type ?index)
(begin))))
(define-syntax ref-proc
(syntax-rules ()
((ref-proc #t)
provisional-checked-record-ref)
((ref-proc #f)
checked-record-ref)))
(define-syntax set-proc
(syntax-rules ()
((set-proc #t)
provisional-checked-record-set!)
((set-proc #f)
checked-record-set!)))

31
mes.c
View file

@ -342,6 +342,17 @@ eval (scm *e, scm *a)
scm *entry = assq (name, a); scm *entry = assq (name, a);
scm *x = cdar (defines); scm *x = cdar (defines);
set_cdr_x (entry, cdr (define (x, a))); set_cdr_x (entry, cdr (define (x, a)));
if (eq_p (car (x), &symbol_define_macro) == &scm_t)
// HACK: macros are global
// should we go back to (*macro* . ...) entry?
// scm *last = last_pair (a);
// printf ("\n LAST=");
// display (last);
// puts ("");
set_cdr_x (last_pair (a), cons (cons (name, cdr (define (x, a))), &scm_nil));
// printf ("a=");
// display (a);
// puts ("");
defines = cdr (defines); defines = cdr (defines);
} }
scm *fubar = cons (&scm_dot, &scm_dot); scm *fubar = cons (&scm_dot, &scm_dot);
@ -361,6 +372,8 @@ eval (scm *e, scm *a)
return eval_quasiquote (cadr (e), add_unquoters (a)); return eval_quasiquote (cadr (e), add_unquoters (a));
if (car (e) == &symbol_cond) if (car (e) == &symbol_cond)
return evcon (cdr (e), a); return evcon (cdr (e), a);
if (eq_p (car (e), &symbol_define) == &scm_t)
return define (e, a);
if (eq_p (car (e), &symbol_define_macro) == &scm_t) if (eq_p (car (e), &symbol_define_macro) == &scm_t)
return define (e, a); return define (e, a);
if ((macro = lookup_macro (car (e), a)) != &scm_f) if ((macro = lookup_macro (car (e), a)) != &scm_f)
@ -606,6 +619,16 @@ length (scm *x)
return make_number (n); return make_number (n);
} }
scm *
last_pair (scm *x)
{
//if (x != &scm_nil && cdr (x) != &scm_nil)
//return last_pair (cdr (x));
while (x != &scm_nil && cdr (x) != &scm_nil)
x = cdr (x);
return x;
}
scm * scm *
builtin_list (scm *x/*...*/) builtin_list (scm *x/*...*/)
{ {
@ -833,9 +856,9 @@ display_helper (scm *x, bool cont, char *sep, bool quote)
if (!cont) printf (")"); if (!cont) printf (")");
} }
else if (x->type == VECTOR) { else if (x->type == VECTOR) {
printf ("#("); printf ("#[%d](", x->length);
for (int i = 0; i < x->length; i++) // for (int i = 0; i < x->length; i++)
display_helper (x->vector[i], true, i ? " " : "", false); // display_helper (x->vector[i], true, i ? " " : "", false);
printf (")"); printf (")");
} }
else if (atom_p (x) == &scm_t) printf ("%s", x->name); else if (atom_p (x) == &scm_t) printf ("%s", x->name);
@ -1112,6 +1135,8 @@ mes_environment ()
a = cons (cons (&scm_nil, &scm_nil), a); a = cons (cons (&scm_nil, &scm_nil), a);
a = cons (cons (&scm_t, &scm_t), a); a = cons (cons (&scm_t, &scm_t), a);
a = cons (cons (&scm_unspecified, &scm_unspecified), a); a = cons (cons (&scm_unspecified, &scm_unspecified), a);
a = cons (cons (&symbol_begin, &symbol_begin), a);
a = cons (cons (&symbol_quote, &scm_quote), a);
#include "environment.i" #include "environment.i"

View file

@ -94,6 +94,11 @@
(#t (eq? a b)))) (#t (eq? a b))))
(define (vector . rest) (list->vector rest)) (define (vector . rest) (list->vector rest))
(define (make-vector n . x)
(let ((fill (if (pair? x) (cdr x) *unspecified*)))
(list->vector (let loop ((n n))
(if (= 0 n) '()
(cons fill (loop (- n 1))))))))
(define (apply f args) (define (apply f args)
(eval (cons f args) (current-module))) (eval (cons f args) (current-module)))
@ -204,3 +209,6 @@
(let loop ((lst lst)) (let loop ((lst lst))
(if (or (null? lst) (null? (cdr lst))) lst (if (or (null? lst) (null? (cdr lst))) lst
(loop (cdr lst))))) (loop (cdr lst)))))
(define else #t)
(define (unspecific) (if #f #f))

View file

@ -4,7 +4,7 @@
(display "syntax-error:") (display "syntax-error:")
(display message) (display message)
(display ":") (display ":")
;;(display thing) (display thing)
(newline)) (newline))
;;; Adapted from scheme48-1.1/scheme/alt/syntax.scm ;;; Adapted from scheme48-1.1/scheme/alt/syntax.scm
@ -246,5 +246,3 @@
`(define-syntax ,(car id-pattern) `(define-syntax ,(car id-pattern)
(syntax-rules () (syntax-rules ()
((,(car id-pattern) . ,(cdr id-pattern)) ,@template)))) ((,(car id-pattern) . ,(cdr id-pattern)) ,@template))))
(define else #t)