1
1
mirror of https://github.com/github/semantic.git synced 2024-12-30 18:36:27 +03:00

🔥 the prototype.

This commit is contained in:
Rob Rix 2015-12-18 14:20:46 -05:00
parent 32f562eea0
commit 44d437ccdb
59 changed files with 0 additions and 7272 deletions

View File

@ -1,6 +0,0 @@
.DS_Store
xcuserdata
*.xcuserdatad
*.xccheckout
*.mode*
*.pbxuser

View File

@ -1,801 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
D18FF8821BD0404700D18F2D /* Madness.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D18FF8811BD0404700D18F2D /* Madness.framework */; };
D1F5FE201BDE891F0048BAE4 /* JSONParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1F5FE1F1BDE891F0048BAE4 /* JSONParserTests.swift */; };
D1F5FE211BDE9C450048BAE4 /* JSONLeaf.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0934C1BD188F5005A6326 /* JSONLeaf.swift */; };
D1F5FE221BDE9CC10048BAE4 /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0934A1BD188CA005A6326 /* JSONParser.swift */; };
D40B89C41BC319070078E098 /* Matrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40B89C31BC319070078E098 /* Matrix.swift */; };
D40B89C81BC439000078E098 /* Assertions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40B89C71BC439000078E098 /* Assertions.framework */; };
D40D72541BCEEB1F001B7A9E /* InterpreterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40D72531BCEEB1F001B7A9E /* InterpreterTests.swift */; };
D40D72561BCFF360001B7A9E /* Interpreter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40D72551BCFF360001B7A9E /* Interpreter.swift */; };
D40D725A1BD15321001B7A9E /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40D72591BD15321001B7A9E /* SwiftCheck.framework */; };
D40D725C1BD15417001B7A9E /* RangedTerm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40D725B1BD15417001B7A9E /* RangedTerm.swift */; };
D40D725E1BD1826C001B7A9E /* TermTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40D725D1BD1826C001B7A9E /* TermTests.swift */; };
D40D72601BD19E69001B7A9E /* DiffTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40D725F1BD19E69001B7A9E /* DiffTests.swift */; };
D40D72621BD1A07E001B7A9E /* UnannotatedTerm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40D72611BD1A07E001B7A9E /* UnannotatedTerm.swift */; };
D40D72641BD1A0C1001B7A9E /* RangedDiff.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40D72631BD1A0C1001B7A9E /* RangedDiff.swift */; };
D42F096B1BCCC41600B95610 /* Either.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F09671BCCC41600B95610 /* Either.framework */; };
D42F096C1BCCC41600B95610 /* Memo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F09681BCCC41600B95610 /* Memo.framework */; };
D42F096D1BCCC41600B95610 /* Prelude.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F09691BCCC41600B95610 /* Prelude.framework */; };
D42F096E1BCCC41600B95610 /* Stream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F096A1BCCC41600B95610 /* Stream.framework */; };
D42F09771BCCC5DC00B95610 /* Either.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F09671BCCC41600B95610 /* Either.framework */; };
D42F09781BCCC5DC00B95610 /* Memo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F09681BCCC41600B95610 /* Memo.framework */; };
D42F09791BCCC5DC00B95610 /* Prelude.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F09691BCCC41600B95610 /* Prelude.framework */; };
D42F097A1BCCC5DC00B95610 /* Stream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F096A1BCCC41600B95610 /* Stream.framework */; };
D42F097C1BCE914A00B95610 /* Cofree.swift in Sources */ = {isa = PBXBuildFile; fileRef = D42F097B1BCE914A00B95610 /* Cofree.swift */; };
D42F097E1BCEAEDA00B95610 /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D42F097D1BCEAEDA00B95610 /* Operation.swift */; };
D42F09801BCECB7900B95610 /* TermType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D42F097F1BCECB7900B95610 /* TermType.swift */; };
D432D4711BA9AC0B00F3FABC /* SESTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D432D4701BA9AC0B00F3FABC /* SESTests.swift */; };
D4413FEF1BB06D4C00E3C3C1 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4413FEE1BB06D4C00E3C3C1 /* Dictionary.swift */; };
D4413FF11BB08FDC00E3C3C1 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4413FF01BB08FDC00E3C3C1 /* JSON.swift */; };
D45A36C91BBC667D00BE3DDE /* Categorizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45A36C81BBC667D00BE3DDE /* Categorizable.swift */; };
D46452C71BE7C6C800D7D26E /* Argument.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46452C61BE7C6C800D7D26E /* Argument.swift */; };
D46452C91BE7EB2500D7D26E /* Unified.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46452C81BE7EB2500D7D26E /* Unified.swift */; };
D46452D81BEA731800D7D26E /* Location.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46452D71BEA731800D7D26E /* Location.swift */; };
D464530C1BEBB1F900D7D26E /* LocationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D464530B1BEBB1F900D7D26E /* LocationTests.swift */; };
D49FCBC41BBEF98E00C5E9C3 /* Free.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49FCBC31BBEF98E00C5E9C3 /* Free.swift */; };
D49FCBC61BBF214300C5E9C3 /* Patch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49FCBC51BBF214300C5E9C3 /* Patch.swift */; };
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 */; };
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 */; };
D4DF96ED1BC46B630040F41F /* SES.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4DF96EC1BC46B630040F41F /* SES.swift */; };
D4DF970C1BC5DF9E0040F41F /* BoundsCheckedArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = D435B7521BB31BBC000902F6 /* BoundsCheckedArray.swift */; };
D4FB2CD61BDEBC9000B3CCE0 /* Doubt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4AAE4FD1B5AE22E004E581F /* Doubt.framework */; };
D4FB2CD71BDEBC9D00B3CCE0 /* Either.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F09671BCCC41600B95610 /* Either.framework */; };
D4FB2CD81BDEBC9D00B3CCE0 /* Memo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F09681BCCC41600B95610 /* Memo.framework */; };
D4FB2CD91BDEBC9D00B3CCE0 /* Prelude.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F09691BCCC41600B95610 /* Prelude.framework */; };
D4FB2CDA1BDEBC9D00B3CCE0 /* Stream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D42F096A1BCCC41600B95610 /* Stream.framework */; };
D4FB2CDC1BDEBCCD00B3CCE0 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FB2CDB1BDEBCCD00B3CCE0 /* main.swift */; };
D4FB2CE01BDEBD1C00B3CCE0 /* libruntime.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D4FB2CDE1BDEBD1C00B3CCE0 /* libruntime.a */; };
D4FB2CF81BE1560400B3CCE0 /* TSNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FB2CF71BE1560400B3CCE0 /* TSNode.swift */; };
D4FB2CFA1BE28F6D00B3CCE0 /* parser.c in Sources */ = {isa = PBXBuildFile; fileRef = D4FB2CF91BE28F6D00B3CCE0 /* parser.c */; };
D4FB2CFC1BE292BB00B3CCE0 /* parser.c in Sources */ = {isa = PBXBuildFile; fileRef = D4FB2CFB1BE292BB00B3CCE0 /* parser.c */; };
D4FB2D021BE2943A00B3CCE0 /* Info.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FB2D011BE2943A00B3CCE0 /* Info.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
D4AAE50F1B5AE22E004E581F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D4AAE4F41B5AE22E004E581F /* Project object */;
proxyType = 1;
remoteGlobalIDString = D4AAE4FC1B5AE22E004E581F;
remoteInfo = Doubt;
};
D4FB2CE31BDEBD4200B3CCE0 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D4AAE4F41B5AE22E004E581F /* Project object */;
proxyType = 1;
remoteGlobalIDString = D485A7841BDEB6C5003A17B6;
remoteInfo = runtime;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
D18FF8811BD0404700D18F2D /* Madness.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Madness.framework; path = "../../../../Library/Developer/Xcode/DerivedData/Doubt-gibmbsxjgxflybarnuoisglmgdll/Build/Products/Debug/Madness.framework"; sourceTree = "<group>"; };
D1A0934A1BD188CA005A6326 /* JSONParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONParser.swift; sourceTree = "<group>"; };
D1A0934C1BD188F5005A6326 /* JSONLeaf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONLeaf.swift; sourceTree = "<group>"; };
D1F5FE1F1BDE891F0048BAE4 /* JSONParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONParserTests.swift; sourceTree = "<group>"; };
D40B89C31BC319070078E098 /* Matrix.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matrix.swift; sourceTree = "<group>"; };
D40B89C71BC439000078E098 /* Assertions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Assertions.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D40D72531BCEEB1F001B7A9E /* InterpreterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterpreterTests.swift; sourceTree = "<group>"; };
D40D72551BCFF360001B7A9E /* Interpreter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Interpreter.swift; sourceTree = "<group>"; };
D40D72591BD15321001B7A9E /* SwiftCheck.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D40D725B1BD15417001B7A9E /* RangedTerm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RangedTerm.swift; sourceTree = "<group>"; };
D40D725D1BD1826C001B7A9E /* TermTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TermTests.swift; sourceTree = "<group>"; };
D40D725F1BD19E69001B7A9E /* DiffTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiffTests.swift; sourceTree = "<group>"; };
D40D72611BD1A07E001B7A9E /* UnannotatedTerm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnannotatedTerm.swift; sourceTree = "<group>"; };
D40D72631BD1A0C1001B7A9E /* RangedDiff.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RangedDiff.swift; sourceTree = "<group>"; };
D42F09671BCCC41600B95610 /* Either.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Either.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D42F09681BCCC41600B95610 /* Memo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Memo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D42F09691BCCC41600B95610 /* Prelude.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Prelude.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D42F096A1BCCC41600B95610 /* Stream.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Stream.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D42F097B1BCE914A00B95610 /* Cofree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cofree.swift; sourceTree = "<group>"; };
D42F097D1BCEAEDA00B95610 /* Operation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operation.swift; sourceTree = "<group>"; };
D42F097F1BCECB7900B95610 /* TermType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TermType.swift; sourceTree = "<group>"; };
D432D4701BA9AC0B00F3FABC /* SESTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SESTests.swift; sourceTree = "<group>"; };
D435B7521BB31BBC000902F6 /* BoundsCheckedArray.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoundsCheckedArray.swift; sourceTree = "<group>"; };
D4413FEE1BB06D4C00E3C3C1 /* Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = "<group>"; };
D4413FF01BB08FDC00E3C3C1 /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
D45A36C81BBC667D00BE3DDE /* Categorizable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Categorizable.swift; sourceTree = "<group>"; };
D46452C61BE7C6C800D7D26E /* Argument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Argument.swift; sourceTree = "<group>"; };
D46452C81BE7EB2500D7D26E /* Unified.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Unified.swift; sourceTree = "<group>"; };
D46452D71BEA731800D7D26E /* Location.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Location.swift; sourceTree = "<group>"; };
D464530B1BEBB1F900D7D26E /* LocationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationTests.swift; sourceTree = "<group>"; };
D49FCBC31BBEF98E00C5E9C3 /* Free.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Free.swift; sourceTree = "<group>"; };
D49FCBC51BBF214300C5E9C3 /* Patch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Patch.swift; sourceTree = "<group>"; };
D49FCBC71BBF2C4300C5E9C3 /* Algorithm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Algorithm.swift; sourceTree = "<group>"; };
D4AAE4FD1B5AE22E004E581F /* Doubt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Doubt.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D4AAE5011B5AE22E004E581F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
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 = "<group>"; };
D4AAE5351B5AE2D0004E581F /* RangeReplaceableCollectionType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RangeReplaceableCollectionType.swift; sourceTree = "<group>"; };
D4AAE53C1B5AE2D0004E581F /* Optional.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Optional.swift; sourceTree = "<group>"; };
D4AAE53E1B5AE2D0004E581F /* StringLiteralConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringLiteralConvertible.swift; sourceTree = "<group>"; };
D4AAE53F1B5AE2D0004E581F /* Syntax.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Syntax.swift; sourceTree = "<group>"; };
D4DF96EC1BC46B630040F41F /* SES.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SES.swift; sourceTree = "<group>"; };
D4DF96F01BC54C970040F41F /* Doubt.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = Doubt.modulemap; sourceTree = "<group>"; };
D4FB2CC91BDEBC6300B3CCE0 /* doubt-difftool.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "doubt-difftool.app"; sourceTree = BUILT_PRODUCTS_DIR; };
D4FB2CDB1BDEBCCD00B3CCE0 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
D4FB2CDE1BDEBD1C00B3CCE0 /* libruntime.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libruntime.a; path = "External/tree-sitter/out/Release/libruntime.a"; sourceTree = SOURCE_ROOT; };
D4FB2CE51BDEBE7900B3CCE0 /* doubt-difftool-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "doubt-difftool-Bridging-Header.h"; sourceTree = "<group>"; };
D4FB2CF71BE1560400B3CCE0 /* TSNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TSNode.swift; sourceTree = "<group>"; };
D4FB2CF91BE28F6D00B3CCE0 /* parser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = parser.c; path = "External/tree-sitter-javascript/src/parser.c"; sourceTree = SOURCE_ROOT; };
D4FB2CFB1BE292BB00B3CCE0 /* parser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = parser.c; path = "External/tree-sitter-c/src/parser.c"; sourceTree = SOURCE_ROOT; };
D4FB2D011BE2943A00B3CCE0 /* Info.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Info.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D4AAE4F91B5AE22E004E581F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D18FF8821BD0404700D18F2D /* Madness.framework in Frameworks */,
D42F096B1BCCC41600B95610 /* Either.framework in Frameworks */,
D42F096C1BCCC41600B95610 /* Memo.framework in Frameworks */,
D42F096D1BCCC41600B95610 /* Prelude.framework in Frameworks */,
D42F096E1BCCC41600B95610 /* Stream.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D4AAE50A1B5AE22E004E581F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D40D725A1BD15321001B7A9E /* SwiftCheck.framework in Frameworks */,
D40B89C81BC439000078E098 /* Assertions.framework in Frameworks */,
D4AAE50E1B5AE22E004E581F /* Doubt.framework in Frameworks */,
D42F09771BCCC5DC00B95610 /* Either.framework in Frameworks */,
D42F09781BCCC5DC00B95610 /* Memo.framework in Frameworks */,
D42F09791BCCC5DC00B95610 /* Prelude.framework in Frameworks */,
D42F097A1BCCC5DC00B95610 /* Stream.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D4FB2CC61BDEBC6300B3CCE0 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D4FB2CD61BDEBC9000B3CCE0 /* Doubt.framework in Frameworks */,
D4FB2CD71BDEBC9D00B3CCE0 /* Either.framework in Frameworks */,
D4FB2CD81BDEBC9D00B3CCE0 /* Memo.framework in Frameworks */,
D4FB2CE01BDEBD1C00B3CCE0 /* libruntime.a in Frameworks */,
D4FB2CD91BDEBC9D00B3CCE0 /* Prelude.framework in Frameworks */,
D4FB2CDA1BDEBC9D00B3CCE0 /* Stream.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
D4AAE4F31B5AE22E004E581F = {
isa = PBXGroup;
children = (
D4AAE4FF1B5AE22E004E581F /* Doubt */,
D4AAE5111B5AE22E004E581F /* DoubtTests */,
D4FB2CCA1BDEBC6300B3CCE0 /* doubt-difftool */,
D4AAE4FE1B5AE22E004E581F /* Products */,
);
sourceTree = "<group>";
};
D4AAE4FE1B5AE22E004E581F /* Products */ = {
isa = PBXGroup;
children = (
D4AAE4FD1B5AE22E004E581F /* Doubt.framework */,
D4AAE50D1B5AE22E004E581F /* DoubtTests.xctest */,
D4FB2CC91BDEBC6300B3CCE0 /* doubt-difftool.app */,
);
name = Products;
sourceTree = "<group>";
};
D4AAE4FF1B5AE22E004E581F /* Doubt */ = {
isa = PBXGroup;
children = (
D4AAE5351B5AE2D0004E581F /* RangeReplaceableCollectionType.swift */,
D4AAE53C1B5AE2D0004E581F /* Optional.swift */,
D4AAE53E1B5AE2D0004E581F /* StringLiteralConvertible.swift */,
D4AAE53F1B5AE2D0004E581F /* Syntax.swift */,
D4413FEE1BB06D4C00E3C3C1 /* Dictionary.swift */,
D4413FF01BB08FDC00E3C3C1 /* JSON.swift */,
D40B89C31BC319070078E098 /* Matrix.swift */,
D45A36C81BBC667D00BE3DDE /* Categorizable.swift */,
D49FCBC31BBEF98E00C5E9C3 /* Free.swift */,
D42F097B1BCE914A00B95610 /* Cofree.swift */,
D49FCBC51BBF214300C5E9C3 /* Patch.swift */,
D49FCBC71BBF2C4300C5E9C3 /* Algorithm.swift */,
D42F097D1BCEAEDA00B95610 /* Operation.swift */,
D4DF96EC1BC46B630040F41F /* SES.swift */,
D435B7521BB31BBC000902F6 /* BoundsCheckedArray.swift */,
D42F097F1BCECB7900B95610 /* TermType.swift */,
D1A0934A1BD188CA005A6326 /* JSONParser.swift */,
D1A0934C1BD188F5005A6326 /* JSONLeaf.swift */,
D40D72551BCFF360001B7A9E /* Interpreter.swift */,
D46452D71BEA731800D7D26E /* Location.swift */,
D4AAE5001B5AE22E004E581F /* Supporting Files */,
);
path = Doubt;
sourceTree = "<group>";
};
D4AAE5001B5AE22E004E581F /* Supporting Files */ = {
isa = PBXGroup;
children = (
D4AAE5011B5AE22E004E581F /* Info.plist */,
D4DF96F01BC54C970040F41F /* Doubt.modulemap */,
D42F09671BCCC41600B95610 /* Either.framework */,
D42F09681BCCC41600B95610 /* Memo.framework */,
D18FF8811BD0404700D18F2D /* Madness.framework */,
D42F09691BCCC41600B95610 /* Prelude.framework */,
D42F096A1BCCC41600B95610 /* Stream.framework */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
D4AAE5111B5AE22E004E581F /* DoubtTests */ = {
isa = PBXGroup;
children = (
D1F5FE1F1BDE891F0048BAE4 /* JSONParserTests.swift */,
D432D4701BA9AC0B00F3FABC /* SESTests.swift */,
D40D72531BCEEB1F001B7A9E /* InterpreterTests.swift */,
D40D725B1BD15417001B7A9E /* RangedTerm.swift */,
D40D72611BD1A07E001B7A9E /* UnannotatedTerm.swift */,
D40D72631BD1A0C1001B7A9E /* RangedDiff.swift */,
D40D725D1BD1826C001B7A9E /* TermTests.swift */,
D40D725F1BD19E69001B7A9E /* DiffTests.swift */,
D464530B1BEBB1F900D7D26E /* LocationTests.swift */,
D4AAE5141B5AE22E004E581F /* Info.plist */,
D40B89C71BC439000078E098 /* Assertions.framework */,
D40D72591BD15321001B7A9E /* SwiftCheck.framework */,
);
path = DoubtTests;
sourceTree = "<group>";
};
D4FB2CCA1BDEBC6300B3CCE0 /* doubt-difftool */ = {
isa = PBXGroup;
children = (
D4FB2CDB1BDEBCCD00B3CCE0 /* main.swift */,
D4FB2D011BE2943A00B3CCE0 /* Info.swift */,
D4FB2CF71BE1560400B3CCE0 /* TSNode.swift */,
D46452C61BE7C6C800D7D26E /* Argument.swift */,
D46452C81BE7EB2500D7D26E /* Unified.swift */,
D4FB2CE51BDEBE7900B3CCE0 /* doubt-difftool-Bridging-Header.h */,
D4FB2D001BE2936800B3CCE0 /* Parsers */,
D4FB2CDE1BDEBD1C00B3CCE0 /* libruntime.a */,
);
path = "doubt-difftool";
sourceTree = "<group>";
};
D4FB2CFE1BE2934A00B3CCE0 /* C */ = {
isa = PBXGroup;
children = (
D4FB2CFB1BE292BB00B3CCE0 /* parser.c */,
);
name = C;
sourceTree = "<group>";
};
D4FB2CFF1BE2934E00B3CCE0 /* JavaScript */ = {
isa = PBXGroup;
children = (
D4FB2CF91BE28F6D00B3CCE0 /* parser.c */,
);
name = JavaScript;
sourceTree = "<group>";
};
D4FB2D001BE2936800B3CCE0 /* Parsers */ = {
isa = PBXGroup;
children = (
D4FB2CFF1BE2934E00B3CCE0 /* JavaScript */,
D4FB2CFE1BE2934A00B3CCE0 /* C */,
);
name = Parsers;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
D4AAE4FA1B5AE22E004E581F /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXLegacyTarget section */
D485A7841BDEB6C5003A17B6 /* runtime */ = {
isa = PBXLegacyTarget;
buildArgumentsString = "$(ACTION)";
buildConfigurationList = D485A7871BDEB6C5003A17B6 /* Build configuration list for PBXLegacyTarget "runtime" */;
buildPhases = (
);
buildToolPath = "$(SRCROOT)/script/tree-sitter.sh";
buildWorkingDirectory = "$(SRCROOT)/External/tree-sitter";
dependencies = (
);
name = runtime;
passBuildSettingsInEnvironment = 1;
productName = "tree-sitter";
};
/* End PBXLegacyTarget section */
/* Begin PBXNativeTarget section */
D4AAE4FC1B5AE22E004E581F /* Doubt */ = {
isa = PBXNativeTarget;
buildConfigurationList = D4AAE5171B5AE22E004E581F /* Build configuration list for PBXNativeTarget "Doubt" */;
buildPhases = (
D4AAE4F81B5AE22E004E581F /* Sources */,
D4AAE4F91B5AE22E004E581F /* Frameworks */,
D4AAE4FA1B5AE22E004E581F /* Headers */,
D4AAE4FB1B5AE22E004E581F /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = Doubt;
productName = Doubt;
productReference = D4AAE4FD1B5AE22E004E581F /* Doubt.framework */;
productType = "com.apple.product-type.framework";
};
D4AAE50C1B5AE22E004E581F /* DoubtTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = D4AAE51A1B5AE22E004E581F /* Build configuration list for PBXNativeTarget "DoubtTests" */;
buildPhases = (
D4AAE5091B5AE22E004E581F /* Sources */,
D4AAE50A1B5AE22E004E581F /* Frameworks */,
D4AAE50B1B5AE22E004E581F /* Resources */,
);
buildRules = (
);
dependencies = (
D4AAE5101B5AE22E004E581F /* PBXTargetDependency */,
);
name = DoubtTests;
productName = DoubtTests;
productReference = D4AAE50D1B5AE22E004E581F /* DoubtTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
D4FB2CC81BDEBC6300B3CCE0 /* doubt-difftool */ = {
isa = PBXNativeTarget;
buildConfigurationList = D4FB2CD31BDEBC6300B3CCE0 /* Build configuration list for PBXNativeTarget "doubt-difftool" */;
buildPhases = (
D4FB2CC51BDEBC6300B3CCE0 /* Sources */,
D4FB2CC61BDEBC6300B3CCE0 /* Frameworks */,
);
buildRules = (
);
dependencies = (
D4FB2CE41BDEBD4200B3CCE0 /* PBXTargetDependency */,
);
name = "doubt-difftool";
productName = "doubt-difftool";
productReference = D4FB2CC91BDEBC6300B3CCE0 /* doubt-difftool.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
D4AAE4F41B5AE22E004E581F /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0710;
LastUpgradeCheck = 0710;
ORGANIZATIONNAME = GitHub;
TargetAttributes = {
D485A7841BDEB6C5003A17B6 = {
CreatedOnToolsVersion = 7.1;
};
D4AAE4FC1B5AE22E004E581F = {
CreatedOnToolsVersion = 7.0;
};
D4AAE50C1B5AE22E004E581F = {
CreatedOnToolsVersion = 7.0;
};
D4FB2CC81BDEBC6300B3CCE0 = {
CreatedOnToolsVersion = 7.1;
};
};
};
buildConfigurationList = D4AAE4F71B5AE22E004E581F /* Build configuration list for PBXProject "Doubt" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = D4AAE4F31B5AE22E004E581F;
productRefGroup = D4AAE4FE1B5AE22E004E581F /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
D4AAE4FC1B5AE22E004E581F /* Doubt */,
D4AAE50C1B5AE22E004E581F /* DoubtTests */,
D4FB2CC81BDEBC6300B3CCE0 /* doubt-difftool */,
D485A7841BDEB6C5003A17B6 /* runtime */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
D4AAE4FB1B5AE22E004E581F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
D4AAE50B1B5AE22E004E581F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
D4AAE4F81B5AE22E004E581F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D40D72561BCFF360001B7A9E /* Interpreter.swift in Sources */,
D4AAE5471B5AE2D0004E581F /* Optional.swift in Sources */,
D46452D81BEA731800D7D26E /* Location.swift in Sources */,
D4413FEF1BB06D4C00E3C3C1 /* Dictionary.swift in Sources */,
D42F097E1BCEAEDA00B95610 /* Operation.swift in Sources */,
D45A36C91BBC667D00BE3DDE /* Categorizable.swift in Sources */,
D4DF96ED1BC46B630040F41F /* SES.swift in Sources */,
D1F5FE221BDE9CC10048BAE4 /* JSONParser.swift in Sources */,
D42F09801BCECB7900B95610 /* TermType.swift in Sources */,
D4AAE5401B5AE2D0004E581F /* RangeReplaceableCollectionType.swift in Sources */,
D49FCBC41BBEF98E00C5E9C3 /* Free.swift in Sources */,
D42F097C1BCE914A00B95610 /* Cofree.swift in Sources */,
D4AAE54A1B5AE2D0004E581F /* Syntax.swift in Sources */,
D49FCBC61BBF214300C5E9C3 /* Patch.swift in Sources */,
D49FCBC81BBF2C4300C5E9C3 /* Algorithm.swift in Sources */,
D4DF970C1BC5DF9E0040F41F /* BoundsCheckedArray.swift in Sources */,
D40B89C41BC319070078E098 /* Matrix.swift in Sources */,
D4AAE5491B5AE2D0004E581F /* StringLiteralConvertible.swift in Sources */,
D4413FF11BB08FDC00E3C3C1 /* JSON.swift in Sources */,
D1F5FE211BDE9C450048BAE4 /* JSONLeaf.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D4AAE5091B5AE22E004E581F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D40D72641BD1A0C1001B7A9E /* RangedDiff.swift in Sources */,
D40D725E1BD1826C001B7A9E /* TermTests.swift in Sources */,
D1F5FE201BDE891F0048BAE4 /* JSONParserTests.swift in Sources */,
D40D72601BD19E69001B7A9E /* DiffTests.swift in Sources */,
D432D4711BA9AC0B00F3FABC /* SESTests.swift in Sources */,
D40D72621BD1A07E001B7A9E /* UnannotatedTerm.swift in Sources */,
D40D72541BCEEB1F001B7A9E /* InterpreterTests.swift in Sources */,
D464530C1BEBB1F900D7D26E /* LocationTests.swift in Sources */,
D40D725C1BD15417001B7A9E /* RangedTerm.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D4FB2CC51BDEBC6300B3CCE0 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D46452C71BE7C6C800D7D26E /* Argument.swift in Sources */,
D4FB2CF81BE1560400B3CCE0 /* TSNode.swift in Sources */,
D4FB2CFA1BE28F6D00B3CCE0 /* parser.c in Sources */,
D4FB2CFC1BE292BB00B3CCE0 /* parser.c in Sources */,
D4FB2D021BE2943A00B3CCE0 /* Info.swift in Sources */,
D46452C91BE7EB2500D7D26E /* Unified.swift in Sources */,
D4FB2CDC1BDEBCCD00B3CCE0 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
D4AAE5101B5AE22E004E581F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D4AAE4FC1B5AE22E004E581F /* Doubt */;
targetProxy = D4AAE50F1B5AE22E004E581F /* PBXContainerItemProxy */;
};
D4FB2CE41BDEBD4200B3CCE0 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D485A7841BDEB6C5003A17B6 /* runtime */;
targetProxy = D4FB2CE31BDEBD4200B3CCE0 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
D485A7851BDEB6C5003A17B6 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEBUGGING_SYMBOLS = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
D485A7861BDEB6C5003A17B6 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
D4AAE5151B5AE22E004E581F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
D4AAE5161B5AE22E004E581F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
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 = "";
};
name = Release;
};
D4AAE5181B5AE22E004E581F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = Doubt/Info.plist;
INSTALL_PATH = "@rpath";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MODULEMAP_FILE = Doubt/Doubt.modulemap;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
D4AAE5191B5AE22E004E581F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = Doubt/Info.plist;
INSTALL_PATH = "@rpath";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MODULEMAP_FILE = Doubt/Doubt.modulemap;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Release;
};
D4AAE51B1B5AE22E004E581F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
INFOPLIST_FILE = DoubtTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.github.DoubtTests;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
D4AAE51C1B5AE22E004E581F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
INFOPLIST_FILE = DoubtTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.github.DoubtTests;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
D4FB2CD41BDEBC6300B3CCE0 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
HEADER_SEARCH_PATHS = "$(SRCROOT)/External/tree-sitter/include/";
INFOPLIST_FILE = "doubt-difftool/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/External/tree-sitter/out/Release",
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.doubt-difftool";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "doubt-difftool/doubt-difftool-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
D4FB2CD51BDEBC6300B3CCE0 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
HEADER_SEARCH_PATHS = "$(SRCROOT)/External/tree-sitter/include/";
INFOPLIST_FILE = "doubt-difftool/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/External/tree-sitter/out/Release",
);
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.doubt-difftool";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "doubt-difftool/doubt-difftool-Bridging-Header.h";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
D485A7871BDEB6C5003A17B6 /* Build configuration list for PBXLegacyTarget "runtime" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D485A7851BDEB6C5003A17B6 /* Debug */,
D485A7861BDEB6C5003A17B6 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D4AAE4F71B5AE22E004E581F /* Build configuration list for PBXProject "Doubt" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D4AAE5151B5AE22E004E581F /* Debug */,
D4AAE5161B5AE22E004E581F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D4AAE5171B5AE22E004E581F /* Build configuration list for PBXNativeTarget "Doubt" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D4AAE5181B5AE22E004E581F /* Debug */,
D4AAE5191B5AE22E004E581F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D4AAE51A1B5AE22E004E581F /* Build configuration list for PBXNativeTarget "DoubtTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D4AAE51B1B5AE22E004E581F /* Debug */,
D4AAE51C1B5AE22E004E581F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D4FB2CD31BDEBC6300B3CCE0 /* Build configuration list for PBXNativeTarget "doubt-difftool" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D4FB2CD41BDEBC6300B3CCE0 /* Debug */,
D4FB2CD51BDEBC6300B3CCE0 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = D4AAE4F41B5AE22E004E581F /* Project object */;
}

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:Doubt.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,99 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D4AAE4FC1B5AE22E004E581F"
BuildableName = "Doubt.framework"
BlueprintName = "Doubt"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D4AAE50C1B5AE22E004E581F"
BuildableName = "DoubtTests.xctest"
BlueprintName = "DoubtTests"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D4AAE4FC1B5AE22E004E581F"
BuildableName = "Doubt.framework"
BlueprintName = "Doubt"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D4AAE4FC1B5AE22E004E581F"
BuildableName = "Doubt.framework"
BlueprintName = "Doubt"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D4AAE4FC1B5AE22E004E581F"
BuildableName = "Doubt.framework"
BlueprintName = "Doubt"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,105 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D4FB2CC81BDEBC6300B3CCE0"
BuildableName = "doubt-difftool.app"
BlueprintName = "doubt-difftool"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D4FB2CC81BDEBC6300B3CCE0"
BuildableName = "doubt-difftool.app"
BlueprintName = "doubt-difftool"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "NO"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D4FB2CC81BDEBC6300B3CCE0"
BuildableName = "doubt-difftool.app"
BlueprintName = "doubt-difftool"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "--unified"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "https://raw.githubusercontent.com/jquery/jquery/2.1.0/src/effects.js"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "https://raw.githubusercontent.com/jquery/jquery/2.1.4/src/effects.js"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "NO">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D4FB2CC81BDEBC6300B3CCE0"
BuildableName = "doubt-difftool.app"
BlueprintName = "doubt-difftool"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,80 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D485A7841BDEB6C5003A17B6"
BuildableName = "runtime"
BlueprintName = "runtime"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D485A7841BDEB6C5003A17B6"
BuildableName = "runtime"
BlueprintName = "runtime"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D485A7841BDEB6C5003A17B6"
BuildableName = "runtime"
BlueprintName = "runtime"
ReferencedContainer = "container:Doubt.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Doubt.xcodeproj">
</FileRef>
<FileRef
location = "group:External/Madness/Madness.xcodeproj">
</FileRef>
<FileRef
location = "group:External/Assertions/Assertions.xcodeproj">
</FileRef>
<FileRef
location = "group:External/SwiftCheck/SwiftCheck.xcodeproj">
</FileRef>
<FileRef
location = "group:External/Stream/Stream.xcodeproj">
</FileRef>
<FileRef
location = "group:External/Stream/Carthage/Checkouts/Memo/Memo.xcodeproj">
</FileRef>
<FileRef
location = "group:External/Stream/Carthage/Checkouts/Either/Either.xcodeproj">
</FileRef>
<FileRef
location = "group:External/Stream/Carthage/Checkouts/Prelude/Prelude.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,23 +0,0 @@
/// The free monad over `Operation`, implementing the language of diffing.
///
/// As with `Free`, this is free in the sense of unconstrained, i.e. the monad induced by `Operation` without extra assumptions.
///
/// Where `Operation` models a single diffing strategy, `Algorithm` models the recursive selection of diffing strategies at each node. Thus, a value in `Algorithm` models an algorithm for constructing a value in the type `Result` from the resulting diffs. By this means, diffing can be adapted not just to the specific grammar, but to specific trees produced by that grammar, and even the values of type `A` encapsulated at each node.
public enum Algorithm<Term: CofreeType, Result> {
/// 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<Term.Leaf, (Term.Annotation, Term.Annotation), Patch>
/// The injection of a value of type `Result` into an `Operation`.
///
/// Equally, a way to return a result or throw an error during computation, as determined by the type which `Result` is instantiated to, and the specific context in which it is being evaluated.
case Pure(Result)
/// A recursive instantiation of `Operation`, unrolling another iteration of the recursive type.
indirect case Roll(Operation<Algorithm, Term, Diff>)
}
import Prelude

