1
1
mirror of https://github.com/github/semantic.git synced 2024-12-24 23:42:31 +03:00
semantic/prototype/Doubt/Syntax.swift

128 lines
3.3 KiB
Swift
Raw Normal View History

2015-10-01 21:25:17 +03:00
/// 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, CustomDocConvertible {
2015-09-30 19:41:20 +03:00
case Leaf(A)
2015-10-03 00:12:49 +03:00
case Indexed([Recur])
2015-10-03 00:18:38 +03:00
case Keyed([String:Recur])
2015-07-18 22:43:49 +03:00
2015-10-06 18:08:39 +03:00
// MARK: Functor
public func map<T>(@noescape transform: Recur -> T) -> Syntax<T, A> {
2015-07-18 22:43:49 +03:00
switch self {
2015-09-30 17:36:25 +03:00
case let .Leaf(n):
return .Leaf(n)
2015-10-03 00:12:49 +03:00
case let .Indexed(x):
return .Indexed(x.map(transform))
2015-10-03 00:18:38 +03:00
case let .Keyed(d):
return .Keyed(Dictionary(elements: d.map { ($0, transform($1)) }))
2015-07-18 22:43:49 +03:00
}
}
public var debugDescription: String {
2015-07-18 22:43:49 +03:00
switch self {
2015-09-30 17:36:25 +03:00
case let .Leaf(n):
return ".Leaf(\(n))"
2015-10-03 00:12:49 +03:00
case let .Indexed(x):
2015-10-03 00:13:27 +03:00
return ".Indexed(\(String(reflecting: x)))"
2015-10-03 00:18:38 +03:00
case let .Keyed(d):
return ".Keyed(\(String(reflecting: d)))"
2015-07-18 22:43:49 +03:00
}
}
2015-09-29 05:36:22 +03:00
public var doc: Doc {
2015-07-18 22:43:49 +03:00
switch self {
2015-09-30 17:36:25 +03:00
case let .Leaf(n):
2015-09-30 19:41:20 +03:00
return Doc(n)
2015-10-03 00:12:49 +03:00
case let .Indexed(x):
2015-10-08 00:42:43 +03:00
return x.map(Doc.init).joinWithSeparator(",").bracket("[", "]")
2015-10-03 00:18:38 +03:00
case let .Keyed(d):
2015-10-08 00:42:43 +03:00
return d.lazy.map { Doc($0) <> Doc(":") <+> Doc($1) }.joinWithSeparator(",").bracket("[", "]")
2015-07-18 22:43:49 +03:00
}
}
}
// MARK: - Equality
extension Syntax {
public static func equals(ifLeaf ifLeaf: (A, A) -> Bool, ifRecur: (Recur, Recur) -> Bool)(_ left: Syntax<Recur, A>, _ right: Syntax<Recur, A>) -> Bool {
switch (left, right) {
case let (.Leaf(l1), .Leaf(l2)):
return ifLeaf(l1, l2)
2015-10-03 00:12:49 +03:00
case let (.Indexed(v1), .Indexed(v2)):
2015-10-03 00:11:02 +03:00
return v1.count == v2.count && zip(v1, v2).lazy.map(ifRecur).reduce(true) { $0 && $1 }
2015-10-03 00:18:38 +03:00
case let (.Keyed(d1), .Keyed(d2)):
return Array(d1.keys) == Array(d2.keys) && d1.keys.lazy.map { ifRecur(d1[$0]!, d2[$0]!) }.reduce(true) { $0 && $1 }
default:
return false
}
}
}
2015-10-01 22:25:49 +03:00
public func == <F: Equatable, A: Equatable> (left: Syntax<F, A>, right: Syntax<F, A>) -> Bool {
return Syntax.equals(ifLeaf: ==, ifRecur: ==)(left, right)
2015-10-01 22:25:49 +03:00
}
2015-10-08 14:15:52 +03:00
// MARK: - Hashing
2015-10-02 21:33:41 +03:00
extension Syntax {
public func hash(ifLeaf ifLeaf: A -> Hash, ifRecur: Recur -> Hash) -> Hash {
switch self {
2015-09-30 17:36:25 +03:00
case let .Leaf(n):
2015-10-02 21:33:41 +03:00
return Hash("Leaf", ifLeaf(n))
2015-10-03 00:12:49 +03:00
case let .Indexed(x):
return Hash("Indexed", .Ordered(x.map(ifRecur)))
2015-10-03 00:18:38 +03:00
case let .Keyed(d):
return Hash("Keyed", .Ordered(d.keys.sort().map { Hash($0, ifRecur(d[$0]!)) }))
}
}
}
extension Syntax where Recur: Hashable, A: Hashable {
public var hash: Hash {
2015-10-02 21:33:41 +03:00
return hash(ifLeaf: Hash.init, ifRecur: Hash.init)
}
}
2015-10-08 14:19:37 +03:00
2015-10-09 15:40:57 +03:00
// MARK: - JSON
2015-10-08 14:19:37 +03:00
extension Syntax {
public func JSON(ifLeaf ifLeaf: A -> Doubt.JSON, ifRecur: Recur -> Doubt.JSON) -> Doubt.JSON {
switch self {
case let .Leaf(a):
return ifLeaf(a)
case let .Indexed(a):
2015-10-09 15:44:16 +03:00
return .Array(a.map(ifRecur))
2015-10-08 14:19:37 +03:00
case let .Keyed(d):
2015-10-09 15:44:16 +03:00
return .Dictionary(Dictionary(elements: d.map { ($0, ifRecur($1)) }))
2015-10-08 14:19:37 +03:00
}
}
}
// MARK: - Construction
/// SyntaxConvertible types can be constructed with the same constructors available on Syntax itself, as a convenience.
public protocol SyntaxConvertible {
typealias RecurType
typealias LeafType
init(syntax: Syntax<RecurType, LeafType>)
}
extension SyntaxConvertible {
static func Leaf(value: LeafType) -> Self {
return Self(syntax: .Leaf(value))
}
static func Indexed(children: [RecurType]) -> Self {
return Self(syntax: .Indexed(children))
}
static func Keyed(children: [String:RecurType]) -> Self {
return Self(syntax: .Keyed(children))
}
}