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