1
1
mirror of https://github.com/github/semantic.git synced 2024-11-24 17:04:47 +03:00

Merge branch 'master' into parse-with-tree-sitter

Conflicts:
	prototype/Doubt.xcodeproj/project.pbxproj
This commit is contained in:
Rob Rix 2015-10-27 18:15:53 -04:00
commit 06185b9b4f
5 changed files with 69 additions and 66 deletions

View File

@ -8,8 +8,9 @@
/* 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 */; };
D1A0934F1BD189B4005A6326 /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0934A1BD188CA005A6326 /* JSONParser.swift */; };
D1F5FE201BDE891F0048BAE4 /* JSONParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1F5FE1F1BDE891F0048BAE4 /* JSONParserTests.swift */; };
D1F5FE211BDE9C450048BAE4 /* JSONLeaf.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0934C1BD188F5005A6326 /* JSONLeaf.swift */; };
D1F5FE221BDE9CC10048BAE4 /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A0934A1BD188CA005A6326 /* JSONParser.swift */; };
D40B89C41BC319070078E098 /* Matrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40B89C31BC319070078E098 /* Matrix.swift */; };
D40B89C81BC439000078E098 /* Assertions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40B89C71BC439000078E098 /* Assertions.framework */; };
D40D72541BCEEB1F001B7A9E /* InterpreterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40D72531BCEEB1F001B7A9E /* InterpreterTests.swift */; };
@ -83,6 +84,7 @@
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>"; };
D1F5FE1F1BDE891F0048BAE4 /* JSONParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONParserTests.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 /* InterpreterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterpreterTests.swift; sourceTree = "<group>"; };
@ -250,6 +252,7 @@
D4AAE5111B5AE22E004E581F /* DoubtTests */ = {
isa = PBXGroup;
children = (
D1F5FE1F1BDE891F0048BAE4 /* JSONParserTests.swift */,
D432D4701BA9AC0B00F3FABC /* SESTests.swift */,
D40D72531BCEEB1F001B7A9E /* InterpreterTests.swift */,
D40D725B1BD15417001B7A9E /* RangedTerm.swift */,
@ -459,6 +462,7 @@
D42F097E1BCEAEDA00B95610 /* Operation.swift in Sources */,
D45A36C91BBC667D00BE3DDE /* Categorizable.swift in Sources */,
D4DF96ED1BC46B630040F41F /* SES.swift in Sources */,
D1F5FE221BDE9CC10048BAE4 /* JSONParser.swift in Sources */,
D42F09801BCECB7900B95610 /* TermType.swift in Sources */,
D4AAE5401B5AE2D0004E581F /* RangeReplaceableCollectionType.swift in Sources */,
D49FCBC41BBEF98E00C5E9C3 /* Free.swift in Sources */,
@ -470,6 +474,7 @@
D40B89C41BC319070078E098 /* Matrix.swift in Sources */,
D4AAE5491B5AE2D0004E581F /* StringLiteralConvertible.swift in Sources */,
D4413FF11BB08FDC00E3C3C1 /* JSON.swift in Sources */,
D1F5FE211BDE9C450048BAE4 /* JSONLeaf.swift in Sources */,
D4AAE5451B5AE2D0004E581F /* Operators.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -480,6 +485,7 @@
files = (
D40D72641BD1A0C1001B7A9E /* RangedDiff.swift in Sources */,
D40D725E1BD1826C001B7A9E /* TermTests.swift in Sources */,
D1F5FE201BDE891F0048BAE4 /* JSONParserTests.swift in Sources */,
D40D72601BD19E69001B7A9E /* DiffTests.swift in Sources */,
D432D4711BA9AC0B00F3FABC /* SESTests.swift in Sources */,
D40D72621BD1A07E001B7A9E /* UnannotatedTerm.swift in Sources */,
@ -493,8 +499,6 @@
buildActionMask = 2147483647;
files = (
D4DF970A1BC5DF800040F41F /* main.swift in Sources */,
D1A0934E1BD18969005A6326 /* JSONLeaf.swift in Sources */,
D1A0934F1BD189B4005A6326 /* JSONParser.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -7,12 +7,11 @@
//
import Foundation
import Doubt
typealias Term = Cofree<JSONLeaf, Range<String.Index>>
typealias Diff = Free<JSONLeaf, Term.Annotation, Patch<Term>>
enum JSONLeaf: CustomJSONConvertible, CustomStringConvertible, Equatable {
public enum JSONLeaf: CustomJSONConvertible, CustomStringConvertible, Equatable {
case Number(Double)
case Boolean(Bool)
case String(Swift.String)
@ -21,7 +20,7 @@ enum JSONLeaf: CustomJSONConvertible, CustomStringConvertible, Equatable {
// MARK: CustomJSONConvertible
var JSON: Doubt.JSON {
public var JSON: Doubt.JSON {
switch self {
case let .Number(n):
return .Number(n)
@ -37,7 +36,7 @@ enum JSONLeaf: CustomJSONConvertible, CustomStringConvertible, Equatable {
// MARK: CustomStringConvertible
var description: Swift.String {
public var description: Swift.String {
switch self {
case let .Number(n):
return Swift.String(n)
@ -51,7 +50,7 @@ enum JSONLeaf: CustomJSONConvertible, CustomStringConvertible, Equatable {
}
}
func == (left: JSONLeaf, right: JSONLeaf) -> Bool {
public func == (left: JSONLeaf, right: JSONLeaf) -> Bool {
switch (left, right) {
case let (.Number(a), .Number(b)):
return a == b

View File

@ -8,80 +8,53 @@
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
}
public static func lift<A>(parser: Parser<String.CharacterView, A>.Function) -> Parser<String, A>.Function {
return {
parser($0.characters, $1)
}
}
}
typealias StringParser = Parser<String, String>.Function
typealias CharacterParser = Parser<String, [Character]>.Function
public typealias CofreeJSON = Cofree<JSONLeaf, Range<String.CharacterView.Index>>
public typealias JSONParser = Parser<String.CharacterView, CofreeJSON>.Function
// Inlined for performance reasons
let whitespaceChars: [Character] = [" ", "\n", "\t", "\r"]
let whitespace: CharacterParser = String.lift(satisfy({ whitespaceChars.contains($0) })*)
let whitespace = oneOf(" \n\r\t")*
// TODO: Parse unicode escape sequence
let escapeChar: StringParser = curry(+) <^> %"\\" <*> ({ String($0) } <^> oneOf("\\\"bfnrt"))
let otherChar: StringParser = { String($0) } <^> noneOf("\"\\")
// Quoted strings parser
// TODO: Improve string parsing
let stringBody: StringParser = { $0.map({ String($0) }).joinWithSeparator("") } <^>
String.lift(noneOf("\"")*)
let quoted = %"\"" *> stringBody <* %"\"" <* whitespace
let stringBody: StringParser = { $0.joinWithSeparator("") } <^> many(escapeChar <|> otherChar)
let quoted = %"\"" *> stringBody <* %"\""
typealias MembersParser = Parser<String, [(String, CofreeJSON)]>.Function;
typealias MembersParser = Parser<String.CharacterView, [(String, CofreeJSON)]>.Function;
// Parses an array of (String, CofreeJSON) object members
func members(json: JSONParser) -> MembersParser {
let pairs: Parser<String, (String, CofreeJSON)>.Function = (curry(pair) <^>
quoted
let keyAndKeyTerm: Parser<String.CharacterView, (String, CofreeJSON)>.Function = quoted --> { (_, range, key) in
(key, Cofree(range, .Leaf(.String(key))))
}
let pairs: Parser<String.CharacterView, (String, CofreeJSON)>.Function = (curry(pair) <^>
keyAndKeyTerm
<* whitespace
<* %":"
<* whitespace
<*> json)
<*> json) --> { (_, range, values) in
(values.0.0, Cofree(range, .Fixed([values.0.1, values.1])))
}
let separatedPairs: MembersParser = (%"," *> whitespace *> pairs <* whitespace)*
let oneOrMore: MembersParser = curry { [$0] + $1 } <^>
pairs
<* whitespace
<*> separatedPairs
return oneOrMore <|> pure([])
return sepBy(pairs, whitespace <* %"," <* whitespace)
}
typealias ValuesParser = Parser<String, [CofreeJSON]>.Function;
// Parses an array of CofreeJSON array values
func elements(json: JSONParser) -> ValuesParser {
let value: Parser<String, CofreeJSON>.Function = whitespace *> json <* whitespace
return sepBy(value, %",")
}
let json: JSONParser = fix { json in
// TODO: Parse backslashed escape characters
public let json: JSONParser = fix { json in
let string: JSONParser = quoted --> {
Cofree($1, .Leaf(.String($2)))
} <?> "string"
let array: JSONParser = %"["
<* whitespace
*> elements(json)
*> sepBy(whitespace *> json, whitespace <* %"," <* whitespace)
<* whitespace
<* %"]"
<* whitespace --> {
--> {
Cofree($1, .Indexed($2))
} <?> "array"
@ -90,15 +63,12 @@ let json: JSONParser = fix { json in
*> members(json)
<* whitespace
<* %"}"
<* whitespace
--> { (_, range, values) in
--> { (_, range, values: [(String, CofreeJSON)]) in
Cofree(range, .Keyed(Dictionary(elements: values)))
} <?> "object"
let doubleParser: DoubleParser = number
let numberParser: JSONParser = String.lift(doubleParser --> { _, range, value in
let num = JSONLeaf.Number(value)
return Cofree(range, .Leaf(num))
let numberParser: JSONParser = (number --> { _, range, value in
Cofree(range, .Leaf(JSONLeaf.Number(value)))
}) <?> "number"
let null: JSONParser = %"null" --> { (_, range, value) in
@ -112,5 +82,5 @@ let json: JSONParser = fix { json in
// TODO: This should be JSON = dict <|> array and
// Value = dict | array | string | number | null | bool
return object <|> array <|> string <|> numberParser <|> boolean <|> null
return (object <|> array <|> string <|> numberParser <|> boolean <|> null) <* whitespace
}

View File

@ -91,6 +91,8 @@ extension Syntax {
return leaf(l1, l2)
case let (.Indexed(v1), .Indexed(v2)):
return v1.count == v2.count && zip(v1, v2).lazy.map(recur).reduce(true) { $0 && $1 }
case let (.Fixed(v1), .Fixed(v2)):
return v1.count == v2.count && zip(v1, v2).lazy.map(recur).reduce(true) { $0 && $1 }
case let (.Keyed(d1), .Keyed(d2)):
return Set(d1.keys) == Set(d2.keys) && d1.keys.map { recur(d1[$0]!, d2[$0]!) }.reduce(true) { $0 && $1 }
default:

View File

@ -0,0 +1,28 @@
import Assertions
import Doubt
import Prelude
import Madness
import XCTest
final class JSONParserTests: XCTestCase {
func testCapturesKeysInKeyedElements() {
let dictWithArray = "{ \"hello\":\n [\"world\",\n \"sailor\"\n ]}"
let array: Cofree<JSONLeaf, Range<Int>> = Cofree(15..<41, .Indexed([
Cofree(16..<23, .Leaf(.String("world"))),
Cofree(29..<37, .Leaf(.String("sailor")))
]))
let fixedPairs: Cofree<JSONLeaf, Range<Int>> = Cofree(2..<41, .Fixed([Cofree(2..<9, .Leaf(.String("hello"))), array]))
let expected: Cofree<JSONLeaf, Range<Int>> = Cofree(0..<42, .Keyed(["hello": fixedPairs]))
let actual = Madness.parse(json, input: dictWithArray).right!
let firstIndex = actual.extract
let new: Cofree<JSONLeaf, Range<Int>> = actual.map({ range in
let startI: Int = firstIndex.startIndex.distanceTo(range.startIndex)
let endI: Int = firstIndex.startIndex.distanceTo(range.endIndex)
return Range(start: startI, end: endI)
})
assert(new, == , expected)
}
}