-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinterpreter_framework.clj
More file actions
50 lines (43 loc) · 1.87 KB
/
interpreter_framework.clj
File metadata and controls
50 lines (43 loc) · 1.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
(ns compojure.interpreter-framework
"This framework assumes the structure of Program and FunctionDef
records is similar across different IRs (which holds true so far)."
(:require [compojure.exceptions :refer [arity-exception]]
[compojure.parser :refer [parse]]))
(defn get-main-fn
[prog]
(first
(filter #(= (:name %) "main") (:functions prog))))
(defn validate-args-count [main-fn provided-args]
(let [expected (count (:params main-fn))
actual (count provided-args)]
(when (> expected actual)
(throw (arity-exception (:name main-fn)
expected actual)))))
(defn load-fn-args [fn args state]
(into state
(map #(vector %1 %2) (:params fn) args)))
(defn interpreter-maker
"Takes as input a function that converts a parsed AST
to some IR program, and a function that executes the
'main' of the IR program (assuming its arguments have
already been loaded into state).
Returns an interpreter function, that takes as input
a source code string and a coll of arguments, and returns
the execution result as a map with keys
:output, :error, :retval, and :final-state if the program
successfully returned."
[converter main-fn-executer]
(fn [source-code args]
(let [e-prog (converter (parse source-code))
main-fn (get-main-fn e-prog)
initial-state (load-fn-args main-fn args {})]
(validate-args-count main-fn args)
(binding [*out* (java.io.StringWriter.)]
(try
(main-fn-executer main-fn initial-state)
(catch clojure.lang.ExceptionInfo e
(let [data (ex-data e)]
(if (= (:type data) :return-encountered)
{:output (str *out*), :error nil
:retval (:retval data), :final-state (:final-state data)}
{:output (str *out*), :error (ex-message e), :retval nil}))))))))