1 import "os" for Process
3 import "./readline" for Readline
4 import "./reader" for MalReader
5 import "./printer" for Printer
6 import "./types" for MalSymbol, MalList, MalVector, MalMap, MalNativeFn, MalFn
7 import "./core" for Core
11 return MalReader.read_str(str)
14 static eval_ast(ast, env) {
15 if (ast is MalSymbol) {
16 return env.get(ast.value)
17 } else if (ast is MalList) {
18 return MalList.new(ast.elements.map { |e| eval(e, env) }.toList)
19 } else if (ast is MalVector) {
20 return MalVector.new(ast.elements.map { |e| eval(e, env) }.toList)
21 } else if (ast is MalMap) {
24 m[e.key] = eval(e.value, env)
32 static eval(ast, env) {
35 if (!(ast is MalList)) return eval_ast(ast, env)
36 if (ast.isEmpty) return ast
37 if (ast[0] is MalSymbol) {
38 if (ast[0].value == "def!") {
39 return env.set(ast[1].value, eval(ast[2], env))
40 } else if (ast[0].value == "let*") {
41 var letEnv = Env.new(env)
43 while (i < ast[1].count) {
44 letEnv.set(ast[1][i].value, eval(ast[1][i + 1], letEnv))
50 } else if (ast[0].value == "do") {
51 for (i in 1...(ast.count - 1)) {
56 } else if (ast[0].value == "if") {
57 var condval = eval(ast[1], env)
61 if (ast.count <= 3) return null
65 } else if (ast[0].value == "fn*") {
66 return MalFn.new(ast[2], ast[1].elements, env,
67 Fn.new { |a| eval(ast[2], Env.new(env, ast[1].elements, a)) })
71 var evaled_ast = eval_ast(ast, env)
73 if (f is MalNativeFn) {
74 return f.call(evaled_ast[1..-1])
75 } else if (f is MalFn) {
77 env = Env.new(f.env, f.params, evaled_ast[1..-1])
80 Fiber.abort("unknown function type")
87 return Printer.pr_str(ast)
91 return print(eval(read(str), __repl_env))
95 __repl_env = Env.new()
96 // core.wren: defined in wren
97 for (e in Core.ns) { __repl_env.set(e.key, e.value) }
98 __repl_env.set("eval", MalNativeFn.new { |a| eval(a[0], __repl_env) })
99 __repl_env.set("*ARGV*", MalList.new(Process.arguments.count > 0 ? Process.arguments[1..-1] : []))
100 // core.mal: defined using the language itself
101 rep("(def! not (fn* (a) (if a false true)))")
102 rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))")
104 if (Process.arguments.count > 0) {
105 rep("(load-file \"%(Process.arguments[0])\")")
110 var line = Readline.readLine("user> ")
111 if (line == null) break
113 var fiber = Fiber.new { System.print(rep(line)) }
115 if (fiber.error) System.print("Error: %(fiber.error)")