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 | |
| parent | 937f0cdc6614592b9057c023be67b8ff0db8758c (diff) | |
| download | mal-b94acce656db4f0b129cd939765c0ca451f6a538.tar.gz mal-b94acce656db4f0b129cd939765c0ca451f6a538.zip | |
Nim: step1
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | nim/Makefile | 35 | ||||
| -rw-r--r-- | nim/mal.nimble | 3 | ||||
| -rw-r--r-- | nim/nim.cfg | 1 | ||||
| -rw-r--r-- | nim/printer.nim | 15 | ||||
| -rw-r--r-- | nim/reader.nim | 97 | ||||
| -rw-r--r-- | nim/step1_read_print.nim | 14 | ||||
| -rw-r--r-- | nim/types.nim | 33 |
8 files changed, 200 insertions, 2 deletions
@@ -12,7 +12,7 @@ PYTHON = python IMPLS = bash c clojure coffee cs forth go haskell java js lua make mal \ ocaml matlab miniMAL perl php ps python r racket ruby rust \ - scala vb + scala vb nim step0 = step0_repl step1 = step1_read_print @@ -76,6 +76,7 @@ ruby_STEP_TO_PROG = ruby/$($(1)).rb rust_STEP_TO_PROG = rust/target/$($(1)) scala_STEP_TO_PROG = scala/$($(1)).scala vb_STEP_TO_PROG = vb/$($(1)).exe +nim_STEP_TO_PROG = nim/$($(1)) # Needed some argument munging COMMA = , @@ -109,6 +110,7 @@ ruby_RUNSTEP = ruby ../$(2) $(3) rust_RUNSTEP = ../$(2) $(3) scala_RUNSTEP = sbt 'run-main $($(1))$(if $(3), $(3),)' vb_RUNSTEP = mono ../$(2) --raw $(3) +nim_RUNSTEP = ../$(2) $(3) # Extra options to pass to runtest.py cs_TEST_OPTS = --redirect diff --git a/nim/Makefile b/nim/Makefile new file mode 100644 index 0000000..5fba42c --- /dev/null +++ b/nim/Makefile @@ -0,0 +1,35 @@ +##################### + +SOURCES_BASE = types.nim reader.nim printer.nim +#SOURCES_LISP = env.nim core.nim stepA_interop.nim +SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) + +##################### + +SRCS = step0_repl.nim step1_read_print.nim +BINS = $(SRCS:%.nim=%) + +##################### + +all: $(BINS) mal + +mal: $(word $(words $(BINS)),$(BINS)) + #nimble build + cp $< $@ + +define dep_template +$(1): $(SOURCES_BASE) $(1).nim + nim c $$@ +endef +$(foreach b,$(BINS),$(eval $(call dep_template,$(b)))) + +clean: + rm -rf nimcache/ $(BINS) + rm -f mal + +.PHONY: stats stats-lisp + +stats: $(SOURCES) + @wc $^ +#stats-lisp: $(SOURCES_LISP) +# @wc $^ diff --git a/nim/mal.nimble b/nim/mal.nimble index f512616..94e85df 100644 --- a/nim/mal.nimble +++ b/nim/mal.nimble @@ -6,6 +6,7 @@ description = "Mal code in Nim" license = "MIT" bin = "step0_repl" +bin = "step1_read_print" [Deps] -Requires: "nim >= 0.10.0" +Requires = "nim >= 0.10.0, nre >= 0.6.0" diff --git a/nim/nim.cfg b/nim/nim.cfg new file mode 100644 index 0000000..cd37578 --- /dev/null +++ b/nim/nim.cfg @@ -0,0 +1 @@ +d: pcreDynlib diff --git a/nim/printer.nim b/nim/printer.nim new file mode 100644 index 0000000..45c21f1 --- /dev/null +++ b/nim/printer.nim @@ -0,0 +1,15 @@ +import strutils, tables, types + +proc pr_str*(m: MalType): string = + case m.kind + of Nil: result = "nil" + of Symbol: result = m.symbol + of Number: result = $m.number + of List: result = "(" & m.list.map(pr_str).join(" ") & ")" + of Vector: result = "[" & m.vector.map(pr_str).join(" ") & "]" + of HashMap: + result = "{" + for key, val in m.hash_map.pairs: + if result.len > 1: result.add " " + result.add key & " " & val.pr_str + result.add "}" 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 diff --git a/nim/step1_read_print.nim b/nim/step1_read_print.nim new file mode 100644 index 0000000..4be5898 --- /dev/null +++ b/nim/step1_read_print.nim @@ -0,0 +1,14 @@ +import rdstdin, types, reader, printer + +proc read(str: string): MalType = str.read_str + +proc eval(ast: MalType): MalType = ast + +proc print(exp: MalType): string = exp.pr_str + +while true: + try: + let line = readLineFromStdin("user> ") + echo line.read.eval.print + except: + echo getCurrentExceptionMsg() diff --git a/nim/types.nim b/nim/types.nim new file mode 100644 index 0000000..866d6db --- /dev/null +++ b/nim/types.nim @@ -0,0 +1,33 @@ +import tables + +type + MalTypeKind* = enum Nil, Number, Symbol, List, Vector, HashMap + + MalType* = object + case kind*: MalTypeKind + of Nil: nil + of Number: number*: int + of Symbol: symbol*: string + of List: list*: seq[MalType] + of Vector: vector*: seq[MalType] + of HashMap: hash_map*: TableRef[string, MalType] + +# Convenience procs +const nilObj*: MalType = MalType(kind: Nil) + +proc number*(x: int): MalType = MalType(kind: Number, number: x) + +proc symbol*(x: string): MalType = MalType(kind: Symbol, symbol: x) + +proc list*(xs: varargs[MalType]): MalType = + result = MalType(kind: List, list: @[]) + for x in xs: result.list.add x + +proc vector*(xs: varargs[MalType]): MalType = + result = MalType(kind: Vector, vector: @[]) + for x in xs: result.vector.add x + +proc hash_map*(xs: varargs[MalType]): MalType = + result = MalType(kind: HashMap, hash_map: newTable[string, MalType]()) + for i in countup(0, xs.high, 2): + result.hash_map[xs[i].symbol] = xs[i+1] |
