2015-09-16 22:47:03 +03:00
|
|
|
|
public enum Diff: Comparable, CustomDebugStringConvertible, CustomDocConvertible {
|
2015-09-15 21:07:35 +03:00
|
|
|
|
case Empty
|
2015-09-18 17:12:34 +03:00
|
|
|
|
case Patch(Term, Term)
|
2015-09-11 18:40:01 +03:00
|
|
|
|
indirect case Copy(Syntax<Diff>)
|
2015-07-18 22:43:49 +03:00
|
|
|
|
|
2015-09-18 17:12:34 +03:00
|
|
|
|
public static func Insert(term: Term) -> Diff {
|
2015-09-16 20:52:53 +03:00
|
|
|
|
return .Patch(.Empty, term)
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 17:12:34 +03:00
|
|
|
|
public static func Delete(term: Term) -> Diff {
|
2015-09-16 20:52:53 +03:00
|
|
|
|
return .Patch(term, .Empty)
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 17:12:34 +03:00
|
|
|
|
public init(_ term: Term) {
|
2015-09-17 22:55:01 +03:00
|
|
|
|
switch term {
|
|
|
|
|
case .Empty:
|
|
|
|
|
self = .Empty
|
|
|
|
|
case let .Roll(s):
|
|
|
|
|
self = .Copy(s.map(Diff.init))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-15 20:55:09 +03:00
|
|
|
|
public var doc: Doc {
|
2015-07-18 22:43:49 +03:00
|
|
|
|
switch self {
|
2015-09-15 21:07:35 +03:00
|
|
|
|
case .Empty:
|
|
|
|
|
return .Empty
|
2015-07-18 22:43:49 +03:00
|
|
|
|
case let .Patch(a, b):
|
|
|
|
|
return .Horizontal([
|
2015-09-15 21:33:09 +03:00
|
|
|
|
.Wrap(.Text("{-"), Doc(a), .Text("-}")),
|
|
|
|
|
.Wrap(.Text("{+"), Doc(b), .Text("+}"))
|
2015-07-18 22:43:49 +03:00
|
|
|
|
])
|
|
|
|
|
case let .Copy(a):
|
2015-09-11 18:40:01 +03:00
|
|
|
|
return a.doc
|
2015-07-18 22:43:49 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-15 21:08:59 +03:00
|
|
|
|
public var debugDescription: String {
|
2015-07-18 22:43:49 +03:00
|
|
|
|
switch self {
|
2015-09-15 21:07:35 +03:00
|
|
|
|
case .Empty:
|
|
|
|
|
return ".Empty"
|
2015-07-18 22:43:49 +03:00
|
|
|
|
case let .Patch(a, b):
|
2015-09-15 21:09:45 +03:00
|
|
|
|
return ".Patch(\(String(reflecting: a)), \(String(reflecting: b)))"
|
2015-07-18 22:43:49 +03:00
|
|
|
|
case let .Copy(a):
|
2015-09-15 21:09:45 +03:00
|
|
|
|
return ".Copy(\(String(reflecting: a)))"
|
2015-07-18 22:43:49 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-16 19:23:24 +03:00
|
|
|
|
public var magnitude: Int {
|
|
|
|
|
switch self {
|
|
|
|
|
case .Empty:
|
|
|
|
|
return 0
|
|
|
|
|
case .Patch:
|
|
|
|
|
return 1
|
|
|
|
|
case let .Copy(s):
|
|
|
|
|
return s.map { $0.magnitude }.reduce(0, combine: +)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 17:12:34 +03:00
|
|
|
|
public init(_ a: Term, _ b: Term) {
|
2015-09-15 21:07:35 +03:00
|
|
|
|
switch (a, b) {
|
|
|
|
|
case (.Empty, .Empty):
|
|
|
|
|
self = .Empty
|
2015-07-18 22:43:49 +03:00
|
|
|
|
|
2015-09-15 21:07:35 +03:00
|
|
|
|
case let (.Roll(a), .Roll(b)):
|
|
|
|
|
switch (a, b) {
|
|
|
|
|
case let (.Apply(a, aa), .Apply(b, bb)):
|
2015-09-16 22:00:06 +03:00
|
|
|
|
self = .Copy(.Apply(Diff(a, b), Diff.diff(aa, bb)))
|
2015-07-18 22:43:49 +03:00
|
|
|
|
|
2015-09-15 21:07:35 +03:00
|
|
|
|
case let (.Abstract(p1, b1), .Abstract(p2, b2)):
|
2015-09-23 00:23:48 +03:00
|
|
|
|
self = .Copy(.Abstract(Diff.diff(p1, p2), Diff.diff(b1, b2)))
|
2015-07-18 22:43:49 +03:00
|
|
|
|
|
2015-09-15 21:07:35 +03:00
|
|
|
|
case let (.Assign(n1, v1), .Assign(n2, v2)) where n1 == n2:
|
|
|
|
|
self = .Copy(.Assign(n2, Diff(v1, v2)))
|
2015-07-18 22:43:49 +03:00
|
|
|
|
|
2015-09-15 21:07:35 +03:00
|
|
|
|
case let (.Variable(n1), .Variable(n2)) where n1 == n2:
|
|
|
|
|
self = .Copy(.Variable(n2))
|
2015-07-18 22:43:49 +03:00
|
|
|
|
|
2015-09-15 21:07:35 +03:00
|
|
|
|
case let (.Literal(v1), .Literal(v2)) where v1 == v2:
|
|
|
|
|
self = .Copy(.Literal(v2))
|
|
|
|
|
|
|
|
|
|
case let (.Group(n1, v1), .Group(n2, v2)):
|
2015-09-16 22:00:06 +03:00
|
|
|
|
self = .Copy(.Group(Diff(n1, n2), Diff.diff(v1, v2)))
|
2015-09-15 21:07:35 +03:00
|
|
|
|
|
|
|
|
|
default:
|
2015-09-18 17:12:34 +03:00
|
|
|
|
self = .Patch(Term(a), Term(b))
|
2015-09-15 21:07:35 +03:00
|
|
|
|
}
|
2015-07-18 22:43:49 +03:00
|
|
|
|
|
2015-09-11 18:35:51 +03:00
|
|
|
|
default:
|
2015-09-15 21:07:35 +03:00
|
|
|
|
self = Patch(a, b)
|
2015-09-11 18:35:51 +03:00
|
|
|
|
}
|
2015-07-18 22:43:49 +03:00
|
|
|
|
}
|
2015-09-16 16:56:15 +03:00
|
|
|
|
|
2015-09-18 17:12:34 +03:00
|
|
|
|
public static func diff<C1: CollectionType, C2: CollectionType where C1.Index : RandomAccessIndexType, C1.Generator.Element == Term, C2.Index : RandomAccessIndexType, C2.Generator.Element == Term>(a: C1, _ b: C2) -> [Diff] {
|
2015-09-28 21:17:48 +03:00
|
|
|
|
func magnitude(diffs: Stream<(Diff, Int)>) -> Int {
|
|
|
|
|
return diffs.first?.1 ?? 0
|
|
|
|
|
// fixme; this should actually consider the rest of the diff, but we aren’t memoizing that correctly.
|
|
|
|
|
// return diffs.map { $1 }.fold(0, combine: { $0 + $1.value })
|
2015-09-17 22:12:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-17 22:55:11 +03:00
|
|
|
|
func min<A>(a: A, _ rest: A..., _ isLessThan: (A, A) -> Bool) -> A {
|
2015-09-28 21:17:48 +03:00
|
|
|
|
return rest.reduce(a) { isLessThan($0, $1) ? $0 : $1 }
|
2015-09-17 22:55:11 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-28 21:17:48 +03:00
|
|
|
|
let graph = Vertex<(Term, Term, Diff, Int)>(rows: Stream(sequence: a), columns: Stream(sequence: b)) {
|
|
|
|
|
let diff = Diff($0, $1)
|
|
|
|
|
return ($0, $1, diff, diff.magnitude)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func diff(vertex: Vertex<(Term, Term, Diff, Int)>) -> Stream<(Diff, Int)> {
|
|
|
|
|
switch vertex {
|
|
|
|
|
case .End:
|
2015-09-17 22:12:49 +03:00
|
|
|
|
return .Nil
|
2015-09-28 21:17:48 +03:00
|
|
|
|
|
|
|
|
|
case let .XY((a, b, copy, copyCost), x, y):
|
|
|
|
|
let right = x.value
|
|
|
|
|
let down = y.value
|
|
|
|
|
switch (right, down) {
|
|
|
|
|
case (.End, .End):
|
|
|
|
|
return .Cons((copy, copyCost), Memo(evaluated: .Nil))
|
|
|
|
|
case (.End, .XY):
|
|
|
|
|
return vertex.row.map { (Diff.Delete($0.0), 1) }
|
|
|
|
|
case (.XY, .End):
|
|
|
|
|
return vertex.column.map { (Diff.Insert($0.0), 1) }
|
|
|
|
|
case (.XY, .XY):
|
|
|
|
|
let copy = Stream.Cons((copy, copyCost), vertex.diagonal.map(diff))
|
|
|
|
|
let insert = Stream.Cons((Diff.Insert(b), 1), x.map(diff))
|
|
|
|
|
let delete = Stream.Cons((Diff.Delete(a), 1), y.map(diff))
|
|
|
|
|
return min(copy, insert, delete) {
|
|
|
|
|
magnitude($0) < magnitude($1)
|
|
|
|
|
}
|
2015-09-17 22:57:04 +03:00
|
|
|
|
}
|
2015-09-16 21:58:53 +03:00
|
|
|
|
}
|
2015-09-17 22:12:49 +03:00
|
|
|
|
}
|
2015-09-16 21:58:53 +03:00
|
|
|
|
|
2015-09-28 21:17:48 +03:00
|
|
|
|
return Array(diff(graph).map { $0.0 })
|
2015-09-16 16:56:15 +03:00
|
|
|
|
}
|
2015-07-18 22:43:49 +03:00
|
|
|
|
}
|