-
-
Save nerdsupremacist/8558223183db9d9a71fbfe790fdadf0a to your computer and use it in GitHub Desktop.
JSON Parser built using Ogma
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ogma | |
public enum JSON { | |
case dictionary([String : JSON]) | |
case array([JSON]) | |
case int(Int) | |
case double(Double) | |
case string(String) | |
case bool(Bool) | |
case null | |
} | |
extension JSON { | |
public enum Token: TokenProtocol { | |
case openCurlyBracket | |
case closeCurlyBracket | |
case openSquareBracket | |
case closeSquareBracket | |
case comma | |
case colon | |
case `true` | |
case `false` | |
case string(String) | |
case double(Double) | |
case int(Int) | |
case null | |
} | |
} | |
extension JSON.Token { | |
var string: String? { | |
guard case .string(let string) = self else { return nil } | |
return string | |
} | |
var int: Int? { | |
guard case .int(let int) = self else { return nil } | |
return int | |
} | |
var double: Double? { | |
guard case .double(let double) = self else { return nil } | |
return double | |
} | |
} | |
extension JSON { | |
enum Lexer: GeneratorLexer { | |
typealias Token = JSON.Token | |
static let generators: Generators = [ | |
RegexTokenGenerator(pattern: "\\{").map(to: .openCurlyBracket), | |
RegexTokenGenerator(pattern: "\\}").map(to: .closeCurlyBracket), | |
RegexTokenGenerator(pattern: "\\[").map(to: .openSquareBracket), | |
RegexTokenGenerator(pattern: "\\]").map(to: .closeSquareBracket), | |
RegexTokenGenerator(pattern: ",").map(to: .comma), | |
RegexTokenGenerator(pattern: ":").map(to: .colon), | |
RegexTokenGenerator(pattern: "true\\b").map(to: .true), | |
RegexTokenGenerator(pattern: "false\\b").map(to: .false), | |
RegexTokenGenerator(pattern: "null\\b").map(to: .null), | |
StringLiteralTokenGenerator().map(Token.string), | |
DoubleLiteralTokenGenerator().map(Token.double), | |
IntLiteralTokenGenerator().map(Token.int), | |
WhiteSpaceTokenGenerator().ignore(), | |
] | |
} | |
} | |
extension Bool: Parsable { | |
public static let parser: AnyParser<JSON.Token, Bool> = Token.true.map { true } || | |
Token.false.map { false } | |
} | |
extension String: Parsable { | |
public static let parser: AnyParser<JSON.Token, String> = .consuming(keyPath: \.string) | |
} | |
extension Int: Parsable { | |
public static let parser: AnyParser<JSON.Token, Int> = .consuming(keyPath: \.int) | |
} | |
extension Double: Parsable { | |
public static let parser: AnyParser<JSON.Token, Double> = .consuming(keyPath: \.double) | |
} | |
extension Array: Parsable where Element: Parsable, Element.Token == JSON.Token { | |
public typealias Token = JSON.Token | |
public static let parser: AnyParser<JSON.Token, Array<JSON>> = Element | |
.separated(by: .comma, allowsEmpty: true) | |
.wrapped(by: .openSquareBracket, and: .closeSquareBracket) | |
} | |
extension Dictionary: Parsable where Key: Parsable, Key.Token == JSON.Token, Value: Parsable, Value.Token == JSON.Token { | |
public typealias Token = JSON.Token | |
public static var parser: AnyParser<JSON.Token, Dictionary<Key, Value>> { | |
let element = Key.self && .colon && Value.self | |
return element | |
.separated(by: .comma, allowsTrailingSeparator: true, allowsEmpty: true) | |
.map { Dictionary($0, uniquingKeysWith: { $1 }) } | |
.wrapped(by: .openCurlyBracket, and: .closeCurlyBracket) | |
} | |
} | |
extension JSON: Parsable { | |
public static let parser: AnyParser<Token, JSON> = Bool.map(JSON.bool) || | |
Int.map(JSON.int) || | |
Double.map(JSON.double) || | |
String.map(JSON.string) || | |
Token.null.map { .null } || | |
Array<JSON>.map(JSON.array) || | |
Dictionary<String, JSON>.map(JSON.dictionary) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment