1
1
mirror of https://github.com/kanaka/mal.git synced 2024-10-26 14:22:25 +03:00

Scala: all steps 0-9 but no metadata.

This commit is contained in:
Joel Martin 2014-12-18 23:21:39 -06:00
parent b8ee29b22f
commit 821930dbd9
20 changed files with 1690 additions and 1 deletions

2
.gitignore vendored
View File

@ -35,3 +35,5 @@ rust/.cargo
r/lib
vb/*.exe
vb/*.dll
scala/target
scala/project

View File

@ -11,7 +11,7 @@ PYTHON = python
#
IMPLS = bash c clojure coffee cs go java js make mal perl php ps \
python r ruby rust vb
python r ruby rust scala vb
step0 = step0_repl
step1 = step1_read_print
@ -65,6 +65,7 @@ python_STEP_TO_PROG = python/$($(1)).py
r_STEP_TO_PROG = r/$($(1)).r
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
@ -85,6 +86,7 @@ python_RUNSTEP = $(PYTHON) ../$(2) $(3)
r_RUNSTEP = Rscript ../$(2) $(3)
ruby_RUNSTEP = ruby ../$(2) $(3)
rust_RUNSTEP = ../$(2) $(3)
scala_RUNSTEP = sbt 'run-main $($(1))$(if $(3), $(3),)'
vb_RUNSTEP = mono ../$(2) --raw $(3)
# Extra options to pass to runtest.py

View File

@ -22,6 +22,7 @@ language. Mal is implemented from scratch in 18 different languages:
* R
* Ruby
* Rust
* Scala
* Visual Basic.NET
@ -214,6 +215,18 @@ cargo build
./target/stepX_YYY
```
### Scala ###
Install scala and sbt (http://www.scala-sbt.org/0.13/tutorial/Installing-sbt-on-Linux.html):
```
cd scala
sbt 'run-main stepX_YYY'
# OR
sbt compile
scala -classpath target/scala*/classes stepX_YYY
```
### Visual Basic.NET ###
The VB.NET implementation of mal has been tested on Linux using the Mono

View File

@ -122,6 +122,10 @@ Future Implementations:
- http://groovy-lang.org/learn.html
- http://groovy-lang.org/structure.html
- Scala
- aptitude install scala
- http://learnxinyminutes.com/docs/scala/
- Visual Basic
aptitude install mono-vbnc

15
scala/build.sbt Normal file
View File

@ -0,0 +1,15 @@
lazy val root = (project in file(".")).
settings(
name := "mal",
version := "0.1",
scalaVersion := "2.11.4"
)
// Suppress message for command line execution
onLoadMessage := ""
showSuccess := false
logLevel in runMain := Level.Warn

178
scala/core.scala Normal file
View File

@ -0,0 +1,178 @@
import scala.collection.mutable
import scala.io.Source
import printer._pr_list
object core {
def mal_throw(a: List[Any]) = {
throw new types.MalException(printer._pr_str(a(0))).init(a(0))
}
// Scalar functions
def keyword(a: List[Any]) = {
"\u029e" + a(0).asInstanceOf[String]
}
def keyword_Q(a: List[Any]) = {
a(0) match {
case s: String => s(0) == '\u029e'
case _ => false
}
}
// 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")
}
// 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]])
}
def dissoc(a: List[Any]): Any = {
var kSet = types._toList(a.drop(1)).toSet
a(0).asInstanceOf[Map[String,Any]]
.filterKeys{ !kSet.contains(_) }
}
def get(a: List[Any]): Any = {
val hm = a(0).asInstanceOf[Map[String,Any]]
val key = a(1).asInstanceOf[String]
if (hm != null && hm.contains(key)) hm(key) else null
}
def contains_Q(a: List[Any]): Any = {
a(0).asInstanceOf[Map[String,Any]]
.contains(a(1).asInstanceOf[String])
}
// sequence functions
def concat(a: List[Any]): List[Any] = {
(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]
if (idx < lst.length) {
lst(idx)
} else {
throw new Exception("nth: index out of range")
}
}
def first(a: List[Any]): Any = {
val lst = types._toList(a(0))
if (lst.length > 0) lst(0) else null
}
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))
types._apply(f, args)
}
case _ => throw new Exception("invalid apply call")
}
}
def do_map(a: List[Any]): Any = {
a match {
case f :: seq :: Nil => {
types._toList(seq).map(x => types._apply(f,List(x)))
}
case _ => throw new Exception("invalid map call")
}
}
// atom functions
def reset_BANG(a: List[Any]): Any = {
a(0).asInstanceOf[types.Atom].value = a(1)
a(1)
}
def swap_BANG(a: List[Any]): Any = {
a match {
case a0 :: f :: rest => {
val atm = a0.asInstanceOf[types.Atom]
val args = atm.value +: rest
atm.value = types._apply(f, args)
atm.value
}
case _ => throw new Exception("invalid swap! call")
}
}
val ns: Map[String, Any] = Map(
"=" -> ((a: List[Any]) => types._equal_Q(a(0), a(1))),
"throw" -> mal_throw _,
"nil?" -> ((a: List[Any]) => a(0) == null),
"true?" -> ((a: List[Any]) => a(0) == true),
"false?" -> ((a: List[Any]) => a(0) == false),
"symbol" -> ((a: List[Any]) => Symbol(a(0).asInstanceOf[String])),
"symbol?" -> ((a: List[Any]) => a(0).isInstanceOf[Symbol]),
"keyword" -> keyword _,
"keyword?" -> keyword_Q _,
"pr-str" -> ((a: List[Any]) => _pr_list(a, true, " ")),
"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}),
"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]),
"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),
"sequential?" -> ((a: List[Any]) => types._sequential_Q(a(0))),
"cons" -> ((a: List[Any]) => a(0) +: types._toList(a(1))),
"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),
"apply" -> apply _,
"map" -> do_map _,
"with-meta" -> ((a: List[Any]) => null),
"meta" -> ((a: List[Any]) => null),
"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),
"reset!" -> reset_BANG _,
"swap!" -> swap_BANG _
)
}
// vim:ts=2:sw=2

40
scala/env.scala Normal file
View File

@ -0,0 +1,40 @@
import scala.collection.mutable
object env {
class Env(outer: Env = null,
binds: Iterator[Any] = null,
exprs: Iterator[Any] = null) {
val data: mutable.Map[Symbol, Any] = mutable.Map()
if (binds != null && exprs != null) {
binds.foreach(b => {
val k = b.asInstanceOf[Symbol]
if (k == '&) {
data(binds.next().asInstanceOf[Symbol]) = exprs.toList
} else {
data(k) = exprs.next()
}
})
}
def find(key: Symbol): Env = {
if (data.contains(key)) {
this
} else if (outer != null) {
outer.find(key)
} else {
null
}
}
def set(key: Symbol, value: Any): Any = {
data(key) = value
value
}
def get(key: Symbol): Any = {
val env = find(key)
if (env == null) throw new Exception("'" + key.name + "' not found")
env.data(key)
}
}
}
// vim:ts=2:sw=2

45
scala/printer.scala Normal file
View File

@ -0,0 +1,45 @@
import types.Function
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 s: String => {
if (s.length > 0 && s(0) == '\u029e') {
":" + s.substring(1,s.length)
} else if (_r) {
//println("here1: " + s)
"\"" + s.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n") + "\""
} else {
s
}
}
case Symbol(s) => s
case a: types.Atom => "(atom " + a.value + ")"
case null => "nil"
case _ => {
if (obj.isInstanceOf[Function]) {
val f = obj.asInstanceOf[Function]
"<function (fn* " + _pr_str(f.params) + " " + _pr_str(f.ast) + ")>"
} else {
obj.toString
}
}
}
}
def _pr_list(lst: List[Any], print_readably: Boolean = true,
sep: String = " "): String = {
lst.map{_pr_str(_, print_readably)}.mkString(sep)
}
}
// vim: ts=2:sw=2

88
scala/reader.scala Normal file
View File

@ -0,0 +1,88 @@
import scala.util.matching.Regex
object reader {
class Reader (tokens: Array[String]) {
var data = tokens
var position: Int = 0
def peek(): String = {
if (position >= data.length) return(null)
data(position)
}
def next(): String = {
if (position >= data.length) return(null)
position = position + 1
data(position-1)
}
}
def tokenize(str: String): Array[String] = {
val re = """[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)""".r
re.findAllMatchIn(str).map{ _.group(1) }
.filter{ s => s != "" && s(0) != ';' }
.toArray
}
def parse_str(s: String): String = {
s.replace("\\\"", "\"").replace("\\n", "\n")
}
def read_atom(rdr: Reader): Any = {
val token = rdr.next()
val re_int = """^(-?[0-9]+)$""".r
val re_flt = """^(-?[0-9][0-9.]*)$""".r
val re_str = """^"(.*)"$""".r
val re_key = """^:(.*)$""".r
return token match {
case re_int(i) => i.toInt // integer
case re_flt(f) => f.toDouble // float
case re_str(s) => parse_str(s) // string
case re_key(k) => "\u029e" + k // keyword
case "nil" => null
case "true" => true
case "false" => false
case _ => Symbol(token) // symbol
}
}
def read_list(rdr: Reader,
start: String = "(", end: String = ")"): List[Any] = {
var ast: List[Any] = List()
var token = rdr.next()
if (token != start) throw new Exception("expected '" + start + "', got EOF")
while ({token = rdr.peek(); token != end}) {
if (token == null) throw new Exception("expected '" + end + "', got EOF")
ast = ast :+ read_form(rdr)
}
rdr.next()
ast
}
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; val meta = 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 "]" => throw new Exception("unexpected ']')")
case "{" => types._hash_map(read_list(rdr, "{", "}"))
case "}" => throw new Exception("unexpected '}')")
case _ => read_atom(rdr)
}
}
def read_str(str: String): Any = {
val tokens = tokenize(str)
if (tokens.length == 0) return null
return read_form(new Reader(tokens))
}
}
// vim: ts=2:sw=2

33
scala/step0_repl.scala Normal file
View File

@ -0,0 +1,33 @@
object step0_repl {
def READ(str: String): String = {
str
}
def EVAL(str: String, env: String): String = {
str
}
def PRINT(str: String): String = {
str
}
def REP(str: String): String = {
PRINT(EVAL(READ(str), ""))
}
def main(args: Array[String]) {
var line:String = null
while ({line = readLine("user> "); line != null}) {
try {
println(REP(line))
} catch {
case e : Exception => {
println("Error: " + e.getMessage)
println(" " + e.getStackTrace.mkString("\n "))
}
}
}
}
}
// vim: ts=2:sw=2

View File

@ -0,0 +1,39 @@
import reader.tokenize
object step1_read_print {
// read
def READ(str: String): Any = {
reader.read_str(str)
}
// eval
def EVAL(ast: Any, env: String): Any = {
ast
}
// print
def PRINT(exp: Any): String = {
printer._pr_str(exp, true)
}
// repl
def main(args: Array[String]) = {
val REP = (str: String) => {
PRINT(EVAL(READ(str), ""))
}
var line:String = null
while ({line = readLine("user> "); line != null}) {
try {
println(REP(line))
} catch {
case e : Exception => {
println("Error: " + e.getMessage)
println(" " + e.getStackTrace.mkString("\n "))
}
}
}
}
}
// vim: ts=2:sw=2

73
scala/step2_eval.scala Normal file
View File

@ -0,0 +1,73 @@
import reader.tokenize
object step2_eval {
// read
def READ(str: String): Any = {
reader.read_str(str)
}
// 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 _ => ast
}
}
def EVAL(ast: Any, env: Map[Symbol,Any]): Any = {
//println("EVAL: " + printer._pr_str(ast,true))
if (!ast.isInstanceOf[List[Any]])
return eval_ast(ast, env)
// apply list
eval_ast(ast, env) match {
case f :: el => {
var fn: List[Any] => Any = null
try {
fn = f.asInstanceOf[(List[Any]) => Any]
} catch {
case _: Throwable =>
throw new Exception("attempt to call non-function")
}
return fn(el)
}
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: 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]))
val REP = (str: String) => {
PRINT(EVAL(READ(str), repl_env))
}
var line:String = null
while ({line = readLine("user> "); line != null}) {
try {
println(REP(line))
} catch {
case e : Exception => {
println("Error: " + e.getMessage)
println(" " + e.getStackTrace.mkString("\n "))
}
}
}
}
}
// vim: ts=2:sw=2

93
scala/step3_env.scala Normal file
View File

@ -0,0 +1,93 @@
import env.Env
object step3_env {
// read
def READ(str: String): Any = {
reader.read_str(str)
}
// eval
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 _ => ast
}
}
def EVAL(ast: Any, env: Env): Any = {
//println("EVAL: " + printer._pr_str(ast,true))
if (!ast.isInstanceOf[List[Any]])
return eval_ast(ast, env)
// apply list
ast.asInstanceOf[List[Any]] 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)) {
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 {
case f :: el => {
var fn: List[Any] => Any = null
try {
fn = f.asInstanceOf[(List[Any]) => Any]
} catch {
case _: Throwable =>
throw new Exception("attempt to call non-function")
}
return fn(el)
}
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()
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])
val REP = (str: String) => {
PRINT(EVAL(READ(str), repl_env))
}
var line:String = null
while ({line = readLine("user> "); line != null}) {
try {
println(REP(line))
} catch {
case e : Exception => {
println("Error: " + e.getMessage)
println(" " + e.getStackTrace.mkString("\n "))
}
}
}
}
}
// vim: ts=2:sw=2

106
scala/step4_if_fn_do.scala Normal file
View File

@ -0,0 +1,106 @@
import env.Env
object step4_if_fn_do {
// read
def READ(str: String): Any = {
reader.read_str(str)
}
// eval
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 _ => ast
}
}
def EVAL(ast: Any, env: Env): Any = {
//println("EVAL: " + printer._pr_str(ast,true))
if (!ast.isInstanceOf[List[Any]])
return eval_ast(ast, env)
// apply list
ast.asInstanceOf[List[Any]] 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)) {
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
}
case Symbol("if") :: a1 :: a2 :: rest => {
val cond = EVAL(a1, env)
if (cond == null || cond == false) {
if (rest.length == 0) return null
return EVAL(rest(0), env)
} else {
return EVAL(a2, env)
}
}
case Symbol("fn*") :: a1 :: a2 :: Nil => {
return (args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
}
}
case _ => {
// function call
eval_ast(ast, env) match {
case f :: el => {
var fn: List[Any] => Any = null
try {
fn = f.asInstanceOf[(List[Any]) => Any]
} catch {
case _: Throwable =>
throw new Exception("attempt to call non-function")
}
return fn(el)
}
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), v) }}
// core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
var line:String = null
while ({line = readLine("user> "); line != null}) {
try {
println(REP(line))
} catch {
case e : Exception => {
println("Error: " + e.getMessage)
println(" " + e.getStackTrace.mkString("\n "))
}
}
}
}
}
// vim: ts=2:sw=2

117
scala/step5_tco.scala Normal file
View File

@ -0,0 +1,117 @@
import env.Env
object step5_tco {
// read
def READ(str: String): Any = {
reader.read_str(str)
}
// eval
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 _ => 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 (!ast.isInstanceOf[List[Any]])
return eval_ast(ast, env)
// apply list
ast.asInstanceOf[List[Any]] 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)) {
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)
}
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 types.Function(a2, env, a1.asInstanceOf[List[Any]],
(args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
}
)
}
case _ => {
// function call
eval_ast(ast, env) match {
case f :: el => {
f match {
case fn: types.Function => {
env = fn.gen_env(el)
ast = fn.ast // continue loop (TCO)
}
case fn: ((List[Any]) => Any) @unchecked => {
return fn(el)
}
case _ => {
throw new Exception("attempt to call non-function")
}
}
}
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), v) }}
// core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
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

126
scala/step6_file.scala Normal file
View File

@ -0,0 +1,126 @@
import env.Env
object step6_file {
// read
def READ(str: String): Any = {
reader.read_str(str)
}
// eval
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 _ => 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 (!ast.isInstanceOf[List[Any]])
return eval_ast(ast, env)
// apply list
ast.asInstanceOf[List[Any]] 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)) {
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)
}
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 types.Function(a2, env, a1.asInstanceOf[List[Any]],
(args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
}
)
}
case _ => {
// function call
eval_ast(ast, env) match {
case f :: el => {
f match {
case fn: types.Function => {
env = fn.gen_env(el)
ast = fn.ast // continue loop (TCO)
}
case fn: ((List[Any]) => Any) @unchecked => {
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), 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.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
if (args.length > 0) {
REP("(load-file \"" + args(0) + "\")")
System.exit(0)
}
// repl loop
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

159
scala/step7_quote.scala Normal file
View File

@ -0,0 +1,159 @@
import env.Env
object step7_quote {
// read
def READ(str: String): Any = {
reader.read_str(str)
}
// eval
def is_pair(x: Any): Boolean = {
types._sequential_Q(x) && types._toIter(x).length > 0
}
def quasiquote(ast: Any): Any = {
if (!is_pair(ast)) {
return List(Symbol("quote"), ast)
} else {
val a0 = types._toList(ast)(0)
if (types._symbol_Q(a0) &&
a0.asInstanceOf[Symbol].name == "unquote") {
return types._toList(ast)(1)
} else if (is_pair(a0)) {
val a00 = types._toList(a0)(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("cons"),
quasiquote(a0),
quasiquote(types._toList(ast).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 _ => 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 (!ast.isInstanceOf[List[Any]])
return eval_ast(ast, env)
// apply list
ast.asInstanceOf[List[Any]] 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)) {
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("do") :: rest => {
eval_ast(rest.slice(0,rest.length-1), env)
ast = ast.asInstanceOf[List[Any]].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 types.Function(a2, env, a1.asInstanceOf[List[Any]],
(args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
}
)
}
case _ => {
// function call
eval_ast(ast, env) match {
case f :: el => {
f match {
case fn: types.Function => {
env = fn.gen_env(el)
ast = fn.ast // continue loop (TCO)
}
case fn: ((List[Any]) => Any) @unchecked => {
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), 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.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
if (args.length > 0) {
REP("(load-file \"" + args(0) + "\")")
System.exit(0)
}
// repl loop
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

204
scala/step8_macros.scala Normal file
View File

@ -0,0 +1,204 @@
import env.Env
import types.Function
object step8_macros {
// read
def READ(str: String): Any = {
reader.read_str(str)
}
// eval
def is_pair(x: Any): Boolean = {
types._sequential_Q(x) && types._toIter(x).length > 0
}
def quasiquote(ast: Any): Any = {
if (!is_pair(ast)) {
return List(Symbol("quote"), ast)
} else {
val a0 = types._toList(ast)(0)
if (types._symbol_Q(a0) &&
a0.asInstanceOf[Symbol].name == "unquote") {
return types._toList(ast)(1)
} else if (is_pair(a0)) {
val a00 = types._toList(a0)(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("cons"),
quasiquote(a0),
quasiquote(types._toList(ast).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 _ => 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[List[Any]] match {
case f :: args => {
val mac = env.get(f.asInstanceOf[Symbol])
ast = mac.asInstanceOf[Function](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 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 _ => 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 (!ast.isInstanceOf[List[Any]])
return eval_ast(ast, env)
// apply list
ast = macroexpand(ast, env)
if (!ast.isInstanceOf[List[Any]]) return ast
ast.asInstanceOf[List[Any]] 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)) {
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[Function].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)
}
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 Function(a2, env, types._toList(a1),
(args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
}
)
}
case _ => {
// function call
eval_ast(ast, env) match {
case f :: el => {
f match {
case fn: Function => {
env = fn.gen_env(el)
ast = fn.ast // continue loop (TCO)
}
case fn: ((List[Any]) => Any) @unchecked => {
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), 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.mal: defined using the language itself
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
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

224
scala/step9_try.scala Normal file
View File

@ -0,0 +1,224 @@
import env.Env
import types.Function
object step9_try {
// read
def READ(str: String): Any = {
reader.read_str(str)
}
// eval
def is_pair(x: Any): Boolean = {
types._sequential_Q(x) && types._toIter(x).length > 0
}
def quasiquote(ast: Any): Any = {
if (!is_pair(ast)) {
return List(Symbol("quote"), ast)
} else {
val a0 = types._toList(ast)(0)
if (types._symbol_Q(a0) &&
a0.asInstanceOf[Symbol].name == "unquote") {
return types._toList(ast)(1)
} else if (is_pair(a0)) {
val a00 = types._toList(a0)(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("cons"),
quasiquote(a0),
quasiquote(types._toList(ast).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 _ => 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[List[Any]] match {
case f :: args => {
val mac = env.get(f.asInstanceOf[Symbol])
ast = mac.asInstanceOf[Function](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 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 _ => 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 (!ast.isInstanceOf[List[Any]])
return eval_ast(ast, env)
// apply list
ast = macroexpand(ast, env)
if (!ast.isInstanceOf[List[Any]]) return ast
ast.asInstanceOf[List[Any]] 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)) {
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[Function].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) 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(rest.slice(0,rest.length-1), env)
ast = ast.asInstanceOf[List[Any]].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 Function(a2, env, types._toList(a1),
(args: List[Any]) => {
EVAL(a2, new Env(env, types._toIter(a1), args.iterator))
}
)
}
case _ => {
// function call
eval_ast(ast, env) match {
case f :: el => {
f match {
case fn: Function => {
env = fn.gen_env(el)
ast = fn.ast // continue loop (TCO)
}
case fn: ((List[Any]) => Any) @unchecked => {
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), 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.mal: defined using the language itself
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
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

128
scala/types.scala Normal file
View File

@ -0,0 +1,128 @@
import scala.collection._
import scala.collection.generic._
import env.Env
object types {
class MalException(msg: String) extends Throwable(msg) {
var value: Any = null
def init(obj: Any) = { value = obj; this }
}
def _toIter(obj: Any): Iterator[Any] = {
obj match {
case l: List[Any] => l.iterator
case v: Array[Any] => v.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 == b
}
}
def _sequential_Q(a: Any): Boolean = {
a match {
case l: List[Any] => true
case v: Array[Any] => true
case _ => false
}
}
def _symbol_Q(a: Any) = { a.isInstanceOf[Symbol] }
// Lists
class MalList[A](seq : A*) extends Traversable[A]
with GenericTraversableTemplate[A, MalList]
with TraversableLike[A, MalList[A]] {
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:_*)
}
}
}
// 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)
}
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:_*)
}
}
}
class Function(_ast: Any, _env: Env, _params: List[Any],
fn: ((List[Any]) => Any)) {
val ast = _ast
val env = _env
val params = _params
var ismacro = false
def apply(args: List[Any]): Any = {
fn(args)
}
def gen_env(args: List[Any]): Env = {
return new Env(env, params.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 _ => throw new Exception("attempt to call non-function")
}
}
def _hash_map(lst: List[Any]): Any = {
lst.grouped(2).map(
(kv: List[Any]) => (kv(0).asInstanceOf[String], kv(1))).toMap
}
class Atom(_value: Any) {
var value = _value
}
}
// vim:ts=2:sw=2