2015-09-11 17:17:19 +03:00
|
|
|
public struct Fix: CustomDebugStringConvertible, CustomDocConvertible, CustomStringConvertible, Equatable, FixpointType {
|
|
|
|
public init(_ roll: () -> Syntax<Fix>) {
|
2015-07-18 22:43:49 +03:00
|
|
|
self.roll = roll
|
|
|
|
}
|
2015-09-11 17:17:19 +03:00
|
|
|
public init(_ out: Syntax<Fix>) {
|
2015-07-18 22:43:49 +03:00
|
|
|
self.init { out }
|
|
|
|
}
|
|
|
|
|
|
|
|
let roll: () -> Syntax<Fix>
|
|
|
|
|
2015-09-11 17:17:19 +03:00
|
|
|
public var out: Syntax<Fix> {
|
2015-07-18 22:43:49 +03:00
|
|
|
return roll()
|
|
|
|
}
|
|
|
|
|
2015-09-11 17:17:19 +03:00
|
|
|
public var debugDescription: String {
|
2015-07-18 22:43:49 +03:00
|
|
|
return cata { String(reflecting: $0) } (self)
|
|
|
|
}
|
|
|
|
|
2015-09-11 17:17:19 +03:00
|
|
|
public var doc: Doc<Pretty> {
|
2015-07-18 22:43:49 +03:00
|
|
|
return cata { (syntax: Syntax<Doc<Pretty>>) in syntax.doc } (self)
|
|
|
|
}
|
|
|
|
|
2015-09-11 17:17:19 +03:00
|
|
|
public var description: String {
|
2015-07-18 22:43:49 +03:00
|
|
|
return cata { String($0) } (self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-11 17:17:19 +03:00
|
|
|
public enum Syntax<Payload>: AlgebraicType, CustomDebugStringConvertible, CustomDocConvertible {
|
2015-07-18 22:43:49 +03:00
|
|
|
case Apply(Payload, [Payload])
|
|
|
|
case Abstract([Payload], Payload)
|
|
|
|
case Assign(String, Payload)
|
|
|
|
case Variable(String)
|
|
|
|
case Literal(String)
|
|
|
|
case Group(Payload, [Payload])
|
|
|
|
|
2015-09-11 17:17:19 +03:00
|
|
|
public func map<T>(@noescape transform: Payload -> T) -> Syntax<T> {
|
2015-07-18 22:43:49 +03:00
|
|
|
switch self {
|
|
|
|
case let .Apply(f, args):
|
|
|
|
return .Apply(transform(f), args.map(transform))
|
|
|
|
case let .Abstract(parameters, body):
|
|
|
|
return .Abstract(parameters.map(transform), transform(body))
|
|
|
|
case let .Assign(n, v):
|
|
|
|
return .Assign(n, transform(v))
|
|
|
|
case let .Variable(n):
|
|
|
|
return .Variable(n)
|
|
|
|
case let .Literal(v):
|
|
|
|
return .Literal(v)
|
|
|
|
case let .Group(n, v):
|
|
|
|
return .Group(transform(n), v.map(transform))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-11 17:17:19 +03:00
|
|
|
public typealias Recur = Payload
|
2015-07-18 22:43:49 +03:00
|
|
|
|
2015-09-11 17:17:19 +03:00
|
|
|
public var debugDescription: String {
|
2015-07-18 22:43:49 +03:00
|
|
|
switch self {
|
|
|
|
case let .Apply(f, vs):
|
2015-09-09 21:59:08 +03:00
|
|
|
let s = vs.map { String($0) }.joinWithSeparator(", ")
|
2015-07-18 22:43:49 +03:00
|
|
|
return ".Apply(\(f), [ \(s) ])"
|
|
|
|
case let .Abstract(parameters, body):
|
2015-09-09 21:59:08 +03:00
|
|
|
let s = parameters.map { String($0) }.joinWithSeparator(", ")
|
2015-07-18 22:43:49 +03:00
|
|
|
return ".Abstract([ \(s) ], \(body))"
|
|
|
|
case let .Assign(n, v):
|
|
|
|
return ".Assign(\(n), \(v))"
|
|
|
|
case let .Variable(n):
|
|
|
|
return ".Variable(\(n))"
|
|
|
|
case let .Literal(s):
|
|
|
|
return ".Literal(\(s))"
|
|
|
|
case let .Group(n, vs):
|
2015-09-09 21:59:08 +03:00
|
|
|
let s = vs.map { String($0) }.joinWithSeparator(", ")
|
2015-07-18 22:43:49 +03:00
|
|
|
return ".Group(\(n), [ \(s) ])"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-11 17:17:19 +03:00
|
|
|
public var doc: Doc<Pretty> {
|
2015-07-18 22:43:49 +03:00
|
|
|
switch self {
|
|
|
|
case let .Apply(f, vs):
|
|
|
|
return .Horizontal([
|
|
|
|
Pretty(f),
|
|
|
|
Pretty.Wrap(Pretty.Text("("), Pretty.Join(Pretty.Text(", "), vs.map(Pretty.init)), Pretty.Text(")"))
|
|
|
|
])
|
|
|
|
case let .Abstract(parameters, body):
|
|
|
|
return .Horizontal([
|
|
|
|
Pretty.Text("λ"),
|
|
|
|
Pretty.Join(Pretty.Text(", "), parameters.map(Pretty.init)),
|
|
|
|
Pretty.Text("."),
|
|
|
|
Pretty(body)
|
|
|
|
])
|
|
|
|
case let .Assign(n, v):
|
|
|
|
return .Horizontal([ .Text(n), .Text("="), Pretty(v) ])
|
|
|
|
case let .Variable(n):
|
|
|
|
return .Text(n)
|
|
|
|
case let .Literal(s):
|
|
|
|
return .Text(s)
|
|
|
|
case let .Group(n, vs):
|
|
|
|
return .Horizontal([
|
|
|
|
Pretty(n),
|
|
|
|
Pretty.Wrap(.Text("{"), Pretty.Vertical(vs.map(Pretty.init)), .Text("}"))
|
|
|
|
])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func cata<T>(f: Syntax<T> -> T)(_ term: Fix) -> T {
|
|
|
|
return (Fix.out >>> { $0.map(cata(f)) } >>> f)(term)
|
|
|
|
}
|