Commit 10bc41b5 authored by Drew's avatar Drew

Remove atpkg from this repository

parent 90fabe15
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
final public class Task {
public var key: String = ""
public var dependencies: [String] = []
public var tool: String = "atllbuild"
private var kvp: [String:ParseValue]
init?(value: ParseValue, name: String) {
guard let kvp = value.map else { return nil }
self.kvp = kvp
self.key = name
self.tool = kvp["tool"]?.string ?? self.tool
if let values = kvp["dependencies"]?.vector {
for value in values {
if let dep = value.string { self.dependencies.append(dep) }
}
}
}
public subscript(key: String) -> ParseValue? {
return kvp[key]
}
}
final public class Package {
// The required properties.
public var name: String
// The optional properties. All optional properties must have a default value.
public var version: String = ""
public var tasks: [String:Task] = [:]
public init(name: String) {
self.name = name
}
public convenience init?(filepath: String, configurations: [String: String] = [:]) {
guard let parser = Parser(filepath: filepath) else { return nil }
do {
let result = try parser.parse()
self.init(type: result, configurations: configurations)
}
catch {
print("error: \(error)")
return nil
}
}
public init?(type: ParseType, configurations: [String: String]) {
if type.name != "package" { return nil }
if let value = type.properties["name"]?.string { self.name = value }
else {
print("ERROR: No name specified for the package.")
return nil
}
if let value = type.properties["version"]?.string { self.version = value }
if let parsedTasks = type.properties["tasks"]?.map {
for (key, value) in parsedTasks {
if let task = Task(value: value, name: key) {
self.tasks[key] = task
}
}
}
//swap in configurations
for requestedConfiguration in configurations.keys {
let requestedConfigurationValue = configurations[requestedConfiguration]!
//find the overrides specific to this configuration
guard let parsedConfigurations = type.properties["configurations"]?.map else {
fatalError("You requested configuration --\(requestedConfiguration) but no configurations were present in the package file.")
}
guard let parsedConfiguration = parsedConfigurations[requestedConfiguration]?.map else {
fatalError("You requested configuration --\(requestedConfiguration) but we only have \(Array(parsedConfigurations.keys))")
}
guard let overrideSpecifications = parsedConfiguration[requestedConfigurationValue]?.map else {
fatalError("You requested configuration --\(requestedConfiguration) \(requestedConfigurationValue) but we only have \(Array(parsedConfiguration.keys))")
}
for taskSpec in overrideSpecifications.keys {
guard let overrideSpecification = overrideSpecifications[taskSpec]?.map else {
fatalError("Cannot get override specification for --\(requestedConfiguration) \(requestedConfigurationValue)")
}
if let task = tasks[taskSpec] {
for(k,v) in overrideSpecification {
task.kvp[k] = v
}
}
else {
fatalError("Global configurations not implemented; can't configure option \(requestedConfigurationValue) for non-task spec \(taskSpec)")
}
}
}
}
}
\ No newline at end of file
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
public enum ParseError: ErrorType {
case InvalidPackageFile
case ExpectedTokenType(TokenType, Token?)
case InvalidTokenForValueType(Token?)
}
public enum ParseValue {
case StringLiteral(String)
case IntegerLiteral(Int)
case FloatLiteral(Double)
case BoolLiteral(Bool)
case Map([String:ParseValue])
case Vector([ParseValue])
}
extension ParseValue {
public var string: String? {
if case let .StringLiteral(value) = self { return value }
return nil
}
public var integer: Int? {
if case let .IntegerLiteral(value) = self { return value }
return nil
}
public var float: Double? {
if case let .FloatLiteral(value) = self { return value }
return nil
}
public var bool: Bool? {
if case let .BoolLiteral(value) = self { return value }
return nil
}
public var map: [String:ParseValue]? {
if case let .Map(value) = self { return value }
return nil
}
public var vector: [ParseValue]? {
if case let .Vector(value) = self { return value }
return nil
}
}
final public class ParseType {
public var name: String = ""
public var properties: [String:ParseValue] = [:]
}
final public class Parser {
let lexer: Lexer
private func next() -> Token? {
while true {
guard let token = lexer.next() else { return nil }
if token.type != .Comment && token.type != .Terminal {
return lexer.peek()
}
}
}
public init?(filepath: String) {
guard let content = try? NSString(contentsOfFile: filepath, encoding: NSUTF8StringEncoding) else {
return nil
}
let scanner = Scanner(content: content as String)
self.lexer = Lexer(scanner: scanner)
}
public func parse() throws -> ParseType {
guard let token = next() else { throw ParseError.InvalidPackageFile }
if token.type == .OpenParen {
return try parseType()
}
else {
throw ParseError.ExpectedTokenType(.OpenParen, token)
}
}
private func parseType() throws -> ParseType {
let type = ParseType()
type.name = try parseIdentifier()
type.properties = try parseKeyValuePairs()
return type
}
private func parseKeyValuePairs() throws -> [String:ParseValue] {
var pairs: [String:ParseValue] = [:]
while let token = next() where token.type != .CloseParen && token.type != .CloseBrace {
lexer.stall()
let key = try parseKey()
let value = try parseValue()
pairs[key] = value
}
lexer.stall()
return pairs
}
private func parseKey() throws -> String {
let colon = next()
if colon?.type != .Colon { throw ParseError.ExpectedTokenType(.Colon, lexer.peek()) }
return try parseIdentifier()
}
private func parseIdentifier() throws -> String {
guard let identifier = next() else { throw ParseError.ExpectedTokenType(.Identifier, lexer.peek()) }
if identifier.type != .Identifier { throw ParseError.ExpectedTokenType(.Identifier, lexer.peek()) }
return identifier.value
}
private func parseValue() throws -> ParseValue {
guard let token = next() else { throw ParseError.InvalidTokenForValueType(nil) }
switch token.type {
case .OpenBrace: lexer.stall(); return try parseMap()
case .OpenBracket: lexer.stall(); return try parseVector()
case .StringLiteral: return .StringLiteral(token.value)
case .Identifier where token.value == "true": return .BoolLiteral(true)
case .Identifier where token.value == "false": return .BoolLiteral(false)
default: throw ParseError.InvalidTokenForValueType(token)
}
}
private func parseVector() throws -> ParseValue {
if let token = next() where token.type != .OpenBracket { throw ParseError.ExpectedTokenType(.OpenBracket, token) }
var items: [ParseValue] = []
while let token = next() where token.type != .CloseBracket {
lexer.stall()
items.append(try parseValue())
}
lexer.stall()
if let token = next() where token.type != .CloseBracket { throw ParseError.ExpectedTokenType(.CloseBracket, token) }
return .Vector(items)
}
private func parseMap() throws -> ParseValue {
if let token = next() where token.type != .OpenBrace { throw ParseError.ExpectedTokenType(.OpenBrace, token) }
let items = try parseKeyValuePairs()
if let token = next() where token.type != .CloseBrace { throw ParseError.ExpectedTokenType(.CloseBrace, token) }
return .Map(items)
}
}
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
public struct ScannerInfo {
public let character: Character?
public let line: Int
public let column: Int
}
final public class Scanner {
var content: String
var index: String.Index
var current: ScannerInfo? = nil
private var shouldStall = false
var line: Int = 0
var column: Int = 0
public init(content: String) {
self.content = content
self.index = content.startIndex
self._defaults()
}
func _defaults() {
self.index = content.startIndex
self.line = 0
self.column = 0
self.shouldStall = false
self.current = nil
}
public func stall() {
shouldStall = true
}
public func next() -> ScannerInfo? {
if shouldStall {
shouldStall = false
return current
}
if index == content.endIndex {
current = nil
}
else {
current = ScannerInfo(character: content[index], line: line, column: column)
index = index.successor()
if current?.character == "\n" {
line += 1
column = 0
}
else {
column += 1
}
}
return current
}
public func peek() -> ScannerInfo? {
return current
}
}
\ No newline at end of file
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
public enum TokenType {
case Identifier
case OpenParen
case CloseParen
case OpenBracket
case CloseBracket
case OpenBrace
case CloseBrace
case StringLiteral
case Terminal
case Colon
case Comment
case Unknown
case EOF
}
public func ==(lhs: Token, rhs: Token) -> Bool {
return lhs.type == rhs.type &&
lhs.line == rhs.line &&
lhs.column == rhs.column &&
lhs.value == rhs.value
}
public struct Token: Equatable {
public let value: String
public let line: Int
public let column: Int
public let type: TokenType
public init(type: TokenType, value: String = "", line: Int = 0, column: Int = 0) {
self.type = type
self.value = value
self.line = line
self.column = column
}
}
func isCharacterPartOfSet(c: Character?, set: NSCharacterSet) -> Bool {
guard let c = c else { return false }
var isMember = true
for utf16Component in String(c).utf16 {
if !set.characterIsMember(utf16Component) { isMember = false; break }
}
return isMember
}
func isValidIdentifierSignalCharacter(c: Character?) -> Bool {
return isCharacterPartOfSet(c, set: NSCharacterSet.letterCharacterSet())
}
func isValidIdenitifierCharacter(c: Character?) -> Bool {
return isCharacterPartOfSet(c, set: NSCharacterSet.letterCharacterSet()) || c == "-" || c == "." || c == "/"
}
func isWhitespace(c: Character?) -> Bool {
return isCharacterPartOfSet(c, set: NSCharacterSet.whitespaceCharacterSet())
}
final public class Lexer {
var scanner: Scanner
var current: Token? = nil
var shouldStall = false
public init(scanner: Scanner) {
self.scanner = scanner
}
public func next() -> Token? {
if shouldStall {
shouldStall = false
return current
}
func work() -> Token {
if scanner.next() == nil { return Token(type: .EOF) }
scanner.stall()
while let info = scanner.next() where isWhitespace(info.character) {}
scanner.stall()
guard let next = scanner.next() else { return Token(type: .EOF) }
if next.character == "\n" {
return Token(type: .Terminal, value: "\n", line: next.line, column: next.column)
}
else if isValidIdentifierSignalCharacter(next.character) {
var content = String(next.character!)
while let info = scanner.next() where isValidIdenitifierCharacter(info.character) {
content.append(info.character!)
}
scanner.stall()
return Token(type: .Identifier, value: content, line: next.line, column: next.column)
}
else if next.character == "(" {
return Token(type: .OpenParen, value: "(", line: next.line, column: next.column)
}
else if next.character == ")" {
return Token(type: .CloseParen, value: ")", line: next.line, column: next.column)
}
else if next.character == "[" {
return Token(type: .OpenBracket, value: "[", line: next.line, column: next.column)
}
else if next.character == "]" {
return Token(type: .CloseBracket, value: "]", line: next.line, column: next.column)
}
else if next.character == "{" {
return Token(type: .OpenBrace, value: "{", line: next.line, column: next.column)
}
else if next.character == "}" {
return Token(type: .CloseBrace, value: "}", line: next.line, column: next.column)
}
else if next.character == ":" {
return Token(type: .Colon, value: ":", line: next.line, column: next.column)
}
else if next.character == ";" {
let column = scanner.peek()!.column
let line = scanner.peek()!.line
var comment = ""
while let info = scanner.next() where info.character == ";" {}
scanner.stall()
while let info = scanner.next() where info.character != "\n" {
comment.append(info.character!)
}
return Token(type: .Comment, value: comment, line: line, column: column)
}
else if next.character == "\"" {
var content = ""
while let info = scanner.next() where info.character != "\"" {
content.append(info.character!)
}
return Token(type: .StringLiteral, value: content, line: next.line, column: next.column)
}
else {
return Token(type: .Unknown, value: String(next.character!), line: next.line, column: next.column)
}
}
if self.current?.type == .EOF {
self.current = nil
}
else {
self.current = work()
}
return self.current
}
func tokenize() -> [Token] {
var tokens = [Token]()
while let token = self.next() { tokens.append(token) }
return tokens
}
public func peek() -> Token? {
return current
}
public func stall() {
shouldStall = true
}
}
\ No newline at end of file
;; This is the most basic of sample files.
(package
:name "basic"
:version "0.1.0-dev"
:tasks {:build {:tool "lldb-build"
:name "json-swift"
:output-type "lib"
:source [ "src/**.swift" "lib/**.swift" ]}}
)
; End of the sample.
\ No newline at end of file
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// NOTE: This is the crappiest test thing ever... but it works for now.
extension String : ErrorType {}
enum test {
static func assert(condition: Bool, file: String = __FILE__, functionName: String = __FUNCTION__, line: Int = __LINE__) throws {
if !condition {
print(" \(file):\(line) \(functionName) **FAILED**")
throw "atpkg.tests.failed"
}
}
}
protocol Test {
init()
func runTests()
var tests: [() throws -> ()] { get }
var filename: String { get }
}
extension Test {
func runTests() {
print("Tests for \(filename)")
for test in tests {
do {
try test()
}
catch {
print("\(filename): **FAILED** \(error)")
}
}
}
}
print()
let tests: [Test] = [
// NOTE: Add your test classes here...
ScannerTests(),
LexerTests(),
ParserTests(),
PackageTests()
]
for test in tests {
test.runTests()
}
print()
\ No newline at end of file
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
import atpkg
class PackageTests: Test {
required init() {}
let tests = [
PackageTests.testBasic
]
let filename = __FILE__
static func testBasic() throws {
let filepath = "./atpkg/tests/collateral/basic.atpkg"
guard let parser = Parser(filepath: filepath) else {
try test.assert(false); return
}
let result = try parser.parse()
guard let package = Package(type: result) else { try test.assert(false); return }
try test.assert(package.name == "basic")
try test.assert(package.version == "0.1.0-dev")
try test.assert(package.tasks.count == 1)
for (key, task) in package.tasks {
try test.assert(key == "build")
try test.assert(task.tool == "lldb-build")
try test.assert(task["name"]?.string == "json-swift")
try test.assert(task["output-type"]?.string == "lib")
try test.assert(task["source"]?.vector?.count == 2)
try test.assert(task["source"]?.vector?[0].string == "src/**.swift")
try test.assert(task["source"]?.vector?[1].string == "lib/**.swift")
}
}
}
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
import atpkg
func outputBaseline(lexer: Lexer) {
print("--- baseline ---")
while let token = lexer.next() {
let type = String(reflecting: token.type).stringByReplacingOccurrencesOfString("atpkgparser.", withString: "")
var value = ""
switch token.type {
case .Terminal: value = "\\n"
default: value = token.value