Skip to content

Instantly share code, notes, and snippets.

@conf8o
Last active June 23, 2021 02:21
Show Gist options
  • Save conf8o/fddee24aeb2fb830f3ef7b0233e010ac to your computer and use it in GitHub Desktop.
Save conf8o/fddee24aeb2fb830f3ef7b0233e010ac to your computer and use it in GitHub Desktop.
SwiftでつくるAST
enum Val {
case int(Int)
case bool(Bool)
case symbol(String)
}
enum Ope {
case add
case mul
case lt
case assign
/// 式としての演算子
func form(_ left: Val, _ right: Val) throws -> Val {
switch (self, left, right) {
case let (.add, .int(left), .int(right)):
return .int(left + right)
case let (.mul, .int(left), .int(right)):
return .int(left * right)
case let (.lt, .int(left), .int(right)):
return .bool(left < right)
default:
throw OpeError.notImplemented("\(self) is not implemented between \(left) and \(right)")
}
}
/// 文としての演算子
func statement(_ left: Val, _ right: Val, env: inout [String: Val]) throws {
switch (self, left, right) {
case let (.assign, .symbol(symbol), _):
env[symbol] = right
default:
throw OpeError.malformedStatement("\(self): \(left): \(right)")
}
}
}
enum OpeError: Error {
case notImplemented(String)
case malformedStatement(String)
}
enum AST {
case val(Val)
indirect case form(Ope, AST, AST)
indirect case statement(Ope, AST, AST)
}
extension AST {
func unwrapVal() throws -> Val {
guard case let .val(v) = self else {
throw ASTError.cannotUnwrap("Cannot unwrap: \(self)")
}
return v
}
}
extension AST {
func reduce(env: inout [String: Val]) throws -> AST {
switch self {
case let .form(ope, left, right):
let v1 = try left.reduce(env: &env).unwrapVal()
let v2 = try right.reduce(env: &env).unwrapVal()
return .val(try ope.form(v1, v2))
case let .statement(ope, .val(left), right):
guard case .symbol = left else {
throw ASTError.cannotReduce("Cannot reduce: \(self)")
}
let v = try right.reduce(env: &env).unwrapVal()
try ope.statement(left, v, env: &env)
return .val(v)
case let .val(.symbol(symbol)):
guard let v = env[symbol] else {
throw ASTError.notAssigned("Not Assigned: \(symbol)")
}
return .val(v)
case .val:
return self
default:
throw ASTError.cannotReduce("Cannot reduce: \(self)")
}
}
}
enum ASTError: Error {
case cannotUnwrap(String)
case notAssigned(String)
case cannotReduce(String)
}
// (1 + (20 + 3) * 5) == 116
let form: AST =
.form(.add,
.val(.int(1)),
.form(.mul,
.form(.add,
.val(.int(20)),
.val(.int(3))),
.val(.int(5))))
// x = 116
let statement: AST =
.statement(.assign,
.val(.symbol("x")),
form)
var env = [String: Val]()
try statement.reduce(env: &env)
print(env)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment