1
1
mirror of https://github.com/kanaka/mal.git synced 2024-11-13 11:23:59 +03:00
mal/swift3/Sources/step4_if_fn_do/main.swift
2016-07-31 23:25:23 -05:00

132 lines
4.0 KiB
Swift

import Foundation
// read
func READ(_ str: String) throws -> MalVal {
return try read_str(str)
}
// eval
func eval_ast(_ ast: MalVal, _ env: Env) throws -> MalVal {
switch ast {
case MalVal.MalSymbol:
return try env.get(ast)
case MalVal.MalList(let lst, _):
return list(try lst.map { try EVAL($0, env) })
case MalVal.MalVector(let lst, _):
return vector(try lst.map { try EVAL($0, env) })
case MalVal.MalHashMap(let dict, _):
var new_dict = Dictionary<String,MalVal>()
for (k,v) in dict { new_dict[k] = try EVAL(v, env) }
return hash_map(new_dict)
default:
return ast
}
}
func EVAL(_ ast: MalVal, _ env: Env) throws -> MalVal {
switch ast {
case MalVal.MalList(let lst, _): if lst.count == 0 { return ast }
default: return try eval_ast(ast, env)
}
switch ast {
case MalVal.MalList(let lst, _):
switch lst[0] {
case MalVal.MalSymbol("def!"):
return try env.set(lst[1], try EVAL(lst[2], env))
case MalVal.MalSymbol("let*"):
let let_env = try Env(env)
var binds = Array<MalVal>()
switch lst[1] {
case MalVal.MalList(let l, _): binds = l
case MalVal.MalVector(let l, _): binds = l
default:
throw MalError.General(msg: "Invalid let* bindings")
}
var idx = binds.startIndex
while idx < binds.endIndex {
let v = try EVAL(binds[binds.index(after: idx)], let_env)
try let_env.set(binds[idx], v)
idx = binds.index(idx, offsetBy: 2)
}
return try EVAL(lst[2], let_env)
case MalVal.MalSymbol("do"):
let slc = lst[lst.index(after: lst.startIndex)..<lst.endIndex]
switch try eval_ast(list(Array(slc)), env) {
case MalVal.MalList(let elst, _):
return elst[elst.index(before: elst.endIndex)]
default:
throw MalError.General(msg: "Invalid do form")
}
case MalVal.MalSymbol("if"):
switch try EVAL(lst[1], env) {
case MalVal.MalFalse, MalVal.MalNil:
if lst.count > 3 {
return try EVAL(lst[3], env)
} else {
return MalVal.MalNil
}
default:
return try EVAL(lst[2], env)
}
case MalVal.MalSymbol("fn*"):
return malfunc( {
return try EVAL(lst[2], Env(env, binds: lst[1],
exprs: list($0)))
})
default:
switch try eval_ast(ast, env) {
case MalVal.MalList(let elst, _):
switch elst[0] {
case MalVal.MalFunc(let fn,_,_,_,_,_):
let args = Array(elst[1..<elst.count])
return try fn(args)
default:
throw MalError.General(msg: "Cannot apply on '\(elst[0])'")
}
default: throw MalError.General(msg: "Invalid apply")
}
}
default:
throw MalError.General(msg: "Invalid apply")
}
}
// print
func PRINT(_ exp: MalVal) -> String {
return pr_str(exp, true)
}
// repl
@discardableResult
func rep(_ str:String) throws -> String {
return PRINT(try EVAL(try READ(str), repl_env))
}
var repl_env: Env = try Env()
// core.swift: defined using Swift
for (k, fn) in core_ns {
try repl_env.set(MalVal.MalSymbol(k), malfunc(fn))
}
// core.mal: defined using the language itself
try rep("(def! not (fn* (a) (if a false true)))")
while true {
print("user> ", terminator: "")
let line = readLine(strippingNewline: true)
if line == nil { break }
if line == "" { continue }
do {
print(try rep(line!))
} catch (MalError.Reader(let msg)) {
print("Error: \(msg)")
} catch (MalError.General(let msg)) {
print("Error: \(msg)")
}
}