#lang scheme/base (require scheme/list) (require (file "utilities.scm")) (require (file "primitives.scm")) (provide write-rla-value current-indent current-indent-step verbose-rla?) (define current-indent (make-parameter 0)) (define current-indent-step (make-parameter 2)) (define verbose-rla? (make-parameter #f)) (define hex-digits "0123456789abcdef") (define (hard-new-line port) (write-char #\Newline port) (for ([i (in-range 0 (current-indent))]) (write-char #\Space port))) (define (req-new-line port) (if (verbose-rla?) (hard-new-line port) (write-char #\Space port))) (define (opt-new-line port) (when (verbose-rla?) (hard-new-line port))) (define (write-hex-char ord port) (write-string "\\x" port) (write-char (string-ref hex-digits (quotient ord 16)) port) (write-char (string-ref hex-digits (remainder ord 16)) port)) (define (write-hex-byte ord port) (write-string "0x" port) (write-char (string-ref hex-digits (quotient ord 16)) port) (write-char (string-ref hex-digits (remainder ord 16)) port)) (define (write-rla-string value port) (write-char #\" port) (for ([ch (in-string value)]) (cond [(and (eq? ch #\")) (write-string "\\\"" port)] [(and (< (char->integer ch) 128) (char-graphic? ch)) (write-char ch port)] [else (write-hex-char (char->integer ch) port)])) (write-char #\" port)) (define (write-instance-string inst-vars port) (write-string "#@\"" port) (for ([var (in-list inst-vars)]) (write-hex-char (variable->code var) port)) (write-char #\" port)) (define (write-rla-bytecode+tail-call forms port) (define (write-tail-call tc-form) (req-new-line port) (write-string "#@\"" port) (for ([var (in-list (cdr tc-form))]) (write-hex-char (variable->code var) port)) (write-char #\" port) (when (verbose-rla?) (write-char #\; port) (for ([var (in-list (cdr tc-form))]) (write-char #\Space port) (write var port)))) (let-values ([(line col pos) (port-next-location port)]) (parameterize ([current-indent col]) (write-string "#@\"" port) (if (eq? (first (first forms)) '#%tail-call) (begin (write-char #\" port) (write-tail-call (first forms))) (let iter ([forms forms]) (map (lambda (x) (write-hex-char x port)) (statement->code (car forms))) (if (eq? (first (second forms)) '#%tail-call) (begin (if (verbose-rla?) (begin (write-string "\"; " port) (write (car forms) port)) (write-char #\" port)) (write-tail-call (second forms))) (begin (when (verbose-rla?) (write-string "\\; " port) (write (car forms) port) (hard-new-line port) (write-char #\Space port)) (iter (cdr forms))))))))) (define (write-rla-function value port) (define template? (eq? (first value) '#%template)) (let-values ([(line col pos) (port-next-location port)]) (parameterize ([current-indent col]) (write-string "#@#S(" port) (if (eq? (first value) '#%template) (write-string "#=\"template\"" port) (write-string "#=\"lambda\"" port)) (parameterize ([current-indent (+ (current-indent-step) (current-indent))]) (req-new-line port) (write-string "#@#(" port) (unless (null? (second value)) (parameterize ([current-indent (+ (current-indent-step) (current-indent))]) (opt-new-line port) (write-rla-value (first (second value)) port) (for ([global (in-list (cdr (second value)))]) (req-new-line port) (write-rla-value global port))) (opt-new-line port)) (write-string ")" port) (req-new-line port) (if template? (write-instance-string (third value) port) (begin (write-string "#@#(" port) (unless (null? (third value)) (parameterize ([current-indent (+ (current-indent-step) (current-indent))]) (opt-new-line port) (write-rla-value (first (third value)) port) (for ([instance (in-list (cdr (third value)))]) (req-new-line port) (write-rla-value instance port))) (opt-new-line port)) (write-string ")" port))) (req-new-line port) (write-rla-value (length (second (fourth value))) port) (req-new-line port) (write-rla-bytecode+tail-call (cddr (fourth value)) port)) (opt-new-line port)) (write-string ")" port))) (define (write-rla-value value [port (current-output-port)]) (port-count-lines! port) (void (cond [(eq? value '#%undef) (write-string "#=\"undefined\"" port)] [(symbol? value) (write-string "#=\"" port) (write-string (symbol->string value) port) (write-string "\"" port)] [(or (boolean? value) (number? value)) (write value port)] [(char? value) (write (char->integer value) port)] [(string? value) (write-rla-string value port)] [(and (pair? value) (memq (car value) '(#%lambda #%template))) (write-rla-function value port)] [(vector? value) (write-string "#(" port) (unless (zero? (vector-length value)) (write-rla-value (vector-ref value 0) port)) (for ([i (in-range 1 (vector-length value))]) (write-rla-value (vector-ref value i) port) (write-char #\Space port)) (write-string ")" port)] [(null? value) (write-string "()" port)] [(pair? value) (write-string "(" port) (let iter ([lst value]) (write-rla-value (car lst) port) (cond [(null? (cdr lst)) (write-string ")" port)] [(pair? (cdr lst)) (write-char #\Space port) (iter (cdr lst))] [else (write-string " . " port) (write-rla-value (cdr lst)) (write-string ")" port)]))] [else (error "Don't know how to write Rosella syntax for:" value)]))) (define (variable->code var) (or (and (eq? var '#%nil) #x00) (let ([index (find var global-variables)]) (and index (+ #x01 index))) (let ([index (find var instance-variables)]) (and index (+ #x40 index))) (let ([index (find var frame-variables)]) (and index (+ #x80 index))) (let ([index (find var '(#%self #%argv #%kw-args #%kw-vals #%ctx #%k))]) (and index (+ #xfa index))) (error "No bytecode for variable:" var))) (define (statement->code form) (if (eq? (first form) '#%set!) (let ([out (variable->code (second form))] [value (third form)]) (cond [(machine-variable? value) (list #x00 out #x01 (variable->code value))] [(eq? (length (cdr value)) 1) (let ([item (assoc (first value) unary-value-primitives)]) (unless item (error "Invalid unary value primitive:" value)) (list #x00 out (second item) (variable->code (second value))))] [(eq? (length (cdr value)) 2) (let ([item (assoc (first value) binary-value-primitives)]) (unless item (error "Invalid binary value primitive:" value)) (list* (second item) out (map variable->code (cdr value))))] [else (unless (and (eq? (first value) '#%if) (eq? (length (cdr value)) 3)) (error "Invalid ternary primitive:" form)) (list* out (map variable->code (cdr value)))])) (case (length (cdr form)) [(1) (let ([item (assoc (first form) unary-statement-primitives)]) (unless item (error "Invalid unary statement primitive:" form)) (list (second item) (variable->code (second form)) #x00 #x00))] [(2) (let ([item (assoc (first form) binary-statement-primitives)]) (unless item (error "Invalid binary statement primitive:" form)) (list (second item) (variable->code (second form)) (variable->code (third form)) #x00))] [(3) (let ([item (assoc (first form) ternary-statement-primitives)]) (unless item (error "Invalid ternary statement primitive:" form)) (list (second item) (variable->code (second form)) (variable->code (third form)) (variable->code (fourth form))))] [else (error "Unsupported form:" form)]))) ; vim:set sw=2 expandtab: