Advertisement
Guest User

Untitled

a guest
Jul 21st, 2019
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 1.72 KB | None | 0 0
  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 "")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement