mirror of
https://github.com/kanaka/mal.git
synced 2024-09-11 13:55:55 +03:00
swift5: refactor a bit
This commit is contained in:
parent
6aa9c258a5
commit
b667adf5e3
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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),
|
||||
|
@ -16,11 +16,11 @@ public class Env {
|
||||
for i in 0..<binds.count {
|
||||
let bindName = binds[i]
|
||||
if bindName == "&" {
|
||||
guard let key = binds[safe: i + 1] else { throw MalError("invalid variadic function definition") }
|
||||
guard let key = binds[safe: i + 1] else { throw MalError.invalidVariadicFunction() }
|
||||
data[key] = .list(Array(exprs[i...]))
|
||||
break
|
||||
}
|
||||
guard let exp = exprs[safe: i] else { throw MalError("function call: invalid arguments") }
|
||||
guard let exp = exprs[safe: i] else { throw MalError.invalidArguments() }
|
||||
data[bindName] = exp
|
||||
}
|
||||
}
|
||||
@ -30,7 +30,7 @@ public class Env {
|
||||
}
|
||||
|
||||
public func get(_ key: String) throws -> Expr {
|
||||
guard let val = find(key) else { throw MalError("'\(key)' not found") }
|
||||
guard let val = find(key) else { throw MalError.symbolNotFound(key) }
|
||||
return val
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -51,6 +51,9 @@ extension Parsers {
|
||||
static func string(excluding string: String) -> Parser<String> {
|
||||
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<Void> {
|
||||
map { _ in nil }
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Parser (Optional)
|
||||
@ -144,15 +142,6 @@ func optional<A>(_ parser: Parser<A>) -> Parser<A?> {
|
||||
}
|
||||
}
|
||||
|
||||
func optional(_ parser: Parser<Void>) -> Parser<Bool> {
|
||||
Parser<Bool> { 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 {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
extension Expr {
|
||||
|
||||
public static func print(readable: Bool = true, _ expr: Expr) -> String {
|
||||
|
||||
let print = curry(Self.print)(readable)
|
||||
|
@ -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<Expr> = 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<Expr> = 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<Expr> {
|
||||
return map { Expr.list([.symbol(s), $0]) }
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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,85 +24,64 @@ 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)
|
||||
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 values[1] {
|
||||
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("let*: invalid arguments") }
|
||||
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 = values[2]
|
||||
let expToEval = ast[2]
|
||||
return try eval(expToEval, env: letEnv)
|
||||
default:
|
||||
throw MalError("let*: invalid arguments")
|
||||
}
|
||||
}
|
||||
|
||||
func eval_list(_ expr: Expr, env: Env) throws -> Expr {
|
||||
guard case let .list(values, _) = expr else { fatalError() }
|
||||
|
||||
if values.isEmpty {
|
||||
return expr
|
||||
throw MalError.invalidArguments("let*")
|
||||
}
|
||||
|
||||
if isDefinition(values) {
|
||||
return try evalDefinition(values, env: env)
|
||||
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()))
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -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()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user