WIP
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
|||||||
|
/target
|
||||||
|
/classes
|
||||||
|
/checkouts
|
||||||
|
pom.xml
|
||||||
|
pom.xml.asc
|
||||||
|
*.jar
|
||||||
|
*.class
|
||||||
|
/.lein-*
|
||||||
|
/.nrepl-port
|
||||||
|
.hgignore
|
||||||
|
.hg/
|
||||||
@@ -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"]])
|
||||||
@@ -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 []}))
|
||||||
|
|
||||||
@@ -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 "," "")))))
|
||||||
Reference in New Issue
Block a user