1
1
mirror of https://github.com/github/semantic.git synced 2024-12-01 17:59:10 +03:00
semantic/prototype/Doubt/Doc.swift

150 lines
4.0 KiB
Swift
Raw Normal View History

2015-09-29 05:28:37 +03:00
public enum Layout: CustomStringConvertible, Equatable {
2015-07-18 22:43:49 +03:00
case Empty
2015-09-29 05:28:37 +03:00
indirect case Text(String, Layout)
indirect case Line(Int, Layout)
2015-09-29 05:36:22 +03:00
public init(width: Int, placed: Int, alternatives: Stream<(Int, Doc)>) {
2015-09-29 05:22:13 +03:00
switch alternatives {
case .Nil:
self = .Empty
case let .Cons((_, .Empty), rest):
2015-09-29 05:28:37 +03:00
self = Layout(width: width, placed: placed, alternatives: rest.value)
2015-09-29 05:22:13 +03:00
case let .Cons((i, .Concat(x, y)), rest):
2015-09-29 05:28:37 +03:00
self = Layout(width: width, placed: placed, alternatives: .Cons((i, x), Memo(evaluated: .Cons((i, y), rest))))
2015-09-29 05:22:13 +03:00
case let .Cons((i, .Nest(j, x)), rest):
2015-09-29 05:28:37 +03:00
self = Layout(width: width, placed: placed, alternatives: .Cons((i + j, x), rest))
2015-09-29 05:22:13 +03:00
case let .Cons((_, .Text(s)), rest):
2015-09-29 05:28:37 +03:00
self = .Text(s, Layout(width: width, placed: placed + Int(s.characters.count), alternatives: rest.value))
2015-09-29 05:22:13 +03:00
case let .Cons((i, .Line), rest):
2015-09-29 05:28:37 +03:00
self = .Line(i, Layout(width: width, placed: i, alternatives: rest.value))
2015-09-29 05:22:13 +03:00
case let .Cons((i, .Union(x, y)), z):
2015-09-29 05:28:37 +03:00
self = .better(width, placed, Layout(width: width, placed: placed, alternatives: .Cons((i, x), z)), Layout(width: width, placed: placed, alternatives: .Cons((i, y), z)))
2015-09-29 05:22:13 +03:00
}
}
public var description: String {
switch self {
case .Empty:
return ""
case let .Text(s, doc):
return s + doc.description
case let .Line(n, doc):
return "\n" + String(count: n, repeatedValue: " " as Character) + doc.description
}
}
2015-09-29 05:12:08 +03:00
public func fits(width: Int) -> Bool {
guard width >= 0 else { return false }
switch self {
case .Empty, .Line:
return true
case let .Text(s, x):
return x.fits(width - Int(s.characters.count))
}
}
2015-09-29 05:23:23 +03:00
2015-09-29 05:28:37 +03:00
public static func better(width: Int, _ placed: Int, _ x: Layout, _ y: Layout) -> Layout {
2015-09-29 05:27:46 +03:00
return x.fits(width - placed) ? x : y
2015-09-29 05:23:23 +03:00
}
}
2015-09-29 05:36:22 +03:00
public enum Doc: CustomDocConvertible, Equatable {
case Empty
2015-09-29 05:36:22 +03:00
indirect case Concat(Doc, Doc)
indirect case Union(Doc, Doc)
2015-07-18 22:43:49 +03:00
case Text(String)
2015-09-29 05:36:22 +03:00
indirect case Nest(Int, Doc)
case Line
2015-07-18 22:43:49 +03:00
public init<T>(_ value: T) {
self = (value as? CustomDocConvertible)?.doc ?? .Text(String(value))
2015-07-18 22:43:49 +03:00
}
2015-09-29 05:36:22 +03:00
public static func group(doc: Doc) -> Doc {
return Union(doc.flattened, doc)
}
2015-09-29 05:36:22 +03:00
public static func bracket(l: String, _ x: Doc, _ r: String) -> Doc {
return group(Concat(Text(l), Concat(Nest(2, Concat(Line, x)), Concat(Line, Text(r)))))
}
2015-09-29 05:36:22 +03:00
public static func foldDoc<C: CollectionType where C.Generator.Element == Doc>(Docs: C, combine: (Doc, Doc) -> Doc) -> Doc {
func fold(Docs: Stream<Doc>) -> Doc {
switch Docs {
case .Nil:
return .Empty
case let .Cons(x, rest) where rest.value.isEmpty:
return x
case let .Cons(x, rest):
return combine(x, fold(rest.value))
}
}
2015-09-29 05:36:22 +03:00
return fold(Stream(sequence: Docs))
}
2015-09-29 05:36:22 +03:00
public static func spread<C: CollectionType where C.Generator.Element == Doc>(Docs: C) -> Doc {
return foldDoc(Docs, combine: <+>)
}
2015-09-29 05:36:22 +03:00
public static func stack<C: CollectionType where C.Generator.Element == Doc>(Docs: C) -> Doc {
return foldDoc(Docs, combine: </>)
}
2015-09-29 05:36:22 +03:00
public static func join<C: CollectionType where C.Generator.Element == Doc>(separator: String, _ Docs: C) -> Doc {
return foldDoc(Docs) {
$0 <> Text(separator) <+> $1
}
}
2015-09-29 05:36:22 +03:00
public var flattened: Doc {
2015-07-18 22:43:49 +03:00
switch self {
case .Empty, .Text:
return self
case let .Concat(a, b):
return .Concat(a.flattened, b.flattened)
case let .Union(a, _):
return a.flattened
2015-09-29 05:36:22 +03:00
case let .Nest(_, Doc):
return Doc.flattened
case .Line:
return .Text(" ")
2015-07-18 22:43:49 +03:00
}
}
2015-09-29 00:13:10 +03:00
public func pretty(width: Int) -> String {
2015-09-29 05:16:19 +03:00
return best(width).description
2015-09-29 00:13:10 +03:00
}
2015-07-18 22:43:49 +03:00
2015-09-29 05:28:37 +03:00
public func best(width: Int, placed: Int = 0) -> Layout {
return Layout(width: width, placed: placed, alternatives: .pure((0, self)))
}
2015-09-29 05:33:18 +03:00
2015-09-29 05:36:22 +03:00
public var doc: Doc {
2015-09-29 05:33:18 +03:00
return self
}
}
public protocol CustomDocConvertible: CustomStringConvertible {
2015-09-29 05:36:22 +03:00
var doc: Doc { get }
2015-07-18 22:43:49 +03:00
}
extension CustomDocConvertible {
public var description: String {
2015-09-29 00:13:10 +03:00
return doc.pretty(70)
2015-07-18 22:43:49 +03:00
}
}
2015-09-29 05:36:22 +03:00
public func <> (left: Doc, right: Doc) -> Doc {
return .Concat(left, right)
}
2015-09-29 05:36:22 +03:00
public func <+> (left: Doc, right: Doc) -> Doc {
return left <> .Text(" ") <> right
}
2015-09-29 05:36:22 +03:00
public func </> (left: Doc, right: Doc) -> Doc {
return left <> .Line <> right
}