Repository: robrix/Madness
Branch: master
Commit: add3ee4bf05d
Files: 49
Total size: 112.8 KB
Directory structure:
gitextract_t4_kha8o/
├── .gitignore
├── .gitmodules
├── .travis.yml
├── Cartfile
├── Cartfile.resolved
├── Documentation/
│ ├── Collections.playground/
│ │ ├── Contents.swift
│ │ └── contents.xcplayground
│ ├── Colours.playground/
│ │ ├── Contents.swift
│ │ └── contents.xcplayground
│ ├── Lambda Calculus.playground/
│ │ ├── Contents.swift
│ │ └── contents.xcplayground
│ └── Subset of Common Markdown.playground/
│ ├── Contents.swift
│ └── contents.xcplayground
├── LICENSE
├── Madness/
│ ├── Alternation.swift
│ ├── Combinator.swift
│ ├── Concatenation.swift
│ ├── Error.swift
│ ├── Info.plist
│ ├── Madness.h
│ ├── Map.swift
│ ├── Negation.swift
│ ├── Parser.swift
│ ├── Reduction.swift
│ ├── Repetition.swift
│ ├── SourcePos.swift
│ └── String.swift
├── Madness.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ └── contents.xcworkspacedata
│ └── xcshareddata/
│ └── xcschemes/
│ ├── Madness-Mac.xcscheme
│ └── Madness-iOS.xcscheme
├── Madness.xcworkspace/
│ └── contents.xcworkspacedata
├── MadnessTests/
│ ├── AlternationTests.swift
│ ├── CollectionTests.swift
│ ├── CombinatorTests.swift
│ ├── ConcatenationTests.swift
│ ├── ErrorTests.swift
│ ├── Fixtures.swift
│ ├── IgnoreTests.swift
│ ├── Info.plist
│ ├── MapTests.swift
│ ├── NegationTests.swift
│ ├── ParserTests.swift
│ ├── ReductionTests.swift
│ ├── RepetitionTests.swift
│ └── StringTests.swift
├── README.md
└── script/
├── cibuild
└── validate-playground.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.DS_Store
build
xcuserdata
*.mode*
*.pbxuser
*.xcuserdatad
*.xccheckout
*.xcscmblueprint
*.xctimeline
================================================
FILE: .gitmodules
================================================
[submodule "Carthage/Checkouts/Result"]
path = Carthage/Checkouts/Result
url = https://github.com/antitypical/Result.git
================================================
FILE: .travis.yml
================================================
language: objective-c
osx_image: xcode9
branches:
only:
- master
xcode_workspace: Madness.xcworkspace
script:
- script/cibuild
matrix:
include:
- xcode_scheme: Madness-Mac
env:
- XCODE_SDK=macosx
- XCODE_ACTION="build test"
- XCODE_DESTINATION="arch=x86_64"
- xcode_scheme: Madness-Mac
env:
- XCODE_SDK=macosx
- XCODE_ACTION="build"
- XCODE_DESTINATION="arch=x86_64"
- XCODE_PLAYGROUND="Documentation/Collections.playground"
- JOB=Collections.playground
- xcode_scheme: Madness-Mac
env:
- XCODE_SDK=macosx
- XCODE_ACTION="build"
- XCODE_DESTINATION="arch=x86_64"
- XCODE_PLAYGROUND="Documentation/Colours.playground"
- JOB=Colours.playground
- xcode_scheme: Madness-Mac
env:
- XCODE_SDK=macosx
- XCODE_ACTION="build"
- XCODE_DESTINATION="arch=x86_64"
- XCODE_PLAYGROUND="Documentation/Lambda Calculus.playground"
- JOB=Lambda Calculus.playground
- xcode_scheme: Madness-Mac
env:
- XCODE_SDK=macosx
- XCODE_ACTION="build"
- XCODE_DESTINATION="arch=x86_64"
- XCODE_PLAYGROUND="Documentation/Subset of Common Markdown.playground"
- JOB=Subset of Common Markdown.playground
- xcode_scheme: Madness-iOS
env:
- XCODE_SDK=iphonesimulator
- XCODE_ACTION="build-for-testing test-without-building"
- XCODE_DESTINATION="platform=iOS Simulator,name=iPhone X"
notifications:
email: false
================================================
FILE: Cartfile
================================================
github "antitypical/Result" ~> 3.2.4
================================================
FILE: Cartfile.resolved
================================================
github "antitypical/Result" "3.2.4"
================================================
FILE: Documentation/Collections.playground/Contents.swift
================================================
import Madness
import Result
let input = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
typealias Fibonacci = Parser<[Int], [Int]>.Function
func fibonacci(_ x: Int, _ y: Int) -> Fibonacci {
let combined: Fibonacci = %(x + y) >>- { (xy: Int) -> Fibonacci in
{ [ xy ] + $0 } <^> fibonacci(y, xy)
}
return combined <|> pure([])
}
parse(fibonacci(0, 1), input: input).value
================================================
FILE: Documentation/Collections.playground/contents.xcplayground
================================================
================================================
FILE: Documentation/Colours.playground/Contents.swift
================================================
import Cocoa
import Darwin
import Madness
func toComponent(_ string: String) -> CGFloat {
return CGFloat(strtol(string, nil, 16)) / 255
}
let digit = %("0"..."9")
let lower = %("a"..."f")
let upper = %("A"..."F")
let hex = digit <|> lower <|> upper
let hex2 = lift(+) <*> hex <*> hex
let component1: Parser.Function = { toComponent($0 + $0) } <^> hex
let component2: Parser.Function = toComponent <^> hex2
let three: Parser.Function = component1 * 3
let six: Parser.Function = component2 * 3
let colour: Parser.Function = map({
NSColor(calibratedRed: $0[0], green: $0[1], blue: $0[2], alpha: 1)
})(%"#" *> (six <|> three))
let reddish = parse(colour, input: "#d52a41").value
let greenish = parse(colour, input: "#5a2").value
let blueish = parse(colour, input: "#5e8ca1").value
================================================
FILE: Documentation/Colours.playground/contents.xcplayground
================================================
================================================
FILE: Documentation/Lambda Calculus.playground/Contents.swift
================================================
import Madness
indirect enum Lambda: CustomStringConvertible {
case variable(String)
case abstraction(String, Lambda)
case application(Lambda, Lambda)
var description: String {
switch self {
case let .variable(symbol):
return symbol
case let .abstraction(symbol, body):
return "λ\(symbol).\(body.description)"
case let .application(x, y):
return "(\(x.description) \(y.description))"
}
}
}
typealias LambdaParser = Parser
func lambda(_ input: String.CharacterView, sourcePos: SourcePos) -> LambdaParser.Result {
let symbol: StringParser = %("a"..."z")
let variable: LambdaParser.Function = Lambda.variable <^> symbol
let abstraction: LambdaParser.Function = Lambda.abstraction <^> ( lift(pair) <*> (%"λ" *> symbol) <*> (%"." *> lambda) )
let application: LambdaParser.Function = Lambda.application <^> ( lift(pair) <*> (%"(" *> lambda) <*> (%" " *> lambda) <* %")" )
let parser: LambdaParser.Function = variable <|> abstraction <|> application
return parser(input, sourcePos)
}
parse(lambda, input: "λx.(x x)".characters).value?.description
parse(lambda, input: "(λx.(x x) λx.(x x))".characters).value?.description
================================================
FILE: Documentation/Lambda Calculus.playground/contents.xcplayground
================================================
================================================
FILE: Documentation/Subset of Common Markdown.playground/Contents.swift
================================================
import Madness
// MARK: - Lexing rules
let newline = %"\n"
let ws = %" " <|> %"\t"
let lower = %("a"..."z")
let upper = %("A"..."Z")
let digit = %("0"..."9")
let text = lower <|> upper <|> digit <|> ws
let restOfLine = { $0.joined(separator: "") } <^> many(text) <* newline
let texts = { $0.joined(separator: "") } <^> some(text <|> (%"" <* newline))
// MARK: - AST
enum Node: CustomStringConvertible {
case blockquote([Node])
case header(Int, String)
case paragraph(String)
func analysis(ifBlockquote: ([Node]) -> T, ifHeader: (Int, String) -> T, ifParagraph: (String) -> T) -> T {
switch self {
case let .blockquote(nodes):
return ifBlockquote(nodes)
case let .header(level, text):
return ifHeader(level, text)
case let .paragraph(text):
return ifParagraph(text)
}
}
// MARK: Printable
var description: String {
return analysis(
ifBlockquote: { "" + $0.lazy.map{ $0.description }.joined(separator: "") + "
" },
ifHeader: { "\($1)" },
ifParagraph: { "\($0)
" })
}
}
// MARK: - Parsing rules
typealias NodeParser = Parser.Function
typealias ElementParser = (@escaping StringParser) -> NodeParser
func fix(_ f: @escaping (@escaping (T) -> U) -> (T) -> U) -> (T) -> U {
return { f(fix(f))($0) }
}
let element: ElementParser = fix { element in
{ prefix in
let octothorpes: IntParser = { $0.count } <^> (%"#" * (1..<7))
let header: NodeParser = prefix *> ( Node.header <^> (lift(pair) <*> octothorpes <*> (%" " *> restOfLine)) )
let paragraph: NodeParser = prefix *> ( Node.paragraph <^> texts )
let blockquote: NodeParser = prefix *> { ( Node.blockquote <^> some(element(prefix *> %"> ")) )($0, $1) }
return header <|> paragraph <|> blockquote
}
}
let parser = many(element(pure("")))
if let parsed = parse(parser, input: "> # hello\n> \n> hello\n> there\n> \n> \n").value {
let description = parsed.reduce(""){ $0 + $1.description }
print(description)
}
if let parsed = parse(parser, input: "This is a \nparagraph\n> # title\n> ### subtitle\n> a").value {
let description = parsed.reduce(""){ $0 + $1.description }
print(description)
}
================================================
FILE: Documentation/Subset of Common Markdown.playground/contents.xcplayground
================================================
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Rob Rix
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Madness/Alternation.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
/// Parses `parser` 0 or one time.
public postfix func |? (parser: @escaping Parser.Function) -> Parser.Function {
return { $0.first } <^> parser * (0...1)
}
/// Parses either `left` or `right` and coalesces their trees.
public func <|> (left: @escaping Parser.Function, right: @escaping Parser.Function) -> Parser.Function {
return alternate(left, right)
}
// MARK: - n-ary alternation
/// Alternates over a sequence of literals, coalescing their parse trees.
public func oneOf(_ input: S) -> Parser.Function where C.Element: Equatable, S.Element == C.Element {
return satisfy(input.contains)
}
/// Given a set of literals, parses an array of any matches in the order they were found.
///
/// Each literal will only match the first time.
public func anyOf(_ set: Set) -> Parser.Function {
return oneOf(set) >>- { match in
var rest = set
rest.remove(match)
return prepend(match) <^> anyOf(rest) <|> pure([match])
}
}
/// Given a set of literals, parses an array of all matches in the order they were found.
///
/// Each literal will be matched as many times as it is found.
public func allOf(_ input: Set) -> Parser.Function {
return oneOf(input) >>- { match in
prepend(match) <^> allOf(input) <|> pure([match])
}
}
// MARK: - Private
/// Defines alternation for use in the `<|>` operator definitions above.
private func alternate(_ left: @escaping Parser.Function, _ right: @escaping Parser.Function) -> Parser.Function {
return { input, sourcePos in
return left(input, sourcePos)
.flatMapError { left in
return right(input, sourcePos)
.mapError { right in
return Error.withReason("no alternative matched:", sourcePos)(left, right)
}
}
}
}
/// Curried function that prepends a value to an array.
func prepend(_ value: T) -> ([T]) -> [T] {
return { [value] + $0 }
}
// MARK: - Operators
/// Optional alternation operator.
postfix operator |?
precedencegroup AlternationPrecedence {
associativity: left
higherThan: ChainingPrecedence
lowerThan: MultiplicationPrecedence
}
infix operator <|> : AlternationPrecedence
// MARK: - Imports
import Result
================================================
FILE: Madness/Combinator.swift
================================================
// Copyright © 2015 Rob Rix. All rights reserved.
/// Parses `open`, followed by `parser` and `close`. Returns the value returned by `parser`.
public func between(_ open: @escaping Parser.Function, _ close: @escaping Parser.Function) -> (@escaping Parser.Function) -> Parser.Function {
return { open *> $0 <* close }
}
/// Parses 0 or more `parser` until `end`. Returns the list of values returned by `parser`.
public func manyTill(_ parser: @escaping Parser.Function, _ end: @escaping Parser.Function) -> Parser.Function {
return many(parser) <* end
}
================================================
FILE: Madness/Concatenation.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
import Result
precedencegroup ConcatenationPrecedence {
associativity: left
higherThan: AlternationPrecedence
lowerThan: MultiplicationPrecedence
}
/// Parses the concatenation of `left` and `right`, pairing their parse trees.
public func <*> (left: @escaping Parser U>.Function, right: @escaping Parser.Function) -> Parser.Function {
return left >>- { $0 <^> right }
}
/// Parses the concatenation of `left` and `right`, dropping `right`’s parse tree.
public func <* (left: @escaping Parser.Function, right: @escaping Parser.Function) -> Parser.Function {
return left >>- { x in { _ in x } <^> right }
}
/// Parses the concatenation of `left` and `right`, dropping `left`’s parse tree.
public func *> (left: @escaping Parser.Function, right: @escaping Parser.Function) -> Parser.Function {
return left >>- { _ in right }
}
infix operator <*> : ConcatenationPrecedence
infix operator *> : ConcatenationPrecedence
infix operator <* : ConcatenationPrecedence
================================================
FILE: Madness/Error.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
import Result
/// A composite error.
public enum Error: Swift.Error, CustomStringConvertible {
indirect case branch(String, SourcePos, [Error])
/// Constructs a leaf error, e.g. for terminal parsers.
public static func leaf(_ reason: String, _ sourcePos: SourcePos) -> Error {
return .branch(reason, sourcePos, [])
}
public static func withReason(_ reason: String, _ sourcePos: SourcePos) -> (Error, Error) -> Error {
return { Error(reason: reason, sourcePos: sourcePos, children: [$0, $1]) }
}
public init(reason: String, sourcePos: SourcePos, children: [Error]) {
self = .branch(reason, sourcePos, children)
}
public var reason: String {
switch self {
case let .branch(s, _, _):
return s
}
}
public var sourcePos: SourcePos {
switch self {
case let .branch(_, sourcePos, _):
return sourcePos
}
}
public var children: [Error] {
switch self {
case let .branch(_, _, c):
return c
}
}
public var depth: Int {
return 1 + ((children.sorted { $0.depth < $1.depth }).last?.depth ?? 0)
}
// MARK: Printable
public var description: String {
return describe(0)
}
fileprivate func describe(_ n: Int) -> String {
let description = String(repeating: "\t", count: n) + "\(sourcePos.index): \(reason)"
if children.count > 0 {
return description + "\n" + children.lazy.map { $0.describe(n + 1) }.joined(separator: "\n")
}
return description
}
}
/// MARK: - Annotations
/// Annotate a parser with a name.
public func > (parser: @escaping Parser.Function, name: String) -> Parser.Function {
return describeAs(name)(parser)
}
/// Adds a name to parse errors.
public func describeAs(_ name: String) -> (@escaping Parser.Function) -> Parser.Function {
return { parser in
{ input, index in
return parser(input, index).mapError {
Error(reason: "\(name): \($0.reason)", sourcePos: $0.sourcePos, children: $0.children)
}
}
}
}
// MARK: - Operators
precedencegroup AnnotationPrecedence {
associativity: left
lowerThan: ChainingPrecedence
}
infix operator > : AnnotationPrecedence
================================================
FILE: Madness/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
FMWK
CFBundleShortVersionString
0.0.1
CFBundleSignature
????
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSHumanReadableCopyright
Copyright © 2014 Rob Rix. All rights reserved.
NSPrincipalClass
================================================
FILE: Madness/Madness.h
================================================
// Copyright (c) 2014 Rob Rix. All rights reserved.
/// Project version number for Madness.
extern double MadnessVersionNumber;
/// Project version string for Madness.
extern const unsigned char MadnessVersionString[];
================================================
FILE: Madness/Map.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
// MARK: - flatMap
/// Returns a parser which requires `parser` to parse, passes its parsed trees to a function `f`, and then requires the result of `f` to parse.
///
/// This can be used to conveniently make a parser which depends on earlier parsed input, for example to parse exactly the same number of characters, or to parse structurally significant indentation.
public func >>- (parser: @escaping Parser.Function, f: @escaping (T) -> Parser.Function) -> Parser.Function {
return { input, index in parser(input, index).flatMap { f($0)(input, $1) } }
}
// MARK: - map
/// Returns a parser which applies `f` to transform the output of `parser`.
public func <^> (f: @escaping (T) -> U, parser: @escaping Parser.Function) -> Parser.Function {
return parser >>- { pure(f($0)) }
}
/// Returns a parser which first parses `right`, replacing successful parses with `left`.
public func <^ (left: T, right: @escaping Parser.Function) -> Parser.Function {
return { (_: U) -> T in left } <^> right
}
/// Curried `<^>`. Returns a parser which applies `f` to transform the output of `parser`.
public func map(_ f: @escaping (T) -> U) -> (@escaping Parser.Function) -> Parser.Function {
return { f <^> $0 }
}
// MARK: - pure
/// Returns a parser which always ignores its input and produces a constant value.
///
/// When combining parsers with `>>-`, allows constant values to be injected into the parser chain.
public func pure(_ value: T) -> Parser.Function {
return { _, index in .success((value, index)) }
}
// MARK: - lift
public func lift(_ f: @escaping (T, U) -> V) -> Parser (U) -> V>.Function {
return pure({ t in { u in f(t, u) } })
}
public func lift(_ f: @escaping (T, U, V) -> W) -> Parser (U) -> (V) -> W>.Function {
return pure({ t in { u in { v in f(t, u, v) } } })
}
// MARK: - pair
public func pair(_ a: A, b: B) -> (A, B) {
return (a, b)
}
// MARK: - Operators
/// Flat map operator.
infix operator >>- : ChainingPrecedence
/// Map operator.
infix operator <^> : ConcatenationPrecedence
/// Replace operator.
infix operator <^ : ConcatenationPrecedence
import Result
================================================
FILE: Madness/Negation.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
/// This parser succeeds iff `parser` fails. This parser does not consume any input.
public func not (_ parser: @escaping Parser.Function) -> Parser.Function {
return { input, index in
return parser(input, index).analysis(
ifSuccess: { (_, endIndex) in
Result.failure(Error.leaf("failed negative lookahead ending at \(endIndex)", index))
},
ifFailure: { _ in Result.success(((), index)) }
)
}
}
// MARK: - Imports
import Result
================================================
FILE: Madness/Parser.swift
================================================
// Copyright (c) 2014 Rob Rix. All rights reserved.
// Swift has no way to resolve to `Result.Result` inside `Parser.Result`.
public typealias ParserResult = Result<(Tree, SourcePos), Error>
/// Convenience for describing the types of parser combinators.
///
/// \param Tree The type of parse tree generated by the parser.
public enum Parser {
/// The type of parser combinators.
public typealias Function = (C, SourcePos) -> Result
/// The type produced by parser combinators.
public typealias Result = ParserResult
}
/// Parses `input` with `parser`, returning the parse trees or `nil` if nothing could be parsed, or if parsing did not consume the entire input.
public func parse(_ parser: Parser.Function, input: C) -> Result> {
let result = parser(input, SourcePos(index: input.startIndex))
return result.flatMap { tree, sourcePos in
return sourcePos.index == input.endIndex
? .success(tree)
: .failure(.leaf("finished parsing before end of input", sourcePos))
}
}
public func parse(_ parser: Parser.Function, input: String) -> Result> {
return parse(parser, input: input.characters)
}
// MARK: - Terminals
/// Returns a parser which never parses its input.
public func none(_ string: String = "no way forward") -> Parser.Function {
return { _, sourcePos in .failure(.leaf(string, sourcePos)) }
}
// Returns a parser which parses any single character.
public func any(_ input: C, sourcePos: SourcePos) -> Parser.Result {
return satisfy { _ in true }(input, sourcePos)
}
public func any(_ input: String.CharacterView, sourcePos: SourcePos) -> Parser.Result {
return satisfy { _ in true }(input, sourcePos)
}
/// Returns a parser which parses a `literal` sequence of elements from the input.
///
/// This overload enables e.g. `%"xyz"` to produce `String -> (String, String)`.
public prefix func % (literal: C) -> Parser.Function where C.Element: Equatable {
return { input, sourcePos in
if input[sourcePos.index...].starts(with: literal) {
return .success((literal, sourcePos.advanced(by: literal.count, from: input)))
} else {
return .failure(.leaf("expected \(literal)", sourcePos))
}
}
}
public prefix func %(literal: String) -> Parser.Function {
return { input, sourcePos in
if input[sourcePos.index...].starts(with: literal.characters) {
return .success((literal, sourcePos.advanced(by: literal, from: input)))
} else {
return .failure(.leaf("expected \(literal)", sourcePos))
}
}
}
/// Returns a parser which parses a `literal` element from the input.
public prefix func % (literal: C.Element) -> Parser.Function where C.Element: Equatable {
return { input, sourcePos in
if sourcePos.index != input.endIndex && input[sourcePos.index] == literal {
return .success((literal, sourcePos.advanced(by: 1, from: input)))
} else {
return .failure(.leaf("expected \(literal)", sourcePos))
}
}
}
/// Returns a parser which parses any character in `range`.
public prefix func %(range: ClosedRange) -> Parser.Function {
return { (input: String.CharacterView, sourcePos: SourcePos) in
let index = sourcePos.index
if index < input.endIndex && range.contains(input[index]) {
let string = String(input[index])
return .success((string, sourcePos.advanced(by: 1, from: input)))
} else {
return .failure(.leaf("expected an element in range \(range)", sourcePos))
}
}
}
// MARK: - Nonterminals
private func memoize(_ f: @escaping () -> T) -> () -> T {
var memoized: T!
return {
if memoized == nil {
memoized = f()
}
return memoized
}
}
public func delay(_ parser: @escaping () -> Parser.Function) -> Parser.Function {
let memoized = memoize(parser)
return { memoized()($0, $1) }
}
// Returns a parser that satisfies the given predicate
public func satisfy(_ pred: @escaping (Character) -> Bool) -> Parser.Function {
return tokenPrim(pred) { $0.advanced(by: $1, from: $2) }
}
// Returns a parser that satisfies the given predicate
public func satisfy (_ pred: @escaping (C.Element) -> Bool) -> Parser.Function {
return tokenPrim(pred) { $0.advanced(by: 1, from: $2) }
}
public func tokenPrim (_ pred: @escaping (C.Element) -> Bool, _ nextPos: @escaping (SourcePos, C.Element, C) -> SourcePos) -> Parser.Function {
return { input, sourcePos in
let index = sourcePos.index
if index != input.endIndex {
let parsed = input[index]
if pred(parsed) {
return .success((parsed, nextPos(sourcePos, parsed, input)))
} else {
return .failure(Error.leaf("Failed to parse \(String(describing: parsed)) with predicate at index", sourcePos))
}
} else {
return .failure(Error.leaf("Failed to parse at end of input", sourcePos))
}
}
}
// MARK: - Operators
/// Map operator.
infix operator --> : ChainingPrecedence
/// Literal operator.
prefix operator %
// MARK: - Imports
import Result
================================================
FILE: Madness/Reduction.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
/// Returns a parser which maps parse trees into another type.
public func --> (parser: @escaping Parser.Function, f: @escaping (C, CountableClosedRange, CountableClosedRange, Range, T) -> U) -> Parser.Function {
return { input, inputPos in
return parser(input, inputPos).map { output, outputPos in
(f(input, inputPos.line...outputPos.line, outputPos.column...outputPos.column, inputPos.index.. (parser: @escaping Parser.Function, transform: @escaping (Parser.Result) -> Parser.Result) -> Parser.Function {
return { transform(parser($0, $1)) }
}
================================================
FILE: Madness/Repetition.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
/// Parser `parser` 1 or more times.
public func some (_ parser: @escaping Parser.Function) -> Parser.Function {
return prepend <^> require(parser) <*> many(parser)
}
/// Parses 1 or more `parser` separated by `separator`.
public func sepBy1(_ parser: @escaping Parser.Function, _ separator: @escaping Parser.Function) -> Parser.Function {
return prepend <^> parser <*> many(separator *> parser)
}
/// Parses 0 or more `parser` separated by `separator`.
public func sepBy(_ parser: @escaping Parser.Function, _ separator: @escaping Parser.Function) -> Parser.Function {
return sepBy1(parser, separator) <|> pure([])
}
/// Parses 1 or more `parser` ended by `terminator`.
public func endBy1(_ parser: @escaping Parser.Function, _ terminator: @escaping Parser.Function) -> Parser.Function {
return some(parser <* terminator)
}
/// Parses 0 or more `parser` ended by `terminator`.
public func endBy(_ parser: @escaping Parser.Function, _ terminator: @escaping Parser.Function) -> Parser.Function {
return many(parser <* terminator)
}
/// Parses `parser` the number of times specified in `interval`.
///
/// \param interval An interval specifying the number of repetitions to perform. `0...n` means at most `n` repetitions; `m...Int.max` means at least `m` repetitions; and `m...n` means between `m` and `n` repetitions (inclusive).
public func * (parser: @escaping Parser.Function, interval: CountableClosedRange) -> Parser.Function {
if interval.upperBound <= 0 { return { .success(([], $1)) } }
return (parser >>- { x in { [x] + $0 } <^> (parser * decrement(interval)) })
<|> { interval.lowerBound <= 0 ? .success(([], $1)) : .failure(.leaf("expected at least \(interval.lowerBound) matches", $1)) }
}
/// Parses `parser` exactly `n` times.
///
/// `n` must be > 0 to make any sense.
public func * (parser: @escaping Parser.Function, n: Int) -> Parser.Function {
return ntimes(parser, n)
}
/// Parses `parser` the number of times specified in `interval`.
///
/// \param interval An interval specifying the number of repetitions to perform. `0.. (parser: @escaping Parser.Function, interval: Range) -> Parser.Function {
if interval.isEmpty { return { .failure(.leaf("cannot parse an empty interval of repetitions", $1)) } }
return parser * (interval.lowerBound...decrement(interval.upperBound))
}
/// Parses `parser` 0 or more times.
public func many (_ p: @escaping Parser.Function) -> Parser.Function {
return prepend <^> require(p) <*> delay { many(p) } <|> pure([])
}
/// Parses `parser` `n` number of times.
public func ntimes (_ p: @escaping Parser.Function, _ n: Int) -> Parser.Function {
guard n > 0 else { return pure([]) }
return prepend <^> p <*> delay { ntimes(p, n - 1) }
}
// MARK: - Private
/// Decrements `x` iff it is not equal to `Int.max`.
private func decrement(_ x: Int) -> Int {
return (x == Int.max ? Int.max : x - 1)
}
private func decrement(_ x: CountableClosedRange) -> CountableClosedRange {
return decrement(x.lowerBound)...decrement(x.upperBound)
}
/// Fails iff `parser` does not consume input, otherwise pass through its results
private func require (_ parser: @escaping Parser.Function) -> Parser.Function {
return { (input, sourcePos) in
return parser(input, sourcePos).flatMap { resultInput, resultPos in
if sourcePos.index == resultPos.index {
return Result.failure(Error.leaf("parser did not consume input when required", sourcePos))
}
return Result.success((resultInput, resultPos))
}
}
}
// MARK: - Imports
import Result
================================================
FILE: Madness/SourcePos.swift
================================================
// Copyright (c) 2014 Josh Vera. All rights reserved.
public typealias Line = Int
public typealias Column = Int
var DefaultTabWidth = 8
public struct SourcePos {
public let line: Line
public let column: Column
public let index: Index
public init(index: Index) {
line = 1
column = 1
self.index = index
}
public init(line: Line, column: Column, index: Index) {
self.line = line
self.column = column
self.index = index
}
}
extension SourcePos: Equatable {
/// Returns whether two SourcePos are equal.
public static func ==(first: SourcePos, other: SourcePos) -> Bool {
return first.line == other.line && first.column == other.column && first.index == other.index
}
}
extension SourcePos {
/// Returns a new SourcePos advanced by the given index.
public func advanced(to index: Index) -> SourcePos {
return SourcePos(line: line, column: column, index: index)
}
/// Returns a new SourcePos advanced by `count`.
public func advanced(by distance: C.IndexDistance, from input: C) -> SourcePos where C.Index == Index {
return advanced(to: input.index(index, offsetBy: distance))
}
}
extension SourcePos where Index == String.Index {
/// Returns a new SourcePos with its line, column, and index advanced by the given character.
public func advanced(by char: Character, from input: String.CharacterView) -> SourcePos {
let nextIndex = input.index(after: index)
if char == "\n" {
return SourcePos(line: line + 1, column: 0, index: nextIndex)
} else if char == "\t" {
return SourcePos(line: line, column: column + DefaultTabWidth - ((column - 1) % DefaultTabWidth), index: nextIndex)
} else {
return SourcePos(line: line, column: column + 1, index: nextIndex)
}
}
/// Returns a new SourcePos with its line, column, and index advanced by the given string.
func advanced(by string: String, from input: String.CharacterView) -> SourcePos {
return string.characters.reduce(self) { $0.advanced(by: $1, from: input) }
}
}
================================================
FILE: Madness/String.swift
================================================
//
// String.swift
// Madness
//
// Created by Josh Vera on 10/19/15.
// Copyright © 2015 Rob Rix. All rights reserved.
//
import Foundation
public typealias CharacterParser = Parser.Function
public typealias CharacterArrayParser = Parser.Function
public typealias StringParser = Parser.Function
public typealias DoubleParser = Parser.Function
public typealias IntParser = Parser.Function
private func maybePrepend(_ value: T?) -> ([T]) -> [T] {
return { value != nil ? [value!] + $0 : $0 }
}
private func concat(_ value: [T]) -> ([T]) -> [T] {
return { value + $0 }
}
private func concat2(_ value: [T]) -> ([T]) -> ([T]) -> [T] {
return { value2 in { value + value2 + $0 } }
}
private let someDigits: CharacterArrayParser = some(digit)
// Parses integers as an array of characters
public let int: CharacterArrayParser = {
let minus: Parser.Function = char("-")|?
return maybePrepend <^> minus <*> someDigits
}()
private let decimal: CharacterArrayParser = prepend <^> %"." <*> someDigits
private let exp: StringParser = %"e+" <|> %"e-" <|> %"e" <|> %"E+" <|> %"E-" <|> %"E"
private let exponent: CharacterArrayParser = { s in { s.characters + $0 } } <^> exp <*> someDigits
// Parses floating point numbers as doubles
public let number: DoubleParser = { characters in Double(String(characters))! } <^>
((concat2 <^> int <*> decimal <*> exponent)
<|> (concat <^> int <*> decimal)
<|> (concat <^> int <*> exponent)
<|> int)
public let digit: CharacterParser = oneOf("0123456789")
public let space: CharacterParser = char(" ")
public let newline: CharacterParser = char("\n")
public let cr = char("\r")
public let crlf: CharacterParser = char("\r\n")
public let endOfLine: CharacterParser = newline <|> crlf
public let tab: CharacterParser = char("\t")
public func oneOf(_ input: String) -> CharacterParser {
return satisfy { input.characters.contains($0) }
}
public func noneOf(_ input: String) -> CharacterParser {
return satisfy { !input.characters.contains($0) }
}
public func char(_ input: Character) -> CharacterParser {
return satisfy { $0 == input }
}
================================================
FILE: Madness.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
849DC2381C0F21D0004C1A1E /* Combinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849DC2371C0F21D0004C1A1E /* Combinator.swift */; };
849DC2391C0F21D0004C1A1E /* Combinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849DC2371C0F21D0004C1A1E /* Combinator.swift */; };
849DC23A1C0F21E1004C1A1E /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1E153551BD5B78E00627E39 /* String.swift */; };
849DC23C1C0F224D004C1A1E /* CombinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849DC23B1C0F224D004C1A1E /* CombinatorTests.swift */; };
849DC23D1C0F224D004C1A1E /* CombinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849DC23B1C0F224D004C1A1E /* CombinatorTests.swift */; };
B8219A941BF1DF05000006F1 /* Negation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8219A931BF1DF05000006F1 /* Negation.swift */; };
B8219A951BF1DF0A000006F1 /* Negation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8219A931BF1DF05000006F1 /* Negation.swift */; };
B8219A981BF1ED07000006F1 /* NegationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8219A971BF1ED07000006F1 /* NegationTests.swift */; };
B88CCA091BF2C17700979677 /* NegationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8219A971BF1ED07000006F1 /* NegationTests.swift */; };
B8E0AB871BF098DD002B5C8B /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8E0AB861BF098DD002B5C8B /* StringTests.swift */; };
B8E0AB881BF098DD002B5C8B /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8E0AB861BF098DD002B5C8B /* StringTests.swift */; };
BECD3BD21F8D918E006FF13E /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BECD3BD11F8D918E006FF13E /* Result.framework */; };
BECD3BD51F8D91A8006FF13E /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BECD3BD41F8D91A8006FF13E /* Result.framework */; };
D1A6B7F91BE01B8F00B4858C /* SourcePos.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A6B7F81BE01B8F00B4858C /* SourcePos.swift */; };
D1A6B7FA1BE01B8F00B4858C /* SourcePos.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A6B7F81BE01B8F00B4858C /* SourcePos.swift */; };
D1E153561BD5B78E00627E39 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1E153551BD5B78E00627E39 /* String.swift */; };
D421A2A91A9A8E33009AC3B1 /* IgnoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D421A2A81A9A8E33009AC3B1 /* IgnoreTests.swift */; };
D421A2AA1A9A8E33009AC3B1 /* IgnoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D421A2A81A9A8E33009AC3B1 /* IgnoreTests.swift */; };
D421A2AC1A9A9540009AC3B1 /* ReductionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D421A2AB1A9A9540009AC3B1 /* ReductionTests.swift */; };
D421A2AD1A9A9540009AC3B1 /* ReductionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D421A2AB1A9A9540009AC3B1 /* ReductionTests.swift */; };
D47B10761A9A9A1C006701A8 /* Reduction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47B10751A9A9A1C006701A8 /* Reduction.swift */; };
D47B10771A9A9A1C006701A8 /* Reduction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47B10751A9A9A1C006701A8 /* Reduction.swift */; };
D490927A1A98F11A00275C79 /* CollectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49092791A98F11A00275C79 /* CollectionTests.swift */; };
D490927B1A98F11A00275C79 /* CollectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49092791A98F11A00275C79 /* CollectionTests.swift */; };
D4BC5E021A98C8B4008C6851 /* Madness.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4BC5DF71A98C8B4008C6851 /* Madness.framework */; };
D4BC5E101A98C978008C6851 /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FC47CD1A37E48800D23A6F /* Parser.swift */; };
D4BC5E121A98C97C008C6851 /* ParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FC47C31A37E47C00D23A6F /* ParserTests.swift */; };
D4BC5E131A98C97C008C6851 /* MapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C8B02D1A69B1A900943303 /* MapTests.swift */; };
D4C0FB011AC5EDA500936032 /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C0FAFE1AC5ECCE00936032 /* Fixtures.swift */; };
D4C0FB021AC5EDA600936032 /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C0FAFE1AC5ECCE00936032 /* Fixtures.swift */; };
D4C2EDA71A98D38E00054FAA /* Concatenation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDA61A98D38E00054FAA /* Concatenation.swift */; };
D4C2EDAA1A98D4D400054FAA /* ConcatenationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDA81A98D49500054FAA /* ConcatenationTests.swift */; };
D4C2EDAB1A98D4D600054FAA /* ConcatenationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDA81A98D49500054FAA /* ConcatenationTests.swift */; };
D4C2EDAC1A98D4DE00054FAA /* Concatenation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDA61A98D38E00054FAA /* Concatenation.swift */; };
D4C2EDAE1A98D52B00054FAA /* Alternation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDAD1A98D52B00054FAA /* Alternation.swift */; };
D4C2EDAF1A98D53400054FAA /* Alternation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDAD1A98D52B00054FAA /* Alternation.swift */; };
D4C2EDB11A98D5DB00054FAA /* AlternationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDB01A98D5DB00054FAA /* AlternationTests.swift */; };
D4C2EDB21A98D5DB00054FAA /* AlternationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDB01A98D5DB00054FAA /* AlternationTests.swift */; };
D4C2EDB61A98D65300054FAA /* Repetition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDB31A98D63600054FAA /* Repetition.swift */; };
D4C2EDB71A98D65400054FAA /* Repetition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDB31A98D63600054FAA /* Repetition.swift */; };
D4C2EDB91A98D82200054FAA /* RepetitionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDB81A98D82200054FAA /* RepetitionTests.swift */; };
D4C2EDBA1A98D82200054FAA /* RepetitionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDB81A98D82200054FAA /* RepetitionTests.swift */; };
D4C2EDBC1A98D8F800054FAA /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDBB1A98D8F800054FAA /* Map.swift */; };
D4C2EDBD1A98D8F800054FAA /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C2EDBB1A98D8F800054FAA /* Map.swift */; };
D4C2EDFC1A98DEE800054FAA /* Madness.h in Headers */ = {isa = PBXBuildFile; fileRef = D4FC47B61A37E47C00D23A6F /* Madness.h */; settings = {ATTRIBUTES = (Public, ); }; };
D4C8B02E1A69B1A900943303 /* MapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C8B02D1A69B1A900943303 /* MapTests.swift */; };
D4D328491A9AFE2700216D7E /* ErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D328481A9AFE2700216D7E /* ErrorTests.swift */; };
D4D9F28A1A9C42A7002BEFF2 /* ErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D328481A9AFE2700216D7E /* ErrorTests.swift */; };
D4DE2EE61ABCB2D000D3D70A /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D3284B1A9AFE6000216D7E /* Error.swift */; };
D4DE2EE71ABCB2D100D3D70A /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D3284B1A9AFE6000216D7E /* Error.swift */; };
D4FC47B71A37E47C00D23A6F /* Madness.h in Headers */ = {isa = PBXBuildFile; fileRef = D4FC47B61A37E47C00D23A6F /* Madness.h */; settings = {ATTRIBUTES = (Public, ); }; };
D4FC47BD1A37E47C00D23A6F /* Madness.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4FC47B11A37E47C00D23A6F /* Madness.framework */; };
D4FC47C41A37E47C00D23A6F /* ParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FC47C31A37E47C00D23A6F /* ParserTests.swift */; };
D4FC47CE1A37E48800D23A6F /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FC47CD1A37E48800D23A6F /* Parser.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
D4BC5E031A98C8B4008C6851 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D4FC47A81A37E47C00D23A6F /* Project object */;
proxyType = 1;
remoteGlobalIDString = D4BC5DF61A98C8B4008C6851;
remoteInfo = Madness;
};
D4FC47BE1A37E47C00D23A6F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D4FC47A81A37E47C00D23A6F /* Project object */;
proxyType = 1;
remoteGlobalIDString = D4FC47B01A37E47C00D23A6F;
remoteInfo = Madness;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
849DC2371C0F21D0004C1A1E /* Combinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Combinator.swift; sourceTree = ""; };
849DC23B1C0F224D004C1A1E /* CombinatorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombinatorTests.swift; sourceTree = ""; };
B8219A931BF1DF05000006F1 /* Negation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Negation.swift; sourceTree = ""; };
B8219A971BF1ED07000006F1 /* NegationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NegationTests.swift; sourceTree = ""; };
B8E0AB861BF098DD002B5C8B /* StringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = ""; };
BECD3BD11F8D918E006FF13E /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BECD3BD41F8D91A8006FF13E /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D1A6B7F81BE01B8F00B4858C /* SourcePos.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SourcePos.swift; sourceTree = ""; };
D1E153551BD5B78E00627E39 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; };
D421A2A81A9A8E33009AC3B1 /* IgnoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IgnoreTests.swift; sourceTree = ""; };
D421A2AB1A9A9540009AC3B1 /* ReductionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReductionTests.swift; path = MadnessTests/ReductionTests.swift; sourceTree = SOURCE_ROOT; };
D47B10751A9A9A1C006701A8 /* Reduction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reduction.swift; sourceTree = ""; };
D49092791A98F11A00275C79 /* CollectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionTests.swift; sourceTree = ""; };
D4BC5DF71A98C8B4008C6851 /* Madness.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Madness.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D4BC5E011A98C8B4008C6851 /* Madness-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Madness-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
D4C0FAFE1AC5ECCE00936032 /* Fixtures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fixtures.swift; sourceTree = ""; };
D4C2EDA61A98D38E00054FAA /* Concatenation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Concatenation.swift; sourceTree = ""; };
D4C2EDA81A98D49500054FAA /* ConcatenationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcatenationTests.swift; sourceTree = ""; };
D4C2EDAD1A98D52B00054FAA /* Alternation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Alternation.swift; sourceTree = ""; };
D4C2EDB01A98D5DB00054FAA /* AlternationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlternationTests.swift; sourceTree = ""; };
D4C2EDB31A98D63600054FAA /* Repetition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Repetition.swift; sourceTree = ""; };
D4C2EDB81A98D82200054FAA /* RepetitionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepetitionTests.swift; sourceTree = ""; };
D4C2EDBB1A98D8F800054FAA /* Map.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Map.swift; sourceTree = ""; };
D4C8B02D1A69B1A900943303 /* MapTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapTests.swift; sourceTree = ""; };
D4D328481A9AFE2700216D7E /* ErrorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorTests.swift; sourceTree = ""; };
D4D3284B1A9AFE6000216D7E /* Error.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = ""; };
D4FC47B11A37E47C00D23A6F /* Madness.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Madness.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D4FC47B51A37E47C00D23A6F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
D4FC47B61A37E47C00D23A6F /* Madness.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Madness.h; sourceTree = ""; };
D4FC47BC1A37E47C00D23A6F /* Madness-MacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Madness-MacTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
D4FC47C21A37E47C00D23A6F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
D4FC47C31A37E47C00D23A6F /* ParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParserTests.swift; sourceTree = ""; };
D4FC47CD1A37E48800D23A6F /* Parser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D4BC5DF31A98C8B4008C6851 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
BECD3BD51F8D91A8006FF13E /* Result.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D4BC5DFE1A98C8B4008C6851 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D4BC5E021A98C8B4008C6851 /* Madness.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D4FC47AD1A37E47C00D23A6F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
BECD3BD21F8D918E006FF13E /* Result.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D4FC47B91A37E47C00D23A6F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D4FC47BD1A37E47C00D23A6F /* Madness.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
BECD3BD31F8D9199006FF13E /* Frameworks */ = {
isa = PBXGroup;
children = (
BECD3BD41F8D91A8006FF13E /* Result.framework */,
BECD3BD11F8D918E006FF13E /* Result.framework */,
);
name = Frameworks;
sourceTree = "";
};
D4FC47A71A37E47C00D23A6F = {
isa = PBXGroup;
children = (
D4FC47B31A37E47C00D23A6F /* Madness */,
D4FC47C01A37E47C00D23A6F /* MadnessTests */,
BECD3BD31F8D9199006FF13E /* Frameworks */,
D4FC47B21A37E47C00D23A6F /* Products */,
);
sourceTree = "";
usesTabs = 1;
};
D4FC47B21A37E47C00D23A6F /* Products */ = {
isa = PBXGroup;
children = (
D4FC47B11A37E47C00D23A6F /* Madness.framework */,
D4FC47BC1A37E47C00D23A6F /* Madness-MacTests.xctest */,
D4BC5DF71A98C8B4008C6851 /* Madness.framework */,
D4BC5E011A98C8B4008C6851 /* Madness-iOSTests.xctest */,
);
name = Products;
sourceTree = "";
};
D4FC47B31A37E47C00D23A6F /* Madness */ = {
isa = PBXGroup;
children = (
D4FC47B61A37E47C00D23A6F /* Madness.h */,
D4FC47CD1A37E48800D23A6F /* Parser.swift */,
D1A6B7F81BE01B8F00B4858C /* SourcePos.swift */,
D4C2EDAD1A98D52B00054FAA /* Alternation.swift */,
D4C2EDA61A98D38E00054FAA /* Concatenation.swift */,
D4D3284B1A9AFE6000216D7E /* Error.swift */,
D4C2EDBB1A98D8F800054FAA /* Map.swift */,
B8219A931BF1DF05000006F1 /* Negation.swift */,
D47B10751A9A9A1C006701A8 /* Reduction.swift */,
D4C2EDB31A98D63600054FAA /* Repetition.swift */,
849DC2371C0F21D0004C1A1E /* Combinator.swift */,
D4FC47B41A37E47C00D23A6F /* Supporting Files */,
D1E153551BD5B78E00627E39 /* String.swift */,
);
path = Madness;
sourceTree = "";
};
D4FC47B41A37E47C00D23A6F /* Supporting Files */ = {
isa = PBXGroup;
children = (
D4FC47B51A37E47C00D23A6F /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "";
};
D4FC47C01A37E47C00D23A6F /* MadnessTests */ = {
isa = PBXGroup;
children = (
D4FC47C31A37E47C00D23A6F /* ParserTests.swift */,
D4C2EDB01A98D5DB00054FAA /* AlternationTests.swift */,
D49092791A98F11A00275C79 /* CollectionTests.swift */,
D4C2EDA81A98D49500054FAA /* ConcatenationTests.swift */,
849DC23B1C0F224D004C1A1E /* CombinatorTests.swift */,
D4D328481A9AFE2700216D7E /* ErrorTests.swift */,
D4C8B02D1A69B1A900943303 /* MapTests.swift */,
B8219A971BF1ED07000006F1 /* NegationTests.swift */,
D421A2A81A9A8E33009AC3B1 /* IgnoreTests.swift */,
D421A2AB1A9A9540009AC3B1 /* ReductionTests.swift */,
D4C2EDB81A98D82200054FAA /* RepetitionTests.swift */,
B8E0AB861BF098DD002B5C8B /* StringTests.swift */,
D4C0FAFE1AC5ECCE00936032 /* Fixtures.swift */,
D4FC47C11A37E47C00D23A6F /* Supporting Files */,
);
path = MadnessTests;
sourceTree = "";
};
D4FC47C11A37E47C00D23A6F /* Supporting Files */ = {
isa = PBXGroup;
children = (
D4FC47C21A37E47C00D23A6F /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
D4BC5DF41A98C8B4008C6851 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
D4C2EDFC1A98DEE800054FAA /* Madness.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D4FC47AE1A37E47C00D23A6F /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
D4FC47B71A37E47C00D23A6F /* Madness.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
D4BC5DF61A98C8B4008C6851 /* Madness-iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = D4BC5E0A1A98C8B4008C6851 /* Build configuration list for PBXNativeTarget "Madness-iOS" */;
buildPhases = (
D4BC5DF21A98C8B4008C6851 /* Sources */,
D4BC5DF31A98C8B4008C6851 /* Frameworks */,
D4BC5DF41A98C8B4008C6851 /* Headers */,
D4BC5DF51A98C8B4008C6851 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "Madness-iOS";
productName = Madness;
productReference = D4BC5DF71A98C8B4008C6851 /* Madness.framework */;
productType = "com.apple.product-type.framework";
};
D4BC5E001A98C8B4008C6851 /* Madness-iOSTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = D4BC5E0D1A98C8B4008C6851 /* Build configuration list for PBXNativeTarget "Madness-iOSTests" */;
buildPhases = (
D4BC5DFD1A98C8B4008C6851 /* Sources */,
D4BC5DFE1A98C8B4008C6851 /* Frameworks */,
D4BC5DFF1A98C8B4008C6851 /* Resources */,
);
buildRules = (
);
dependencies = (
D4BC5E041A98C8B4008C6851 /* PBXTargetDependency */,
);
name = "Madness-iOSTests";
productName = MadnessTests;
productReference = D4BC5E011A98C8B4008C6851 /* Madness-iOSTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
D4FC47B01A37E47C00D23A6F /* Madness-Mac */ = {
isa = PBXNativeTarget;
buildConfigurationList = D4FC47C71A37E47C00D23A6F /* Build configuration list for PBXNativeTarget "Madness-Mac" */;
buildPhases = (
D4FC47AC1A37E47C00D23A6F /* Sources */,
D4FC47AD1A37E47C00D23A6F /* Frameworks */,
D4FC47AE1A37E47C00D23A6F /* Headers */,
D4FC47AF1A37E47C00D23A6F /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "Madness-Mac";
productName = Madness;
productReference = D4FC47B11A37E47C00D23A6F /* Madness.framework */;
productType = "com.apple.product-type.framework";
};
D4FC47BB1A37E47C00D23A6F /* Madness-MacTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = D4FC47CA1A37E47C00D23A6F /* Build configuration list for PBXNativeTarget "Madness-MacTests" */;
buildPhases = (
D4FC47B81A37E47C00D23A6F /* Sources */,
D4FC47B91A37E47C00D23A6F /* Frameworks */,
D4FC47BA1A37E47C00D23A6F /* Resources */,
);
buildRules = (
);
dependencies = (
D4FC47BF1A37E47C00D23A6F /* PBXTargetDependency */,
);
name = "Madness-MacTests";
productName = MadnessTests;
productReference = D4FC47BC1A37E47C00D23A6F /* Madness-MacTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
D4FC47A81A37E47C00D23A6F /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0900;
ORGANIZATIONNAME = "Rob Rix";
TargetAttributes = {
D4BC5DF61A98C8B4008C6851 = {
CreatedOnToolsVersion = 6.3;
};
D4BC5E001A98C8B4008C6851 = {
CreatedOnToolsVersion = 6.3;
};
D4FC47B01A37E47C00D23A6F = {
CreatedOnToolsVersion = 6.1.1;
LastSwiftMigration = 0900;
};
D4FC47BB1A37E47C00D23A6F = {
CreatedOnToolsVersion = 6.1.1;
LastSwiftMigration = 0900;
};
};
};
buildConfigurationList = D4FC47AB1A37E47C00D23A6F /* Build configuration list for PBXProject "Madness" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = D4FC47A71A37E47C00D23A6F;
productRefGroup = D4FC47B21A37E47C00D23A6F /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
D4FC47B01A37E47C00D23A6F /* Madness-Mac */,
D4FC47BB1A37E47C00D23A6F /* Madness-MacTests */,
D4BC5DF61A98C8B4008C6851 /* Madness-iOS */,
D4BC5E001A98C8B4008C6851 /* Madness-iOSTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
D4BC5DF51A98C8B4008C6851 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
D4BC5DFF1A98C8B4008C6851 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
D4FC47AF1A37E47C00D23A6F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
D4FC47BA1A37E47C00D23A6F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
D4BC5DF21A98C8B4008C6851 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
849DC23A1C0F21E1004C1A1E /* String.swift in Sources */,
D4DE2EE71ABCB2D100D3D70A /* Error.swift in Sources */,
849DC2391C0F21D0004C1A1E /* Combinator.swift in Sources */,
D4C2EDAF1A98D53400054FAA /* Alternation.swift in Sources */,
D4BC5E101A98C978008C6851 /* Parser.swift in Sources */,
D4C2EDBD1A98D8F800054FAA /* Map.swift in Sources */,
D4C2EDAC1A98D4DE00054FAA /* Concatenation.swift in Sources */,
D1A6B7FA1BE01B8F00B4858C /* SourcePos.swift in Sources */,
D47B10771A9A9A1C006701A8 /* Reduction.swift in Sources */,
B8219A951BF1DF0A000006F1 /* Negation.swift in Sources */,
D4C2EDB61A98D65300054FAA /* Repetition.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D4BC5DFD1A98C8B4008C6851 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D4C2EDAB1A98D4D600054FAA /* ConcatenationTests.swift in Sources */,
D4C2EDBA1A98D82200054FAA /* RepetitionTests.swift in Sources */,
849DC23D1C0F224D004C1A1E /* CombinatorTests.swift in Sources */,
D490927B1A98F11A00275C79 /* CollectionTests.swift in Sources */,
D4C0FB011AC5EDA500936032 /* Fixtures.swift in Sources */,
B8E0AB881BF098DD002B5C8B /* StringTests.swift in Sources */,
D4BC5E131A98C97C008C6851 /* MapTests.swift in Sources */,
B88CCA091BF2C17700979677 /* NegationTests.swift in Sources */,
D4BC5E121A98C97C008C6851 /* ParserTests.swift in Sources */,
D4C2EDB21A98D5DB00054FAA /* AlternationTests.swift in Sources */,
D421A2AA1A9A8E33009AC3B1 /* IgnoreTests.swift in Sources */,
D4D9F28A1A9C42A7002BEFF2 /* ErrorTests.swift in Sources */,
D421A2AD1A9A9540009AC3B1 /* ReductionTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D4FC47AC1A37E47C00D23A6F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D4DE2EE61ABCB2D000D3D70A /* Error.swift in Sources */,
D4C2EDAE1A98D52B00054FAA /* Alternation.swift in Sources */,
D4FC47CE1A37E48800D23A6F /* Parser.swift in Sources */,
B8219A941BF1DF05000006F1 /* Negation.swift in Sources */,
D4C2EDBC1A98D8F800054FAA /* Map.swift in Sources */,
D4C2EDA71A98D38E00054FAA /* Concatenation.swift in Sources */,
D1A6B7F91BE01B8F00B4858C /* SourcePos.swift in Sources */,
849DC2381C0F21D0004C1A1E /* Combinator.swift in Sources */,
D47B10761A9A9A1C006701A8 /* Reduction.swift in Sources */,
D1E153561BD5B78E00627E39 /* String.swift in Sources */,
D4C2EDB71A98D65400054FAA /* Repetition.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D4FC47B81A37E47C00D23A6F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D4C2EDAA1A98D4D400054FAA /* ConcatenationTests.swift in Sources */,
D4C8B02E1A69B1A900943303 /* MapTests.swift in Sources */,
849DC23C1C0F224D004C1A1E /* CombinatorTests.swift in Sources */,
D490927A1A98F11A00275C79 /* CollectionTests.swift in Sources */,
D4C0FB021AC5EDA600936032 /* Fixtures.swift in Sources */,
B8E0AB871BF098DD002B5C8B /* StringTests.swift in Sources */,
D4C2EDB91A98D82200054FAA /* RepetitionTests.swift in Sources */,
B8219A981BF1ED07000006F1 /* NegationTests.swift in Sources */,
D4FC47C41A37E47C00D23A6F /* ParserTests.swift in Sources */,
D4D328491A9AFE2700216D7E /* ErrorTests.swift in Sources */,
D4C2EDB11A98D5DB00054FAA /* AlternationTests.swift in Sources */,
D421A2A91A9A8E33009AC3B1 /* IgnoreTests.swift in Sources */,
D421A2AC1A9A9540009AC3B1 /* ReductionTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
D4BC5E041A98C8B4008C6851 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D4BC5DF61A98C8B4008C6851 /* Madness-iOS */;
targetProxy = D4BC5E031A98C8B4008C6851 /* PBXContainerItemProxy */;
};
D4FC47BF1A37E47C00D23A6F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D4FC47B01A37E47C00D23A6F /* Madness-Mac */;
targetProxy = D4FC47BE1A37E47C00D23A6F /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
D4BC5E0B1A98C8B4008C6851 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = Madness/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = Madness;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
D4BC5E0C1A98C8B4008C6851 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COPY_PHASE_STRIP = NO;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Madness/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = Madness;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
D4BC5E0E1A98C8B4008C6851 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEBUG_INFORMATION_FORMAT = dwarf;
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = MadnessTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_VERSION = 3.0;
};
name = Debug;
};
D4BC5E0F1A98C8B4008C6851 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
INFOPLIST_FILE = MadnessTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_VERSION = 3.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
D4FC47C51A37E47C00D23A6F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
D4FC47C61A37E47C00D23A6F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
D4FC47C81A37E47C00D23A6F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = Madness/Info.plist;
INSTALL_PATH = "@rpath";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = Madness;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
};
name = Debug;
};
D4FC47C91A37E47C00D23A6F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = Madness/Info.plist;
INSTALL_PATH = "@rpath";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = Madness;
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.0;
};
name = Release;
};
D4FC47CB1A37E47C00D23A6F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = MadnessTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
};
name = Debug;
};
D4FC47CC1A37E47C00D23A6F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
INFOPLIST_FILE = MadnessTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
D4BC5E0A1A98C8B4008C6851 /* Build configuration list for PBXNativeTarget "Madness-iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D4BC5E0B1A98C8B4008C6851 /* Debug */,
D4BC5E0C1A98C8B4008C6851 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D4BC5E0D1A98C8B4008C6851 /* Build configuration list for PBXNativeTarget "Madness-iOSTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D4BC5E0E1A98C8B4008C6851 /* Debug */,
D4BC5E0F1A98C8B4008C6851 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D4FC47AB1A37E47C00D23A6F /* Build configuration list for PBXProject "Madness" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D4FC47C51A37E47C00D23A6F /* Debug */,
D4FC47C61A37E47C00D23A6F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D4FC47C71A37E47C00D23A6F /* Build configuration list for PBXNativeTarget "Madness-Mac" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D4FC47C81A37E47C00D23A6F /* Debug */,
D4FC47C91A37E47C00D23A6F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D4FC47CA1A37E47C00D23A6F /* Build configuration list for PBXNativeTarget "Madness-MacTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D4FC47CB1A37E47C00D23A6F /* Debug */,
D4FC47CC1A37E47C00D23A6F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = D4FC47A81A37E47C00D23A6F /* Project object */;
}
================================================
FILE: Madness.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: Madness.xcodeproj/xcshareddata/xcschemes/Madness-Mac.xcscheme
================================================
================================================
FILE: Madness.xcodeproj/xcshareddata/xcschemes/Madness-iOS.xcscheme
================================================
================================================
FILE: Madness.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: MadnessTests/AlternationTests.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
final class AlternationTests: XCTestCase {
// MARK: Alternation
func testAlternationParsesEitherAlternative() {
assertAdvancedBy(alternation, input: "xy".characters, lineOffset: 0, columnOffset: 1, offset: 1)
assertAdvancedBy(alternation, input: "yx".characters, lineOffset: 0, columnOffset: 1, offset: 1)
}
func testAlternationOfASingleTypeCoalescesTheParsedValue() {
assertTree(alternation, "xy".characters, ==, "x")
}
// MARK: Optional
func testOptionalProducesWhenPresent() {
assertTree(optional, "y".characters, ==, "y")
assertTree(prefixed, "xy".characters, ==, "xy")
assertTree(suffixed, "yzsandwiched".characters, ==, "yz")
}
func testOptionalProducesWhenAbsent() {
assertTree(optional, "".characters, ==, "")
assertTree(prefixed, "x".characters, ==, "x")
assertTree(suffixed, "z".characters, ==, "z")
assertTree(sandwiched, "xz".characters, ==, "xz")
}
// MARK: One-of
func testOneOfParsesFirstMatch() {
assertTree(one, "xyz".characters, ==, "x")
assertTree(one, "yzx".characters, ==, "y")
assertTree(one, "zxy".characters, ==, "z")
}
// MARK: Any-of
func testAnyOfParsesAnArrayOfMatchesPreservingOrder() {
assertTree(any, "xy".characters, ==, ["x", "y"])
assertTree(any, "yx".characters, ==, ["y", "x"])
assertTree(any, "zxy".characters, ==, ["z", "x", "y"])
}
func testAnyOfRejectsWhenNoneMatch() {
assertUnmatched(anyOf(Set("x")), Set("y".characters))
}
func testAnyOfOnlyParsesFirstMatch() {
assertTree(any, "xyy".characters, ==, ["x", "y"])
}
// MARK: All-of
func testAllOfParsesAnArrayOfMatchesPreservingOrder() {
assertTree(all, "xy".characters, ==, ["x", "y"])
assertTree(all, "yx".characters, ==, ["y", "x"])
assertTree(all, "zxy".characters, ==, ["z", "x", "y"])
}
func testAllOfRejectsWhenNoneMatch() {
assertUnmatched(allOf(Set("x")), Set(["y"]))
}
}
// MARK: - Fixtures
private let alternation = %"x" <|> %"y"
private let optional = map({ $0 ?? "" })((%"y")|?)
private let prefixed = { x in { y in x + y } } <^> %"x" <*> optional
private let suffixed = { x in { y in x + y } } <^> optional <*> %"z"
private let sandwiched = { x in { y in x + y } } <^> prefixed <*> %"z"
private let arrayOfChars: Set = ["x", "y", "z"]
private let chars: String = "xyz"
private let one = oneOf(chars)
private let any: Parser.Function = anyOf(arrayOfChars)
private let all: Parser.Function = allOf(arrayOfChars)
// MARK: - Imports
import Madness
import Result
import XCTest
================================================
FILE: MadnessTests/CollectionTests.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
final class CollectionTests: XCTestCase {
func testParsingCollections() {
let input = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
typealias Fibonacci = Parser<[Int], [Int]>.Function
func fibonacci(_ x: Int, _ y: Int) -> Fibonacci {
let combined: Fibonacci = %(x + y) >>- { (xy: Int) -> Fibonacci in
{ [ xy ] + $0 } <^> fibonacci(y, xy)
}
return combined <|> pure([])
}
XCTAssertEqual(parse(fibonacci(0, 1), input: input).value!, input)
}
}
// MARK: - Imports
import Madness
import XCTest
================================================
FILE: MadnessTests/CombinatorTests.swift
================================================
// Copyright © 2015 Rob Rix. All rights reserved.
final class CombinatorTests: XCTestCase {
// MARK: - between
let braces: (@escaping StringParser) -> StringParser = between(%"{", %"}")
func testBetweenCombinatorParsesSandwichedString(){
assertTree(braces(%"a"), "{a}".characters, ==, "a")
}
func testBetweenCombinatorAcceptsEmptyString(){
assertTree(braces(%""), "{}".characters, ==, "")
}
// MARK: - manyTill
let digits = manyTill(digit, %",")
func testManyTillCombinatorParsesElementsUntilEndParser(){
assertTree(digits, "123,".characters, ==, ["1", "2", "3"])
}
func testManyTillCombinatorAcceptsEmptyString(){
assertTree(digits, ",".characters, ==, [])
}
}
// MARK: - Imports
import Madness
import XCTest
================================================
FILE: MadnessTests/ConcatenationTests.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
final class ConcatenationTests: XCTestCase {
let concatenation = lift(pair) <*> %"x" <*> %"y"
func testConcatenationRejectsPartialParses() {
assertUnmatched(concatenation, "x".characters)
}
func testConcatenationParsesBothOperands() {
assertAdvancedBy(concatenation, input: "xyz".characters, lineOffset: 0, columnOffset: 2, offset: 2)
}
func testConcatenationProducesPairsOfTerms() {
let input = "xy".characters
let parsed = concatenation(input, SourcePos(index: input.startIndex))
XCTAssertEqual(parsed.value?.0.0, "x")
XCTAssertEqual(parsed.value?.0.1, "y")
}
}
func matches(_ parser: Parser.Function, input: C) -> Bool {
return parser(input, SourcePos(index: input.startIndex)).value != nil
}
func doesNotMatch(_ parser: Parser.Function, input: C) -> Bool {
return parser(input, SourcePos(index: input.startIndex)).value == nil
}
func assertUnmatched(_ parser: Parser.Function, _ input: C, message: String = "", file: StaticString = #file, line: UInt = #line) {
XCTAssertNil(parser(input, SourcePos(index: input.startIndex)).value, "should not have matched \(input). " + message, file: file, line: line)
}
func assertMatched(_ parser: Parser.Function, input: C, message: String = "", file: StaticString = #file, line: UInt = #line) {
XCTAssertNotNil(parser(input, SourcePos(index: input.startIndex)).value, "should have matched \(input). " + message, file: file, line: line)
}
func assertTree(_ parser: Parser.Function, _ input: C, _ match: @escaping (T, T) -> Bool, _ tree: T, message: String = "", file: StaticString = #file, line: UInt = #line) {
let parsed: Parser.Result = parser(input, SourcePos(index: input.startIndex))
let value = parsed.value?.0
XCTAssert(value.map { match($0, tree) } ?? false, "should have parsed \(input) as \(tree). " + message, file: file, line: line)
}
func assertAdvancedBy(_ parser: Parser.Function, input: C, offset: C.IndexDistance, message: String = "", file: StaticString = #file, line: UInt = #line) {
let pos = SourcePos(index: input.startIndex)
let newSourcePos: SourcePos? = SourcePos(line: pos.line, column: pos.column, index: input.index(pos.index, offsetBy: offset))
let value = parser(input, pos).value
XCTAssertNotNil(value, "should have parsed \(input) and advanced by \(offset). " + message, file: file, line: line)
XCTAssertEqual(value?.1, newSourcePos, "should have parsed \(input) and advanced by \(offset). " + message, file: file, line: line)
}
func assertAdvancedBy(_ parser: Parser.Function, input: C, lineOffset: Line, columnOffset: Column, offset: C.IndexDistance, message: String = "", file: StaticString = #file, line: UInt = #line) {
let pos = SourcePos(index: input.startIndex)
let newSourcePos: SourcePos? = SourcePos(line: pos.line + lineOffset, column: pos.column + columnOffset, index: input.index(pos.index, offsetBy: offset))
let value = parser(input, pos).value
XCTAssertNotNil(value, "should have parsed \(String(describing: input)) and advanced by \(offset). " + message, file: file, line: line)
XCTAssertEqual(value?.1, newSourcePos, "should have parsed \(String(describing: input)) and advanced by \(offset). " + message, file: file, line: line)
}
// MARK: - Imports
import Madness
import XCTest
================================================
FILE: MadnessTests/ErrorTests.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
final class ErrorTests: XCTestCase {
func testLiftedParsersDoNotReportErrorsWhenTheyMatch() {
let parser = %"x"
let input = "x".characters
let sourcePos = SourcePos(index: input.startIndex)
XCTAssertNotNil(parser(input, sourcePos).value)
XCTAssertNil(parser(input, sourcePos).error)
}
func testLiftedParsersReportErrorsWhenTheyDoNotMatch() {
let parser = %"x"
let input = "y"
let sourcePos = SourcePos(index: input.startIndex)
XCTAssertNil(parser(input.characters, sourcePos).value)
XCTAssertNotNil(parser(input.characters, sourcePos).error)
}
func testParseError() {
XCTAssertEqual(parse(lambda, input: "λx.").error?.depth, 5)
}
func testParseNaming() {
XCTAssertNotNil(parse(describeAs("lambda")(lambda), input: "λx.").error)
}
}
// MARK: - Imports
import Madness
import XCTest
================================================
FILE: MadnessTests/Fixtures.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
extension String {
public static func lift(_ parser: @escaping Parser.Function) -> Parser.Function {
return {
parser($0.characters, $1)
}
}
}
/// Returns the least fixed point of the function returned by `f`.
///
/// This is useful for e.g. making recursive closures without using the two-step assignment dance.
///
/// \param f - A function which takes a parameter function, and returns a result function. The result function may recur by calling the parameter function.
///
/// \return A recursive function.
func fix(_ f: @escaping (@escaping (T) -> U) -> (T) -> U) -> (T) -> U {
return { f(fix(f))($0) }
}
typealias LambdaParser = Parser.Function
func lambda(_ input: String, sourcePos: SourcePos) -> Parser.Result {
let symbol: Parser.Function = String.lift(%("a"..."z"))
let variable: LambdaParser = Lambda.variable <^> symbol
let abstraction: LambdaParser = { x in { y in Lambda.abstraction(x, y) } } <^> (%"λ" *> symbol) <*> (%"." *> lambda)
let application: LambdaParser = { x in { y in Lambda.application(x, y) } } <^> (%"(" *> lambda) <*> (%" " *> lambda) <* %")"
let parser: LambdaParser = variable <|> abstraction <|> application
return parser(input, sourcePos)
}
enum Lambda: CustomStringConvertible {
case variable(String)
indirect case abstraction(String, Lambda)
indirect case application(Lambda, Lambda)
var description: String {
switch self {
case let .variable(symbol):
return symbol
case let .abstraction(symbol, body):
return "λ\(symbol).\(body.description)"
case let .application(x, y):
return "(\(x.description) \(y.description))"
}
}
}
import Madness
================================================
FILE: MadnessTests/IgnoreTests.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
final class IgnoreTests: XCTestCase {
let ignored = %"x"
func testIgnoredInputDoesNotGetConcatenatedAtLeft() {
assertTree(ignored *> %"y", "xy".characters, ==, "y")
}
func testIgnoredInputDoesNotGetConcatenatedAtRight() {
assertTree(%"y" <* ignored, "yx".characters, ==, "y")
}
func testRepeatedIgnoredEmptyParsesAreDropped() {
assertTree(many(ignored) *> %"y", "y".characters, ==, "y")
}
func testRepeatedIgnoredParsesAreDropped() {
assertTree(many(ignored) *> %"y", "xxy".characters, ==, "y")
}
}
// MARK: - Imports
import Madness
import XCTest
================================================
FILE: MadnessTests/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
BNDL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1
================================================
FILE: MadnessTests/MapTests.swift
================================================
// Copyright (c) 2015 Rob Rix. All rights reserved.
private struct Tree: Equatable, CustomStringConvertible {
init(_ value: T, _ children: [Tree] = []) {
self.values = [ value ]
self.children = children
}
let values: [T]
let children: [Tree]
// MARK: Printable
var description: String {
let space = " "
let valueString = values.map({ String(describing: $0) }).joined(separator: space)
return children.count > 0 ?
"(\(valueString) \(children.map({ String(describing: $0) }).joined(separator: space)))"
: "(\(valueString))"
}
}
private func == (left: Tree, right: Tree) -> Bool {
return left.values == right.values && left.children == right.children
}
private func == (l: (T, U), r: (T, U)) -> Bool {
return l.0 == r.0 && l.1 == r.1
}
final class MapTests: XCTestCase {
// MARK: flatMap
func testFlatMap() {
let item: Parser