Skip to content

Instantly share code, notes, and snippets.

@JRHeaton
Last active August 29, 2015 14:18
Show Gist options
  • Save JRHeaton/644d253a82a149ac8b43 to your computer and use it in GitHub Desktop.
Save JRHeaton/644d253a82a149ac8b43 to your computer and use it in GitHub Desktop.
more parser combinator fun (i have no idea what i'm doing :D)
class Box<T>: Printable {
let unbox: T
init(_ value: T) {
self.unbox = value
}
var description: String {
return toString(unbox)
}
}
enum ParserResult<Input: CollectionType, Tree>: Printable {
case Success(tree: Box<Tree>, index: Box<Input.Index>)
case Error(error: String)
func bind<U>(transform: (Tree, Input.Index) -> ParserResult<Input, U>) -> ParserResult<Input, U> {
switch self {
case .Success(let tree, let index):
return transform(tree.unbox, index.unbox)
case .Error(let error):
return .Error(error: error)
}
}
var description: String {
switch self {
case let .Success(tree, residual):
return "Success[tree=\(tree), index=\(residual)]"
case let .Error(error):
return "Error: \(error)"
}
}
}
struct Parser<Input: CollectionType, Tree> {
typealias Result = ParserResult<Input, Tree>
typealias Function = (Input, Input.Index) -> Result
}
infix operator >>- { associativity left precedence 160 }
func >>- <Input: CollectionType, Tree, U>(result: ParserResult<Input, Tree>, transform: (Tree, Input.Index) -> ParserResult<Input, U>) -> ParserResult<Input, U> {
return result.bind(transform)
}
func ?? <Input: CollectionType, Tree>(result: ParserResult<Input, Tree>, @autoclosure closure: () -> ParserResult<Input, Tree>) -> ParserResult<Input, Tree> {
switch result {
case .Error(let _):
return closure()
default: return result
}
}
func either<Input, Tree>(left: Parser<Input, Tree>.Function, right: Parser<Input, Tree>.Function) -> Parser<Input, Tree>.Function {
return { input, index in
let first = left(input, index)
switch first {
case .Success(let _, let _):
return first
case .Error(let firstError):
let second = right(input, index)
switch second {
case .Success(let _, residual: let _):
return second
case .Error(error: let secondError):
return .Error(error: "Expected to satisfy either of two given parsers but failed:\n\(firstError)\n\(secondError)")
}
}
}
}
infix operator ++ { associativity right }
func ++<Input, Tree1, Tree2>(left: Parser<Input, Tree1>.Function, right: Parser<Input, Tree2>.Function) -> Parser<Input, (Tree1, Tree2)>.Function {
return { rootInput, rootIndex in
left(rootInput, rootIndex) >>- { (leftTree: Tree1, leftIndex: Input.Index) in
right(rootInput, leftIndex) >>- { (rightTree: Tree2, rightIndex: Input.Index) in
.Success(tree: Box((leftTree, rightTree)), index: Box(rightIndex))
}
}
}
}
func ++<Input, Tree>(left: Parser<Input, ()>.Function, right: Parser<Input, Tree>.Function) -> Parser<Input, Tree>.Function {
return { rootInput, rootIndex in
left(rootInput, rootIndex) >>- { (_, leftIndex: Input.Index) in
right(rootInput, leftIndex) >>- { rightTree, rightIndex in
.Success(tree: Box(rightTree), index: Box(rightIndex))
}
}
}
}
func ++<Input, Tree>(left: Parser<Input, Tree>.Function, right: Parser<Input, ()>.Function) -> Parser<Input, Tree>.Function {
return { rootInput, rootIndex in
left(rootInput, rootIndex) >>- { (leftTree: Tree, leftIndex: Input.Index) in
right(rootInput, leftIndex) >>- { _, rightIndex in
.Success(tree: Box(leftTree), index: Box(rightIndex))
}
}
}
}
func satisfy<Input: CollectionType>(test: Input.Generator.Element -> Bool) -> Parser<Input, Input.Generator.Element>.Function {
return { input, index in
let first = input[index]
if test(first) {
return .Success(tree: Box(first), index: Box(index.successor()))
} else {
return .Error(error: "satisfy block failed for input: \(first)")
}
}
}
func single<Input: CollectionType where Input.Generator.Element: Equatable>(element: Input.Generator.Element) -> Parser<Input, Input.Generator.Element>.Function {
return satisfy { $0 == element }
}
func single(character: Character) -> Parser<String, Character>.Function {
return satisfy { $0 == character }
}
func parse<Input: CollectionType, Tree>(parser: Parser<Input, Tree>.Function, input: Input) -> ParserResult<Input, Tree> {
return parser(input, input.startIndex)
}
func takeWhile<Input: CollectionType, Tree>(parser: Parser<Input, Tree>.Function) -> Parser<Input, [Tree]>.Function {
return { input, index in
var ret = [Tree]()
var mIndex = index
loop: while mIndex != input.endIndex {
let result = parser(input, mIndex)
switch result {
case .Success(let tree, index: let index):
ret.append(tree.unbox)
mIndex = index.unbox
case .Error(let error) where mIndex == index:
return .Error(error: error)
case .Error(let _):
break loop
}
}
return .Success(tree: Box(ret), index: Box(mIndex))
}
}
func takeWhileCharacter(test: Character -> Bool) -> Parser<String, [Character]>.Function {
return takeWhile(satisfy(test))
}
func map<Input: CollectionType, Tree, NewTree>(parser: Parser<Input, Tree>.Function, transform: Tree -> NewTree) -> Parser<Input, NewTree>.Function {
return { input, index in
parser(input, index) >>- { .Success(tree: Box(transform($0)), index: Box($1)) }
}
}
func optional<Input: CollectionType, Tree>(parser: Parser<Input, Tree>.Function) -> Parser<Input, Tree?>.Function {
return { input, index in
return parser(input, index) >>- {
.Success(tree: Box(Optional($0)), index: Box($1))
} ?? .Success(tree: Box(nil), index: Box(index))
}
}
func skip<Input: CollectionType, Tree>(parser: Parser<Input, Tree>.Function) -> Parser<Input, ()>.Function {
return map(parser, const(()))
}
func surround<Input: CollectionType, Tree>(parser: Parser<Input, Tree>.Function, #by: Parser<Input, ()>.Function) -> Parser<Input, Tree>.Function {
return by ++ parser ++ by
}
let concat: [Character] -> String = { reduce($0, "", { $0 + String($1) }) }
let alphanumToWord = curry(~map)(concat) <| takeWhileCharacter { ("a"..."z").contains(String($0)) }
let digits: Parser<String, Character?>.Function = optional <| satisfy { ("0"..."9").contains($0) }
let spaces = optional <| takeWhile <| single(" ")
let spacePaddedWords = skip(spaces) ++ alphanumToWord
let words = takeWhile <| (spacePaddedWords ++ surround(skip <| digits, by: skip <| spaces))
println(parse(words, "john 3 cool 9bobby8 ")) // Success[tree=[john, cool, bobby], index=30]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment