aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-12-18 23:52:59 -0600
committerJoel Martin <github@martintribe.org>2015-01-09 16:16:51 -0600
commita816262a057ecc4bd1fd07750d21cab81490f336 (patch)
treef83bea9965ef09460d213812f738a32a2dc6803c
parent821930dbd9febf45fad25aefa9bc64e8ace4c737 (diff)
downloadmal-a816262a057ecc4bd1fd07750d21cab81490f336.tar.gz
mal-a816262a057ecc4bd1fd07750d21cab81490f336.zip
Scala: refactor collections with metadata.
Convert numeric to Long. Add time-ms. Add Makefile for stats targets.
-rw-r--r--README.md4
-rw-r--r--scala/Makefile20
-rw-r--r--scala/core.scala169
-rw-r--r--scala/env.scala4
-rw-r--r--scala/printer.scala16
-rw-r--r--scala/reader.scala24
-rw-r--r--scala/step2_eval.scala24
-rw-r--r--scala/step3_env.scala32
-rw-r--r--scala/step4_if_fn_do.scala36
-rw-r--r--scala/step5_tco.scala34
-rw-r--r--scala/step6_file.scala36
-rw-r--r--scala/step7_quote.scala58
-rw-r--r--scala/step8_macros.scala77
-rw-r--r--scala/step9_try.scala79
-rw-r--r--scala/stepA_interop.scala229
-rw-r--r--scala/types.scala182
-rw-r--r--tests/step6_file.mal7
17 files changed, 734 insertions, 297 deletions
diff --git a/README.md b/README.md
index 7ed6a7b..9427657 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
## Description
Mal is an interpreter for a subset of the Clojure programming
-language. Mal is implemented from scratch in 18 different languages:
+language. Mal is implemented from scratch in 19 different languages:
* Bash shell
* C
@@ -243,7 +243,7 @@ mono ./stepX_YYY.exe
## Running tests
-The are nearly 400 generic Mal tests (for all implementations) in the
+The are nearly 500 generic Mal tests (for all implementations) in the
`tests/` directory. Each step has a corresponding test file containing
tests specific to that step. The `runtest.py` test harness uses
pexpect to launch a Mal step implementation and then feeds the tests
diff --git a/scala/Makefile b/scala/Makefile
new file mode 100644
index 0000000..10c2e11
--- /dev/null
+++ b/scala/Makefile
@@ -0,0 +1,20 @@
+TESTS =
+
+SOURCES_BASE = types.scala reader.scala printer.scala
+SOURCES_LISP = env.scala core.scala stepA_interop.scala
+SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)
+
+#all: mal.scala
+
+.PHONY: stats tests $(TESTS)
+
+stats: $(SOURCES)
+ @wc $^
+stats-lisp: $(SOURCES_LISP)
+ @wc $^
+
+tests: $(TESTS)
+
+$(TESTS):
+ @echo "Running $@"; \
+ ruby $@ || exit 1; \
diff --git a/scala/core.scala b/scala/core.scala
index 6310f89..3317d08 100644
--- a/scala/core.scala
+++ b/scala/core.scala
@@ -1,6 +1,10 @@
import scala.collection.mutable
import scala.io.Source
+import types.{MalList, _list, _list_Q,
+ MalVector, _vector, _vector_Q,
+ MalHashMap, _hash_map_Q, _hash_map,
+ Func, MalFunction}
import printer._pr_list
object core {
@@ -20,65 +24,106 @@ object core {
}
}
+
+ // number functions
+ def _bool_op(a: List[Any], op: (Long, Long) => Boolean) = {
+ op(a(0).asInstanceOf[Long],a(1).asInstanceOf[Long])
+ }
+
+ def _num_op(a: List[Any], op: (Long, Long) => Long) = {
+ op(a(0).asInstanceOf[Long],a(1).asInstanceOf[Long])
+ }
+
+
// string functions
def read_string(a: List[Any]) = {
reader.read_str(a(0).asInstanceOf[String])
}
def slurp(a: List[Any]) = {
- Source.fromFile(a(0).asInstanceOf[String]).getLines.mkString("\n")
+ Source.fromFile(a(0).asInstanceOf[String]).getLines.mkString("\n") + "\n"
}
// Hash Map functions
def assoc(a: List[Any]): Any = {
- a(0).asInstanceOf[Map[String,Any]] ++
- (types._hash_map(a.drop(1)).asInstanceOf[Map[String,Any]])
+ a(0).asInstanceOf[MalHashMap] ++ _hash_map(a.drop(1):_*)
}
def dissoc(a: List[Any]): Any = {
- var kSet = types._toList(a.drop(1)).toSet
- a(0).asInstanceOf[Map[String,Any]]
+ var kSet = a.drop(1).toSet
+ a(0).asInstanceOf[MalHashMap]
.filterKeys{ !kSet.contains(_) }
}
def get(a: List[Any]): Any = {
- val hm = a(0).asInstanceOf[Map[String,Any]]
+ val hm = a(0).asInstanceOf[MalHashMap]
val key = a(1).asInstanceOf[String]
- if (hm != null && hm.contains(key)) hm(key) else null
+ if (hm != null && hm.value.contains(key)) hm(key) else null
}
def contains_Q(a: List[Any]): Any = {
- a(0).asInstanceOf[Map[String,Any]]
+ a(0).asInstanceOf[MalHashMap].value
.contains(a(1).asInstanceOf[String])
}
// sequence functions
- def concat(a: List[Any]): List[Any] = {
- (for (sq <- a) yield types._toIter(sq)).flatten
+ def concat(a: List[Any]): Any = {
+ _list((for (sq <- a) yield types._toIter(sq)).flatten:_*)
}
def nth(a: List[Any]): Any = {
- val lst = types._toList(a(0))
- val idx = a(1).asInstanceOf[Int]
+ val lst = a(0).asInstanceOf[MalList].value
+ val idx = a(1).asInstanceOf[Long]
if (idx < lst.length) {
- lst(idx)
+ lst(idx.toInt)
} else {
throw new Exception("nth: index out of range")
}
}
def first(a: List[Any]): Any = {
- val lst = types._toList(a(0))
+ val lst = a(0).asInstanceOf[MalList].value
if (lst.length > 0) lst(0) else null
}
+ def rest(a: List[Any]): Any = {
+ a(0) match {
+ case null => true
+ case ml: MalList => _list(ml.drop(1).value:_*)
+ }
+ }
+
+ def empty_Q(a: List[Any]): Any = {
+ a(0) match {
+ case null => true
+ case ml: MalList => ml.value.isEmpty
+ }
+ }
+
+ def count(a: List[Any]): Any = {
+ a(0) match {
+ case null => 0
+ case ml: MalList => ml.value.length.asInstanceOf[Long]
+ }
+ }
+
+ def conj(a: List[Any]): Any = {
+ a(0) match {
+ case mv: MalVector => {
+ _vector(mv.value ++ a.slice(1,a.length):_*)
+ }
+ case ml: MalList => {
+ _list(a.slice(1,a.length).reverse ++ ml.value:_*)
+ }
+ }
+ }
def apply(a: List[Any]): Any = {
a match {
case f :: rest => {
var args1 = rest.slice(0,rest.length-1)
- var args = args1 ++ types._toList(rest(rest.length-1))
+ var args = args1 ++ rest(rest.length-1).asInstanceOf[MalList].value
types._apply(f, args)
}
case _ => throw new Exception("invalid apply call")
@@ -88,13 +133,52 @@ object core {
def do_map(a: List[Any]): Any = {
a match {
case f :: seq :: Nil => {
- types._toList(seq).map(x => types._apply(f,List(x)))
+ seq.asInstanceOf[MalList].map(x => types._apply(f,List(x)))
}
case _ => throw new Exception("invalid map call")
}
}
+ // meta functions
+ def with_meta(a: List[Any]): Any = {
+ val meta: Any = a(1)
+ a(0) match {
+ case ml: MalList => {
+ val new_ml = ml.clone()
+ new_ml.meta = meta
+ new_ml
+ }
+ case hm: MalHashMap => {
+ val new_hm = hm.clone()
+ new_hm.meta = meta
+ new_hm
+ }
+ case fn: Func => {
+ val new_fn = fn.clone()
+ new_fn.meta = meta
+ new_fn
+ }
+ case fn: MalFunction => {
+ val new_fn = fn.clone()
+ new_fn.meta = meta
+ new_fn
+ }
+ case _ => throw new Exception("no meta support for " + a(0).getClass)
+ }
+ }
+
+ def meta(a: List[Any]): Any = {
+ a(0) match {
+ case ml: MalList => ml.meta
+ case hm: MalHashMap => hm.meta
+ case fn: Func => fn.meta
+ case fn: MalFunction => fn.meta
+ case _ => throw new Exception("no meta support for " + a(0).getClass)
+ }
+ }
+
+
// atom functions
def reset_BANG(a: List[Any]): Any = {
a(0).asInstanceOf[types.Atom].value = a(1)
@@ -114,7 +198,7 @@ object core {
}
- val ns: Map[String, Any] = Map(
+ val ns: Map[String, (List[Any]) => Any] = Map(
"=" -> ((a: List[Any]) => types._equal_Q(a(0), a(1))),
"throw" -> mal_throw _,
"nil?" -> ((a: List[Any]) => a(0) == null),
@@ -129,44 +213,47 @@ object core {
"str" -> ((a: List[Any]) => _pr_list(a, false, "")),
"prn" -> ((a: List[Any]) => { println(_pr_list(a, true, " ")); null}),
"println" -> ((a: List[Any]) => { println(_pr_list(a, false, " ")); null}),
+ "readline" -> ((a: List[Any]) => readLine(a(0).asInstanceOf[String])),
"read-string" -> read_string _,
"slurp" -> slurp _,
- "<" -> ((a: List[Any]) => a(0).asInstanceOf[Int] < a(1).asInstanceOf[Int]),
- "<=" -> ((a: List[Any]) => a(0).asInstanceOf[Int] <= a(1).asInstanceOf[Int]),
- ">" -> ((a: List[Any]) => a(0).asInstanceOf[Int] > a(1).asInstanceOf[Int]),
- ">=" -> ((a: List[Any]) => a(0).asInstanceOf[Int] >= a(1).asInstanceOf[Int]),
- "+" -> ((a: List[Any]) => a(0).asInstanceOf[Int] + a(1).asInstanceOf[Int]),
- "-" -> ((a: List[Any]) => a(0).asInstanceOf[Int] - a(1).asInstanceOf[Int]),
- "*" -> ((a: List[Any]) => a(0).asInstanceOf[Int] * a(1).asInstanceOf[Int]),
- "/" -> ((a: List[Any]) => a(0).asInstanceOf[Int] / a(1).asInstanceOf[Int]),
-
- "list" -> ((a: List[Any]) => a),
- "list?" -> ((a: List[Any]) => a(0).isInstanceOf[List[Any]]),
- "vector" -> ((a: List[Any]) => a.toArray),
- "vector?" -> ((a: List[Any]) => a(0).isInstanceOf[Array[Any]]),
- "hash-map" -> ((a: List[Any]) => types._hash_map(a)),
- "map?" -> ((a: List[Any]) => a(0).isInstanceOf[Map[String,Any] @unchecked]),
+
+ "<" -> ((a: List[Any]) => _bool_op(a, _ < _)),
+ "<=" -> ((a: List[Any]) => _bool_op(a, _ <= _)),
+ ">" -> ((a: List[Any]) => _bool_op(a, _ > _)),
+ ">=" -> ((a: List[Any]) => _bool_op(a, _ >= _)),
+ "+" -> ((a: List[Any]) => _num_op(a, _ + _)),
+ "-" -> ((a: List[Any]) => _num_op(a, _ - _)),
+ "*" -> ((a: List[Any]) => _num_op(a, _ * _)),
+ "/" -> ((a: List[Any]) => _num_op(a, _ / _)),
+ "time-ms" -> ((a: List[Any]) => System.currentTimeMillis),
+
+ "list" -> ((a: List[Any]) => _list(a:_*)),
+ "list?" -> ((a: List[Any]) => _list_Q(a(0))),
+ "vector" -> ((a: List[Any]) => _vector(a:_*)),
+ "vector?" -> ((a: List[Any]) => _vector_Q(a(0))),
+ "hash-map" -> ((a: List[Any]) => _hash_map(a:_*)),
+ "map?" -> ((a: List[Any]) => _hash_map_Q(a(0))),
"assoc" -> assoc _,
"dissoc" -> dissoc _,
"get" -> get _,
"contains?" -> contains_Q _,
- "keys" -> ((a: List[Any]) => a(0).asInstanceOf[Map[String,Any]].keys.toList),
- "vals" -> ((a: List[Any]) => a(0).asInstanceOf[Map[String,Any]].values.toList),
+ "keys" -> ((a: List[Any]) => a(0).asInstanceOf[MalHashMap].keys),
+ "vals" -> ((a: List[Any]) => a(0).asInstanceOf[MalHashMap].vals),
"sequential?" -> ((a: List[Any]) => types._sequential_Q(a(0))),
- "cons" -> ((a: List[Any]) => a(0) +: types._toList(a(1))),
+ "cons" -> ((a: List[Any]) => a(0) +: a(1).asInstanceOf[MalList]),
"concat" -> concat _,
"nth" -> nth _,
"first" -> first _,
- "rest" -> ((a: List[Any]) => types._toList(a(0)).drop(1)),
- "empty?" -> ((a: List[Any]) => types._toIter(a(0)).isEmpty),
- "count" -> ((a: List[Any]) => types._toIter(a(0)).length),
- "conj" -> ((a: List[Any]) => null),
+ "rest" -> rest _,
+ "empty?" -> empty_Q _,
+ "count" -> count _,
+ "conj" -> conj _,
"apply" -> apply _,
"map" -> do_map _,
- "with-meta" -> ((a: List[Any]) => null),
- "meta" -> ((a: List[Any]) => null),
+ "with-meta" -> with_meta _,
+ "meta" -> meta _,
"atom" -> ((a: List[Any]) => new types.Atom(a(0))),
"atom?" -> ((a: List[Any]) => a(0).isInstanceOf[types.Atom]),
"deref" -> ((a: List[Any]) => a(0).asInstanceOf[types.Atom].value),
diff --git a/scala/env.scala b/scala/env.scala
index 9b6cff8..33be545 100644
--- a/scala/env.scala
+++ b/scala/env.scala
@@ -1,3 +1,5 @@
+import types._list
+
import scala.collection.mutable
object env {
@@ -9,7 +11,7 @@ object env {
binds.foreach(b => {
val k = b.asInstanceOf[Symbol]
if (k == '&) {
- data(binds.next().asInstanceOf[Symbol]) = exprs.toList
+ data(binds.next().asInstanceOf[Symbol]) = _list(exprs.toSeq:_*)
} else {
data(k) = exprs.next()
}
diff --git a/scala/printer.scala b/scala/printer.scala
index 74b1433..0a0e0b7 100644
--- a/scala/printer.scala
+++ b/scala/printer.scala
@@ -1,15 +1,13 @@
-import types.Function
+import types.{MalList, MalVector, MalHashMap, MalFunction}
+
object printer {
def _pr_str(obj: Any, print_readably: Boolean = true): String = {
val _r = print_readably
return obj match {
- case l: List[Any] => "(" + l.map(_pr_str(_, _r)).mkString(" ") + ")"
- case v: Array[Any] => "[" + v.map(_pr_str(_, _r)).mkString(" ") + "]"
- case m: Map[String @unchecked,Any @unchecked] => {
- val lst = m.map{case (k,v) => List(k, v)}.flatten
- "{" + lst.map(_pr_str(_,_r)).mkString(" ") + "}"
- }
+ case v: MalVector => v.toString(_r)
+ case l: MalList => l.toString(_r)
+ case hm: MalHashMap => hm.toString(_r)
case s: String => {
if (s.length > 0 && s(0) == '\u029e') {
":" + s.substring(1,s.length)
@@ -26,8 +24,8 @@ object printer {
case a: types.Atom => "(atom " + a.value + ")"
case null => "nil"
case _ => {
- if (obj.isInstanceOf[Function]) {
- val f = obj.asInstanceOf[Function]
+ if (obj.isInstanceOf[MalFunction]) {
+ val f = obj.asInstanceOf[MalFunction]
"<function (fn* " + _pr_str(f.params) + " " + _pr_str(f.ast) + ")>"
} else {
obj.toString
diff --git a/scala/reader.scala b/scala/reader.scala
index fc16f28..de45923 100644
--- a/scala/reader.scala
+++ b/scala/reader.scala
@@ -1,5 +1,7 @@
import scala.util.matching.Regex
+import types.{MalList, _list, MalVector, _vector, MalHashMap, _hash_map}
+
object reader {
class Reader (tokens: Array[String]) {
@@ -34,7 +36,7 @@ object reader {
val re_str = """^"(.*)"$""".r
val re_key = """^:(.*)$""".r
return token match {
- case re_int(i) => i.toInt // integer
+ case re_int(i) => i.toLong // integer
case re_flt(f) => f.toDouble // float
case re_str(s) => parse_str(s) // string
case re_key(k) => "\u029e" + k // keyword
@@ -46,8 +48,8 @@ object reader {
}
def read_list(rdr: Reader,
- start: String = "(", end: String = ")"): List[Any] = {
- var ast: List[Any] = List()
+ start: String = "(", end: String = ")"): MalList = {
+ var ast: MalList = _list()
var token = rdr.next()
if (token != start) throw new Exception("expected '" + start + "', got EOF")
while ({token = rdr.peek(); token != end}) {
@@ -60,19 +62,19 @@ object reader {
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; _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)) }
+ _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 "[" => _vector(read_list(rdr, "[", "]").value:_*)
case "]" => throw new Exception("unexpected ']')")
- case "{" => types._hash_map(read_list(rdr, "{", "}"))
+ case "{" => _hash_map(read_list(rdr, "{", "}").value:_*)
case "}" => throw new Exception("unexpected '}')")
case _ => read_atom(rdr)
}
diff --git a/scala/step2_eval.scala b/scala/step2_eval.scala
index b7b209d..d31d339 100644
--- a/scala/step2_eval.scala
+++ b/scala/step2_eval.scala
@@ -1,4 +1,4 @@
-import reader.tokenize
+import types.{MalList, _list_Q, MalVector, MalHashMap, MalFunction}
object step2_eval {
// read
@@ -10,10 +10,10 @@ object step2_eval {
def eval_ast(ast: Any, env: Map[Symbol,Any]): Any = {
ast match {
case s : Symbol => env(s)
- case l: List[Any] => l.map(EVAL(_, env))
- case v: Array[Any] => v.map(EVAL(_, env)).toArray
- case m: Map[String @unchecked,Any @unchecked] => {
- m.map{case (k: String,v: Any) => (k, EVAL(v, env))}.toMap
+ case v: MalVector => v.map(EVAL(_, env))
+ case l: MalList => l.map(EVAL(_, env))
+ case m: MalHashMap => {
+ m.map{case (k: String,v: Any) => (k, EVAL(v, env))}
}
case _ => ast
}
@@ -21,15 +21,15 @@ object step2_eval {
def EVAL(ast: Any, env: Map[Symbol,Any]): Any = {
//println("EVAL: " + printer._pr_str(ast,true))
- if (!ast.isInstanceOf[List[Any]])
+ if (!_list_Q(ast))
return eval_ast(ast, env)
// apply list
- eval_ast(ast, env) match {
+ eval_ast(ast, env).asInstanceOf[MalList].value match {
case f :: el => {
var fn: List[Any] => Any = null
try {
- fn = f.asInstanceOf[(List[Any]) => Any]
+ fn = f.asInstanceOf[List[Any] => Any]
} catch {
case _: Throwable =>
throw new Exception("attempt to call non-function")
@@ -48,10 +48,10 @@ object step2_eval {
// repl
def main(args: Array[String]) = {
val repl_env: Map[Symbol,Any] = Map(
- '+ -> ((a: List[Any]) => a(0).asInstanceOf[Int] + a(1).asInstanceOf[Int]),
- '- -> ((a: List[Any]) => a(0).asInstanceOf[Int] - a(1).asInstanceOf[Int]),
- '* -> ((a: List[Any]) => a(0).asInstanceOf[Int] * a(1).asInstanceOf[Int]),
- '/ -> ((a: List[Any]) => a(0).asInstanceOf[Int] / a(1).asInstanceOf[Int]))
+ '+ -> ((a: List[Any]) => a(0).asInstanceOf[Long] + a(1).asInstanceOf[Long]),
+ '- -> ((a: List[Any]) => a(0).asInstanceOf[Long] - a(1).asInstanceOf[Long]),
+ '* -> ((a: List[Any]) => a(0).asInstanceOf[Long] * a(1).asInstanceOf[Long]),
+ '/ -> ((a: List[Any]) => a(0).asInstanceOf[Long] / a(1).asInstanceOf[Long]))
val REP = (str: String) => {
PRINT(EVAL(READ(str), repl_env))
}
diff --git a/scala/step3_env.scala b/scala/step3_env.scala
index 12d335d..37572fe 100644
--- a/scala/step3_env.scala
+++ b/scala/step3_env.scala
@@ -1,3 +1,4 @@
+import types.{MalList, _list_Q, MalVector, MalHashMap, MalFunction}
import env.Env
object step3_env {
@@ -10,10 +11,10 @@ object step3_env {
def eval_ast(ast: Any, env: Env): Any = {
ast match {
case s : Symbol => env.get(s)
- case l: List[Any] => l.map(EVAL(_, env))
- case v: Array[Any] => v.map(EVAL(_, env)).toArray
- case m: Map[String @unchecked,Any @unchecked] => {
- m.map{case (k: String,v: Any) => (k, EVAL(v, env))}.toMap
+ case v: MalVector => v.map(EVAL(_, env))
+ case l: MalList => l.map(EVAL(_, env))
+ case m: MalHashMap => {
+ m.map{case (k: String,v: Any) => (k, EVAL(v, env))}
}
case _ => ast
}
@@ -21,29 +22,24 @@ object step3_env {
def EVAL(ast: Any, env: Env): Any = {
//println("EVAL: " + printer._pr_str(ast,true))
- if (!ast.isInstanceOf[List[Any]])
+ if (!_list_Q(ast))
return eval_ast(ast, env)
// apply list
- ast.asInstanceOf[List[Any]] match {
+ ast.asInstanceOf[MalList].value match {
case Symbol("def!") :: a1 :: a2 :: Nil => {
return env.set(a1.asInstanceOf[Symbol], EVAL(a2, env))
}
case Symbol("let*") :: a1 :: a2 :: Nil => {
val let_env = new Env(env)
- val it: Iterator[Any] = a1 match {
- case l: List[Any] => l.iterator
- case v: Array[Any] => v.iterator
- case _ => throw new Exception("let* non-sequence bindings")
- }
- for (g <- it.grouped(2)) {
+ for (g <- a1.asInstanceOf[MalList].value.grouped(2)) {
let_env.set(g(0).asInstanceOf[Symbol],EVAL(g(1),let_env))
}
return EVAL(a2, let_env)
}
case _ => {
// function call
- eval_ast(ast, env) match {
+ eval_ast(ast, env).asInstanceOf[MalList].value match {
case f :: el => {
var fn: List[Any] => Any = null
try {
@@ -68,10 +64,10 @@ object step3_env {
// repl
def main(args: Array[String]) = {
val repl_env: Env = new Env()
- repl_env.set('+, (a: List[Any]) => a(0).asInstanceOf[Int] + a(1).asInstanceOf[Int])
- repl_env.set('-, (a: List[Any]) => a(0).asInstanceOf[Int] - a(1).asInstanceOf[Int])
- repl_env.set('*, (a: List[Any]) => a(0).asInstanceOf[Int] * a(1).asInstanceOf[Int])
- repl_env.set('/, (a: List[Any]) => a(0).asInstanceOf[Int] / a(1).asInstanceOf[Int])
+ repl_env.set('+, (a: List[Any]) => a(0).asInstanceOf[Long] + a(1).asInstanceOf[Long])
+ repl_env.set('-, (a: List[Any]) => a(0).asInstanceOf[Long] - a(1).asInstanceOf[Long])
+ repl_env.set('*, (a: List[Any]) => a(0).asInstanceOf[Long] * a(1).asInstanceOf[Long])
+ repl_env.set('/, (a: List[Any]) => a(0).asInstanceOf[Long] / a(1).asInstanceOf[Long])
val REP = (str: String) => {
PRINT(EVAL(READ(str), repl_env))
}
@@ -81,7 +77,7 @@ object step3_env {
try {
println(REP(line))
} catch {
- case e : Exception => {
+ case e : Throwable => {
println("Error: " + e.getMessage)
println(" " + e.getStackTrace.mkString("\n "))
}
diff --git a/scala/step4_if_fn_do.scala b/scala/step4_if_fn_do.scala
index a7a6b22..b6c2dc1 100644
--- a/scala/step4_if_fn_do.scala
+++ b/scala/step4_if_fn_do.scala
@@ -1,3 +1,5 @@
+import types.{MalList, _list, _list_Q, MalVector, MalHashMap,
+ Func, MalFunction}
import env.Env
object step4_if_fn_do {
@@ -10,10 +12,10 @@ object step4_if_fn_do {
def eval_ast(ast: Any, env: Env): Any = {
ast match {
case s : Symbol => env.get(s)
- case l: List[Any] => l.map(EVAL(_, env))
- case v: Array[Any] => v.map(EVAL(_, env)).toArray
- case m: Map[String @unchecked,Any @unchecked] => {
- m.map{case (k: String,v: Any) => (k, EVAL(v, env))}.toMap
+ case v: MalVector => v.map(EVAL(_, env))
+ case l: MalList => l.map(EVAL(_, env))
+ case m: MalHashMap => {
+ m.map{case (k: String,v: Any) => (k, EVAL(v, env))}
}
case _ => ast
}
@@ -21,24 +23,24 @@ object step4_if_fn_do {
def EVAL(ast: Any, env: Env): Any = {
//println("EVAL: " + printer._pr_str(ast,true))
- if (!ast.isInstanceOf[List[Any]])
+ if (!_list_Q(ast))
return eval_ast(ast, env)
// apply list
- ast.asInstanceOf[List[Any]] match {
+ ast.asInstanceOf[MalList].value match {
case Symbol("def!") :: a1 :: a2 :: Nil => {
return env.set(a1.asInstanceOf[Symbol], EVAL(a2, env))
}
case Symbol("let*") :: a1 :: a2 :: Nil => {
val let_env = new Env(env)
- for (g <- types._toIter(a1).grouped(2)) {
+ for (g <- a1.asInstanceOf[MalList].value.grouped(2)) {
let_env.set(g(0).asInstanceOf[Symbol],EVAL(g(1),let_env))
}
return EVAL(a2, let_env)
}
case Symbol("do") :: rest => {
- val el = eval_ast(rest, env)
- return el.asInstanceOf[List[Any]].last
+ val el = eval_ast(_list(rest:_*), env)
+ return el.asInstanceOf[MalList].value.last
}
case Symbol("if") :: a1 :: a2 :: rest => {
val cond = EVAL(a1, env)
@@ -50,17 +52,17 @@ object step4_if_fn_do {
}
}
case Symbol("fn*") :: a1 :: a2 :: Nil => {
- return (args: List[Any]) => {
+ return new Func((args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
- }
+ })
}
case _ => {
// function call
- eval_ast(ast, env) match {
+ eval_ast(ast, env).asInstanceOf[MalList].value match {
case f :: el => {
- var fn: List[Any] => Any = null
+ var fn: Func = null
try {
- fn = f.asInstanceOf[(List[Any]) => Any]
+ fn = f.asInstanceOf[Func]
} catch {
case _: Throwable =>
throw new Exception("attempt to call non-function")
@@ -84,7 +86,9 @@ object step4_if_fn_do {
val REP = (str: String) => PRINT(EVAL(READ(str), repl_env))
// core.scala: defined using scala
- core.ns.map{case (k: String,v: Any) => { repl_env.set(Symbol(k), v) }}
+ core.ns.map{case (k: String,v: Any) => {
+ repl_env.set(Symbol(k), new Func(v))
+ }}
// core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
@@ -94,7 +98,7 @@ object step4_if_fn_do {
try {
println(REP(line))
} catch {
- case e : Exception => {
+ case e : Throwable => {
println("Error: " + e.getMessage)
println(" " + e.getStackTrace.mkString("\n "))
}
diff --git a/scala/step5_tco.scala b/scala/step5_tco.scala
index d54eaa7..c4511e5 100644
--- a/scala/step5_tco.scala
+++ b/scala/step5_tco.scala
@@ -1,3 +1,5 @@
+import types.{MalList, _list, _list_Q, MalVector, MalHashMap,
+ Func, MalFunction}
import env.Env
object step5_tco {
@@ -10,10 +12,10 @@ object step5_tco {
def eval_ast(ast: Any, env: Env): Any = {
ast match {
case s : Symbol => env.get(s)
- case l: List[Any] => l.map(EVAL(_, env))
- case v: Array[Any] => v.map(EVAL(_, env)).toArray
- case m: Map[String @unchecked,Any @unchecked] => {
- m.map{case (k: String,v: Any) => (k, EVAL(v, env))}.toMap
+ case v: MalVector => v.map(EVAL(_, env))
+ case l: MalList => l.map(EVAL(_, env))
+ case m: MalHashMap => {
+ m.map{case (k: String,v: Any) => (k, EVAL(v, env))}
}
case _ => ast
}
@@ -24,25 +26,25 @@ object step5_tco {
while (true) {
//println("EVAL: " + printer._pr_str(ast,true))
- if (!ast.isInstanceOf[List[Any]])
+ if (!_list_Q(ast))
return eval_ast(ast, env)
// apply list
- ast.asInstanceOf[List[Any]] match {
+ ast.asInstanceOf[MalList].value match {
case Symbol("def!") :: a1 :: a2 :: Nil => {
return env.set(a1.asInstanceOf[Symbol], EVAL(a2, env))
}
case Symbol("let*") :: a1 :: a2 :: Nil => {
val let_env = new Env(env)
- for (g <- types._toIter(a1).grouped(2)) {
+ for (g <- a1.asInstanceOf[MalList].value.grouped(2)) {
let_env.set(g(0).asInstanceOf[Symbol],EVAL(g(1),let_env))
}
env = let_env
ast = a2 // continue loop (TCO)
}
case Symbol("do") :: rest => {
- eval_ast(rest.slice(1,rest.length-1), env)
- ast = ast.asInstanceOf[List[Any]].last // continue loop (TCO)
+ eval_ast(_list(rest.slice(0,rest.length-1):_*), env)
+ ast = ast.asInstanceOf[MalList].value.last // continue loop (TCO)
}
case Symbol("if") :: a1 :: a2 :: rest => {
val cond = EVAL(a1, env)
@@ -54,7 +56,7 @@ object step5_tco {
}
}
case Symbol("fn*") :: a1 :: a2 :: Nil => {
- return new types.Function(a2, env, a1.asInstanceOf[List[Any]],
+ return new MalFunction(a2, env, a1.asInstanceOf[MalList],
(args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
}
@@ -62,18 +64,18 @@ object step5_tco {
}
case _ => {
// function call
- eval_ast(ast, env) match {
+ eval_ast(ast, env).asInstanceOf[MalList].value match {
case f :: el => {
f match {
- case fn: types.Function => {
+ case fn: MalFunction => {
env = fn.gen_env(el)
ast = fn.ast // continue loop (TCO)
}
- case fn: ((List[Any]) => Any) @unchecked => {
+ case fn: Func => {
return fn(el)
}
case _ => {
- throw new Exception("attempt to call non-function")
+ throw new Exception("attempt to call non-function: " + f)
}
}
}
@@ -95,7 +97,9 @@ object step5_tco {
val REP = (str: String) => PRINT(EVAL(READ(str), repl_env))
// core.scala: defined using scala
- core.ns.map{case (k: String,v: Any) => { repl_env.set(Symbol(k), v) }}
+ core.ns.map{case (k: String,v: Any) => {
+ repl_env.set(Symbol(k), new Func(v))
+ }}
// core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
diff --git a/scala/step6_file.scala b/scala/step6_file.scala
index 0b4d228..0dad7cd 100644
--- a/scala/step6_file.scala
+++ b/scala/step6_file.scala
@@ -1,3 +1,5 @@
+import types.{MalList, _list, _list_Q, MalVector, MalHashMap,
+ Func, MalFunction}
import env.Env
object step6_file {
@@ -10,10 +12,10 @@ object step6_file {
def eval_ast(ast: Any, env: Env): Any = {
ast match {
case s : Symbol => env.get(s)
- case l: List[Any] => l.map(EVAL(_, env))
- case v: Array[Any] => v.map(EVAL(_, env)).toArray
- case m: Map[String @unchecked,Any @unchecked] => {
- m.map{case (k: String,v: Any) => (k, EVAL(v, env))}.toMap
+ case v: MalVector => v.map(EVAL(_, env))
+ case l: MalList => l.map(EVAL(_, env))
+ case m: MalHashMap => {
+ m.map{case (k: String,v: Any) => (k, EVAL(v, env))}
}
case _ => ast
}
@@ -24,25 +26,25 @@ object step6_file {
while (true) {
//println("EVAL: " + printer._pr_str(ast,true))
- if (!ast.isInstanceOf[List[Any]])
+ if (!_list_Q(ast))
return eval_ast(ast, env)
// apply list
- ast.asInstanceOf[List[Any]] match {
+ ast.asInstanceOf[MalList].value match {
case Symbol("def!") :: a1 :: a2 :: Nil => {
return env.set(a1.asInstanceOf[Symbol], EVAL(a2, env))
}
case Symbol("let*") :: a1 :: a2 :: Nil => {
val let_env = new Env(env)
- for (g <- types._toIter(a1).grouped(2)) {
+ for (g <- a1.asInstanceOf[MalList].value.grouped(2)) {
let_env.set(g(0).asInstanceOf[Symbol],EVAL(g(1),let_env))
}
env = let_env
ast = a2 // continue loop (TCO)
}
case Symbol("do") :: rest => {
- eval_ast(rest.slice(0,rest.length-1), env)
- ast = ast.asInstanceOf[List[Any]].last // continue loop (TCO)
+ eval_ast(_list(rest.slice(0,rest.length-1):_*), env)
+ ast = ast.asInstanceOf[MalList].value.last // continue loop (TCO)
}
case Symbol("if") :: a1 :: a2 :: rest => {
val cond = EVAL(a1, env)
@@ -54,7 +56,7 @@ object step6_file {
}
}
case Symbol("fn*") :: a1 :: a2 :: Nil => {
- return new types.Function(a2, env, a1.asInstanceOf[List[Any]],
+ return new MalFunction(a2, env, a1.asInstanceOf[MalList],
(args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
}
@@ -62,14 +64,14 @@ object step6_file {
}
case _ => {
// function call
- eval_ast(ast, env) match {
+ eval_ast(ast, env).asInstanceOf[MalList].value match {
case f :: el => {
f match {
- case fn: types.Function => {
+ case fn: MalFunction => {
env = fn.gen_env(el)
ast = fn.ast // continue loop (TCO)
}
- case fn: ((List[Any]) => Any) @unchecked => {
+ case fn: Func => {
return fn(el)
}
case _ => {
@@ -95,9 +97,11 @@ object step6_file {
val REP = (str: String) => PRINT(EVAL(READ(str), repl_env))
// core.scala: defined using scala
- core.ns.map{case (k: String,v: Any) => { repl_env.set(Symbol(k), v) }}
- repl_env.set(Symbol("eval"), (a: List[Any]) => EVAL(a(0), repl_env))
- repl_env.set(Symbol("*ARGV*"), args.slice(1,args.length).toList)
+ core.ns.map{case (k: String,v: Any) => {
+ repl_env.set(Symbol(k), new Func(v))
+ }}
+ repl_env.set(Symbol("eval"), new Func((a: List[Any]) => EVAL(a(0), repl_env)))
+ repl_env.set(Symbol("*ARGV*"), _list(args.slice(1,args.length):_*))
// core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
diff --git a/scala/step7_quote.scala b/scala/step7_quote.scala
index 1bb617a..3f0a4d8 100644
--- a/scala/step7_quote.scala
+++ b/scala/step7_quote.scala
@@ -1,3 +1,5 @@
+import types.{MalList, _list, _list_Q, MalVector, MalHashMap,
+ Func, MalFunction}
import env.Env
object step7_quote {
@@ -8,39 +10,39 @@ object step7_quote {
// eval
def is_pair(x: Any): Boolean = {
- types._sequential_Q(x) && types._toIter(x).length > 0
+ types._sequential_Q(x) && x.asInstanceOf[MalList].value.length > 0
}
def quasiquote(ast: Any): Any = {
if (!is_pair(ast)) {
- return List(Symbol("quote"), ast)
+ return _list(Symbol("quote"), ast)
} else {
- val a0 = types._toList(ast)(0)
+ val a0 = ast.asInstanceOf[MalList](0)
if (types._symbol_Q(a0) &&
a0.asInstanceOf[Symbol].name == "unquote") {
- return types._toList(ast)(1)
+ return ast.asInstanceOf[MalList](1)
} else if (is_pair(a0)) {
- val a00 = types._toList(a0)(0)
+ val a00 = a0.asInstanceOf[MalList](0)
if (types._symbol_Q(a00) &&
a00.asInstanceOf[Symbol].name == "splice-unquote") {
- return List(Symbol("concat"),
- types._toList(a0)(1),
- quasiquote(types._toList(ast).drop(1)))
+ return _list(Symbol("concat"),
+ a0.asInstanceOf[MalList](1),
+ quasiquote(ast.asInstanceOf[MalList].drop(1)))
}
}
- return List(Symbol("cons"),
- quasiquote(a0),
- quasiquote(types._toList(ast).drop(1)))
+ return _list(Symbol("cons"),
+ quasiquote(a0),
+ quasiquote(ast.asInstanceOf[MalList].drop(1)))
}
}
def eval_ast(ast: Any, env: Env): Any = {
ast match {
case s : Symbol => env.get(s)
- case l: List[Any] => l.map(EVAL(_, env))
- case v: Array[Any] => v.map(EVAL(_, env)).toArray
- case m: Map[String @unchecked,Any @unchecked] => {
- m.map{case (k: String,v: Any) => (k, EVAL(v, env))}.toMap
+ case v: MalVector => v.map(EVAL(_, env))
+ case l: MalList => l.map(EVAL(_, env))
+ case m: MalHashMap => {
+ m.map{case (k: String,v: Any) => (k, EVAL(v, env))}
}
case _ => ast
}
@@ -51,17 +53,17 @@ object step7_quote {
while (true) {
//println("EVAL: " + printer._pr_str(ast,true))
- if (!ast.isInstanceOf[List[Any]])
+ if (!_list_Q(ast))
return eval_ast(ast, env)
// apply list
- ast.asInstanceOf[List[Any]] match {
+ ast.asInstanceOf[MalList].value match {
case Symbol("def!") :: a1 :: a2 :: Nil => {
return env.set(a1.asInstanceOf[Symbol], EVAL(a2, env))
}
case Symbol("let*") :: a1 :: a2 :: Nil => {
val let_env = new Env(env)
- for (g <- types._toIter(a1).grouped(2)) {
+ for (g <- a1.asInstanceOf[MalList].value.grouped(2)) {
let_env.set(g(0).asInstanceOf[Symbol],EVAL(g(1),let_env))
}
env = let_env
@@ -74,8 +76,8 @@ object step7_quote {
ast = quasiquote(a1) // continue loop (TCO)
}
case Symbol("do") :: rest => {
- eval_ast(rest.slice(0,rest.length-1), env)
- ast = ast.asInstanceOf[List[Any]].last // continue loop (TCO)
+ eval_ast(_list(rest.slice(0,rest.length-1):_*), env)
+ ast = ast.asInstanceOf[MalList].value.last // continue loop (TCO)
}
case Symbol("if") :: a1 :: a2 :: rest => {
val cond = EVAL(a1, env)
@@ -87,7 +89,7 @@ object step7_quote {
}
}
case Symbol("fn*") :: a1 :: a2 :: Nil => {
- return new types.Function(a2, env, a1.asInstanceOf[List[Any]],
+ return new MalFunction(a2, env, a1.asInstanceOf[MalList],
(args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
}
@@ -95,14 +97,14 @@ object step7_quote {
}
case _ => {
// function call
- eval_ast(ast, env) match {
+ eval_ast(ast, env).asInstanceOf[MalList].value match {
case f :: el => {
f match {
- case fn: types.Function => {
+ case fn: MalFunction => {
env = fn.gen_env(el)
ast = fn.ast // continue loop (TCO)
}
- case fn: ((List[Any]) => Any) @unchecked => {
+ case fn: Func => {
return fn(el)
}
case _ => {
@@ -128,9 +130,11 @@ object step7_quote {
val REP = (str: String) => PRINT(EVAL(READ(str), repl_env))
// core.scala: defined using scala
- core.ns.map{case (k: String,v: Any) => { repl_env.set(Symbol(k), v) }}
- repl_env.set(Symbol("eval"), (a: List[Any]) => EVAL(a(0), repl_env))
- repl_env.set(Symbol("*ARGV*"), args.slice(1,args.length).toList)
+ core.ns.map{case (k: String,v: Any) => {
+ repl_env.set(Symbol(k), new Func(v))
+ }}
+ repl_env.set(Symbol("eval"), new Func((a: List[Any]) => EVAL(a(0), repl_env)))
+ repl_env.set(Symbol("*ARGV*"), _list(args.slice(1,args.length):_*))
// core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
diff --git a/scala/step8_macros.scala b/scala/step8_macros.scala
index 8e4cc56..e1a2222 100644
--- a/scala/step8_macros.scala
+++ b/scala/step8_macros.scala
@@ -1,5 +1,6 @@
+import types.{MalList, _list, _list_Q, MalVector, MalHashMap,
+ Func, MalFunction}
import env.Env
-import types.Function
object step8_macros {
// read
@@ -9,39 +10,39 @@ object step8_macros {
// eval
def is_pair(x: Any): Boolean = {
- types._sequential_Q(x) && types._toIter(x).length > 0
+ types._sequential_Q(x) && x.asInstanceOf[MalList].value.length > 0
}
def quasiquote(ast: Any): Any = {
if (!is_pair(ast)) {
- return List(Symbol("quote"), ast)
+ return _list(Symbol("quote"), ast)
} else {
- val a0 = types._toList(ast)(0)
+ val a0 = ast.asInstanceOf[MalList](0)
if (types._symbol_Q(a0) &&
a0.asInstanceOf[Symbol].name == "unquote") {
- return types._toList(ast)(1)
+ return ast.asInstanceOf[MalList](1)
} else if (is_pair(a0)) {
- val a00 = types._toList(a0)(0)
+ val a00 = a0.asInstanceOf[MalList](0)
if (types._symbol_Q(a00) &&
a00.asInstanceOf[Symbol].name == "splice-unquote") {
- return List(Symbol("concat"),
- types._toList(a0)(1),
- quasiquote(types._toList(ast).drop(1)))
+ return _list(Symbol("concat"),
+ a0.asInstanceOf[MalList](1),
+ quasiquote(ast.asInstanceOf[MalList].drop(1)))
}
}
- return List(Symbol("cons"),
- quasiquote(a0),
- quasiquote(types._toList(ast).drop(1)))
+ return _list(Symbol("cons"),
+ quasiquote(a0),
+ quasiquote(ast.asInstanceOf[MalList].drop(1)))
}
}
def is_macro_call(ast: Any, env: Env): Boolean = {
ast match {
- case l: List[Any] => {
- if (types._symbol_Q(l(0)) &&
- env.find(l(0).asInstanceOf[Symbol]) != null) {
- env.get(l(0).asInstanceOf[Symbol]) match {
- case f: Function => return f.ismacro
+ case ml: MalList => {
+ if (types._symbol_Q(ml(0)) &&
+ env.find(ml(0).asInstanceOf[Symbol]) != null) {
+ env.get(ml(0).asInstanceOf[Symbol]) match {
+ case f: MalFunction => return f.ismacro
case _ => return false
}
}
@@ -54,10 +55,10 @@ object step8_macros {
def macroexpand(orig_ast: Any, env: Env): Any = {
var ast = orig_ast;
while (is_macro_call(ast, env)) {
- ast.asInstanceOf[List[Any]] match {
+ ast.asInstanceOf[MalList].value match {
case f :: args => {
val mac = env.get(f.asInstanceOf[Symbol])
- ast = mac.asInstanceOf[Function](args)
+ ast = mac.asInstanceOf[MalFunction](args)
}
case _ => throw new Exception("macroexpand: invalid call")
}
@@ -68,10 +69,10 @@ object step8_macros {
def eval_ast(ast: Any, env: Env): Any = {
ast match {
case s : Symbol => env.get(s)
- case l: List[Any] => l.map(EVAL(_, env))
- case v: Array[Any] => v.map(EVAL(_, env)).toArray
- case m: Map[String @unchecked,Any @unchecked] => {
- m.map{case (k: String,v: Any) => (k, EVAL(v, env))}.toMap
+ case v: MalVector => v.map(EVAL(_, env))
+ case l: MalList => l.map(EVAL(_, env))
+ case m: MalHashMap => {
+ m.map{case (k: String,v: Any) => (k, EVAL(v, env))}
}
case _ => ast
}
@@ -82,20 +83,20 @@ object step8_macros {
while (true) {
//println("EVAL: " + printer._pr_str(ast,true))
- if (!ast.isInstanceOf[List[Any]])
+ if (!_list_Q(ast))
return eval_ast(ast, env)
// apply list
ast = macroexpand(ast, env)
- if (!ast.isInstanceOf[List[Any]]) return ast
+ if (!_list_Q(ast)) return ast
- ast.asInstanceOf[List[Any]] match {
+ ast.asInstanceOf[MalList].value match {
case Symbol("def!") :: a1 :: a2 :: Nil => {
return env.set(a1.asInstanceOf[Symbol], EVAL(a2, env))
}
case Symbol("let*") :: a1 :: a2 :: Nil => {
val let_env = new Env(env)
- for (g <- types._toIter(a1).grouped(2)) {
+ for (g <- a1.asInstanceOf[MalList].value.grouped(2)) {
let_env.set(g(0).asInstanceOf[Symbol],EVAL(g(1),let_env))
}
env = let_env
@@ -109,15 +110,15 @@ object step8_macros {
}
case Symbol("defmacro!") :: a1 :: a2 :: Nil => {
val f = EVAL(a2, env)
- f.asInstanceOf[Function].ismacro = true
+ f.asInstanceOf[MalFunction].ismacro = true
return env.set(a1.asInstanceOf[Symbol], f)
}
case Symbol("macroexpand") :: a1 :: Nil => {
return macroexpand(a1, env)
}
case Symbol("do") :: rest => {
- eval_ast(rest.slice(0,rest.length-1), env)
- ast = ast.asInstanceOf[List[Any]].last // continue loop (TCO)
+ eval_ast(_list(rest.slice(0,rest.length-1):_*), env)
+ ast = ast.asInstanceOf[MalList].value.last // continue loop (TCO)
}
case Symbol("if") :: a1 :: a2 :: rest => {
val cond = EVAL(a1, env)
@@ -129,7 +130,7 @@ object step8_macros {
}
}
case Symbol("fn*") :: a1 :: a2 :: Nil => {
- return new Function(a2, env, types._toList(a1),
+ return new MalFunction(a2, env, a1.asInstanceOf[MalList],
(args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
}
@@ -137,14 +138,14 @@ object step8_macros {
}
case _ => {
// function call
- eval_ast(ast, env) match {
+ eval_ast(ast, env).asInstanceOf[MalList].value match {
case f :: el => {
f match {
- case fn: Function => {
+ case fn: MalFunction => {
env = fn.gen_env(el)
ast = fn.ast // continue loop (TCO)
}
- case fn: ((List[Any]) => Any) @unchecked => {
+ case fn: Func => {
return fn(el)
}
case _ => {
@@ -170,9 +171,11 @@ object step8_macros {
val REP = (str: String) => PRINT(EVAL(READ(str), repl_env))
// core.scala: defined using scala
- core.ns.map{case (k: String,v: Any) => { repl_env.set(Symbol(k), v) }}
- repl_env.set(Symbol("eval"), (a: List[Any]) => EVAL(a(0), repl_env))
- repl_env.set(Symbol("*ARGV*"), args.slice(1,args.length).toList)
+ core.ns.map{case (k: String,v: Any) => {
+ repl_env.set(Symbol(k), new Func(v))
+ }}
+ repl_env.set(Symbol("eval"), new Func((a: List[Any]) => EVAL(a(0), repl_env)))
+ repl_env.set(Symbol("*ARGV*"), _list(args.slice(1,args.length):_*))
// core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
diff --git a/scala/step9_try.scala b/scala/step9_try.scala
index 200d3cf..02c19be 100644
--- a/scala/step9_try.scala
+++ b/scala/step9_try.scala
@@ -1,5 +1,6 @@
+import types.{MalList, _list, _list_Q, MalVector, MalHashMap,
+ Func, MalFunction}
import env.Env
-import types.Function
object step9_try {
// read
@@ -9,39 +10,39 @@ object step9_try {
// eval
def is_pair(x: Any): Boolean = {
- types._sequential_Q(x) && types._toIter(x).length > 0
+ types._sequential_Q(x) && x.asInstanceOf[MalList].value.length > 0
}
def quasiquote(ast: Any): Any = {
if (!is_pair(ast)) {
- return List(Symbol("quote"), ast)
+ return _list(Symbol("quote"), ast)
} else {
- val a0 = types._toList(ast)(0)
+ val a0 = ast.asInstanceOf[MalList](0)
if (types._symbol_Q(a0) &&
a0.asInstanceOf[Symbol].name == "unquote") {
- return types._toList(ast)(1)
+ return ast.asInstanceOf[MalList](1)
} else if (is_pair(a0)) {
- val a00 = types._toList(a0)(0)
+ val a00 = a0.asInstanceOf[MalList](0)
if (types._symbol_Q(a00) &&
a00.asInstanceOf[Symbol].name == "splice-unquote") {
- return List(Symbol("concat"),
- types._toList(a0)(1),
- quasiquote(types._toList(ast).drop(1)))
+ return _list(Symbol("concat"),
+ a0.asInstanceOf[MalList](1),
+ quasiquote(ast.asInstanceOf[MalList].drop(1)))
}
}
- return List(Symbol("cons"),
- quasiquote(a0),
- quasiquote(types._toList(ast).drop(1)))
+ return _list(Symbol("cons"),
+ quasiquote(a0),
+ quasiquote(ast.asInstanceOf[MalList].drop(1)))
}
}
def is_macro_call(ast: Any, env: Env): Boolean = {
ast match {
- case l: List[Any] => {
- if (types._symbol_Q(l(0)) &&
- env.find(l(0).asInstanceOf[Symbol]) != null) {
- env.get(l(0).asInstanceOf[Symbol]) match {
- case f: Function => return f.ismacro
+ case ml: MalList => {
+ if (types._symbol_Q(ml(0)) &&
+ env.find(ml(0).asInstanceOf[Symbol]) != null) {
+ env.get(ml(0).asInstanceOf[Symbol]) match {
+ case f: MalFunction => return f.ismacro
case _ => return false
}
}
@@ -54,10 +55,10 @@ object step9_try {
def macroexpand(orig_ast: Any, env: Env): Any = {
var ast = orig_ast;
while (is_macro_call(ast, env)) {
- ast.asInstanceOf[List[Any]] match {
+ ast.asInstanceOf[MalList].value match {
case f :: args => {
val mac = env.get(f.asInstanceOf[Symbol])
- ast = mac.asInstanceOf[Function](args)
+ ast = mac.asInstanceOf[MalFunction](args)
}
case _ => throw new Exception("macroexpand: invalid call")
}
@@ -68,10 +69,10 @@ object step9_try {
def eval_ast(ast: Any, env: Env): Any = {
ast match {
case s : Symbol => env.get(s)
- case l: List[Any] => l.map(EVAL(_, env))
- case v: Array[Any] => v.map(EVAL(_, env)).toArray
- case m: Map[String @unchecked,Any @unchecked] => {
- m.map{case (k: String,v: Any) => (k, EVAL(v, env))}.toMap
+ case v: MalVector => v.map(EVAL(_, env))
+ case l: MalList => l.map(EVAL(_, env))
+ case m: MalHashMap => {
+ m.map{case (k: String,v: Any) => (k, EVAL(v, env))}
}
case _ => ast
}
@@ -82,20 +83,20 @@ object step9_try {
while (true) {
//println("EVAL: " + printer._pr_str(ast,true))
- if (!ast.isInstanceOf[List[Any]])
+ if (!_list_Q(ast))
return eval_ast(ast, env)
// apply list
ast = macroexpand(ast, env)
- if (!ast.isInstanceOf[List[Any]]) return ast
+ if (!_list_Q(ast)) return ast
- ast.asInstanceOf[List[Any]] match {
+ ast.asInstanceOf[MalList].value match {
case Symbol("def!") :: a1 :: a2 :: Nil => {
return env.set(a1.asInstanceOf[Symbol], EVAL(a2, env))
}
case Symbol("let*") :: a1 :: a2 :: Nil => {
val let_env = new Env(env)
- for (g <- types._toIter(a1).grouped(2)) {
+ for (g <- a1.asInstanceOf[MalList].value.grouped(2)) {
let_env.set(g(0).asInstanceOf[Symbol],EVAL(g(1),let_env))
}
env = let_env
@@ -109,7 +110,7 @@ object step9_try {
}
case Symbol("defmacro!") :: a1 :: a2 :: Nil => {
val f = EVAL(a2, env)
- f.asInstanceOf[Function].ismacro = true
+ f.asInstanceOf[MalFunction].ismacro = true
return env.set(a1.asInstanceOf[Symbol], f)
}
case Symbol("macroexpand") :: a1 :: Nil => {
@@ -120,7 +121,7 @@ object step9_try {
return EVAL(a1, env)
} catch {
case t: Throwable => {
- rest(0) match {
+ rest(0).asInstanceOf[MalList].value match {
case List(Symbol("catch*"), a21, a22) => {
val exc: Any = t match {
case mex: types.MalException => mex.value
@@ -136,8 +137,8 @@ object step9_try {
}
}
case Symbol("do") :: rest => {
- eval_ast(rest.slice(0,rest.length-1), env)
- ast = ast.asInstanceOf[List[Any]].last // continue loop (TCO)
+ eval_ast(_list(rest.slice(0,rest.length-1):_*), env)
+ ast = ast.asInstanceOf[MalList].value.last // continue loop (TCO)
}
case Symbol("if") :: a1 :: a2 :: rest => {
val cond = EVAL(a1, env)
@@ -149,7 +150,7 @@ object step9_try {
}
}
case Symbol("fn*") :: a1 :: a2 :: Nil => {
- return new Function(a2, env, types._toList(a1),
+ return new MalFunction(a2, env, a1.asInstanceOf[MalList],
(args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
}
@@ -157,14 +158,14 @@ object step9_try {
}
case _ => {
// function call
- eval_ast(ast, env) match {
+ eval_ast(ast, env).asInstanceOf[MalList].value match {
case f :: el => {
f match {
- case fn: Function => {
+ case fn: MalFunction => {
env = fn.gen_env(el)
ast = fn.ast // continue loop (TCO)
}
- case fn: ((List[Any]) => Any) @unchecked => {
+ case fn: Func => {
return fn(el)
}
case _ => {
@@ -190,9 +191,11 @@ object step9_try {
val REP = (str: String) => PRINT(EVAL(READ(str), repl_env))
// core.scala: defined using scala
- core.ns.map{case (k: String,v: Any) => { repl_env.set(Symbol(k), v) }}
- repl_env.set(Symbol("eval"), (a: List[Any]) => EVAL(a(0), repl_env))
- repl_env.set(Symbol("*ARGV*"), args.slice(1,args.length).toList)
+ core.ns.map{case (k: String,v: Any) => {
+ repl_env.set(Symbol(k), new Func(v))
+ }}
+ repl_env.set(Symbol("eval"), new Func((a: List[Any]) => EVAL(a(0), repl_env)))
+ repl_env.set(Symbol("*ARGV*"), _list(args.slice(1,args.length):_*))
// core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
diff --git a/scala/stepA_interop.scala b/scala/stepA_interop.scala
new file mode 100644
index 0000000..2ba6b5a
--- /dev/null
+++ b/scala/stepA_interop.scala
@@ -0,0 +1,229 @@
+import types.{MalList, _list, _list_Q, MalVector, MalHashMap,
+ Func, MalFunction}
+import env.Env
+
+object stepA_interop {
+ // read
+ def READ(str: String): Any = {
+ reader.read_str(str)
+ }
+
+ // eval
+ def is_pair(x: Any): Boolean = {
+ types._sequential_Q(x) && x.asInstanceOf[MalList].value.length > 0
+ }
+
+ def quasiquote(ast: Any): Any = {
+ if (!is_pair(ast)) {
+ return _list(Symbol("quote"), ast)
+ } else {
+ val a0 = ast.asInstanceOf[MalList](0)
+ if (types._symbol_Q(a0) &&
+ a0.asInstanceOf[Symbol].name == "unquote") {
+ return ast.asInstanceOf[MalList](1)
+ } else if (is_pair(a0)) {
+ val a00 = a0.asInstanceOf[MalList](0)
+ if (types._symbol_Q(a00) &&
+ a00.asInstanceOf[Symbol].name == "splice-unquote") {
+ return _list(Symbol("concat"),
+ a0.asInstanceOf[MalList](1),
+ quasiquote(ast.asInstanceOf[MalList].drop(1)))
+ }
+ }
+ return _list(Symbol("cons"),
+ quasiquote(a0),
+ quasiquote(ast.asInstanceOf[MalList].drop(1)))
+ }
+ }
+
+ def is_macro_call(ast: Any, env: Env): Boolean = {
+ ast match {
+ case ml: MalList => {
+ if (types._symbol_Q(ml(0)) &&
+ env.find(ml(0).asInstanceOf[Symbol]) != null) {
+ env.get(ml(0).asInstanceOf[Symbol]) match {
+ case f: MalFunction => return f.ismacro
+ case _ => return false
+ }
+ }
+ return false
+ }
+ case _ => return false
+ }
+ }
+
+ def macroexpand(orig_ast: Any, env: Env): Any = {
+ var ast = orig_ast;
+ while (is_macro_call(ast, env)) {
+ ast.asInstanceOf[MalList].value match {
+ case f :: args => {
+ val mac = env.get(f.asInstanceOf[Symbol])
+ ast = mac.asInstanceOf[MalFunction](args)
+ }
+ case _ => throw new Exception("macroexpand: invalid call")
+ }
+ }
+ ast
+ }
+
+ def eval_ast(ast: Any, env: Env): Any = {
+ ast match {
+ case s : Symbol => env.get(s)
+ case v: MalVector => v.map(EVAL(_, env))
+ case l: MalList => l.map(EVAL(_, env))
+ case m: MalHashMap => {
+ m.map{case (k: String,v: Any) => (k, EVAL(v, env))}
+ }
+ case _ => ast
+ }
+ }
+
+ def EVAL(orig_ast: Any, orig_env: Env): Any = {
+ var ast = orig_ast; var env = orig_env;
+ while (true) {
+
+ //println("EVAL: " + printer._pr_str(ast,true))
+ if (!_list_Q(ast))
+ return eval_ast(ast, env)
+
+ // apply list
+ ast = macroexpand(ast, env)
+ if (!_list_Q(ast)) return ast
+
+ ast.asInstanceOf[MalList].value match {
+ case Symbol("def!") :: a1 :: a2 :: Nil => {
+ return env.set(a1.asInstanceOf[Symbol], EVAL(a2, env))
+ }
+ case Symbol("let*") :: a1 :: a2 :: Nil => {
+ val let_env = new Env(env)
+ for (g <- a1.asInstanceOf[MalList].value.grouped(2)) {
+ let_env.set(g(0).asInstanceOf[Symbol],EVAL(g(1),let_env))
+ }
+ env = let_env
+ ast = a2 // continue loop (TCO)
+ }
+ case Symbol("quote") :: a1 :: Nil => {
+ return a1
+ }
+ case Symbol("quasiquote") :: a1 :: Nil => {
+ ast = quasiquote(a1) // continue loop (TCO)
+ }
+ case Symbol("defmacro!") :: a1 :: a2 :: Nil => {
+ val f = EVAL(a2, env)
+ f.asInstanceOf[MalFunction].ismacro = true
+ return env.set(a1.asInstanceOf[Symbol], f)
+ }
+ case Symbol("macroexpand") :: a1 :: Nil => {
+ return macroexpand(a1, env)
+ }
+ case Symbol("try*") :: a1 :: rest => {
+ try {
+ return EVAL(a1, env)
+ } catch {
+ case t: Throwable => {
+ rest(0).asInstanceOf[MalList].value match {
+ case List(Symbol("catch*"), a21, a22) => {
+ val exc: Any = t match {
+ case mex: types.MalException => mex.value
+ case _ => t.getMessage
+ }
+ return EVAL(a22, new Env(env,
+ List(a21).iterator,
+ List(exc).iterator))
+ }
+ }
+ throw t
+ }
+ }
+ }
+ case Symbol("do") :: rest => {
+ eval_ast(_list(rest.slice(0,rest.length-1):_*), env)
+ ast = ast.asInstanceOf[MalList].value.last // continue loop (TCO)
+ }
+ case Symbol("if") :: a1 :: a2 :: rest => {
+ val cond = EVAL(a1, env)
+ if (cond == null || cond == false) {
+ if (rest.length == 0) return null
+ ast = rest(0) // continue loop (TCO)
+ } else {
+ ast = a2 // continue loop (TCO)
+ }
+ }
+ case Symbol("fn*") :: a1 :: a2 :: Nil => {
+ return new MalFunction(a2, env, a1.asInstanceOf[MalList],
+ (args: List[Any]) => {
+ EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
+ }
+ )
+ }
+ case _ => {
+ // function call
+ eval_ast(ast, env).asInstanceOf[MalList].value match {
+ case f :: el => {
+ f match {
+ case fn: MalFunction => {
+ env = fn.gen_env(el)
+ ast = fn.ast // continue loop (TCO)
+ }
+ case fn: Func => {
+ return fn(el)
+ }
+ case _ => {
+ throw new Exception("attempt to call non-function: " + f)
+ }
+ }
+ }
+ case _ => throw new Exception("invalid apply")
+ }
+ }
+ }
+ }
+ }
+
+ // print
+ def PRINT(exp: Any): String = {
+ printer._pr_str(exp, true)
+ }
+
+ // repl
+ def main(args: Array[String]) = {
+ val repl_env: Env = new Env()
+ val REP = (str: String) => PRINT(EVAL(READ(str), repl_env))
+
+ // core.scala: defined using scala
+ core.ns.map{case (k: String,v: Any) => {
+ repl_env.set(Symbol(k), new Func(v))
+ }}
+ repl_env.set(Symbol("eval"), new Func((a: List[Any]) => EVAL(a(0), repl_env)))
+ repl_env.set(Symbol("*ARGV*"), _list(args.slice(1,args.length):_*))
+
+ // core.mal: defined using the language itself
+ REP("(def! *host-language* \"scala\")")
+ REP("(def! not (fn* (a) (if a false true)))")
+ REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
+ REP("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))")
+ REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))")
+
+
+ if (args.length > 0) {
+ REP("(load-file \"" + args(0) + "\")")
+ System.exit(0)
+ }
+
+ // repl loop
+ REP("(println (str \"Mal [\" *host-language* \"]\"))")
+ var line:String = null
+ while ({line = readLine("user> "); line != null}) {
+ try {
+ println(REP(line))
+ } catch {
+ case e : Throwable => {
+ println("Error: " + e.getMessage)
+ println(" " + e.getStackTrace.mkString("\n "))
+ }
+ }
+ }
+ }
+}
+
+// vim: ts=2:sw=2
diff --git a/scala/types.scala b/scala/types.scala
index cf93ac2..91af068 100644
--- a/scala/types.scala
+++ b/scala/types.scala
@@ -2,6 +2,7 @@ import scala.collection._
import scala.collection.generic._
import env.Env
+import printer._pr_str
object types {
class MalException(msg: String) extends Throwable(msg) {
@@ -11,40 +12,25 @@ object types {
def _toIter(obj: Any): Iterator[Any] = {
obj match {
- case l: List[Any] => l.iterator
- case v: Array[Any] => v.iterator
+ case v: MalVector => v.value.iterator
+ case l: MalList => l.value.iterator
case null => Iterator.empty
case _ => throw new Exception("cannot convert " +
obj.getClass + " to iterator")
}
}
- def _toList(obj: Any): List[Any] = {
- obj match {
- case l: List[Any] => l
- case v: Array[Any] => v.toList
- case null => List()
- case _ => throw new Exception("cannot convert " +
- obj.getClass + " to list")
- }
- }
-
def _equal_Q(a: Any, b: Any): Any = {
(a, b) match {
- case (a: List[Any], b: List[Any]) => a == b
- case (a: Array[Any], b: Array[Any]) => a.deep == b.deep
- case (a: List[Any], b: Array[Any]) => a == b.deep
- case (a: Array[Any], b: List[Any]) => a.deep == b
- case (a: Map[String @unchecked,Any @unchecked],
- b: Map[String @unchecked,Any @unchecked]) => a == b
+ case (a: MalList, b: MalList) => a.value == b.value
+ case (a: MalHashMap, b: MalHashMap) => a.value == b.value
case _ => a == b
}
}
def _sequential_Q(a: Any): Boolean = {
a match {
- case l: List[Any] => true
- case v: Array[Any] => true
+ case l: MalList => true
case _ => false
}
}
@@ -53,64 +39,152 @@ object types {
// Lists
-
- class MalList[A](seq : A*) extends Traversable[A]
- with GenericTraversableTemplate[A, MalList]
- with TraversableLike[A, MalList[A]] {
+ class MalList(seq: Any*) {
+ var value: List[Any] = seq.toList
var meta: Any = null
- override def companion = MalList
- def foreach[U](f: A => U) = seq.foreach(f)
- }
- object MalList extends TraversableFactory[MalList] {
- implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, MalList[A]] = new GenericCanBuildFrom[A]
- def newBuilder[A] = new scala.collection.mutable.LazyBuilder[A,MalList[A]] {
- def result = {
- val data = parts.foldLeft(List[A]()){(l,n) => l ++ n}
- new MalList(data:_*)
- }
+
+ override def clone(): MalList = {
+ val new_ml = new MalList()
+ new_ml.value = value
+ new_ml.meta = meta
+ new_ml
+ }
+
+ def apply(idx: Int): Any = value(idx)
+ def map(f: Any => Any) = new MalList(value.map(f):_*)
+ def drop(cnt: Int) = new MalList(value.drop(cnt):_*)
+ def :+(that: Any) = new MalList((value :+ that):_*)
+ def +:(that: Any) = new MalList((that +: value):_*)
+
+ override def toString() = {
+ "(" + value.map(_pr_str(_, true)).mkString(" ") + ")"
+ }
+ def toString(print_readably: Boolean) = {
+ "(" + value.map(_pr_str(_, print_readably)).mkString(" ") + ")"
}
}
+ def _list(seq: Any*) = {
+ new MalList(seq:_*)
+ }
+ def _list_Q(obj: Any) = {
+ obj.isInstanceOf[MalList] && !obj.isInstanceOf[MalVector]
+ }
// Vectors
- class MalVector[A](seq : A*) extends Traversable[A]
- with GenericTraversableTemplate[A, MalVector]
- with TraversableLike[A, MalVector[A]] {
- var meta: Any = null
- override def companion = MalVector
- def foreach[U](f: A => U) = seq.foreach(f)
+ class MalVector(seq: Any*) extends MalList(seq:_*) {
+ override def clone() = {
+ val new_mv = new MalVector()
+ new_mv.value = value
+ new_mv.meta = meta
+ new_mv
+ }
+
+ override def map(f: Any => Any) = new MalVector(value.map(f):_*)
+ override def drop(cnt: Int) = new MalVector(value.drop(cnt):_*)
+
+ override def toString() = {
+ "[" + value.map(_pr_str(_, true)).mkString(" ") + "]"
+ }
+ override def toString(print_readably: Boolean) = {
+ "[" + value.map(_pr_str(_, print_readably)).mkString(" ") + "]"
+ }
+ }
+ def _vector(seq: Any*) = {
+ new MalVector(seq:_*)
}
- object MalVector extends TraversableFactory[MalVector] {
- implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, MalVector[A]] = new GenericCanBuildFrom[A]
- def newBuilder[A] = new scala.collection.mutable.LazyBuilder[A,MalVector[A]] {
- def result = {
- val data = parts.foldLeft(List[A]()){(l,n) => l ++ n}
- new MalVector(data:_*)
- }
+ def _vector_Q(obj: Any) = {
+ obj.isInstanceOf[MalVector]
+ }
+
+
+ // Hash Maps
+ class MalHashMap(seq: Any*) {
+ var flat_value: List[Any] = seq.toList
+ var value: Map[String,Any] = flat_value.grouped(2).map(
+ (kv: List[Any]) => (kv(0).asInstanceOf[String], kv(1))).toMap
+ var meta: Any = null
+
+ override def clone(): MalHashMap = {
+ val new_hm = new MalHashMap()
+ new_hm.value = value
+ new_hm.flat_value = flat_value
+ new_hm.meta = meta
+ new_hm
+ }
+
+ def keys(): MalList = new MalList(value.keys.toSeq:_*)
+ def vals(): MalList = new MalList(value.values.toSeq:_*)
+
+ def apply(key: String): Any = value(key)
+ def map(f: ((String, Any)) => (String, Any)) = {
+ val res = value.map(f).map{case (k,v) => List(k,v)}
+ new MalHashMap(res.flatten.toSeq:_*)
+ }
+ def filterKeys(f: String => Boolean) = {
+ val res = value.filterKeys(f).map{case (k,v) => List(k,v)}
+ new MalHashMap(res.flatten.toSeq:_*)
+ }
+ def ++(that: MalHashMap) = {
+ new MalHashMap((flat_value ++ that.flat_value):_*)
+ }
+
+ override def toString() = {
+ "{" + flat_value.map(_pr_str(_, true)).mkString(" ") + "}"
+ }
+ def toString(print_readably: Boolean) = {
+ "{" + flat_value.map(_pr_str(_, print_readably)).mkString(" ") + "}"
}
}
+ def _hash_map(seq: Any*) = {
+ new MalHashMap(seq:_*)
+ }
+ def _hash_map_Q(obj: Any) = {
+ obj.isInstanceOf[MalHashMap]
+ }
+
+ // Function types
- class Function(_ast: Any, _env: Env, _params: List[Any],
- fn: ((List[Any]) => Any)) {
+ class Func(_fn: ((List[Any]) => Any)) {
+ val fn = _fn
+ var meta: Any = null
+
+ override def clone(): Func = {
+ val new_fn = new Func(fn)
+ new_fn.meta = meta
+ new_fn
+ }
+
+ def apply(args: List[Any]): Any = fn(args)
+ }
+
+ class MalFunction(_ast: Any, _env: Env, _params: MalList,
+ fn: ((List[Any]) => Any)) {
val ast = _ast
val env = _env
val params = _params
var ismacro = false
+ var meta: Any = null
- def apply(args: List[Any]): Any = {
- fn(args)
+ override def clone(): MalFunction = {
+ val new_fn = new MalFunction(ast, env, params, fn)
+ new_fn.ismacro = ismacro
+ new_fn.meta = meta
+ new_fn
}
+ def apply(args: List[Any]): Any = fn(args)
+
def gen_env(args: List[Any]): Env = {
- return new Env(env, params.iterator, args.iterator)
+ return new Env(env, params.value.iterator, args.iterator)
}
}
def _apply(f: Any, args: List[Any]): Any = {
f match {
- case fn: types.Function => fn(args)
- case fn: ((List[Any]) => Any) @unchecked => fn(args)
+ case fn: types.MalFunction => fn(args)
+ case fn: Func => fn(args)
case _ => throw new Exception("attempt to call non-function")
}
}
diff --git a/tests/step6_file.mal b/tests/step6_file.mal
index f102c34..f76e4f5 100644
--- a/tests/step6_file.mal
+++ b/tests/step6_file.mal
@@ -27,6 +27,13 @@
;=>2
;;
+;; Testing that *ARGV* exists and is an empty list
+(list? *ARGV*)
+;=>true
+*ARGV*
+;=>()
+
+;;
;; -------- Optional Functionality --------
(load-file "../tests/incB.mal")