1
1
mirror of https://github.com/github/semantic.git synced 2024-12-12 04:58:02 +03:00
semantic/prototype/Doubt/Diff.swift

114 lines
3.0 KiB
Swift
Raw Normal View History

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-29 19:48:53 +03:00
return .Patch(Term(.Empty), term)
}
2015-09-18 17:12:34 +03:00
public static func Delete(term: Term) -> Diff {
2015-09-29 19:48:53 +03:00
return .Patch(term, 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 let .Roll(s):
self = .Copy(s.map(Diff.init))
}
}
2015-09-29 05:36:22 +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):
2015-09-29 05:57:29 +03:00
return Doc(a).bracket("{-", "-}")
<> Doc(b).bracket("{+", "+}")
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):
return ".Patch(\(String(reflecting: a)), \(String(reflecting: b)))"
2015-07-18 22:43:49 +03:00
case let .Copy(a):
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-29 19:48:53 +03:00
switch (a.syntax, b.syntax) {
case let (.Apply(a, aa), .Apply(b, bb)):
self = .Copy(.Apply(Diff(a, b), Diff.diff(aa, bb)))
2015-07-18 22:43:49 +03:00
2015-09-29 19:48:53 +03:00
case let (.Abstract(p1, b1), .Abstract(p2, b2)):
self = .Copy(.Abstract(Diff.diff(p1, p2), Diff.diff(b1, b2)))
2015-07-18 22:43:49 +03:00
2015-09-29 19:48:53 +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-29 19:48:53 +03:00
case let (.Variable(n1), .Variable(n2)) where n1 == n2:
self = .Copy(.Variable(n2))
2015-09-15 21:07:35 +03:00
2015-09-29 19:48:53 +03:00
case let (.Literal(v1), .Literal(v2)) where v1 == v2:
self = .Copy(.Literal(v2))
2015-09-15 21:07:35 +03:00
2015-09-29 19:48:53 +03:00
case let (.Group(n1, v1), .Group(n2, v2)):
self = .Copy(.Group(Diff(n1, n2), Diff.diff(v1, v2)))
2015-07-18 22:43:49 +03:00
default:
2015-09-29 19:48:53 +03:00
self = .Patch(a, b)
}
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:21:13 +03:00
func magnitude(diffs: Stream<(Diff, Int)>) -> Int {
// return diffs.first?.magnitude ?? 0
return diffs.map { $1 }.reduce(0, combine: +)
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 {
return rest.reduce(a, combine: {
isLessThan($0, $1) ? $0 : $1
})
2015-09-17 22:55:11 +03:00
}
2015-09-28 21:21:13 +03:00
func diff(a: Stream<Term>, _ b: Stream<Term>) -> Stream<(Diff, Int)> {
switch (a, b) {
case (.Nil, .Nil):
2015-09-17 22:12:49 +03:00
return .Nil
case (.Nil, .Cons):
2015-09-28 21:21:13 +03:00
return b.map { (Diff.Insert($0), 1) }
case (.Cons, .Nil):
2015-09-28 21:21:13 +03:00
return a.map { (Diff.Delete($0), 1) }
case let (.Cons(x, xs), .Cons(y, ys)):
2015-09-28 21:21:13 +03:00
let copy = Diff(x, y)
let here = Stream.Cons((copy, copy.magnitude), Memo { diff(xs.value, ys.value) })
let insert = Stream.Cons((Diff.Insert(y), 1), Memo { diff(a, ys.value) })
let delete = Stream.Cons((Diff.Delete(x), 1), Memo { diff(xs.value, b) })
return min(here, 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:21:13 +03:00
return Array(diff(Stream(sequence: a), Stream(sequence: b)).map { $0.0 })
2015-09-16 16:56:15 +03:00
}
2015-07-18 22:43:49 +03:00
}