Parsing swiftly-Cocoaheads-2015-02-12

Preview:

Citation preview

Parsing(Swi+ly

ParsingLexing'(Tokenizing)

Parsing((Extrac.ng(meaning)

What%is%the%Type%of%a%parser?

Parsing(an(Int

String'(>'Int

String'(>'(Int,'remainder:'String)

String'(>'(Int,'remainder:'String)?

<ValueType>+String+2>+(ValueType,+remainder:+String)?

struct Parser<ValueType> { let apply:(String) -> (ValueType, String)?}

struct Parser<ValueType> { typealias Function = (String) -> (ValueType, String)? let apply:Function

init(apply: Function) { self.apply = apply }}

Building(Blocks

Parser.result()Parser.zero()Parser.item()

Parser.result()

static func result(value:ValueType) -> Parser { return Parser { (input) in return (value, remainder:input) }}

Parser.zero()

static func zero() -> Parser { return Parser { (input) in return nil }}

Parser.item()static func item() -> Parser<Character> { return Parser<Character> { (input) in

let firstIndex = input.startIndex

if firstIndex == input.endIndex { return nil } else { return (input[firstIndex], remainder: String(dropFirst(input))) } }}

Let$Our$Parsers$Combine!

bindfunc bind<T, U>(parserT:Parser<T>, lift:(T -> Parser<U>)) -> Parser<U> { return Parser<U> { (input) in if let (theT, theRemainder) = parserT.apply(input) { return lift(theT).apply(theRemainder) } else { return nil } }}

sa#sfyfunc satisfy(predicate:(Character -> Bool)) -> Parser<Character> { return bind(Parser<Character>.item()) { theChar in if predicate(theChar) { return Parser.result(theChar) } else { return Parser.zero() } }}

char

func char(x:Character) -> Parser<Character> { return satisfy { $0 == x }}

func charIn<CharSeq: SequenceType where CharSeq.Generator.Element == Character> (x:CharSeq) -> Parser<Character> { return satisfy { Set(x).contains($0) }}

let digit:Parser<Character> = satisfy { "0"..."9" ~= $0 }let lower:Parser<Character> = satisfy { "a"..."z" ~= $0 }let upper:Parser<Character> = satisfy { "A"..."Z" ~= $0 }

I"Said""Let"Our"Parsers"Combine!"let nsParser:Parser<String> = bind(char("N")) { (theLetterN) in bind(char("S")) { (theLetterS) in Parser<String>.result(String([theLetterN, theLetterS])) }}

nsParser.apply("NS")nsParser.apply("AB")

a"small"detourextension Optional { internal func bind<U>(f: T -> U?) -> U? { if let x = self { return f(x) } else { return nil } }}

func headAndTail(input:String) -> (head:Character, tail:String)? { return first(input).bind { head in

return (head:head, tail:String(dropFirst(input))) }}

Words!func word(x:String) -> Parser<String> { if let found = headAndTail(x) { return bind(char(found.head)) { (a:Character) in return bind(word(found.tail)) { (b:String) in return Parser<String>.result(x) } } } else { return Parser<String>.result(x) }}

Choicefunc choice<T>(lhs:Parser<T>, rhs:Parser<T>) -> Parser<T> { return Parser { (input) in if let leftParse = lhs.apply(input) { return leftParse } else { return rhs.apply(input) } }}

Parse&you&a&Monad

Monadic(Parser(CombinatorsGraham&Hu)on&and&Erik&Meijer

• h#p://www.cs.no#.ac.uk/~gmh/monparsing.pdf)

Parsec:(Direct(Style(Monadic(Parser(Combinators(For(The(Real(WorldDaan$Leijen

• h#p://research.microso0.com/en2us/um/people/daan/download/papers/parsec2paper.pdf

Examples

• Rob%Rix%(%Madness%(%h0ps://github.com/robrix/Madness

• Parsec%