Swift SIL: some improvements for WalkUtils and EscapeInfo

* "merge" the `Path` and `State` in WalkUtils into a single `WalkingPath`. This makes it simpler for clients to configure a path and additional state variables. EscapeInfo now defines `EscapePath` which includes the projection path and EscapeInfo's specific state variables.
* Make the `WalkerCache` part of the WalkUtils, so that not all clients have to re-implement it.
* Rename `walkDownResults` -> `walkDownAllResults` and `walkUpOperands` -> `walkUpAllOperands` and make these functions client configurable.
This commit is contained in:
Erik Eckstein
2022-07-19 19:41:51 +02:00
parent 7a43d246b0
commit b52297bb79
6 changed files with 492 additions and 426 deletions

View File

@@ -205,14 +205,20 @@ public struct SmallProjectionPath : CustomStringConvertible, CustomReflectable,
return (idx, newPath)
}
/// Pops the first path component if it matches `kind` and (optionally) `index` -
/// also considering wildcards.
/// Pops the first path component if it matches `kind` and (optionally) `index`.
///
/// For example:
/// popping `s0` from `s0.c3.e1` returns `c3.e1`
/// popping `c2` from `c*.e1` returns `e1`
/// popping `s0` from `v**.c3.e1` return `v**.c3.e1` (because `v**` means _any_ number of value fields)
/// popping `s0` from `c*.e1` returns nil
///
/// Note that if `kind` is a wildcard, also the first path component must be a wildcard to popped.
/// For example:
/// popping `v**` from `s0.c1` returns nil
/// popping `v**` from `v**.c1` returns `v**.c1` (because `v**` means _any_ number of value fields)
/// popping `c*` from `c0.e3` returns nil
/// popping `c*` from `c*.e3` returns `e3`
public func popIfMatches(_ kind: FieldKind, index: Int? = nil) -> SmallProjectionPath? {
let (k, idx, numBits) = top
switch k {
@@ -232,28 +238,10 @@ public struct SmallProjectionPath : CustomStringConvertible, CustomReflectable,
}
return pop(numBits: numBits)
default:
if kind == .anyValueFields && k.isValueField {
return pop(numBits: numBits)
}
if kind == .anyClassField && k.isClassField {
return pop(numBits: numBits)
}
return nil
}
}
/// Returns true if all value fields match the first component of a pattern path.
/// For example:
/// returns true for `v**.c3`
/// returns true for `**`
/// returns false for `s0.c3` (because e.g. `s1` would not match)
public var topMatchesAnyValueField: Bool {
switch top.kind {
case .anyValueFields, .anything: return true
default: return false
}
}
/// Returns true if the path does not have any class projections.
/// For example:
/// returns true for `v**`
@@ -630,10 +618,6 @@ extension SmallProjectionPath {
}
func predicates() {
testPredicate("v**.c3", \.topMatchesAnyValueField, expect: true)
testPredicate("**", \.topMatchesAnyValueField, expect: true)
testPredicate("s0.c3", \.topMatchesAnyValueField, expect: false)
testPredicate("v**", \.hasNoClassProjection, expect: true)
testPredicate("c0", \.hasNoClassProjection, expect: false)
testPredicate("1", \.hasNoClassProjection, expect: true)
@@ -665,15 +649,27 @@ extension SmallProjectionPath {
testPath2Path("s1.ct.v**", { $0.popLastClassAndValuesFromTail() }, expect: "s1")
testPath2Path("c0.c1.c2", { $0.popLastClassAndValuesFromTail() }, expect: "c0.c1")
testPath2Path("**", { $0.popLastClassAndValuesFromTail() }, expect: "**")
testPath2Path("v**.c3", { $0.popIfMatches(.anyValueFields) }, expect: "v**.c3")
testPath2Path("**", { $0.popIfMatches(.anyValueFields) }, expect: "**")
testPath2Path("s0.c3", { $0.popIfMatches(.anyValueFields) }, expect: nil)
testPath2Path("c0.s3", { $0.popIfMatches(.anyClassField) }, expect: nil)
testPath2Path("**", { $0.popIfMatches(.anyClassField) }, expect: "**")
testPath2Path("c*.e3", { $0.popIfMatches(.anyClassField) }, expect: "e3")
}
func testPath2Path(_ pathStr: String, _ transform: (SmallProjectionPath) -> SmallProjectionPath, expect: String) {
func testPath2Path(_ pathStr: String, _ transform: (SmallProjectionPath) -> SmallProjectionPath?, expect: String?) {
var parser = StringParser(pathStr)
let path = try! parser.parseProjectionPathFromSIL()
var expectParser = StringParser(expect)
let expectPath = try! expectParser.parseProjectionPathFromSIL()
let result = transform(path)
precondition(result == expectPath)
if let expect = expect {
var expectParser = StringParser(expect)
let expectPath = try! expectParser.parseProjectionPathFromSIL()
precondition(result == expectPath)
} else {
precondition(result == nil)
}
}
}
}