SHARE
TWEET

Untitled

a guest Jul 21st, 2019 77 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import Foundation
  2.  
  3. struct Parser<A> {
  4.   let run: (inout Substring) -> A?
  5. }
  6.  
  7. extension Parser {
  8.   func map<B>(_ f: @escaping (A) -> B) -> Parser<B> {
  9.     return Parser<B> { str -> B? in
  10.       self.run(&str).map(f)
  11.     }
  12.   }
  13.   func run(_ str: String) -> (match: A?, rest: Substring) {
  14.     var str = str[...]
  15.     let match = self.run(&str)
  16.     return (match, str)
  17.   }
  18. }
  19.  
  20. func zip<A, B>(_ a: Parser<A>, _ b: Parser<B>) -> Parser<(A, B)> {
  21.   return Parser<(A, B)> { str -> (A, B)? in
  22.     let original = str
  23.     guard let matchA = a.run(&str) else { return nil }
  24.     guard let matchB = b.run(&str) else {
  25.       str = original
  26.       return nil
  27.     }
  28.     return (matchA, matchB)
  29.   }
  30. }
  31.  
  32. func zip<A, B, C>(
  33.   _ a: Parser<A>,
  34.   _ b: Parser<B>,
  35.   _ c: Parser<C>
  36.   ) -> Parser<(A, B, C)> {
  37.   return zip(a, zip(b, c))
  38.     .map { a, bc in (a, bc.0, bc.1) }
  39. }
  40.  
  41. func prefix(while p: @escaping (Character) -> Bool) -> Parser<Substring> {
  42.   return Parser<Substring> { str in
  43.     let prefix = str.prefix(while: p)
  44.     str.removeFirst(prefix.count)
  45.     return prefix
  46.   }
  47. }
  48.  
  49. func literal(_ p: String) -> Parser<Void> {
  50.   return Parser<Void> { str in
  51.     guard str.hasPrefix(p) else { return nil }
  52.     str.removeFirst(p.count)
  53.     return ()
  54.   }
  55. }
  56.  
  57. let word = prefix(while: { $0 != " " && $0 != "-" })
  58.  
  59. func optional<A>(_ parser: Parser<A>) -> Parser<A?> {
  60.   return Parser<A?> { str in
  61.     .some(parser.run(&str))
  62.   }
  63. }
  64.  
  65. let testTwoWords: Parser<[Substring?]> = zip(
  66.   optional(word),
  67.   literal(" "),
  68.   word
  69.   ).map { word1, _, word2 in
  70.     return [word1, word2]
  71. }
  72.  
  73.  
  74. testTwoWords.run("OptionalWord RequiredWord")
  75. // Output: (["Hello", "There"], rest "")
  76.  
  77. testTwoWords.run(" RequiredWord")
  78. // Output: (["", "There"], rest "")
  79. // However, ideally I would like ([nil, "There"], rest "")
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top