diff options
| author | def <dennis@felsin9.de> | 2015-02-28 14:14:18 +0100 |
|---|---|---|
| committer | def <dennis@felsin9.de> | 2015-02-28 14:23:19 +0100 |
| commit | b94acce656db4f0b129cd939765c0ca451f6a538 (patch) | |
| tree | b18e1bfc4865248ab1578989ecbdbec1e1fd04e2 /nim/reader.nim | |
| parent | 937f0cdc6614592b9057c023be67b8ff0db8758c (diff) | |
| download | mal-b94acce656db4f0b129cd939765c0ca451f6a538.tar.gz mal-b94acce656db4f0b129cd939765c0ca451f6a538.zip | |
Nim: step1
Diffstat (limited to 'nim/reader.nim')
| -rw-r--r-- | nim/reader.nim | 97 |
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 |
