This commit is contained in:
Marko Zivanovic
2015-04-17 16:16:18 +02:00
commit ff35e03087
4 changed files with 129 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
/target
/classes
/checkouts
pom.xml
pom.xml.asc
*.jar
*.class
/.lein-*
/.nrepl-port
.hgignore
.hg/
+6
View File
@@ -0,0 +1,6 @@
(defproject brainfuck "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"]])
+69
View File
@@ -0,0 +1,69 @@
(ns brainfuck)
(defn inc-data
[{:keys [data dp] :as state}]
(let [curval (get data dp 0)]
(assoc state :data
(assoc data dp (if (= curval 255) 0 (inc curval))))))
(defn dec-data
[{:keys [data dp] :as state}]
(let [curval (get data dp 0)]
(assoc state :data
(assoc data dp (if (= curval 0) 255 (dec curval))))))
(defn output
[{:keys [data dp output] :as state}]
(assoc state :output (conj output (char (get data dp 0)))))
(defn input
[{:keys [input data dp] :as state}]
(assoc state :data (assoc data dp (int (first input))) :input (rest input)))
(defn jump-fwd
[{:keys [code input data ip dp] :as state}]
state)
(defn jump-bwd
[{:keys [code input data ip dp] :as state}]
state)
(defn execute-current-instruction
[{:keys [code ip dp] :as state}]
(let [instruction (nth code ip)]
(case instruction
\> (assoc state dp (inc dp))
\< (assoc state dp (dec dp))
\+ (inc-data state)
\- (dec-data state)
\. (output state)
\, (input state)
\[ (jump-fwd state)
\] (jump-bwd state)
state)
)
)
(defn execute-step
"Execute single BF instruction returning current state of the
output"
[{:keys [code input data ip dp] :as state} ]
(if (< ip (count code))
(let [new-state (execute-current-instruction state)]
(println new-state)
(recur (assoc new-state :ip (inc ip))))
output))
(defn execute-string
"Evaluate the Brainfuck source code in `source` using `input` as a
source of characters for the `,` input command.
Either returns a sequence of output characters, or `nil` if there
was insufficient input."
[source input]
(println (str "Executing code: " source))
(execute-step {:code source :input input :data {} :ip 0 :dp 0 :output []}))
+43
View File
@@ -0,0 +1,43 @@
(ns brainfuck-test
(:require [clojure.test :refer :all]
[clojure.string :as s]
[brainfuck :refer [execute-string]]))
(defn- ord->str [n] (str (char n)))
(deftest basic-program-tests
(testing "output until inclusive 0"
(let [in (-> (range 1 256) vec (conj 0)
(->> (map char) (apply str)))]
(= in (execute-string "+[,.]" in))))
(testing "output n exclamation marks"
(let [pluses (s/join (repeat (int \!) \+))
src (str ">" pluses "<,[>.<-]")
! #(s/join (repeat % \!))]
(are [n] (= (execute-string src (ord->str n))
(! n))
1 2 3 4 5 6 7 8 9 10)))
(testing "memory 0 initialized"
(is (= (execute-string ".>." "")
"\0\0")))
(testing "memory operations"
(is (= (execute-string ".>.+.<." "")
"\0\0\1\0")))
(testing "input output"
(are [n] (= (execute-string ".,." (ord->str n))
(str "\0" (char n)))
11 12 13 14 15 16 17 18 19 20))
(testing "loops"
(let [z #(s/join (repeat % "\0"))]
(are [n] (= (execute-string "[>.<],[>.<-]" (ord->str n))
(z n))
21 22 23 24 25 26 27 28 29 30))))
(deftest error-handling-test
(testing "insufficient input"
(is (nil? (execute-string "," "")))))