aboutsummaryrefslogtreecommitdiff
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
parent937f0cdc6614592b9057c023be67b8ff0db8758c (diff)
downloadmal-b94acce656db4f0b129cd939765c0ca451f6a538.tar.gz
mal-b94acce656db4f0b129cd939765c0ca451f6a538.zip
Nim: step1
-rw-r--r--Makefile4
-rw-r--r--nim/Makefile35
-rw-r--r--nim/mal.nimble3
-rw-r--r--nim/nim.cfg1
-rw-r--r--nim/printer.nim15
-rw-r--r--nim/reader.nim97
-rw-r--r--nim/step1_read_print.nim14
-rw-r--r--nim/types.nim33
8 files changed, 200 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 47c7829..0a64d5e 100644
--- a/Makefile
+++ b/Makefile
@@ -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]