def READ(str string) MalVal { return read_str(str) } def eval_ast(ast MalVal, env Env) MalVal { if ast is MalSymbol { return env.get(ast as MalSymbol) } else if ast is MalList { return MalList.new((ast as MalList).val.map(e => EVAL(e, env))) } else if ast is MalVector { return MalVector.new((ast as MalVector).val.map(e => EVAL(e, env))) } else if ast is MalHashMap { var result List = [] (ast as MalHashMap).val.each((k string, v MalVal) => { result.append(EVAL(MalVal.fromHashKey(k), env)) result.append(EVAL(v, env)) }) return MalHashMap.fromList(result) } else { return ast } } def EVAL(ast MalVal, env Env) MalVal { if !(ast is MalList) { return eval_ast(ast, env) } const astList = ast as MalList if astList.isEmpty { return ast } const a0sym = astList[0] as MalSymbol if a0sym.val == "def!" { return env.set(astList[1] as MalSymbol, EVAL(astList[2], env)) } else if a0sym.val == "let*" { var letenv = Env.new(env) const assigns = astList[1] as MalSequential for i = 0; i < assigns.count; i += 2 { letenv.set(assigns[i] as MalSymbol, EVAL(assigns[i + 1], letenv)) } return EVAL(astList[2], letenv) } else if a0sym.val == "do" { const r = eval_ast(MalList.new(astList.val.slice(1)), env) as MalList return r[r.count - 1] } else if a0sym.val == "if" { const condRes = EVAL(astList[1], env) if condRes is MalNil || condRes is MalFalse { return astList.count > 3 ? EVAL(astList[3], env) : gNil } else { return EVAL(astList[2], env) } } else if a0sym.val == "fn*" { const argsNames = (astList[1] as MalSequential).val return MalNativeFunc.new((args List) => EVAL(astList[2], Env.new(env, argsNames, args))) } else { const evaledList = eval_ast(ast, env) as MalList const fn = evaledList[0] as MalNativeFunc return fn.call(evaledList.val.slice(1)) } } def PRINT(exp MalVal) string { return exp?.print(true) } var repl_env = Env.new(null) def RE(str string) MalVal { return EVAL(READ(str), repl_env) } def REP(str string) string { return PRINT(RE(str)) } @entry def main { # core.sk: defined using Skew ns.each((name, func) => repl_env.set(MalSymbol.new(name), MalNativeFunc.new(func))) # core.mal: defined using the language itself RE("(def! not (fn* (a) (if a false true)))") var line string while (line = readLine("user> ")) != null { if line == "" { continue } try { printLn(REP(line)) } catch e MalError { printLn("Error: \(e.message)") } } }