Advertisement
Revolucent

JSON parser combinators using Parsimonious

Apr 13th, 2019
638
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 2.15 KB | None | 0 0
  1. import XCTest
  2. @testable import Parsimonious
  3.  
  4. indirect enum JSON {
  5.     case string(String)
  6.     case number(NSNumber)
  7.     case boolean(Bool)
  8.     case object([String: JSON])
  9.     case array([JSON])
  10. }
  11.  
  12. let escape = "\\"
  13. let quote = "\""
  14.  
  15. let quotation = char(quote) *> manyS(char(all: !escape, !quote) | (char(escape) *> char(any: escape, quote))) <* char(quote)
  16. let jstring = JSON.string <*> quotation
  17.  
  18. func jnumber(_ context: Context<String>) throws -> JSON {
  19.     let digits = many1S("0123456789")
  20.     let num = digits + optionalS(char(".") + digits)
  21.     let formatter = NumberFormatter()
  22.     formatter.numberStyle = .decimal
  23.     let ns = try context <- num
  24.     guard let n = formatter.number(from: ns) else {
  25.         throw ParseError(message: "Expected a number, but got \(ns).", context: context)
  26.     }
  27.     return JSON.number(n)
  28. }
  29.  
  30. let jbool = {s in JSON.boolean(s == "true")} <*> string("true") | string("false") | fail("Expected a boolean value.")
  31.  
  32. let ws = manyS(\Character.isWhitespace)
  33.  
  34. func jarray(_ context: Context<String>) throws -> JSON {
  35.     return try context <- JSON.array <*> char("[") *> ws *> many(json <* ws, sepBy: ws + char(",") + ws) <* char("]")
  36. }
  37.  
  38. func jpair(_ context: Context<String>) throws -> (key: String, value: JSON) {
  39.     return try context.transact {
  40.         let key = try context <- quotation
  41.         try context <- ws + char(":") + ws
  42.         let value = try context <- json
  43.         return (key, value)
  44.     }
  45. }
  46.  
  47. func jobject(_ context: Context<String>) throws -> JSON {
  48.     return try context.transact {
  49.         try context <- char("{") <* ws
  50.         let pairs = try context <- many(jpair <* ws, sepBy: ws + char(",") + ws)
  51.         try context <- char("}")
  52.         var object: [String: JSON] = [:]
  53.         for pair in pairs {
  54.             object[pair.key] = pair.value
  55.         }
  56.         return JSON.object(object)
  57.     }
  58. }
  59.  
  60. let json = jstring | jnumber | jbool | jarray | jobject
  61.  
  62. class ParsimoniousTests: XCTestCase {
  63.  
  64.     func testParser() {
  65.         let s = """
  66. {
  67.    "foo": "bar",
  68.    "x": [7, 9, 11.14, {"yes": true}]
  69. }
  70. """
  71.         try XCTAssertNoThrow(parse(s, with: ws *> json <* ws))
  72.     }
  73.  
  74. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement