Monday, May 31, 2010

After playing with Clojure for a little while, one feature that I really like about it is doc and doc-strings, which work just like doc-strings in Emacs Lisp. I can use find-doc and ns-publics to find or explore the available symbols. I'm sure that an emacs mode or an IDE could make the interface as nice as the Emacs Lisp interface, but the functionality is there.

In Java, I often use javap to see what the method signatures of a class were, and have sometimes wished that the Javadoc were also available in the same way. The Java compiler could have put the Javadoc in attributes in the class files, which would then be available to tools like javap.

When using hugs or ghci for Haskell, I like using :browse and :info. The name and type almost always is enough to convey what a function does. It would be nice to have a short description of relevant information not captured by the name and type, but that's somewhat rare.

In any case, if I really needed to, documentation for the standard libraries for all three of these languages are available online. For Clojure and Haskell, the source code is available. For Java, the class files can be disassembled, though the occasional native method would remain opaque.

I find Clojure compelling in a way that I do not find Python compelling. They are both dynamically typed, which is a minus to me for both. I'm neither drawn to nor repelled by the syntax of either. However, I like feel of the immutable data structures of Clojure better than the data structures of Python. I'm also going to play around with integrating Clojure code with Java code. And while I haven't explored multimethods or any concurrency features, I can see learning new concepts, perhaps even learning when volatile would be useful when writing in Java, when looking into them.

Monday, May 24, 2010

In the product I work on at work, there are modules that accept items of various content types. Somebody made a dumb extension that made text content a special case, so now I'm getting silly NullPointerException bugs assigned to me because null is being passed in for the content. It would have been much cleaner to just use "text/plain" as the content type without any new special case code.

Monday, May 17, 2010

It seemed inappropriate that I hadn't implemented Parenthesis Hell in a Lisp, so I decided to learn a little about Clojure, a new Lisp dialect. I didn't use any of the concurrency features of Clojure, which is one of its main selling points. However, a Parenthesis Hell interpreter doesn't need any mutable state.

