mirror of
https://github.com/github/semantic.git
synced 2024-11-29 02:44:36 +03:00
commit
df31170dc8
@ -7,8 +7,11 @@ public enum Algorithm<A, B> {
|
||||
/// The type of `Term`s over which `Algorithm`s operate.
|
||||
public typealias Term = Fix<A>
|
||||
|
||||
/// The type of `Patch`es produced by `Algorithm`s.
|
||||
public typealias Patch = Doubt.Patch<Term>
|
||||
|
||||
/// The type of `Diff`s which `Algorithm`s produce.
|
||||
public typealias Diff = Free<A, Patch<A>>
|
||||
public typealias Diff = Free<A, Patch>
|
||||
|
||||
/// The injection of a value of type `B` into an `Operation`.
|
||||
///
|
||||
@ -82,7 +85,7 @@ public enum Algorithm<A, B> {
|
||||
return f(Dictionary(elements: deleted + inserted + patched)).evaluate(equals, recur: recur)
|
||||
|
||||
case let .Roll(.ByIndex(a, b, f)):
|
||||
return f(SES(a, b, equals: equals, recur: recur)).evaluate(equals, recur: recur)
|
||||
return f(SES(a, b, recur: recur)).evaluate(equals, recur: recur)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -107,7 +110,7 @@ extension Free: FreeConvertible {
|
||||
public var free: Free { return self }
|
||||
}
|
||||
|
||||
extension Algorithm where B: FreeConvertible, B.RollType == A, B.PureType == Patch<A> {
|
||||
extension Algorithm where B: FreeConvertible, B.RollType == A, B.PureType == Algorithm<A, B>.Patch {
|
||||
/// `Algorithm<A, Diff>`s can be constructed from a pair of `Term`s using `ByKey` when `Keyed`, `ByIndex` when `Indexed`, and `Recursive` otherwise.
|
||||
public init(_ a: Term, _ b: Term) {
|
||||
switch (a.out, b.out) {
|
||||
@ -125,7 +128,7 @@ extension Algorithm where B: FreeConvertible, B.RollType == A, B.PureType == Pat
|
||||
}
|
||||
}
|
||||
|
||||
extension Algorithm where A: Equatable, B: FreeConvertible, B.RollType == A, B.PureType == Patch<A> {
|
||||
extension Algorithm where A: Equatable, B: FreeConvertible, B.RollType == A, B.PureType == Algorithm<A, B>.Patch {
|
||||
public func evaluate() -> B {
|
||||
return evaluate(==)
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ public enum Free<A, B>: CustomDebugStringConvertible, CustomDocConvertible, Synt
|
||||
}
|
||||
|
||||
|
||||
extension Free where B: PatchConvertible, B.Info == A {
|
||||
extension Free where B: PatchConvertible, B.Element == Fix<A> {
|
||||
public typealias Term = Fix<A>
|
||||
|
||||
private func discardNullTerms(syntax: Syntax<Term?, A>) -> Term? {
|
||||
@ -190,9 +190,9 @@ extension Free where A: CustomJSONConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
extension Free where A: CustomJSONConvertible, B: PatchConvertible, B.Info == A {
|
||||
extension Free where A: CustomJSONConvertible, B: PatchConvertible, B.Element == Fix<A> {
|
||||
public var JSON: Doubt.JSON {
|
||||
return JSON { $0.patch.JSON }
|
||||
return JSON { $0.patch.JSON { $0.JSON } }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
/// A patch to some part of a `Syntax` tree.
|
||||
public enum Patch<A>: CustomDebugStringConvertible, CustomDocConvertible {
|
||||
case Replace(Fix<A>, Fix<A>)
|
||||
case Insert(Fix<A>)
|
||||
case Delete(Fix<A>)
|
||||
case Replace(A, A)
|
||||
case Insert(A)
|
||||
case Delete(A)
|
||||
|
||||
public var state: (before: Fix<A>?, after: Fix<A>?) {
|
||||
public var state: (before: A?, after: A?) {
|
||||
switch self {
|
||||
case let .Replace(a, b):
|
||||
return (a, b)
|
||||
@ -45,8 +45,8 @@ public enum Patch<A>: CustomDebugStringConvertible, CustomDocConvertible {
|
||||
// MARK: CustomDocConvertible
|
||||
|
||||
public var doc: Doc {
|
||||
return (state.before?.doc.bracket("{-", "-}") ?? .Empty)
|
||||
<> (state.after?.doc.bracket("{+", "+}") ?? .Empty)
|
||||
return (state.before.map(Doc.init)?.bracket("{-", "-}") ?? .Empty)
|
||||
<> (state.after.map(Doc.init)?.bracket("{+", "+}") ?? .Empty)
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,8 +55,8 @@ public enum Patch<A>: CustomDebugStringConvertible, CustomDocConvertible {
|
||||
|
||||
extension Patch {
|
||||
public static func equals(param: (A, A) -> Bool)(_ left: Patch, _ right: Patch) -> Bool {
|
||||
return Optional.equals(Fix.equals(param))(left.state.before, right.state.before)
|
||||
&& Optional.equals(Fix.equals(param))(left.state.after, right.state.after)
|
||||
return Optional.equals(param)(left.state.before, right.state.before)
|
||||
&& Optional.equals(param)(left.state.after, right.state.after)
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,8 +66,8 @@ extension Patch {
|
||||
extension Patch {
|
||||
public func hash(param: A -> Hash) -> Hash {
|
||||
return Hash.Ordered([
|
||||
state.before.map { $0.hash(param) } ?? Hash.Empty,
|
||||
state.after.map { $0.hash(param) } ?? Hash.Empty
|
||||
state.before.map(param) ?? Hash.Empty,
|
||||
state.after.map(param) ?? Hash.Empty
|
||||
])
|
||||
}
|
||||
}
|
||||
@ -81,17 +81,17 @@ extension Patch {
|
||||
case let .Replace(a, b):
|
||||
return [
|
||||
"replace": [
|
||||
"before": a.JSON(ifLeaf),
|
||||
"after": b.JSON(ifLeaf),
|
||||
"before": ifLeaf(a),
|
||||
"after": ifLeaf(b),
|
||||
]
|
||||
]
|
||||
case let .Insert(b):
|
||||
return [
|
||||
"insert": b.JSON(ifLeaf),
|
||||
"insert": ifLeaf(b),
|
||||
]
|
||||
case let .Delete(a):
|
||||
return [
|
||||
"delete": a.JSON(ifLeaf)
|
||||
"delete": ifLeaf(a)
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -100,17 +100,17 @@ extension Patch {
|
||||
|
||||
extension Patch where A: CustomJSONConvertible {
|
||||
public var JSON: Doubt.JSON {
|
||||
return self.JSON { $0.JSON }
|
||||
return JSON { $0.JSON }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A hack to enable constrained extensions on `Free<A, Patch<A>>`.
|
||||
/// A hack to enable constrained extensions on `Free<A, Patch<Fix<A>>`.
|
||||
public protocol PatchConvertible {
|
||||
typealias Info
|
||||
typealias Element
|
||||
|
||||
init(patch: Patch<Info>)
|
||||
var patch: Patch<Info> { get }
|
||||
init(patch: Patch<Element>)
|
||||
var patch: Patch<Element> { get }
|
||||
}
|
||||
|
||||
extension Patch: PatchConvertible {
|
||||
|
@ -1,9 +1,8 @@
|
||||
/// Computes the SES (shortest edit script), i.e. the shortest sequence of diffs (`Free<A, Patch<A>>`) for two arrays of terms (`Fix<A>`) which would suffice to transform `a` into `b`.
|
||||
/// Computes the SES (shortest edit script), i.e. the shortest sequence of diffs (`Free<A, Patch<Term>>`) for two arrays of `Term`s which would suffice to transform `a` into `b`.
|
||||
///
|
||||
/// This is computed w.r.t. an `equals` function, which computes the equality of leaf nodes within terms, and a `recur` function, which produces diffs representing matched-up terms.
|
||||
public func SES<A>(a: [Fix<A>], _ b: [Fix<A>], equals: (A, A) -> Bool, recur: (Fix<A>, Fix<A>) -> Free<A, Patch<A>>?) -> [Free<A, Patch<A>>] {
|
||||
typealias Term = Fix<A>
|
||||
typealias Diff = Free<A, Patch<A>>
|
||||
public func SES<Term, A>(a: [Term], _ b: [Term], recur: (Term, Term) -> Free<A, Patch<Term>>?) -> [Free<A, Patch<Term>>] {
|
||||
typealias Diff = Free<A, Patch<Term>>
|
||||
|
||||
if a.isEmpty { return b.map { Diff.Pure(Patch.Insert($0)) } }
|
||||
if b.isEmpty { return a.map { Diff.Pure(Patch.Delete($0)) } }
|
||||
@ -46,12 +45,6 @@ public func SES<A>(a: [Fix<A>], _ b: [Fix<A>], equals: (A, A) -> Bool, recur: (F
|
||||
let down = matrix[i, j + 1]
|
||||
let diagonal = matrix[i + 1, j + 1]
|
||||
|
||||
let recur = {
|
||||
Term.equals(equals)($0, $1)
|
||||
? Diff($1)
|
||||
: recur($0, $1)
|
||||
}
|
||||
|
||||
if let right = right, down = down, diagonal = diagonal {
|
||||
let right = (right, Diff.Pure(Patch.Delete(a[i])), costOfStream(right))
|
||||
let down = (down, Diff.Pure(Patch.Insert(b[j])), costOfStream(down))
|
||||
|
@ -48,16 +48,16 @@ private func delete(term: Term) -> Diff {
|
||||
return Diff.Pure(.Delete(term))
|
||||
}
|
||||
|
||||
private typealias Term = Fix<Info>
|
||||
private typealias Diff = Free<Info, Patch<Info>>
|
||||
private typealias Term = Fix<String>
|
||||
private typealias Diff = Free<String, Patch<Term>>
|
||||
|
||||
private let a = Term.Leaf(.Literal("a", []))
|
||||
private let b = Term.Leaf(.Literal("b", []))
|
||||
private let c = Term.Leaf(.Literal("c", []))
|
||||
private let d = Term.Leaf(.Literal("d", []))
|
||||
private let a = Term.Leaf("a")
|
||||
private let b = Term.Leaf("b")
|
||||
private let c = Term.Leaf("c")
|
||||
private let d = Term.Leaf("d")
|
||||
|
||||
private func SES(a: [Term], _ b: [Term]) -> [Diff] {
|
||||
return SES(a, b, equals: ==, recur: const(nil))
|
||||
return SES(a, b) { $0 == $1 ? Diff($1) : nil }
|
||||
}
|
||||
|
||||
private func == (a: [Diff], b: [Diff]) -> Bool {
|
||||
|
Loading…
Reference in New Issue
Block a user