diff --git a/impls/swift5/Sources/core/Env.swift b/impls/swift5/Sources/core/Env.swift index ef86a598b4..4fe7d6ef95 100644 --- a/impls/swift5/Sources/core/Env.swift +++ b/impls/swift5/Sources/core/Env.swift @@ -29,17 +29,12 @@ public class Env { data[key] = val } - public func get(_ key: String) throws -> Expr { - guard let val = find(key) else { throw MalError.symbolNotFound(key) } - return val - } - - private func find(_ key: String) -> Expr? { + public func get(_ key: String) -> Expr? { if let val = data[key] { return val } if let outer = outer { - return outer.find(key) + return outer.get(key) } return nil } diff --git a/impls/swift5/Sources/step2_eval/main.swift b/impls/swift5/Sources/step2_eval/main.swift index 378b0f0d78..60b7b53019 100644 --- a/impls/swift5/Sources/step2_eval/main.swift +++ b/impls/swift5/Sources/step2_eval/main.swift @@ -24,33 +24,32 @@ func read(_ s: String) throws -> Expr { return try Reader.read(s) } -private func evalAst(_ expr: Expr, env: Env) throws -> Expr { +func eval(_ expr: Expr, env: Env) throws -> Expr { + + // print("EVAL: " + print(expr)) + switch expr { case let .symbol(name): - return try env.get(name) + let val = env.get(name) + guard val != nil else { throw MalError.symbolNotFound(name) } + return val! case let .vector(values, _): return .vector(try values.map { try eval($0, env: env) }) case let .hashmap(values, _): return .hashmap(try values.mapValues { try eval($0, env: env) }) case let .list(ast, _): - return .list(try ast.map { try eval($0, env: env) }) - default: - return expr - } -} -func eval(_ expr: Expr, env: Env) throws -> Expr { - guard case let .list(values, _) = expr else { - return try evalAst(expr, env: env) - } + if ast.isEmpty { + return expr + } - if values.isEmpty { + let ast = try ast.map { try eval($0, env: env) } + guard case let .function(fn) = ast.first else { throw MalError.invalidFunctionCall(ast[0]) } + return try fn.run(Array(ast.dropFirst())) + + default: return expr } - - let ast = try values.map { try eval($0, env: env) } - guard case let .function(fn) = ast.first else { throw MalError.invalidFunctionCall(ast[0]) } - return try fn.run(Array(ast.dropFirst())) } func print(_ expr: Expr) -> String { diff --git a/impls/swift5/Sources/step3_env/main.swift b/impls/swift5/Sources/step3_env/main.swift index 14d79aa5d3..ea93a2feb0 100644 --- a/impls/swift5/Sources/step3_env/main.swift +++ b/impls/swift5/Sources/step3_env/main.swift @@ -24,63 +24,64 @@ func read(_ s: String) throws -> Expr { return try Reader.read(s) } -private func evalAst(_ expr: Expr, env: Env) throws -> Expr { +func eval(_ expr: Expr, env: Env) throws -> Expr { + + switch env.get("DEBUG-EVAL") { + case nil, .bool(false), .null: break + default: print("EVAL: " + print(expr)) + } + switch expr { case let .symbol(name): - return try env.get(name) + let val = env.get(name) + guard val != nil else { throw MalError.symbolNotFound(name) } + return val! case let .vector(values, _): return .vector(try values.map { try eval($0, env: env) }) case let .hashmap(values, _): return .hashmap(try values.mapValues { try eval($0, env: env) }) case let .list(ast, _): - return .list(try ast.map { try eval($0, env: env) }) - default: - return expr - } -} -func eval(_ expr: Expr, env: Env) throws -> Expr { + if ast.isEmpty { + return expr + } - guard case let .list(ast, _) = expr else { - return try evalAst(expr, env: env) - } - if ast.isEmpty { - return expr - } + switch ast[0] { - switch ast[0] { + case .symbol("def!"): + guard ast.count == 3 else { throw MalError.invalidArguments("def!") } + guard case let .symbol(name) = ast[1] else { throw MalError.invalidArguments("def!") } - case .symbol("def!"): - guard ast.count == 3 else { throw MalError.invalidArguments("def!") } - guard case let .symbol(name) = ast[1] else { throw MalError.invalidArguments("def!") } + let val = try eval(ast[2], env: env) + env.set(forKey: name, val: val) + return val - let val = try eval(ast[2], env: env) - env.set(forKey: name, val: val) - return val + case .symbol("let*"): + guard ast.count == 3 else { throw MalError.invalidArguments("let*") } - case .symbol("let*"): - guard ast.count == 3 else { throw MalError.invalidArguments("let*") } + switch ast[1] { + case let .list(bindable, _), let .vector(bindable, _): + let letEnv = Env(outer: env) - switch ast[1] { - case let .list(bindable, _), let .vector(bindable, _): - let letEnv = Env(outer: env) + for i in stride(from: 0, to: bindable.count - 1, by: 2) { + guard case let .symbol(key) = bindable[i] else { throw MalError.invalidArguments("let*") } + let value = bindable[i + 1] + letEnv.set(forKey: key, val: try eval(value, env: letEnv)) + } - for i in stride(from: 0, to: bindable.count - 1, by: 2) { - guard case let .symbol(key) = bindable[i] else { throw MalError.invalidArguments("let*") } - let value = bindable[i + 1] - letEnv.set(forKey: key, val: try eval(value, env: letEnv)) + let expToEval = ast[2] + return try eval(expToEval, env: letEnv) + default: + throw MalError.invalidArguments("let*") } - let expToEval = ast[2] - return try eval(expToEval, env: letEnv) default: - throw MalError.invalidArguments("let*") + let ast = try ast.map { try eval($0, env: env) } + guard case let .function(fn) = ast[0] else { throw MalError.invalidFunctionCall(ast[0]) } + return try fn.run(Array(ast.dropFirst())) } - default: - guard case let .list(ast, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = ast[0] else { throw MalError.invalidFunctionCall(ast[0]) } - return try fn.run(Array(ast.dropFirst())) + return expr } } diff --git a/impls/swift5/Sources/step4_if_fn_do/main.swift b/impls/swift5/Sources/step4_if_fn_do/main.swift index 2c110443cc..b8ce6f3d32 100644 --- a/impls/swift5/Sources/step4_if_fn_do/main.swift +++ b/impls/swift5/Sources/step4_if_fn_do/main.swift @@ -5,101 +5,102 @@ func read(_ s: String) throws -> Expr { return try Reader.read(s) } -private func evalAst(_ expr: Expr, env: Env) throws -> Expr { +func eval(_ expr: Expr, env: Env) throws -> Expr { + + switch env.get("DEBUG-EVAL") { + case nil, .bool(false), .null: break + default: print("EVAL: " + print(expr)) + } + switch expr { case let .symbol(name): - return try env.get(name) + let val = env.get(name) + guard val != nil else { throw MalError.symbolNotFound(name) } + return val! case let .vector(values, _): return .vector(try values.map { try eval($0, env: env) }) case let .hashmap(values, _): return .hashmap(try values.mapValues { try eval($0, env: env) }) case let .list(ast, _): - return .list(try ast.map { try eval($0, env: env) }) - default: - return expr - } -} -func eval(_ expr: Expr, env: Env) throws -> Expr { + if ast.isEmpty { + return expr + } - guard case let .list(ast, _) = expr else { - return try evalAst(expr, env: env) - } - if ast.isEmpty { - return expr - } + switch ast[0] { - switch ast[0] { + case .symbol("def!"): + guard ast.count == 3 else { throw MalError.invalidArguments("def!") } + guard case let .symbol(name) = ast[1] else { throw MalError.invalidArguments("def!") } - case .symbol("def!"): - guard ast.count == 3 else { throw MalError.invalidArguments("def!") } - guard case let .symbol(name) = ast[1] else { throw MalError.invalidArguments("def!") } + let val = try eval(ast[2], env: env) + env.set(forKey: name, val: val) + return val - let val = try eval(ast[2], env: env) - env.set(forKey: name, val: val) - return val + case .symbol("let*"): + guard ast.count == 3 else { throw MalError.invalidArguments("let*") } - case .symbol("let*"): - guard ast.count == 3 else { throw MalError.invalidArguments("let*") } + switch ast[1] { + case let .list(bindable, _), let .vector(bindable, _): + let letEnv = Env(outer: env) - switch ast[1] { - case let .list(bindable, _), let .vector(bindable, _): - let letEnv = Env(outer: env) + for i in stride(from: 0, to: bindable.count - 1, by: 2) { + guard case let .symbol(key) = bindable[i] else { throw MalError.invalidArguments("let*") } + let value = bindable[i + 1] + letEnv.set(forKey: key, val: try eval(value, env: letEnv)) + } - for i in stride(from: 0, to: bindable.count - 1, by: 2) { - guard case let .symbol(key) = bindable[i] else { throw MalError.invalidArguments("let*") } - let value = bindable[i + 1] - letEnv.set(forKey: key, val: try eval(value, env: letEnv)) + let expToEval = ast[2] + return try eval(expToEval, env: letEnv) + default: + throw MalError.invalidArguments("let*") } - let expToEval = ast[2] - return try eval(expToEval, env: letEnv) - default: - throw MalError.invalidArguments("let*") - } - - case .symbol("do"): - let exprsToEval = ast.dropFirst() - if exprsToEval.isEmpty { throw MalError.invalidArguments("do") } - return try exprsToEval.map { try eval($0, env: env) }.last! - - case .symbol("if"): - guard 3...4 ~= ast.count else { throw MalError.invalidArguments("if") } + case .symbol("do"): + let exprsToEval = ast.dropFirst() + if exprsToEval.isEmpty { throw MalError.invalidArguments("do") } + return try exprsToEval.map { try eval($0, env: env) }.last! + + case .symbol("if"): + guard 3...4 ~= ast.count else { throw MalError.invalidArguments("if") } + + let condExpr = ast[1] + switch try eval(condExpr, env: env) { + case .bool(false), .null: + if let falseExpr = ast[safe: 3] { + return try eval(falseExpr, env: env) + } + return .null + default: + return try eval(ast[2], env: env) + } - let condExpr = ast[1] - switch try eval(condExpr, env: env) { - case .bool(false), .null: - if let falseExpr = ast[safe: 3] { - return try eval(falseExpr, env: env) + case .symbol("fn*"): + guard ast.count == 3 else { throw MalError.invalidArguments("fn*") } + let binds: [String] + switch ast[1] { + case let .list(xs, _), let .vector(xs, _): + binds = try xs.map { + guard case let .symbol(name) = $0 else { throw MalError.invalidArguments("fn*") } + return name + } + default: + throw MalError.invalidArguments("fn*") } - return .null - default: - return try eval(ast[2], env: env) - } - case .symbol("fn*"): - guard ast.count == 3 else { throw MalError.invalidArguments("fn*") } - let binds: [String] - switch ast[1] { - case let .list(xs, _), let .vector(xs, _): - binds = try xs.map { - guard case let .symbol(name) = $0 else { throw MalError.invalidArguments("fn*") } - return name + let f = Func { args in + let fEnv = try Env(binds: binds, exprs: args, outer: env) + return try eval(ast[2], env: fEnv) } - default: - throw MalError.invalidArguments("fn*") - } + return .function(f) - let f = Func { args in - let fEnv = try Env(binds: binds, exprs: args, outer: env) - return try eval(ast[2], env: fEnv) + default: + let ast = try ast.map { try eval($0, env: env) } + guard case let .function(fn) = ast[0] else { throw MalError.invalidFunctionCall(ast[0]) } + return try fn.run(Array(ast.dropFirst())) } - return .function(f) - default: - guard case let .list(ast, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = ast[0] else { throw MalError.invalidFunctionCall(ast[0]) } - return try fn.run(Array(ast.dropFirst())) + return expr } } diff --git a/impls/swift5/Sources/step5_tco/main.swift b/impls/swift5/Sources/step5_tco/main.swift index 449dd691f0..56f5740a22 100644 --- a/impls/swift5/Sources/step5_tco/main.swift +++ b/impls/swift5/Sources/step5_tco/main.swift @@ -5,31 +5,28 @@ func read(_ s: String) throws -> Expr { return try Reader.read(s) } -private func evalAst(_ expr: Expr, env: Env) throws -> Expr { +func eval(_ expr: Expr, env: Env) throws -> Expr { + + var env = env + var expr = expr + while true { + + switch env.get("DEBUG-EVAL") { + case nil, .bool(false), .null: break + default: print("EVAL: " + print(expr)) + } + switch expr { case let .symbol(name): - return try env.get(name) + let val = env.get(name) + guard val != nil else { throw MalError.symbolNotFound(name) } + return val! case let .vector(values, _): return .vector(try values.map { try eval($0, env: env) }) case let .hashmap(values, _): return .hashmap(try values.mapValues { try eval($0, env: env) }) case let .list(ast, _): - return .list(try ast.map { try eval($0, env: env) }) - default: - return expr - } -} -func eval(_ expr: Expr, env: Env) throws -> Expr { - - var env = env - var expr = expr - - while true { - - guard case let .list(ast, _) = expr else { - return try evalAst(expr, env: env) - } if ast.isEmpty { return expr } @@ -106,7 +103,7 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(ast, _) = try evalAst(expr, env: env) else { fatalError() } + let ast = try ast.map { try eval($0, env: env) } guard case let .function(fn) = ast[0] else { throw MalError.invalidFunctionCall(ast[0]) } let args = Array(ast.dropFirst()) @@ -118,6 +115,9 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return try fn.run(args) } } + default: + return expr + } } } diff --git a/impls/swift5/Sources/step6_file/main.swift b/impls/swift5/Sources/step6_file/main.swift index 935fcb9da6..dd871c8ba1 100644 --- a/impls/swift5/Sources/step6_file/main.swift +++ b/impls/swift5/Sources/step6_file/main.swift @@ -5,31 +5,28 @@ func read(_ s: String) throws -> Expr { return try Reader.read(s) } -private func evalAst(_ expr: Expr, env: Env) throws -> Expr { +func eval(_ expr: Expr, env: Env) throws -> Expr { + + var env = env + var expr = expr + while true { + + switch env.get("DEBUG-EVAL") { + case nil, .bool(false), .null: break + default: print("EVAL: " + print(expr)) + } + switch expr { case let .symbol(name): - return try env.get(name) + let val = env.get(name) + guard val != nil else { throw MalError.symbolNotFound(name) } + return val! case let .vector(values, _): return .vector(try values.map { try eval($0, env: env) }) case let .hashmap(values, _): return .hashmap(try values.mapValues { try eval($0, env: env) }) case let .list(ast, _): - return .list(try ast.map { try eval($0, env: env) }) - default: - return expr - } -} -func eval(_ expr: Expr, env: Env) throws -> Expr { - - var env = env - var expr = expr - - while true { - - guard case let .list(ast, _) = expr else { - return try evalAst(expr, env: env) - } if ast.isEmpty { return expr } @@ -106,7 +103,7 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(ast, _) = try evalAst(expr, env: env) else { fatalError() } + let ast = try ast.map { try eval($0, env: env) } guard case let .function(fn) = ast[0] else { throw MalError.invalidFunctionCall(ast[0]) } let args = Array(ast.dropFirst()) @@ -118,6 +115,9 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return try fn.run(args) } } + default: + return expr + } } } diff --git a/impls/swift5/Sources/step7_quote/main.swift b/impls/swift5/Sources/step7_quote/main.swift index 5dacab4286..026fdb8af4 100644 --- a/impls/swift5/Sources/step7_quote/main.swift +++ b/impls/swift5/Sources/step7_quote/main.swift @@ -39,31 +39,28 @@ private func quasiquote(_ expr: Expr) throws -> Expr { } } -private func evalAst(_ expr: Expr, env: Env) throws -> Expr { +func eval(_ expr: Expr, env: Env) throws -> Expr { + + var env = env + var expr = expr + while true { + + switch env.get("DEBUG-EVAL") { + case nil, .bool(false), .null: break + default: print("EVAL: " + print(expr)) + } + switch expr { case let .symbol(name): - return try env.get(name) + let val = env.get(name) + guard val != nil else { throw MalError.symbolNotFound(name) } + return val! case let .vector(values, _): return .vector(try values.map { try eval($0, env: env) }) case let .hashmap(values, _): return .hashmap(try values.mapValues { try eval($0, env: env) }) case let .list(ast, _): - return .list(try ast.map { try eval($0, env: env) }) - default: - return expr - } -} -func eval(_ expr: Expr, env: Env) throws -> Expr { - - var env = env - var expr = expr - - while true { - - guard case let .list(ast, _) = expr else { - return try evalAst(expr, env: env) - } if ast.isEmpty { return expr } @@ -101,10 +98,6 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { guard ast.count == 2 else { throw MalError.invalidArguments("quote") } return ast[1] - case .symbol("quasiquoteexpand"): - guard ast.count == 2 else { throw MalError.invalidArguments("quasiquoteexpand") } - return try quasiquote(ast[1]) - case .symbol("quasiquote"): guard ast.count == 2 else { throw MalError.invalidArguments("quasiquote") } expr = try quasiquote(ast[1]) @@ -152,7 +145,7 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(ast, _) = try evalAst(expr, env: env) else { fatalError() } + let ast = try ast.map { try eval($0, env: env) } guard case let .function(fn) = ast[0] else { throw MalError.invalidFunctionCall(ast[0]) } let args = Array(ast.dropFirst()) @@ -164,6 +157,9 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return try fn.run(args) } } + default: + return expr + } } } diff --git a/impls/swift5/Sources/step8_macros/main.swift b/impls/swift5/Sources/step8_macros/main.swift index 9998ab62b4..1317368d7e 100644 --- a/impls/swift5/Sources/step8_macros/main.swift +++ b/impls/swift5/Sources/step8_macros/main.swift @@ -39,48 +39,27 @@ private func quasiquote(_ expr: Expr) throws -> Expr { } } -private func macroExpand(_ expr: Expr, env: Env) throws -> Expr { +func eval(_ expr: Expr, env: Env) throws -> Expr { + + var env = env var expr = expr while true { - guard case let .list(ast, _) = expr, - case let .symbol(name) = ast.first, - case let .function(fn) = try? env.get(name), - fn.isMacro else { - break - } - expr = try fn.run(Array(ast.dropFirst())) + switch env.get("DEBUG-EVAL") { + case nil, .bool(false), .null: break + default: print("EVAL: " + print(expr)) } - return expr -} -private func evalAst(_ expr: Expr, env: Env) throws -> Expr { switch expr { case let .symbol(name): - return try env.get(name) + let val = env.get(name) + guard val != nil else { throw MalError.symbolNotFound(name) } + return val! case let .vector(values, _): return .vector(try values.map { try eval($0, env: env) }) case let .hashmap(values, _): return .hashmap(try values.mapValues { try eval($0, env: env) }) case let .list(ast, _): - return .list(try ast.map { try eval($0, env: env) }) - default: - return expr - } -} - -func eval(_ expr: Expr, env: Env) throws -> Expr { - - var env = env - var expr = expr - - while true { - - expr = try macroExpand(expr, env: env) - - guard case let .list(ast, _) = expr else { - return try evalAst(expr, env: env) - } if ast.isEmpty { return expr @@ -119,10 +98,6 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { guard ast.count == 2 else { throw MalError.invalidArguments("quote") } return ast[1] - case .symbol("quasiquoteexpand"): - guard ast.count == 2 else { throw MalError.invalidArguments("quasiquoteexpand") } - return try quasiquote(ast[1]) - case .symbol("quasiquote"): guard ast.count == 2 else { throw MalError.invalidArguments("quasiquote") } expr = try quasiquote(ast[1]) @@ -136,10 +111,6 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { env.set(forKey: name, val: .function(macros)) return .function(macros) - case .symbol("macroexpand"): - guard ast.count == 2 else { throw MalError.invalidArguments("macroexpand") } - return try macroExpand(ast[1], env: env) - case .symbol("do"): let exprsToEval = ast.dropFirst() guard !exprsToEval.isEmpty else { throw MalError.invalidArguments("do") } @@ -183,10 +154,12 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(ast, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = ast[0] else { throw MalError.invalidFunctionCall(ast[0]) } - - let args = Array(ast.dropFirst()) + guard case let .function(fn) = try eval(ast[0], env: env) else { throw MalError.invalidFunctionCall(ast[0]) } + if fn.isMacro { + expr = try fn.run(Array(ast.dropFirst())) + continue + } + let args = try ast.dropFirst().map { try eval($0, env: env) } if let ast = fn.ast, let fnEnv = fn.env { let newEnv = try Env(binds: fn.params, exprs: args, outer: fnEnv) env = newEnv @@ -195,6 +168,9 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return try fn.run(args) } } + default: + return expr + } } } diff --git a/impls/swift5/Sources/step9_try/main.swift b/impls/swift5/Sources/step9_try/main.swift index a30731d4f9..c90663c957 100644 --- a/impls/swift5/Sources/step9_try/main.swift +++ b/impls/swift5/Sources/step9_try/main.swift @@ -39,48 +39,27 @@ private func quasiquote(_ expr: Expr) throws -> Expr { } } -private func macroExpand(_ expr: Expr, env: Env) throws -> Expr { +func eval(_ expr: Expr, env: Env) throws -> Expr { + + var env = env var expr = expr while true { - guard case let .list(ast, _) = expr, - case let .symbol(name) = ast.first, - case let .function(fn) = try? env.get(name), - fn.isMacro else { - break - } - expr = try fn.run(Array(ast.dropFirst())) + switch env.get("DEBUG-EVAL") { + case nil, .bool(false), .null: break + default: print("EVAL: " + print(expr)) } - return expr -} -private func evalAst(_ expr: Expr, env: Env) throws -> Expr { switch expr { case let .symbol(name): - return try env.get(name) + let val = env.get(name) + guard val != nil else { throw MalError.symbolNotFound(name) } + return val! case let .vector(values, _): return .vector(try values.map { try eval($0, env: env) }) case let .hashmap(values, _): return .hashmap(try values.mapValues { try eval($0, env: env) }) case let .list(ast, _): - return .list(try ast.map { try eval($0, env: env) }) - default: - return expr - } -} - -func eval(_ expr: Expr, env: Env) throws -> Expr { - - var env = env - var expr = expr - - while true { - - expr = try macroExpand(expr, env: env) - - guard case let .list(ast, _) = expr else { - return try evalAst(expr, env: env) - } if ast.isEmpty { return expr @@ -119,10 +98,6 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { guard ast.count == 2 else { throw MalError.invalidArguments("quote") } return ast[1] - case .symbol("quasiquoteexpand"): - guard ast.count == 2 else { throw MalError.invalidArguments("quasiquoteexpand") } - return try quasiquote(ast[1]) - case .symbol("quasiquote"): guard ast.count == 2 else { throw MalError.invalidArguments("quasiquote") } expr = try quasiquote(ast[1]) @@ -136,10 +111,6 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { env.set(forKey: name, val: .function(macros)) return .function(macros) - case .symbol("macroexpand"): - guard ast.count == 2 else { throw MalError.invalidArguments("macroexpand") } - return try macroExpand(ast[1], env: env) - case .symbol("try*"): if ast.count == 2 { expr = ast[1] @@ -202,10 +173,12 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(ast, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = ast[0] else { throw MalError.invalidFunctionCall(ast[0]) } - - let args = Array(ast.dropFirst()) + guard case let .function(fn) = try eval(ast[0], env: env) else { throw MalError.invalidFunctionCall(ast[0]) } + if fn.isMacro { + expr = try fn.run(Array(ast.dropFirst())) + continue + } + let args = try ast.dropFirst().map { try eval($0, env: env) } if let ast = fn.ast, let fnEnv = fn.env { let newEnv = try Env(binds: fn.params, exprs: args, outer: fnEnv) env = newEnv @@ -214,6 +187,9 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return try fn.run(args) } } + default: + return expr + } } } diff --git a/impls/swift5/Sources/stepA_mal/main.swift b/impls/swift5/Sources/stepA_mal/main.swift index defb9edeae..0afd903525 100644 --- a/impls/swift5/Sources/stepA_mal/main.swift +++ b/impls/swift5/Sources/stepA_mal/main.swift @@ -39,48 +39,27 @@ private func quasiquote(_ expr: Expr) throws -> Expr { } } -private func macroExpand(_ expr: Expr, env: Env) throws -> Expr { +func eval(_ expr: Expr, env: Env) throws -> Expr { + + var env = env var expr = expr while true { - guard case let .list(ast, _) = expr, - case let .symbol(name) = ast.first, - case let .function(fn) = try? env.get(name), - fn.isMacro else { - break - } - expr = try fn.run(Array(ast.dropFirst())) + switch env.get("DEBUG-EVAL") { + case nil, .bool(false), .null: break + default: print("EVAL: " + print(expr)) } - return expr -} -private func evalAst(_ expr: Expr, env: Env) throws -> Expr { switch expr { case let .symbol(name): - return try env.get(name) + let val = env.get(name) + guard val != nil else { throw MalError.symbolNotFound(name) } + return val! case let .vector(values, _): return .vector(try values.map { try eval($0, env: env) }) case let .hashmap(values, _): return .hashmap(try values.mapValues { try eval($0, env: env) }) case let .list(ast, _): - return .list(try ast.map { try eval($0, env: env) }) - default: - return expr - } -} - -func eval(_ expr: Expr, env: Env) throws -> Expr { - - var env = env - var expr = expr - - while true { - - expr = try macroExpand(expr, env: env) - - guard case let .list(ast, _) = expr else { - return try evalAst(expr, env: env) - } if ast.isEmpty { return expr @@ -119,10 +98,6 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { guard ast.count == 2 else { throw MalError.invalidArguments("quote") } return ast[1] - case .symbol("quasiquoteexpand"): - guard ast.count == 2 else { throw MalError.invalidArguments("quasiquoteexpand") } - return try quasiquote(ast[1]) - case .symbol("quasiquote"): guard ast.count == 2 else { throw MalError.invalidArguments("quasiquote") } expr = try quasiquote(ast[1]) @@ -136,10 +111,6 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { env.set(forKey: name, val: .function(macros)) return .function(macros) - case .symbol("macroexpand"): - guard ast.count == 2 else { throw MalError.invalidArguments("macroexpand") } - return try macroExpand(ast[1], env: env) - case .symbol("try*"): if ast.count == 2 { expr = ast[1] @@ -202,10 +173,12 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(ast, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = ast[0] else { throw MalError.invalidFunctionCall(ast[0]) } - - let args = Array(ast.dropFirst()) + guard case let .function(fn) = try eval(ast[0], env: env) else { throw MalError.invalidFunctionCall(ast[0]) } + if fn.isMacro { + expr = try fn.run(Array(ast.dropFirst())) + continue + } + let args = try ast.dropFirst().map { try eval($0, env: env) } if let ast = fn.ast, let fnEnv = fn.env { let newEnv = try Env(binds: fn.params, exprs: args, outer: fnEnv) env = newEnv @@ -214,6 +187,9 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return try fn.run(args) } } + default: + return expr + } } }