diff --git a/prototype/Doubt.xcodeproj/project.pbxproj b/prototype/Doubt.xcodeproj/project.pbxproj index 866926139..e42188255 100644 --- a/prototype/Doubt.xcodeproj/project.pbxproj +++ b/prototype/Doubt.xcodeproj/project.pbxproj @@ -43,7 +43,6 @@ D49FCBC81BBF2C4300C5E9C3 /* Algorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49FCBC71BBF2C4300C5E9C3 /* Algorithm.swift */; }; D4AAE50E1B5AE22E004E581F /* Doubt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4AAE4FD1B5AE22E004E581F /* Doubt.framework */; }; D4AAE5401B5AE2D0004E581F /* RangeReplaceableCollectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4AAE5351B5AE2D0004E581F /* RangeReplaceableCollectionType.swift */; }; - D4AAE5451B5AE2D0004E581F /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4AAE53A1B5AE2D0004E581F /* Operators.swift */; }; D4AAE5471B5AE2D0004E581F /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4AAE53C1B5AE2D0004E581F /* Optional.swift */; }; D4AAE5491B5AE2D0004E581F /* StringLiteralConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4AAE53E1B5AE2D0004E581F /* StringLiteralConvertible.swift */; }; D4AAE54A1B5AE2D0004E581F /* Syntax.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4AAE53F1B5AE2D0004E581F /* Syntax.swift */; }; @@ -116,7 +115,6 @@ D4AAE50D1B5AE22E004E581F /* DoubtTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DoubtTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D4AAE5141B5AE22E004E581F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D4AAE5351B5AE2D0004E581F /* RangeReplaceableCollectionType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RangeReplaceableCollectionType.swift; sourceTree = ""; }; - D4AAE53A1B5AE2D0004E581F /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; D4AAE53C1B5AE2D0004E581F /* Optional.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Optional.swift; sourceTree = ""; }; D4AAE53E1B5AE2D0004E581F /* StringLiteralConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringLiteralConvertible.swift; sourceTree = ""; }; D4AAE53F1B5AE2D0004E581F /* Syntax.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Syntax.swift; sourceTree = ""; }; @@ -199,7 +197,6 @@ isa = PBXGroup; children = ( D4AAE5351B5AE2D0004E581F /* RangeReplaceableCollectionType.swift */, - D4AAE53A1B5AE2D0004E581F /* Operators.swift */, D4AAE53C1B5AE2D0004E581F /* Optional.swift */, D4AAE53E1B5AE2D0004E581F /* StringLiteralConvertible.swift */, D4AAE53F1B5AE2D0004E581F /* Syntax.swift */, @@ -464,7 +461,6 @@ D4AAE5491B5AE2D0004E581F /* StringLiteralConvertible.swift in Sources */, D4413FF11BB08FDC00E3C3C1 /* JSON.swift in Sources */, D1F5FE211BDE9C450048BAE4 /* JSONLeaf.swift in Sources */, - D4AAE5451B5AE2D0004E581F /* Operators.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -618,6 +614,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_DISABLE_SAFETY_CHECKS = YES; SWIFT_INSTALL_OBJC_HEADER = NO; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; diff --git a/prototype/Doubt.xcodeproj/xcshareddata/xcschemes/doubt-difftool.xcscheme b/prototype/Doubt.xcodeproj/xcshareddata/xcschemes/doubt-difftool.xcscheme index d39788a85..2de6b9e1d 100644 --- a/prototype/Doubt.xcodeproj/xcshareddata/xcschemes/doubt-difftool.xcscheme +++ b/prototype/Doubt.xcodeproj/xcshareddata/xcschemes/doubt-difftool.xcscheme @@ -64,7 +64,7 @@ + isEnabled = "NO"> + debugDocumentVersioning = "NO"> { /// A recursive instantiation of `Operation`, unrolling another iteration of the recursive type. indirect case Roll(Operation) - - public func analysis(@noescape ifPure ifPure: Result -> C, @noescape ifRoll: Operation -> C) -> C { - switch self { - case let .Pure(b): - return ifPure(b) - case let .Roll(a): - return ifRoll(a) - } - } - - - // MARK: Functor - - public func map(transform: Result -> Other) -> Algorithm { - return analysis(ifPure: transform >>> Algorithm.Pure, ifRoll: { .Roll($0.map { $0.map(transform) }) }) - } - - - // MARK: Monad - - public func flatMap(transform: Result -> Algorithm) -> Algorithm { - return analysis(ifPure: transform, ifRoll: { .Roll($0.map { $0.flatMap(transform) }) }) - } } diff --git a/prototype/Doubt/Cofree.swift b/prototype/Doubt/Cofree.swift index 2db6d597c..a4f6c50ec 100644 --- a/prototype/Doubt/Cofree.swift +++ b/prototype/Doubt/Cofree.swift @@ -121,11 +121,11 @@ extension CofreeType { } - /// Catamorphism over `TermType`s. + /// Catamorphism over `CofreeType`s. /// /// Folds the tree encoded by the receiver into a single value by recurring top-down through the tree, applying `transform` to leaves, then to branches, and so forth. - public func cata(transform: (Annotation, Syntax) -> Result) -> Result { - return self |> (Self.eliminate >>> { ($0, $1.map { $0.cata(transform) }) } >>> transform) + public func cata(transform: (Annotation, Syntax) throws -> Result) rethrows -> Result { + return try transform(extract, unwrap.map { try $0.cata(transform) }) } diff --git a/prototype/Doubt/Free.swift b/prototype/Doubt/Free.swift index ab8fa27f5..24106a7d9 100644 --- a/prototype/Doubt/Free.swift +++ b/prototype/Doubt/Free.swift @@ -21,15 +21,6 @@ public enum Free: CustomDebugStringConvertible { } - public func analysis(@noescape ifPure ifPure: Value throws -> C, @noescape ifRoll: (Annotation, Syntax) throws -> C) rethrows -> C { - switch self { - case let .Pure(b): - return try ifPure(b) - case let .Roll(s): - return try ifRoll(s) - } - } - /// Reduce the receiver by iteration. /// /// `Pure` values are simply unpacked. `Roll` values are mapped recursively, and then have `transform` applied to them. @@ -57,9 +48,12 @@ public enum Free: CustomDebugStringConvertible { /// /// For a lucid, in-depth tutorial on recursion schemes, I recommend [Patrick Thomson](https://twitter.com/importantshock)’s _[An Introduction to Recursion Schemes](http://patrickthomson.ghost.io/an-introduction-to-recursion-schemes/)_ and _[Recursion Schemes, Part 2: A Mob of Morphisms](http://patrickthomson.ghost.io/recursion-schemes-part-2/)_. public func cata(@noescape transform: (Annotation, Syntax) throws -> Value) rethrows -> Value { - return try analysis( - ifPure: id, - ifRoll: { try transform($0, $1.map { try $0.cata(transform) }) }) + switch self { + case let .Pure(a): + return a + case let .Roll(annotation, syntax): + return try transform(annotation, syntax.map { try $0.cata(transform) }) + } } @@ -88,14 +82,12 @@ public enum Free: CustomDebugStringConvertible { // MARK: Functor public func map(@noescape transform: Value throws -> C) rethrows -> Free { - return try analysis(ifPure: { try .Pure(transform($0)) }, ifRoll: { try .Roll($0, $1.map { try $0.map(transform) }) }) - } - - - // MARK: Monad - - public func flatMap(@noescape transform: Value throws -> Free) rethrows -> Free { - return try analysis(ifPure: transform, ifRoll: { try .Roll($0, $1.map { try $0.flatMap(transform) }) }) + switch self { + case let .Pure(a): + return try .Pure(transform(a)) + case let .Roll(annotation, syntax): + return try .Roll(annotation, syntax.map { try $0.map(transform) }) + } } @@ -216,14 +208,17 @@ public func == (left: extension Free { public func JSON(pure pure: Value -> Doubt.JSON, leaf: Leaf -> Doubt.JSON, annotation: Annotation -> Doubt.JSON) -> Doubt.JSON { - return analysis( - ifPure: { [ "pure": pure($0) ] }, - ifRoll: { - [ "roll": [ - "extract": annotation($0), - "unwrap": $1.JSON(leaf: leaf, recur: { $0.JSON(pure: pure, leaf: leaf, annotation: annotation) }) - ] ] - }) + switch self { + case let .Pure(a): + return [ "pure": pure(a) ] + case let .Roll(a, b): + return [ + "roll": [ + "extract": annotation(a), + "unwrap": b.JSON(leaf: leaf, recur: { $0.JSON(pure: pure, leaf: leaf, annotation: annotation) }) + ] + ] + } } } diff --git a/prototype/Doubt/Operators.swift b/prototype/Doubt/Operators.swift deleted file mode 100644 index 772c5c12f..000000000 --- a/prototype/Doubt/Operators.swift +++ /dev/null @@ -1,19 +0,0 @@ -infix operator <> { - associativity right - precedence 140 -} - -infix operator <+> { - associativity right - precedence 140 -} - -infix operator { - associativity right - precedence 140 -} - -infix operator >>> { - associativity right - precedence 170 -} diff --git a/prototype/Doubt/Syntax.swift b/prototype/Doubt/Syntax.swift index f55b2da73..c66043f3b 100644 --- a/prototype/Doubt/Syntax.swift +++ b/prototype/Doubt/Syntax.swift @@ -48,8 +48,8 @@ public enum Syntax: CustomDebugStringConvertible { /// Hylomorphisms are used to construct diffs corresponding to equal terms; see also `CofreeType.zip`. /// /// `hylo` can be used with arbitrary functors which can eliminate to and introduce with `Syntax` values. -public func hylo(down: Syntax -> B, _ up: A -> Syntax) -> A -> B { - return up >>> { $0.map(hylo(down, up)) } >>> down +public func hylo(down: Syntax -> B, _ up: A -> Syntax)(_ a: A) -> B { + return down(up(a).map(hylo(down, up))) } /// Reiteration through `Syntax`. @@ -59,8 +59,9 @@ public func hylo(down: Syntax -> B, _ up: A -> Syntax(down: (Annotation, Syntax) -> B, _ up: A -> (Annotation, Syntax)) -> A -> B { - return up >>> { ($0, $1.map(hylo(down, up))) } >>> down +public func hylo(down: (Annotation, Syntax) -> B, _ up: A -> (Annotation, Syntax))(_ a: A) -> B { + let (annotation, syntax) = up(a) + return down(annotation, syntax.map(hylo(down, up))) } @@ -89,12 +90,12 @@ extension Syntax { switch (left, right) { case let (.Leaf(l1), .Leaf(l2)): return leaf(l1, l2) - case let (.Indexed(v1), .Indexed(v2)): - return v1.count == v2.count && zip(v1, v2).lazy.map(recur).reduce(true) { $0 && $1 } - case let (.Fixed(v1), .Fixed(v2)): - return v1.count == v2.count && zip(v1, v2).lazy.map(recur).reduce(true) { $0 && $1 } - case let (.Keyed(d1), .Keyed(d2)): - return Set(d1.keys) == Set(d2.keys) && d1.keys.map { recur(d1[$0]!, d2[$0]!) }.reduce(true) { $0 && $1 } + case let (.Indexed(v1), .Indexed(v2)) where v1.count == v2.count: + return zip(v1, v2).reduce(true) { $0 && recur($1) } + case let (.Fixed(v1), .Fixed(v2)) where v1.count == v2.count: + return zip(v1, v2).reduce(true) { $0 && recur($1) } + case let (.Keyed(d1), .Keyed(d2)) where Set(d1.keys) == Set(d2.keys): + return d1.keys.reduce(true) { $0 && recur(d1[$1]!, d2[$1]!) } default: return false } diff --git a/prototype/Doubt/TermType.swift b/prototype/Doubt/TermType.swift index f1a7a06b4..1f7b83b1e 100644 --- a/prototype/Doubt/TermType.swift +++ b/prototype/Doubt/TermType.swift @@ -14,15 +14,15 @@ extension TermType { /// Catamorphism over `TermType`s. /// /// Folds the tree encoded by the receiver into a single value by recurring top-down through the tree, applying `transform` to leaves, then to branches, and so forth. - public func cata(transform: Syntax -> Result) -> Result { - return self |> (Self.unwrap >>> { $0.map { $0.cata(transform) } } >>> transform) + public func cata(transform: Syntax throws -> Result) rethrows -> Result { + return try transform(unwrap.map { try $0.cata(transform) }) } /// Paramorphism over `TermType`s. /// /// Folds the tree encoded by the receiver into a single value by recurring top-down through the tree, applying `transform` to leaves, then to branches, and so forth. Each recursive instance is made available in the `Syntax` alongside the result value at that node. - public func para(transform: Syntax<(Self, Result), Leaf> -> Result) -> Result { - return self |> (Self.unwrap >>> { $0.map { ($0, $0.para(transform)) } } >>> transform) + public func para(transform: Syntax<(Self, Result), Leaf> throws -> Result) rethrows -> Result { + return try transform(unwrap.map { try ($0, $0.para(transform)) }) } diff --git a/prototype/UI/diff.js b/prototype/UI/diff.js index fa4448879..5b50d50fe 100644 --- a/prototype/UI/diff.js +++ b/prototype/UI/diff.js @@ -67,10 +67,12 @@ function wrap(tagName, element) { } /// String -> Syntax a -> Range -> (a -> Range) -> (a -> DOM) -> DOM -function rangeAndSyntaxToDOM(source, syntax, range, getRange, recur) { +function termToDOM(source, syntax, extract, getRange, recur) { recur = recur || function(term) { - return rangeAndSyntaxToDOM(source, term.unwrap, term.extract, getRange); + return termToDOM(source, term.unwrap, term.extract, getRange); } + var categories = extract.categories; + var range = extract.range; var element; if (syntax.leaf != null) { element = document.createElement("span"); @@ -83,18 +85,9 @@ function rangeAndSyntaxToDOM(source, syntax, range, getRange, recur) { var child = values[i]; if (child.pure == "") continue; var childRange = getRange(child); - if (childRange.before != null) { - var beforeRange = childRange.before; - element.appendChild(document.createTextNode(source.substr(previous, beforeRange[0] - previous))); - element.appendChild(wrap("li", recur(child))); - previous = beforeRange[0] + beforeRange[1]; - } - if (childRange.after != null) { - var afterRange = childRange.before; - element.appendChild(document.createTextNode(source.substr(previous, afterRange[0] - previous))); - element.appendChild(wrap("td", recur(child))); - previous = afterRange[0] + afterRange[1]; - } + element.appendChild(document.createTextNode(source.substr(previous, childRange[0] - previous))); + element.appendChild(wrap("li", recur(child))); + previous = childRange[0] + childRange[1]; } element.appendChild(document.createTextNode(source.substr(previous, range[0] + range[1] - previous))); } else if (syntax.keyed != null) { @@ -127,6 +120,11 @@ function rangeAndSyntaxToDOM(source, syntax, range, getRange, recur) { element.appendChild(document.createTextNode(source.substr(previous, range[0] + range[1] - previous))); } element["data-range"] = range; + + for (index in categories) { + element.classList.add('category-'+categories[index]); + } + return element; } @@ -137,11 +135,11 @@ function diffToDOM(diff, sources) { if (diffOrTerm.pure != null) { var beforeRange, afterRange; if (diffOrTerm.pure.before != null) { - beforeRange = diffOrTerm.pure.before.extract + beforeRange = diffOrTerm.pure.before.extract.range } if (diffOrTerm.pure.after != null) { - afterRange = diffOrTerm.pure.after.extract + afterRange = diffOrTerm.pure.after.extract.range } if (beforeRange == null) { @@ -154,10 +152,10 @@ function diffToDOM(diff, sources) { return { "before": beforeRange, "after": afterRange }; } if (diffOrTerm.roll != null) { - return diffOrTerm.roll.extract; + return { before: diffOrTerm.roll.extract.before.range, after: diffOrTerm.roll.extract.after.range }; } if (diffOrTerm.extract != null) { - return diffOrTerm.extract; + return diffOrTerm.extract.range; } } @@ -175,7 +173,7 @@ function diffToDOM(diff, sources) { function pureToDOM(sources, patch, getRangeFun, diffToDOMFun) { var elementA, elementB; if (patch.before != null) { - elementA = rangeAndSyntaxToDOM(sources.before, patch.before.unwrap, patch.before.extract, getRangeFun); + elementA = termToDOM(sources.before, patch.before.unwrap, patch.before.extract, getRangeFun); elementA.classList.add("delete"); if (patch.after != null) { elementA.classList.add("replace"); @@ -183,7 +181,7 @@ function pureToDOM(sources, patch, getRangeFun, diffToDOMFun) { } if (patch.after != null) { - elementB = rangeAndSyntaxToDOM(sources.after, patch.after.unwrap, patch.after.extract, getRangeFun); + elementB = termToDOM(sources.after, patch.after.unwrap, patch.after.extract, getRangeFun); elementB.classList.add("insert"); if (patch.before != null) { elementB.classList.add("replace"); @@ -205,7 +203,14 @@ function pureToDOM(sources, patch, getRangeFun, diffToDOMFun) { function rollToDOM(sources, rollOrTerm, getRangeFun, diffToDOMFun) { var syntax = rollOrTerm.unwrap - var range = rollOrTerm.extract + var categories = { + before: rollOrTerm.extract.before.categories, + after: rollOrTerm.extract.after.categories + } + var range = { + before: rollOrTerm.extract.before.range, + after: rollOrTerm.extract.after.range + } var elementA; var elementB; @@ -429,6 +434,14 @@ function rollToDOM(sources, rollOrTerm, getRangeFun, diffToDOMFun) { elementB.appendChild(document.createTextNode(textB)); } + for (index in categories.before) { + elementA.classList.add('category-'+categories.before[index]); + } + + for (index in categories.after) { + elementB.classList.add('category-'+categories.after[index]); + } + return { "before": elementA, "after": elementB } } diff --git a/prototype/UI/dom.js b/prototype/UI/dom.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/prototype/UI/index.html b/prototype/UI/index.html index 3bcd72d54..3d1b3da27 100644 --- a/prototype/UI/index.html +++ b/prototype/UI/index.html @@ -29,25 +29,69 @@ background-color: #ffffec; outline: 1px solid #e9e9c0; } - .invisible { - background-color: #fff; - visibility: hidden; - } + + .invisible { + background-color: #fff; + visibility: hidden; + } .diff div, .diff ul, .diff li, .diff dl, .diff dd, .diff span { white-space: pre-wrap; display: inline; margin: 0; padding: 0; + color: initial; } .diff dt { display: none; } + + /* syntax highlighting */ + .diff .category-regex, + .diff .category-string { + color: #183691; + } + + .diff .category-false, + .diff .category-true, + .diff .category-null, + .diff .category-undefined, + .diff .category-number, + .diff .category-function_call>li>.category-identifier, + .diff .category-function_call>li>.category-member_access>.category-identifier, + .diff .category-member_access>:not(:first-child)>.category-identifier { + color: #0086b3; + } + + .diff .category-comment { + color: #969896; + } + + .diff [class^="category-"][class$="_op"], + .diff .category-ternary, + .diff .category-var_declaration, + .diff .category-new_expression, + .diff .category-if_statement, + .diff .category-do_statement, + .diff .category-for_statement, + .diff .category-for_in_statement, + .diff .category-return_statement, + .diff .category-function, + .diff .category-assignment, + .diff .category-var_assignment { + color: #a71d5d; + } + + .diff .category-function>li:first-child>.category-identifier, + .diff .category-new_expression>li>.category-function_call>li:first-child>.category-identifier, + .diff .category-pair>li:first-child>.category-identifier, + .diff .category-assignment>li:first-child>.category-member_access>:not(:first-child)>.category-identifier { + color: #795da3; + } - @@ -66,16 +110,15 @@ -
-
+
+
diff --git a/prototype/UI/term.js b/prototype/UI/term.js index 10dae6208..f0e834616 100644 --- a/prototype/UI/term.js +++ b/prototype/UI/term.js @@ -12,12 +12,3 @@ function Term(object) { this.unwrap = object.unwrap; return this; } - -/// Term -> String -> DOM -function termToDOM(term, which, source) { - return rangeAndSyntaxToDOM(term.range, term.unwrap, source, function(term) { - return term.range; - }, function(term) { - return termToDOM(term, which, source); - }); -} diff --git a/prototype/doubt-difftool/TSNode.swift b/prototype/doubt-difftool/TSNode.swift index 1ddf84ccd..c8e848140 100644 --- a/prototype/doubt-difftool/TSNode.swift +++ b/prototype/doubt-difftool/TSNode.swift @@ -26,20 +26,20 @@ extension TSNode { var namedChildren: ChildrenCollection { return ChildrenCollection(node: self, count: ts_node_named_child_count(self), child: ts_node_named_child) } +} - struct ChildrenCollection: CollectionType { - let node: TSNode - let count: Int - let child: (TSNode, Int) -> TSNode +struct ChildrenCollection: CollectionType { + let node: TSNode + let count: Int + let child: (TSNode, Int) -> TSNode - subscript (index: Int) -> TSNode { - return child(node, index) - } + subscript (index: Int) -> TSNode { + return child(node, index) + } - let startIndex = 0 - var endIndex: Int { - return count - } + let startIndex = 0 + var endIndex: Int { + return count } } diff --git a/prototype/doubt-difftool/main.swift b/prototype/doubt-difftool/main.swift index ecbbb361d..cb25c8ac4 100644 --- a/prototype/doubt-difftool/main.swift +++ b/prototype/doubt-difftool/main.swift @@ -3,9 +3,9 @@ import Doubt import Prelude import Madness -func benchmark(label: String? = nil, _ f: () -> T) -> T { +func benchmark(label: String? = nil, _ f: () throws -> T) rethrows -> T { let start = NSDate.timeIntervalSinceReferenceDate() - let result = f() + let result = try f() let end = NSDate.timeIntervalSinceReferenceDate() print((label.map { "\($0): " } ?? "") + "\(end - start)s") return result @@ -144,7 +144,7 @@ func parserForType(type: String) -> String throws -> Term { } } -let parsed = parse(argumentsParser, input: Process.arguments) +let parsed = benchmark("parsing arguments & loading sources") { parse(argumentsParser, input: Process.arguments) } let arguments: Argument = try parsed.either(ifLeft: { throw "\($0)" }, ifRight: { $0 }) let (aSource, bSource) = arguments.sources let jsonURL = NSURL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).URLByAppendingPathComponent("diff.json") @@ -152,18 +152,18 @@ guard let uiPath = NSBundle.mainBundle().infoDictionary?["PathToUISource"] as? S guard aSource.type == bSource.type else { throw "can’t compare files of different types" } let parser = parserForType(aSource.type) -let a = try parser(aSource.contents) -let b = try parser(bSource.contents) -let diff = Interpreter(equal: Term.equals(annotation: const(true), leaf: ==), comparable: Interpreter.comparable { $0.extract.categories }, cost: Free.sum(Patch.sum)).run(a, b) +let a = try benchmark("parsing source a") { try parser(aSource.contents) } +let b = try benchmark("parsing source b") { try parser(bSource.contents) } +let diff = benchmark("diffing") { Interpreter(equal: Term.equals(annotation: const(true), leaf: ==), comparable: Interpreter.comparable { $0.extract.categories }, cost: Free.sum(Patch.sum)).run(a, b) } switch arguments.output { case .Split: let JSON: Doubt.JSON = [ "before": .String(aSource.contents), "after": .String(bSource.contents), - "diff": diff.JSON(pure: { $0.JSON { $0.JSON(annotation: { $0.range.JSON }, leaf: Doubt.JSON.String) } }, leaf: Doubt.JSON.String, annotation: { + "diff": diff.JSON(pure: { $0.JSON { $0.JSON(annotation: { $0.JSON }, leaf: Doubt.JSON.String) } }, leaf: Doubt.JSON.String, annotation: { [ - "before": $0.range.JSON, - "after": $1.range.JSON, + "before": $0.JSON, + "after": $1.JSON, ] }), ] @@ -178,5 +178,5 @@ case .Split: NSWorkspace.sharedWorkspace().openURL(URL) } case .Unified: - print(benchmark { unified(diff, before: aSource.contents, after: bSource.contents) }) + print(benchmark("formatting unified diff") { unified(diff, before: aSource.contents, after: bSource.contents) }) }