mirror of
https://github.com/github/semantic.git
synced 2024-12-25 07:55:12 +03:00
Merge pull request #40 from github/syntactic-categorization
Syntactic categorization
This commit is contained in:
commit
cb5b7c0b33
@ -19,6 +19,8 @@
|
||||
D4413FE91BB055B500E3C3C1 /* Commandant.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4413FE71BB055AE00E3C3C1 /* Commandant.framework */; };
|
||||
D4413FEF1BB06D4C00E3C3C1 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4413FEE1BB06D4C00E3C3C1 /* Dictionary.swift */; };
|
||||
D4413FF11BB08FDC00E3C3C1 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4413FF01BB08FDC00E3C3C1 /* JSON.swift */; };
|
||||
D45A36C91BBC667D00BE3DDE /* Category.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45A36C81BBC667D00BE3DDE /* Category.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
D45A36CD1BBC75DF00BE3DDE /* Info.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45A36CC1BBC75DF00BE3DDE /* Info.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
D4A71DC51BB45B850051416D /* Vertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A71DC41BB45B850051416D /* Vertex.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
D4A71DC71BB4AC9E0051416D /* VertexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A71DC61BB4AC9E0051416D /* VertexTests.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
D4AAE50E1B5AE22E004E581F /* Doubt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4AAE4FD1B5AE22E004E581F /* Doubt.framework */; };
|
||||
@ -94,6 +96,8 @@
|
||||
D4413FE71BB055AE00E3C3C1 /* Commandant.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Commandant.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
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 /* Category.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Category.swift; sourceTree = "<group>"; };
|
||||
D45A36CC1BBC75DF00BE3DDE /* Info.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Info.swift; sourceTree = "<group>"; };
|
||||
D4A71DC41BB45B850051416D /* Vertex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vertex.swift; sourceTree = "<group>"; };
|
||||
D4A71DC61BB4AC9E0051416D /* VertexTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VertexTests.swift; sourceTree = "<group>"; };
|
||||
D4AAE4FD1B5AE22E004E581F /* Doubt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Doubt.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@ -199,6 +203,8 @@
|
||||
D4413FF01BB08FDC00E3C3C1 /* JSON.swift */,
|
||||
D4A71DC41BB45B850051416D /* Vertex.swift */,
|
||||
D4D7F3161BBB22E500AAB0C0 /* Hash.swift */,
|
||||
D45A36C81BBC667D00BE3DDE /* Category.swift */,
|
||||
D45A36CC1BBC75DF00BE3DDE /* Info.swift */,
|
||||
D4AAE5001B5AE22E004E581F /* Supporting Files */,
|
||||
);
|
||||
path = Doubt;
|
||||
@ -379,6 +385,7 @@
|
||||
D4AAE5481B5AE2D0004E581F /* String.swift in Sources */,
|
||||
D4AAE5411B5AE2D0004E581F /* Diff.swift in Sources */,
|
||||
D4D7F3171BBB22E500AAB0C0 /* Hash.swift in Sources */,
|
||||
D45A36C91BBC667D00BE3DDE /* Category.swift in Sources */,
|
||||
D4AAE5401B5AE2D0004E581F /* Array.swift in Sources */,
|
||||
D4AAE54C1B5AE42D004E581F /* Equatable.swift in Sources */,
|
||||
D4A71DC51BB45B850051416D /* Vertex.swift in Sources */,
|
||||
@ -386,6 +393,7 @@
|
||||
D432D4731BA9C55300F3FABC /* Stream.swift in Sources */,
|
||||
D4AAE5421B5AE2D0004E581F /* Doc.swift in Sources */,
|
||||
D432D4771BA9FE6A00F3FABC /* Comparable.swift in Sources */,
|
||||
D45A36CD1BBC75DF00BE3DDE /* Info.swift in Sources */,
|
||||
D4AAE5461B5AE2D0004E581F /* Parse.swift in Sources */,
|
||||
D432D4751BA9D6A400F3FABC /* Memo.swift in Sources */,
|
||||
D4AAE5491B5AE2D0004E581F /* StringLiteralConvertible.swift in Sources */,
|
||||
|
22
prototype/Doubt/Category.swift
Normal file
22
prototype/Doubt/Category.swift
Normal file
@ -0,0 +1,22 @@
|
||||
public enum Category: AlgebraicHashable {
|
||||
case Tag(String)
|
||||
|
||||
|
||||
public var tag: String {
|
||||
switch self {
|
||||
case let .Tag(s):
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
public var hash: Hash {
|
||||
return Hash("Tag", Hash(tag))
|
||||
}
|
||||
}
|
||||
|
||||
public func == (left: Category, right: Category) -> Bool {
|
||||
switch (left, right) {
|
||||
case let (.Tag(a), .Tag(b)):
|
||||
return a == b
|
||||
}
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
public enum Diff: Comparable, CustomDebugStringConvertible, CustomDocConvertible {
|
||||
case Patch(Term, Term)
|
||||
indirect case Copy(Syntax<Diff, String>)
|
||||
case Patch(Term<Info>, Term<Info>)
|
||||
indirect case Copy(Syntax<Diff, Info>)
|
||||
|
||||
public static func Insert(term: Term) -> Diff {
|
||||
public static func Insert(term: Term<Info>) -> Diff {
|
||||
return .Patch(.Empty, term)
|
||||
}
|
||||
|
||||
public static func Delete(term: Term) -> Diff {
|
||||
public static func Delete(term: Term<Info>) -> Diff {
|
||||
return .Patch(term, .Empty)
|
||||
}
|
||||
|
||||
public init(_ term: Term) {
|
||||
public init(_ term: Term<Info>) {
|
||||
switch term {
|
||||
case let .Roll(s):
|
||||
self = .Copy(s.map(Diff.init))
|
||||
@ -45,7 +45,7 @@ public enum Diff: Comparable, CustomDebugStringConvertible, CustomDocConvertible
|
||||
}
|
||||
}
|
||||
|
||||
public init(_ a: Term, _ b: Term) {
|
||||
public init(_ a: Term<Info>, _ b: Term<Info>) {
|
||||
if a == b {
|
||||
self = Diff(b)
|
||||
return
|
||||
@ -62,7 +62,7 @@ public enum Diff: Comparable, CustomDebugStringConvertible, CustomDocConvertible
|
||||
}
|
||||
}
|
||||
|
||||
public static func diff<C1: CollectionType, C2: CollectionType where C1.Index : RandomAccessIndexType, C1.Generator.Element == Term, C2.Index : RandomAccessIndexType, C2.Generator.Element == Term>(a: C1, _ b: C2) -> [Diff] {
|
||||
public static func diff<C1: CollectionType, C2: CollectionType where C1.Index : RandomAccessIndexType, C1.Generator.Element == Term<Info>, C2.Index : RandomAccessIndexType, C2.Generator.Element == Term<Info>>(a: C1, _ b: C2) -> [Diff] {
|
||||
func magnitude(diffs: Stream<(Diff, Int)>) -> Int {
|
||||
// return diffs.first?.magnitude ?? 0
|
||||
return diffs.map { $1 }.reduce(0, combine: +)
|
||||
@ -74,7 +74,7 @@ public enum Diff: Comparable, CustomDebugStringConvertible, CustomDocConvertible
|
||||
})
|
||||
}
|
||||
|
||||
func diff(a: Stream<Term>, _ b: Stream<Term>) -> Stream<(Diff, Int)> {
|
||||
func diff(a: Stream<Term<Info>>, _ b: Stream<Term<Info>>) -> Stream<(Diff, Int)> {
|
||||
switch (a, b) {
|
||||
case (.Nil, .Nil):
|
||||
return .Nil
|
||||
|
@ -1,20 +1,24 @@
|
||||
public func == (left: Term, right: Term) -> Bool {
|
||||
return left.syntax == right.syntax
|
||||
public func == <A: Equatable> (left: Term<A>, right: Term<A>) -> Bool {
|
||||
return equals(left.syntax, right.syntax, ==)
|
||||
}
|
||||
|
||||
public func == <F: Equatable, A: Equatable> (left: Syntax<F, A>, right: Syntax<F, A>) -> Bool {
|
||||
private func equals<F, A: Equatable>(left: Syntax<F, A>, _ right: Syntax<F, A>, _ recur: (F, F) -> Bool) -> Bool {
|
||||
switch (left, right) {
|
||||
case (.Empty, .Empty):
|
||||
return true
|
||||
case let (.Leaf(l1), .Leaf(l2)):
|
||||
return l1 == l2
|
||||
case let (.Branch(v1), .Branch(v2)):
|
||||
return v1 == v2
|
||||
return v1.count == v2.count && zip(v1, v2).reduce(true) { $0 && recur($1.0, $1.1) }
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public func == <F: Equatable, A: Equatable> (left: Syntax<F, A>, right: Syntax<F, A>) -> Bool {
|
||||
return equals(left, right, ==)
|
||||
}
|
||||
|
||||
public func == (left: Diff, right: Diff) -> Bool {
|
||||
switch (left, right) {
|
||||
case let (.Patch(a1, b1), .Patch(a2, b2)):
|
||||
|
@ -59,12 +59,10 @@ public func == (left: Hash, right: Hash) -> Bool {
|
||||
}
|
||||
}
|
||||
|
||||
public protocol CustomHashConvertible {
|
||||
public protocol AlgebraicHashable: Hashable {
|
||||
var hash: Hash { get }
|
||||
}
|
||||
|
||||
public protocol AlgebraicHashable: CustomHashConvertible, Hashable {}
|
||||
|
||||
extension AlgebraicHashable {
|
||||
public var hashValue: Int {
|
||||
return hash.hashValue
|
||||
|
18
prototype/Doubt/Info.swift
Normal file
18
prototype/Doubt/Info.swift
Normal file
@ -0,0 +1,18 @@
|
||||
public enum Info: Equatable {
|
||||
case Literal(String, Set<Category>)
|
||||
|
||||
public var categories: Set<Category> {
|
||||
switch self {
|
||||
case let .Literal(_, c):
|
||||
return c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func == (left: Info, right: Info) -> Bool {
|
||||
switch (left, right) {
|
||||
case let (.Literal(s1, c1), .Literal(s2, c2)):
|
||||
return s1 == s2 && c1 == c2
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
public enum Term: CustomDebugStringConvertible, CustomDocConvertible, CustomStringConvertible, AlgebraicHashable {
|
||||
public init(_ out: Syntax<Term, String>) {
|
||||
public enum Term<A>: CustomDebugStringConvertible, CustomDocConvertible, CustomStringConvertible {
|
||||
public init(_ out: Syntax<Term, A>) {
|
||||
self = .Roll(out)
|
||||
}
|
||||
|
||||
indirect case Roll(Syntax<Term, String>)
|
||||
indirect case Roll(Syntax<Term, A>)
|
||||
|
||||
public var syntax: Syntax<Term, String> {
|
||||
public var syntax: Syntax<Term, A> {
|
||||
switch self {
|
||||
case let .Roll(syntax):
|
||||
return syntax
|
||||
@ -13,22 +13,11 @@ public enum Term: CustomDebugStringConvertible, CustomDocConvertible, CustomStri
|
||||
}
|
||||
|
||||
public var debugDescription: String {
|
||||
switch self {
|
||||
case let .Roll(s):
|
||||
return s.debugDescription
|
||||
}
|
||||
return syntax.debugDescription
|
||||
}
|
||||
|
||||
public var doc: Doc {
|
||||
switch self {
|
||||
case let .Roll(s):
|
||||
return s.doc
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public var hash: Hash {
|
||||
return syntax.hash
|
||||
return syntax.doc
|
||||
}
|
||||
|
||||
|
||||
@ -36,90 +25,15 @@ public enum Term: CustomDebugStringConvertible, CustomDocConvertible, CustomStri
|
||||
return Term(.Empty)
|
||||
}
|
||||
|
||||
public static let Leaf = Syntax.Leaf >>> Roll
|
||||
public static let Branch: [Term] -> Term = Syntax.Branch >>> Roll
|
||||
|
||||
|
||||
// MARK: JSON representation.
|
||||
|
||||
/// Constructs a Term representing the `JSON` in a file at `path`.
|
||||
public init?(path: String, JSON: Doubt.JSON) {
|
||||
struct E: ErrorType {}
|
||||
func die<A>() throws -> A {
|
||||
throw E()
|
||||
}
|
||||
do {
|
||||
switch JSON.dictionary?["key.substructure"] {
|
||||
case let .Some(.Array(a)):
|
||||
self = .Roll(.Branch(try a.map { try Term(JSON: $0) ?? die() }))
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} catch _ {
|
||||
return nil
|
||||
}
|
||||
public static func Leaf(a: A) -> Term {
|
||||
return Term(.Leaf(a))
|
||||
}
|
||||
|
||||
/// Constructs a Term representing `JSON`.
|
||||
public init?(JSON: Doubt.JSON) {
|
||||
enum Key: String {
|
||||
case Name = "key.name"
|
||||
case Substructure = "key.substructure"
|
||||
}
|
||||
struct E: ErrorType {}
|
||||
func die<A>() throws -> A {
|
||||
throw E()
|
||||
}
|
||||
do {
|
||||
switch JSON {
|
||||
case let .Dictionary(d) where d["key.name"] != nil:
|
||||
let name = d["key.name"]?.string ?? ""
|
||||
let substructure = d["key.substructure"]?.array ?? []
|
||||
let kind = d["key.kind"]?.string
|
||||
switch kind {
|
||||
case
|
||||
.Some("source.lang.swift.decl.class"),
|
||||
.Some("source.lang.swift.decl.extension"),
|
||||
.Some("source.lang.swift.decl.enum"),
|
||||
.Some("source.lang.swift.decl.struct"):
|
||||
self = .Branch([ .Leaf(name), .Branch(try substructure.map { try Term(JSON: $0) ?? die() }) ])
|
||||
|
||||
case .Some("source.lang.swift.decl.enumelement"):
|
||||
fallthrough
|
||||
case
|
||||
.Some("source.lang.swift.decl.function.method.instance"),
|
||||
.Some("source.lang.swift.decl.function.free"):
|
||||
self = .Branch([ .Leaf(name), .Branch(try substructure.map { try Term(JSON: $0) ?? die() }) ])
|
||||
|
||||
case
|
||||
.Some("source.lang.swift.decl.var.instance"),
|
||||
.Some("source.lang.swift.decl.var.static"):
|
||||
self = .Leaf(name)
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
case let .Dictionary(d) where d["key.kind"]?.string == "source.lang.swift.decl.enumcase" && d["key.substructure"]?.array?.count == 1:
|
||||
let substructure = d["key.substructure"]?.array ?? []
|
||||
self = try Term(JSON: substructure[0]) ?? die()
|
||||
|
||||
case let .Dictionary(d) where d["key.kind"]?.string == "source.lang.swift.syntaxtype.comment.mark":
|
||||
self = .Empty
|
||||
|
||||
case .Null:
|
||||
self = .Empty
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} catch _ {
|
||||
return nil
|
||||
}
|
||||
public static func Branch(terms: [Term]) -> Term {
|
||||
return Term(.Branch(terms))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum Syntax<Recur, A>: CustomDebugStringConvertible, CustomDocConvertible {
|
||||
case Empty
|
||||
case Leaf(A)
|
||||
|
@ -33,10 +33,10 @@ final class DiffTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
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 let a: Term<Info> = Term(.Leaf(.Literal("a", [])))
|
||||
private let b: Term<Info> = Term(.Leaf(.Literal("b", [])))
|
||||
private let c: Term<Info> = Term(.Leaf(.Literal("c", [])))
|
||||
private let d: Term<Info> = Term(.Leaf(.Literal("d", [])))
|
||||
|
||||
import Doubt
|
||||
import XCTest
|
||||
|
@ -9,7 +9,7 @@ final class SwiftTests: XCTestCase {
|
||||
let structure = Structure(file: file)
|
||||
let dictionary = toAnyObject(structure.dictionary)
|
||||
|
||||
print(JSON(object: dictionary).map { Term(path: path, JSON: $0) })
|
||||
// print(JSON(object: dictionary).map { Term<String>(path: path, JSON: $0) })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,91 @@ import SourceKittenFramework
|
||||
|
||||
let arguments = BoundsCheckedArray(array: Process.arguments)
|
||||
|
||||
extension Term {
|
||||
public protocol StringConvertible {
|
||||
init(string: String)
|
||||
}
|
||||
|
||||
extension String: StringConvertible {
|
||||
public init(string: String) {
|
||||
self = string
|
||||
}
|
||||
}
|
||||
|
||||
private struct Bail: ErrorType {}
|
||||
|
||||
extension Term where A: StringConvertible {
|
||||
/// Constructs a Term representing `JSON`.
|
||||
init?(JSON: Doubt.JSON) {
|
||||
func bail<B>() throws -> B {
|
||||
throw Bail()
|
||||
}
|
||||
do {
|
||||
switch JSON {
|
||||
case let .Dictionary(d) where d["key.name"] != nil:
|
||||
let name = d["key.name"]?.string ?? ""
|
||||
let substructure = d["key.substructure"]?.array ?? []
|
||||
let kind = d["key.kind"]?.string
|
||||
switch kind {
|
||||
case
|
||||
.Some("source.lang.swift.decl.class"),
|
||||
.Some("source.lang.swift.decl.extension"),
|
||||
.Some("source.lang.swift.decl.enum"),
|
||||
.Some("source.lang.swift.decl.struct"):
|
||||
self = .Branch([ .Leaf(A(string: name)), .Branch(try substructure.map { try Term(JSON: $0) ?? bail() }) ])
|
||||
|
||||
case .Some("source.lang.swift.decl.enumelement"):
|
||||
fallthrough
|
||||
case
|
||||
.Some("source.lang.swift.decl.function.method.instance"),
|
||||
.Some("source.lang.swift.decl.function.free"):
|
||||
self = .Branch([ .Leaf(A(string: name)), .Branch(try substructure.map { try Term(JSON: $0) ?? bail() }) ])
|
||||
|
||||
case
|
||||
.Some("source.lang.swift.decl.var.instance"),
|
||||
.Some("source.lang.swift.decl.var.static"):
|
||||
self = .Leaf(A(string: name))
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
case let .Dictionary(d) where d["key.kind"]?.string == "source.lang.swift.decl.enumcase" && d["key.substructure"]?.array?.count == 1:
|
||||
let substructure = d["key.substructure"]?.array ?? []
|
||||
self = try Term(JSON: substructure[0]) ?? bail()
|
||||
|
||||
case let .Dictionary(d) where d["key.kind"]?.string == "source.lang.swift.syntaxtype.comment.mark":
|
||||
self = .Empty
|
||||
|
||||
case .Null:
|
||||
self = .Empty
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} catch _ {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a Term representing the `JSON` in a file at `path`.
|
||||
init?(path: String, JSON: Doubt.JSON) {
|
||||
func bail<B>() throws -> B {
|
||||
throw Bail()
|
||||
}
|
||||
do {
|
||||
switch JSON.dictionary?["key.substructure"] {
|
||||
case let .Some(.Array(a)):
|
||||
self = .Roll(.Branch(try a.map { try Term(JSON: $0) ?? bail() }))
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} catch _ {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Term where A: StringConvertible {
|
||||
init?(path: String) {
|
||||
guard path != "/dev/null" else {
|
||||
self = .Empty
|
||||
@ -18,6 +102,6 @@ extension Term {
|
||||
}
|
||||
}
|
||||
|
||||
if let a = arguments[1].flatMap(Term.init), b = arguments[2].flatMap(Term.init) {
|
||||
if let a = arguments[1].flatMap(Term<Info>.init), b = arguments[2].flatMap(Term<Info>.init) {
|
||||
print(String(reflecting: Diff(a, b)))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user