1
1
mirror of https://github.com/github/semantic.git synced 2024-12-27 00:44:57 +03:00
semantic/prototype/DoubtTests/UnannotatedTerm.swift

148 lines
4.5 KiB
Swift
Raw Normal View History

struct UnannotatedTerm {
2015-10-17 00:16:34 +03:00
typealias Term = Cofree<String, ()>
let term: Term
static let indexed = (prefix: "[\n\t", separator: ",\n\t", suffix: "\n]")
2015-10-23 21:47:44 +03:00
static let fixed = (prefix: "(\n\t", separator: ",\n\t", suffix: "\n)")
2015-10-17 00:16:34 +03:00
static let keyed = (prefix: "[\n\t", separator: ",\n\t", suffix: "\n}")
var source: String {
let indexed = UnannotatedTerm.indexed
let keyed = UnannotatedTerm.keyed
2015-10-23 21:47:44 +03:00
let fixed = UnannotatedTerm.fixed
2015-10-17 00:16:34 +03:00
return term.cata {
switch $0 {
case let .Leaf(s):
return s
case let .Indexed(s):
return indexed.prefix + s.joinWithSeparator(indexed.separator) + indexed.suffix
2015-10-23 21:47:44 +03:00
case let .Fixed(s):
return fixed.prefix + s.joinWithSeparator(fixed.separator) + fixed.suffix
2015-10-17 00:16:34 +03:00
case let .Keyed(s):
return keyed.prefix + s.map { "\"\($0)\": \($1)" }.joinWithSeparator(keyed.separator) + keyed.suffix
}
}
}
var ranged: Cofree<String, Range<Int>> {
let indexed = UnannotatedTerm.indexed
let keyed = UnannotatedTerm.keyed
2015-10-23 21:47:44 +03:00
let fixed = UnannotatedTerm.fixed
2015-10-17 00:16:34 +03:00
return term.cata {
switch $0 {
case let .Leaf(s):
return Cofree(0..<s.characters.count, .Leaf(s))
case let .Indexed(i):
var length = indexed.prefix.characters.count
var results: [Cofree<String, Range<Int>>] = []
for value in i {
if results.count > 0 {
length += indexed.separator.characters.count
}
results.append(value.map {
($0.startIndex + length)..<($0.endIndex + length)
})
length += value.extract.count
}
return Cofree(0..<(length + indexed.suffix.characters.count), .Indexed(results))
2015-10-23 21:47:44 +03:00
case let .Fixed(i):
var length = fixed.prefix.characters.count
var results: [Cofree<String, Range<Int>>] = []
for value in i {
if results.count > 0 {
length += fixed.separator.characters.count
}
results.append(value.map {
($0.startIndex + length)..<($0.endIndex + length)
})
length += value.extract.count
}
return Cofree(0..<(length + fixed.suffix.characters.count), .Fixed(results))
2015-10-17 00:16:34 +03:00
case let .Keyed(k):
var length = keyed.prefix.characters.count
var results: [(String, Cofree<String, Range<Int>>)] = []
for (key, value) in k {
if results.count > 0 {
length += keyed.separator.characters.count
}
results.append((key, value.map {
($0.startIndex + length)..<($0.endIndex + length)
}))
length += value.extract.count + 4 // for the characters around the key
}
return Cofree(0..<(length + keyed.suffix.characters.count), .Keyed(Dictionary(elements: results)))
}
}
}
var arranged: RangedTerm {
let source = self.source
return RangedTerm(
term: ranged.map {
source.startIndex.advancedBy($0.startIndex)..<source.startIndex.advancedBy($0.endIndex)
},
source: source)
}
}
extension UnannotatedTerm: Arbitrary {
static func arbitrary(k: Int) -> Gen<UnannotatedTerm> {
let symbol: Gen<String> = Gen<Int>.choose((0, 15)).fmap { "_\($0)" }
let leaf: Gen<Term> = symbol.fmap { Term((), .Leaf($0)) }
let indexed: Gen<Term> = Gen<Int>.choose((0, k)).bind { n in
sequence((0..<n).map { _ in arbitrary(k - 1) }).fmap {
Term((), .Indexed($0.map { $0.term }))
}
}
let keyed: Gen<Term> = Gen<Int>.choose((0, k)).bind { n in
sequence((0..<n).map { _ in symbol.bind { key in Gen.pure(()).bind { arbitrary(k - 1) }.fmap { (key, $0.term) } } }).fmap {
Term((), .Keyed(Dictionary(elements: $0)))
}
}
return Gen.oneOf([
leaf,
indexed,
keyed,
]).fmap(UnannotatedTerm.init)
}
static var arbitrary: Gen<UnannotatedTerm> {
2015-10-19 19:44:59 +03:00
return arbitrary(4)
2015-10-17 00:16:34 +03:00
}
2015-10-19 17:35:58 +03:00
static func shrink(term: UnannotatedTerm) -> [UnannotatedTerm] {
2015-10-19 18:27:05 +03:00
let equal = Term.equals(annotation: const(true), leaf: ==)
2015-10-19 18:31:35 +03:00
/// A smaller-than-or-equal-to permutation of `term`. Shrinking is performed outward-in by dropping elements from branches.
2015-10-19 18:27:05 +03:00
let shrunk: UnannotatedTerm.Term = term.term.para {
2015-10-19 17:47:24 +03:00
switch $0 {
2015-10-19 18:27:05 +03:00
case let .Leaf(a):
return Cofree((), .Leaf(a))
2015-10-19 17:47:24 +03:00
case let .Indexed(i):
2015-10-19 18:28:18 +03:00
return Cofree((), .Indexed(i.reduce(true) { $0 && equal($1) }
? i.dropLast().map { $1 }
: i.map { $1 }))
2015-10-23 21:47:44 +03:00
case let .Fixed(i):
return Cofree((), .Fixed(i.reduce(true) { $0 && equal($1) }
? i.dropLast().map { $1 }
: i.map { $1 }))
2015-10-19 17:47:24 +03:00
case let .Keyed(k):
2015-10-19 18:31:44 +03:00
return Cofree((), .Keyed(Dictionary(elements: k.reduce(true) { $0 && equal($1.1) }
? k.dropLast().map { ($0, $1.1) }
: k.map { ($0, $1.1) })))
2015-10-19 17:47:24 +03:00
}
}
2015-10-19 18:31:48 +03:00
/// If the permutation is unchanged, we cannot shrink any further.
2015-10-19 18:27:05 +03:00
return equal(term.term, shrunk)
? []
: [ UnannotatedTerm(term: shrunk) ]
2015-10-19 17:35:58 +03:00
}
2015-10-17 00:16:34 +03:00
}
import Doubt
import Prelude
import SwiftCheck