;; Lexical variables in rpn code. ;; All rpn syntax expanders capture lexical variables. This mechanism ;; can be used to create rpn code with named arguments, following the ;; subsitution: ;; ;; (a b | a b +) -> ;; ;; (lambda (b a . s) ;; (let ((a (constant a)) ;; wrap them with the right behaviour ;; (b (constant b))) ;; (apply (base: a b +) s))) ;; ;; Instead of using 'constant' to transform the semantics from ;; function to constant, the code could use the built-in constant ;; quoting mechanism. However, that requires manual subsitutition. (module macro-lambda-tx mzscheme (require "list-utils.ss" "tx-utils.ss" "rep.ss" "stream.ss" "stx-stream.ss" (lib "match.ss")) (require-for-template mzscheme (lib "match.ss") ;; "rpn-runtime.ss" "rep.ss" ) (provide macro-lambda-tx) ;; For macros, there's a particular semantics for lexical variables: ;; they refer to quoted words in the assembly stack. ;; FORTH SOURCE: ;; : foo | a b | a b + ; ;; ;; INTERMEDIATE: ;; ((a b) (a b +)) ;; ( ) ;; ;; EXPANDS TO: ;; (match stack ;; (((('qw b) ('qw a) . rasm) . rstack) ;; (let ((a (literal a)) ;; (b (literal b))) ;; (apply (macro: a b +) ;; (cons rasm rstack))))) ;; Please note that the 'source' syntax is DIFFERENT from the normal ;; concatenative syntax! This hack is here to be able to use ;; 'rpn-compile' to compile code at run time, even if it's not ;; strictly concatenative code. (define (macro-lambda-tx compile: compile-lex: source) (define (formals->qw fs) (reverse (map (lambda (f) #`('qw #,f)) fs))) (define (formals->lit fs) (map (lambda (f) #`(#,f (#,compile: '#,f))) fs)) (syntax-case source () (((formals ...) (pure-source ...)) (let ((formals-lst (syntax->list #'(formals ...)))) #`(make-word '#,compile-lex: '#,source (match-lambda* (((#,@(formals->qw formals-lst) . rasm) . rstack) (let #,(formals->lit formals-lst) (apply (#,compile: pure-source ...) (cons rasm rstack)))))))))) )