Skip to content

Instantly share code, notes, and snippets.

@oisdk
Last active September 13, 2015 15:37
Show Gist options
  • Save oisdk/1636179be6be9ac428e6 to your computer and use it in GitHub Desktop.
Save oisdk/1636179be6be9ac428e6 to your computer and use it in GitHub Desktop.
extension CollectionType where Index : BidirectionalIndexType {
private func lastIndexOfNot(@noescape isNotElement: Generator.Element throws -> Bool) rethrows -> Index? {
for i in indices.reverse()
where (try !isNotElement(self[i])) {
return i
}
return nil
}
}
extension CollectionType {
private func indexOfNot(@noescape isNotElement: Generator.Element throws -> Bool) rethrows -> Index? {
for i in indices
where (try !isNotElement(self[i])) {
return i
}
return nil
}
}
extension CollectionType where Generator.Element : Equatable {
private func indexOfNot(e: Generator.Element) -> Index? {
return indexOfNot { o in o == e }
}
}
extension CollectionType where Index : BidirectionalIndexType, Generator.Element : Equatable {
private func lastIndexOfNot(e: Generator.Element) -> Index? {
return lastIndexOfNot { o in o == e }
}
}
extension String.CharacterView {
private func trim(c: Character) -> String.CharacterView {
guard let s = indexOfNot(c), e = lastIndexOfNot(c) else { return "".characters }
return self[s...e]
}
private func trim(cs: Set<Character>) -> String.CharacterView {
guard let s = indexOfNot(cs.contains), e = lastIndexOfNot(cs.contains) else { return "".characters }
return self[s...e]
}
private func trim(c0: Character, _ c1: Character, _ rest: Character...) -> String.CharacterView {
return trim(Set([c0, c1] + rest))
}
}
public enum Result<T,E> { case Some(T), Error(E) }
public enum JSONError : ErrorType { case UnBalancedBrackets, ParseError, Empty }
extension String.CharacterView {
func bracketSplit(open: Character, _ close: Character) -> Result<(String.CharacterView, String.CharacterView),JSONError> {
var count = 1
for i in indices.dropFirst() {
if self[i.predecessor()] == "\\" { continue }
if self[i] == close { --count } else
if self[i] == open { ++count }
if count == 0 {
return .Some(self[startIndex.successor()..<i], suffixFrom(i.successor()))
}
}
return .Error(.UnBalancedBrackets)
}
}
public enum JSON { case S(String), D(Double), I(Int), B(Bool), A([JSON]), O([String:JSON]), null }
extension String {
private func decodeAsAtom() -> Result<JSON,JSONError> {
switch self {
case "null" : return .Some(.null)
case "true" : return .Some(.B(true))
case "false": return .Some(.B(false))
case let s: return
Int(s).map { i in .Some(.I(i)) } ??
Double(s).map { d in .Some(.D(d)) } ??
.Error(.ParseError)
}
}
}
extension String.CharacterView {
private func decodeAsArray() -> Result<[JSON],JSONError> {
return decodeAsArrayWith([])
}
private func decodeAsArrayWith(p: [JSON]) -> Result<[JSON],JSONError> {
switch decodeToDelim() {
case let (f,b)?: return b.decodeAsArrayWith(p + [f])
case let .Error(e):
if case .Empty = e { return .Some(p) }
return .Error(e)
}
}
private func decodeAsDict() -> Result<[String:JSON],JSONError> {
return decodeAsDictWith([:])
}
private func decodeAsDictWith(var p: [String:JSON]) -> Result<[String:JSON],JSONError> {
guard let i = indexOf("\"") else { return .Some(p) }
guard let (k,b) = suffixFrom(i).bracketSplit("\"", "\"") else { return .Error(.UnBalancedBrackets) }
guard let j = b.indexOf(":") else { return .Error(.ParseError) }
guard let (v,d) = b.suffixFrom(j.successor()).decodeToDelim() else { return .Error(.ParseError) }
p[String(k)] = v
return d.decodeAsDictWith(p)
}
}
extension String.CharacterView {
private func decodeToDelim() -> Result<(JSON, String.CharacterView),JSONError> {
let wSpace: Set<Character> = [" ", ",", "\n"]
guard let i = indexOfNot(wSpace.contains) else { return .Error(.Empty) }
switch self[i] {
case "[":
guard let (f,b) = suffixFrom(i).bracketSplit("[", "]")
else { return .Error(.UnBalancedBrackets) }
switch f.decodeAsArray() {
case let a? : return .Some(.A(a), b)
case let .Error(e): return .Error(e)
}
case "{":
guard let (f,b) = suffixFrom(i).bracketSplit("{", "}")
else { return .Error(.UnBalancedBrackets) }
switch f.decodeAsDict() {
case let o? : return .Some(.O(o), b)
case let .Error(e): return .Error(e)
}
case "\"":
guard let (f,b) = suffixFrom(i).bracketSplit("\"", "\"")
else { return .Error(.UnBalancedBrackets) }
return .Some(.S(String(f)), b)
default:
let suff = suffixFrom(i)
let j = suff.indexOf(",") ?? suff.endIndex
guard let a = String(suff.prefixUpTo(j).trim(wSpace)).decodeAsAtom()
else { return .Error(.ParseError) }
return .Some(a, suff.suffixFrom(j))
}
}
}
extension JSON : CustomStringConvertible {
private func desWithInd(i: String) -> String {
switch self {
case let .A(a):
let indented = a.map { e in i + " " + e.desWithInd(i + " ") }
let joined = indented.joinWithSeparator(",\n")
return "[\n" + joined + "\n" + i + "]"
case let .O(o):
let indented = o.map { (k,v) in i + " \"" + k + "\": " + v.desWithInd(i + " ")}
let joined = indented.joinWithSeparator(",\n")
return "{\n" + joined + "\n" + i + "}"
case let .S(s): return "\"" + s + "\""
case let .B(b): return b.description
case let .D(d): return d.description
case let .I(i): return i.description
case null: return "null"
}
}
public var description: String {
return desWithInd("")
}
}
extension String {
public func asJSONThrow() throws -> JSON {
switch characters.decodeToDelim() {
case let j?: return j.0
case let .Error(e): throw e
}
}
public func asJSONResult() -> Result<JSON,JSONError> {
switch characters.decodeToDelim() {
case let j?: return .Some(j.0)
case let .Error(e): return .Error(e)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment