#lang scheme/base ;; This contains the base language for macros. It implements: ;; * partial evaluation ;; * bindings to code compilation (labels) ;; * basic Forth control macros (provide (all-defined-out)) (require scheme/match "../tools.ss" "../scat.ss" "pattern.ss" "macro-utils.ss" "macro-prim.ss" "macro-syntax.ss" "macro-eval.ss" "core.ss" ;; compile + literal "../target.ss" "target-scat.ss" ;; target: "../asm/dictionary.ss" ) ;; TOOLS ;; To enable macros to reference instantiated runtime library words, ;; the convention is used to create stub words that start with ;; tilde. These can then be overridden by instantiated code words, or ;; throw an error if instantiated before that. (define (undefined-stub name) (make-word (lambda _ (error 'undefined-stub "~a" name)))) (define-syntax-rule (declare-stubs name ...) (begin (define-ns (macro) name (undefined-stub 'name)) ...)) (declare-stubs ~run) ;; Universal list -> macro convertor: each element is quoted and ;; posprocessed with a glue macro. This can be used to construct ;; tables or simple embedded point-free languages. (define (list->macro glue lst) (scat-compose (map (lambda (el) (macro: ',el ,glue)) lst))) ;; For use in the (? fn) pattern matcher. This creates a curried ;; function which lifts all its arguments to normal values. (define (target fn . vs) (lambda (v) (target-value-catch-undefined (lambda () (apply fn (map target-value-eval (cons v vs))))))) ;; Convert a wrapper macro to the word instance, leave other types ;; intact. NOTE: it might be best to restrict this to 'address' only, ;; because ticked words (macros) are really different from addresses. (define (unwrap macro) (if (word? macro) (let ((word (macro->data macro 'cw))) (tscat: word)) macro)) (define macro-word? word?) ;; LOWLEVEL MACROS. (patterns (macro) ;; Transfer of Scat semantics to Coma (postponed) semantics. (([qw a] dup) ([qw a] [qw a])) (([qw a] drop) ()) (([qw a] not) ([qw (not a)])) (([qw a] [qw b] swap) ([qw b] [qw a])) (([qw a] [qw b] +) ([qw (tscat: a b +)])) (([dw a] dw>) ([qw a])) ;; Will be redefined when data word size != program word size. The ;; convention is to use the data word size as unit. (([qw a] |,|) ([dw a])) (([qw x] |string,|) (list->macro (macro: |,|) ;; glue (let ((l (->byte-list x))) (cons (length l) l)))) ;; DELAYED CODE (([qw ma] [qw mb] compose) ([qw (macro: ,ma ,mb)])) (([qw label] jump) ([jw label])) ;; Get the address from the macro that wraps a postponed ;; word. Perform the macro->data part immediately (as a type check ;; for the macro). Postpone the address evaluation, since it is only ;; available during assembly. (([qw a] address) ([qw (unwrap a)])) ;; The basic behaviour is 'run, which will invoke a quoted macro, or ;; will delegate a call to the run-time word. (([qw (? macro-word? w)] run) w) ((run) (macro: ~run)) ;; 'execute has a lower level semantics: it operates on quoted ;; numbers/labels instead, and will not execute macros. (([qw label] execute) ([cw label])) ((execute) (macro: ~run)) ;; 'compile will operate on both macros and labels, but won't ;; delegate to run-time. (([qw (? target-word? w)] compile) ([cw w])) (([qw (? macro-word? w)] compile) w) ;; WORD CREATION ((save) ([save])) ;; This has a bit of an awkward syntax due its generality. The ;; 'asm-transformers' syntax serves the greater good of the pattern ;; matching assemblers (one level of quoting).. ; (([,rator . rands] opcode) ; (list `([,rator ,@rands] [qw ,rator]))) ;; If a macro is found in the macro dictionary, run the macro, else ;; pass the name to another macro. This is used in VM -> native ;; forth mapping. ;; (([qw word-name] [qw default-semantics-name] macro/default) ;; ((insert ;; (if (macro-find/false word-name) ;; `(,(macro-prim: '(word-name) :macro run/s)) ;; `([qw ,word-name] ;; ,(macro-prim: '(default-semantics-name) :macro run/s)))))) ;; Quoted parser backends. (([qw thing] |*'|) ([qw thing])) ;; RAM ;; (([qw realm] [qw n] allot) ([allot realm n])) (([qw n] allot) ([allot-data n])) ((here) ([here])) ;; Dictionary lookup. ;; (([qw tag] [qw dict] dict-find) ([qw (dict-find dict tag)])) ;; Name mangling. (([qw method] [qw class] [qw dash] prefix) ([qw (string->symbol (format "~a~a~a" class dash method))])) ) ;; HIGLEVEL MACROS (compositions (macro) macro: ;; Namespaces (pc ' |.| prefix compile) ;; method object -- ) ;; Asm ops used in this module. These all needs to be substituted or ;; implemented by the target assembler. (ir-ops (save) (stub) (dw value) (jw word) (cw word) (qw value)) (check-opcodes asm-find)