#lang scheme/base
(require "parse.ss"
"../ns.ss"
"parse-tx.ss"
(for-syntax "../tools.ss"
"parse-tx.ss"
scheme/base))
(provide
(all-defined-out)
(all-from-out "parse.ss")
(all-from-out "parse-tx.ss"))
(define-syntax (rpn-lambda stx)
(syntax-case stx ()
((_ . txs)
#`(lambda (p)
#,(foldr (lambda (compile expr)
(append (syntax->list compile)
(list #'p expr)))
#'p (syntax->list #'txs))))))
(define-syntax rpn:-compile
(syntax-rules ()
((_ (compile code ...)) (compile code ...))))
(define-syntax-rule (prefix-parsers namespace ((name arg ...) template) ...)
(ns namespace
(define-syntaxes (name ...)
(values (rpn-syntax-rules () ((_ arg ...) template)) ...))))
(define-syntax-rule (primitive-prefix-parsers ns lang: (pat code) ...)
(begin
(prefix-parsers ns (pat (,(lang: . code))) ...)))
(define-syntax (rpn-lex stx)
(syntax-case stx ()
((_ compile str)
(let ((words
(port->syntax-list
(open-input-string (syntax->datum #'str)) stx)))
#`(compile #,@words)))))
(define-syntax (rpn-let-locals stx)
(syntax-case stx ()
((_ (namespace
program:
pop-values)
(formal ...) p sub)
(let ((flist (syntax->list #'(formal ...))))
#`(let-values (((p formal ...) (pop-values p #,(length flist))))
(ns namespace
(let ((formal (program: ',formal)) ...)
sub)))))))
(define (rpn-take-reversed n lst)
(let _take ((n n)
(in lst)
(out '()))
(if (or (zero? n)
(null? lst))
(values out in)
(_take (sub1 n)
(cdr in)
(cons (car in) out)))))
(define (rpn-wrap-dynamic fn)
(lambda stack
(define (go n stack [optional '()])
(let-values (((args stack+) (rpn-take-reversed n stack)))
(append
(call-with-values (lambda () (apply fn (append args optional))) list)
stack+)))
(let ((n (procedure-arity fn)))
(cond
((arity-at-least? n)
(go (arity-at-least-value n) (cdr stack) (car stack)))
((number? n) (go n stack))
(else (error 'hell-froze-over))))))
(define-syntax (rpn-wrap-static stx)
(syntax-case stx ()
((_ nargs fn)
(let ((formals
(generate-temporaries
(build-list (syntax->datum #'nargs) add1))))
#`(lambda (#,@(reverse formals) . stack)
(cons (fn #,@formals) stack))))))
(define (rpn-wrap: . fns)
(lambda stack
(foldl apply
stack
(map rpn-wrap-dynamic fns))))