1
1
mirror of https://github.com/github/semantic.git synced 2024-12-25 16:02:43 +03:00

Merge pull request #38 from github/algebraic-hashing

Algebraic hashing
This commit is contained in:
Rob Rix 2015-09-30 10:26:25 -04:00
commit 96ff73726f
3 changed files with 111 additions and 2 deletions

View File

@ -46,6 +46,7 @@
D4C2B1421BB3474C0096F92A /* SwiftXPC.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D4413FD61BB0531E00E3C3C1 /* SwiftXPC.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D4C2B1421BB3474C0096F92A /* SwiftXPC.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D4413FD61BB0531E00E3C3C1 /* SwiftXPC.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
D4C2B1431BB3474C0096F92A /* SourceKittenFramework.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D4413FD41BB052ED00E3C3C1 /* SourceKittenFramework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D4C2B1431BB3474C0096F92A /* SourceKittenFramework.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D4413FD41BB052ED00E3C3C1 /* SourceKittenFramework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
D4C2B1441BB347500096F92A /* Doubt.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D4AAE4FD1B5AE22E004E581F /* Doubt.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D4C2B1441BB347500096F92A /* Doubt.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D4AAE4FD1B5AE22E004E581F /* Doubt.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
D4D7F3171BBB22E500AAB0C0 /* Hash.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D7F3161BBB22E500AAB0C0 /* Hash.swift */; settings = {ASSET_TAGS = (); }; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -109,6 +110,7 @@
D4AAE53E1B5AE2D0004E581F /* StringLiteralConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringLiteralConvertible.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>"; }; D4AAE53F1B5AE2D0004E581F /* Syntax.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Syntax.swift; sourceTree = "<group>"; };
D4AAE54B1B5AE42D004E581F /* Equatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Equatable.swift; sourceTree = "<group>"; }; D4AAE54B1B5AE42D004E581F /* Equatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Equatable.swift; sourceTree = "<group>"; };
D4D7F3161BBB22E500AAB0C0 /* Hash.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Hash.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -196,6 +198,7 @@
D4413FEE1BB06D4C00E3C3C1 /* Dictionary.swift */, D4413FEE1BB06D4C00E3C3C1 /* Dictionary.swift */,
D4413FF01BB08FDC00E3C3C1 /* JSON.swift */, D4413FF01BB08FDC00E3C3C1 /* JSON.swift */,
D4A71DC41BB45B850051416D /* Vertex.swift */, D4A71DC41BB45B850051416D /* Vertex.swift */,
D4D7F3161BBB22E500AAB0C0 /* Hash.swift */,
D4AAE5001B5AE22E004E581F /* Supporting Files */, D4AAE5001B5AE22E004E581F /* Supporting Files */,
); );
path = Doubt; path = Doubt;
@ -375,6 +378,7 @@
D4413FEF1BB06D4C00E3C3C1 /* Dictionary.swift in Sources */, D4413FEF1BB06D4C00E3C3C1 /* Dictionary.swift in Sources */,
D4AAE5481B5AE2D0004E581F /* String.swift in Sources */, D4AAE5481B5AE2D0004E581F /* String.swift in Sources */,
D4AAE5411B5AE2D0004E581F /* Diff.swift in Sources */, D4AAE5411B5AE2D0004E581F /* Diff.swift in Sources */,
D4D7F3171BBB22E500AAB0C0 /* Hash.swift in Sources */,
D4AAE5401B5AE2D0004E581F /* Array.swift in Sources */, D4AAE5401B5AE2D0004E581F /* Array.swift in Sources */,
D4AAE54C1B5AE42D004E581F /* Equatable.swift in Sources */, D4AAE54C1B5AE42D004E581F /* Equatable.swift in Sources */,
D4A71DC51BB45B850051416D /* Vertex.swift in Sources */, D4A71DC51BB45B850051416D /* Vertex.swift in Sources */,

View File

