#lang scheme/base
(provide
forth-tx
macro-tx
:-tx
:forth-tx
:macro-tx
create-tx
load-tx
path-tx
require-tx
provide-tx
open-paren-tx
close-paren-tx
open-sexp-tx
forth->records
forth-rules
forth-search-path
)
(require
"../tools.ss"
"../tools-tx.ss"
"../scat-tx.ss"
"locals-tx.ss"
"lexer.ss" scheme/control
syntax/stx
scheme/pretty
(for-template
(lib "match.ss")
"../scat.ss"
scheme/base))
(define-sr (forth-rules (literals ...)
((pattern ...) (template ...)) ...)
(lambda (stx expr)
(syntax-case stx (literals ...)
((pattern ... . code+)
((rpn-next) #`(template ... . code+) expr)) ...)))
(define current-mode (make-parameter #f))
(define (forth-mode) 'forth)
(define (macro-mode) 'macro)
(define (variable-mode) 'variable)
(define (mode-tx mode)
(lambda (code expr)
(current-mode (mode))
((finalize-current) expr)
(init-record)
(collect-next (stx-cdr code))))
(define macro-tx (mode-tx macro-mode))
(define forth-tx (mode-tx forth-mode))
(define (temp sym)
(car (generate-temporaries (list sym))))
(define (stx-srcloc stx)
#`(list #,(syntax-source stx)
#,(syntax-line stx)
#,(syntax-column stx)
#,(syntax-position stx)
#,(syntax-span stx)))
(define forth-search-path (make-parameter '()))
(define (new-record name mode loc)
(finalize-current
(lambda (expr)
(register-record
#`(#,name #,mode #,loc
#,(rpn-close-expression expr)))
(finalize-current no-record))))
(define (no-record expr) (error 'no-current-record))
(define finalize-current (make-parameter no-record))
(define (collect-next code)
((rpn-next) code (rpn-state)))
(define (definer mode)
(lambda (code expr)
((finalize-current) expr)
(syntax-case code ()
((_ name . code+)
(new-record #'name
(mode)
(stx-srcloc #'name))
(collect-next #'code+)))))
(define :-tx (definer current-mode))
(define create-tx (definer variable-mode))
(define :macro-tx (definer macro-mode))
(define :forth-tx (definer forth-mode))
(define forth-toplevel-forms (make-parameter '()))
(define forth-records (make-parameter '()))
(define (register-toplevel x)
(forth-toplevel-forms
(cons x (forth-toplevel-forms))))
(define (register-record x)
(forth-records
(cons x (forth-records))))
(define (forth->records forth-definitions)
(parameterize
((current-mode (forth-mode))
(forth-records '())
(forth-toplevel-forms '()))
(rpn-init (lambda ()
(init-record)
(let-values
(((_ last) (collect-next forth-definitions)))
((finalize-current) last))
(let ((records (reverse (forth-records))))
(cons
`(#f scheme #f (begin ,@(reverse (forth-toplevel-forms))))
records))))))
(define (init-record [mode current-mode])
(new-record #f (mode) #f))
(define abort/cc abort-current-continuation)
(define (make-until tag)
(lambda (code expr)
(abort/cc tag
(lambda ()
(values (stx-cdr code) expr)))))
(define (next-until tag code expr)
(prompt-at tag
((rpn-next) code expr)
(error 'non-terminated-parser-nesting "~a" tag)))
(define code-quotation
(make-continuation-prompt-tag 'code-quotation))
(define (open-paren-tx code exp)
(let-values
(((code+ body)
(next-until code-quotation
(stx-cdr code) (rpn-state))))
((rpn-next)
code+
((rpn-immediate)
(rpn-close-expression body)
exp))))
(define close-paren-tx (make-until code-quotation))
(define load-end (make-continuation-prompt-tag 'load))
(define (path-tx code expr)
(syntax-case code ()
((_ path . code+)
(begin
(forth-search-path
(cons (stx->string #'path)
(forth-search-path)))
((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 (load-tx code expr)
(syntax-case code ()
((_ file . code+)
(let* ((rel-file (stx->string #'file))
(abs-file
(resolve-path-list
rel-file
(cons
(let ((dir (current-load-relative-directory)))
(or dir (current-directory)))
(forth-search-path)))))
(call-with-values
(lambda ()
(let-values (((path base _) (split-path abs-file)))
(parameterize
((current-load-relative-directory path))
(next-until
load-end
(append
(file->forth-syntax
#'file abs-file)
(list (make-until load-end))
#'code+)
expr))))
(rpn-next))))))
(define (open-sexp-tx code exp)
(define open (string->symbol "{"))
(define close (string->symbol "}"))
(define (collect stx-list)
(let next ((l '())
(s stx-list))
(cond
((null? s)
(error 'sexp-error))
((eq? open (syntax->datum (car s)))
(let-values
(((list rest) (collect (cdr s))))
(next (cons list l)
rest)))
((eq? close (syntax->datum (car s)))
(values
(reverse l)
(cdr s)))
(else
(next (cons (car s) l)
(cdr s))))))
(let-values (((list code+)
(collect (stx-cdr code))))
(register-toplevel list)
((rpn-next) code+ exp)))
(define (require-tx code expr)
(syntax-case code ()
((_ module . code+)
(register-toplevel
`(require ,(symbol->string
(syntax->datum #'module))))
((rpn-next) #'code+ expr))))
(define (provide-tx code expr)
(syntax-case code ()
((_ name . code+)
(register-toplevel
`(provide ,#'name))
((rpn-next) #'code+ expr))))