aboutsummaryrefslogtreecommitdiff
path: root/nim/reader.nim
diff options
context:
space:
mode:
authordef <dennis@felsin9.de>2015-02-28 14:14:18 +0100
committerdef <dennis@felsin9.de>2015-02-28 14:23:19 +0100
commitb94acce656db4f0b129cd939765c0ca451f6a538 (patch)
treeb18e1bfc4865248ab1578989ecbdbec1e1fd04e2 /nim/reader.nim
parent937f0cdc6614592b9057c023be67b8ff0db8758c (diff)
downloadmal-b94acce656db4f0b129cd939765c0ca451f6a538.tar.gz
mal-b94acce656db4f0b129cd939765c0ca451f6a538.zip
Nim: step1
Diffstat (limited to 'nim/reader.nim')
-rw-r--r--nim/reader.nim97
1 files changed, 97 insertions, 0 deletions
diff --git a/nim/reader.nim b/nim/reader.nim
new file mode 100644
index 0000000..c8f9096
--- /dev/null
+++ b/nim/reader.nim
@@ -0,0 +1,97 @@
+import nre, optional_t, strutils, types
+
+var
+ tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"""
+ intRE = re"-?[0-9]+$"
+
+type Reader = object
+ tokens: seq[string]
+ position: int
+
+proc next(r: var Reader): string =
+ if r.position >= r.tokens.len:
+ result = nil
+ else:
+ result = r.tokens[r.position]
+ inc r.position
+
+proc peek(r: Reader): string =
+ if r.position >= r.tokens.len: nil
+ else: r.tokens[r.position]
+
+proc tokenize(str: string): seq[string] =
+ result = @[]
+ for match in str.findIter(tokenRE):
+ result.add match.captures[0]
+
+proc read_form(r: var Reader): MalType
+
+proc read_seq(r: var Reader, fr, to: string): seq[MalType] =
+ result = @[]
+ var t = r.next
+ if t != fr: raise newException(ValueError, "expected '" & fr & "'")
+
+ t = r.peek
+ while t != to:
+ if t == nil: raise newException(ValueError, "expected '" & to & "', got EOF")
+ result.add r.read_form
+ t = r.peek
+ discard r.next
+
+proc read_list(r: var Reader): MalType =
+ result = list r.read_seq("(", ")")
+
+proc read_vector(r: var Reader): MalType =
+ result = vector r.read_seq("[", "]")
+
+proc read_hash_map(r: var Reader): MalType =
+ result = hash_map r.read_seq("{", "}")
+
+proc read_atom(r: var Reader): MalType =
+ let t = r.next
+ if t.match(intRE): number t.parseInt
+ else: symbol t
+
+proc read_form(r: var Reader): MalType =
+ if r.peek[0] == ';':
+ discard r.next
+ return nilObj
+ case r.peek
+ of "'":
+ discard r.next
+ result = list(symbol "quote", r.read_form)
+ of "`":
+ discard r.next
+ result = list(symbol "quasiquote", r.read_form)
+ of "~":
+ discard r.next
+ result = list(symbol "unquote", r.read_form)
+ of "~@":
+ discard r.next
+ result = list(symbol "splice-unquote", r.read_form)
+ of "^":
+ discard r.next
+ let meta = r.read_form
+ result = list(symbol "with-meta", r.read_form, meta)
+ of "@":
+ discard r.next
+ result = list(symbol "deref", r.read_form)
+
+ # list
+ of "(": result = r.read_list
+ of ")": raise newException(ValueError, "unexpected ')'")
+
+ # vector
+ of "[": result = r.read_vector
+ of "]": raise newException(ValueError, "unexpected ']'")
+
+ # hash-map
+ of "{": result = r.read_hash_map
+ of "}": raise newException(ValueError, "unexpected '}'")
+
+ # atom
+ else: result = r.read_atom
+
+proc read_str*(str: string): MalType =
+ var r = Reader(tokens: str.tokenize)
+ r.read_form