@ -0,0 +1,78 @@
public enum Hash: Hashable {
case Sequence([Hash])
case String(Swift.String)
case Int(Swift.Int)
public static func Case(label: Swift.String, _ hashes: Hash...) -> Hash {
return .Sequence([ .String(label) ] + hashes)
}
public static func Case(index: Swift.Int, _ hashes: Hash...) -> Hash {
return .Sequence([ .Int(index) ] + hashes)
}
public init<A: AlgebraicHashable>(_ hashable: A) {
self = hashable.hash
}
public init<A: Hashable>(_ hashable: A) {
self = .Int(hashable.hashValue)
}
public var hashValue: Swift.Int {
switch self {
case let .Sequence(s):
// Bob Jenkins one-at-a-time hash: https://en.wikipedia.org/wiki/Jenkins_hash_function
var hash = 0
for each in s {
hash += each.hashValue
hash += hash << 10
hash ^= hash >> 6
}
hash += hash << 3
hash ^= hash >> 11
hash += hash << 15
return hash
case let .String(s):
return s.hashValue
case let .Int(i):
return i.hashValue
}
}
}
public func == (left: Hash, right: Hash) -> Bool {
switch (left, right) {
case let (.Sequence(a), .Sequence(b)):
return a == b
case let (.String(a), .String(b)):
return a == b
case let (.Int(a), .Int(b)):
return a == b
default:
return false
}
}
public protocol AlgebraicHashable: Hashable {
var hash: Hash { get }
}
extension AlgebraicHashable {
public var hashValue: Int {
return hash.hashValue
}
}
extension RawRepresentable where RawValue: Hashable {
public var hash: Hash {
return Hash(rawValue)
}
}
extension RawRepresentable where RawValue: AlgebraicHashable {
public var hash: Hash {
return Hash(rawValue)
}
}

View File

@ -1,4 +1,4 @@
public enum Term: CustomDebugStringConvertible, CustomDocConvertible, CustomStringConvertible, Equatable { public enum Term: CustomDebugStringConvertible, CustomDocConvertible, CustomStringConvertible, AlgebraicHashable {
public init(_ out: Syntax<Term>) { public init(_ out: Syntax<Term>) {
self = .Roll(out) self = .Roll(out)
} }
@ -27,6 +27,11 @@ public enum Term: CustomDebugStringConvertible, CustomDocConvertible, CustomStri
} }
public var hash: Hash {
return syntax.hash
}
public static var Empty: Term { public static var Empty: Term {
return Term(.Empty) return Term(.Empty)
} }
@ -180,7 +185,8 @@ public enum Syntax<Payload>: CustomDebugStringConvertible, CustomDocConvertible
return ".Apply(\(f), [ \(s) ])" return ".Apply(\(f), [ \(s) ])"
case let .Abstract(parameters, body): case let .Abstract(parameters, body):
let s = parameters.map { String(reflecting: $0) }.joinWithSeparator(", ") let s = parameters.map { String(reflecting: $0) }.joinWithSeparator(", ")
return ".Abstract([ \(s) ], \(body))" let b = body.map { String(reflecting: $0) }.joinWithSeparator("\n")
return ".Abstract([ \(s) ], \(b))"
case let .Assign(n, v): case let .Assign(n, v):
return ".Assign(\(n), \(v))" return ".Assign(\(n), \(v))"
case let .Variable(n): case let .Variable(n):
@ -215,3 +221,24 @@ public enum Syntax<Payload>: CustomDebugStringConvertible, CustomDocConvertible
} }
} }
} }
extension Syntax where Payload: AlgebraicHashable {
public var hash: Hash {
switch self {
case .Empty:
return .Case("Empty")
case let .Apply(f, vs):
return .Case("Apply", .Sequence([ f.hash ] + vs.map { $0.hash }))
case let .Abstract(parameters, body):
return .Case("Abstract", .Sequence(parameters.map { $0.hash }), .Sequence(body.map { $0.hash }))
case let .Assign(name, value):
return .Case("Assign", .String(name), value.hash)
case let .Variable(n):
return .Case("Variable", .String(n))
case let .Literal(s):
return .Case("Literal", .String(s))
case let .Group(n, vs):
return .Case("Group", n.hash, .Sequence(vs.map { $0.hash }))
}
}
}