1
1
mirror of https://github.com/github/semantic.git synced 2024-12-23 06:41:45 +03:00
semantic/prototype/Doubt/JSONParser.swift

87 lines
2.8 KiB
Swift
Raw Normal View History

2015-10-16 22:41:35 +03:00
//
// JSONParser.swift
// Doubt
//
// Created by Josh Vera on 10/16/15.
// Copyright © 2015 GitHub. All rights reserved.
//
import Foundation
import Madness
import Prelude
public typealias CofreeJSON = Cofree<JSONLeaf, (Range<Line>, Range<Column>, Range<String.Index>)>
public typealias JSONParser = Parser<String.CharacterView, CofreeJSON>.Function
2015-10-16 22:41:35 +03:00
2015-10-20 18:11:06 +03:00
// Inlined for performance reasons
let whitespace = many(oneOf(" \n\r\t"))
2015-10-20 18:11:06 +03:00
2015-10-26 23:37:50 +03:00
// TODO: Parse unicode escape sequence
2015-10-27 23:12:23 +03:00
let escapeChar: StringParser = curry(+) <^> %"\\" <*> ({ String($0) } <^> oneOf("\\\"bfnrt"))
let otherChar: StringParser = { String($0) } <^> noneOf("\"\\")
2015-10-26 23:37:50 +03:00
2015-10-20 18:11:06 +03:00
// Quoted strings parser
2015-10-21 18:21:37 +03:00
// TODO: Improve string parsing
2015-10-27 23:11:38 +03:00
let stringBody: StringParser = { $0.joinWithSeparator("") } <^> many(escapeChar <|> otherChar)
let quoted = %"\"" *> stringBody <* %"\""
2015-10-16 22:41:35 +03:00
typealias MembersParser = Parser<String.CharacterView, [(String, CofreeJSON)]>.Function;
2015-10-16 22:41:35 +03:00
2015-10-20 18:11:06 +03:00
// Parses an array of (String, CofreeJSON) object members
2015-10-16 22:41:35 +03:00
func members(json: JSONParser) -> MembersParser {
2015-11-10 22:11:09 +03:00
let keyAndKeyTerm: Parser<String.CharacterView, (String, CofreeJSON)>.Function = quoted --> { _, lines, columns, range, key in
(key, Cofree((lines, columns, range), .Leaf(.String(key))))
2015-10-27 23:11:45 +03:00
}
let pairs: Parser<String.CharacterView, (String, CofreeJSON)>.Function = (curry(pair) <^>
2015-10-27 23:11:45 +03:00
keyAndKeyTerm
2015-10-21 18:25:33 +03:00
<* whitespace
<* %":"
<* whitespace
2015-11-10 22:11:09 +03:00
<*> json) --> { _, lines, columns, range, values in
(values.0.0, Cofree((lines, columns, range), .Fixed([values.0.1, values.1])))
2015-10-26 22:06:45 +03:00
}
2015-10-16 22:41:35 +03:00
2015-10-26 23:52:30 +03:00
return sepBy(pairs, whitespace <* %"," <* whitespace)
2015-10-16 22:41:35 +03:00
}
2015-10-26 22:06:33 +03:00
public let json: JSONParser = fix { json in
2015-10-21 18:25:28 +03:00
let string: JSONParser = quoted --> {
2015-11-10 22:11:09 +03:00
Cofree(($1, $2, $3), .Leaf(.String($4)))
2015-10-21 18:25:28 +03:00
} <?> "string"
let array: JSONParser = %"["
<* whitespace
2015-10-27 23:26:24 +03:00
*> sepBy(whitespace *> json, whitespace <* %"," <* whitespace)
<* whitespace
2015-10-21 18:25:28 +03:00
<* %"]"
--> {
2015-11-10 22:11:09 +03:00
Cofree(($1, $2, $3), .Indexed($4))
2015-10-21 18:25:28 +03:00
} <?> "array"
let object: JSONParser = %"{"
*> whitespace
*> members(json)
<* whitespace
<* %"}"
2015-11-10 22:11:09 +03:00
--> { (_, lines, columns, range, values: [(String, CofreeJSON)]) in
Cofree((lines, columns, range), .Keyed(Dictionary(elements: values)))
2015-10-21 18:25:28 +03:00
} <?> "object"
2015-10-16 22:41:35 +03:00
2015-11-10 22:11:09 +03:00
let numberParser: JSONParser = (number --> { _, lines, columns, range, value in
Cofree((lines, columns, range), .Leaf(JSONLeaf.Number(value)))
2015-10-21 18:25:28 +03:00
}) <?> "number"
2015-10-20 18:11:06 +03:00
2015-11-10 22:11:09 +03:00
let null: JSONParser = %"null" --> { _, lines, columns, range, value in
return Cofree((lines, columns, range), .Leaf(.Null))
2015-10-21 18:25:28 +03:00
} <?> "null"
2015-10-20 18:11:06 +03:00
2015-11-10 22:11:09 +03:00
let boolean: JSONParser = %"false" <|> %"true" --> { _, lines, columns, range, value in
2015-10-20 18:11:06 +03:00
let boolean = value == "true"
return Cofree((lines, columns, range), .Leaf(.Boolean(boolean)))
2015-10-21 18:25:28 +03:00
} <?> "boolean"
2015-10-16 22:41:35 +03:00
2015-10-20 18:11:06 +03:00
// TODO: This should be JSON = dict <|> array and
// Value = dict | array | string | number | null | bool
return (object <|> array <|> string <|> numberParser <|> boolean <|> null) <* whitespace
2015-10-21 18:11:49 +03:00
}