View File

@ -1,16 +0,0 @@
public struct BoundsCheckedArray<Element>: CollectionType {
public init(array: [Element]) {
self.array = array
}
let array: [Element]
public let startIndex = 0
public var endIndex: Int {
return array.count
}
public subscript (i: Int) -> Element? {
return i < count ? array[i] : nil
}
}

View File

@ -1,6 +0,0 @@
/// A type whose values belong to a set of categories.
public protocol Categorizable {
typealias Category: Hashable
var categories: Set<Category> { get }
}

View File

@ -1,227 +0,0 @@
/// The cofree comonad over `Syntax`.
///
/// This is free in the sense of unconstrained rather than zero-cost; its the comonad obtained by taking a functor (in this case `Syntax`) and adding the minimum necessary details (the `Annotation` paired with it) to satisfy the comonad laws.
///
/// This type is dual to `Free`. Where `Free` is inhabited by syntax trees where some terms are replaced with `Annotation`s, `Cofree` is inhabited by syntax trees where all terms are annotated with `Annotation`s. In Doubt, this allows us to e.g. annotate terms with source range information, categorization, etc.
public enum Cofree<Leaf, Annotation> {
indirect case Unroll(Annotation, Syntax<Cofree, Leaf>)
public var unwrap: Syntax<Cofree, Leaf> {
switch self {
case let .Unroll(_, rest):
return rest
}
}
public init(_ annotation: Annotation, _ syntax: Syntax<Cofree, Leaf>) {
self = .Unroll(annotation, syntax)
}
}
// MARK: - CustomDebugStringConvertible
extension Cofree: CustomDebugStringConvertible {
public var debugDescription: String {
return "(\(String(reflecting: extract)), \(String(reflecting: unwrap)))"
}
}
// MARK: - Functor
extension Cofree {
public func map<Other>(@noescape transform: Annotation throws -> Other) rethrows -> Cofree<Leaf, Other> {
return try .Unroll(transform(extract), unwrap.map { try $0.map(transform) })
}
}
// MARK: - Comonad
extension Cofree {
/// Returns the value annotating the syntax tree at this node.
public var extract: Annotation {
switch self {
case let .Unroll(b, _):
return b
}
}
/// Returns a new `Cofree` by recursively applying `transform` to each node, producing the annotations for the copy.
public func extend<Other>(transform: Cofree -> Other) -> Cofree<Leaf, Other> {
return .Unroll(transform(self), unwrap.map { $0.extend(transform) })
}
/// Returns a new `Cofree` constructed by recursively annotating each subtree with itself.
public var duplicate: Cofree<Leaf, Cofree<Leaf, Annotation>> {
return extend(id)
}
}
// MARK: - Equality
extension Cofree {
public static func equals(annotation annotation: (Annotation, Annotation) -> Bool, leaf: (Leaf, Leaf) -> Bool)(_ left: Cofree, _ right: Cofree) -> Bool {
switch (left, right) {
case let (.Unroll(a, s), .Unroll(b, t)):
return annotation(a, b) && Syntax.equals(leaf: leaf, recur: Cofree.equals(annotation: annotation, leaf: leaf))(s, t)
}
}
}
public func == <Leaf: Equatable, Annotation: Equatable> (left: Cofree<Leaf, Annotation>, right: Cofree<Leaf, Annotation>) -> Bool {
return Cofree.equals(annotation: ==, leaf: ==)(left, right)
}
// MARK: - JSON
extension Cofree {
public func JSON(annotation annotation: Annotation -> Doubt.JSON, leaf: Leaf -> Doubt.JSON) -> Doubt.JSON {
return [
"extract": annotation(extract),
"unwrap": unwrap.JSON(leaf: leaf, recur: { $0.JSON(annotation: annotation, leaf: leaf) })
]
}
}
extension Cofree where Leaf: CustomJSONConvertible, Annotation: CustomJSONConvertible {
public var JSON: Doubt.JSON {
return JSON(annotation: { $0.JSON }, leaf: { $0.JSON })
}
}
// MARK: - Categorizable
extension Cofree where Annotation: Categorizable {
var categories: Set<Annotation.Category> {
return extract.categories
}
}
// MARK: - CofreeType
public protocol CofreeType: TermType {
typealias Annotation
init(_ annotation: Annotation, _ syntax: Syntax<Self, Leaf>)
var extract: Annotation { get }
}
extension CofreeType {
public static func Introduce(annotation: Annotation)(syntax: Syntax<Self, Leaf>) -> Self {
return Self(annotation, syntax)
}
public static func eliminate(term: Self) -> (Annotation, Syntax<Self, Leaf>) {
return (term.extract, term.unwrap)
}
/// 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<Result>(transform: (Annotation, Syntax<Result, Leaf>) throws -> Result) rethrows -> Result {
return try transform(extract, unwrap.map { try $0.cata(transform) })
}
/// Constructs a cofree by coiteration.
///
/// This is an _anamorphism_ (from the Greek ana, upwards; compare anabolism), a generalization of unfolds over regular trees (and datatypes isomorphic to them). The initial seed is used as the annotation of the returned value. The continuation of the structure is unpacked by applying `annotate` to the seed and mapping the resulting syntaxs values recursively. In this manner, the structure is unfolded bottom-up, starting with `seed` and ending at the leaves.
///
/// As this is the dual of `cata`, its unsurprising that we have a similar guarantee: coiteration is linear in the size of the constructed tree.
public static func ana(@noescape unfold: Annotation throws -> Syntax<Annotation, Leaf>)(_ seed: Annotation) rethrows -> Self {
return try Self(seed, unfold(seed).map { try ana(unfold)($0) })
}
/// `Zip` two `CofreeType` values into a single `Cofree`, pairing their annotations.
///
/// This is partial, returning `nil` for any pair of values which are not of the same shape, i.e. where they wrap `Syntax` values of different constructors. The values of leaves are always taken from the second parameter.
public static func zip(a: Self, _ b: Self) -> Cofree<Leaf, (Annotation, Annotation)>? {
let annotations = (a.extract, b.extract)
switch (a.unwrap, b.unwrap) {
case let (.Leaf, .Leaf(b)):
return Cofree(annotations, .Leaf(b))
case let (.Indexed(a), .Indexed(b)):
return Cofree(annotations, .Indexed(Swift.zip(a, b).flatMap(zip)))
case let (.Fixed(a), .Fixed(b)):
return Cofree(annotations, .Fixed(Swift.zip(a, b).flatMap(zip)))
case let (.Keyed(a), .Keyed(b)):
return Cofree(annotations, .Keyed(Dictionary(elements: b.keys.flatMap { key in zip(a[key]!, b[key]!).map { (key, $0) } })))
default:
return nil
}
}
}
extension Cofree: CofreeType {}
extension CofreeType where Self.Annotation == Range<String.Index> {
public func JSON(source: String) -> Doubt.JSON {
return unwrap.JSON(
leaf: { _ in .String(source[extract]) },
recur: {
[
"range": [
"offset": .Number(Double(source.startIndex.distanceTo($0.extract.startIndex))),
"length": .Number(Double($0.extract.count)),
],
"unwrap": $0.JSON(source)
]
})
}
}
// MARK: - Weaving
extension Cofree {
public func explore() -> Location<Cofree> {
func weave(cofree: Cofree) -> Location<Cofree>.Unweave {
switch cofree {
case .Unroll(_, .Leaf):
return Location.nullary
case let .Unroll(annotation, .Indexed(i)):
return Location.variadic(i, weave, { Cofree(annotation, .Indexed($0)) })
case let .Unroll(annotation, .Fixed(f)):
return Location.variadic(f, weave, { Cofree(annotation, .Fixed($0)) })
case let .Unroll(annotation, .Keyed(k)):
return Location.variadic(k, weave, { Cofree(annotation, .Keyed($0)) })
}
}
return Location.explore(weave)(self)
}
}
// MARK: - Size
extension Cofree {
/// The count of nodes in the receiver.
///
/// This is used to compute the cost of patches, such that a patch inserting a very large tree will be charged approximately the same as a very large tree consisting of many small patches.
public static func size(term: Cofree) -> Int {
switch term {
case .Unroll(_, .Leaf):
return 1
case let .Unroll(_, .Indexed(a)):
return a.reduce(0) { $0 + size($1) }
case let .Unroll(_, .Fixed(a)):
return a.reduce(0) { $0 + size($1) }
case let .Unroll(_, .Keyed(a)):
return a.reduce(0) { $0 + size($1.1) }
}
}
}
import Prelude

View File

@ -1,8 +0,0 @@
extension Dictionary {
public init<C: CollectionType where C.Generator.Element == (Key, Value)>(elements: C) {
self.init(minimumCapacity: Int(elements.count.toIntMax()))
for (key, value) in elements {
self[key] = value
}
}
}

View File

@ -1,3 +0,0 @@
framework module Doubt {
export *
}

View File

@ -1,262 +0,0 @@
/// The free monad over `Syntax`.
///
/// This is free in the sense of unconstrained rather than zero-cost; its the monad obtained by taking a functor (in this case `Syntax`) and adding the minimum necessary details (the `Pure` case) to satisfy the monad laws.
///
/// `Syntax` is a non-recursive type parameterized by the type of its child nodes. Instantiating it to `Free` makes it recursive through the `Roll` case, and allows it to wrap values of type `Value` through the `Pure` case.
///
/// In Doubt, this allows us to represent diffs as values of the `Free` monad obtained from `Syntax`, injecting `Patch` into the tree; or otherwise put, a diff is a tree of mutually-recursive `Free.Roll`/`Syntax` nodes with `Pure` nodes injecting the actual changes.
public enum Free<Leaf, Annotation, Value>: CustomDebugStringConvertible {
/// The injection of a value of type `Value` into the `Syntax` tree.
case Pure(Value)
/// A recursive instantiation of `Syntax`, unrolling another iteration of the recursive type.
indirect case Roll(Annotation, Syntax<Free, Leaf>)
/// Construct a `Free` from a `CofreeType` with matching `Leaf` and `Annotation` types, copying the recursive structure of the term in via hylomorphism.
///
/// The resulting `Free` value will not have any `Pure` cases.
public init<Term: CofreeType where Term.Leaf == Leaf, Term.Annotation == Annotation>(_ term: Term) {
self = hylo(Free.Roll, Term.eliminate)(term)
}
/// Reduce the receiver by iteration.
///
/// `Pure` values are simply unpacked. `Roll` values are mapped recursively, and then have `transform` applied to them.
///
/// This forms a _catamorphism_ (from the Greek cata, downwards; compare catastrophe), a generalization of folds over regular trees (and datatypes isomorphic to them). It operates at the leaves first, and then branches near the periphery, recursively collapsing values by whatever is computed by `transform`. Catamorphisms are themselves an example of _recursion schemes_, which characterize specific well-behaved patterns of recursion. This gives `cata` some useful properties for computations performed over trees.
///
/// Due to the character of recursion captured by catamorphisms, `cata` ensures that computation will not only halt, but will further be linear in the size of the receiver. (Nesting a call to `cata` will therefore result in O(n²) complexity.) This guarantee is achieved by careful composition of calls to `map` with recursive calls to `cata`, only calling `transform` once the recursive call has completed. `transform` is itself non-recursive, receiving a `Syntax` whose recurrences have already been flattened to `Value`.
///
/// The linearity of `cata` in the size of the receiver makes it trivial to compute said size, by counting leaves as 1 and summing branches children:
///
/// func size<Leaf, Annotation, Value>(free: Free<Leaf, Annotation, Value>) -> Int {
/// return free.cata { flattenedSyntax in
/// switch flattenedSyntax {
/// case .Leaf:
/// return 1
/// case let .Indexed(children):
/// return children.reduce(0, combine: +)
/// case let .Keyed(children):
/// return children.lazy.map { $1 }.reduce(0, combine: +)
/// }
/// }
/// }
///
/// While not every function on a given `Free` can be computed using `cata`, these guarantees of termination and complexity, as well as the brevity and focus on the operation being performed n times, make it a desirable scaffolding for any function which can.
///
/// 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<Value, Leaf>) throws -> Value) rethrows -> Value {
switch self {
case let .Pure(a):
return a
case let .Roll(annotation, syntax):
return try transform(annotation, syntax.map { try $0.cata(transform) })
}
}
/// Returns a function which sums `Free`s by first `transform`ing `Pure` values into integers, and then summing these.
public static func sum(transform: Value -> Int) -> Free -> Int {
func sum(free: Free) -> Int {
switch free {
case let .Pure(a):
return transform(a)
case .Roll(_, .Leaf):
return 0
case let .Roll(_, .Indexed(a)):
return a.reduce(0) { into, each in into + sum(each) }
case let .Roll(_, .Fixed(a)):
return a.reduce(0) { into, each in into + sum(each) }
case let .Roll(_, .Keyed(a)):
return a.reduce(0) { into, each in into + sum(each.1) }
}
}
return sum
}
// MARK: Functor
public func map<C>(@noescape transform: Value throws -> C) rethrows -> Free<Leaf, Annotation, C> {
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) })
}
}
// MARK: CustomDebugStringConvertible
public var debugDescription: String {
switch self {
case let .Pure(b):
return ".Pure(\(String(reflecting: b)))"
case let .Roll(s):
return ".Roll(\(String(reflecting: s)))"
}
}
}
// MARK: - Monad
extension Free {
public func flatMap<Other>(@noescape transform: Value throws -> Free<Leaf, Annotation, Other>) rethrows -> Free<Leaf, Annotation, Other> {
switch self {
case let .Pure(a):
return try transform(a)
case let .Roll(annotation, rest):
return try .Roll(annotation, rest.map { try $0.flatMap(transform) })
}
}
}
// MARK: - Anamorphism
extension Free {
public static func Introduce(annotation: Annotation)(syntax: Syntax<Free, Leaf>) -> Free {
return Roll(annotation, syntax)
}
/// Anamorphism over `Free`.
///
/// Unfolds a tree bottom-up by recursively applying `transform` to a series of values starting with `seed`. Since `Syntax.Leaf` does not recur, this will halt when it has produced leaves for every branch.
public static func ana(@noescape unfold: Annotation throws -> Syntax<Annotation, Leaf>)(_ seed: Annotation) rethrows -> Free {
return try Roll(seed, unfold(seed).map { try ana(unfold)($0) })
}
}
extension Free where Value: PatchType, Value.Element == Cofree<Leaf, ()> {
public typealias Term = Value.Element
public func merge(@noescape transform: Value -> Term) -> Term {
return map(transform).cata { Cofree((), $1) }
}
public func merge(@noescape transform: Value -> Term?) -> Term? {
return map(transform).cata { Free.discardNullTerms($1) }
}
private static func discardNullTerms(syntax: Syntax<Term?, Leaf>) -> Term? {
switch syntax {
case let .Leaf(a):
return Cofree((), .Leaf(a))
case let .Indexed(a):
return Cofree((), .Indexed(a.flatMap(id)))
case let .Fixed(a):
return Cofree((), .Fixed(a.flatMap(id)))
case let .Keyed(a):
return Cofree((), .Keyed(Dictionary(elements: a.flatMap { k, v in v.map { (k, $0) } })))
}
}
public var before: Term? {
return merge { $0.state.before }
}
public var after: Term? {
return merge { $0.state.after }
}
}
// MARK: - Patch construction
extension Free where Value: PatchType {
public static func Replace(before: Value.Element, _ after: Value.Element) -> Free {
return .Pure(Value(replacing: before, with: after))
}
public static func Insert(after: Value.Element) -> Free {
return .Pure(Value(inserting: after))
}
public static func Delete(before: Value.Element) -> Free {
return .Pure(Value(deleting: before))
}
public var inverse: Free {
return map { $0.inverse }
}
}
// MARK: - Equality
extension Free {
public static func equals(pure pure: (Value, Value) -> Bool, leaf: (Leaf, Leaf) -> Bool, annotation: (Annotation, Annotation) -> Bool)(_ left: Free, _ right: Free) -> Bool {
switch (left, right) {
case let (.Pure(a), .Pure(b)):
return pure(a, b)
case let (.Roll(annotation1, syntax1), .Roll(annotation2, syntax2)):
return annotation(annotation1, annotation2) && Syntax.equals(leaf: leaf, recur: equals(pure: pure, leaf: leaf, annotation: annotation))(syntax1, syntax2)
default:
return false
}
}
}
public func == <Leaf: Equatable, Value: Equatable, Annotation: Equatable> (left: Free<Leaf, Annotation, Value>, right: Free<Leaf, Annotation, Value>) -> Bool {
return Free.equals(pure: ==, leaf: ==, annotation: ==)(left, right)
}
public func == <Term: CofreeType, Annotation: Equatable where Term.Leaf: Equatable> (left: Free<Term.Leaf, Annotation, Patch<Term>>, right: Free<Term.Leaf, Annotation, Patch<Term>>) -> Bool {
return Free.equals(pure: Patch.equals(Term.equals(==)), leaf: ==, annotation: ==)(left, right)
}
public func == <Term: CofreeType, Annotation where Term.Leaf: Equatable> (left: Free<Term.Leaf, Annotation, Patch<Term>>, right: Free<Term.Leaf, Annotation, Patch<Term>>) -> Bool {
return Free.equals(pure: Patch.equals(Term.equals(==)), leaf: ==, annotation: const(true))(left, right)
}
// MARK: - JSON
extension Free {
public func JSON(pure pure: Value -> Doubt.JSON, leaf: Leaf -> Doubt.JSON, annotation: Annotation -> Doubt.JSON) -> Doubt.JSON {
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) })
]
]
}
}
}
// MARK: - Weaving
extension Free {
public func explore() -> Location<Free> {
func weave(free: Free) -> Location<Free>.Unweave {
switch free {
case .Pure, .Roll(_, .Leaf):
return Location.nullary
case let .Roll(annotation, .Indexed(i)):
return Location.variadic(i, weave, { Free.Roll(annotation, .Indexed($0)) })
case let .Roll(annotation, .Fixed(f)):
return Location.variadic(f, weave, { Free.Roll(annotation, .Fixed($0)) })
case let .Roll(annotation, .Keyed(k)):
return Location.variadic(k, weave, { Free.Roll(annotation, .Keyed($0)) })
}
}
return Location.explore(weave)(self)
}
}
import Prelude

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.0.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 GitHub. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -1,115 +0,0 @@
/// An interpreter of `Algorithm`s.
public struct Interpreter<Term: CofreeType> {
/// The type of diffs constructed by `Interpreter`s.
public typealias Diff = Free<Term.Leaf, (Term.Annotation, Term.Annotation), Patch<Term>>
/// Constructs an `Interpreter` parameterized by the `equal` and `comparable` tests on `Term`s, and the `cost` function for `Diff`s.
///
/// `equal` determines whether two terms are equal. This should typically be strict syntactic equality, not e.g. including any annotations of source ranges. If two terms are considered equal by this function, then an unchanged diff will be returned directly. No diffing will be performed, and `comparable` will not be applied to the terms at all.
///
/// `comparable` determines whether two terms should be considered comparable when encountered at some point within the tree. When diffing two `.Indexed` terms, this will cause diffing to delete one term and insert the other rather than recurring through the pair (possibly constructing a single replacement). This has far-reaching implications for performance, as it enables the caller to dramatically prune the search space.
///
/// `cost` computes the cost of a single diff. This is used when computing the diff of `.Indexed` terms: the algorithm selects the lowest-total-cost sequence of diffs which completely cover the arrays. This computation is performed a minimum of 2mn and a maximum of 3mn times, where m is the length of the first array and n is the length of the second. Therefore, it should be as efficient as possible, ideally no more than linear in the size of the diff.
public init(equal: (Term, Term) -> Bool, comparable: (Term, Term) -> Bool, cost: Diff -> Int) {
self.equal = equal
self.comparable = comparable
self.cost = cost
}
/// Computes a term comparable function from a categorizing function.
public static func comparable<C>(categorize: Term -> Set<C>)(_ a: Term, _ b: Term) -> Bool {
let c0 = categorize(a)
let c1 = categorize(b)
return c0 == c1 || !categorize(a).intersect(categorize(b)).isEmpty
}
/// Run the interpreter over a given pair of `Term`s, producing a `Diff` as its result.
public func run(a: Term, _ b: Term) -> Diff {
return recur(a, b) ?? .Replace(a, b)
}
private let equal: (Term, Term) -> Bool
private let comparable: (Term, Term) -> Bool
private let cost: Diff -> Int
/// Diff `a` against `b`, if comparable.
private func recur(a: Term, _ b: Term) -> Diff? {
// If both terms are equal, we dont need to bother diffing.
//
// In that case, zip the two terms together (to pair their annotations), and then map the resulting `Term` (which, since the terms are equal, will be non-nil) into a `Diff`.
if equal(a, b) { return Term.zip(a, b).map(Diff.init) }
guard comparable(a, b) else { return nil }
let algorithm: Algorithm<Term, Diff>
let annotations = (a.extract, b.extract)
switch (a.unwrap, b.unwrap) {
case let (.Leaf, .Leaf(leaf)) where equal(a, b):
return .Roll(annotations, .Leaf(leaf))
case let (.Keyed(a), .Keyed(b)):
algorithm = .Roll(.ByKey(a, b, Syntax.Keyed >>> Diff.Introduce(annotations) >>> Algorithm.Pure))
case let (.Indexed(a), .Indexed(b)):
algorithm = .Roll(.ByIndex(a, b, Syntax.Indexed >>> Diff.Introduce(annotations) >>> Algorithm.Pure))
case (.Fixed(_), .Fixed(_)):
fallthrough
default:
algorithm = .Roll(.Recursive(a, b, Algorithm.Pure))
}
return recur(algorithm)
}
private func recur(algorithm: Algorithm<Term, Diff>) -> Diff? {
switch algorithm {
case let .Pure(diff):
return diff
case let .Roll(.Recursive(a, b, f)):
// Recur structurally into both terms, patching differing sub-terms. This is akin to unification, except that it computes a patched tree instead of a substitution. Its also a little like a structural zip on pairs of terms.
let annotations = (a.extract, b.extract)
switch (a.unwrap, b.unwrap) {
case let (.Indexed(a), .Indexed(b)) where a.count == b.count:
return recur(f(.Roll(annotations, .Indexed(zip(a, b).map(run)))))
case let (.Fixed(a), .Fixed(b)) where a.count == b.count:
return recur(f(.Roll(annotations, .Fixed(zip(a, b).map(run)))))
case let (.Keyed(a), .Keyed(b)) where Array(a.keys) == Array(b.keys):
return recur(f(.Roll(annotations, .Keyed(Dictionary(elements: b.keys.map { ($0, self.run(a[$0]!, b[$0]!)) })))))
default:
// This must not call `recur` directly with `a` and `b`, as that would infinite loop if actually recursive.
return recur(f(.Replace(a, b)))
}
case let .Roll(.ByKey(a, b, f)):
// Perform [set reconciliation](https://en.wikipedia.org/wiki/Data_synchronization#Unordered_data) on the keys, followed by recurring into the values of the intersecting keys.
let deleted = Set(a.keys).subtract(b.keys).map { ($0, Diff.Delete(a[$0]!)) }
let inserted = Set(b.keys).subtract(a.keys).map { ($0, Diff.Insert(b[$0]!)) }
let patched = Set(a.keys).intersect(b.keys).map { ($0, run(a[$0]!, b[$0]!)) }
return recur(f(Dictionary(elements: deleted + inserted + patched)))
case let .Roll(.ByIndex(a, b, f)):
return recur(f(SES(a, b, cost: cost, recur: recur)))
}
}
}
// MARK: - Constrained constructors
extension Interpreter where Term.Leaf: Equatable {
public init(comparable: (Term, Term) -> Bool, cost: Diff -> Int) {
self.init(equal: Term.equals(==), comparable: comparable, cost: cost)
}
}
extension Interpreter where Term: CofreeType, Term.Annotation: Categorizable {
public init(equal: (Term, Term) -> Bool, cost: Diff -> Int) {
self.init(equal: equal, comparable: Interpreter.comparable { $0.extract.categories }, cost: cost)
}
}
import Prelude

View File

@ -1,216 +0,0 @@
public enum JSON: ArrayLiteralConvertible, BooleanLiteralConvertible, DictionaryLiteralConvertible, Equatable, FloatLiteralConvertible, IntegerLiteralConvertible, JSONConvertible, NilLiteralConvertible, StringLiteralConvertible {
public typealias ArrayType = [Doubt.JSON]
public typealias DictionaryType = [Swift.String:Doubt.JSON]
case Number(Double)
case Boolean(Bool)
case String(Swift.String)
case Array(ArrayType)
case Dictionary(DictionaryType)
case Null
public init(_ convertible: CustomJSONConvertible) {
self = convertible.JSON
}
public var number: Double? {
if case let .Number(d) = self { return d }
return nil
}
public var boolean: Bool? {
if case let .Boolean(b) = self { return b }
return nil
}
public var string: Swift.String? {
if case let .String(s) = self { return s }
return nil
}
public var array: ArrayType? {
if case let .Array(a) = self { return a }
return nil
}
public var dictionary: DictionaryType? {
if case let .Dictionary(d) = self { return d }
return nil
}
public var isNull: Bool {
if case .Null = self { return true }
return false
}
public init?(object: AnyObject) {
struct E: ErrorType {}
func die<T>() throws -> T {
throw E()
}
do {
switch object {
case let n as Double:
self = .Number(n)
case let b as Bool:
self = .Boolean(b)
case let s as Swift.String:
self = .String(s)
case let a as [AnyObject]:
self = .Array(try a.map { try Doubt.JSON(object: $0) ?? die() })
case let d as [Swift.String:AnyObject]:
self = .Dictionary(Swift.Dictionary(elements: try d.map { ($0, try Doubt.JSON(object: $1) ?? die()) }))
case is NSNull:
self = .Null
default:
return nil
}
} catch { return nil }
}
public var object: AnyObject {
switch self {
case let .Number(n):
return n
case let .Boolean(b):
return b
case let .String(s):
return s
case let .Array(a):
return a.map { $0.object }
case let .Dictionary(d):
return Swift.Dictionary(elements: d.map { ($0, $1.object) })
case .Null:
return NSNull()
}
}
public func serialize() -> NSData {
return try! NSJSONSerialization.dataWithJSONObject(object, options: [])
}
// MARK: ArrayLiteralConvertible
public init(arrayLiteral: Doubt.JSON...) {
self = .Array(arrayLiteral)
}
// MARK: BooleanLiteralConvertible
public init(booleanLiteral: Bool) {
self = .Boolean(booleanLiteral)
}
// MARK: DictionaryLiteralConvertible
public init(dictionaryLiteral: (Swift.String, Doubt.JSON)...) {
self = .Dictionary(Swift.Dictionary(elements: dictionaryLiteral))
}
// MARK: FloatLiteralConvertible
public init(floatLiteral: Double) {
self = .Number(floatLiteral)
}
// MARK: IntegerLiteralConvertible
public init(integerLiteral: Int) {
self = .Number(Double(integerLiteral))
}
// MARK: JSONConvertible
public init?(JSON: Doubt.JSON) {
self = JSON
}
public var JSON: Doubt.JSON {
return self
}
// MARK: NilLiteralConvertible
public init(nilLiteral: ()) {
self = .Null
}
// MARK: StringLiteralConvertible
public init(stringLiteral: Swift.String) {
self = .String(stringLiteral)
}
}
public func == (left: JSON, right: JSON) -> Bool {
switch (left, right) {
case let (.Number(a), .Number(b)):
return a == b
case let (.Boolean(a), .Boolean(b)):
return a == b
case let (.String(a), .String(b)):
return a == b
case let (.Array(a), .Array(b)):
return a == b
case let (.Dictionary(a), .Dictionary(b)):
return a == b
case (.Null, .Null):
return true
default:
return false
}
}
/// A type which can be converted to JSON.
public protocol CustomJSONConvertible {
var JSON: Doubt.JSON { get }
}
extension String: CustomJSONConvertible {
public var JSON: Doubt.JSON {
return .String(self)
}
}
extension Int: CustomJSONConvertible {
public var JSON: Doubt.JSON {
return .Number(Double(self))
}
}
extension Array where Element: CustomJSONConvertible {
public var JSON: Doubt.JSON {
return .Array(map { Doubt.JSON($0) })
}
}
extension Range where Element: CustomJSONConvertible, Element.Distance: CustomJSONConvertible {
public var JSON: Doubt.JSON {
return [
startIndex.JSON,
count.JSON,
]
}
}
/// A type which can be converted to and from JSON.
public protocol JSONConvertible: CustomJSONConvertible {
init?(JSON: Doubt.JSON)
}
import Foundation

View File

@ -1,69 +0,0 @@
public enum JSONLeaf: Categorizable, CustomJSONConvertible, CustomStringConvertible, Equatable {
case Number(Double)
case Boolean(Bool)
case String(Swift.String)
case Null
// MARK: Categorizable
public var categories: Set<Swift.String> {
switch self {
case .Number:
return [ "number" ]
case .Boolean:
return [ "boolean" ]
case .String:
return [ "string" ]
case .Null:
return [ "null" ]
}
}
// MARK: CustomJSONConvertible
public var JSON: Doubt.JSON {
switch self {
case let .Number(n):
return .Number(n)
case let .Boolean(b):
return .Boolean(b)
case let .String(s):
return .String(s)
case .Null:
return .Null
}
}
// MARK: CustomStringConvertible
public var description: Swift.String {
switch self {
case let .Number(n):
return Swift.String(n)
case let .Boolean(b):
return Swift.String(b)
case let .String(s):
return Swift.String(reflecting: s)
case .Null:
return "null"
}
}
}
public func == (left: JSONLeaf, right: JSONLeaf) -> Bool {
switch (left, right) {
case let (.Number(a), .Number(b)):
return a == b
case let (.Boolean(a), .Boolean(b)):
return a == b
case let (.String(a), .String(b)):
return a == b
case (.Null, .Null):
return true
default:
return false
}
}

View File

@ -1,86 +0,0 @@
//
// JSONParser.swift
// Doubt
//
// Created by Josh Vera on 10/16/15.
// Copyright © 2015 GitHub. All rights reserved.
//
import Foundation
import Madness
import Prelude
public typealias CofreeJSON = Cofree<JSONLeaf, (Range<Line>, Range<Column>, Range<String.Index>)>
public typealias JSONParser = Parser<String.CharacterView, CofreeJSON>.Function
// Inlined for performance reasons
let whitespace = many(oneOf(" \n\r\t"))
// TODO: Parse unicode escape sequence
let escapeChar: StringParser = curry(+) <^> %"\\" <*> ({ String($0) } <^> oneOf("\\\"bfnrt"))
let otherChar: StringParser = { String($0) } <^> noneOf("\"\\")
// Quoted strings parser
// TODO: Improve string parsing
let stringBody: StringParser = { $0.joinWithSeparator("") } <^> many(escapeChar <|> otherChar)
let quoted = %"\"" *> stringBody <* %"\""
typealias MembersParser = Parser<String.CharacterView, [(String, CofreeJSON)]>.Function;
// Parses an array of (String, CofreeJSON) object members
func members(json: JSONParser) -> MembersParser {
let keyAndKeyTerm: Parser<String.CharacterView, (String, CofreeJSON)>.Function = quoted --> { _, lines, columns, range, key in
(key, Cofree((lines, columns, range), .Leaf(.String(key))))
}
let pairs: Parser<String.CharacterView, (String, CofreeJSON)>.Function = (curry(pair) <^>
keyAndKeyTerm
<* whitespace
<* %":"
<* whitespace
<*> json) --> { _, lines, columns, range, values in
(values.0.0, Cofree((lines, columns, range), .Fixed([values.0.1, values.1])))
}
return sepBy(pairs, whitespace <* %"," <* whitespace)
}
public let json: JSONParser = fix { json in
let string: JSONParser = quoted --> {
Cofree(($1, $2, $3), .Leaf(.String($4)))
} <?> "string"
let array: JSONParser = %"["
<* whitespace
*> sepBy(whitespace *> json, whitespace <* %"," <* whitespace)
<* whitespace
<* %"]"
--> {
Cofree(($1, $2, $3), .Indexed($4))
} <?> "array"
let object: JSONParser = %"{"
*> whitespace
*> members(json)
<* whitespace
<* %"}"
--> { (_, lines, columns, range, values: [(String, CofreeJSON)]) in
Cofree((lines, columns, range), .Keyed(Dictionary(elements: values)))
} <?> "object"
let numberParser: JSONParser = (number --> { _, lines, columns, range, value in
Cofree((lines, columns, range), .Leaf(JSONLeaf.Number(value)))
}) <?> "number"
let null: JSONParser = %"null" --> { _, lines, columns, range, value in
return Cofree((lines, columns, range), .Leaf(.Null))
} <?> "null"
let boolean: JSONParser = %"false" <|> %"true" --> { _, lines, columns, range, value in
let boolean = value == "true"
return Cofree((lines, columns, range), .Leaf(.Boolean(boolean)))
} <?> "boolean"
// TODO: This should be JSON = dict <|> array and
// Value = dict | array | string | number | null | bool
return (object <|> array <|> string <|> numberParser <|> boolean <|> null) <* whitespace
}

View File

@ -1,154 +0,0 @@
/// A `Location` is a structure similar to a `Lens` which allows introspection of & update to subtrees of some tree.
///
/// In the former case, a `Location` is essentially an implementation of a [Zipper][], allowing exploration into and out of nodes, as well as to adjacent nodes.
///
/// [Hinze & Jeuring][] then extended this to support replacing the focused node. `Location` implements their approach (see §5, A Read-write Web).
///
/// This is also closely related to [McBride][]s observations about the derivative of regular types.
///
/// [Zipper]: https://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-zipper.pdf
/// [Hinze & Jeuring]: https://github.com/github/semantic-diff/files/27297/Weaving.a.Web.pdf
/// [McBride]: http://strictlypositive.org/diff.pdf
public struct Location<A>: SequenceType {
/// Construct a `Location` representing some position within a tree.
public init(it: A, into: A -> Location?, outOf: A -> Location?, left: A -> Location?, right: A -> Location?) {
self.it = it
_left = left
_right = right
_outOf = outOf
_into = into
}
/// The node currently in focus.
public let it: A
/// Returns the `Location` representing the contents of `it`, or `nil` if `it` is a leaf.
public var into: Location? { return _into(it) }
/// Returns the `Location` representing the parent of `it` in the current exploration, or `nil` if the receiver is the `root`.
public var outOf: Location? { return _outOf(it) }
/// Returns the `Location` which immediately precedes the receiver within its parent in the current exploration, or `nil` if the receiver is the `root` or the first child of its parent.
public var left: Location? { return _left(it) }
/// Returns the `Location` which immediately follows the receiver within its parent in the current exploration, or `nil` if the receiver is the `root` or the last child of its parent.
public var right: Location? { return _right(it) }
/// The root `Location` in the current exploration.
public var root: Location {
return outOf?.root ?? self
}
/// Returns the logically next `Location` after the receiver in a pre-order depth-first traversal.
public var next: Location? {
return into ?? nextAfter
}
/// Returns the logically next `Location` after the receiver and its children in a pre-order depth-first traversal.
private var nextAfter: Location? {
return right ?? outOf?.nextAfter
}
/// Return a new `Location` by replacing the current value with a new one produced by `f`.
public func modify(@noescape f: A -> A) -> Location {
return Location(it: f(it), into: _into, outOf: _outOf, left: _left, right: _right)
}
public typealias Weave = A -> Unweave
public typealias Unweave = (A -> Location?) -> Location?
// MARK: - Constructors
public static func nullary(outOf: A -> Location?) -> Location? {
return nil
}
public static func unary(t1: A, _ weave: Weave, _ reconstruct: A -> A)(_ outOf: A -> Location?) -> Location? {
return Location(flip(weave), { $0[0] } >>> reconstruct >>> outOf, [t1])
}
public static func binary(t1: A, _ t2: A, _ weave: Weave, _ reconstruct: (A, A) -> A)(_ outOf: A -> Location?) -> Location? {
return Location(flip(weave), { ($0[0], $0[1]) } >>> reconstruct >>> outOf, [t1, t2])
}
public static func ternary(t1: A, _ t2: A, _ t3: A, _ weave: Weave, _ reconstruct: (A, A, A) -> A)(_ outOf: A -> Location?) -> Location? {
return Location(flip(weave), { ($0[0], $0[1], $0[2]) } >>> reconstruct >>> outOf, [t1, t2, t3])
}
public static func variadic<C: MutableCollectionType where C.Generator.Element == A, C.Index: BidirectionalIndexType>(ts: C, _ weave: Weave, _ reconstruct: C -> A)(_ outOf: A -> Location?) -> Location? {
return Location(flip(weave), reconstruct >>> outOf, ts)
}
public static func variadic<Key>(ts: [Key:A], _ weave: Weave, _ reconstruct: [Key:A] -> A)(_ outOf: A -> Location?) -> Location? {
return Location(flip(weave), Dictionary.init >>> reconstruct >>> outOf, Array(ts))
}
public static func explore(weave: Weave)(_ a : A) -> Location {
return Location(it: a, into: flip(weave)(explore(weave) >>> Optional.Some), outOf: const(nil), left: const(nil), right: const(nil))
}
// MARK: - Implementation details
private init?<C: MutableCollectionType where C.Generator.Element == A, C.Index: BidirectionalIndexType>(_ weave: (A -> Location?) -> A -> Location?, _ outOf: C -> Location?, _ ts: C) {
func update(index: C.Index, _ ts: C)(_ f: C -> Location?)(_ a: A) -> Location? {
guard ts.indices.contains(index) else { return nil }
var copy = ts
copy[index] = a
return f(copy)
}
func into(index: C.Index)(_ ts: C) -> Location? {
guard ts.indices.contains(index) else { return nil }
return Location(it: ts[index], into: weave(update(index, ts)(into(index))), outOf: update(index, ts)(outOf), left: update(index, ts)(into(index.predecessor())), right: update(index, ts)(into(index.successor())))
}
guard let location = into(ts.startIndex)(ts) else { return nil }
self = location
}
private init?<C: MutableCollectionType, Key where C.Generator.Element == (Key, A), C.Index: BidirectionalIndexType>(_ weave: (A -> Location?) -> A -> Location?, _ outOf: C -> Location?, _ ts: C) {
func update(index: C.Index, _ ts: C)(_ f: C -> Location?)(_ key: Key)(_ a: A) -> Location? {
guard ts.indices.contains(index) else { return nil }
var copy = ts
copy[index] = (key, a)
return f(copy)
}
func into(index: C.Index)(_ ts: C) -> Location? {
guard ts.indices.contains(index) else { return nil }
let (key, value) = ts[index]
return Location(it: value, into: weave(update(index, ts)(into(index))(key)), outOf: update(index, ts)(outOf)(key), left: update(index, ts)(into(index.predecessor()))(key), right: update(index, ts)(into(index.successor()))(key))
}
guard let location = into(ts.startIndex)(ts) else { return nil }
self = location
}
private let _into: A -> Location?
private let _outOf: A -> Location?
private let _left: A -> Location?
private let _right: A -> Location?
// MARK: SequenceType
public func generate() -> AnyGenerator<Location> {
var current: Location? = self
return anyGenerator {
let next = current
current = current?.next
return next
}
}
}
// Flipping of curried functions.
private func flip<A, B, C>(f: A -> B -> C)(_ b: B)(_ a: A) -> C {
return f(a)(b)
}
import Prelude

View File

@ -1,55 +0,0 @@
/// A two-dimensional matrix of memoized values.
///
/// These values are populated by a function from the coordinates of a given cell to the matrixs element type.
///
/// Values are retrieved by subscripting with row/column indices. Out-of-bound indices produce `nil` values, rather than asserting.
public struct Matrix<A, I: ForwardIndexType> {
public init(across: Range<I>, down: Range<I>, compute: (I, I) -> A) {
self.init(across: across, down: down, values: constructRowMajor(across, down: down, forEach: { i, j in Memo { compute(i, j) } }))
}
public let across: Range<I>
public let down: Range<I>
private let width: I.Distance
private let values: [Memo<A>]
public subscript (i: I, j: I) -> Memo<A>? {
guard i != across.endIndex && j != down.endIndex else { return nil }
let i = across.startIndex.distanceTo(i)
let j = down.startIndex.distanceTo(j)
return values[Int((i + j * width).toIntMax())]
}
// MARK: Functor
public func map<Other>(transform: A -> Other) -> Matrix<Other, I> {
return Matrix<Other, I>(across: across, down: down, values: values.map { $0.map(transform) })
}
// MARK: Implementation details
private init(across: Range<I>, down: Range<I>, values: [Memo<A>]) {
self.across = across
self.down = down
self.values = values
self.width = across.count
}
}
/// Constructs a row-major ordering of values produced with `forEach`.
private func constructRowMajor<A, I: ForwardIndexType>(across: Range<I>, down: Range<I>, @noescape forEach: (I, I) -> A) -> [A] {
var values: [A] = []
values.reserveCapacity(Int(across.count.toIntMax()) * Int(down.count.toIntMax()))
for j in down {
for i in across {
values.append(forEach(i, j))
}
}
return values
}
import Memo

View File

@ -1,32 +0,0 @@
/// An operation of diffing over terms or collections of terms.
public enum Operation<Recur, Term, Diff> {
/// Indicates that diffing should compare the enclosed `Term`s.
///
/// When run, the enclosed function will be applied to the resulting `Diff`.
case Recursive(Term, Term, Diff -> Recur)
/// Represents a diff to be performed on a collection of terms identified by keys.
case ByKey([String:Term], [String:Term], [String:Diff] -> Recur)
/// Represents a diff to be performed over an array of terms by index.
case ByIndex([Term], [Term], [Diff] -> Recur)
}
// MARK: - Functor
extension Operation {
public func map<Other>(transform: Recur -> Other) -> Operation<Other, Term, Diff> {
switch self {
case let .Recursive(a, b, f):
return .Recursive(a, b, f >>> transform)
case let .ByKey(a, b, f):
return .ByKey(a, b, f >>> transform)
case let .ByIndex(a, b, f):
return .ByIndex(a, b, f >>> transform)
}
}
}
import Prelude

View File

@ -1,12 +0,0 @@
extension Optional {
static func equals(param: (Wrapped, Wrapped) -> Bool)(_ left: Wrapped?, _ right: Wrapped?) -> Bool {
switch (left, right) {
case let (.Some(a), .Some(b)):
return param(a, b)
case (.None, .None):
return true
default:
return false
}
}
}

View File

@ -1,175 +0,0 @@
/// A patch to some part of a `Syntax` tree.
public enum Patch<A>: CustomDebugStringConvertible {
case Replace(A, A)
case Insert(A)
case Delete(A)
public var state: (before: A?, after: A?) {
switch self {
case let .Replace(a, b):
return (a, b)
case let .Insert(b):
return (nil, b)
case let .Delete(a):
return (a, nil)
}
}
public var inverse: Patch {
switch self {
case let .Replace(a, b):
return .Replace(b, a)
case let .Insert(b):
return .Delete(b)
case let .Delete(a):
return .Insert(a)
}
}
// MARK: CustomDebugStringConvertible
public var debugDescription: String {
switch self {
case let .Replace(a, b):
return ".Replace(\(String(reflecting: a)), \(String(reflecting: b)))"
case let .Insert(b):
return ".Insert(\(String(reflecting: b)))"
case let .Delete(a):
return ".Delete(\(String(reflecting: a)))"
}
}
}
// MARK: - Functor
extension Patch {
public func map<B>(@noescape transform: A throws -> B) rethrows -> Patch<B> {
switch self {
case let .Replace(a, b):
return try .Replace(transform(a), transform(b))
case let .Delete(a):
return try .Delete(transform(a))
case let .Insert(b):
return try .Insert(transform(b))
}
}
}
// MARK: - Equality
extension Patch {
public static func equals(param: (A, A) -> Bool)(_ left: Patch, _ right: Patch) -> Bool {
return Optional.equals(param)(left.state.before, right.state.before)
&& Optional.equals(param)(left.state.after, right.state.after)
}
}
// MARK: - Cost calculations
extension Patch {
/// Returns a function which computes the size of a `patch` as the sum of the sizes of its terms, as computed by `size`.
public static func sum(@noescape size: A -> Int)(_ patch: Patch) -> Int {
switch patch {
case let .Replace(a, b):
return size(a) + size(b)
case let .Insert(b):
return size(b)
case let .Delete(a):
return size(a)
}
}
/// Returns a function which computes the size of a `patch` as the absolute difference of the sizes of its terms, as computed by `size`.
public static func difference(@noescape size: A -> Int)(_ patch: Patch) -> Int {
return abs((patch.state.before.map(size) ?? 0) - (patch.state.after.map(size) ?? 0))
}
}
extension Patch where A: TermType {
/// Computes the size of a `patch` as the sum of the sizes of its terms.
public static func sum(patch: Patch) -> Int {
return sum { $0.size } (patch)
}
/// Computes the size of a `patch` as the absolute difference of the sizes of its terms.
public static func difference(patch: Patch) -> Int {
return difference { $0.size } (patch)
}
}
// MARK: - JSON
extension Patch {
public func JSON(ifLeaf: A -> Doubt.JSON) -> Doubt.JSON {
switch self {
case let .Replace(a, b):
return [
"replace": [
"before": ifLeaf(a),
"after": ifLeaf(b),
]
]
case let .Insert(b):
return [
"insert": ifLeaf(b),
]
case let .Delete(a):
return [
"delete": ifLeaf(a)
]
}
}
}
extension Patch where A: CustomJSONConvertible {
public var JSON: Doubt.JSON {
return JSON { $0.JSON }
}
}
// MARK: - PatchType
/// A hack to enable constrained extensions on `Free<Leaf, Annotation, Patch<Term: CofreeType where Term.Leaf == Leaf, Term.Annotation == Annotation>`.
public protocol PatchType {
typealias Element
var state: (before: Element?, after: Element?) { get }
var inverse: Self { get }
init(replacing before: Element, with after: Element)
init(deleting before: Element)
init(inserting after: Element)
}
extension Patch: PatchType {
public init(replacing before: A, with after: A) {
self = .Replace(before, after)
}
public init(deleting before: A) {
self = .Delete(before)
}
public init(inserting after: A) {
self = .Insert(after)
}
}
extension PatchType where Element: CofreeType, Element.Annotation == Range<String.Index> {
public func JSON(a a: String, b: String) -> Doubt.JSON {
return [
"before": state.before.map { $0.JSON(a) } ?? nil,
"after": state.after.map { $0.JSON(b) } ?? nil,
]
}
}

View File

@ -1,5 +0,0 @@
extension RangeReplaceableCollectionType {
static func cons(head: Generator.Element, _ tail: Self) -> Self {
return [ head ] + tail
}
}

View File

@ -1,83 +0,0 @@
/// Computes the SES (shortest edit script), i.e. the shortest sequence of diffs (`Free<Leaf, Annotation, 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<Leaf, Annotation, C: CollectionType>(a: C, _ b: C, cost: Free<Leaf, Annotation, Patch<C.Generator.Element>> -> Int, recur: (C.Generator.Element, C.Generator.Element) -> Free<Leaf, Annotation, Patch<C.Generator.Element>>?) -> [Free<Leaf, Annotation, Patch<C.Generator.Element>>] {
typealias Diff = Free<Leaf, Annotation, Patch<C.Generator.Element>>
if a.isEmpty { return b.map { .Insert($0) } }
if b.isEmpty { return a.map { .Delete($0) } }
// A matrix whose values are streams representing paths through the edit graph, carrying both the diff & the cost of the remainder of the path.
var matrix: Matrix<Stream<(Diff, Int)>, C.Index>!
matrix = Matrix(across: a.startIndex..<a.endIndex.successor(), down: b.startIndex..<b.endIndex.successor()) { i, j in
// Some explanation is warranted:
//
// 1. `matrix` captures itself during construction, because each vertex in the edit graph depends on other vertices. This is safe, because a) `Matrix` populates its fields lazily, and b) vertices only depend on those vertices downwards and rightwards of them.
//
// 2. `matrix` is sized bigger than `a.count` x `b.count`. This is safe, because a) we only get a[i]/b[j] when right/down are non-nil (respectively), and b) right/down are found by looking up elements (i + 1, j) & (i, j + 1) in the matrix, which returns `nil` when out of bounds. So we only access a[i] and b[j] when i and j are in bounds.
let right = matrix[i.successor(), j]
let down = matrix[i, j.successor()]
let diagonal = matrix[i.successor(), j.successor()]
if let diagonal = diagonal, right = right, down = down {
let here = recur(a[i], b[j])
if let diagonalDiff = here {
let hereCost = cost(diagonalDiff)
let diagonalCost = hereCost + (diagonal.value.first?.1 ?? 0)
// If the diff at this vertex is zero-cost, were not going to find a cheaper one either rightwards or downwards. We can therefore short-circuit selecting the best outgoing edge and save ourselves evaluating the entire row rightwards and the entire column downwards from this point.
//
// Thus, in the best case (two equal sequences), we now complete in O(n + m). However, this optimization only applies to equalities at the beginning of the edit graph; once inequalities are encountered, the remainder of the diff is effectively O(nm).
guard hereCost != 0 else { return .Cons((diagonalDiff, diagonalCost), diagonal) }
let rightDiff = Diff.Delete(a[i])
let rightCost = cost(rightDiff) + (right.value.first?.1 ?? 0)
let downDiff = Diff.Insert(b[j])
let downCost = cost(downDiff) + (down.value.first?.1 ?? 0)
if rightCost < downCost && rightCost < diagonalCost {
return .Cons((rightDiff, rightCost), right)
} else if downCost < diagonalCost {
return .Cons((downDiff, downCost), down)
} else {
return .Cons((diagonalDiff, diagonalCost), diagonal)
}
} else {
let rightDiff = Diff.Delete(a[i])
let rightCost = cost(rightDiff) + (right.value.first?.1 ?? 0)
let downDiff = Diff.Insert(b[j])
let downCost = cost(downDiff) + (down.value.first?.1 ?? 0)
if rightCost < downCost {
return .Cons((rightDiff, rightCost), right)
} else {
return .Cons((downDiff, downCost), down)
}
}
}
// right extent of the edit graph; can only move down
if let down = down {
let diff = Diff.Insert(b[j])
let cost = cost(diff) + (down.value.first?.1 ?? 0)
return .Cons((diff, cost), down)
}
// bottom extent of the edit graph; can only move right
if let right = right {
let diff = Diff.Delete(a[i])
let cost = cost(diff) + (right.value.first?.1 ?? 0)
return .Cons((diff, cost), right)
}
// bottom-right corner of the edit graph
return Stream.Nil
}
return Array(matrix[a.startIndex, b.startIndex]!.value.map { diff, _ in diff })
}
import Memo
import Prelude
import Stream

View File

@ -1,9 +0,0 @@
extension StringLiteralConvertible {
public init(unicodeScalarLiteral: Self.StringLiteralType) {
self.init(stringLiteral: unicodeScalarLiteral)
}
public init(extendedGraphemeClusterLiteral: Self.StringLiteralType) {
self.init(stringLiteral: extendedGraphemeClusterLiteral)
}
}

View File

@ -1,128 +0,0 @@
/// A node in a syntax tree. Expressed algebraically to enable representation of both normal syntax trees and their diffs.
public enum Syntax<Recur, A>: CustomDebugStringConvertible {
case Leaf(A)
case Indexed([Recur])
case Fixed([Recur])
case Keyed([String:Recur])
// MARK: Functor
public func map<T>(@noescape transform: Recur throws -> T) rethrows -> Syntax<T, A> {
switch self {
case let .Leaf(n):
return .Leaf(n)
case let .Indexed(x):
return try .Indexed(x.map(transform))
case let .Fixed(x):
return try .Fixed(x.map(transform))
case let .Keyed(d):
return try .Keyed(Dictionary(elements: d.map { try ($0, transform($1)) }))
}
}
// MARK: CustomDebugStringConvertible
public var debugDescription: String {
switch self {
case let .Leaf(n):
return ".Leaf(\(n))"
case let .Indexed(x):
return ".Indexed(\(String(reflecting: x)))"
case let .Fixed(x):
return ".Fixed(\(String(reflecting: x)))"
case let .Keyed(d):
return ".Keyed(\(String(reflecting: d)))"
}
}
}
// MARK: - Hylomorphism
/// Hylomorphism through `Syntax`.
///
/// A hylomorphism (from the Aristotelian philosophy that form and matter are one) is a function of type `A B` whose call-tree is linear in the size of the nodes produced by `up`. Conceptually, its the composition of a catamorphism (see also `cata`) and an anamorphism (see also `ana`), but is implemented by [Stream fusion](http://lambda-the-ultimate.org/node/2192) and as such enjoys O(n) time complexity, O(1) size complexity, and small constant factors for both (modulo inadvisable implementations of `up` and `down`).
///
/// 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<A, B, Leaf>(down: Syntax<B, Leaf> -> B, _ up: A -> Syntax<A, Leaf>)(_ a: A) -> B {
return down(up(a).map(hylo(down, up)))
}
/// Reiteration through `Syntax`.
///
/// This is a form of hylomorphism (from the Aristotelian philosophy that form and matter are one). As such, it returns a function of type `A B` whose call-tree is linear in the size of the nodes produced by `up`. Conceptually, its the composition of a catamorphism (see also `cata`) and an anamorphism (see also `ana`), but is implemented by [Stream fusion](http://lambda-the-ultimate.org/node/2192) and as such enjoys O(n) time complexity, O(1) size complexity, and small constant factors for both (modulo inadvisable implementations of `up` and `down`).
///
/// 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 `Annotation` & `Syntax` pairs.
public func hylo<A, B, Leaf, Annotation>(down: (Annotation, Syntax<B, Leaf>) -> B, _ up: A -> (Annotation, Syntax<A, Leaf>))(_ a: A) -> B {
let (annotation, syntax) = up(a)
return down(annotation, syntax.map(hylo(down, up)))
}
// MARK: - ArrayLiteralConvertible
extension Syntax: ArrayLiteralConvertible {
public init(arrayLiteral: Recur...) {
self = .Indexed(arrayLiteral)
}
}
// MARK: - DictionaryLiteralConvertible
extension Syntax: DictionaryLiteralConvertible {
public init(dictionaryLiteral elements: (String, Recur)...) {
self = .Keyed(Dictionary(elements: elements))
}
}
// MARK: - Equality
extension Syntax {
public static func equals(leaf leaf: (A, A) -> Bool, recur: (Recur, Recur) -> Bool)(_ left: Syntax<Recur, A>, _ right: Syntax<Recur, A>) -> Bool {
switch (left, right) {
case let (.Leaf(l1), .Leaf(l2)):
return leaf(l1, l2)
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
}
}
}
public func == <F: Equatable, A: Equatable> (left: Syntax<F, A>, right: Syntax<F, A>) -> Bool {
return Syntax.equals(leaf: ==, recur: ==)(left, right)
}
// MARK: - JSON
extension Syntax {
public func JSON(@noescape leaf leaf: A -> Doubt.JSON, @noescape recur: Recur -> Doubt.JSON) -> Doubt.JSON {
switch self {
case let .Leaf(a):
return [ "leaf": leaf(a) ]
case let .Indexed(a):
return [ "indexed": .Array(a.map(recur)) ]
case let .Fixed(a):
return [ "fixed": .Array(a.map(recur)) ]
case let .Keyed(d):
return [ "keyed": .Dictionary(Dictionary(elements: d.map { ($0, recur($1)) })) ]
}
}
}
import Prelude

View File

@ -1,59 +0,0 @@
/// The type of terms.
public protocol TermType {
typealias Leaf
var unwrap: Syntax<Self, Leaf> { get }
}
extension TermType {
public static func unwrap(term: Self) -> Syntax<Self, Leaf> {
return term.unwrap
}
/// 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<Result>(transform: Syntax<Result, Leaf> 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<Result>(transform: Syntax<(Self, Result), Leaf> throws -> Result) rethrows -> Result {
return try transform(unwrap.map { try ($0, $0.para(transform)) })
}
/// The count of nodes in the receiver.
///
/// This is used to compute the cost of patches, such that a patch inserting a very large tree will be charged approximately the same as a very large tree consisting of many small patches.
public var size: Int {
func size(term: Self) -> Int {
switch term.unwrap {
case .Leaf:
return 1
case let .Indexed(a):
return a.reduce(0) { $0 + size($1) }
case let .Fixed(a):
return a.reduce(0) { $0 + size($1) }
case let .Keyed(a):
return a.reduce(0) { $0 + size($1.1) }
}
}
return size(self)
}
}
// MARK: - Equality
extension TermType {
public static func equals(leaf: (Leaf, Leaf) -> Bool)(_ a: Self, _ b: Self) -> Bool {
return Syntax.equals(leaf: leaf, recur: equals(leaf))(a.unwrap, b.unwrap)
}
}
import Prelude

View File

@ -1,66 +0,0 @@
final class DiffTests: XCTestCase {
override static func setUp() {
sranddev()
}
typealias Term = RangedTerm.Term
typealias Diff = Free<String, (Term.Annotation, Term.Annotation), Patch<Term>>
let interpreter = Interpreter<Term>(equal: ==, comparable: const(true), cost: Diff.sum(const(1)))
func testEqualTermsProduceIdentityDiffs() {
property("equal terms produce identity diffs") <- forAll { (term: RangedTerm) in
Diff.sum(const(1))(self.interpreter.run(term.term, term.term)) == 0
}
}
func testRecursivelyCopiedDiffsHaveNoPatches() {
property("recursively copying a term into a diff produces no patches") <- forAll { (term: RangedTerm) in
Free.sum(const(1))(Free<Term.Leaf, Term.Annotation, Patch<Term>>(term.term)) == 0
}
}
func testInequalTermsProduceNonIdentityDiffs() {
property("inequal terms produce non-identity diffs") <- forAll { (diff: RangedDiff) in
(!Term.equals(annotation: const(true), leaf: ==)(diff.a.term, diff.b.term)) ==> Diff.sum(const(1))(diff.diff) > 0
}
}
func testEqualityIsReflexive() {
property("equality is reflexive") <- forAll { (diff: RangedDiff) in
equal(diff.diff, diff.diff)
}
}
func testDoubleInversionIsIdempotent() {
property("double inversion is idempotent") <- forAll { (diff: RangedDiff) in
equal(diff.diff, diff.diff.inverse.inverse)
}
}
func testOriginalTermsAreRecoverable() {
let equal = Cofree<String, ()>.equals(annotation: const(true), leaf: ==)
property("before state is recoverable") <- forAll { (diff: RangedDiff) in
diff.diff.map { $0.map { $0.map(const(())) } }.before.map {
equal($0, diff.a.stripped.term)
} ?? false
}
property("after state is recoverable") <- forAll { (diff: RangedDiff) in
diff.diff.map { $0.map { $0.map(const(())) } }.after.map {
equal($0, diff.b.stripped.term)
} ?? false
}
}
}
private func equal(a: DiffTests.Diff, _ b: DiffTests.Diff) -> Bool {
return Free.equals(pure: Patch.equals(Cofree.equals(annotation: ==, leaf: ==)), leaf: ==, annotation: const(true))(a, b)
}
@testable import Doubt
import Prelude
import SwiftCheck
import XCTest

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -1,49 +0,0 @@
final class InterpreterTests: XCTestCase {
func testRestrictsComparisons() {
let comparable: (Term, Term) -> Bool = { $0.extract == 0 && $1.extract == 0 }
let i = Interpreter(equal: ==, comparable: comparable, cost: const(1))
let d = i.run(a, b)
assert(d, ==, restricted)
}
func testComparisonsOfDisjointlyCategorizedTermsAreRestricted() {
var effects = 0
let categorize: Term -> Set<Int> = { $0.extract == 0 ? [ 0 ] : [ effects++ ] }
assert(Interpreter(equal: ==, comparable: Interpreter.comparable(categorize), cost: const(1)).run(a, b), ==, restricted)
}
func testUnrestrictedComparisonsComputeReplacements() {
assert(Interpreter(equal: ==, comparable: const(true), cost: const(1)).run(a, b), ==, unrestricted)
}
func testComparisonsOfUncategorizedTermsAreUnrestricted() {
assert(Interpreter(equal: ==, comparable: Interpreter.comparable { _ in Set<String>() }, cost: const(1)).run(a, b), ==, unrestricted)
}
}
private typealias Term = Cofree<String, Int>
private typealias Diff = Free<String, (Int, Int), Patch<Term>>
private let a = Term(0, [ Term(1, .Leaf("a")), Term(2, .Leaf("b")), Term(3, .Leaf("c")) ])
private let b = Term(0, [ Term(1, .Leaf("c")), Term(2, .Leaf("b")), Term(3, .Leaf("a")) ])
private let restricted = Diff.Roll((0, 0), [
.Pure(.Insert(Term(1, .Leaf("c")))),
.Pure(.Delete(Term(1, .Leaf("a")))),
.Roll((2, 2), .Leaf("b")),
.Pure(.Insert(Term(3, .Leaf("a")))),
.Pure(.Delete(Term(3, .Leaf("c")))),
])
private let unrestricted = Diff.Roll((0, 0), [
.Pure(.Replace(Term(1, .Leaf("a")), Term(1, .Leaf("c")))),
.Roll((2, 2), .Leaf("b")),
.Pure(.Replace(Term(3, .Leaf("c")), Term(3, .Leaf("a")))),
])
import Assertions
@testable import Doubt
import Prelude
import XCTest

View File

@ -1,28 +0,0 @@
import Assertions
import Doubt
import Prelude
import Madness
import XCTest
final class JSONParserTests: XCTestCase {
func testCapturesKeysInKeyedElements() {
let dictWithArray = "{ \"hello\":\n [\"world\",\n \"sailor\"\n ]}"
let array: Cofree<JSONLeaf, Range<Int>> = Cofree(15..<41, .Indexed([
Cofree(16..<23, .Leaf(.String("world"))),
Cofree(29..<37, .Leaf(.String("sailor")))
]))
let fixedPairs: Cofree<JSONLeaf, Range<Int>> = Cofree(2..<41, .Fixed([Cofree(2..<9, .Leaf(.String("hello"))), array]))
let expected: Cofree<JSONLeaf, Range<Int>> = Cofree(0..<42, .Keyed(["hello": fixedPairs]))
let actual = Madness.parse(json, input: dictWithArray).right!
let startRange = actual.extract.2
let new: Cofree<JSONLeaf, Range<Int>> = actual.map({ tuple in
let startI: Int = startRange.startIndex.distanceTo(tuple.2.startIndex)
let endI: Int = startRange.startIndex.distanceTo(tuple.2.endIndex)
return Range(start: startI, end: endI)
})
assert(new, == , expected)
}
}

View File

@ -1,107 +0,0 @@
final class LocationTests: XCTestCase {
func testExplorationOfATermBeginsAtTheExploredTerm() {
assert(term.explore().it, ==, term)
}
func testCannotMoveUpwardsAtTheStartOfAnExploration() {
assert(term.explore().outOf?.it, ==, nil)
}
func testCannotMoveSidewaysAtTheStartOfAnExploration() {
assert(term.explore().left?.it, ==, nil)
assert(term.explore().right?.it, ==, nil)
}
func testCannotMoveDownwardsFromLeaves() {
assert(leafA.explore().into?.it, ==, nil)
}
func testCanMoveDownwardsIntoBranches() {
assert(term.explore().into?.it, ==, leafA)
}
func testCanMoveBackUpwards() {
assert(term.explore().into?.outOf?.it, ==, term)
}
func testCannotMoveLeftwardsFromFirstChildOfBranch() {
assert(term.explore().into?.left?.it, ==, nil)
}
func testCanMoveRightwardsFromLeftmostChildOfLongBranch() {
assert(term.explore().into?.right?.it, ==, leafB)
}
func testCanExploreBranchesDeeply() {
assert(term.explore().into?.right?.right?.into?.it, ==, innerLeafB)
}
func testCanMoveBackUpwardsFromDeepExplorations() {
assert(term.explore().into?.right?.right?.into?.right?.outOf?.outOf?.it, ==, term)
}
func testCanReturnToStartOfExplorationFromArbitrarilyDeepNodes() {
assert(term.explore().into?.right?.right?.into?.right?.root.it, ==, term)
}
func testSequenceIsPreOrderDepthFirstTraversal() {
assert(term.explore().map { $0.it.extract }, ==, [ 0, 1, 2, 3, 5, 4 ])
}
func testModifyReplacesSubtrees() {
assert(term.explore().into?.modify(const(leafB)).right?.outOf?.it, ==, Cofree(0, .Indexed([ leafB, leafB, keyed ])))
}
func testMultipleModificationsReplaceMultipleSubtrees() {
assert(term.explore().into?.modify(const(leafB)).right?.modify(const(leafA)).outOf?.it, ==, Cofree(0, .Indexed([ leafB, leafA, keyed ])))
}
func testModificationsPreserveKeys() {
assert(keyed.explore().into?.modify(const(leafA)).root.it, ==, Cofree(3, .Keyed([ "a": innerLeafA, "b": leafA ])))
}
func testDeepModificationsReplaceDeepSubtrees() {
assert(term.explore().into?.modify(const(leafB)).right?.modify(const(leafA)).right?.into?.modify(const(innerLeafA)).right?.modify(const(innerLeafB)).root.it, ==, Cofree(0, .Indexed([ leafB, leafA, Cofree(3, .Keyed([ "a": innerLeafB, "b": innerLeafA ])) ])))
}
func testModificationsCanRefineDiffs() {
assert(diff.explore().into?.right?.modify(const(refined)).root.it, ==, Free.Roll(0, .Indexed([ Free.Roll(1, .Leaf("a string")), refined ])))
}
}
private let leafA = Cofree(1, .Leaf("a string"))
private let leafB = Cofree(2, .Leaf("b string"))
private let innerLeafA = Cofree(4, .Leaf("a nested string"))
private let innerLeafB = Cofree(5, .Leaf("b nested string"))
private let keyed = Cofree(3, .Keyed([
"a": innerLeafA,
"b": innerLeafB,
]))
private let term: Cofree<String, Int> = Cofree(0, .Indexed([
leafA,
leafB,
keyed,
]))
private let diff: Free<String, Int, Patch<Cofree<String, Int>>> = Free.Roll(0, .Indexed([
Free.Roll(1, .Leaf("a string")),
Free.Pure(Patch.Replace(leafA, leafB)), // coarse-grained diff of two leaf nodes
]))
// fine-grained diff of same
private let refined = Free.Roll(2, .Indexed([
Free.Pure(Patch.Replace(Cofree(1, .Leaf("a")), Cofree(2, .Leaf("b")))),
Free.Roll(4, .Leaf(" ")),
Free.Roll(5, .Leaf("s")),
Free.Roll(6, .Leaf("t")),
Free.Roll(7, .Leaf("r")),
Free.Roll(8, .Leaf("i")),
Free.Roll(9, .Leaf("n")),
Free.Roll(10, .Leaf("g")),
]))
import Assertions
@testable import Doubt
import Prelude
import XCTest

View File

@ -1,29 +0,0 @@
struct RangedDiff {
typealias Diff = Free<String, (RangedTerm.Term.Annotation, RangedTerm.Term.Annotation), Patch<RangedTerm.Term>>
let a: RangedTerm
let b: RangedTerm
let diff: Diff
}
extension RangedDiff: Arbitrary {
static let interpreter = Interpreter<RangedTerm.Term>(equal: ==, comparable: const(true), cost: Diff.sum(Patch.difference))
static var arbitrary: Gen<RangedDiff> {
return RangedTerm.arbitrary.bind { a in
RangedTerm.arbitrary.fmap { b in
RangedDiff(a: a, b: b, diff: interpreter.run(a.term, b.term))
}
}
}
static func shrink(diff: RangedDiff) -> [RangedDiff] {
return RangedTerm.shrink(diff.a).map { RangedDiff(a: $0, b: diff.b, diff: interpreter.run($0.term, diff.b.term)) }
+ RangedTerm.shrink(diff.b).map { RangedDiff(a: diff.a, b: $0, diff: interpreter.run(diff.a.term, $0.term)) }
}
}
import Doubt
import Prelude
import SwiftCheck

View File

@ -1,24 +0,0 @@
struct RangedTerm {
typealias Term = Cofree<String, Range<String.Index>>
let term: Term
let source: String
var stripped: UnannotatedTerm {
return UnannotatedTerm(term: term.map(const(())))
}
}
extension RangedTerm: Arbitrary {
static var arbitrary: Gen<RangedTerm> {
return UnannotatedTerm.arbitrary.fmap { $0.arranged }
}
static func shrink(term: RangedTerm) -> [RangedTerm] {
return UnannotatedTerm.shrink(term.stripped).map { $0.arranged }
}
}
@testable import Doubt
import Prelude
import SwiftCheck

View File

@ -1,67 +0,0 @@
final class SESTests: XCTestCase {
func testSESOverEmptyCollectionsIsEmpty() {
assert(SES([], []), ==, [])
}
func testSESOverEmptyAndNonEmptyCollectionsIsInsertions() {
assert(SES([], [ a, b ]), ==, [ .Insert(a), .Insert(b) ])
}
func testSESOverNonEmptyAndEmptyCollectionsIsDeletions() {
assert(SES([ a, b ], []), ==, [ .Delete(a), .Delete(b) ])
}
func testSESCanInsertAtHead() {
assert(SES([ a, b, c ], [ d, a, b, c ]), ==, [ .Insert(d), Copy(a), Copy(b), Copy(c) ])
}
func testSESCanDeleteAtHead() {
assert(SES([ d, a, b, c ], [ a, b, c ]), ==, [ .Delete(d), Copy(a), Copy(b), Copy(c) ])
}
func testSESCanInsertInMiddle() {
assert(SES([ a, b, c ], [ a, d, b, c ]), ==, [ Copy(a), .Insert(d), Copy(b), Copy(c) ])
}
func testSESCanDeleteInMiddle() {
assert(SES([ a, d, b, c ], [ a, b, c ]), ==, [ Copy(a), .Delete(d), Copy(b), Copy(c) ])
}
func testInsertsAtEnd() {
assert(SES([ a, b, c ], [ a, b, c, d ]), ==, [ Copy(a), Copy(b), Copy(c), .Insert(d) ])
}
func testDeletesAtEnd() {
assert(SES([ a, b, c, d ], [ a, b, c ]), ==, [ Copy(a), Copy(b), Copy(c), .Delete(d) ])
}
func testSESOfLongerSequences() {
assert(SES([ a, b, c, a, b, b, a ], [ c, b, a, b, a, c ]), ==, [ .Insert(c), .Delete(a), Copy(b), .Delete(c), Copy(a), Copy(b), .Delete(b), Copy(a), .Insert(c) ])
}
}
private typealias Term = Cofree<String, ()>
private typealias Diff = Free<String, (), Patch<Term>>
private func Copy(term: Term) -> Diff {
return hylo(Diff.Introduce(()), Term.unwrap)(term)
}
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, cost: const(1)) { Cofree.equals(annotation: const(true), leaf: ==)($0, $1) ? Copy($1) : nil }
}
private func == (a: [Diff], b: [Diff]) -> Bool {
return a.count == b.count && zip(a, b).lazy.map(Diff.equals(pure: Patch.equals(Cofree.equals(annotation: const(true), leaf: ==)), leaf: ==, annotation: const(true))).reduce(true) { $0 && $1 }
}
import Assertions
@testable import Doubt
import Prelude
import XCTest

View File

@ -1,22 +0,0 @@
final class TermTests: XCTestCase {
override static func setUp() {
sranddev()
}
func testEqualityIsReflexive() {
property("equality is reflexive") <- forAll { (term: RangedTerm) in
Cofree.equals(annotation: ==, leaf: ==)(term.term, term.term)
}
}
func testEqualTermsZipCleanly() {
property("equal terms zip to a non-nil value") <- forAll { (term: RangedTerm) in
Cofree.zip(term.term, term.term) != nil
}
}
}
@testable import Doubt
import SwiftCheck
import XCTest

View File

@ -1,147 +0,0 @@
struct UnannotatedTerm {
typealias Term = Cofree<String, ()>
let term: Term
static let indexed = (prefix: "[\n\t", separator: ",\n\t", suffix: "\n]")
static let fixed = (prefix: "(\n\t", separator: ",\n\t", suffix: "\n)")
static let keyed = (prefix: "[\n\t", separator: ",\n\t", suffix: "\n}")
var source: String {
let indexed = UnannotatedTerm.indexed
let keyed = UnannotatedTerm.keyed
let fixed = UnannotatedTerm.fixed
return term.cata {
switch $1 {
case let .Leaf(s):
return s
case let .Indexed(s):
return indexed.prefix + s.joinWithSeparator(indexed.separator) + indexed.suffix
case let .Fixed(s):
return fixed.prefix + s.joinWithSeparator(fixed.separator) + fixed.suffix
case let .Keyed(s):
return keyed.prefix + s.map { "\"\($0)\": \($1)" }.joinWithSeparator(keyed.separator) + keyed.suffix
}
}
}
var ranged: Cofree<String, Range<Int>> {
let indexed = UnannotatedTerm.indexed
let keyed = UnannotatedTerm.keyed
let fixed = UnannotatedTerm.fixed
return term.cata {
switch $1 {
case let .Leaf(s):
return Cofree(0..<s.characters.count, .Leaf(s))
case let .Indexed(i):
var length = indexed.prefix.characters.count
var results: [Cofree<String, Range<Int>>] = []
for value in i {
if results.count > 0 {
length += indexed.separator.characters.count
}
results.append(value.map {
($0.startIndex + length)..<($0.endIndex + length)
})
length += value.extract.count
}
return Cofree(0..<(length + indexed.suffix.characters.count), .Indexed(results))
case let .Fixed(i):
var length = fixed.prefix.characters.count
var results: [Cofree<String, Range<Int>>] = []
for value in i {
if results.count > 0 {
length += fixed.separator.characters.count
}
results.append(value.map {
($0.startIndex + length)..<($0.endIndex + length)
})
length += value.extract.count
}
return Cofree(0..<(length + fixed.suffix.characters.count), .Fixed(results))
case let .Keyed(k):
var length = keyed.prefix.characters.count
var results: [(String, Cofree<String, Range<Int>>)] = []
for (key, value) in k {
if results.count > 0 {
length += keyed.separator.characters.count
}
results.append((key, value.map {
($0.startIndex + length)..<($0.endIndex + length)
}))
length += value.extract.count + 4 // for the characters around the key
}
return Cofree(0..<(length + keyed.suffix.characters.count), .Keyed(Dictionary(elements: results)))
}
}
}
var arranged: RangedTerm {
let source = self.source
return RangedTerm(
term: ranged.map {
source.startIndex.advancedBy($0.startIndex)..<source.startIndex.advancedBy($0.endIndex)
},
source: source)
}
}
extension UnannotatedTerm: Arbitrary {
static func arbitrary(k: Int) -> Gen<UnannotatedTerm> {
let symbol: Gen<String> = Gen<Int>.choose((0, 15)).fmap { "_\($0)" }
let leaf: Gen<Term> = symbol.fmap { Term((), .Leaf($0)) }
let indexed: Gen<Term> = Gen<Int>.choose((0, k)).bind { n in
sequence((0..<n).map { _ in arbitrary(k - 1) }).fmap {
Term((), .Indexed($0.map { $0.term }))
}
}
let keyed: Gen<Term> = Gen<Int>.choose((0, k)).bind { n in
sequence((0..<n).map { _ in symbol.bind { key in Gen.pure(()).bind { arbitrary(k - 1) }.fmap { (key, $0.term) } } }).fmap {
Term((), .Keyed(Dictionary(elements: $0)))
}
}
return Gen.oneOf([
leaf,
indexed,
keyed,
]).fmap(UnannotatedTerm.init)
}
static var arbitrary: Gen<UnannotatedTerm> {
return arbitrary(4)
}
static func shrink(term: UnannotatedTerm) -> [UnannotatedTerm] {
let equal = Term.equals(annotation: const(true), leaf: ==)
/// A smaller-than-or-equal-to permutation of `term`. Shrinking is performed outward-in by dropping elements from branches.
let shrunk: UnannotatedTerm.Term = term.term.para {
switch $0 {
case let .Leaf(a):
return Cofree((), .Leaf(a))
case let .Indexed(i):
return Cofree((), .Indexed(i.reduce(true) { $0 && equal($1) }
? i.dropLast().map { $1 }
: i.map { $1 }))
case let .Fixed(i):
return Cofree((), .Fixed(i.reduce(true) { $0 && equal($1) }
? i.dropLast().map { $1 }
: i.map { $1 }))
case let .Keyed(k):
return Cofree((), .Keyed(Dictionary(elements: k.reduce(true) { $0 && equal($1.1) }
? k.dropLast().map { ($0, $1.1) }
: k.map { ($0, $1.1) })))
}
}
/// If the permutation is unchanged, we cannot shrink any further.
return equal(term.term, shrunk)
? []
: [ UnannotatedTerm(term: shrunk) ]
}
}
import Doubt
import Prelude
import SwiftCheck

View File

@ -1,7 +0,0 @@
# Doubt
Doubt is the prototype implementing semantic diffing features. It is implemented as a library, with a couple of helper tools for specific experiments, and a small HTML/JS UI for reviewing diffs.
## Building
Doubt requires Xcode 7 to build.

View File

@ -1,2 +0,0 @@
*.json
diff.html

View File

@ -1,16 +0,0 @@
function Dictionary(object) {
this.values = {};
for (key in object) {
this.values[key] = object[key];
}
return this;
}
// forall a b. Dictionary String a -> (a -> b) -> Dictionary String b
Dictionary.prototype.map = function(transform) {
var copy = new Dictionary();
for (key in this.values) {
copy.values[key] = transform(this.values[key], key);
}
return copy;
}

516
prototype/UI/diff.js vendored
View File

@ -1,516 +0,0 @@
function diffFromJSON(json) {
if (json.pure != null) {
return new Diff({
pure: new Patch(json.pure)
});
}
if (json.roll != null) {
return new Diff({
roll: {
extract: json.roll.extract,
unwrap: new Syntax(json.roll.unwrap, function(x) {
return diffFromJSON(x);
})
}
});
}
}
function Diff(object) {
if (object.pure != null) {
this.pure = object.pure;
}
if (object.roll != null) {
this.roll = object.roll;
}
return this;
}
// forall a b. Diff a -> (a -> b) -> Diff b
Diff.prototype.map = function(transform) {
if (this.pure != null) {
return new Diff({
pure: transform(this.pure)
});
}
if (this.roll != null) {
return new Diff({
roll: {
extract: this.roll.extract,
unwrap: this.roll.unwrap.map(function(x) {
return x.map(transform);
})
}
});
}
}
// forall a. Diff a -> (Syntax a -> a) -> a
Diff.prototype.cata = function(transform) {
if (this.pure != null) {
return this.pure;
}
if (this.roll != null) {
return transform(this.roll.unwrap.map(function(diff) {
return diff.cata(transform);
}))
}
}
function wrap(tagName, element) {
if (element == null) {
return null;
}
var node = document.createElement(tagName);
node.appendChild(element);
return node;
}
/// String -> Syntax a -> Range -> (a -> Range) -> (a -> DOM) -> DOM
function termToDOM(source, syntax, extract, getRange, recur) {
recur = recur || function(term) {
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");
element.textContent = source.substr(range[0], range[1]);
} else if (syntax.indexed != null || syntax.fixed != null) {
var values = syntax.indexed || syntax.fixed;
element = document.createElement("ul");
var previous = range[0];
for (i in values) {
var child = values[i];
if (child.pure == "") continue;
var childRange = getRange(child);
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) {
element = document.createElement("dl");
var values = [];
for (k in syntax.keyed.values) {
if (syntax.keyed.values[k].pure == "") continue;
values.push([k, syntax.keyed.values[k]]);
}
values.sort(function(a, b) {
if (getRange(a[1])[0] < getRange(b[1])[0]) {
return -1;
} else if (getRange(a[1])[0] > getRange(b[1])[0]) {
return 1;
}
return 0;
});
var previous = range[0];
for (i in values) {
var pair = values[i];
var key = pair[0];
var child = pair[1];
var childRange = getRange(child);
element.appendChild(document.createTextNode(source.substr(previous, childRange[0] - previous)));
element.appendChild(wrap("dt", document.createTextNode(key)));
element.appendChild(wrap("dd", recur(child)));
previous = childRange[0] + childRange[1];
}
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;
}
/// Diff -> String -> DOM
function diffToDOM(diff, sources, lineNumbers) {
function getRange(diffOrTerm) {
if (diffOrTerm.pure != null) {
var beforeRange, afterRange;
if (diffOrTerm.pure.before != null) {
beforeRange = diffOrTerm.pure.before.extract.range
}
if (diffOrTerm.pure.after != null) {
afterRange = diffOrTerm.pure.after.extract.range
}
if (beforeRange == null) {
beforeRange = afterRange;
}
if (afterRange == null) {
afterRange = beforeRange;
}
return { "before": beforeRange, "after": afterRange };
}
if (diffOrTerm.roll != null) {
return { before: diffOrTerm.roll.extract.before.range, after: diffOrTerm.roll.extract.after.range };
}
if (diffOrTerm.extract != null) {
return diffOrTerm.extract.range;
}
}
if (diff.pure != null) {
return pureToDOM(sources, diff.pure, lineNumbers, getRange, function(diff) {
return diffToDOM(diff, sources, lineNumbers);
})
}
return rollToDOM(sources, diff.roll, lineNumbers, getRange, function(diff) {
return diffToDOM(diff, sources, lineNumbers);
})
}
function pureToDOM(sources, patch, lineNumbers, getRangeFun, diffToDOMFun) {
var elementA, elementB;
if (patch.before != null) {
elementA = termToDOM(sources.before, patch.before.unwrap, patch.before.extract, getRangeFun);
elementA.classList.add("delete");
if (patch.after != null) {
elementA.classList.add("replace");
}
elementA.setAttribute("data-line-number", patch.before.extract.lines[0])
}
if (patch.after != null) {
elementB = termToDOM(sources.after, patch.after.unwrap, patch.after.extract, getRangeFun);
elementB.classList.add("insert");
if (patch.before != null) {
elementB.classList.add("replace");
}
elementB.setAttribute("data-line-number", patch.after.extract.lines[0])
}
if (elementA == null) {
elementA = elementB.cloneNode(true);
elementA.classList.add("invisible");
elementA.setAttribute("data-line-number", '\u00A0')
}
if (elementB == null) {
elementB = elementA.cloneNode(true);
elementB.classList.add("invisible");
elementB.setAttribute("data-line-number", '\u00A0')
}
return { "before": elementA || "", "after": elementB || "" };
}
function rollToDOM(sources, rollOrTerm, lineNumbers, getRangeFun, diffToDOMFun) {
var syntax = rollOrTerm.unwrap
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 lines = {
before: rollOrTerm.extract.before.lines[0],
after: rollOrTerm.extract.after.lines[0]
}
var elementA;
var elementB;
if (syntax.leaf != null) {
elementA = document.createElement("span");
elementA.textContent = sources.before.substr(range.before[0], range.before[1]);
elementB = document.createElement("span");
elementB.textContent = sources.after.substr(range.after[0], range.after[1]);
elementA.setAttribute("data-line-number", lines.before)
elementB.setAttribute("data-line-number", lines.after)
} else if (syntax.indexed != null || syntax.fixed != null) {
var values = syntax.indexed || syntax.fixed;
elementA = document.createElement("ul");
elementB = document.createElement("ul");
var previousBefore = range.before[0];
var previousAfter = range.after[0];
var lineNumbers = { "before": [], "after": [] };
for (i in values) {
var child = values[i];
if (child.pure == "") continue;
var childRange = getRangeFun(child);
var beforeAfterChild = diffToDOMFun(child)
if (childRange.before != null) {
var beforeRange = childRange.before;
var li = wrap("li", beforeAfterChild.before);
if (beforeAfterChild.before.classList.contains("invisible")) {
li.classList.add("invisible");
} else {
var beforeSeparator = sources.before.substr(previousBefore, beforeRange[0] - previousBefore);
elementA.appendChild(document.createTextNode(beforeSeparator));
previousBefore = beforeRange[0] + beforeRange[1];
}
elementA.appendChild(li);
var lineNumber = beforeAfterChild.before.getAttribute("data-line-number")
if (lineNumber != null) {
lineNumbers.before.push(lineNumber)
}
}
if (childRange.after != null) {
var afterRange = childRange.after;
var li = wrap("li", beforeAfterChild.after);
if (beforeAfterChild.after.classList.contains("invisible")) {
li.classList.add("invisible");
} else {
var afterSeparator = sources.after.substr(previousAfter, afterRange[0] - previousAfter);
elementB.appendChild(document.createTextNode(afterSeparator));
previousAfter = afterRange[0] + afterRange[1];
}
elementB.appendChild(li);
var lineNumber = beforeAfterChild.after.getAttribute("data-line-number");
if (lineNumber != null) {
lineNumbers.after.push(lineNumber)
}
}
}
var beforeText = sources.before.substr(previousBefore, range.before[0] + range.before[1] - previousBefore);
var afterText = sources.after.substr(previousAfter, range.after[0] + range.after[1] - previousAfter);
elementA.appendChild(document.createTextNode(beforeText));
elementB.appendChild(document.createTextNode(afterText));
elementA.setAttribute("data-line-number", lineNumbers.before)
elementB.setAttribute("data-line-number", lineNumbers.after)
} else if (syntax.keyed != null) {
elementA = document.createElement("dl");
elementB = document.createElement("dl");
var befores = [];
var afters = [];
for (k in syntax.keyed.values) {
if (syntax.keyed.values[k].pure == "") continue;
var child = syntax.keyed.values[k];
var ranges = getRangeFun(child);
var doms = diffToDOMFun(child)
if (ranges.before != null) {
befores.push({ "key": k, "range": ranges.before, "child": doms.before });
}
if (ranges.after != null) {
afters.push({ "key": k, "range": ranges.after, "child": doms.after });
}
}
var sortByRange = function (array) {
return function(a, b) {
// if a is invisible, sort it based on its range vs. bs opposite range
function sortByOppositeRange(el) {
var opArray = array === befores ? afters : befores;
var opEl = opArray.find(function (e) { return el.key === e.key; });
var otherEl = el === a ? b : a;
var opOtherEl = opArray.find(function (e) { return otherEl.key === e.key; });
if (el.child.classList.contains("delete") && otherEl.child.classList.contains("insert")) {
return -1;
}
if (el.child.classList.contains("insert") && otherEl.child.classList.contains("delete")) {
return 1;
}
if (!el.child.classList.contains("invisible") && !otherEl.child.classList.contains("invisible")) {
if (el.range[0] < otherEl.range[0]) {
return -1;
} else if (el.range[0] > otherEl.range[0]) {
return 1;
}
}
if (opEl.range[0] < opOtherEl.range[0]) {
return -1;
} else if (opEl.range[0] > opOtherEl.range[0]) {
return 1;
}
return 0;
}
return sortByOppositeRange(a);
}
}
befores.sort(sortByRange(befores));
afters.sort(sortByRange(afters));
var previousA = range.before[0];
var previousB = range.after[0];
var lineNumbers = { "before": [ lines.before ], "after": [ lines.after ] };
zip(befores, afters, function (a, b) {
var key = a.key
var childElA = a.child
var childRangeA = a.range
var childElB = b.child
var childRangeB = b.range
var isFirst = elementA.childNodes.length == 0;
function penultimateNode(el) {
var nodes = Array.prototype.slice.call(el.childNodes).reverse();
var lastVisibleNode;
for (i in nodes) {
var node = nodes[i];
if (node.nodeType != 3 && node.classList.contains("invisible")) {
var nextIndex = parseInt(i, 10) + 1;
if (nextIndex < nodes.length) {
var nextNode = nodes[nextIndex];
if (nextNode.nodeType != 3 && !nextNode.classList.contains("invisible")) {
return node;
}
}
}
}
}
if (isFirst || !childElA.classList.contains("invisible")) {
var text = sources.before.substr(previousA, childRangeA[0] - previousA);
var beforeNode = penultimateNode(elementA)
if (beforeNode != null) {
elementA.insertBefore(document.createTextNode(text), beforeNode);
} else {
elementA.appendChild(document.createTextNode(text));
}
}
if (isFirst || !childElB.classList.contains("invisible")) {
var text = sources.after.substr(previousB, childRangeB[0] - previousB);
var beforeNode = penultimateNode(elementB)
if (beforeNode != null) {
elementB.insertBefore(document.createTextNode(text), beforeNode);
} else {
elementB.appendChild(document.createTextNode(text));
}
}
var dtA = wrap("dt", document.createTextNode(key));
elementA.appendChild(dtA);
var ddA = wrap("dd", childElA)
elementA.appendChild(ddA);
if (childElA.classList.contains("invisible")) {
dtA.classList.add("invisible");
ddA.classList.add("invisible");
}
var lineNumberA = childElA.getAttribute("data-line-number");
if (lineNumberA != null) {
lineNumbers.before.push(lineNumberA)
}
var dtB = wrap("dt", document.createTextNode(key));
elementB.appendChild(dtB);
var ddB = wrap("dd", childElB);
elementB.appendChild(ddB);
if (childElB.classList.contains("invisible")) {
dtB.classList.add("invisible");
ddB.classList.add("invisible");
}
var lineNumberB = childElB.getAttribute("data-line-number");
if (lineNumberB != null) {
lineNumbers.after.push(lineNumberB)
}
if (isFirst || !childElA.classList.contains("invisible")) {
previousA = childRangeA[0] + childRangeA[1]
}
if (isFirst || !childElB.classList.contains("invisible")) {
previousB = childRangeB[0] + childRangeB[1]
}
var nextIndex = befores.indexOf(a) + 1;
if (childElA.classList.contains("invisible") && nextIndex < afters.length) {
var nextVisibleElement = afters[nextIndex]
while (nextVisibleElement.child.classList.contains("invisible") && ++nextIndex < afters.length) {
nextVisibleElement = afters[nextIndex]
}
if (nextVisibleElement == null) return;
var beginningOfNextElement = nextVisibleElement.range[0];
var text = sources.after.substr(previousB, beginningOfNextElement - previousB);
var node = wrap("span", document.createTextNode(text));
node.classList.add("invisible");
elementA.appendChild(node);
}
var nextIndex = afters.indexOf(b) + 1;
if (childElB.classList.contains("invisible") && nextIndex < befores.length) {
var nextVisibleElement = befores[nextIndex]
while (nextVisibleElement.child.classList.contains("invisible") && ++nextIndex < befores.length) {
nextVisibleElement = befores[nextIndex]
}
if (nextVisibleElement == null) return;
var beginningOfNextElement = nextVisibleElement.range[0];
var text = sources.before.substr(previousA, beginningOfNextElement - previousA);
var node = wrap("span", document.createTextNode(text));
node.classList.add("invisible");
elementB.appendChild(node);
}
});
var textA = sources.before.substr(previousA, range.before[0] + range.before[1] - previousA);
elementA.appendChild(document.createTextNode(textA));
var textB = sources.after.substr(previousB, range.after[0] + range.after[1] - previousB);
elementB.appendChild(document.createTextNode(textB));
lineNumbers.before.push(rollOrTerm.extract.before.lines[1])
lineNumbers.after.push(rollOrTerm.extract.after.lines[1])
elementA.setAttribute("data-line-number", lineNumbers.before)
elementB.setAttribute("data-line-number", lineNumbers.after)
}
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 }
}
/// ([a], [b]) -> [(a, b)]
function zip (a, b, callback) {
if (a.length > b.length) {
return b.map(function(b, index) {
return callback(a[index], b);
});
} else {
return a.map(function(a, index) {
return callback(a, b[index]) ;
});
}
}

View File

@ -1,72 +0,0 @@
<!doctype html>
<html>
<head>
<title>semantic-diff</title>
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="dictionary.js"></script>
<script type="text/javascript" src="diff.js"></script>
<script type="text/javascript" src="patch.js"></script>
<script type="text/javascript" src="syntax.js"></script>
<script type="text/javascript" src="term.js"></script>
<script type="text/javascript">
function loadJSON(path, callback) {
var request = new XMLHttpRequest();
request.overrideMimeType("application/json");
request.open('GET', '' + path, true);
request.onreadystatechange = function () {
if (request.readyState == 4 && (request.status == "200" || request.status == 0)) {
callback(JSON.parse(request.responseText));
}
};
request.send(null);
}
</script>
</head>
<body>
<div id="before">
<ul id="before-lines" class="line-numbers"></ul>
<div id="before-diff" class="diff"></div>
</div>
<div id="after">
<ul id="after-lines" class="line-numbers"></ul>
<div id="after-diff" class="diff"></div>
</div>
<script type="text/javascript">
var unique = function(array) {
return array.reduce(function(accum, current) {
if (accum.indexOf(current) < 0) {
accum.push(current);
}
return accum;
}, []);
}
loadJSON((window.location.search || '?diff.json').substr(1), function (json) {
var diff = diffFromJSON(json.diff);
var beforeLinesEl = document.getElementById("before-lines")
var afterLinesEl = document.getElementById("after-lines")
var dom = diffToDOM(diff,
{ "before": json["before"] , "after": json["after"] },
{ "before": beforeLinesEl, "after": afterLinesEl });
var beforeLines = dom.before.getAttribute("data-line-number").split(",")
unique(beforeLines).forEach(function(lineNumber) {
var node = wrap("li", document.createTextNode(lineNumber));
beforeLinesEl.appendChild(node);
});
var afterLines = dom.after.getAttribute("data-line-number").split(",")
unique(afterLines).forEach(function(lineNumber) {
var node = wrap("li", document.createTextNode(lineNumber));
afterLinesEl.appendChild(node);
});
document.getElementById("before-diff").appendChild(dom.before);
document.getElementById("after-diff").appendChild(dom.after);
});
</script>
</body>
</html>

13
prototype/UI/patch.js vendored
View File

@ -1,13 +0,0 @@
function Patch(patch) {
if (patch.delete != null) {
this.before = termFromJSON(patch.delete);
}
if (patch.insert != null) {
this.after = termFromJSON(patch.insert);
}
if (patch.replace != null) {
this.before = termFromJSON(patch.replace.before);
this.after = termFromJSON(patch.replace.after);
}
return this;
}

View File

@ -1,39 +0,0 @@
function Syntax(json, continuation) {
if (json.indexed != null) {
this.indexed = json.indexed.map(continuation);
}
if (json.fixed != null) {
this.fixed = json.fixed.map(continuation);
}
if (json.keyed != null) {
this.keyed = (new Dictionary(json.keyed)).map(continuation);
}
if (json.leaf != null) {
this.leaf = json.leaf;
}
return this;
}
// forall a b. Syntax a -> (a -> b) -> Syntax b
Syntax.prototype.map = function(transform) {
if (this.leaf != null) {
return new Syntax({
leaf: this.leaf
}, transform);
}
if (this.indexed != null) {
return new Syntax({
indexed: this.indexed
}, transform);
}
if (this.fixed != null) {
return new Syntax({
fixed: this.fixed
}, transform);
}
if (this.keyed != null) {
return new Syntax({
keyed: this.keyed.values
}, transform);
}
}

14
prototype/UI/term.js vendored
View File

@ -1,14 +0,0 @@
function termFromJSON(json) {
return new Term({
extract: json.extract,
unwrap: new Syntax(json.unwrap, function(x) {
return termFromJSON(x);
})
});
}
function Term(object) {
this.extract = object.extract;
this.unwrap = object.unwrap;
return this;
}

View File

@ -1,43 +0,0 @@
/// A list of arguments for the difftool.
enum Argument {
indirect case OutputFlag(Output, Argument)
case Sources(Source, Source)
var sources: (Source, Source) {
switch self {
case let .Sources(a, b):
return (a, b)
case let .OutputFlag(_, rest):
return rest.sources
}
}
var output: Output {
switch self {
case let .OutputFlag(output, _):
return output
default:
return .Split
}
}
enum Output {
case Unified
case Split
}
}
private let flag: Madness.Parser<[String], Argument.Output>.Function =
const(Argument.Output.Unified) <^> satisfy { $0 == "--unified" }
<|> const(Argument.Output.Split) <^> satisfy { $0 == "--split" }
<|> pure(Argument.Output.Split)
private let source: Madness.Parser<[String], Source>.Function =
{ try! Source($0) } <^> satisfy { !$0.hasPrefix("--") }
let argumentsParser: Madness.Parser<[String], Argument>.Function = any // skip the path to the difftool
*> (curry(Argument.OutputFlag) <^> flag)
<*> (curry(Argument.Sources) <^> source <*> source)
import Madness
import Prelude

View File

@ -1,692 +0,0 @@
{
"AWSTemplateFormatVersion": "2010-09-09",
"Conditions": {
"EbsVolumeSnapshotIdIsEmpty": {
"Fn::Equals": [
{
"Ref": "EbsVolumeSnapshotId"
},
""
]
},
"EbsVolumeSnapshotIdIsPresent": {
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "EbsVolumeSnapshotId"
},
""
]
}
]
},
"not_production": {
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "Environment"
},
"production"
]
}
]
},
"not_staging": {
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "Environment"
},
"staging"
]
}
]
},
"not_test": {
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "Environment"
},
"test"
]
}
]
},
"production": {
"Fn::Equals": [
{
"Ref": "Environment"
},
"production"
]
},
"staging": {
"Fn::Equals": [
{
"Ref": "Environment"
},
"staging"
]
},
"test": {
"Fn::Equals": [
{
"Ref": "Environment"
},
"test"
]
}
},
"Description": "A single EC2 instance with an EBS volume",
"Mappings": {},
"Metadata": {},
"Outputs": {
"AvailabilityZone": {
"Description": "The instance availability zone",
"Value": {
"Fn::GetAtt": [
"EbsInstance",
"AvailabilityZone"
]
}
},
"InstanceID": {
"Description": "The instance identifier",
"Value": "EbsInstance"
},
"PrivateDnsName": {
"Description": "The instance private DNS name",
"Value": {
"Fn::GetAtt": [
"EbsInstance",
"PrivateDnsName"
]
}
},
"PrivateIp": {
"Description": "The instance private IP address",
"Value": {
"Fn::GetAtt": [
"EbsInstance",
"PrivateIp"
]
}
}
},
"Parameters": {
"App": {
"Description": "App",
"MinLength": "1",
"Type": "String"
},
"CreationPolicyResourceSignalCount": {
"Default": "1",
"Description": "Number of signals to wait on to consider an instance ready",
"Type": "String"
},
"CreationPolicyResourceSignalTimeout": {
"Default": "PT1H",
"Description": "How long to wait for an instance to signal before timing out",
"Type": "String"
},
"EbsDeleteOnTermination": {
"Default": true,
"Description": "Determines whether to delete the volume on instance termination. The default value is true",
"Type": "String"
},
"EbsDeviceName": {
"Default": "/dev/xvdf",
"Description": "The name of the device within Amazon EC2",
"Type": "String"
},
"EbsVolumeSize": {
"Default": "40",
"Description": "The size of the EBS (gp2) volume",
"Type": "String"
},
"EbsVolumeSnapshotId": {
"Default": "",
"Description": "The snapshot from which to create the new volume",
"Type": "String"
},
"Environment": {
"AllowedValues": [
"test",
"staging",
"production"
],
"ConstraintDescription": "must be test, staging, or production",
"Default": "test",
"Description": "Environment. Defaults to test",
"Type": "String"
},
"GpanelSnsTopic": {
"Description": "GpanelSnsTopic",
"MinLength": "1",
"Type": "String"
},
"IamRole": {
"Description": "IamRole",
"MinLength": "1",
"Type": "String"
},
"ImageId": {
"Description": "AMI",
"Type": "AWS::EC2::Image::Id"
},
"InstanceName": {
"Description": "The name of the instance being added",
"Type": "String"
},
"InstanceProfile": {
"Description": "InstanceProfile",
"MinLength": "1",
"Type": "String"
},
"InstanceType": {
"Default": "c4.large",
"Description": "Instance Type",
"Type": "String"
},
"KeyName": {
"Description": "Key Name",
"Type": "AWS::EC2::KeyPair::KeyName"
},
"LogRetentionInDays": {
"Default": "7",
"Description": "Days to retain logs in CloudWatch Logs",
"Type": "Number"
},
"ResourceBase": {
"Description": "S3 Base URL for stack resources",
"Type": "String"
},
"ResourceBucket": {
"Description": "S3 Bucket",
"Type": "String"
},
"Role": {
"Description": "Role",
"MinLength": "1",
"Type": "String"
},
"SecurityGroupIds": {
"Description": "List of security groups to assign to the instance",
"Type": "CommaDelimitedList"
},
"StackIdentifier": {
"Description": "Treeish or PID to represent the version of this stack. Related resources are similary named",
"Type": "String"
},
"StackInstance": {
"Description": "Stack name and Identifier",
"Type": "String"
},
"Subnet": {
"Description": "Subnets",
"Type": "AWS::EC2::Subnet::Id"
},
"Vpc": {
"Description": "VPC ID",
"Type": "AWS::EC2::VPC::Id"
},
"Zone": {
"Description": "AZs",
"Type": "AWS::EC2::AvailabilityZone::Name"
},
"ZoneId": {
"Description": "Zone ID",
"Type": "AWS::Route53::HostedZone::Id"
},
"ZoneName": {
"Description": "Zone Domain Name",
"MinLength": "1",
"Type": "String"
}
},
"Resources": {
"EbsInstance": {
"CreationPolicy": {
"ResourceSignal": {
"Count": {
"Ref": "CreationPolicyResourceSignalCount"
},
"Timeout": {
"Ref": "CreationPolicyResourceSignalTimeout"
}
}
},
"Metadata": {
"AWS::CloudFormation::Authentication": {
"CoreS3ResourceBucketAuth": {
"buckets": [
{
"Ref": "ResourceBucket"
}
],
"roleName": {
"Ref": "IamRole"
},
"type": "s3"
}
},
"AWS::CloudFormation::Init": {
"GpanelConfigset": {
"commands": {
"/root/gpanel.sh": {
"command": "/root/gpanel.sh",
"cwd": "/root",
"env": {
"AWS_DEFAULT_REGION": {
"Ref": "AWS::Region"
},
"ROUTE53_DOMAIN": {
"Ref": "ZoneName"
},
"ROUTE53_ZONEID": {
"Ref": "ZoneId"
},
"TOPIC": {
"Ref": "GpanelSnsTopic"
}
}
}
},
"files": {
"/etc/init.d/route53": {
"authentication": "CoreS3ResourceBucketAuth",
"group": "root",
"mode": "000755",
"owner": "root",
"source": {
"Fn::Join": [
"/",
[
{
"Ref": "ResourceBase"
},
{
"Ref": "StackInstance"
},
"resources",
"route53.init"
]
]
}
},
"/home/ubuntu/.ssh/id_rsa": {
"Fn::If": [
"test",
{
"authentication": "CoreS3ResourceBucketAuth",
"group": "ubuntu",
"mode": "000400",
"owner": "ubuntu",
"source": {
"Fn::Join": [
"/",
[
{
"Ref": "ResourceBase"
},
{
"Ref": "StackInstance"
},
"resources",
"github-cloudformation-test"
]
]
}
},
{
"Ref": "AWS::NoValue"
}
]
},
"/root/gpanel.sh": {
"authentication": "CoreS3ResourceBucketAuth",
"group": "root",
"mode": "000755",
"owner": "root",
"source": {
"Fn::Join": [
"/",
[
{
"Ref": "ResourceBase"
},
{
"Ref": "StackInstance"
},
"resources",
"gpanel.sh"
]
]
}
},
"/usr/local/sbin/route53": {
"authentication": "CoreS3ResourceBucketAuth",
"group": "root",
"mode": "000755",
"owner": "root",
"source": {
"Fn::Join": [
"/",
[
{
"Ref": "ResourceBase"
},
{
"Ref": "StackInstance"
},
"resources",
"route53.sh"
]
]
}
}
}
},
"PuppetConfigset": {
"commands": {
"/root/puppet.sh": {
"command": "/root/puppet.sh",
"cwd": "/root",
"env": {
"AWS_DEFAULT_REGION": {
"Ref": "AWS::Region"
},
"BRANCH": "master",
"ENVIRONMENT": {
"Ref": "Environment"
}
}
}
},
"files": {
"/root/puppet.sh": {
"authentication": "CoreS3ResourceBucketAuth",
"group": "root",
"mode": "000755",
"owner": "root",
"source": {
"Fn::Join": [
"/",
[
{
"Ref": "ResourceBase"
},
{
"Ref": "StackInstance"
},
"resources",
"puppet.sh"
]
]
}
},
"/tmp/awslogs.conf": {
"content": {
"Fn::Join": [
"",
[
"[general]\n",
"state_file= /var/awslogs/state/agent-state\n",
"[/var/log/syslog]\n",
"file = /var/log/syslog\n",
"log_group_name = ",
{
"Ref": "LogGroup"
},
"\n",
"log_stream_name = {hostname}/syslog\n",
"datetime_format = %b %d %H:%M:%S\n",
"[/var/log/messages]\n",
"file = /var/log/messages\n",
"log_group_name = ",
{
"Ref": "LogGroup"
},
"\n",
"log_stream_name = {hostname}/messages\n",
"datetime_format = %b %d %H:%M:%S\n",
"[/var/log/cloud-init.log]\n",
"file = /var/log/cloud-init.log\n",
"log_group_name = ",
{
"Ref": "LogGroup"
},
"\n",
"log_stream_name = {hostname}/cloud-init.log\n",
"datetime_format = \n",
"[/var/log/cloud-init.log]\n",
"file = /var/log/cloud-init.log\n",
"log_group_name = ",
{
"Ref": "LogGroup"
},
"\n",
"log_stream_name = {hostname}/cloud-init.log\n",
"datetime_format = \n",
"[/var/log/cfn-init-cmd.log]\n",
"file = /var/log/cfn-init-cmd.log\n",
"log_group_name = ",
{
"Ref": "LogGroup"
},
"\n",
"log_stream_name = {hostname}/cfn-init-cmd.log\n",
"datetime_format = \n",
"[/var/log/cfn-init.log]\n",
"file = /var/log/cfn-init.log\n",
"log_group_name = ",
{
"Ref": "LogGroup"
},
"\n",
"log_stream_name = {hostname}/cfn-init.log\n",
"datetime_format = \n",
"[/var/log/cfn-hup.log]\n",
"file = /var/log/cfn-hup.log\n",
"log_group_name = ",
{
"Ref": "LogGroup"
},
"\n",
"log_stream_name = {hostname}/cfn-hup.log\n",
"datetime_format = \n",
"[/var/log/cfn-wire.log]\n",
"file = /var/log/cfn-wire.log\n",
"log_group_name = ",
{
"Ref": "LogGroup"
},
"\n",
"log_stream_name = {hostname}/cfn-wire.log\n",
"datetime_format = \n"
]
]
},
"group": "root",
"mode": "000444",
"owner": "root"
}
}
},
"configSets": {
"default": [
"GpanelConfigset",
"PuppetConfigset"
]
}
},
"facter": {
"app": {
"Ref": "App"
},
"environment": {
"Ref": "Environment"
},
"puppet_autorole": "true",
"role": {
"Ref": "Role"
}
}
},
"Properties": {
"AvailabilityZone": {
"Ref": "Zone"
},
"BlockDeviceMappings": [
{
"DeviceName": {
"Ref": "EbsDeviceName"
},
"Ebs": {
"DeleteOnTermination": {
"Ref": "EbsDeleteOnTermination"
},
"Encrypted": true,
"SnapshotId": {
"Fn::If": [
"EbsVolumeSnapshotIdIsPresent",
{
"Ref": "EbsVolumeSnapshotId"
},
{
"Ref": "AWS::NoValue"
}
]
},
"VolumeSize": {
"Ref": "EbsVolumeSize"
},
"VolumeType": "gp2"
}
}
],
"EbsOptimized": true,
"IamInstanceProfile": {
"Ref": "InstanceProfile"
},
"ImageId": {
"Ref": "ImageId"
},
"InstanceType": {
"Ref": "InstanceType"
},
"KeyName": {
"Ref": "KeyName"
},
"Monitoring": "true",
"SecurityGroupIds": {
"Ref": "SecurityGroupIds"
},
"SubnetId": {
"Ref": "Subnet"
},
"Tags": [
{
"Key": "monitored",
"Value": "true"
},
{
"Key": "app",
"Value": {
"Ref": "App"
}
},
{
"Key": "role",
"Value": {
"Ref": "Role"
}
},
{
"Key": "env",
"Value": {
"Ref": "Environment"
}
},
{
"Key": "provisioner",
"Value": "gh-aws:cloudformation"
},
{
"Key": "Name",
"Value": "EbsInstance"
}
],
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"#!/bin/bash -x\n",
"# 0 \n",
"/sbin/ifconfig eth0 mtu 1436 up\n",
"/usr/bin/apt-get install -y python-setuptools\n",
"/usr/bin/easy_install --upgrade awscli\n",
"/usr/bin/easy_install ",
"https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n",
"STACK_STATE=$(aws cloudformation describe-stacks",
" --region",
{
"Ref": "AWS::StackName"
},
" --stack-name",
{
"Ref": "AWS::StackName"
},
" --query 'Stacks[*].StackStatus'",
" --output text)\n",
"/usr/local/bin/cfn-init -v ",
" --configsets default ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource EbsInstance ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n",
"cfn_init_res=$?\n",
"if [ echo $STACK_STATE | grep -q ROLLBACK ]; then\n",
" cfn_init_res=0\n",
"fi\n",
"/usr/local/bin/cfn-signal -e $cfn_init_res ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource EbsInstance ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n",
"cat /var/log/cfn-init.log \n"
]
]
}
}
},
"Type": "AWS::EC2::Instance"
},
"LogGroup": {
"Properties": {
"RetentionInDays": {
"Ref": "LogRetentionInDays"
}
},
"Type": "AWS::Logs::LogGroup"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,53 +0,0 @@
function diffFromJSON(json) {
if (json.pure != null) { return new Diff({ pure: new Patch(json.pure) }); }
if (json.roll != null) {
return new Diff({
roll: {
extract: json.roll.extract,
unwrap: new Syntax(json.roll.unwrap, function(x) { return diffFromJSON(x); })
}
});
}
}
function Diff(object) {
if (object.pure != null) { this.pure = object.pure; }
if (object.roll != null) { this.roll = object.roll; }
return this;
}
// forall a b. Diff a -> (a -> b) -> Diff b
Diff.prototype.map = function(transform) {
if (this.pure != null) { return new Diff({ pure: transform(this.pure) }); }
if (this.roll != null) {
return new Diff({
roll: {
extract: this.roll.extract,
unwrap: this.roll.unwrap.map(function(x) { return x.map(transform); })
}
});
}
}
// forall a. Diff a -> (Syntax a -> a) -> a
Diff.prototype.cata = function(transform) {
if (this.pure != null) { return this.pure; }
if (this.roll != null) {
return transform(this.roll.unwrap.map(function(diff) {
return diff.cata(transform);
}))
}
}
/// Diff -> String -> String -> DOM
function diffToDOM(diff, which, source) {
if (diff.pure != null) { return diff.pure; }
function getRange(diff) {
if (diff.pure != null) { return diff.pure["data-range"]; }
if (diff.roll != null) { return diff.roll.extract[which]; }
}
return rangeAndSyntaxToDOM(getRange(diff), diff.roll.unwrap, source, getRange, function(diff) {
return diffToDOM(diff, which, source);
})
}

View File

@ -1,77 +0,0 @@
function diffFromJSON(json) {
if (json.pure != null) {
return new Diff({
pure: new Patch(json.pure)
});
}
if (json.roll != null) {
return new Diff({
roll: {
extract: json.roll.extract,
unwrap: new Syntax(json.roll.unwrap, function(x) {
return diffFromJSON(x);
})
}
});
}
}
function Diff(object) {
if (object.pure != null) {
this.pure = object.pure;
}
if (object.roll != null) {
this.roll = object.roll;
}
return this;
}
// forall a b. Diff a -> (a -> b) -> Diff b
Diff.prototype.map = function(transform) {
if (this.pure != null) {
return new Diff({
pure: transform(this.pure)
});
}
if (this.roll != null) {
return new Diff({
roll: {
extract: this.roll.extract,
unwrap: this.roll.unwrap.map(function(x) {
return x.map(transform);
})
}
});
}
}
// forall a. Diff a -> (Syntax a -> a) -> a
Diff.prototype.cata = function(transform) {
if (this.pure != null) {
return this.pure;
}
if (this.roll != null) {
return transform(this.roll.unwrap.map(function(diff) {
return diff.cata(transform);
}))
}
}
/// Diff -> String -> String -> DOM
function diffToDOM(diff, which, source) {
if (diff.pure != null) {
return diff.pure;
}
function getRange(diff) {
if (diff.pure != null) {
return diff.pure["data-range"];
}
if (diff.roll != null) {
return diff.roll.extract[which];
}
}
return rangeAndSyntaxToDOM(getRange(diff), diff.roll.unwrap, source, getRange, function(diff) {
return diffToDOM(diff, which, source);
})
}

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 GitHub. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>PathToUISource</key>
<string>$(SRCROOT)/UI/index.html</string>
</dict>
</plist>

View File

@ -1,46 +0,0 @@
struct Info: Categorizable, CustomJSONConvertible, Equatable {
init(range: Range<Int>, lines: Range<Line>, columns: Range<Column>, categories: Set<String>) {
self.range = range
self.lines = lines
self.columns = columns
self.categories = categories
}
init(range: Range<String.CharacterView.Index>, lines: Range<Line>, columns: Range<Column>, categories: Set<String>) {
// FIXME: this is terrible. see also https://github.com/github/semantic-diff/issues/136
self.range = Int(String(range.startIndex))!..<Int(String(range.endIndex))!
self.lines = lines
self.columns = columns
self.categories = categories
}
let range: Range<Int>
let lines: Range<Line>
let columns: Range<Column>
// MARK: Categorizable
let categories: Set<String>
// MARK: CustomJSONConvertible
var JSON: Doubt.JSON {
return [
"range": range.JSON,
"lines": lines.JSON,
"columns": columns.JSON,
"categories": Array(categories).JSON
]
}
}
func == (left: Info, right: Info) -> Bool {
return left.range == right.range && left.categories == right.categories && left.lines == left.lines && left.columns == right.columns
}
import Madness
import Doubt

View File

@ -1,45 +0,0 @@
// Copyright © 2015 GitHub. All rights reserved.
typealias TSDocument = COpaquePointer
typealias TSLanguage = COpaquePointer
extension TSNode {
func category(document: TSDocument) throws -> String {
guard let category = String.fromCString(ts_node_name(self, document)) else { throw "couldnt make a String from the node name" }
return category
}
var range: Range<Int> {
let start = ts_node_pos(self).chars
return start..<(start + ts_node_size(self).chars)
}
func substring(string: String) throws -> String {
guard let result = String(string.utf16[range]) else { throw "could not make a string from utf16 range '\(range)'" }
return result
}
var children: ChildrenCollection {
return ChildrenCollection(node: self, count: ts_node_child_count(self), child: ts_node_child)
}
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
subscript (index: Int) -> TSNode {
return child(node, index)
}
let startIndex = 0
var endIndex: Int {
return count
}
}

View File

@ -1,93 +0,0 @@
private func unified(term: Term, source: String) -> String {
return term.cata { info, syntax -> (String, Range<Int>?) in
switch syntax {
case .Leaf:
return (String(source.utf16[info.range]), info.range)
case let .Indexed(i):
return (unified(info.range, children: i, source: source), info.range)
case let .Fixed(f):
return (unified(info.range, children: f, source: source), info.range)
case let .Keyed(k):
return (unified(info.range, children: k.values.sort(isOrderedBefore), source: source), info.range)
}
}.0
}
private func isOrderedBefore(a: (String, Range<Int>?), _ b: (String, Range<Int>?)) -> Bool {
if let a = a.1, b = b.1 {
return a.startIndex < b.startIndex
}
return false
}
private var isTTY = isatty(STDOUT_FILENO) != 0
private var isDumb = String.fromCString(getenv("TERM")).map { $0.hasPrefix("dumb") } ?? true
private var shouldFormat = isTTY && !isDumb
private struct Attribute {
let colour: Colour
let style: Style
enum Colour: Int {
case Black = 30
case Red
case Green
case Yellow
case Blue
case Purple
case Cyan
case White
}
enum Style: Int {
case Normal = 0
case Bold = 1
case Underline = 4
}
func wrap(string: String) -> String {
return shouldFormat
? "\u{001B}[\(style.rawValue);\(colour.rawValue)m\(string)\u{001B}[0m"
: string
}
}
private func unified(patch: Patch<Term>, before: String, after: String) -> String {
return (patch.state.before.map { Attribute(colour: .Red, style: .Bold).wrap("{-\(unified($0, source: before))-}") } ?? "")
+ (patch.state.after.map { Attribute(colour: .Green, style: .Bold).wrap("{+\(unified($0, source: after))+}") } ?? "")
}
private func range(patch: Patch<Term>) -> Range<Int>? {
return patch.state.after?.extract.range
}
private func unified(range: Range<Int>, children: [(String, Range<Int>?)], source: String) -> String {
var previous = range.startIndex
var out: String = ""
for (string, range) in children {
if let range = range {
out += String(source.utf16[previous..<range.startIndex])
previous = range.endIndex
}
out += string
}
return out + String(source.utf16[previous..<range.endIndex])
}
func unified(diff: Diff, before: String, after: String) -> String {
return diff.map { (unified($0, before: before, after: after), range($0)) }.cata { info, syntax in
switch syntax {
case .Leaf:
return (String(after.utf16[info.1.range]), info.1.range)
case let .Indexed(i):
return (unified(info.1.range, children: i, source: after), info.1.range)
case let .Fixed(f):
return (unified(info.1.range, children: f, source: after), info.1.range)
case let .Keyed(k):
return (unified(info.1.range, children: k.values.sort(isOrderedBefore), source: after), info.1.range)
}
}.0
}
import Doubt

View File

@ -1,4 +0,0 @@
#import "tree_sitter/runtime.h"
extern TSLanguage *ts_language_javascript();
extern TSLanguage *ts_language_c();

View File

@ -1,205 +0,0 @@
import Cocoa
import Doubt
import Prelude
import Madness
func benchmark<T>(label: String? = nil, _ f: () throws -> T) rethrows -> T {
let start = NSDate.timeIntervalSinceReferenceDate()
let result = try f()
let end = NSDate.timeIntervalSinceReferenceDate()
print((label.map { "\($0): " } ?? "") + "\(end - start)s")
return result
}
extension String: ErrorType {}
typealias Term = Cofree<String, Info>
typealias Diff = Free<Term.Leaf, (Term.Annotation, Term.Annotation), Patch<Term>>
typealias Parser = String throws -> Term
struct Source {
init(_ argument: String) throws {
let supportedSchemes = [ "http", "https", "file" ]
if let URL = NSURL(string: argument) where supportedSchemes.contains(URL.scheme) {
self.URL = URL
} else {
self.URL = NSURL(fileURLWithPath: argument)
}
contents = try NSString(contentsOfURL: URL, encoding: NSUTF8StringEncoding) as String
}
let URL: NSURL
var type: String {
if let pathExtension = URL.pathExtension where pathExtension != "" { return pathExtension }
return URL.fragment ?? ""
}
let contents: String
private static let languagesByType: [String:TSLanguage] = [
"js": ts_language_javascript(),
"c": ts_language_c(),
"h": ts_language_c(),
]
}
extension String.UTF16View {
subscript (range: Range<Int>) -> String.UTF16View {
return self[Index(_offset: range.startIndex)..<Index(_offset: range.endIndex)]
}
}
/// Allow predicates to occur in pattern matching.
func ~= <A> (left: A -> Bool, right: A) -> Bool {
return left(right)
}
func termWithInput(language: TSLanguage)(_ string: String) throws -> Term {
let keyedProductions: Set<String> = [ "object" ]
let fixedProductions: Set<String> = [ "pair", "rel_op", "math_op", "bool_op", "bitwise_op", "type_op", "math_assignment", "assignment", "subscript_access", "member_access", "new_expression", "function_call", "function", "ternary" ]
let document = ts_document_make()
defer { ts_document_free(document) }
return try string.withCString {
ts_document_set_language(document, language)
ts_document_set_input_string(document, $0)
ts_document_parse(document)
let root = ts_document_root_node(document)
return try Cofree
.ana { node, category in
let count = node.namedChildren.count
guard count > 0 else { return try Syntax.Leaf(node.substring(string)) }
switch category {
case fixedProductions.contains:
return try .Fixed(node.namedChildren.map {
($0, try $0.category(document))
})
case keyedProductions.contains:
return try .Keyed(Dictionary(elements: node.namedChildren.map {
switch try $0.category(document) {
case "pair":
return try ($0.namedChildren[0].substring(string), ($0, "pair"))
default:
// We might have a comment inside an object literal. It should still be assigned a key, however.
return try (try node.substring(string), ($0, $0.category(document)))
}
}))
default:
return try .Indexed(node.namedChildren.map {
($0, try $0.category(document))
})
}
} (root, "program")
.map { node, category in
// TODO: Calculate line and column from TSNodes
Info(range: node.range, lines: 0..<1, columns: 0..<1, categories: [ category ])
}
}
}
func toTerm(term: CofreeJSON) -> Term {
let lines = term.extract.0
let columns = term.extract.1
let range = term.extract.2
let annotation = Info(range: range, lines: lines, columns: columns, categories: [])
switch term.unwrap {
case let .Leaf(a):
return Term(Info(range: range, lines: lines, columns: columns, categories: a.categories), Syntax<Term, String>.Leaf(String(a)))
case let .Indexed(i):
return Term(annotation, .Indexed(i.map(toTerm)))
case let .Fixed(f):
return Term(annotation, .Fixed(f.map(toTerm)))
case let .Keyed(k):
return Term(annotation, .Keyed(Dictionary(elements: k.map { ($0, toTerm($1)) })))
}
}
func lines(input: String) -> Term {
var lines: [Term] = []
var previous = 0
var lineNumber = 0
input.enumerateSubstringsInRange(input.characters.indices, options: .ByLines) { (line, _, enclosingRange, _) in
let range: Range<Int> = previous..<(previous + enclosingRange.count)
previous = range.endIndex
if let line = line {
lineNumber += 1
lines.append(Term(Info(range: range, lines: 0..<lineNumber, columns: 0..<1, categories: []), Syntax.Leaf(line)))
}
}
return Term(Info(range: 0..<input.utf16.count, lines: 0..<lineNumber, columns: 0..<1, categories: []), .Indexed(lines))
}
func parserForType(type: String) -> String throws -> Term {
switch type {
case "json":
return { (input: String) throws -> Term in
switch parse(json, input: input.characters) {
case let .Right(term):
return toTerm(term)
case let .Left(error):
throw error.description
}
}
default:
if let parser = Source.languagesByType[type].map(termWithInput) {
return parser
}
return lines
}
}
extension ForwardIndexType {
/// The range encompassing a single index.
var range: Range<Self> {
return self..<self.successor()
}
}
let cost = Diff.sum(Patch.sum(Term.size))
func refineLeafReplacement(aString: String, _ bString: String)(_ patch: Patch<Term>) -> Diff {
guard case let .Replace(.Unroll(aExtract, .Leaf), .Unroll(bExtract, .Leaf)) = patch else { return .Pure(patch) }
let a = aString.utf16[aExtract.range].enumerate().map { Term(Info(range: (aExtract.range.startIndex + $0).range, lines: aExtract.lines, columns: aExtract.columns, categories: aExtract.categories), .Leaf(String($1))) }
let b = bString.utf16[bExtract.range].enumerate().map { Term(Info(range: (bExtract.range.startIndex + $0).range, lines: bExtract.lines, columns: bExtract.columns, categories: bExtract.categories), .Leaf(String($1))) }
return .Roll((aExtract, bExtract), .Indexed(SES(a, b, cost: cost, recur: { Term.equals(annotation: const(true), leaf: ==)($0, $1) ? Term.zip($0, $1).map(Diff.init) : Diff.Replace($0, $1) })))
}
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")
guard let uiPath = NSBundle.mainBundle().infoDictionary?["PathToUISource"] as? String else { throw "need ui path" }
guard aSource.type == bSource.type else { throw "cant compare files of different types" }
let parser = parserForType(aSource.type)
let a = try benchmark("parsing source a") { try parser(aSource.contents) }
let b = try benchmark("parsing source b") { try parser(bSource.contents) }
let initialDiff = benchmark("diffing") { Interpreter<Term>(equal: Term.equals(annotation: const(true), leaf: ==), comparable: Interpreter<Term>.comparable { $0.extract.categories }, cost: cost).run(a, b) }
let diff = benchmark("diffing within leaves") { initialDiff.flatMap(refineLeafReplacement(aSource.contents, bSource.contents)) }
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.JSON }, leaf: Doubt.JSON.String) } }, leaf: Doubt.JSON.String, annotation: {
[
"before": $0.JSON,
"after": $1.JSON,
]
}),
]
let data = JSON.serialize()
try data.writeToURL(jsonURL, options: .DataWritingAtomic)
let components = NSURLComponents()
components.scheme = "file"
components.path = uiPath
components.query = jsonURL.absoluteString
if let URL = components.URL {
NSWorkspace.sharedWorkspace().openURL(URL)
}
case .Unified:
print(benchmark("formatting unified diff") { unified(diff, before: aSource.contents, after: bSource.contents) })
}

View File

@ -1,17 +0,0 @@
#!/bin/bash
cd `dirname $0`/../External/tree-sitter
case "$1" in
""|build)
script/configure.sh
make "$PRODUCT_NAME"
;;
clean)
script/clean.sh
;;
*)
echo "I don't know how to '$1'"
exit 1
;;
esac