mirror of
https://github.com/github/semantic.git
synced 2024-12-26 16:33:03 +03:00
Move JSONLeaf and JSONParser to files
This commit is contained in:
parent
e7fa851420
commit
295afbef6f
@ -8,6 +8,8 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
D18FF8821BD0404700D18F2D /* Madness.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D18FF8811BD0404700D18F2D /* Madness.framework */; };
|
||||
D1A0934E1BD18969005A6326 /* JSONLeaf.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0934C1BD188F5005A6326 /* JSONLeaf.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
D1A0934F1BD189B4005A6326 /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0934A1BD188CA005A6326 /* JSONParser.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
D40B89C41BC319070078E098 /* Matrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40B89C31BC319070078E098 /* Matrix.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
D40B89C81BC439000078E098 /* Assertions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40B89C71BC439000078E098 /* Assertions.framework */; };
|
||||
D40D72541BCEEB1F001B7A9E /* AlgorithmTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40D72531BCEEB1F001B7A9E /* AlgorithmTests.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
@ -57,6 +59,8 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
D18FF8811BD0404700D18F2D /* Madness.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Madness.framework; path = "../../../../Library/Developer/Xcode/DerivedData/Doubt-gibmbsxjgxflybarnuoisglmgdll/Build/Products/Debug/Madness.framework"; sourceTree = "<group>"; };
|
||||
D1A0934A1BD188CA005A6326 /* JSONParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONParser.swift; sourceTree = "<group>"; };
|
||||
D1A0934C1BD188F5005A6326 /* JSONLeaf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONLeaf.swift; sourceTree = "<group>"; };
|
||||
D40B89C31BC319070078E098 /* Matrix.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matrix.swift; sourceTree = "<group>"; };
|
||||
D40B89C71BC439000078E098 /* Assertions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Assertions.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D40D72531BCEEB1F001B7A9E /* AlgorithmTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlgorithmTests.swift; sourceTree = "<group>"; };
|
||||
@ -171,6 +175,8 @@
|
||||
D4DF96EC1BC46B630040F41F /* SES.swift */,
|
||||
D435B7521BB31BBC000902F6 /* BoundsCheckedArray.swift */,
|
||||
D42F097F1BCECB7900B95610 /* TermType.swift */,
|
||||
D1A0934A1BD188CA005A6326 /* JSONParser.swift */,
|
||||
D1A0934C1BD188F5005A6326 /* JSONLeaf.swift */,
|
||||
D4AAE5001B5AE22E004E581F /* Supporting Files */,
|
||||
);
|
||||
path = Doubt;
|
||||
@ -379,6 +385,8 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D4DF970A1BC5DF800040F41F /* main.swift in Sources */,
|
||||
D1A0934E1BD18969005A6326 /* JSONLeaf.swift in Sources */,
|
||||
D1A0934F1BD189B4005A6326 /* JSONParser.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
106
prototype/Doubt/JSONLeaf.swift
Normal file
106
prototype/Doubt/JSONLeaf.swift
Normal file
@ -0,0 +1,106 @@
|
||||
//
|
||||
// JSONLeaf.swift
|
||||
// Doubt
|
||||
//
|
||||
// Created by Josh Vera on 10/16/15.
|
||||
// Copyright © 2015 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Doubt
|
||||
|
||||
typealias Term = Cofree<JSONLeaf, Int>
|
||||
typealias Diff = Free<JSONLeaf, Patch<Term>>
|
||||
|
||||
enum JSONLeaf: CustomJSONConvertible, CustomStringConvertible, Equatable {
|
||||
case Number(Double)
|
||||
case Boolean(Bool)
|
||||
case String(Swift.String)
|
||||
case Null
|
||||
|
||||
|
||||
// MARK: CustomJSONConvertible
|
||||
|
||||
var JSON: Doubt.JSON {
|
||||
switch self {
|
||||
case let .Number(n):
|
||||
return .Number(n)
|
||||
case let .Boolean(b):
|
||||
return .Boolean(b)
|
||||
case let .String(s):
|
||||
return .String(s)
|
||||
case .Null:
|
||||
return .Null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: CustomStringConvertible
|
||||
|
||||
var description: Swift.String {
|
||||
switch self {
|
||||
case let .Number(n):
|
||||
return Swift.String(n)
|
||||
case let .Boolean(b):
|
||||
return Swift.String(b)
|
||||
case let .String(s):
|
||||
return Swift.String(reflecting: s)
|
||||
case .Null:
|
||||
return "null"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func == (left: JSONLeaf, right: JSONLeaf) -> Bool {
|
||||
switch (left, right) {
|
||||
case let (.Number(a), .Number(b)):
|
||||
return a == b
|
||||
case let (.Boolean(a), .Boolean(b)):
|
||||
return a == b
|
||||
case let (.String(a), .String(b)):
|
||||
return a == b
|
||||
case (.Null, .Null):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
extension JSON {
|
||||
init?(path: Swift.String) {
|
||||
guard let data = try? NSData(contentsOfFile: path, options: []) else { return nil }
|
||||
guard let object = try? NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) else { return nil }
|
||||
self.init(object: object)
|
||||
}
|
||||
|
||||
var term: Term {
|
||||
func annotate(json: Syntax<Term, JSONLeaf>) -> Term {
|
||||
return Cofree(size(json), json)
|
||||
}
|
||||
func size(syntax: Syntax<Term, JSONLeaf>) -> Int {
|
||||
switch syntax {
|
||||
case .Leaf:
|
||||
return 1
|
||||
case let .Indexed(i):
|
||||
return 1 + i.map { size($0.unwrap) }.reduce(0, combine: +)
|
||||
case let .Keyed(i):
|
||||
return 1 + i.values.map { size($0.unwrap) }.reduce(0, combine: +)
|
||||
}
|
||||
}
|
||||
|
||||
switch self {
|
||||
case let .Array(a):
|
||||
return annotate(.Indexed(a.map { $0.term }))
|
||||
case let .Dictionary(d):
|
||||
return annotate(.Keyed(Swift.Dictionary(elements: d.map { ($0, $1.term) })))
|
||||
case let .Number(n):
|
||||
return annotate(.Leaf(.Number(n)))
|
||||
case let .Boolean(b):
|
||||
return annotate(.Leaf(.Boolean(b)))
|
||||
case let .String(s):
|
||||
return annotate(.Leaf(.String(s)))
|
||||
case .Null:
|
||||
return annotate(.Leaf(.Null))
|
||||
}
|
||||
}
|
||||
}
|
110
prototype/Doubt/JSONParser.swift
Normal file
110
prototype/Doubt/JSONParser.swift
Normal file
@ -0,0 +1,110 @@
|
||||
//
|
||||
// JSONParser.swift
|
||||
// Doubt
|
||||
//
|
||||
// Created by Josh Vera on 10/16/15.
|
||||
// Copyright © 2015 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Madness
|
||||
import Either
|
||||
import Prelude
|
||||
import Doubt
|
||||
|
||||
typealias CofreeJSON = Cofree<JSONLeaf, Range<String.CharacterView.Index>>
|
||||
typealias JSONParser = Parser<String, CofreeJSON>.Function
|
||||
|
||||
extension String: CollectionType {
|
||||
public var count: Index.Distance {
|
||||
return characters.count
|
||||
}
|
||||
}
|
||||
|
||||
func not<C: CollectionType, T>(parser: Parser<C, T>.Function)(_ input: C, _ index: C.Index) -> Either<Error<C.Index>, (C.Generator.Element, C.Index)> {
|
||||
if index.distanceTo(input.endIndex) <= 0 || parser(input, index).right != nil {
|
||||
return .Left(Error(reason: "", index: index, children: []))
|
||||
} else {
|
||||
return .Right(input[index], index.successor())
|
||||
}
|
||||
}
|
||||
|
||||
public func satisfy<C: CollectionType> (pred: C.Generator.Element -> Bool) -> Parser<C, C.Generator.Element>.Function {
|
||||
return { input, index in
|
||||
if input.count > 0 {
|
||||
let parsed = input[index]
|
||||
let next = index.successor()
|
||||
|
||||
return pred(parsed)
|
||||
? .Right((parsed, next))
|
||||
: .Left(Error.leaf("Failed to match predicate at index", index))
|
||||
} else {
|
||||
return .Left(Error.leaf("", index))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typealias StringParser = Parser<String, String>.Function
|
||||
typealias CharacterParser = Parser<String, [Character]>.Function
|
||||
|
||||
let stringBody: StringParser = { $0.map({ String($0) }).joinWithSeparator("") } <^>
|
||||
not(%"\\" <|> %"\"")*
|
||||
let quoted = %"\"" *> stringBody <* %"\""
|
||||
let whitespace: CharacterParser = satisfy({ (c: Character) in c == " " })*
|
||||
|
||||
typealias MembersParser = Parser<String, [(String, CofreeJSON)]>.Function;
|
||||
|
||||
func members(json: JSONParser) -> MembersParser {
|
||||
let pairs: Parser<String, (String, CofreeJSON)>.Function = (curry(pair) <^>
|
||||
quoted
|
||||
<* whitespace
|
||||
<* %":"
|
||||
<* whitespace
|
||||
<*> json)
|
||||
|
||||
let separatedPairs: MembersParser = (%"," *> whitespace *> pairs <* whitespace)*
|
||||
|
||||
let oneOrMore: MembersParser = curry { [$0] + $1 } <^>
|
||||
pairs
|
||||
<* whitespace
|
||||
<*> separatedPairs
|
||||
|
||||
return oneOrMore <|> pure([])
|
||||
}
|
||||
|
||||
typealias ValuesParser = Parser<String, [CofreeJSON]>.Function;
|
||||
func elements(json: JSONParser) -> ValuesParser {
|
||||
let value: Parser<String, CofreeJSON>.Function = whitespace *> json <* whitespace
|
||||
|
||||
let separatedValues: ValuesParser = (%"," *> whitespace *> value <* whitespace)*
|
||||
|
||||
let oneOrMore: ValuesParser = curry { [$0] + $1 } <^>
|
||||
value
|
||||
<* whitespace
|
||||
<*> separatedValues
|
||||
return oneOrMore <|> pure([])
|
||||
}
|
||||
|
||||
|
||||
let json: JSONParser = fix { json in
|
||||
// TODO: Parse backslashed escape characters
|
||||
|
||||
let string: JSONParser = quoted --> { Cofree($1, .Leaf(.String($2))) }
|
||||
let array: JSONParser = %"[" *> elements(json) <* %"]" --> { Cofree($1, .Indexed($2)) }
|
||||
|
||||
let object: JSONParser =
|
||||
%"{"
|
||||
*> whitespace
|
||||
*> members(json)
|
||||
<* whitespace
|
||||
<* %"}"
|
||||
--> { (_, range, values) in
|
||||
Cofree(range, .Keyed(Dictionary(elements: values)))
|
||||
}
|
||||
|
||||
// TODO: Parse Numbers correctly
|
||||
let number: JSONParser = %"0" --> { Cofree($1, .Leaf(.String($2))) }
|
||||
|
||||
// TODO: This should just be dict <|> array and Value = dict | array | string | number | null | bool
|
||||
return object <|> array <|> string <|> number
|
||||
}
|
@ -4,206 +4,9 @@ import Either
|
||||
import Prelude
|
||||
import Madness
|
||||
|
||||
typealias Term = Cofree<JSONLeaf, Int>
|
||||
typealias Diff = Free<JSONLeaf, Patch<Term>>
|
||||
|
||||
enum JSONLeaf: CustomJSONConvertible, CustomStringConvertible, Equatable {
|
||||
case Number(Double)
|
||||
case Boolean(Bool)
|
||||
case String(Swift.String)
|
||||
case Null
|
||||
|
||||
|
||||
// MARK: CustomJSONConvertible
|
||||
|
||||
var JSON: Doubt.JSON {
|
||||
switch self {
|
||||
case let .Number(n):
|
||||
return .Number(n)
|
||||
case let .Boolean(b):
|
||||
return .Boolean(b)
|
||||
case let .String(s):
|
||||
return .String(s)
|
||||
case .Null:
|
||||
return .Null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: CustomStringConvertible
|
||||
|
||||
var description: Swift.String {
|
||||
switch self {
|
||||
case let .Number(n):
|
||||
return Swift.String(n)
|
||||
case let .Boolean(b):
|
||||
return Swift.String(b)
|
||||
case let .String(s):
|
||||
return Swift.String(reflecting: s)
|
||||
case .Null:
|
||||
return "null"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func == (left: JSONLeaf, right: JSONLeaf) -> Bool {
|
||||
switch (left, right) {
|
||||
case let (.Number(a), .Number(b)):
|
||||
return a == b
|
||||
case let (.Boolean(a), .Boolean(b)):
|
||||
return a == b
|
||||
case let (.String(a), .String(b)):
|
||||
return a == b
|
||||
case (.Null, .Null):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
extension JSON {
|
||||
init?(path: Swift.String) {
|
||||
guard let data = try? NSData(contentsOfFile: path, options: []) else { return nil }
|
||||
guard let object = try? NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) else { return nil }
|
||||
self.init(object: object)
|
||||
}
|
||||
|
||||
var term: Term {
|
||||
func annotate(json: Syntax<Term, JSONLeaf>) -> Term {
|
||||
return Cofree(size(json), json)
|
||||
}
|
||||
func size(syntax: Syntax<Term, JSONLeaf>) -> Int {
|
||||
switch syntax {
|
||||
case .Leaf:
|
||||
return 1
|
||||
case let .Indexed(i):
|
||||
return 1 + i.map { size($0.unwrap) }.reduce(0, combine: +)
|
||||
case let .Keyed(i):
|
||||
return 1 + i.values.map { size($0.unwrap) }.reduce(0, combine: +)
|
||||
}
|
||||
}
|
||||
|
||||
switch self {
|
||||
case let .Array(a):
|
||||
return annotate(.Indexed(a.map { $0.term }))
|
||||
case let .Dictionary(d):
|
||||
return annotate(.Keyed(Swift.Dictionary(elements: d.map { ($0, $1.term) })))
|
||||
case let .Number(n):
|
||||
return annotate(.Leaf(.Number(n)))
|
||||
case let .Boolean(b):
|
||||
return annotate(.Leaf(.Boolean(b)))
|
||||
case let .String(s):
|
||||
return annotate(.Leaf(.String(s)))
|
||||
case .Null:
|
||||
return annotate(.Leaf(.Null))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let arguments = BoundsCheckedArray(array: Process.arguments)
|
||||
|
||||
typealias CofreeJSON = Cofree<JSONLeaf, Range<String.CharacterView.Index>>
|
||||
typealias JSONParser = Parser<String, CofreeJSON>.Function
|
||||
|
||||
extension String: CollectionType {
|
||||
public var count: Index.Distance {
|
||||
return characters.count
|
||||
}
|
||||
|
||||
public static func lift<A>(parser: Parser<String.CharacterView, A>.Function) -> Parser<String, A>.Function {
|
||||
return {
|
||||
parser($0.characters, $1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func not<C: CollectionType, T>(parser: Parser<C, T>.Function)(_ input: C, _ index: C.Index) -> Either<Error<C.Index>, (C.Generator.Element, C.Index)> {
|
||||
if index.distanceTo(input.endIndex) <= 0 || parser(input, index).right != nil {
|
||||
return .Left(Error(reason: "", index: index, children: []))
|
||||
} else {
|
||||
return .Right(input[index], index.successor())
|
||||
}
|
||||
}
|
||||
|
||||
public func satisfy<C: CollectionType> (pred: C.Generator.Element -> Bool) -> Parser<C, C.Generator.Element>.Function {
|
||||
return { input, index in
|
||||
if input.count > 0 {
|
||||
let parsed = input[index]
|
||||
let next = index.successor()
|
||||
|
||||
return pred(parsed)
|
||||
? .Right((parsed, next))
|
||||
: .Left(Error.leaf("Failed to match predicate at index", index))
|
||||
} else {
|
||||
return .Left(Error.leaf("", index))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typealias StringParser = Parser<String, String>.Function
|
||||
typealias CharacterParser = Parser<String, [Character]>.Function
|
||||
|
||||
let stringBody: StringParser = { $0.map({ String($0) }).joinWithSeparator("") } <^>
|
||||
not(%"\\" <|> %"\"")*
|
||||
let quoted = %"\"" *> stringBody <* %"\""
|
||||
let whitespace: CharacterParser = satisfy({ (c: Character) in c == " " })*
|
||||
|
||||
typealias MembersParser = Parser<String, [(String, CofreeJSON)]>.Function;
|
||||
|
||||
func members(json: JSONParser) -> MembersParser {
|
||||
let pairs: Parser<String, (String, CofreeJSON)>.Function = (curry(pair) <^>
|
||||
quoted
|
||||
<* whitespace
|
||||
<* %":"
|
||||
<* whitespace
|
||||
<*> json)
|
||||
|
||||
let separatedPairs: MembersParser = (%"," *> whitespace *> pairs <* whitespace)*
|
||||
|
||||
let oneOrMore: MembersParser = curry { [$0] + $1 } <^>
|
||||
pairs
|
||||
<* whitespace
|
||||
<*> separatedPairs
|
||||
|
||||
return oneOrMore <|> pure([])
|
||||
}
|
||||
|
||||
typealias ValuesParser = Parser<String, [CofreeJSON]>.Function;
|
||||
func elements(json: JSONParser) -> ValuesParser {
|
||||
let value: Parser<String, CofreeJSON>.Function = whitespace *> json <* whitespace
|
||||
|
||||
let separatedValues: ValuesParser = (%"," *> whitespace *> value <* whitespace)*
|
||||
|
||||
let oneOrMore: ValuesParser = curry { [$0] + $1 } <^>
|
||||
value
|
||||
<* whitespace
|
||||
<*> separatedValues
|
||||
return oneOrMore <|> pure([])
|
||||
}
|
||||
|
||||
|
||||
let json: JSONParser = fix { json in
|
||||
// TODO: Parse backslashed escape characters
|
||||
|
||||
let string: JSONParser = quoted --> { Cofree($1, .Leaf(.String($2))) }
|
||||
let array: JSONParser = %"[" *> elements(json) <* %"]" --> { Cofree($1, .Indexed($2)) }
|
||||
|
||||
let dict: JSONParser =
|
||||
%"{"
|
||||
*> whitespace
|
||||
*> members(json)
|
||||
<* whitespace
|
||||
<* %"}"
|
||||
--> { (_, range, values) in
|
||||
Cofree(range, .Keyed(Dictionary(elements: values)))
|
||||
}
|
||||
|
||||
// TODO: Parse Numbers correctly
|
||||
let number: JSONParser = %"0" --> { Cofree($1, .Leaf(.String($2))) }
|
||||
|
||||
return dict <|> array <|> string
|
||||
}
|
||||
|
||||
let empty = "{}"
|
||||
print(parse(json, input: empty))
|
||||
let dict = "{\"hello\":\"world\"}"
|
||||
@ -217,9 +20,9 @@ print(parse(json, input: dictWithMembers))
|
||||
let dictWithArray = "{\"hello\": [\"world\"],\"sup\": [\"cat\", \"dog\", \"keith\"] }"
|
||||
print(parse(json, input: dictWithArray))
|
||||
|
||||
//if let a = arguments[1].flatMap(JSON.init), b = arguments[2].flatMap(JSON.init) {
|
||||
// let diff = Algorithm<Term, Diff>(a.term, b.term).evaluate(Cofree.equals(annotation: const(true), leaf: ==))
|
||||
// if let JSON = NSString(data: diff.JSON(ifPure: { $0.JSON { $0.JSON } }, ifLeaf: { $0.JSON }).serialize(), encoding: NSUTF8StringEncoding) {
|
||||
// print(JSON)
|
||||
// }
|
||||
//}
|
||||
if let a = arguments[1].flatMap(JSON.init), b = arguments[2].flatMap(JSON.init) {
|
||||
let diff = Algorithm<Term, Diff>(a.term, b.term).evaluate(Cofree.equals(annotation: const(true), leaf: ==))
|
||||
if let JSON = NSString(data: diff.JSON(ifPure: { $0.JSON { $0.JSON } }, ifLeaf: { $0.JSON }).serialize(), encoding: NSUTF8StringEncoding) {
|
||||
print(JSON)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user