Custom language - FOR loop in a clojure interpeter?
- by Mark
I have a basic interpreter in clojure. Now i need to implement
for (initialisation; finish-test; loop-update) {
statements
}
Implement a similar for-loop for the interpreted language. The pattern will be:
(for variable-declarations end-test loop-update do statement)
The variable-declarations will set up initial values for variables.The end-test returns a boolean, and the loop will end if end-test returns false. The statement is interpreted followed by the loop-update for each
pass of the loop.
Examples of use are:
(run ’(for ((i 0)) (< i 10) (set i (+ 1 i)) do
(println i)))
(run ’(for ((i 0) (j 0)) (< i 10) (seq (set i (+ 1 i)) (set j (+ j (* 2 i)))) do
(println j)))
inside my interpreter. I will attach my interpreter code I got so far. Any help is appreciated.
Interpreter
(declare interpret make-env) ;; needed as language terms call out to 'interpret'
(def do-trace false) ;; change to 'true' to show calls to 'interpret'
;; simple utilities
(def third ; return third item in a list
(fn [a-list]
(second (rest a-list))))
(def fourth ; return fourth item in a list
(fn [a-list]
(third (rest a-list))))
(def run ; make it easy to test the interpreter
(fn [e]
(println "Processing: " e)
(println "=> " (interpret e (make-env)))))
;; for the environment
(def make-env
(fn []
'()))
(def add-var
(fn [env var val]
(cons (list var val) env)))
(def lookup-var
(fn [env var]
(cond (empty? env) 'error
(= (first (first env)) var) (second (first env))
:else (lookup-var (rest env) var))))
;; for terms in language
;; -- define numbers
(def is-number?
(fn [expn]
(number? expn)))
(def interpret-number
(fn [expn env]
expn))
;; -- define symbols
(def is-symbol?
(fn [expn]
(symbol? expn)))
(def interpret-symbol
(fn [expn env]
(lookup-var env expn)))
;; -- define boolean
(def is-boolean?
(fn [expn]
(or
(= expn 'true)
(= expn 'false))))
(def interpret-boolean
(fn [expn env]
expn))
;; -- define functions
(def is-function?
(fn [expn]
(and
(list? expn)
(= 3 (count expn))
(= 'lambda (first expn)))))
(def interpret-function ; keep function definitions as they are written
(fn [expn env]
expn))
;; -- define addition
(def is-plus?
(fn [expn]
(and
(list? expn)
(= 3 (count expn))
(= '+ (first expn)))))
(def interpret-plus
(fn [expn env]
(+
(interpret (second expn) env)
(interpret (third expn) env))))
;; -- define subtraction
(def is-minus?
(fn [expn]
(and
(list? expn)
(= 3 (count expn))
(= '- (first expn)))))
(def interpret-minus
(fn [expn env]
(-
(interpret (second expn) env)
(interpret (third expn) env))))
;; -- define multiplication
(def is-times?
(fn [expn]
(and
(list? expn)
(= 3 (count expn))
(= '* (first expn)))))
(def interpret-times
(fn [expn env]
(*
(interpret (second expn) env)
(interpret (third expn) env))))
;; -- define division
(def is-divides?
(fn [expn]
(and
(list? expn)
(= 3 (count expn))
(= '/ (first expn)))))
(def interpret-divides
(fn [expn env]
(/
(interpret (second expn) env)
(interpret (third expn) env))))
;; -- define equals test
(def is-equals?
(fn [expn]
(and
(list? expn)
(= 3 (count expn))
(= '= (first expn)))))
(def interpret-equals
(fn [expn env]
(=
(interpret (second expn) env)
(interpret (third expn) env))))
;; -- define greater-than test
(def is-greater-than?
(fn [expn]
(and
(list? expn)
(= 3 (count expn))
(= '> (first expn)))))
(def interpret-greater-than
(fn [expn env]
(>
(interpret (second expn) env)
(interpret (third expn) env))))
;; -- define not
(def is-not?
(fn [expn]
(and
(list? expn)
(= 2 (count expn))
(= 'not (first expn)))))
(def interpret-not
(fn [expn env]
(not
(interpret (second expn) env))))
;; -- define or
(def is-or?
(fn [expn]
(and
(list? expn)
(= 3 (count expn))
(= 'or (first expn)))))
(def interpret-or
(fn [expn env]
(or
(interpret (second expn) env)
(interpret (third expn) env))))
;; -- define and
(def is-and?
(fn [expn]
(and
(list? expn)
(= 3 (count expn))
(= 'and (first expn)))))
(def interpret-and
(fn [expn env]
(and
(interpret (second expn) env)
(interpret (third expn) env))))
;; -- define print
(def is-print?
(fn [expn]
(and
(list? expn)
(= 2 (count expn))
(= 'println (first expn)))))
(def interpret-print
(fn [expn env]
(println (interpret (second expn) env))))
;; -- define with
(def is-with?
(fn [expn]
(and
(list? expn)
(= 3 (count expn))
(= 'with (first expn)))))
(def interpret-with
(fn [expn env]
(interpret (third expn)
(add-var env
(first (second expn))
(interpret (second (second expn)) env)))))
;; -- define if
(def is-if?
(fn [expn]
(and
(list? expn)
(= 4 (count expn))
(= 'if (first expn)))))
(def interpret-if
(fn [expn env]
(cond (interpret (second expn) env) (interpret (third expn) env)
:else (interpret (fourth expn) env))))
;; -- define function-application
(def is-function-application?
(fn [expn env]
(and
(list? expn)
(= 2 (count expn))
(is-function? (interpret (first expn) env)))))
(def interpret-function-application
(fn [expn env]
(let [function (interpret (first expn) env)]
(interpret (third function)
(add-var env
(first (second function))
(interpret (second expn) env))))))
;; the interpreter itself
(def interpret
(fn [expn env]
(cond do-trace (println "Interpret is processing: " expn))
(cond
; basic values
(is-number? expn) (interpret-number expn env)
(is-symbol? expn) (interpret-symbol expn env)
(is-boolean? expn) (interpret-boolean expn env)
(is-function? expn) (interpret-function expn env)
; built-in functions
(is-plus? expn) (interpret-plus expn env)
(is-minus? expn) (interpret-minus expn env)
(is-times? expn) (interpret-times expn env)
(is-divides? expn) (interpret-divides expn env)
(is-equals? expn) (interpret-equals expn env)
(is-greater-than? expn) (interpret-greater-than expn env)
(is-not? expn) (interpret-not expn env)
(is-or? expn) (interpret-or expn env)
(is-and? expn) (interpret-and expn env)
(is-print? expn) (interpret-print expn env)
; special syntax
(is-with? expn) (interpret-with expn env)
(is-if? expn) (interpret-if expn env)
; functions
(is-function-application? expn env) (interpret-function-application expn env)
:else 'error)))
;; tests of using environment
(println "Environment tests:")
(println (add-var (make-env) 'x 1))
(println (add-var (add-var (add-var (make-env) 'x 1) 'y 2) 'x 3))
(println (lookup-var '() 'x))
(println (lookup-var '((x 1)) 'x))
(println (lookup-var '((x 1) (y 2)) 'x))
(println (lookup-var '((x 1) (y 2)) 'y))
(println (lookup-var '((x 3) (y 2) (x 1)) 'x))
;; examples of using interpreter
(println "Interpreter examples:")
(run '1)
(run '2)
(run '(+ 1 2))
(run '(/ (* (+ 4 5) (- 2 4)) 2))
(run '(with (x 1) x))
(run '(with (x 1) (with (y 2) (+ x y))))
(run '(with (x (+ 2 4)) x))
(run 'false)
(run '(not false))
(run '(with (x true) (with (y false) (or x y))))
(run '(or (= 3 4) (> 4 3)))
(run '(with (x 1) (if (= x 1) 2 3)))
(run '(with (x 2) (if (= x 1) 2 3)))
(run '((lambda (n) (* 2 n)) 4))
(run '(with (double (lambda (n) (* 2 n)))
(double 4)))
(run '(with (sum-to (lambda (n) (if (= n 0) 0 (+ n (sum-to (- n 1))))))
(sum-to 100)))
(run '(with (x 1)
(with (f (lambda (n) (+ n x)))
(with (x 2)
(println (f 3))))))