(include "common.scm") (module llrb-symbol-tree ( make-binding-set empty-binding-set binding-set-empty? binding-set-ref/default binding-set-ref binding-set-delete binding-set-insert binding-set-update binding-set-cons binding-set-fold binding-set-union ;; make-table table-copy table? table-set! table-delete! table-ref/default table-ref table-update! ) (import scheme) (cond-expand (chicken-4 (import chicken (only data-structures identity))) (else (import (chicken base) (chicken type) (chicken fixnum) (only miscmacros ensure)))) (import llrb-syntax) ;;(include "llrbsyn.scm") (cond-expand (own-struct (define-syntax make-struct (syntax-rules () ((_ args ...) ((##core#primitive "C_make_structureX") args ...))))) (else (define-syntax make-struct (syntax-rules () ((_ args ...) (##sys#make-structure args ...)))))) (cond-expand (unsafe (define-syntax typecheck (syntax-rules () ((_ obj typetag loc) (begin)))) (define-syntax typecheckp (syntax-rules () ((_ obj typepred loc) (begin))))) (else (define-syntax typecheck (syntax-rules () ((_ obj typetag loc) (##sys#check-structure obj typetag loc)))) (define-syntax typecheckp (syntax-rules () ((_ obj typepred loc) (typepred obj)))))) (define-syntax checkbinding-node (syntax-rules () ((_ obj loc) (typecheck obj ' loc)))) (define-inline (make-binding-node color left right key value) (make-struct ' color left right key value)) (define (binding-node? obj) (##sys#structure? obj ')) (define-syntax binding-node-color (syntax-rules () ((_ n) (##sys#slot n 1)))) (define-syntax binding-node-left (syntax-rules () ((_ n) (##sys#slot n 2)))) (define-syntax binding-node-right (syntax-rules () ((_ n) (##sys#slot n 3)))) (define-syntax %binding-node-name (syntax-rules () ((_ n) (##sys#slot n 4)))) (define (binding-node-name n) (checkbinding-node n 'binding-node-name) (%binding-node-name n)) (define-syntax %binding-node-value (syntax-rules () ((_ n) (##sys#slot n 5)))) (define (binding-node-value n) (checkbinding-node n 'binding-node-value) (%binding-node-value n)) (define-syntax %symbol->string (syntax-rules () ((_ s) (##sys#slot s 1) #;(##sys#symbol->string s)))) (define-syntax %string (struct ))) (define (make-binding-set . lst) ; export (if (null? lst) (empty-binding-set) (do ((lst lst (cdr lst)) (set %empty-binding-set (let* ((x (car lst)) (k (%symbol->string (car x)))) (%binding-set-insert set k #f (%make-new-binding-node k (cdr x)) #f)))) ((null? lst) set)))) (define (%binding-set-ref/thunk envt k thunk success) ; internal (let ((entry (binding-set-lookup envt k))) (if entry (if success (success (%binding-node-value entry)) (%binding-node-value entry)) (thunk)))) (define (%binding-set-ref/default envt k default) ; internal (let ((entry (binding-set-lookup envt k))) (if entry (%binding-node-value entry) default))) (: binding-set-ref/default ((struct ) symbol * --> *)) (define (binding-set-ref/default envt k default) ; export (checkbinding-node envt 'binding-set-ref/default) (ensure symbol? k) (%binding-set-ref/default envt (%symbol->string k) default)) (: binding-set-ref ((struct ) symbol &optional (procedure () *) (procedure (*) *) --> *)) (define (binding-set-ref envt k . thunk+success) ; export (checkbinding-node envt 'binding-set-ref) (ensure symbol? k) (%binding-set-ref/thunk envt (%symbol->string k) (if (pair? thunk+success) (car thunk+success) (lambda () (error "binding-set-ref unbound key" k))) (and (pair? thunk+success) (pair? (cdr thunk+success)) (cadr thunk+success)))) (: binding-set-delete (symbol (struct ) --> (struct ))) (define (binding-set-delete k envt) (checkbinding-node envt 'binding-set-delete) (ensure symbol? k) (binding-node-delete envt (%symbol->string k))) ;; setXkeyXvalue (: binding-set-insert ((struct ) symbol * --> (struct ))) (define (binding-set-insert nodeset k v) ; export (checkbinding-node nodeset 'binding-set-insert) (ensure binding-node? nodeset) (ensure symbol? k) (let ((k (%symbol->string k))) (%binding-set-insert nodeset k #f (%make-new-binding-node k v) #f))) (: binding-set-update ((struct ) symbol (procedure (*) *) (procedure () *) --> (struct ))) (define (binding-set-update nodeset k update dflt) ; export (checkbinding-node nodeset 'binding-set-update) (ensure symbol? k) (ensure procedure? update) (ensure procedure? dflt) (let ((k (%symbol->string k))) (%binding-set-insert nodeset k #f (lambda (n) (let ((v (update (binding-node-value n)))) (make-binding-node #f #f #f (%binding-node-name n) v))) (lambda () (%make-new-binding-node k (dflt)))))) ;; srfi-1::alist-cons compatible (: binding-set-cons (symbol * (struct ) --> (struct ))) (define (binding-set-cons k v nodeset) ; export (binding-set-insert nodeset k v)) (: binding-set-fold ((procedure (* *) . *) * (struct ) -> *)) (define (binding-set-fold kvcons nil nodeset) (checkbinding-node nodeset 'binding-set-fold) (ensure procedure? kvcons) (%binding-set-fold (lambda (e i) (kvcons (string->symbol (%binding-node-name e)) (%binding-node-value e) i)) nil nodeset)) ;; setXset (: binding-set-union ((struct ) (struct ) --> (struct ))) (define (binding-set-union inner outer) ; export (checkbinding-node inner 'binding-union) (checkbinding-node outer 'binding-union) (%binding-set-fold (lambda (node init) (%binding-set-insert init (%binding-node-name node) #f node #f)) outer inner)) (define-type :table: (struct )) (define-record-type (%make-symbol-table root) table? (root root root-set!)) (define-syntax check-table (syntax-rules () ((_ obj loc) (typecheckp obj table? loc)))) (: make-table ( --> :table:)) (define (make-table) (%make-symbol-table (empty-binding-set))) (: table-copy (:table: --> :table:)) (define (table-copy table) (check-table table 'symbol-table-copy) (%make-symbol-table (root table))) (: table-delete! (:table: symbol -> *)) (define (table-delete! table key) (check-table table 'symbol-table-delete!) (ensure symbol? key) (root-set! table (binding-node-delete (root table) (%symbol->string key)))) (: table-set! (:table: symbol * -> *)) (define (table-set! table key value) (check-table table 'symbol-table-set!) (ensure symbol? key) (let ((key (%symbol->string key))) (root-set! table (%binding-set-insert (root table) key #f (%make-new-binding-node key value) #f)))) (: table-ref/default (:table: symbol * --> *)) (define (table-ref/default table key default) (check-table table 'symbol-table-ref/default) (ensure symbol? key) (%binding-set-ref/default (root table) (%symbol->string key) default)) (: table-ref (:table: symbol &optional (procedure () *) (procedure (*) *) -> *)) (define (table-ref table key . thunk+success) (check-table table 'symbol-table-ref) (ensure symbol? key) (%binding-set-ref/thunk (root table) (%symbol->string key) (if (pair? thunk+success) (car thunk+success) (lambda () (error "symbol-table-ref unbound key" key))) (and (pair? thunk+success) (pair? (cdr thunk+success)) (cadr thunk+success)))) (: table-update! (:table: symbol procedure &rest procedure -> *)) (define (table-update! table key update . default) (check-table table 'symbol-table-update!) (ensure symbol? key) (ensure procedure? update) (let loop ((key (%symbol->string key)) (old (root table)) (result #f)) (let ((new (%binding-set-insert old key #f (let ((update (or update identity))) (lambda (n) (let ((v (update (binding-node-value n)))) (set! result v) (make-binding-node #f #f #f (%binding-node-name n) v)))) (if (and (pair? default) (procedure? (car default))) (let ((thunk (car default))) (lambda () (%make-new-binding-node key (thunk)))) (lambda () (error "symbol-table-update! no default" default)))))) (if (eq? old (root table)) (begin (root-set! table new) result) (loop key (root table) #f))))) )