;;; cl-scopes/forge - may the forge be with you! ;;;; A Forth-like interpreter implemented in Common Lisp. (defpackage :scopes/forge (:use :common-lisp) (:export #:*forge-env* #:forge-env #:dstack #:exec #:exec-str #:repl #:make-iseq #:isq-all #:isq-cur #:isq-next #:isq-end #:isq-add #:add)) (in-package :scopes/forge) ;;; builtins (defvar add #'(lambda () (pushd (cl:+ (popd) (popd))))) (defvar lit #'(lambda () (pushd (isq-next (ip *forge-env*))))) ;;; iseq: iterable sequence (defclass iseq () ((start :reader start :initform (list nil) :initarg :start) (cur :accessor cur) (end :accessor end))) (defun make-iseq (&optional start) (let* ((start (cons nil start)) (seq (make-instance 'iseq :start start))) (setf (cur seq) (setf (end seq) start)) seq)) (defun isq-all (seq) (cdr (start seq))) (defun isq-cur (seq) (car (cur seq))) (defun isq-end (seq) (car (end seq))) (defun isq-next (seq) (pop (cur seq)) (car (cur seq))) (defun isq-add (seq v) (setf (cdr (end seq)) (list v)) (pop (end seq))) (defclass forge-env () ((data-stack :initform nil :accessor data-stack) (cp :initform (make-iseq) :accessor cp) (ip :initform (make-iseq) :accessor ip))) ;;; forge environment (defun forge-env () (let ((fe (make-instance 'forge-env))) fe)) (defvar *forge-env* (forge-env)) (defun dstack() (data-stack *forge-env*)) (defun exec-str (s) (exec (read-from-string (concatenate 'string "(" s ")")))) (defun repl () (do ((input (read-line) (read-line))) ((string= input "q") nil) (exec-str input))) (defun exec (code) (call (comp code))) (defun call (code) (let ((ip (make-iseq code))) (setf (ip *forge-env*) ip) (do ((item (isq-next ip) (isq-next ip))) ((null item)) (funcall item)))) (defun comp (slist) (setf (cp *forge-env*) (make-iseq)) (let ((inp (make-iseq slist))) (do ((item (isq-next inp) (isq-next inp))) ((null item)) (typecase item (symbol (comp1 (symbol-value item))) (cons (comp1 lit) (comp1 (comp item))) (t (comp1 lit) (comp1 item))))) (isq-all (cp *forge-env*))) (defun comp1 (item) (isq-add (cp *forge-env*) item)) ;;; internal definitions (defun popd () (pop (data-stack *forge-env*))) (defun pushd (v) (push v (data-stack *forge-env*)))