Custom language - FOR loop in a clojure interpeter?

Posted by Mark on Stack Overflow See other posts from Stack Overflow or by Mark
Published on 2011-01-15T21:12:26Z Indexed on 2011/01/16 8:53 UTC
Read the original article Hit count: 308

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))))))

© Stack Overflow or respective owner

Related posts about loops

Related posts about clojure