-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConstProp.swift
More file actions
156 lines (134 loc) · 3.97 KB
/
ConstProp.swift
File metadata and controls
156 lines (134 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//
// ConstProp.swift - AST-level Constant Propagation
//
// SwiSwi - a tiny Swift-like language
//
// Created for the Budapest Swift Meetup
// by Árpád Goretity (H2CO3)
// on 23/02/2016
//
// There's no warranty whatsoever.
//
// If the AST represents a Boolean literal, return its value.
// Otherwise, return nil.
func boolLiteralValue(ast: AST) -> Bool? {
guard let ident = ast as? IdentifierAST else {
return nil
}
return ["false": false, "true": true][ident.name]
}
// Make an AST node representing a Boolean literal
func boolLiteralAST(loc: SrcLoc, _ b: Bool) -> IdentifierAST {
let names = [false: "false", true: "true"]
return IdentifierAST(loc, names[b]!)
}
func propagatePrefixOp(ast: PrefixOpAST) -> AST {
let child = performConstProp(ast.child)
if ast.op == "!" {
if let b = boolLiteralValue(child) {
return boolLiteralAST(ast.loc, !b)
}
}
// don't know what to do - try propagating subexpression anyway
ast.child = child
return ast
}
// TODO: use identities to simplify partially-const expressions:
// true && rhs == rhs, false && rhs == false
// true || rhs == true, false || rhs == rhs
// and the same with the LHS
func propagateBinaryOp(ast: BinaryOpAST) -> AST {
let lhs = performConstProp(ast.lhs)
let rhs = performConstProp(ast.rhs)
guard let bl = boolLiteralValue(lhs), br = boolLiteralValue(rhs) else {
// 'ast' is not a literal per se, but let's not lose track of
// its already-propagated subexpressions!
ast.lhs = lhs
ast.rhs = rhs
return ast
}
switch ast.op {
case "&&":
return boolLiteralAST(ast.loc, bl && br)
case "||":
return boolLiteralAST(ast.loc, bl || br)
default:
// don't know what to do, just fall back to propagation of subexpressions
ast.lhs = lhs
ast.rhs = rhs
return ast
}
}
func propagateProgram(ast: ProgramAST) -> ProgramAST {
ast.children = ast.children.map(performConstProp)
return ast
}
func propagateBlock(ast: BlockAST) -> BlockAST {
ast.children = ast.children.map(performConstProp)
return ast
}
func propagateFuncDef(ast: FuncDefAST) -> FuncDefAST {
ast.body = propagateBlock(ast.body)
return ast
}
func propagateWhileLoop(ast: WhileLoopAST) -> WhileLoopAST {
ast.condition = performConstProp(ast.condition)
ast.body = propagateBlock(ast.body)
return ast
}
func propagateIfThenElse(ast: IfThenElseAST) -> IfThenElseAST {
ast.condition = performConstProp(ast.condition)
ast.thenBranch = propagateBlock(ast.thenBranch)
if let elseBranch = ast.elseBranch {
ast.elseBranch = performConstProp(elseBranch)
}
return ast
}
func propagateVarDecl(ast: VarDeclAST) -> VarDeclAST {
ast.initExpr = performConstProp(ast.initExpr)
return ast
}
func propagateReturn(ast: ReturnAST) -> ReturnAST {
if let expr = ast.expression {
ast.expression = performConstProp(expr)
}
return ast
}
func propagateFuncCall(ast: FuncCallAST) -> FuncCallAST {
ast.function = performConstProp(ast.function)
if let param = ast.parameter {
ast.parameter = performConstProp(param)
}
return ast
}
func performConstProp(ast: AST) -> AST {
// For now, we'll focus on Booleans.
// The same techniques apply to many other primitives as well.
switch ast {
case let binOp as BinaryOpAST:
return propagateBinaryOp(binOp)
case let prefixOp as PrefixOpAST:
return propagatePrefixOp(prefixOp)
// In the case of statements, try digging into their children of expression type.
case let program as ProgramAST:
return propagateProgram(program)
case let block as BlockAST:
return propagateBlock(block)
case let funcDef as FuncDefAST:
return propagateFuncDef(funcDef)
case let whileLoop as WhileLoopAST:
return propagateWhileLoop(whileLoop)
case let ifThenElse as IfThenElseAST:
return propagateIfThenElse(ifThenElse)
case let varDecl as VarDeclAST:
return propagateVarDecl(varDecl)
case let returnAST as ReturnAST:
return propagateReturn(returnAST)
// case let subscriptAST as SubscriptAST:
// return propagateSubscript(subscriptAST)
case let funcCall as FuncCallAST:
return propagateFuncCall(funcCall)
default:
return ast
}
}