Skip to content

Commit

Permalink
swift5: merge eval_ast into eval
Browse files Browse the repository at this point in the history
  • Loading branch information
asarhaddon committed Oct 14, 2024
1 parent 7eed3ef commit ebdaca0
Show file tree
Hide file tree
Showing 10 changed files with 235 additions and 315 deletions.
9 changes: 2 additions & 7 deletions impls/swift5/Sources/core/Env.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
31 changes: 15 additions & 16 deletions impls/swift5/Sources/step2_eval/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
75 changes: 38 additions & 37 deletions impls/swift5/Sources/step3_env/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down
143 changes: 72 additions & 71 deletions impls/swift5/Sources/step4_if_fn_do/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down
Loading

0 comments on commit ebdaca0

Please sign in to comment.