Last active
June 23, 2021 02:21
-
-
Save conf8o/fddee24aeb2fb830f3ef7b0233e010ac to your computer and use it in GitHub Desktop.
SwiftでつくるAST
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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