;; -*- Mode: Irken -*- (include "self/lisp_reader.scm") ;; --- s-expression input --- (define (find-and-read-file path) (raise (:NoIncludeFiles)) ) (define (file/read-line file) (let loop ((ch (file/read-char file)) (r '())) (if (eq? ch #\newline) (list->string (reverse r)) (loop (file/read-char file) (list:cons ch r))))) (define (ask prompt file) (printf prompt) (flush) (file/read-line file)) ;; --- universal datatype --- ;; ;; this datatype covers all the types known by the interpreter. ;; (datatype univ (:int int) (:char char) (:string string) (:bool bool) (:symbol symbol) (:undef) (:list (list univ)) ;; (:function ...) ) ;; how to print out a universal value (define univ-repr (univ:int n) -> (format (int n)) (univ:char n) -> (format (char n)) (univ:string s) -> (format (string s)) (univ:bool b) -> (format (bool b)) (univ:symbol s) -> (format (sym s)) (univ:undef) -> "#u" (univ:list subs) -> (format "(" (join univ-repr " " subs) ")") ) ;; flat variable namespace. ;; I'm using a balanced binary tree here, but this will need ;; to be replaced by a 'rib' data structure to support function application. ;; the keys are symbols, the values are a record type containing a single ;; field named 'val', of type 'univ'. (define namespace (tree/empty)) (define (varref name) (match (tree/member namespace symbol val (maybe:no) -> (begin (printf "undefined variable: '" (sym name) "'\n") (univ:undef)) )) (define (varset name val) (match (tree/member namespace symbol (begin (set! cell.val val) (univ:undef)) (maybe:no) -> (let ((cell {val=val})) (tree/insert! namespace symbol (let ((a (eval arg0)) (b (eval arg1))) (match a b with (univ:int a) (univ:int b) -> (univ:int (+ a b)) _ _ -> (eval-error (format "bad args: " (univ-repr a) " " (univ-repr b))) )) prim _ -> (eval-error (format "unknown prim: " (sym prim))) ) ;; top-level eval function (define eval ;; self-evaluating expressions (sexp:int n) -> (univ:int n) (sexp:char ch) -> (univ:char ch) (sexp:string s) -> (univ:string s) (sexp:bool b) -> (univ:bool b) (sexp:undef) -> (univ:undef) ;; variable lookup (sexp:symbol s) -> (varref s) ;; variable assignment (sexp:list ((sexp:symbol 'set!) (sexp:symbol name) val)) -> (varset name (eval val)) ;; application (sexp:list ((sexp:symbol rator) . rands)) -> (if (starts-with (symbol->string rator) "%") (eval-prim rator rands) (eval-error "application NYI")) ;; anything else... exp -> (eval-error (format "bad/unknown expression: " (repr exp))) ) (define (setup-initial-environment) (varset 'x (univ:int 34)) ) (define (read-eval-print-loop stdin) (setup-initial-environment) (let loop ((line (ask "> " stdin))) (match (string-length line) with 0 -> #u _ -> (begin ;;(printf "line = '" line "'\n") (for-list exp (read-string line) (printf (univ-repr (eval exp)) "\n")) (loop (ask "> " stdin))) ))) (read-eval-print-loop (file/open-stdin))