From 55c103928b51a38977e7f5d716b01fd61c8b0358 Mon Sep 17 00:00:00 2001 From: Nicolas Boulenguez Date: Sat, 9 Nov 2024 01:00:54 +0100 Subject: [PATCH] swift[34]: merge eval_ast and macroexpand into EVAL, add DEBUG-EVAL swift3: merge env.find and env.get, take a string as parameter, return nil instead of throwing an exception swift3/stepA: print *host-language* swift4: reduce differences between steps in spacing, ordering and so on. swift4/step5: remove a large comment containing non-printable characters --- impls/swift3/Sources/env.swift | 28 +--- impls/swift3/Sources/step2_eval/main.swift | 40 +++--- impls/swift3/Sources/step3_env/main.swift | 46 +++--- .../swift3/Sources/step4_if_fn_do/main.swift | 56 ++++---- impls/swift3/Sources/step5_tco/main.swift | 54 ++++--- impls/swift3/Sources/step6_file/main.swift | 54 ++++--- impls/swift3/Sources/step7_quote/main.swift | 56 ++++---- impls/swift3/Sources/step8_macros/main.swift | 96 ++++--------- impls/swift3/Sources/step9_try/main.swift | 96 ++++--------- impls/swift3/Sources/stepA_mal/main.swift | 98 ++++--------- impls/swift4/Sources/step2_eval/main.swift | 64 ++++----- impls/swift4/Sources/step3_env/main.swift | 98 +++++++------ .../swift4/Sources/step4_if_fn_do/main.swift | 133 +++++++++--------- impls/swift4/Sources/step5_tco/main.swift | 57 +++----- impls/swift4/Sources/step6_file/main.swift | 44 +++--- impls/swift4/Sources/step7_quote/main.swift | 46 +++--- impls/swift4/Sources/step8_macros/main.swift | 77 +++------- impls/swift4/Sources/step9_try/main.swift | 77 +++------- impls/swift4/Sources/stepA_mal/main.swift | 77 +++------- 19 files changed, 473 insertions(+), 824 deletions(-) diff --git a/impls/swift3/Sources/env.swift b/impls/swift3/Sources/env.swift index f080dce800..2f09af5975 100644 --- a/impls/swift3/Sources/env.swift +++ b/impls/swift3/Sources/env.swift @@ -48,32 +48,8 @@ class Env { } } - func find(_ key: MalVal) throws -> Env? { - switch key { - case MalVal.MalSymbol(let str): - if data[str] != nil { - return self - } else if outer != nil { - return try outer!.find(key) - } else { - return nil - } - default: - throw MalError.General(msg: "invalid Env.find call") - } - } - - func get(_ key: MalVal) throws -> MalVal { - switch key { - case MalVal.MalSymbol(let str): - let env = try self.find(key) - if env == nil { - throw MalError.General(msg: "'\(str)' not found") - } - return env!.data[str]! - default: - throw MalError.General(msg: "invalid Env.find call") - } + func get(_ str: String) -> MalVal? { + return data[str] ?? outer?.get(str) } @discardableResult diff --git a/impls/swift3/Sources/step2_eval/main.swift b/impls/swift3/Sources/step2_eval/main.swift index 7a3e49ad04..acee857be7 100644 --- a/impls/swift3/Sources/step2_eval/main.swift +++ b/impls/swift3/Sources/step2_eval/main.swift @@ -6,45 +6,37 @@ func READ(_ str: String) throws -> MalVal { } // eval -func eval_ast(_ ast: MalVal, _ env: Dictionary) throws -> MalVal { +func EVAL(_ ast: MalVal, _ env: Dictionary) throws -> MalVal { + /* print("EVAL: " + PRINT(ast)) */ switch ast { case MalVal.MalSymbol(let sym): - if env[sym] == nil { + if let value = env[sym] { + return value + } else { throw MalError.General(msg: "'\(sym)' not found") } - return env[sym]! - case MalVal.MalList(let lst, _): - return list(try lst.map { try EVAL($0, env) }) case MalVal.MalVector(let lst, _): return vector(try lst.map { try EVAL($0, env) }) case MalVal.MalHashMap(let dict, _): var new_dict = Dictionary() for (k,v) in dict { new_dict[k] = try EVAL(v, env) } return hash_map(new_dict) + case MalVal.MalList(let lst, _): + if lst.count == 0 { return ast } + + let raw_args = lst[1..) throws -> MalVal { - switch ast { - case MalVal.MalList(let lst, _): if lst.count == 0 { return ast } - default: return try eval_ast(ast, env) - } - - switch try eval_ast(ast, env) { - case MalVal.MalList(let elst, _): - switch elst[0] { - case MalVal.MalFunc(let fn,_,_,_,_,_): - let args = Array(elst[1.. String { return pr_str(exp, true) diff --git a/impls/swift3/Sources/step3_env/main.swift b/impls/swift3/Sources/step3_env/main.swift index 8f37521770..8ee7e3be48 100644 --- a/impls/swift3/Sources/step3_env/main.swift +++ b/impls/swift3/Sources/step3_env/main.swift @@ -6,31 +6,28 @@ func READ(_ str: String) throws -> MalVal { } // eval -func eval_ast(_ ast: MalVal, _ env: Env) throws -> MalVal { +func EVAL(_ ast: MalVal, _ env: Env) throws -> MalVal { + if let dbgeval = env.get("DEBUG-EVAL") { + switch dbgeval { + case MalVal.MalFalse, MalVal.MalNil: break + default: print("EVAL: " + PRINT(ast)) + } + } switch ast { - case MalVal.MalSymbol: - return try env.get(ast) - case MalVal.MalList(let lst, _): - return list(try lst.map { try EVAL($0, env) }) + case MalVal.MalSymbol(let sym): + if let value = env.get(sym) { + return value + } else { + throw MalError.General(msg: "'\(sym)' not found") + } case MalVal.MalVector(let lst, _): return vector(try lst.map { try EVAL($0, env) }) case MalVal.MalHashMap(let dict, _): var new_dict = Dictionary() for (k,v) in dict { new_dict[k] = try EVAL(v, env) } return hash_map(new_dict) - default: - return ast - } -} - -func EVAL(_ ast: MalVal, _ env: Env) throws -> MalVal { - switch ast { - case MalVal.MalList(let lst, _): if lst.count == 0 { return ast } - default: return try eval_ast(ast, env) - } - - switch ast { case MalVal.MalList(let lst, _): + if lst.count == 0 { return ast } switch lst[0] { case MalVal.MalSymbol("def!"): return try env.set(lst[1], try EVAL(lst[2], env)) @@ -51,20 +48,17 @@ func EVAL(_ ast: MalVal, _ env: Env) throws -> MalVal { } return try EVAL(lst[2], let_env) default: - switch try eval_ast(ast, env) { - case MalVal.MalList(let elst, _): - switch elst[0] { - case MalVal.MalFunc(let fn,_,_,_,_,_): - let args = Array(elst[1.. MalVal { } // eval -func eval_ast(_ ast: MalVal, _ env: Env) throws -> MalVal { +func EVAL(_ ast: MalVal, _ env: Env) throws -> MalVal { + if let dbgeval = env.get("DEBUG-EVAL") { + switch dbgeval { + case MalVal.MalFalse, MalVal.MalNil: break + default: print("EVAL: " + PRINT(ast)) + } + } switch ast { - case MalVal.MalSymbol: - return try env.get(ast) - case MalVal.MalList(let lst, _): - return list(try lst.map { try EVAL($0, env) }) + case MalVal.MalSymbol(let sym): + if let value = env.get(sym) { + return value + } else { + throw MalError.General(msg: "'\(sym)' not found") + } case MalVal.MalVector(let lst, _): return vector(try lst.map { try EVAL($0, env) }) case MalVal.MalHashMap(let dict, _): var new_dict = Dictionary() for (k,v) in dict { new_dict[k] = try EVAL(v, env) } return hash_map(new_dict) - default: - return ast - } -} - -func EVAL(_ ast: MalVal, _ env: Env) throws -> MalVal { - switch ast { - case MalVal.MalList(let lst, _): if lst.count == 0 { return ast } - default: return try eval_ast(ast, env) - } - - switch ast { case MalVal.MalList(let lst, _): + if lst.count == 0 { return ast } switch lst[0] { case MalVal.MalSymbol("def!"): return try env.set(lst[1], try EVAL(lst[2], env)) @@ -51,13 +48,11 @@ func EVAL(_ ast: MalVal, _ env: Env) throws -> MalVal { } return try EVAL(lst[2], let_env) case MalVal.MalSymbol("do"): - let slc = lst[lst.index(after: lst.startIndex).. MalVal { exprs: list($0))) }) default: - switch try eval_ast(ast, env) { - case MalVal.MalList(let elst, _): - switch elst[0] { - case MalVal.MalFunc(let fn,_,_,_,_,_): - let args = Array(elst[1.. MalVal { } // eval -func eval_ast(_ ast: MalVal, _ env: Env) throws -> MalVal { +func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + if let dbgeval = env.get("DEBUG-EVAL") { + switch dbgeval { + case MalVal.MalFalse, MalVal.MalNil: break + default: print("EVAL: " + PRINT(ast)) + } + } switch ast { - case MalVal.MalSymbol: - return try env.get(ast) - case MalVal.MalList(let lst, _): - return list(try lst.map { try EVAL($0, env) }) + case MalVal.MalSymbol(let sym): + if let value = env.get(sym) { + return value + } else { + throw MalError.General(msg: "'\(sym)' not found") + } case MalVal.MalVector(let lst, _): return vector(try lst.map { try EVAL($0, env) }) case MalVal.MalHashMap(let dict, _): var new_dict = Dictionary() for (k,v) in dict { new_dict[k] = try EVAL(v, env) } return hash_map(new_dict) - default: - return ast - } -} - -func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { - var ast = orig_ast, env = orig_env - while true { - switch ast { - case MalVal.MalList(let lst, _): if lst.count == 0 { return ast } - default: return try eval_ast(ast, env) - } - - switch ast { case MalVal.MalList(let lst, _): + if lst.count == 0 { return ast } switch lst[0] { case MalVal.MalSymbol("def!"): return try env.set(lst[1], try EVAL(lst[2], env)) @@ -55,7 +52,9 @@ func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { ast = lst[2] // TCO case MalVal.MalSymbol("do"): let slc = lst[1.. MalVal { exprs: list($0))) }, ast:[lst[2]], env:env, params:[lst[1]]) default: - switch try eval_ast(ast, env) { - case MalVal.MalList(let elst, _): - switch elst[0] { + let raw_args = lst[1.. MalVal { } // eval -func eval_ast(_ ast: MalVal, _ env: Env) throws -> MalVal { +func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + if let dbgeval = env.get("DEBUG-EVAL") { + switch dbgeval { + case MalVal.MalFalse, MalVal.MalNil: break + default: print("EVAL: " + PRINT(ast)) + } + } switch ast { - case MalVal.MalSymbol: - return try env.get(ast) - case MalVal.MalList(let lst, _): - return list(try lst.map { try EVAL($0, env) }) + case MalVal.MalSymbol(let sym): + if let value = env.get(sym) { + return value + } else { + throw MalError.General(msg: "'\(sym)' not found") + } case MalVal.MalVector(let lst, _): return vector(try lst.map { try EVAL($0, env) }) case MalVal.MalHashMap(let dict, _): var new_dict = Dictionary() for (k,v) in dict { new_dict[k] = try EVAL(v, env) } return hash_map(new_dict) - default: - return ast - } -} - -func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { - var ast = orig_ast, env = orig_env - while true { - switch ast { - case MalVal.MalList(let lst, _): if lst.count == 0 { return ast } - default: return try eval_ast(ast, env) - } - - switch ast { case MalVal.MalList(let lst, _): + if lst.count == 0 { return ast } switch lst[0] { case MalVal.MalSymbol("def!"): return try env.set(lst[1], try EVAL(lst[2], env)) @@ -55,7 +52,9 @@ func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { ast = lst[2] // TCO case MalVal.MalSymbol("do"): let slc = lst[1.. MalVal { exprs: list($0))) }, ast:[lst[2]], env:env, params:[lst[1]]) default: - switch try eval_ast(ast, env) { - case MalVal.MalList(let elst, _): - switch elst[0] { + let raw_args = lst[1.. MalVal { } } -func eval_ast(_ ast: MalVal, _ env: Env) throws -> MalVal { +func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + if let dbgeval = env.get("DEBUG-EVAL") { + switch dbgeval { + case MalVal.MalFalse, MalVal.MalNil: break + default: print("EVAL: " + PRINT(ast)) + } + } switch ast { - case MalVal.MalSymbol: - return try env.get(ast) - case MalVal.MalList(let lst, _): - return list(try lst.map { try EVAL($0, env) }) + case MalVal.MalSymbol(let sym): + if let value = env.get(sym) { + return value + } else { + throw MalError.General(msg: "'\(sym)' not found") + } case MalVal.MalVector(let lst, _): return vector(try lst.map { try EVAL($0, env) }) case MalVal.MalHashMap(let dict, _): var new_dict = Dictionary() for (k,v) in dict { new_dict[k] = try EVAL(v, env) } return hash_map(new_dict) - default: - return ast - } -} - -func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { - var ast = orig_ast, env = orig_env - while true { - switch ast { - case MalVal.MalList(let lst, _): if lst.count == 0 { return ast } - default: return try eval_ast(ast, env) - } - - switch ast { case MalVal.MalList(let lst, _): + if lst.count == 0 { return ast } switch lst[0] { case MalVal.MalSymbol("def!"): return try env.set(lst[1], try EVAL(lst[2], env)) @@ -100,13 +97,13 @@ func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { ast = lst[2] // TCO case MalVal.MalSymbol("quote"): return lst[1] - case MalVal.MalSymbol("quasiquoteexpand"): - return quasiquote(lst[1]) case MalVal.MalSymbol("quasiquote"): ast = quasiquote(lst[1]) // TCO case MalVal.MalSymbol("do"): let slc = lst[1.. MalVal { exprs: list($0))) }, ast:[lst[2]], env:env, params:[lst[1]]) default: - switch try eval_ast(ast, env) { - case MalVal.MalList(let elst, _): - switch elst[0] { + let raw_args = lst[1.. MalVal { } } -func is_macro(_ ast: MalVal, _ env: Env) -> Bool { - switch ast { - case MalVal.MalList(let lst, _) where lst.count > 0: - let a0 = lst[lst.startIndex] - switch a0 { - case MalVal.MalSymbol: - let e = try! env.find(a0) - if e != nil { - let mac = try! e!.get(a0) - switch mac { - case MalVal.MalFunc(_,_,_,_,let macro,_): return macro - default: return false - } - } else { - return false - } - default: return false - } - default: return false - } -} - -func macroexpand(_ orig_ast: MalVal, _ env: Env) throws -> MalVal { - var ast: MalVal = orig_ast - while is_macro(ast, env) { - switch try! env.get(try! _nth(ast, 0)) { - case MalVal.MalFunc(let mac,_,_,_,_,_): - ast = try mac(_rest(ast)) - default: throw MalError.General(msg: "impossible state in macroexpand") +func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + if let dbgeval = env.get("DEBUG-EVAL") { + switch dbgeval { + case MalVal.MalFalse, MalVal.MalNil: break + default: print("EVAL: " + PRINT(ast)) } } - return ast -} - -func eval_ast(_ ast: MalVal, _ env: Env) throws -> MalVal { switch ast { - case MalVal.MalSymbol: - return try env.get(ast) - case MalVal.MalList(let lst, _): - return list(try lst.map { try EVAL($0, env) }) + case MalVal.MalSymbol(let sym): + if let value = env.get(sym) { + return value + } else { + throw MalError.General(msg: "'\(sym)' not found") + } case MalVal.MalVector(let lst, _): return vector(try lst.map { try EVAL($0, env) }) case MalVal.MalHashMap(let dict, _): var new_dict = Dictionary() for (k,v) in dict { new_dict[k] = try EVAL(v, env) } return hash_map(new_dict) - default: - return ast - } -} - -func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { - var ast = orig_ast, env = orig_env - while true { - switch ast { - case MalVal.MalList(let lst, _): if lst.count == 0 { return ast } - default: return try eval_ast(ast, env) - } - - ast = try macroexpand(ast, env) - switch ast { - case MalVal.MalList: break - default: return try eval_ast(ast, env) - } - - switch ast { case MalVal.MalList(let lst, _): + if lst.count == 0 { return ast } switch lst[0] { case MalVal.MalSymbol("def!"): return try env.set(lst[1], try EVAL(lst[2], env)) @@ -140,8 +97,6 @@ func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { ast = lst[2] // TCO case MalVal.MalSymbol("quote"): return lst[1] - case MalVal.MalSymbol("quasiquoteexpand"): - return quasiquote(lst[1]) case MalVal.MalSymbol("quasiquote"): ast = quasiquote(lst[1]) // TCO case MalVal.MalSymbol("defmacro!"): @@ -152,11 +107,11 @@ func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { default: throw MalError.General(msg: "invalid defmacro! form") } return try env.set(lst[1], mac) - case MalVal.MalSymbol("macroexpand"): - return try macroexpand(lst[1], env) case MalVal.MalSymbol("do"): let slc = lst[1.. MalVal { exprs: list($0))) }, ast:[lst[2]], env:env, params:[lst[1]]) default: - switch try eval_ast(ast, env) { - case MalVal.MalList(let elst, _): - switch elst[0] { + let raw_args = lst[1.. MalVal { } } -func is_macro(_ ast: MalVal, _ env: Env) -> Bool { - switch ast { - case MalVal.MalList(let lst, _) where lst.count > 0: - let a0 = lst[lst.startIndex] - switch a0 { - case MalVal.MalSymbol: - let e = try! env.find(a0) - if e != nil { - let mac = try! e!.get(a0) - switch mac { - case MalVal.MalFunc(_,_,_,_,let macro,_): return macro - default: return false - } - } else { - return false - } - default: return false - } - default: return false - } -} - -func macroexpand(_ orig_ast: MalVal, _ env: Env) throws -> MalVal { - var ast: MalVal = orig_ast - while is_macro(ast, env) { - switch try! env.get(try! _nth(ast, 0)) { - case MalVal.MalFunc(let mac,_,_,_,_,_): - ast = try mac(_rest(ast)) - default: throw MalError.General(msg: "impossible state in macroexpand") +func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + if let dbgeval = env.get("DEBUG-EVAL") { + switch dbgeval { + case MalVal.MalFalse, MalVal.MalNil: break + default: print("EVAL: " + PRINT(ast)) } } - return ast -} - -func eval_ast(_ ast: MalVal, _ env: Env) throws -> MalVal { switch ast { - case MalVal.MalSymbol: - return try env.get(ast) - case MalVal.MalList(let lst, _): - return list(try lst.map { try EVAL($0, env) }) + case MalVal.MalSymbol(let sym): + if let value = env.get(sym) { + return value + } else { + throw MalError.General(msg: "'\(sym)' not found") + } case MalVal.MalVector(let lst, _): return vector(try lst.map { try EVAL($0, env) }) case MalVal.MalHashMap(let dict, _): var new_dict = Dictionary() for (k,v) in dict { new_dict[k] = try EVAL(v, env) } return hash_map(new_dict) - default: - return ast - } -} - -func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { - var ast = orig_ast, env = orig_env - while true { - switch ast { - case MalVal.MalList(let lst, _): if lst.count == 0 { return ast } - default: return try eval_ast(ast, env) - } - - ast = try macroexpand(ast, env) - switch ast { - case MalVal.MalList: break - default: return try eval_ast(ast, env) - } - - switch ast { case MalVal.MalList(let lst, _): + if lst.count == 0 { return ast } switch lst[0] { case MalVal.MalSymbol("def!"): return try env.set(lst[1], try EVAL(lst[2], env)) @@ -140,8 +97,6 @@ func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { ast = lst[2] // TCO case MalVal.MalSymbol("quote"): return lst[1] - case MalVal.MalSymbol("quasiquoteexpand"): - return quasiquote(lst[1]) case MalVal.MalSymbol("quasiquote"): ast = quasiquote(lst[1]) // TCO case MalVal.MalSymbol("defmacro!"): @@ -152,8 +107,6 @@ func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { default: throw MalError.General(msg: "invalid defmacro! form") } return try env.set(lst[1], mac) - case MalVal.MalSymbol("macroexpand"): - return try macroexpand(lst[1], env) case MalVal.MalSymbol("try*"): do { return try EVAL(_nth(ast, 1), env) @@ -189,7 +142,9 @@ func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { } case MalVal.MalSymbol("do"): let slc = lst[1.. MalVal { exprs: list($0))) }, ast:[lst[2]], env:env, params:[lst[1]]) default: - switch try eval_ast(ast, env) { - case MalVal.MalList(let elst, _): - switch elst[0] { + let raw_args = lst[1.. MalVal { } } -func is_macro(_ ast: MalVal, _ env: Env) -> Bool { - switch ast { - case MalVal.MalList(let lst, _) where lst.count > 0: - let a0 = lst[lst.startIndex] - switch a0 { - case MalVal.MalSymbol: - let e = try! env.find(a0) - if e != nil { - let mac = try! e!.get(a0) - switch mac { - case MalVal.MalFunc(_,_,_,_,let macro,_): return macro - default: return false - } - } else { - return false - } - default: return false - } - default: return false - } -} - -func macroexpand(_ orig_ast: MalVal, _ env: Env) throws -> MalVal { - var ast: MalVal = orig_ast - while is_macro(ast, env) { - switch try! env.get(try! _nth(ast, 0)) { - case MalVal.MalFunc(let mac,_,_,_,_,_): - ast = try mac(_rest(ast)) - default: throw MalError.General(msg: "impossible state in macroexpand") +func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { + var ast = orig_ast, env = orig_env + while true { + if let dbgeval = env.get("DEBUG-EVAL") { + switch dbgeval { + case MalVal.MalFalse, MalVal.MalNil: break + default: print("EVAL: " + PRINT(ast)) } } - return ast -} - -func eval_ast(_ ast: MalVal, _ env: Env) throws -> MalVal { switch ast { - case MalVal.MalSymbol: - return try env.get(ast) - case MalVal.MalList(let lst, _): - return list(try lst.map { try EVAL($0, env) }) + case MalVal.MalSymbol(let sym): + if let value = env.get(sym) { + return value + } else { + throw MalError.General(msg: "'\(sym)' not found") + } case MalVal.MalVector(let lst, _): return vector(try lst.map { try EVAL($0, env) }) case MalVal.MalHashMap(let dict, _): var new_dict = Dictionary() for (k,v) in dict { new_dict[k] = try EVAL(v, env) } return hash_map(new_dict) - default: - return ast - } -} - -func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { - var ast = orig_ast, env = orig_env - while true { - switch ast { - case MalVal.MalList(let lst, _): if lst.count == 0 { return ast } - default: return try eval_ast(ast, env) - } - - ast = try macroexpand(ast, env) - switch ast { - case MalVal.MalList: break - default: return try eval_ast(ast, env) - } - - switch ast { case MalVal.MalList(let lst, _): + if lst.count == 0 { return ast } switch lst[0] { case MalVal.MalSymbol("def!"): return try env.set(lst[1], try EVAL(lst[2], env)) @@ -140,8 +97,6 @@ func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { ast = lst[2] // TCO case MalVal.MalSymbol("quote"): return lst[1] - case MalVal.MalSymbol("quasiquoteexpand"): - return quasiquote(lst[1]) case MalVal.MalSymbol("quasiquote"): ast = quasiquote(lst[1]) // TCO case MalVal.MalSymbol("defmacro!"): @@ -152,8 +107,6 @@ func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { default: throw MalError.General(msg: "invalid defmacro! form") } return try env.set(lst[1], mac) - case MalVal.MalSymbol("macroexpand"): - return try macroexpand(lst[1], env) case MalVal.MalSymbol("try*"): do { return try EVAL(_nth(ast, 1), env) @@ -189,7 +142,9 @@ func EVAL(_ orig_ast: MalVal, _ orig_env: Env) throws -> MalVal { } case MalVal.MalSymbol("do"): let slc = lst[1.. MalVal { exprs: list($0))) }, ast:[lst[2]], env:env, params:[lst[1]]) default: - switch try eval_ast(ast, env) { - case MalVal.MalList(let elst, _): - switch elst[0] { + let raw_args = lst[1.. 1 { exit(0) } +try rep("(println (str \"Mal [\" *host-language* \"]\"))") + while true { print("user> ", terminator: "") let line = readLine(strippingNewline: true) diff --git a/impls/swift4/Sources/step2_eval/main.swift b/impls/swift4/Sources/step2_eval/main.swift index e2f4fd2333..a5174cac58 100644 --- a/impls/swift4/Sources/step2_eval/main.swift +++ b/impls/swift4/Sources/step2_eval/main.swift @@ -6,25 +6,33 @@ func READ(_ input: String) throws -> MalData { } func EVAL(_ ast: MalData, env: [String: MalData]) throws -> MalData { - switch ast.dataType { - case .Vector: - let vector = ast as! ContiguousArray - return try ContiguousArray(vector.map { element in try EVAL(element, env: env) }) - case .List: - let list = ast as! [MalData] - if list.isEmpty { return list } - let evaluated = try eval_ast(list, env: env) as! [MalData] - if let function = evaluated[0] as? Function { - return try function.fn(List(evaluated.dropFirst())) - } else { - throw MalError.SymbolNotFound(list[0] as! Symbol) + /* print("EVAL: " + PRINT(ast)) */ + switch ast.dataType { + case .List: + let list = ast as! [MalData] + guard !list.isEmpty else { return list } + guard let function = try EVAL(list[0], env: env) as? Function else { + throw MalError.SymbolNotFound(list[0] as? Symbol ?? Symbol("Symbol")) + } + let raw_args = list.dropFirst() + let args = try raw_args.map { try EVAL($0, env: env) } + return try function.fn(args) + case .Vector: + let vector = ast as! ContiguousArray + return try ContiguousArray(vector.map { element in try EVAL(element, env: env) }) + case .HashMap: + let hashMap = ast as! HashMap + return try hashMap.mapValues { value in try EVAL(value, env: env) } + case .Symbol: + let sym = ast as! Symbol + if let value = env[sym.name] { + return value + } else { + throw MalError.SymbolNotFound(sym) + } + default: + return ast } - case .HashMap: - let hashMap = ast as! HashMap - return try hashMap.mapValues { value in try EVAL(value, env: env) } - default: - return try eval_ast(ast, env: env) - } } func PRINT(_ input: MalData) -> String { @@ -45,26 +53,6 @@ func PRINT(_ input: MalData) -> String { return try PRINT(EVAL(READ(input), env: repl_env)) } -func eval_ast(_ ast: MalData, env: [String: MalData]) throws -> MalData { - switch ast.dataType { - case .Symbol: - let sym = ast as! Symbol - if let function = env[sym.name] { - return function - } else { - throw MalError.SymbolNotFound(sym) - } - case .List: - let list = ast as! [MalData] - return try list.map { element in try EVAL(element, env: env) } - default: - return ast - } -} - - - - while true { print("user> ", terminator: "") if let input = readLine(strippingNewline: true) { diff --git a/impls/swift4/Sources/step3_env/main.swift b/impls/swift4/Sources/step3_env/main.swift index 159cba0127..44945cdaee 100644 --- a/impls/swift4/Sources/step3_env/main.swift +++ b/impls/swift4/Sources/step3_env/main.swift @@ -6,43 +6,57 @@ func READ(_ input: String) throws -> MalData { } func EVAL(_ ast: MalData, env: Env) throws -> MalData { - switch ast.dataType { - case .Vector: - let vector = ast as! ContiguousArray - return try ContiguousArray(vector.map { element in try EVAL(element, env: env) }) - case .List: - let list = ast as! [MalData] - guard !list.isEmpty else { return list } - guard let sym = list[0] as? Symbol else { throw MalError.Error } - - switch sym.name { - case "def!": - let value = try EVAL(list[2], env: env), key = list[1] as! Symbol - env.set(value, forKey: key) - return value - case "let*": - let newEnv = Env(outer: env), expr = list[2] - let bindings = (list[1] is Vector) ? List(list[1] as! Vector) : list[1] as! List - for i in stride(from: 0, to: bindings.count-1, by: 2) { - let key = bindings[i], value = bindings[i+1] - let result = try EVAL(value, env: newEnv) - newEnv.set(result, forKey: key as! Symbol) + if let dbgeval = try? env.get(forKey: Symbol("DEBUG-EVAL")) { + if ![.False, .Nil].contains(dbgeval.dataType) { + print("EVAL: " + PRINT(ast)) } - return try EVAL(expr, env: newEnv) - default: - let evaluated = try eval_ast(list, env: env) as! [MalData] - if let function = evaluated[0] as? Function { - return try function.fn(List(evaluated.dropFirst())) + } + switch ast.dataType { + case .List: + let list = ast as! [MalData] + guard !list.isEmpty else { return list } + if let sym = list[0] as? Symbol { + switch sym.name { + case "def!": + let value = try EVAL(list[2], env: env), key = list[1] as! Symbol + env.set(value, forKey: key) + return value + case "let*": + let newEnv = Env(outer: env), expr = list[2] + let bindings = list[1].listForm + for i in stride(from: 0, to: bindings.count-1, by: 2) { + let key = bindings[i], value = bindings[i+1] + let result = try EVAL(value, env: newEnv) + newEnv.set(result, forKey: key as! Symbol) + } + return try EVAL(expr, env: newEnv) + default: + break + } + } + // not a symbol. maybe: function, list, or some wrong type + guard let function = try EVAL(list[0], env: env) as? Function else { + throw MalError.SymbolNotFound(list[0] as? Symbol ?? Symbol("Symbol")) + } + let raw_args = list.dropFirst() + let args = try raw_args.map { try EVAL($0, env: env) } + return try function.fn(args) + case .Vector: + let vector = ast as! ContiguousArray + return try ContiguousArray(vector.map { element in try EVAL(element, env: env) }) + case .HashMap: + let hashMap = ast as! HashMap + return try hashMap.mapValues { value in try EVAL(value, env: env) } + case .Symbol: + let sym = ast as! Symbol + if let value = try? env.get(forKey: sym) { + return value } else { - throw MalError.SymbolNotFound(list[0] as! Symbol) + throw MalError.SymbolNotFound(sym) } + default: + return ast } - case .HashMap: - let hashMap = ast as! HashMap - return try hashMap.mapValues { value in try EVAL(value, env: env) } - default: - return try eval_ast(ast, env: env) - } } func PRINT(_ input: MalData) -> String { @@ -50,27 +64,9 @@ func PRINT(_ input: MalData) -> String { } @discardableResult func rep(_ input: String, env: Env) throws -> String { - return try PRINT(EVAL(READ(input), env: env)) } -func eval_ast(_ ast: MalData, env: Env) throws -> MalData { - switch ast.dataType { - case .Symbol: - let sym = ast as! Symbol - if let function = try? env.get(forKey: sym) { - return function - } else { - throw MalError.SymbolNotFound(sym) - } - case .List: - let list = ast as! [MalData] - return try list.map { element in try EVAL(element, env: env) } - default: - return ast - } -} - func calculate(_ args: [MalData], op: (Number, Number) -> Number) throws -> MalData { guard args.count == 2, args[0] is Number, args[1] is Number else { throw MalError.InvalidArgument } return op(args[0] as! Number, args[1] as! Number) diff --git a/impls/swift4/Sources/step4_if_fn_do/main.swift b/impls/swift4/Sources/step4_if_fn_do/main.swift index 51dc7c0642..0c3f809aa9 100644 --- a/impls/swift4/Sources/step4_if_fn_do/main.swift +++ b/impls/swift4/Sources/step4_if_fn_do/main.swift @@ -6,60 +6,72 @@ func READ(_ input: String) throws -> MalData { } func EVAL(_ ast: MalData, env: Env) throws -> MalData { - switch ast.dataType { - case .Vector: - let vector = ast as! ContiguousArray - return try ContiguousArray(vector.map { element in try EVAL(element, env: env) }) - case .List: - let list = ast as! [MalData] - guard !list.isEmpty else { return list } - if let sym = list[0] as? Symbol { - switch sym.name { - case "def!": - let value = try EVAL(list[2], env: env), key = list[1] as! Symbol - env.set(value, forKey: key) - return value - case "let*": - let newEnv = Env(outer: env), expr = list[2] - let bindings = (list[1] is Vector) ? List(list[1] as! Vector) : list[1] as! List - for i in stride(from: 0, to: bindings.count-1, by: 2) { - let key = bindings[i], value = bindings[i+1] - let result = try EVAL(value, env: newEnv) - newEnv.set(result, forKey: key as! Symbol) - } - return try EVAL(expr, env: newEnv) - case "do": - return try list.dropFirst().map { try EVAL($0, env: env) }.last ?? Nil() - case "if": - let predicate = try EVAL(list[1], env: env) - if predicate as? Bool == false || predicate is Nil { - return list.count>3 ? try EVAL(list[3], env: env) : Nil() - } else { - return try EVAL(list[2], env: env) - } - case "fn*": - let ops = {(params: [MalData]) -> MalData in - let newEnv = Env(binds: (list[1].listForm as! [Symbol]), exprs: params, outer: env) - return try EVAL(list[2], env: newEnv) - } - return Function(fn: ops) - default: - break + if let dbgeval = try? env.get(forKey: Symbol("DEBUG-EVAL")) { + if ![.False, .Nil].contains(dbgeval.dataType) { + print("EVAL: " + PRINT(ast)) } } - // not a symbol. maybe: function, list, or some wrong type - let evaluated = try eval_ast(list, env: env) as! [MalData] - if let function = evaluated[0] as? Function { - return try function.fn(List(evaluated.dropFirst())) - } else { - throw MalError.SymbolNotFound(list[0] as? Symbol ?? Symbol("Symbol")) + switch ast.dataType { + case .List: + let list = ast as! [MalData] + guard !list.isEmpty else { return list } + if let sym = list[0] as? Symbol { + switch sym.name { + case "def!": + let value = try EVAL(list[2], env: env), key = list[1] as! Symbol + env.set(value, forKey: key) + return value + case "let*": + let newEnv = Env(outer: env), expr = list[2] + let bindings = list[1].listForm + for i in stride(from: 0, to: bindings.count-1, by: 2) { + let key = bindings[i], value = bindings[i+1] + let result = try EVAL(value, env: newEnv) + newEnv.set(result, forKey: key as! Symbol) + } + return try EVAL(expr, env: newEnv) + case "do": + return try list.dropFirst().map { try EVAL($0, env: env) }.last ?? Nil() + case "if": + let predicate = try EVAL(list[1], env: env) + if predicate as? Bool == false || predicate is Nil { + return list.count>3 ? try EVAL(list[3], env: env) : Nil() + } else { + return try EVAL(list[2], env: env) + } + case "fn*": + let fn = {(params: [MalData]) -> MalData in + let newEnv = Env(binds: (list[1].listForm as! [Symbol]), exprs: params, outer: env) + return try EVAL(list[2], env: newEnv) + } + return Function(fn: fn) + default: + break + } + } + // not a symbol. maybe: function, list, or some wrong type + guard let function = try EVAL(list[0], env: env) as? Function else { + throw MalError.SymbolNotFound(list[0] as? Symbol ?? Symbol("Symbol")) + } + let raw_args = list.dropFirst() + let args = try raw_args.map { try EVAL($0, env: env) } + return try function.fn(args) + case .Vector: + let vector = ast as! ContiguousArray + return try ContiguousArray(vector.map { element in try EVAL(element, env: env) }) + case .HashMap: + let hashMap = ast as! HashMap + return try hashMap.mapValues { value in try EVAL(value, env: env) } + case .Symbol: + let sym = ast as! Symbol + if let value = try? env.get(forKey: sym) { + return value + } else { + throw MalError.SymbolNotFound(sym) + } + default: + return ast } - case .HashMap: - let hashMap = ast as! HashMap - return try hashMap.mapValues { value in try EVAL(value, env: env) } - default: - return try eval_ast(ast, env: env) - } } func PRINT(_ input: MalData) -> String { @@ -67,28 +79,9 @@ func PRINT(_ input: MalData) -> String { } @discardableResult func rep(_ input: String, env: Env) throws -> String { - return try PRINT(EVAL(READ(input), env: env)) } -func eval_ast(_ ast: MalData, env: Env) throws -> MalData { - switch ast.dataType { - case .Symbol: - let sym = ast as! Symbol - if let function = try? env.get(forKey: sym) { - return function - } else { - throw MalError.SymbolNotFound(sym) - } - case .List: - let list = ast as! [MalData] - return try list.map { element in try EVAL(element, env: env) } - default: - return ast - } -} - - var repl_env = Env() for (key, value) in ns { repl_env.set(Function(fn: value), forKey: Symbol(key)) diff --git a/impls/swift4/Sources/step5_tco/main.swift b/impls/swift4/Sources/step5_tco/main.swift index 5c29f067f5..f42ffa53ba 100644 --- a/impls/swift4/Sources/step5_tco/main.swift +++ b/impls/swift4/Sources/step5_tco/main.swift @@ -8,6 +8,11 @@ func READ(_ input: String) throws -> MalData { func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { var ast = anAst, env = anEnv while true { + if let dbgeval = try? env.get(forKey: Symbol("DEBUG-EVAL")) { + if ![.False, .Nil].contains(dbgeval.dataType) { + print("EVAL: " + PRINT(ast)) + } + } switch ast.dataType { case .List: let list = ast as! [MalData] @@ -53,45 +58,37 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { } } // not a symbol. maybe: function, list, or some wrong type - let evaluated = try eval_ast(list, env: env) as! [MalData] - guard let function = evaluated[0] as? Function else { + guard let function = try EVAL(list[0], env: env) as? Function else { throw MalError.SymbolNotFound(list[0] as? Symbol ?? Symbol("Symbol")) } + let raw_args = list.dropFirst() + let args = try raw_args.map { try EVAL($0, env: env) } if let fnAst = function.ast { // a full fn ast = fnAst - env = Env(binds: function.params!, exprs: evaluated.dropFirst().listForm, outer: function.env!) + env = Env(binds: function.params!, exprs: args, outer: function.env!) } else { // normal function - return try function.fn(evaluated.dropFirst().listForm) + return try function.fn(args) } continue -/* fn 的尾递归优化 -fn 的语法形式: ((fn (a,b)(+ a b )) 1 2) 形参,函数体,实参 -fn 本来的实现。 - 1.生成:制造一个闭包 - 1.1 闭包的功能:读入实参, 建立 形参=实参 的环境,在这个环境中 求值函数体 - 1.2 闭包本身不带有环境,当求值闭包时使用当时的环境 - 2.使用: - 以使用时的环境,使用实参调用闭包,闭包的返回值作为返回值。over (一次函数调用) -fn 的 TCO 实现。 - 1.生成: 形参 函数体 闭包(闭包包含最初的形参和函数体)+ 生成fn时的环境 - 2.使用: - 取出 函数体, - 使用求值时的形参,以 fn 中的 env 为外层 env 建立环境 () - 通过循环,在新建的环境中求值函数体 - */ case .Vector: let vector = ast as! ContiguousArray return try ContiguousArray(vector.map { element in try EVAL(element, env: env) }) case .HashMap: let hashMap = ast as! HashMap return try hashMap.mapValues { value in try EVAL(value, env: env) } + case .Symbol: + let sym = ast as! Symbol + if let value = try? env.get(forKey: sym) { + return value + } else { + throw MalError.SymbolNotFound(sym) + } default: - return try eval_ast(ast, env: env) + return ast } } } - func PRINT(_ input: MalData) -> String { return pr_str(input, print_readably: true) } @@ -100,24 +97,6 @@ func PRINT(_ input: MalData) -> String { return try PRINT(EVAL(READ(input), env: env)) } -func eval_ast(_ ast: MalData, env: Env) throws -> MalData { - switch ast.dataType { - case .Symbol: - let sym = ast as! Symbol - if let function = try? env.get(forKey: sym) { - return function - } else { - throw MalError.SymbolNotFound(sym) - } - case .List: - let list = ast as! [MalData] - return try list.map { element in try EVAL(element, env: env) } - default: - return ast - } -} - - var repl_env = Env() for (key, value) in ns { repl_env.set(Function(fn: value), forKey: Symbol(key)) diff --git a/impls/swift4/Sources/step6_file/main.swift b/impls/swift4/Sources/step6_file/main.swift index 6a20514e82..c9b636fc4d 100644 --- a/impls/swift4/Sources/step6_file/main.swift +++ b/impls/swift4/Sources/step6_file/main.swift @@ -8,6 +8,11 @@ func READ(_ input: String) throws -> MalData { func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { var ast = anAst, env = anEnv while true { + if let dbgeval = try? env.get(forKey: Symbol("DEBUG-EVAL")) { + if ![.False, .Nil].contains(dbgeval.dataType) { + print("EVAL: " + PRINT(ast)) + } + } switch ast.dataType { case .List: let list = ast as! [MalData] @@ -53,15 +58,16 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { } } // not a symbol. maybe: function, list, or some wrong type - let evaluated = try eval_ast(list, env: env) as! [MalData] - guard let function = evaluated[0] as? Function else { + guard let function = try EVAL(list[0], env: env) as? Function else { throw MalError.SymbolNotFound(list[0] as? Symbol ?? Symbol("Symbol")) } + let raw_args = list.dropFirst() + let args = try raw_args.map { try EVAL($0, env: env) } if let fnAst = function.ast { // a full fn ast = fnAst - env = Env(binds: function.params!, exprs: evaluated.dropFirst().listForm, outer: function.env!) + env = Env(binds: function.params!, exprs: args, outer: function.env!) } else { // normal function - return try function.fn(evaluated.dropFirst().listForm) + return try function.fn(args) } continue case .Vector: @@ -70,8 +76,15 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { case .HashMap: let hashMap = ast as! HashMap return try hashMap.mapValues { value in try EVAL(value, env: env) } + case .Symbol: + let sym = ast as! Symbol + if let value = try? env.get(forKey: sym) { + return value + } else { + throw MalError.SymbolNotFound(sym) + } default: - return try eval_ast(ast, env: env) + return ast } } } @@ -84,27 +97,6 @@ func PRINT(_ input: MalData) -> String { return try PRINT(EVAL(READ(input), env: env)) } -func eval_ast(_ ast: MalData, env: Env) throws -> MalData { - switch ast.dataType { - case .Symbol: - let sym = ast as! Symbol - if let function = try? env.get(forKey: sym) { - return function - } else { - throw MalError.SymbolNotFound(sym) - } - case .List: - let list = ast as! [MalData] - return try list.map { element in try EVAL(element, env: env) } - case .Atom: - return (ast as! Atom).value - default: - return ast - } -} - - - var repl_env = Env() for (key, value) in ns { repl_env.set(Function(fn: value), forKey: Symbol(key)) diff --git a/impls/swift4/Sources/step7_quote/main.swift b/impls/swift4/Sources/step7_quote/main.swift index a5e7a3eb29..2a926b04a1 100644 --- a/impls/swift4/Sources/step7_quote/main.swift +++ b/impls/swift4/Sources/step7_quote/main.swift @@ -50,6 +50,11 @@ func quasiquote(_ ast: MalData) -> MalData { func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { var ast = anAst, env = anEnv while true { + if let dbgeval = try? env.get(forKey: Symbol("DEBUG-EVAL")) { + if ![.False, .Nil].contains(dbgeval.dataType) { + print("EVAL: " + PRINT(ast)) + } + } switch ast.dataType { case .List: let list = ast as! [MalData] @@ -91,8 +96,6 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { return Function(ast: list[2], params: (list[1].listForm as! [Symbol]), env:env , fn: fn) case "quote": return list[1] - case "quasiquoteexpand": - return quasiquote(list[1]) case "quasiquote": ast = quasiquote(list[1]) continue @@ -101,15 +104,16 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { } } // not a symbol. maybe: function, list, or some wrong type - let evaluated = try eval_ast(list, env: env) as! [MalData] - guard let function = evaluated[0] as? Function else { + guard let function = try EVAL(list[0], env: env) as? Function else { throw MalError.SymbolNotFound(list[0] as? Symbol ?? Symbol("Symbol")) } + let raw_args = list.dropFirst() + let args = try raw_args.map { try EVAL($0, env: env) } if let fnAst = function.ast { // a full fn ast = fnAst - env = Env(binds: function.params!, exprs: evaluated.dropFirst().listForm, outer: function.env!) + env = Env(binds: function.params!, exprs: args, outer: function.env!) } else { // normal function - return try function.fn(evaluated.dropFirst().listForm) + return try function.fn(args) } continue case .Vector: @@ -118,8 +122,15 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { case .HashMap: let hashMap = ast as! HashMap return try hashMap.mapValues { value in try EVAL(value, env: env) } + case .Symbol: + let sym = ast as! Symbol + if let value = try? env.get(forKey: sym) { + return value + } else { + throw MalError.SymbolNotFound(sym) + } default: - return try eval_ast(ast, env: env) + return ast } } } @@ -132,27 +143,6 @@ func PRINT(_ input: MalData) -> String { return try PRINT(EVAL(READ(input), env: env)) } -func eval_ast(_ ast: MalData, env: Env) throws -> MalData { - switch ast.dataType { - case .Symbol: - let sym = ast as! Symbol - if let function = try? env.get(forKey: sym) { - return function - } else { - throw MalError.SymbolNotFound(sym) - } - case .List: - let list = ast as! [MalData] - return try list.map { element in try EVAL(element, env: env) } - case .Atom: - return (ast as! Atom).value - default: - return ast - } -} - - - var repl_env = Env() for (key, value) in ns { repl_env.set(Function(fn: value), forKey: Symbol(key)) diff --git a/impls/swift4/Sources/step8_macros/main.swift b/impls/swift4/Sources/step8_macros/main.swift index afd08a4bb4..1da85bf4db 100644 --- a/impls/swift4/Sources/step8_macros/main.swift +++ b/impls/swift4/Sources/step8_macros/main.swift @@ -48,34 +48,16 @@ func quasiquote(_ ast: MalData) -> MalData { } func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { - func macroexpand(_ anAst: MalData, env: Env) throws -> MalData { - func isMacro_call(_ ast: MalData, env: Env) -> Bool { // not used - if let list = ast as? [MalData], - let symbol = list[0] as? Symbol, - let fn = try? env.get(forKey: symbol) as? Function { - return fn?.isMacro ?? false - } - return false - } - - var ast = anAst - while let list = ast as? [MalData], - let symbol = list[0] as? Symbol, - let fn = try? env.get(forKey: symbol) as? Function, - let isMacro = fn?.isMacro, isMacro == true { - ast = try fn!.fn(List(list.dropFirst())) - } - return ast - } - - /// Apply var ast = anAst, env = anEnv while true { + if let dbgeval = try? env.get(forKey: Symbol("DEBUG-EVAL")) { + if ![.False, .Nil].contains(dbgeval.dataType) { + print("EVAL: " + PRINT(ast)) + } + } switch ast.dataType { case .List: - if (ast as! [MalData]).isEmpty { return ast } - ast = try macroexpand(ast, env: env) - guard let list = ast as? [MalData] else { return try eval_ast(ast, env: env) } + let list = ast as! [MalData] guard !list.isEmpty else { return list } if let sym = list[0] as? Symbol { switch sym.name { @@ -119,27 +101,28 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { return Function(ast: list[2], params: (list[1].listForm as! [Symbol]), env:env , fn: fn) case "quote": return list[1] - case "quasiquoteexpand": - return quasiquote(list[1]) case "quasiquote": ast = quasiquote(list[1]) continue - case "macroexpand": - return try macroexpand(list[1], env: env) default: break } } // not a symbol. maybe: function, list, or some wrong type - let evaluated = try eval_ast(list, env: env) as! [MalData] - guard let function = evaluated[0] as? Function else { + guard let function = try EVAL(list[0], env: env) as? Function else { throw MalError.SymbolNotFound(list[0] as? Symbol ?? Symbol("Symbol")) } + let raw_args = list.dropFirst() + if function.isMacro { + ast = try function.fn(List(raw_args)) + continue + } + let args = try raw_args.map { try EVAL($0, env: env) } if let fnAst = function.ast { // a full fn ast = fnAst - env = Env(binds: function.params!, exprs: evaluated.dropFirst().listForm, outer: function.env!) + env = Env(binds: function.params!, exprs: args, outer: function.env!) } else { // normal function - return try function.fn(evaluated.dropFirst().listForm) + return try function.fn(args) } continue case .Vector: @@ -148,8 +131,15 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { case .HashMap: let hashMap = ast as! HashMap return try hashMap.mapValues { value in try EVAL(value, env: env) } + case .Symbol: + let sym = ast as! Symbol + if let value = try? env.get(forKey: sym) { + return value + } else { + throw MalError.SymbolNotFound(sym) + } default: - return try eval_ast(ast, env: env) + return ast } } } @@ -162,27 +152,6 @@ func PRINT(_ input: MalData) -> String { return try PRINT(EVAL(READ(input), env: env)) } -func eval_ast(_ ast: MalData, env: Env) throws -> MalData { - switch ast.dataType { - case .Symbol: - let sym = ast as! Symbol - if let function = try? env.get(forKey: sym) { - return function - } else { - throw MalError.SymbolNotFound(sym) - } - case .List: - let list = ast as! [MalData] - return try list.map { element in try EVAL(element, env: env) } - case .Atom: - return (ast as! Atom).value - default: - return ast - } -} - - - var repl_env = Env() for (key, value) in ns { repl_env.set(Function(fn: value), forKey: Symbol(key)) diff --git a/impls/swift4/Sources/step9_try/main.swift b/impls/swift4/Sources/step9_try/main.swift index 3928329305..afd07bf327 100644 --- a/impls/swift4/Sources/step9_try/main.swift +++ b/impls/swift4/Sources/step9_try/main.swift @@ -48,34 +48,16 @@ func quasiquote(_ ast: MalData) -> MalData { } func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { - func macroexpand(_ anAst: MalData, env: Env) throws -> MalData { - func isMacro_call(_ ast: MalData, env: Env) -> Bool { // not used - if let list = ast as? [MalData], - let symbol = list[0] as? Symbol, - let fn = try? env.get(forKey: symbol) as? Function { - return fn?.isMacro ?? false - } - return false - } - - var ast = anAst - while let list = ast as? [MalData], - let symbol = list[0] as? Symbol, - let fn = try? env.get(forKey: symbol) as? Function, - let isMacro = fn?.isMacro, isMacro == true { - ast = try fn!.fn(List(list.dropFirst())) - } - return ast - } - - /// Apply var ast = anAst, env = anEnv while true { + if let dbgeval = try? env.get(forKey: Symbol("DEBUG-EVAL")) { + if ![.False, .Nil].contains(dbgeval.dataType) { + print("EVAL: " + PRINT(ast)) + } + } switch ast.dataType { case .List: - if (ast as! [MalData]).isEmpty { return ast } - ast = try macroexpand(ast, env: env) - guard let list = ast as? [MalData] else { return try eval_ast(ast, env: env) } + let list = ast as! [MalData] guard !list.isEmpty else { return list } if let sym = list[0] as? Symbol { switch sym.name { @@ -119,13 +101,9 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { return Function(ast: list[2], params: (list[1].listForm as! [Symbol]), env:env , fn: fn) case "quote": return list[1] - case "quasiquoteexpand": - return quasiquote(list[1]) case "quasiquote": ast = quasiquote(list[1]) continue - case "macroexpand": - return try macroexpand(list[1], env: env) case "try*": do { return try EVAL(list[1], env: env) @@ -143,15 +121,20 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { } } // not a symbol. maybe: function, list, or some wrong type - let evaluated = try eval_ast(list, env: env) as! [MalData] - guard let function = evaluated[0] as? Function else { + guard let function = try EVAL(list[0], env: env) as? Function else { throw MalError.SymbolNotFound(list[0] as? Symbol ?? Symbol("Symbol")) } + let raw_args = list.dropFirst() + if function.isMacro { + ast = try function.fn(List(raw_args)) + continue + } + let args = try raw_args.map { try EVAL($0, env: env) } if let fnAst = function.ast { // a full fn ast = fnAst - env = Env(binds: function.params!, exprs: evaluated.dropFirst().listForm, outer: function.env!) + env = Env(binds: function.params!, exprs: args, outer: function.env!) } else { // normal function - return try function.fn(evaluated.dropFirst().listForm) + return try function.fn(args) } continue case .Vector: @@ -160,8 +143,15 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { case .HashMap: let hashMap = ast as! HashMap return try hashMap.mapValues { value in try EVAL(value, env: env) } + case .Symbol: + let sym = ast as! Symbol + if let value = try? env.get(forKey: sym) { + return value + } else { + throw MalError.SymbolNotFound(sym) + } default: - return try eval_ast(ast, env: env) + return ast } } } @@ -174,27 +164,6 @@ func PRINT(_ input: MalData) -> String { return try PRINT(EVAL(READ(input), env: env)) } -func eval_ast(_ ast: MalData, env: Env) throws -> MalData { - switch ast.dataType { - case .Symbol: - let sym = ast as! Symbol - if let function = try? env.get(forKey: sym) { - return function - } else { - throw MalError.SymbolNotFound(sym) - } - case .List: - let list = ast as! [MalData] - return try list.map { element in try EVAL(element, env: env) } - case .Atom: - return (ast as! Atom).value - default: - return ast - } -} - - - var repl_env = Env() for (key, value) in ns { repl_env.set(Function(fn: value), forKey: Symbol(key)) diff --git a/impls/swift4/Sources/stepA_mal/main.swift b/impls/swift4/Sources/stepA_mal/main.swift index 07580b3d49..f04492f3eb 100644 --- a/impls/swift4/Sources/stepA_mal/main.swift +++ b/impls/swift4/Sources/stepA_mal/main.swift @@ -48,34 +48,16 @@ func quasiquote(_ ast: MalData) -> MalData { } func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { - func macroexpand(_ anAst: MalData, env: Env) throws -> MalData { - func isMacro_call(_ ast: MalData, env: Env) -> Bool { // not used - if let list = ast as? [MalData], - let symbol = list[0] as? Symbol, - let fn = try? env.get(forKey: symbol) as? Function { - return fn?.isMacro ?? false - } - return false - } - - var ast = anAst - while let list = ast as? [MalData], - let symbol = list[0] as? Symbol, - let fn = try? env.get(forKey: symbol) as? Function, - let isMacro = fn?.isMacro, isMacro == true { - ast = try fn!.fn(List(list.dropFirst())) - } - return ast - } - - /// Apply var ast = anAst, env = anEnv while true { + if let dbgeval = try? env.get(forKey: Symbol("DEBUG-EVAL")) { + if ![.False, .Nil].contains(dbgeval.dataType) { + print("EVAL: " + PRINT(ast)) + } + } switch ast.dataType { case .List: - if (ast as! [MalData]).isEmpty { return ast } - ast = try macroexpand(ast, env: env) - guard let list = ast as? [MalData] else { return try eval_ast(ast, env: env) } + let list = ast as! [MalData] guard !list.isEmpty else { return list } if let sym = list[0] as? Symbol { switch sym.name { @@ -119,13 +101,9 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { return Function(ast: list[2], params: (list[1].listForm as! [Symbol]), env:env , fn: fn) case "quote": return list[1] - case "quasiquoteexpand": - return quasiquote(list[1]) case "quasiquote": ast = quasiquote(list[1]) continue - case "macroexpand": - return try macroexpand(list[1], env: env) case "try*": do { return try EVAL(list[1], env: env) @@ -143,15 +121,20 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { } } // not a symbol. maybe: function, list, or some wrong type - let evaluated = try eval_ast(list, env: env) as! [MalData] - guard let function = evaluated[0] as? Function else { + guard let function = try EVAL(list[0], env: env) as? Function else { throw MalError.SymbolNotFound(list[0] as? Symbol ?? Symbol("Symbol")) } + let raw_args = list.dropFirst() + if function.isMacro { + ast = try function.fn(List(raw_args)) + continue + } + let args = try raw_args.map { try EVAL($0, env: env) } if let fnAst = function.ast { // a full fn ast = fnAst - env = Env(binds: function.params!, exprs: evaluated.dropFirst().listForm, outer: function.env!) + env = Env(binds: function.params!, exprs: args, outer: function.env!) } else { // normal function - return try function.fn(evaluated.dropFirst().listForm) + return try function.fn(args) } continue case .Vector: @@ -160,8 +143,15 @@ func EVAL(_ anAst: MalData, env anEnv: Env) throws -> MalData { case .HashMap: let hashMap = ast as! HashMap return try hashMap.mapValues { value in try EVAL(value, env: env) } + case .Symbol: + let sym = ast as! Symbol + if let value = try? env.get(forKey: sym) { + return value + } else { + throw MalError.SymbolNotFound(sym) + } default: - return try eval_ast(ast, env: env) + return ast } } } @@ -174,27 +164,6 @@ func PRINT(_ input: MalData) -> String { return try PRINT(EVAL(READ(input), env: env)) } -func eval_ast(_ ast: MalData, env: Env) throws -> MalData { - switch ast.dataType { - case .Symbol: - let sym = ast as! Symbol - if let function = try? env.get(forKey: sym) { - return function - } else { - throw MalError.SymbolNotFound(sym) - } - case .List: - let list = ast as! [MalData] - return try list.map { element in try EVAL(element, env: env) } - case .Atom: - return (ast as! Atom).value - default: - return ast - } -} - - - var repl_env = Env() for (key, value) in ns { repl_env.set(Function(fn: value), forKey: Symbol(key))