aboutsummaryrefslogtreecommitdiff
path: root/scala/reader.scala
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-12-18 23:21:39 -0600
committerJoel Martin <github@martintribe.org>2015-01-09 16:16:51 -0600
commit821930dbd9febf45fad25aefa9bc64e8ace4c737 (patch)
tree8afc5c6c99b5d670fefc75dbcc1b71acda1e2e35 /scala/reader.scala
parentb8ee29b22fbaa7a01f2754b4d6dd9af52e02017c (diff)
downloadmal-821930dbd9febf45fad25aefa9bc64e8ace4c737.tar.gz
mal-821930dbd9febf45fad25aefa9bc64e8ace4c737.zip
Scala: all steps 0-9 but no metadata.
Diffstat (limited to 'scala/reader.scala')
-rw-r--r--scala/reader.scala88
1 files changed, 88 insertions, 0 deletions
diff --git a/scala/reader.scala b/scala/reader.scala
new file mode 100644
index 0000000..fc16f28
--- /dev/null
+++ b/scala/reader.scala
@@ -0,0 +1,88 @@
+import scala.util.matching.Regex
+
+object reader {
+
+ class Reader (tokens: Array[String]) {
+ var data = tokens
+ var position: Int = 0
+ def peek(): String = {
+ if (position >= data.length) return(null)
+ data(position)
+ }
+ def next(): String = {
+ if (position >= data.length) return(null)
+ position = position + 1
+ data(position-1)
+ }
+ }
+
+ def tokenize(str: String): Array[String] = {
+ val re = """[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)""".r
+ re.findAllMatchIn(str).map{ _.group(1) }
+ .filter{ s => s != "" && s(0) != ';' }
+ .toArray
+ }
+
+ def parse_str(s: String): String = {
+ s.replace("\\\"", "\"").replace("\\n", "\n")
+ }
+
+ def read_atom(rdr: Reader): Any = {
+ val token = rdr.next()
+ val re_int = """^(-?[0-9]+)$""".r
+ val re_flt = """^(-?[0-9][0-9.]*)$""".r
+ val re_str = """^"(.*)"$""".r
+ val re_key = """^:(.*)$""".r
+ return token match {
+ case re_int(i) => i.toInt // integer
+ case re_flt(f) => f.toDouble // float
+ case re_str(s) => parse_str(s) // string
+ case re_key(k) => "\u029e" + k // keyword
+ case "nil" => null
+ case "true" => true
+ case "false" => false
+ case _ => Symbol(token) // symbol
+ }
+ }
+
+ def read_list(rdr: Reader,
+ start: String = "(", end: String = ")"): List[Any] = {
+ var ast: List[Any] = List()
+ var token = rdr.next()
+ if (token != start) throw new Exception("expected '" + start + "', got EOF")
+ while ({token = rdr.peek(); token != end}) {
+ if (token == null) throw new Exception("expected '" + end + "', got EOF")
+ ast = ast :+ read_form(rdr)
+ }
+ rdr.next()
+ ast
+ }
+
+ def read_form(rdr: Reader): Any = {
+ return rdr.peek() match {
+ case "'" => { rdr.next; List(Symbol("quote"), read_form(rdr)) }
+ case "`" => { rdr.next; List(Symbol("quasiquote"), read_form(rdr)) }
+ case "~" => { rdr.next; List(Symbol("unquote"), read_form(rdr)) }
+ case "~@" => { rdr.next; List(Symbol("splice-unquote"), read_form(rdr)) }
+ case "^" => { rdr.next; val meta = read_form(rdr);
+ List(Symbol("with-meta"), read_form(rdr), meta) }
+ case "@" => { rdr.next; List(Symbol("deref"), read_form(rdr)) }
+
+ case "(" => read_list(rdr)
+ case ")" => throw new Exception("unexpected ')')")
+ case "[" => read_list(rdr, "[", "]").toArray
+ case "]" => throw new Exception("unexpected ']')")
+ case "{" => types._hash_map(read_list(rdr, "{", "}"))
+ case "}" => throw new Exception("unexpected '}')")
+ case _ => read_atom(rdr)
+ }
+ }
+
+ def read_str(str: String): Any = {
+ val tokens = tokenize(str)
+ if (tokens.length == 0) return null
+ return read_form(new Reader(tokens))
+ }
+}
+
+// vim: ts=2:sw=2