diff options
| author | Joel Martin <github@martintribe.org> | 2014-12-18 23:21:39 -0600 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-01-09 16:16:51 -0600 |
| commit | 821930dbd9febf45fad25aefa9bc64e8ace4c737 (patch) | |
| tree | 8afc5c6c99b5d670fefc75dbcc1b71acda1e2e35 /scala/reader.scala | |
| parent | b8ee29b22fbaa7a01f2754b4d6dd9af52e02017c (diff) | |
| download | mal-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.scala | 88 |
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 |
