From b667adf5e3ccd1b23e9488cc5263e8277b88ba49 Mon Sep 17 00:00:00 2001 From: Oleg Montak Date: Fri, 8 Nov 2019 20:29:42 +0300 Subject: [PATCH] swift5: refactor a bit --- README.md | 3 +- swift5/Dockerfile | 2 +- swift5/Sources/core/Core.swift | 24 ++--- swift5/Sources/core/Env.swift | 6 +- swift5/Sources/core/Errors.swift | 29 ++++-- swift5/Sources/core/Parser.swift | 17 +--- swift5/Sources/core/Printer.swift | 1 + swift5/Sources/core/Reader.swift | 121 +++++++++++++---------- swift5/Sources/core/Types.swift | 4 + swift5/Sources/step2_eval/main.swift | 23 ++--- swift5/Sources/step3_env/main.swift | 93 +++++++---------- swift5/Sources/step4_if_fn_do/main.swift | 8 +- swift5/Sources/step5_tco/main.swift | 8 +- swift5/Sources/step6_file/main.swift | 8 +- swift5/Sources/step7_quote/main.swift | 8 +- swift5/Sources/step8_macros/main.swift | 8 +- swift5/Sources/step9_try/main.swift | 8 +- swift5/Sources/stepA_mal/main.swift | 8 +- 18 files changed, 187 insertions(+), 192 deletions(-) diff --git a/README.md b/README.md index 22dccf8c..6f09403b 100644 --- a/README.md +++ b/README.md @@ -1026,8 +1026,7 @@ has been tested with Swift 5.1.1 release. ``` cd swift5 -make -./stepX_YYY +swift run stepX_YYY ``` ### Tcl 8.6 diff --git a/swift5/Dockerfile b/swift5/Dockerfile index b2f2ef26..b757d3c3 100644 --- a/swift5/Dockerfile +++ b/swift5/Dockerfile @@ -35,7 +35,7 @@ ENV SWIFT_PREFIX swift-5.1.1-RELEASE ENV SWIFT_RELEASE ${SWIFT_PREFIX}-ubuntu16.04 RUN cd /opt && \ - curl -O https://swift.org/builds/swift-4.2.3-release/ubuntu1604/${SWIFT_PREFIX}/${SWIFT_RELEASE}.tar.gz && \ + curl -O https://swift.org/builds/swift-5.1.1-release/ubuntu1604/${SWIFT_PREFIX}/${SWIFT_RELEASE}.tar.gz && \ tar xvzf ${SWIFT_RELEASE}.tar.gz && \ rm ${SWIFT_RELEASE}.tar.gz diff --git a/swift5/Sources/core/Core.swift b/swift5/Sources/core/Core.swift index 73592c7c..0b67a39d 100644 --- a/swift5/Sources/core/Core.swift +++ b/swift5/Sources/core/Core.swift @@ -2,26 +2,22 @@ import Foundation private extension Func { private static func hashMapDataFrom(_ args: [Expr]) throws -> [String: Expr] { - guard args.count.isMultiple(of: 2) else { throw MalError("invalid arguments") } + guard args.count.isMultiple(of: 2) else { throw MalError.invalidArguments() } var data: [String: Expr] = [:] for i in stride(from: 0, to: args.count - 1, by: 2) { - guard case let .string(key) = args[i] else { throw MalError("invalid arguments") } + guard case let .string(key) = args[i] else { throw MalError.invalidArguments() } let value = args[i + 1] data[key] = value } return data } - static let notImplemented = Func { args in - throw MalError("not implemented") - } - - static func infixOperation(_ op: @escaping (Int, Int) -> Int) -> Func { + static func intOperation(_ op: @escaping (Int, Int) -> Int) -> Func { return Func { args in guard args.count == 2, case let .number(a) = args[0], - case let .number(b) = args[1] else { throw MalError("invalid arguments") } + case let .number(b) = args[1] else { throw MalError.invalidArguments() } return .number(op(a, b)) } @@ -31,7 +27,7 @@ private extension Func { return Func { args in guard args.count == 2, case let .number(a) = args[0], - case let .number(b) = args[1] else { throw MalError("invalid arguments") } + case let .number(b) = args[1] else { throw MalError.invalidArguments() } return .bool(op(a, b)) } @@ -135,7 +131,7 @@ private extension Func { } static let swap = Func { args in - guard args.count >= 2 else { throw MalError.invalidArguments("reset!") } + guard args.count >= 2 else { throw MalError.invalidArguments("swap!") } guard case let .atom(atom) = args[0] else { throw MalError.invalidArguments("swap!") } guard case let .function(fn) = args[1] else { throw MalError.invalidArguments("swap!") } let otherArgs = args.dropFirst(2) @@ -491,10 +487,10 @@ private extension Func { } private let data: [String: Expr] = [ - "+": .function(.infixOperation(+)), - "-": .function(.infixOperation(-)), - "*": .function(.infixOperation(*)), - "/": .function(.infixOperation(/)), + "+": .function(.intOperation(+)), + "-": .function(.intOperation(-)), + "*": .function(.intOperation(*)), + "/": .function(.intOperation(/)), "prn": .function(.prn), "println": .function(.println), "pr-str": .function(.prStr), diff --git a/swift5/Sources/core/Env.swift b/swift5/Sources/core/Env.swift index 630a5a92..ef86a598 100644 --- a/swift5/Sources/core/Env.swift +++ b/swift5/Sources/core/Env.swift @@ -16,11 +16,11 @@ public class Env { for i in 0.. Expr { - guard let val = find(key) else { throw MalError("'\(key)' not found") } + guard let val = find(key) else { throw MalError.symbolNotFound(key) } return val } diff --git a/swift5/Sources/core/Errors.swift b/swift5/Sources/core/Errors.swift index ec5ce137..be3b1a1c 100644 --- a/swift5/Sources/core/Errors.swift +++ b/swift5/Sources/core/Errors.swift @@ -13,15 +13,6 @@ public struct MalError: Error, LocalizedError { } extension MalError { - public static func arityMismath(name: String, expected: String, given: Int) -> MalError { - let message = """ - \(name): arity mismatch - expected: \(expected) - given: \(given) - """ - return MalError(message) - } - public static func unbalanced(expected: String) -> MalError { return MalError("unbalanced: expected \(expected)") } @@ -34,9 +25,29 @@ extension MalError { return MalError("\(name): invalid arguments") } + public static func invalidArguments() -> MalError { + return MalError("invalid arguments") + } + public static func outOfRange() -> MalError { return MalError("index out of range") } + + public static func invalidFunctionCall(_ expr: Expr) -> MalError { + return MalError("not a function: \(expr)") + } + + public static func symbolNotFound(_ s: String) -> MalError { + return MalError("'\(s)' not found") + } + + public static func invalidVariadicFunction() -> MalError { + return MalError("invalid variadic function definition") + } + + public static func reader() -> MalError { + return MalError("can't parse") + } } extension Expr: Error, LocalizedError { diff --git a/swift5/Sources/core/Parser.swift b/swift5/Sources/core/Parser.swift index 045cd6d6..2cfb5c4d 100644 --- a/swift5/Sources/core/Parser.swift +++ b/swift5/Sources/core/Parser.swift @@ -51,6 +51,9 @@ extension Parsers { static func string(excluding string: String) -> Parser { char(excluding: string).oneOrMore.map { String($0) } } + + static let digit = char(from: "0123456789") + static let naturalNumber = digit.oneOrMore.map { Int(String($0)) } } extension Parser: ExpressibleByStringLiteral, ExpressibleByUnicodeScalarLiteral, ExpressibleByExtendedGraphemeClusterLiteral where A == Void { @@ -126,11 +129,6 @@ extension Parser { var oneOrMore: Parser<[A]> { zeroOrMore.map { $0.isEmpty ? nil : $0 } } - - /// Matches of the parser produces no matches (inverts the parser). - var zero: Parser { - map { _ in nil } - } } // MARK: - Parser (Optional) @@ -144,15 +142,6 @@ func optional(_ parser: Parser) -> Parser { } } -func optional(_ parser: Parser) -> Parser { - Parser { str -> (Bool, Substring)? in - guard let match = try parser.parse(str) else { - return (false, str) // Return empty match without consuming any characters - } - return (true, match.1) - } -} - // MARK: - Parser (Error Reporting) extension Parser { diff --git a/swift5/Sources/core/Printer.swift b/swift5/Sources/core/Printer.swift index 91c88577..1c41fa69 100644 --- a/swift5/Sources/core/Printer.swift +++ b/swift5/Sources/core/Printer.swift @@ -1,6 +1,7 @@ import Foundation extension Expr { + public static func print(readable: Bool = true, _ expr: Expr) -> String { let print = curry(Self.print)(readable) diff --git a/swift5/Sources/core/Reader.swift b/swift5/Sources/core/Reader.swift index cb6f74cc..32f70c40 100644 --- a/swift5/Sources/core/Reader.swift +++ b/swift5/Sources/core/Reader.swift @@ -3,7 +3,7 @@ import Foundation public enum Reader { public static func read(_ str: String) throws -> Expr { - return try Parsers.expr.orThrow(MalError("Can't parse")).parse(str)! + return try Parsers.expr.orThrow(MalError.reader()).parse(str)! } } @@ -11,20 +11,6 @@ private extension Parsers { static let expr = form <* endPattern - static let form = oneOf( - list, - vector, - hashmap, - eString, - number, - null, - bool, - symbol, - keyword, - sugar - ).spacesAround() - static let _form: Parser = lazy(form) - static let endPattern = oneOf( end, char(from: ")").zeroOrThrow(.unbalanced(unexpected: ")")), @@ -32,19 +18,32 @@ private extension Parsers { char(from: "}").zeroOrThrow(.unbalanced(unexpected: "}")) ) - static let digit = char(from: "0123456789") - static let naturalNumber = digit.oneOrMore.map { Int(String($0)) } - static let number = (optional(char(from: "-")) <*> naturalNumber).map(makeNumber) - static func makeNumber(_ negative: Character?, value: Int) -> Expr { - let factor = negative != nil ? -1 : 1 - return .number(value * factor) - } + static let form = oneOf( + list, + vector, + hashmap, + atom, + readerMacros + ).ignoreAround() - static let list = ("(" *> _form.zeroOrMore.spacesAround() <* string(")").orThrow(.unbalanced(expected: ")"))).map { Expr.list($0) } - static let vector = ("[" *> _form.zeroOrMore.spacesAround() <* string("]").orThrow(.unbalanced(expected: "]"))).map { Expr.vector($0) } + static let _form: Parser = lazy(form) - static let hashmap = ("{" *> (hashmapKey <*> _form).zeroOrMore.spacesAround() <* string("}").orThrow(.unbalanced(expected: "}"))).map(makeExprHashmap) - static func makeExprHashmap(_ xs: [(Expr, Expr)]) -> Expr { + static let atom = oneOf( + malString, + number, + null, + bool, + symbol, + keyword + ) + + static let list = ("(" *> _form.zeroOrMore.ignoreAround() <* string(")").orThrow(.unbalanced(expected: ")"))).map { Expr.list($0) } + static let vector = ("[" *> _form.zeroOrMore.ignoreAround() <* string("]").orThrow(.unbalanced(expected: "]"))).map { Expr.vector($0) } + + // MARK: - Hashmap + + static let hashmap = ("{" *> (hashmapKey <*> _form).zeroOrMore.ignoreAround() <* string("}").orThrow(.unbalanced(expected: "}"))).map(makeHashmap) + static func makeHashmap(_ xs: [(Expr, Expr)]) -> Expr { var dict: [String: Expr] = [:] for x in xs { guard case let .string(key) = x.0 else { fatalError() } @@ -53,7 +52,17 @@ private extension Parsers { return .hashmap(dict) } - static let hashmapKey = oneOf(eString, keyword) + static let hashmapKey = oneOf(malString, keyword) + + // MARK: - Number + + static let number = (optional(char(from: "-")) <*> naturalNumber).map(makeNumber) + static func makeNumber(_ negative: Character?, value: Int) -> Expr { + let factor = negative != nil ? -1 : 1 + return .number(value * factor) + } + + // MARK: - String static let stringContent = oneOf( string(excluding: "\\\""), @@ -63,18 +72,24 @@ private extension Parsers { string("\\").map { "\\" } ) - static let eString = ( - "\"" *> stringContent.zeroOrMore <* string("\"").orThrow(.unbalanced(expected: "\"")) - ).map(makeExprString) - - static func makeExprString(_ xs: [String]) -> Expr { + static let malString = ("\"" *> stringContent.zeroOrMore <* string("\"").orThrow(.unbalanced(expected: "\""))).map(makeMalString) + static func makeMalString(_ xs: [String]) -> Expr { return .string(xs.joined()) } + // MARK: - Keyword + + static let keyword = (":" *> name).map { Expr.string(String(keywordMagic) + $0) } + + // MARK: - Symbol + static let symbolHead = char(excluding: "0123456789^`'\"#~@:%()[]{} \n\r\t,") static let symbolRest = oneOf(symbolHead, char(from: "0123456789.")) + static let name = (symbolHead <*> symbolRest.zeroOrMore).map { String($0) + String($1) } static let symbol = name.map(Expr.symbol) + // MARK: - Bool + static let bool = name.map(makeBool) static func makeBool(_ s: String) -> Expr? { switch s { @@ -84,29 +99,24 @@ private extension Parsers { } } + // MARK: - Null + static let null = name.map(makeNull) static func makeNull(_ s: String) -> Expr? { - if s == "nil" { - return .null - } - return nil + return s == "nil" ? .null : nil } - static let name = (symbolHead <*> symbolRest.zeroOrMore).map { String($0) + String($1) } - static let keyword = (":" *> name).map { Expr.string(String(keywordMagic) + $0) } + // MARK: - Reader macros - private static func expandMacros(_ symbolName: String, _ rest: Expr...) -> Expr { - return Expr.list([.symbol(symbolName)] + rest) - } + static let quote = ("'" *> _form).readerMacros("quote") + static let quasiquote = ("`" *> _form).readerMacros("quasiquote") + static let spliceUnquote = ("~@" *> _form).readerMacros("splice-unquote") + static let unquote = ("~" *> _form).readerMacros("unquote") + static let deref = ("@" *> _form).readerMacros("deref") + static let meta = ("^" *> hashmap <*> _form).map { Expr.list([.symbol("with-meta"), $1, $0]) } - static let quote = ("'" *> _form).map { expandMacros("quote", $0) } - static let quasiquote = ("`" *> _form).map { expandMacros("quasiquote", $0) } - static let spliceUnquote = ("~@" *> _form).map { expandMacros("splice-unquote", $0) } - static let unquote = ("~" *> _form).map { expandMacros("unquote", $0) } - static let deref = ("@" *> _form).map { expandMacros("deref", $0) } - static let meta = ("^" *> hashmap <*> _form).map { expandMacros("with-meta", $1, $0) } - static let sugar = oneOf( + static let readerMacros = oneOf( quote, quasiquote, spliceUnquote, @@ -114,18 +124,23 @@ private extension Parsers { deref, meta ) -} -extension Parsers { + // MARK: - Ignore static let whitespace = char(from: " \n\r\t,") static let comment = char(from: ";") <* char(excluding: "\n\r").zeroOrMore - static let trash = oneOf(whitespace, comment) + static let ignore = oneOf(whitespace, comment) } extension Parser { - func spacesAround() -> Parser { - return (Parsers.trash.zeroOrMore *> self <* Parsers.trash.zeroOrMore) + func ignoreAround() -> Parser { + return (Parsers.ignore.zeroOrMore *> self <* Parsers.ignore.zeroOrMore) + } +} + +extension Parser where A == Expr { + func readerMacros(_ s: String) -> Parser { + return map { Expr.list([.symbol(s), $0]) } } } diff --git a/swift5/Sources/core/Types.swift b/swift5/Sources/core/Types.swift index 8bb69e46..6ee53bc9 100644 --- a/swift5/Sources/core/Types.swift +++ b/swift5/Sources/core/Types.swift @@ -60,6 +60,8 @@ extension Expr: Equatable { } } +// MARK: - Func + final public class Func { public let run: ([Expr]) throws -> Expr public let ast: Expr? @@ -99,6 +101,8 @@ extension Func: Equatable { } } +// MARK: - Atom + final public class Atom { public var val: Expr public let meta: Expr diff --git a/swift5/Sources/step2_eval/main.swift b/swift5/Sources/step2_eval/main.swift index d4334ef0..378b0f0d 100644 --- a/swift5/Sources/step2_eval/main.swift +++ b/swift5/Sources/step2_eval/main.swift @@ -7,7 +7,7 @@ extension Func { return Func { args in guard args.count == 2, case let .number(a) = args[0], - case let .number(b) = args[1] else { throw MalError("invalid arguments") } + case let .number(b) = args[1] else { throw MalError.invalidArguments() } return .number(op(a, b)) } @@ -24,32 +24,33 @@ func read(_ s: String) throws -> Expr { return try Reader.read(s) } -func eval(_ expr: Expr, env: Env) throws -> Expr { +private func evalAst(_ expr: Expr, env: Env) throws -> Expr { switch expr { case let .symbol(name): - let value = try env.get(name) - return value + return try env.get(name) 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 .list: - return try eval_list(expr, env: env) + case let .list(ast, _): + return .list(try ast.map { try eval($0, env: env) }) default: return expr } } -func eval_list(_ expr: Expr, env: Env) throws -> Expr { - guard case let .list(values, _) = expr else { fatalError() } +func eval(_ expr: Expr, env: Env) throws -> Expr { + guard case let .list(values, _) = expr else { + return try evalAst(expr, env: env) + } if values.isEmpty { return expr } - let evaluated = try values.map { try eval($0, env: env) } - guard case let .function(fn) = evaluated.first else { throw MalError("not a function: \(evaluated.first!)") } - return try fn.run(Array(evaluated.dropFirst())) + 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/swift5/Sources/step3_env/main.swift b/swift5/Sources/step3_env/main.swift index 4a1f5f95..14d79aa5 100644 --- a/swift5/Sources/step3_env/main.swift +++ b/swift5/Sources/step3_env/main.swift @@ -7,7 +7,7 @@ extension Func { return Func { args in guard args.count == 2, case let .number(a) = args[0], - case let .number(b) = args[1] else { throw MalError("invalid arguments") } + case let .number(b) = args[1] else { throw MalError.invalidArguments() } return .number(op(a, b)) } @@ -24,87 +24,66 @@ func read(_ s: String) throws -> Expr { return try Reader.read(s) } -func eval(_ expr: Expr, env: Env) throws -> Expr { +private func evalAst(_ expr: Expr, env: Env) throws -> Expr { switch expr { case let .symbol(name): - let value = try env.get(name) - return value + return try env.get(name) 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 .list: - return try eval_list(expr, env: env) + case let .list(ast, _): + return .list(try ast.map { try eval($0, env: env) }) default: return expr } } -private func isTaggedList(_ values: [Expr], tagName: String) -> Bool { - if case let .symbol(name) = values.first, name == tagName { - return true +func eval(_ expr: Expr, env: Env) throws -> Expr { + + guard case let .list(ast, _) = expr else { + return try evalAst(expr, env: env) + } + if ast.isEmpty { + return expr } - return false -} -private func isDefinition(_ values: [Expr]) -> Bool { - return isTaggedList(values, tagName: "def!") -} + switch ast[0] { -private func evalDefinition(_ values: [Expr], env: Env) throws -> Expr { - guard values.count == 3 else { throw MalError("def!: invalid arguments") } - guard case let .symbol(name) = values[1] else { throw MalError("def!: invalid arguments") } + 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 expToEval = values[2] - let val = try eval(expToEval, 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 -private func isLetForm(_ values: [Expr]) -> Bool { - return isTaggedList(values, tagName: "let*") -} + case .symbol("let*"): + guard ast.count == 3 else { throw MalError.invalidArguments("let*") } -private func evalLetForm(_ values: [Expr], env: Env) throws -> Expr { - guard values.count == 3 else { throw MalError("let*: invalid arguments") } + switch ast[1] { + case let .list(bindable, _), let .vector(bindable, _): + let letEnv = Env(outer: env) - switch values[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("let*: invalid arguments") } - 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 = values[2] - return try eval(expToEval, env: letEnv) default: - throw MalError("let*: invalid arguments") + 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())) } } -func eval_list(_ expr: Expr, env: Env) throws -> Expr { - guard case let .list(values, _) = expr else { fatalError() } - - if values.isEmpty { - return expr - } - - if isDefinition(values) { - return try evalDefinition(values, env: env) - } - - if isLetForm(values) { - return try evalLetForm(values, env: env) - } - - let evaluated = try values.map { try eval($0, env: env) } - guard case let .function(fn) = evaluated.first else { throw MalError("not a function: \(evaluated.first!)") } - return try fn.run(Array(evaluated.dropFirst())) -} - func print(_ expr: Expr) -> String { return Expr.print(expr) } diff --git a/swift5/Sources/step4_if_fn_do/main.swift b/swift5/Sources/step4_if_fn_do/main.swift index 583945c6..2c110443 100644 --- a/swift5/Sources/step4_if_fn_do/main.swift +++ b/swift5/Sources/step4_if_fn_do/main.swift @@ -78,7 +78,7 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { } case .symbol("fn*"): - guard ast.count == 3 else { throw MalError("fn*") } + guard ast.count == 3 else { throw MalError.invalidArguments("fn*") } let binds: [String] switch ast[1] { case let .list(xs, _), let .vector(xs, _): @@ -97,9 +97,9 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(evaluatedList, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = evaluatedList[0] else { throw MalError("not a function: \(evaluatedList[0])") } - return try fn.run(Array(evaluatedList.dropFirst())) + 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())) } } diff --git a/swift5/Sources/step5_tco/main.swift b/swift5/Sources/step5_tco/main.swift index 99ece704..449dd691 100644 --- a/swift5/Sources/step5_tco/main.swift +++ b/swift5/Sources/step5_tco/main.swift @@ -84,7 +84,7 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { } case .symbol("fn*"): - guard ast.count == 3 else { throw MalError("fn*") } + guard ast.count == 3 else { throw MalError.invalidArguments("fn*") } let binds: [String] switch ast[1] { @@ -106,10 +106,10 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(evaluatedList, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = evaluatedList[0] else { throw MalError("not a function: \(evaluatedList[0])") } + 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(evaluatedList.dropFirst()) + let args = Array(ast.dropFirst()) if let ast = fn.ast, let fnEnv = fn.env { let newEnv = try Env(binds: fn.params, exprs: args, outer: fnEnv) env = newEnv diff --git a/swift5/Sources/step6_file/main.swift b/swift5/Sources/step6_file/main.swift index 698d73d3..935fcb9d 100644 --- a/swift5/Sources/step6_file/main.swift +++ b/swift5/Sources/step6_file/main.swift @@ -84,7 +84,7 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { } case .symbol("fn*"): - guard ast.count == 3 else { throw MalError("fn*") } + guard ast.count == 3 else { throw MalError.invalidArguments("fn*") } let binds: [String] switch ast[1] { @@ -106,10 +106,10 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(evaluatedList, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = evaluatedList[0] else { throw MalError("not a function: \(evaluatedList[0])") } + 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(evaluatedList.dropFirst()) + let args = Array(ast.dropFirst()) if let ast = fn.ast, let fnEnv = fn.env { let newEnv = try Env(binds: fn.params, exprs: args, outer: fnEnv) env = newEnv diff --git a/swift5/Sources/step7_quote/main.swift b/swift5/Sources/step7_quote/main.swift index b08bcc6f..58da022a 100644 --- a/swift5/Sources/step7_quote/main.swift +++ b/swift5/Sources/step7_quote/main.swift @@ -135,7 +135,7 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { } case .symbol("fn*"): - guard ast.count == 3 else { throw MalError("fn*") } + guard ast.count == 3 else { throw MalError.invalidArguments("fn*") } let binds: [String] switch ast[1] { @@ -157,10 +157,10 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(evaluatedList, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = evaluatedList[0] else { throw MalError("not a function: \(evaluatedList[0])") } + 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(evaluatedList.dropFirst()) + let args = Array(ast.dropFirst()) if let ast = fn.ast, let fnEnv = fn.env { let newEnv = try Env(binds: fn.params, exprs: args, outer: fnEnv) env = newEnv diff --git a/swift5/Sources/step8_macros/main.swift b/swift5/Sources/step8_macros/main.swift index 3d4ea476..a05f3241 100644 --- a/swift5/Sources/step8_macros/main.swift +++ b/swift5/Sources/step8_macros/main.swift @@ -175,7 +175,7 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { } case .symbol("fn*"): - guard ast.count == 3 else { throw MalError("fn*") } + guard ast.count == 3 else { throw MalError.invalidArguments("fn*") } let binds: [String] switch ast[1] { @@ -197,10 +197,10 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(evaluatedList, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = evaluatedList[0] else { throw MalError("not a function: \(evaluatedList[0])") } + 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(evaluatedList.dropFirst()) + let args = Array(ast.dropFirst()) if let ast = fn.ast, let fnEnv = fn.env { let newEnv = try Env(binds: fn.params, exprs: args, outer: fnEnv) env = newEnv diff --git a/swift5/Sources/step9_try/main.swift b/swift5/Sources/step9_try/main.swift index 4d0f2641..f80e05ec 100644 --- a/swift5/Sources/step9_try/main.swift +++ b/swift5/Sources/step9_try/main.swift @@ -185,7 +185,7 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { } case .symbol("fn*"): - guard ast.count == 3 else { throw MalError("fn*") } + guard ast.count == 3 else { throw MalError.invalidArguments("fn*") } let binds: [String] switch ast[1] { @@ -207,10 +207,10 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(evaluatedList, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = evaluatedList[0] else { throw MalError("not a function: \(evaluatedList[0])") } + 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(evaluatedList.dropFirst()) + let args = Array(ast.dropFirst()) if let ast = fn.ast, let fnEnv = fn.env { let newEnv = try Env(binds: fn.params, exprs: args, outer: fnEnv) env = newEnv diff --git a/swift5/Sources/stepA_mal/main.swift b/swift5/Sources/stepA_mal/main.swift index 132b1dcc..f6cf6940 100644 --- a/swift5/Sources/stepA_mal/main.swift +++ b/swift5/Sources/stepA_mal/main.swift @@ -185,7 +185,7 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { } case .symbol("fn*"): - guard ast.count == 3 else { throw MalError("fn*") } + guard ast.count == 3 else { throw MalError.invalidArguments("fn*") } let binds: [String] switch ast[1] { @@ -207,10 +207,10 @@ func eval(_ expr: Expr, env: Env) throws -> Expr { return .function(f) default: - guard case let .list(evaluatedList, _) = try evalAst(expr, env: env) else { fatalError() } - guard case let .function(fn) = evaluatedList[0] else { throw MalError("not a function: \(evaluatedList[0])") } + 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(evaluatedList.dropFirst()) + let args = Array(ast.dropFirst()) if let ast = fn.ast, let fnEnv = fn.env { let newEnv = try Env(binds: fn.params, exprs: args, outer: fnEnv) env = newEnv