#lang scheme/base ;; Generic tools for implementing Forth syntax for macro/target based ;; languages as rpn parser extensions (struct rpn-transformer). (require "../rpn.ss" "../tools.ss") (provide (all-defined-out)) ;; PATH for toplevel (define forth-path (make-parameter '())) ;; PARSER EXTENSIONS ;; Prefix syntax for local variables. (define (make-rpn-locals-transformer locals) (make-rpn-transformer (lambda (w d k) (let next ((w (w-cdr w)) (l '())) (let ((f (w-car w))) (if (eq? '\| (syntax->datum f)) (k (w-cdr w) (d-compile #`(#,locals #,(reverse l)) d)) (next (w-cdr w) (cons f l)))))))) ;; Prefix syntax for definition start. (define (make-rpn-definition-transformer compile) (make-rpn-same-definition-transformer (lambda (d) compile))) ;; Same, but use semantics of last entry. This uses a convenience ;; macro that reads from the input stream and binds pattern names. (define (make-rpn-same-definition-transformer get-compile) (rpn-dict-rule d (name) (let ((compile (get-compile d))) ;; allow inspection of dict (let* ((d (d-start d)) (d (compile #'name d))) d)))) ;; Straight compile of a toplevel expression. This will insert the ;; expression before the one currently being compiled. (define (rpn-compile-toplevel stx d) (d-insert (syntax->list stx) d)) ;; Prefix syntax for scheme s-expressions. (define (make-rpn-sexp-transformer open close compile-sexp) (make-rpn-transformer (lambda (w-in d k) (define (collect w-start) (let next ((w w-start) (l '())) ;; (printf "W: ~a\n" (let ((x (syntax->datum (car w)))) (list x (eq? open x) (eq? close x)))) (when (w-null? w) (raise-syntax-error #f (format "expected '~a', sexp starts" close) (car w-in))) (let ((w-sym (syntax->datum (w-car w))) (w+ (w-cdr w))) (cond ((eq? open w-sym) (let-values (((w-next lst) (collect w+))) (next w-next (cons lst l)))) ((eq? close w-sym) (values w+ (datum->syntax #f (reverse l)))) ;; pack in stx object (else (next w+ (cons (w-car w) l))))))) (let-values (((w-next s) (collect (w-cdr w-in)))) (k w-next (compile-sexp s d)))))) ;; Parameters and dynamic parser state. ;; The Forth parser needs to maintain state while parsing a file. ;; This includes current toplevel forms to be installed and the ;; current "mode". This transformer installs such a dynamic state for ;; the remainder of the parser input. (define (make-rpn-parameterize-transformer param init-state compile-state) (lambda (w d k) (let-values (((d+ k) (parameterize ((param init-state)) (printf "nesting: ~a\n" param) (rpn-parse-nested (w-cdr w) d k)))) (k '() (compile-state (param) d+))))) ;; Prefix syntax for including files. (define (make-rpn-include-transformer file->syntax filename-syntax->string current-search-path [logger void]) (make-rpn-transformer (lambda (w d k) ;; (printf "path: ~a\n" (current-search-path)) (let ((filename-stx (w-cadr w)) (w-rest (w-cddr w))) (let* ([filename (filename-syntax->string filename-stx)] [search-path (cons (let ((dir (current-load-relative-directory))) (or dir (current-directory))) (current-search-path))] [resolved-filename (resolve-path-list filename search-path)] [path (filename->path resolved-filename)]) (let-values (((d+ k) ;; Recursively invoke the parser on the loaded syntax ;; list in a nested dynamic environment. (parameterize ((current-load-relative-directory path)) (logger resolved-filename) (rpn-parse-nested (file->syntax resolved-filename filename-stx) d k)))) ;; Continue in the original dynamic environment. (k w-rest d+))))))) ;; When dictionary forms expand to forms that might introduce syntax ;; bindings, recursive expansion is necessary to postpone further ;; parsing until the defining forms are processed. (define (make-rpn-expand-transformer begin-stx-thunk) (make-rpn-transformer (lambda (w d k) (k '() (rpn-compile-toplevel #`(#,@(begin-stx-thunk) ;; might include dynamic context #,@(w-cdr w)) d))))) ;; Convert a syntax expression for a header into a compiler used in ;; the forms above. (define (rpn-make-header->compile make-header) (lambda (n d) (foldl d-compile d (syntax->list (make-header n))))) (define (make-rpn-forth-definition-transformer make-header) (make-rpn-definition-transformer (rpn-make-header->compile make-header))) (define rpn-curly-brace-transformer (make-rpn-sexp-transformer (string->symbol "{") (string->symbol "}") rpn-compile-toplevel)) ;; TOPLEVEL (define (make-rpn-path-transformer stx->path) (make-rpn-transformer (lambda (w d k) (parameterize ((forth-path (cons (stx->path (w-cadr w)) (forth-path)))) ;; Run until done parsing inside dynamic env. (k (w-cddr w) d))))) ;; TODO (from parser-tx.ss) ;; TOPLEVEL EXPRESSIONS ;; (define (require-tx code expr) ;; (define (p x) (symbol->string (syntax->datum x))) ;; (define (next e c) ;; (register-toplevel e) ;; ((rpn-next) c expr)) ;; (syntax-case code (planet staapl) ;; ((_ planet module . code+) (next `(require (planet ,(p #'module))) #'code+)) ;; ((_ staapl module . code+) (next `(require (planet ,(p #'module) ("zwizwa" "staapl.plt"))) #'code+)) ;; ((_ module . code+) (next `(require ,(p #'module))) #'code+) ;; )) ;; (define (provide-tx code expr) ;; (syntax-case code () ;; ((_ name . code+) ;; (register-toplevel ;; `(provide ,#'name)) ;; ((rpn-next) #'code+ expr)))) ;; ;; Ignore #lang constructs ;; (define (lang-tx code expr) ;; (syntax-case code (planet) ;; ((_ planet path . code+) ((rpn-next) #'code+ expr)) ;; ((_ path . code+) ((rpn-next) #'code+ expr)))) ;; (define (stx->string stx) ;; (let ((sym/str (syntax->datum stx))) ;; (cond ;; ((symbol? sym/str) (symbol->string sym/str)) ;; ((path? sym/str) (path->string sym/str)) ;; ((string? sym/str) sym/str) ;; (else (error 'stx->string))))) ;; (define (path-tx code expr) ;; (define (add-path s-p code+ [pre #f]) ;; (let ((p (stx->string s-p))) ;; (forth-search-path ;; (cons (if pre (simplify-path (build-path pre p)) p) ;; (forth-search-path))) ;; ((rpn-next) code+ expr))) ;; (syntax-case code (staapl) ;; ((_ staapl path . code+) (add-path #'path #'code+ staapl-dir)) ;; ((_ path . code+) (add-path #'path #'code+)) ;; )) ;; (define (stx-srcloc stx) ;; #`(quote (#,(syntax-source stx) ;; #,(syntax-line stx) ;; #,(syntax-column stx) ;; #,(syntax-position stx) ;; #,(syntax-span stx))))