(defn ph-eval* [expr scope input]
(loop [scope* scope]
(cond
(empty? expr) input
(contains? scope* (first expr))
((scope* (first expr)) (rest expr) scope input scope*)
:else (recur (scope* 'outer)))))

(defn ph-valid? [val]
(cond
(not (seq? val)) false
(empty? val) true
(not (seq? (first val))) false
(empty? (first val)) (recur (rest val))
:else (recur (cons (first (first val)) (cons (rest (first val)) (rest val))))))

(defn ph-fn [body]
(fn [expr scope input def-scope]
(ph-eval* body def-scope expr)))

(defn ph-quote [expr scope input def-scope]
expr)

(defn ph-let [expr scope input def-scope]
(if (empty? expr)
()
(loop [bindings (first expr) scope* {'outer scope}]
(cond
(empty? bindings) (ph-eval* (rest expr) scope* input)
(empty? (first bindings)) (recur (rest bindings) scope*)
:else (recur (rest bindings)
(assoc scope*
(first (first bindings))
(ph-fn (rest (first bindings)))))))))

(defn ph-car [expr scope input def-scope]
(let [expr* (ph-eval* expr scope input)]
(if (empty? expr*) () (first expr*))))

(defn ph-cdr [expr scope input def-scope]
(let [expr* (ph-eval* expr scope input)]
(if (empty? expr*) () (rest expr*))))

(defn ph-cons [expr scope input def-scope]
(if (empty? expr)
()
(let [head (ph-eval* (first expr) scope input)
tail (ph-eval* (rest expr) scope input)]
(cons head tail))))

(defn ph-if [expr scope input def-scope]
(cond
(or (empty? expr) (empty? (rest expr))) ()
(not (empty? (ph-eval* (first expr) scope input)))
(ph-eval* (first (rest expr)) scope input)
:else
(ph-eval* (rest (rest expr)) scope input)))

(defn ph-eval [expr scope input def-scope]
(let [expr* (ph-eval* expr scope input)]
(if (not (ph-valid? expr))
(throw (IllegalArgumentException. "Not valid Parenthesis Hell")))
(ph-eval* expr* scope input)))

(defn ph-eval
"Evaluate a Parenthesis Hell expression with optional input."
([expr] (ph-eval expr ()))
([expr input]
(if (or (not (ph-valid? expr))
(not (seq? input)))
(throw (IllegalArgumentException. "Not valid Parenthesis Hell")))
(ph-eval* expr
{'() ph-quote
'(()) ph-let
'((())) ph-car
'(()()) ph-cdr
'((())()) ph-cons
'(()()()) ph-if
'(((()))) ph-eval}
input)))

Monday, May 10, 2010

Here is are a couple of programs in Parenthesis Hell that print themselves. I've inserted a bunch of line breaks, but they should be on one line.

The first one uses the optional concat in the initial scope. The second does not, and I haven't successfully tested it, since my interpreter runs out of memory when running it.

The following uses concat:

((())((((()()))()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()(
)(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()(
)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(
()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()
()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()((
)(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(
()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()((
)(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()
()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()((
)()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()(
)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()
()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()
(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()
()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()((
)(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(
()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()((
)(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(
()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()((
)()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()(
)(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()(
)(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()((
)(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(
()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()
(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()((
)()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(
()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()
()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(
()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()
()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()((
)()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()(
)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()
()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()(
)(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()
()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()
(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(
)()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()
(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()(
)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(
()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()
()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(
()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(
)()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()((
)(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(
()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()
(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()
()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(
()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()((
)()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(
()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()
()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()((
)()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()
()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()((
)()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()(
)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()
()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()(
)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()
()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()(
)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()
()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()(
)(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()
()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()
(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(
)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(
()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()(
)(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(
()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()
()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()
(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()((
)()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()((
)(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()(
)(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(
()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()
()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()
(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()
()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(
()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(
()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()
(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
))))))))))))))))((())(()()())()((()(()))(()()()(()(()()()())))(()(()))((())
((())))(()(()))(()()()(()(()()(()))))(())(()()))()()))(()(()))(()()()(()(()
()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()(
)(()(()()()()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()((
)()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()))
))))))))))))))))))))))))))))))))))))))))(()(()))((())((()())))((()())))

The following does not use concat:

((())((((()()))()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()(
)(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()(
)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(
()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()
(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()((
)(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()
()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()
(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()((
)()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(
()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()(
)(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()
()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()(
)(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()
()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()
(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(
)()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()
(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()(
)()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()((
)()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()
()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()((
)()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()
(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()(
)(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()((
)(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(
)()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()()(()
(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()
()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()
(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()
()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()(
)()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(
()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()
(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()((
)(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()((
)()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(
()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()
()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()((
)()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()(
)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()
()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()
(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(
)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()((
)(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()
()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()
(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()()
()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()((
)()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()(
)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()(
)()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()
(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()
()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(
()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()
(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()
(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()()
()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()((
)()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()
(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()
(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()((
)(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(
()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()
(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()((
)()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(
()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()
()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(
()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()
()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()((
)()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()(
)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()
()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()(
)(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()
()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()
(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(
)()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()
(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()(
)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(
()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()
()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(
()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(
)()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()((
)(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(
()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()
(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()
()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(
()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()((
)()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(
()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()
()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()((
)()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()
()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()((
)()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()(
)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()
()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()(
)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()
()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()(
)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()
()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()(
)(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()
()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()
(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(
)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(
()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()(
)(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(
()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()
()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(
()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(
)()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()((
)(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(
()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()
()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()
(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()
(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()((
)()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()(
)(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(
()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(
()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()
()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()((
)()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()(
)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()()()()(()((
)()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()
(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(
)(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(
()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()((
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))((())(()()())(((())))((()()())(((()))((())))
(((())())((())((())())(((()))((())))(()()))())(()()())((()())((())))(((())(
))(())(())((())())((()())((())))(()()))(()()))(()()))((((())))(()()())()(((
))((())())(()()()(()(()()()())))(())((())())((((())))((())))(())((())())(()
()()(()(()()(()))))(((())))(()()))()()))(())((())())(()()()(()(()()()()()((
)(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(
)()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(
()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()))))))))))))
))))))))))))))))))))))))))))))(())((())())((((())))((()())))((()())))

Monday, May 3, 2010

The tasq programming language

tasq is a macro-expansion language with a single task queue and a small set of operations.
Syntax

A tasq program is a sequence of declarations or comments, optionally separated by whitespace.

A comment starts with a dot (.) and continues to the end of the line.

A declaration is an identifier followed by zero or more operations, and ending with a dot (.). Whitespace may separate identifiers and operations, but is otherwise ignored.

An operation is an identifier or one of +, -, ~, or ?.

An identifier is an uninterrupted sequence of non-whitespace characters not including +, -, ~, and ?.

A declaration of an identifier with zero following operations adds the identifier to the end of the task queue.

A declaration of an identifier followed by one or more operations defines the identifier's expansion as those operations.

It is illegal to use undefined identifiers. It is illegal to have more than one definition for an identifier.
Execution

Execution consists of dequeuing and executing the top item of the task queue repeatedly while the task queue is not empty.
Operations

+ Write 1 to the output.
- Write 0 to the output.
~ Discard the next item in the task queue.
? Read one bit from the input. If 1 is read, do nothing. If 0 is read, discard the next item in the task queue. If at EOF, discard the next two items in the task queue.
identifier Append the identifier's expansion to the end of the task queue.
Examples

Hello world:

w-+--+----++--+-+-++-++---++-++---++-++++--+------+++-
+++-++-++++-+++--+--++-++---++--+----+----+----+-+-.w.

cat:

bit? 1 0. .Read a bit
0 -bit. .Write 0, handle next bit
1 +~. .Write 1, discard the ensuing -
bit. .Initial task queue

Self-printing program (formatted as multiple lines, but should be a 1-liner):

d.0-z.1+o.z--+-------++----.o--+-------++---+.q p.p--+------+++---+--+-+++--
---+-+-.d 0 1 1 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 1 1 0 0 0 0 0 0 1 0 1 1 0 1 0
1 1 1 1 0 1 0 0 0 1 0 1 1 1 0 0 0 1 1 0 0 0 1 0 0 1 0 1 0 1 1 0 1 1 0 1 1 1
1 0 0 1 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1
0 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1
0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0
0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 1
0 0 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1
1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1
0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0
0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 1 0 0 1 1 1 0 0 0
1 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1
1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1
0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0
0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0
1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1
1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0 0 1
0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0
0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 1 0 0 1 1 0 0 1 0
0 q.

Interpreter


module Main(main) where

import Data.Map(Map,empty,insert,(!))
import Data.Bits(testBit)
import Data.Char(chr,ord)
import System.Environment(getArgs)
import Text.ParserCombinators.Parsec(CharParser,anyChar,char,getState,many,many1,manyTill,newline,noneOf,runParser,setState,space,spaces,(<|>),(<?>))

data Task = Out0 | Out1 | In | Discard | Task String

parse :: String -> String -> (String -> [Task],[Task])
parse file src =
either (error . show) id (runParser program (empty,[]) file src)

type Parser a = CharParser (Map String [Task],[Task]) a

program :: Parser (String -> [Task],[Task])
program = do
many (space <|> comment)
many statement
(map,queue) <- getState
return ((map !),reverse queue)

comment :: Parser Char
comment = do
char '.'
manyTill anyChar newline
return ' '

statement :: Parser ()
statement = do
id <- name
body <- many task
char '.'
many (space <|> comment)
(map,queue) <- getState
setState (if null body then (map,Task id:queue)
else (insert id body map,queue))

task :: Parser Task
task = do
t <- (char '-' >> return Out0)
<|> (char '+' >> return Out1)
<|> (char '?' >> return In)
<|> (char '~' >> return Discard)
<|> fmap Task name
spaces
return t

name :: Parser String
name = do
str <- many1 (noneOf "+-?~. \r\n\t\f\v")
spaces
return str

run :: (String -> [Task]) -> [Task] -> [Bool] -> [Bool]
run _ [] _ = []
run defs (Out0:tasks) input = False : run defs tasks input
run defs (Out1:tasks) input = True : run defs tasks input
run defs (In:[]) _ = []
run defs (In:_:[]) [] = []
run defs (In:_:_:tasks) [] = run defs tasks []
run defs (In:_:tasks) (False:input) = run defs tasks input
run defs (In:tasks) (True:input) = run defs tasks input
run defs (Discard:[]) _ = []
run defs (Discard:_:tasks) input = run defs tasks input
run defs (Task name:tasks) input = run defs (tasks ++ (defs name)) input

main :: IO ()
main = do
(file:_) <- getArgs
src <- readFile file
interact (fromBits . uncurry run (parse file src) . toBits)

toBits = concatMap (flip map [7,6..0] . testBit . ord)

fromBits (b7:b6:b5:b4:b3:b2:b1:b0:rest) =
chr ((if b7 then 128 else 0) + (if b6 then 64 else 0)
+ (if b5 then 32 else 0) + (if b4 then 16 else 0)
+ (if b3 then 8 else 0) + (if b2 then 4 else 0)
+ (if b1 then 2 else 0) + (if b0 then 1 else 0)) : fromBits rest
fromBits _ = []

Monday, April 26, 2010

Last year, I made a bunch of changes to automatically do a lot of the manual configuration that was involved in adding a new component and also managed to package everything to do with a component into a single jar file that gets its own ClassLoader so that different components can't interfere with each other. Two major things were making the SNMP configuration almost completely automatic, and automatically adding new database rows required for new components as needed. I did all this after two people involved in implementing the service left so I didn't have to worry too much about stepping on toes or having a bunch of bureaucratic meetings.

It has worked pretty well so far. The biggest snag was that some people ran a build that automatically added some rows to the database, then moved back to an older build that would refuse to initialize because database didn't match the configured components. This is no longer be an issue, as there aren't even builds that old in production.

However, there is another associated service that has a horrible tiered maven build that requires a bunch of configuration in two of the maven components as well as requiring new database rows be added for each new component. As long as somebody else is taking care of all of that, I don't care. But I've been called on to add the configuration when there are new components, and it's annoying to have to add almost 200 lines of boilerplate XML and request a minor database script update for each new component, and then go through the convoluted maven build process.

There are a few other associated services that, as yet, require manually adding stuff for each new component, but other people have been taking care of it. One of them is a hack onto a legacy infrastructure and is the source of most of the usage. Another two really ought to fetch everything associated with a component from the main service, which does have all the mechanisms required for doing so, but were implemented to have hard-coded copies of a few things for each component. But, for at least one of them, it's in the pipeline to do it right, after which it would no longer need any changes every time a new component is added.

The mentality that all new components need a database script update seems to be somewhat ingrained. Even today, someone asked me if they needed to run a database script, presumably for their development environment, as new components are being released to production in a few weeks. Their database probably already has had all the new rows for months, since the code for the new components have been in place for months.

Monday, April 19, 2010

The turn programming language

I decided to take a shot at making a two-dimensional programming language when noting that - and |, and / and \, and N and Z are 90-degree rotations of each other.

turn is a two-dimensional programming language that is invariant under 90-degree rotations and has any number of program counters.

A program counter (PC) has a location, direction, and turn direction.

A direction is up, right, down, or left.

A turn direction is left, straight, right, or u-turn.

Each cycle, each PC executes the operation at its location, then moves to its next location. If the next location is a wall and the turn direction is not straight, the direction is changed in the turn direction until the next location is not a wall. If the PC cannot turn to a location is not a wall, the PC dies. A PC also dies if it moves off the grid. If multiple PCs have the same location, direction, and turn direction, all but one of those PCs die. Execution ends when there are no remaining PCs.

There are 8 types of locations and their operations:
/: If the direction is horizontal, the turn direction rotates 90 degrees left. If the direction is vertical, the turn direction rotates 90 degrees right.
\: If the direction is horizontal, the turn direction rotates 90 degrees right. If the direction is vertical, the turn direction rotates 90 degrees left.
-: If the direction is horizontal, there is no effect. If the direction is vertical, the turn direction rotates 180 degrees.
|: If the direction is horizontal, the turn direction rotates 180 degrees. If the direction is vertical, there is no effect.
Z: If the direction is horizontal, read a bit from input. If the direction is vertical, write a bit to output.
N: If the direction is horizontal, write a bit to output. If the direction is vertical, read a bit from input.
+: Create a new PC at this location with direction in the turned direction and turn direction straight.
O: Read from this location or write to this location. If this location contains a bit, then read that bit, otherwise, write a bit. This location initially does not contain a bit.
space or dot (.): No-op.
^ > v <: No-op. Defines the starting location and direction of a PC. The initial turn direction is straight.
any other character: Wall. No-op.

When reading a bit, if the bit read is a 0, the turn direction is rotated 90 degrees to the left. If the bit read is a 1, the turn direction is rotated 90 degrees to the right. At EOF, the turn direction is rotates 180 degrees.

If multiple PCs read the input in a cycle, they all read the same bit. If multiple PCs read the same location in a cycle, they all read the same bit.

When writing a bit, if the turn direction is left, a 0 is written. If the turn direction is right, a 1 is written. Otherwise, nothing is written.

If multiple PCs are writing to the output in a cycle, if they all write the same value, then one bit with that value is written, otherwise nothing is written. If multiple PCs are writing to the same location in a cycle, if they all write the same value, then that value is written, otherwise nothing is written.

Examples

Hello world

>/N|N|NN|N|NNNN|NN|NN|N|N|N|N|NN|N|NN|NNN|NN|N|NN|NNN|NN|N|NNNN|NN|N|NNNNNN|NN#
#N|N|NNNN|N|NNNN|N|NNNN|N|NN|NN|NNN|NN|N|NN|NN|N|NN|NNN|N|NNNN|N|NN|N|NNN|N|Z
- #
N|Z
#

cat

_v_
+
ZNZ
( )
===

approximate touppercase

##|###|#||##---------#
#.......++.-.........#
##.###.#..#NO.......+#
##.......+|-.........#
##/###.#..##.........#
-.O......O...O......+#
##.###.#..##.........#
#.|N|#...............#
#.....|#.Z##.........#
AT##-#-#\.##.........#
PO.#+/+.+.....O......N
PU.#+.+.+......O.....N
RP.#+.+.+.......O....N
OP.#+.+.+........O...N
XE.#+.+.+.........O..N
IR.#+.+.+..........O.N
MC.#.#.#..##NNNNNNNN.#
AA\#+.+.+.>/++++++++.#
TS.\/\/...|APPROXIMATE
EE#######|#TOUPPERCASE

Interpreter


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;

public class Turn {
private int height;
private int width;
private ArrayList<ArrayList<Instruction>> grid = new ArrayList<ArrayList<Instruction>>();
private ArrayList<ArrayList<Boolean>> data = new ArrayList<ArrayList<Boolean>>();
private ArrayList<PC> pcs = new ArrayList<PC>();

public enum Instruction {
SLASH, BACKSLASH, DASH, VERT, N, Z, PLUS, O, NOOP, WALL,
}

public enum TurnDir {
STRAIGHT, RIGHT, UTURN, LEFT,
}

public class PC {
private int x;
private int y;
private int dx;
private int dy;
private TurnDir turnDir;

public PC(int x, int y, char dir) {
this.x = x;
this.y = y;
switch (dir) {
case '^': dx = 0; dy = -1; break;
case '>': dx = 1; dy = 0; break;
case 'v': dx = 0; dy = 1; break;
case '<': dx = -1; dy = 0; break;
default: assert false; break;
}
turnDir = TurnDir.STRAIGHT;
}

public PC(PC pc) {
this.x = pc.x;
this.y = pc.y;
this.dx = pc.dx;
this.dy = pc.dy;
this.turnDir = pc.turnDir;
doTurn();
this.turnDir = TurnDir.STRAIGHT;
}

public boolean inBounds() {
return x >= 0 && x < width && y >= 0 && y < height;
}

public void move() {
x += dx;
y += dy;
}

public Instruction rotate(Instruction insn) {
if (dx == 0)
return insn;
switch (insn) {
case SLASH: return Instruction.BACKSLASH;
case BACKSLASH: return Instruction.SLASH;
case DASH: return Instruction.VERT;
case VERT: return Instruction.DASH;
case N: return Instruction.Z;
case Z: return Instruction.N;
default: return insn;
}
}

public TurnDir getTurnDir() {
return turnDir;
}

public void setTurnDir() {
switch (rotate(grid.get(y).get(x))) {
case SLASH:
turnDir = TurnDir.values()[(turnDir.ordinal()+1)%4];
break;
case BACKSLASH:
turnDir = TurnDir.values()[(turnDir.ordinal()+3)%4];
break;
case DASH:
turnDir = TurnDir.values()[(turnDir.ordinal()+2)%4];
break;
}
}

public boolean facingWall() {
return x + dx >= 0 && x + dx < width
&& y + dy >= 0 && y + dy < height
&& grid.get(y + dy).get(x + dx) == Instruction.WALL;
}

public void doTurn() {
int t;
switch (turnDir) {
case RIGHT: t = dx; dx = -dy; dy = t; break;
case LEFT: t = dx; dx = dy; dy = -t; break;
case UTURN: dx = -dx; dy = -dy; break;
}
}

public boolean isInput() {
return rotate(grid.get(y).get(x)) == Instruction.N;
}

public void doInput(boolean eof, boolean bit) {
if (eof)
turnDir = TurnDir.values()[(turnDir.ordinal()+2)%4];
else if (bit)
turnDir = TurnDir.values()[(turnDir.ordinal()+1)%4];
else
turnDir = TurnDir.values()[(turnDir.ordinal()+3)%4];
}

public boolean isOutput() {
return (turnDir == TurnDir.LEFT || turnDir == TurnDir.RIGHT)
&& rotate(grid.get(y).get(x)) == Instruction.Z;
}

public boolean getOutput() {
return turnDir == TurnDir.RIGHT;
}

public boolean isSpawn() {
return grid.get(y).get(x) == Instruction.PLUS
&& turnDir != TurnDir.STRAIGHT;
}

public boolean isReadSignal() {
return grid.get(y).get(x) == Instruction.O
&& data.get(y).get(x) != null;
}

public void readSignal() {
doInput(false, data.get(y).get(x));
}

public void clearSignal() {
data.get(y).set(x, null);
}

public boolean isWriteSignal() {
return (turnDir == TurnDir.LEFT || turnDir == TurnDir.RIGHT)
&& grid.get(y).get(x) == Instruction.O
&& data.get(y).get(x) == null;
}

public void setSignal() {
data.get(y).set(x, getOutput());
}

public boolean equals(PC pc) {
return pc.x == x && pc.y == y && pc.dx == dx && pc.dy == dy
&& pc.turnDir == turnDir;
}

public boolean sameLocation(PC pc) {
return pc.x == x && pc.y == y;
}
}

public Turn(BufferedReader in) throws IOException {
String line;
while ((line = in.readLine()) != null)
parseLine(line);
height = grid.size();
width = 0;
for (ArrayList<Instruction> row : grid)
width = Math.max(width, row.size());
for (ArrayList<Instruction> row : grid)
while (row.size() < width)
row.add(Instruction.NOOP);
while (data.size() < height)
data.add(new ArrayList<Boolean>());
for (ArrayList<Boolean> row : data)
while (row.size() < width)
row.add(null);
}

private void parseLine(String line) {
ArrayList<Instruction> row = new ArrayList<Instruction>();
for (int i = 0; i < line.length(); i++)
switch (line.charAt(i)) {
case '^': case '>': case 'v': case '<':
pcs.add(new PC(i, grid.size(), line.charAt(i)));
/*FALLTHROUGH*/
case ' ': case '.':
row.add(Instruction.NOOP);
break;
case '/': row.add(Instruction.SLASH); break;
case '\\': row.add(Instruction.BACKSLASH); break;
case '-': row.add(Instruction.DASH); break;
case '|': row.add(Instruction.VERT); break;
case 'N': row.add(Instruction.N); break;
case 'Z': row.add(Instruction.Z); break;
case '+': row.add(Instruction.PLUS); break;
case 'O': row.add(Instruction.O); break;
case 'X': row.add(Instruction.WALL); break;
default: row.add(Instruction.WALL); break;
}
grid.add(row);
}

public void run(BitInputStream in, BitOutputStream out) throws IOException {
ArrayList<PC> list = new ArrayList<PC>();
ArrayList<PC> list2 = new ArrayList<PC>();
for (;;) {
for (PC pc : pcs)
if (pc.isOutput())
list.add(pc);
boolean doOutput = false;
boolean output = false;
for (PC pc : list)
if (doOutput) {
if (output != pc.getOutput()) {
doOutput = false;
break;
}
} else {
doOutput = true;
output = pc.getOutput();
}
if (doOutput)
out.write(output);
list.clear();

for (PC pc : pcs) {
pc.setTurnDir();
if (pc.isInput())
list.add(pc);
}

if (list.size() > 0) {
boolean eof = in.eof();
boolean bit = in.read();
for (PC pc : list)
pc.doInput(eof, bit);
list.clear();
}

for (PC pc : pcs) {
if (pc.isReadSignal()) {
pc.readSignal();
list2.add(pc);
continue;
} else if (!pc.isWriteSignal() || list.contains(pc)) {
continue;
}
doOutput = true;
for (PC pc2 : pcs)
if (pc != pc2 && pc.sameLocation(pc2)) {
list.add(pc2);
if (pc.getOutput() != pc2.getOutput())
doOutput = false;
}
if (doOutput)
pc.setSignal();
}
list.clear();
for (PC pc : list2)
pc.clearSignal();
list2.clear();

for (PC pc : pcs)
if (pc.isSpawn())
list.add(new PC(pc));
pcs.addAll(list);
list.clear();

loop:
for (Iterator<PC> i = pcs.iterator(); i.hasNext(); ) {
PC pc = i.next();
for (PC pc2 : pcs)
if (pc2 != pc && pc2.equals(pc)) {
i.remove();
continue loop;
}
if (pc.getTurnDir() != TurnDir.STRAIGHT) {
for (int n = 0; n < 4 && pc.facingWall(); n++)
pc.doTurn();
if (pc.facingWall())
i.remove();
}
}

for (Iterator<PC> i = pcs.iterator(); i.hasNext(); ) {
PC pc = i.next();
pc.move();
if (!pc.inBounds())
i.remove();
}

if (pcs.isEmpty())
break;
}
out.flush();
}

public static class BitInputStream {
private InputStream in;
private int bit;
private int octet;

public BitInputStream(InputStream in) {
this.in = in;
this.bit = 0;
this.octet = 0;
}

public boolean eof() throws IOException {
if (octet >= 0 && bit == 0) {
bit = 128;
octet = in.read();
}
return octet < 0;
}

public boolean read() throws IOException {
if (octet >= 0 && bit == 0) {
bit = 128;
octet = in.read();
}
try {
return (octet & bit) != 0;
} finally {
bit >>>= 1;
}
}

public void close() throws IOException {
in.close();
}
}

public static class BitOutputStream {
private OutputStream out;
private int bit;
private int octet;

public BitOutputStream(OutputStream out) {
this.out = out;
this.bit = 128;
this.octet = 0;
}

public void write(boolean b) throws IOException {
if (b)
octet |= bit;
bit >>>= 1;
if (bit == 0) {
out.write(octet);
bit = 128;
octet = 0;
}
}

public void close() throws IOException {
out.close();
}

public void flush() throws IOException {
out.flush();
}
}

public static class ASCIIBitOutputStream extends BitOutputStream {
private OutputStream out;

public ASCIIBitOutputStream(OutputStream out) {
super(out);
this.out = out;
}

public void write(boolean b) throws IOException {
out.write(b ? '1' : '0');
}
}

public static void main(String[] args) throws Exception {
String src;
BitOutputStream out;
if ("-b".equals(args[0])) {
src = args[1];
out = new ASCIIBitOutputStream(System.out);
} else {
src = args[0];
out = new BitOutputStream(System.out);
}
new Turn(new BufferedReader(new FileReader(src))).run(new BitInputStream(System.in), out);
}
}