forked from googleprojectzero/fuzzilli
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathExpression.swift
115 lines (99 loc) · 3.77 KB
/
Expression.swift
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
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// The type of an expression. Also serves as a constructor.
public class ExpressionType {
let precedence: UInt8
let associativity: Associativity
let characteristic: Characteristic
init(precedence: UInt8, associativity: Associativity = .none, characteristic: Characteristic) {
self.precedence = precedence
self.associativity = associativity
self.characteristic = characteristic
}
func new(_ initialText: String = "") -> Expression {
return Expression(type: self, text: initialText, numSubexpressions: 0)
}
public enum Associativity: UInt8 {
case none
case left
case right
}
// Whether an expression can have side effects or not. An effectful expression can only be inlined
// as long as it still executes before any other effectful operation that comes after it.
public enum Characteristic: UInt8 {
// The expression is pure and so can be inlined multiple times, across different blocks in the CFG
case pure
// The expression may have side effects so can only be inlined if:
// - There is a single use of the value
// - The use happens inside the same block in the CFG
// - No other effectful expressions happens between this expression and its use
case effectful
}
}
/// An expression in the target language.
public struct Expression: CustomStringConvertible {
public let type: ExpressionType
public let text: String
let numSubexpressions: UInt
public var characteristic: ExpressionType.Characteristic {
return type.characteristic
}
public var isEffectful: Bool {
return characteristic == .effectful
}
public var description: String {
return text
}
func needsBrackets(in other: Expression, isLhs: Bool = true) -> Bool {
if type.precedence == other.type.precedence {
if type.associativity != other.type.associativity {
return true
}
switch type.associativity {
case .none:
return true
case .left:
return !isLhs
case .right:
return isLhs
}
}
return type.precedence < other.type.precedence
}
func extended(by part: String) -> Expression {
return Expression(type: type,
text: text + part,
numSubexpressions: numSubexpressions)
}
func extended(by part: Expression) -> Expression {
let newText: String
if part.needsBrackets(in: self, isLhs: numSubexpressions == 0) {
newText = text + "(" + part.text + ")"
} else {
newText = text + part.text
}
return Expression(type: type,
text: newText,
numSubexpressions: numSubexpressions + 1)
}
static func +(lhs: Expression, rhs: Expression) -> Expression {
return lhs.extended(by: rhs)
}
static func +(lhs: Expression, rhs: String) -> Expression {
return lhs.extended(by: rhs)
}
static func +(lhs: Expression, rhs: Int64) -> Expression {
return lhs.extended(by: String(rhs))
}
}