From 47a31b90d70854ca7e832bc19dc94bc241cb66b9 Mon Sep 17 00:00:00 2001 From: "Dr. Brandon Wiley" Date: Sun, 18 Aug 2019 21:40:32 -0500 Subject: [PATCH 1/2] Added RPC capability --- .gitignore | 1 + Package.resolved | 12 +- Package.swift | 35 +- Resources/test | 11 + Sources/Chorus/Chorus.swift | 0 Sources/Composition/Composition.swift | 48 +++ Sources/Package/Package.swift | 78 ++++ Sources/Song/Decoding/SongDecoder.swift | 4 +- .../SongSingleValueDecodingContainer.swift | 2 +- Sources/Song/Encoding/SongEncoder.swift | 12 +- .../Encoding/SongKeyedEncodingContainer.swift | 208 +++++++++++ .../SongSingleValueEncodingContainer.swift | 353 ++++++++++++++++++ .../SongUnkeyedEncodingContainer.swift | 123 ++++++ Sources/choir/main.swift | 68 ++++ Sources/compose/main.swift | 192 ++++++++++ Tests/SongTests/SongTests.swift | 110 ++++-- build.sh | 2 + choir.sh | 2 + 18 files changed, 1217 insertions(+), 44 deletions(-) create mode 100644 Resources/test create mode 100644 Sources/Chorus/Chorus.swift create mode 100644 Sources/Composition/Composition.swift create mode 100644 Sources/Package/Package.swift create mode 100644 Sources/Song/Encoding/SongKeyedEncodingContainer.swift create mode 100644 Sources/Song/Encoding/SongSingleValueEncodingContainer.swift create mode 100644 Sources/Song/Encoding/SongUnkeyedEncodingContainer.swift create mode 100644 Sources/choir/main.swift create mode 100644 Sources/compose/main.swift create mode 100755 build.sh create mode 100755 choir.sh diff --git a/.gitignore b/.gitignore index 02c0875..fd3c778 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /.build /Packages /*.xcodeproj +query diff --git a/Package.resolved b/Package.resolved index 8b35458..e05fbd4 100644 --- a/Package.resolved +++ b/Package.resolved @@ -2,12 +2,12 @@ "object": { "pins": [ { - "package": "bocho", - "repositoryURL": "https://github.com/yanagiba/bocho", + "package": "Datable", + "repositoryURL": "https://github.com/OperatorFoundation/Datable", "state": { "branch": null, - "revision": "a02d4faf11539b121cc007210a0141478fa3d924", - "version": "0.1.0" + "revision": "eccbedd3c89007691034b951a1fc0780e54701ea", + "version": "1.1.1" } }, { @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/yanagiba/swift-ast", "state": { "branch": null, - "revision": "87888a78bc264a57536e6c628f4ad4ad02eadd06", - "version": "0.4.1" + "revision": "6656a3dde2e5876818a83c978292687e43620cd1", + "version": "0.19.6" } } ] diff --git a/Package.swift b/Package.swift index 1c3ebe1..94f40b7 100644 --- a/Package.swift +++ b/Package.swift @@ -10,11 +10,27 @@ let package = Package( .library( name: "Song", targets: ["Song"]), + .library( + name: "Composition", + targets: ["Composition"]), + .library( + name: "Chorus", + targets: ["Chorus"]), + .library( + name: "Package", + targets: ["Package"]), + .executable( + name: "compose", + targets: ["compose"]), + .executable( + name: "choir", + targets: ["choir"]), ], dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), - .package(url: "https://github.com/yanagiba/swift-ast", from: "0.4.1") + .package(url: "https://github.com/yanagiba/swift-ast", from: "0.4.2"), + .package(url: "https://github.com/OperatorFoundation/Datable", from: "1.1.1"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -22,9 +38,24 @@ let package = Package( .target( name: "Song", dependencies: ["SwiftAST"]), + .target( + name: "Composition", + dependencies: ["Datable"]), + .target( + name: "Chorus", + dependencies: []), + .target( + name: "Package", + dependencies: []), + .target( + name: "compose", + dependencies: ["Composition", "SwiftAST"]), + .target( + name: "choir", + dependencies: ["Chorus", "Datable", "Package", "SwiftAST"]), .testTarget( name: "SongTests", - dependencies: ["Song"]), + dependencies: ["Song", "Composition"]), ], swiftLanguageVersions: [4] ) diff --git a/Resources/test b/Resources/test new file mode 100644 index 0000000..e33e68a --- /dev/null +++ b/Resources/test @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Sources/Chorus/Chorus.swift b/Sources/Chorus/Chorus.swift new file mode 100644 index 0000000..e69de29 diff --git a/Sources/Composition/Composition.swift b/Sources/Composition/Composition.swift new file mode 100644 index 0000000..4fba152 --- /dev/null +++ b/Sources/Composition/Composition.swift @@ -0,0 +1,48 @@ +import Foundation +import Network +import Datable + +public func remoteCall(code: String, callback: @escaping (Data) -> Void ) +{ + let queue = DispatchQueue(label: "network") + + let conn = NWConnection(host: NWEndpoint.Host("127.0.0.1"), port: NWEndpoint.Port(integerLiteral: 1234), using: .tcp) + conn.start(queue: queue) + + let payload = code.data + let length = payload.count + let length16 = UInt16(length) + let lengthBytes = length16.data + let data = lengthBytes + payload + + conn.send(content: data, completion: NWConnection.SendCompletion.contentProcessed( + { + maybeError in + + guard maybeError == nil else { return } + + conn.receive(minimumIncompleteLength: 2, maximumLength: 2) + { + (maybeData, maybeContext, isComplete, maybeError) in + + print("received \(maybeData)") + + guard maybeError == nil else { return } + guard let data = maybeData else { return } + + let length = Int(data.uint16) + + conn.receive(minimumIncompleteLength: length, maximumLength: length) + { + (maybeData, maybeContext, isComplete, maybeError) in + + print("received.. \(maybeData)") + + guard maybeError == nil else { return } + guard let data = maybeData else { return } + + callback(data) + } + } + })) +} diff --git a/Sources/Package/Package.swift b/Sources/Package/Package.swift new file mode 100644 index 0000000..6766576 --- /dev/null +++ b/Sources/Package/Package.swift @@ -0,0 +1,78 @@ +import Foundation + +public struct Package +{ + public let name: String + public let type: PackageType + + public init(name: String, type: PackageType = .library) + { + self.name = name + self.type = type + + guard let _ = try? FileManager.default.createDirectory(atPath: self.name, withIntermediateDirectories: false, attributes: nil) else { return } + + let process = Process() + process.currentDirectoryPath = self.name + process.launchPath = "/usr/bin/swift" + + switch self.type + { + case .library: + process.arguments = ["package", "init", "--type", "library"] + case .executable: + process.arguments = ["package", "init", "--type", "executable"] + } + + process.launch() + process.waitUntilExit() + } + + public func update() + { + let process = Process() + process.currentDirectoryPath = self.name + process.launchPath = "/usr/bin/swift" + + process.arguments = ["package", "update"] + + process.launch() + process.waitUntilExit() + } + + public func build() + { + let process = Process() + process.currentDirectoryPath = self.name + process.launchPath = "/usr/bin/swift" + + process.arguments = ["build", "-Xswiftc", "-target", "-Xswiftc", "x86_64-apple-macosx10.14"] + + process.launch() + process.waitUntilExit() + } + + public func run() -> Data + { + let process = Process() + process.currentDirectoryPath = self.name + process.launchPath = "/usr/bin/swift" + + process.arguments = ["run"] + let output = Pipe() + process.standardOutput = output + let handle = output.fileHandleForReading + + process.launch() + process.waitUntilExit() + + let data = handle.readDataToEndOfFile() + return data + } +} + +public enum PackageType +{ + case library + case executable +} diff --git a/Sources/Song/Decoding/SongDecoder.swift b/Sources/Song/Decoding/SongDecoder.swift index 7dd8bc1..553a063 100644 --- a/Sources/Song/Decoding/SongDecoder.swift +++ b/Sources/Song/Decoding/SongDecoder.swift @@ -19,7 +19,7 @@ public class SongDecoder { func decode(_ type: [T].Type, from data: Data) throws -> [T] where T : Decodable { NSLog("ARRAY DECODE CHOSEN") - NSLog("decode data: \(data as! NSData)") + NSLog("decode data: \(data as NSData)") self.data=data let container = self._unkeyedContainer() do { @@ -187,7 +187,7 @@ public class SongDecoder { func decode(_ type: T.Type, from data: Data) throws -> T where T : Decodable { - NSLog("decode data: \(data as! NSData)") + NSLog("decode data: \(data as NSData)") self.data=data if singleType(type) { let single = self._singleValueContainer() diff --git a/Sources/Song/Decoding/SongSingleValueDecodingContainer.swift b/Sources/Song/Decoding/SongSingleValueDecodingContainer.swift index 05d474f..296fb35 100644 --- a/Sources/Song/Decoding/SongSingleValueDecodingContainer.swift +++ b/Sources/Song/Decoding/SongSingleValueDecodingContainer.swift @@ -424,7 +424,7 @@ public class SongSingleValueDecodingContainer: SingleValueDecodingContainer { switch ini { case is PatternInitializer: - let pat = ini as! PatternInitializer + let pat = ini let maybeEx = pat.initializerExpression guard let ex = maybeEx else { throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Missing initializer expression")) diff --git a/Sources/Song/Encoding/SongEncoder.swift b/Sources/Song/Encoding/SongEncoder.swift index 45cc937..3bb183a 100644 --- a/Sources/Song/Encoding/SongEncoder.swift +++ b/Sources/Song/Encoding/SongEncoder.swift @@ -41,7 +41,7 @@ public class SongEncoder { if let ints = value as? [Int] { let list = self._unkeyedContainer() do { - list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: "Int")]) + list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Int"))]) for int in ints { try list.encode(int) } @@ -53,7 +53,7 @@ public class SongEncoder { } else if let ints = value as? [Int64] { let list = self._unkeyedContainer() do { - list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: "Int64")]) + list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Int64"))]) for int in ints { try list.encode(int) } @@ -65,7 +65,7 @@ public class SongEncoder { } else if let ints = value as? [Int32] { let list = self._unkeyedContainer() do { - list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: "Int32")]) + list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Int32"))]) for int in ints { try list.encode(int) } @@ -77,7 +77,7 @@ public class SongEncoder { } else if let ints = value as? [Int16] { let list = self._unkeyedContainer() do { - list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: "Int16")]) + list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Int16"))]) for int in ints { try list.encode(int) } @@ -89,7 +89,7 @@ public class SongEncoder { } else if let ints = value as? [Int8] { let list = self._unkeyedContainer() do { - list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: "Int8")]) + list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Int8"))]) for int in ints { try list.encode(int) } @@ -101,7 +101,7 @@ public class SongEncoder { } else { let list = self._unkeyedContainer() do { - list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: String(describing: Value.self))]) + list.type=TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name(String(describing: Value.self)))]) for val in value { try list.encode(val) } diff --git a/Sources/Song/Encoding/SongKeyedEncodingContainer.swift b/Sources/Song/Encoding/SongKeyedEncodingContainer.swift new file mode 100644 index 0000000..11d6d6f --- /dev/null +++ b/Sources/Song/Encoding/SongKeyedEncodingContainer.swift @@ -0,0 +1,208 @@ +// +// SongKeyedEncodingContainer.swift +// Song +// +// Created by Brandon Wiley on 12/26/17. +// + +import Foundation + +import AST + +//import Song + +typealias Parameter = (CodingKey, Expression) + +public class SongKeyedEncodingContainer: KeyedEncodingContainerProtocol { + let encoder: Encoder + let single: SongSingleValueEncodingContainer + + let containerType: String? + + public var codingPath: [CodingKey] + var contents: [(K, Expression)] = [] + + public init(encoder: Encoder, codingPath: [CodingKey], containerType: String?) { + self.encoder=encoder + self.codingPath=codingPath + self.containerType=containerType + self.single=encoder.singleValueContainer() as! SongSingleValueEncodingContainer + } + + public func encodeNil(forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.`nil`) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: Bool, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.boolean(value)) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: Int, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.integer(value, String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: Int8, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: Int16, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: Int32, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: Int64, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: UInt, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: UInt8, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: UInt16, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: UInt32, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: UInt64, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: Float, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.floatingPoint(Double(value), String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: Double, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.floatingPoint(value, String(describing: value))) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: String, forKey key: K) throws { + let kex = key + let vex = single.literal(kind: LiteralExpression.Kind.staticString(value, "\""+value+"\"")) + let tup = (kex, vex) + contents.append(tup) + } + + public func encode(_ value: T, forKey key: K) throws where T : Encodable { + + } + + public func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: K) -> KeyedEncodingContainer where NestedKey : CodingKey { + let container: SongKeyedEncodingContainer = SongKeyedEncodingContainer(encoder: encoder, codingPath: codingPath, containerType: nil) + return KeyedEncodingContainer(container) + } + + public func nestedUnkeyedContainer(forKey key: K) -> UnkeyedEncodingContainer { + return SongUnkeyedEncodingContainer(encoder: encoder, codingPath: codingPath) + } + + public func superEncoder() -> Encoder { + return self.encoder + } + + public func superEncoder(forKey key: K) -> Encoder { + return self.encoder + } + + func literal(containerType: String, contents: [(K, Expression)]) -> Expression { + let constructor = IdentifierExpression(kind: IdentifierExpression.Kind.identifier(Identifier.name(containerType.description), nil)) + var args: [FunctionCallExpression.Argument] = [] + for (key, value) in contents { + args.append(FunctionCallExpression.Argument.namedExpression(Identifier.name(key.stringValue), value)) + } + let lit: Expression = FunctionCallExpression(postfixExpression: constructor, argumentClause: args) + return lit + } + + func wrapValue(containerType: String, contents: [(K, Expression)]) -> Data { + let constructor = IdentifierExpression(kind: IdentifierExpression.Kind.identifier(Identifier.name(containerType.description), nil)) + var args: [FunctionCallExpression.Argument] = [] + for (key, value) in contents { + args.append(FunctionCallExpression.Argument.namedExpression(Identifier.name(key.stringValue), value)) + } + let lit: Expression = FunctionCallExpression(postfixExpression: constructor, argumentClause: args) + + let name = IdentifierPattern(identifier: Identifier.name("value"), typeAnnotation: TypeAnnotation(type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name(containerType.description))]))) + let initializer: PatternInitializer = PatternInitializer(pattern: name, initializerExpression: lit) + let decl = ConstantDeclaration(initializerList: [initializer]) + let top = TopLevelDeclaration(statements: [decl], comments: [], shebang: nil) + let s = top.textDescription + let d = s.data(using: .utf8) + return d! + } +} + +extension SongKeyedEncodingContainer: Datable { + public var data: Data? { + get { + guard let type = containerType else { + NSLog("keyed container has no container type set") + return nil + } + + return wrapValue(containerType: type, contents: contents) + } + } + + public var expression: Expression? { + get { + guard let type = containerType else { + NSLog("keyed container has no container type set") + return nil + } + + return literal(containerType: type, contents: contents) + } + } +} diff --git a/Sources/Song/Encoding/SongSingleValueEncodingContainer.swift b/Sources/Song/Encoding/SongSingleValueEncodingContainer.swift new file mode 100644 index 0000000..2fcea28 --- /dev/null +++ b/Sources/Song/Encoding/SongSingleValueEncodingContainer.swift @@ -0,0 +1,353 @@ +// +// SongSingleValueEncodingContainer.swift +// Song +// +// Created by Brandon Wiley on 12/26/17. +// + +import Foundation + +import AST + +//import Song + +typealias EncodableDictionary = Dictionary where K: Encodable & Hashable, V: Encodable + +public class SongSingleValueEncodingContainer: SingleValueEncodingContainer { + public var encoder: Encoder + public var codingPath: [CodingKey] + public var data: Data? + + public init(encoder: Encoder, codingPath: [CodingKey]) { + self.encoder=encoder + self.codingPath=codingPath + } + + public func encodeNil() throws { + self.data = wrapValue(kind: LiteralExpression.Kind.`nil`, type: AnyType() as Type) + } + + public func encode(_ value: Bool) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.boolean(value), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Bool"))])) + } + + public func encode(_ value: Int) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.integer(value, String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Int"))])) + } + + public func encode(_ value: Int8) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.integer(Int(value), String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Int8"))])) + } + + public func encode(_ value: Int16) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.integer(Int(value), String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Int16"))])) + } + + public func encode(_ value: Int32) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.integer(Int(value), String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Int32"))])) + } + + public func encode(_ value: Int64) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.integer(Int(value), String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Int64"))])) + } + + public func encode(_ value: UInt) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.integer(Int(value), String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("UInt"))])) + } + + public func encode(_ value: UInt8) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.integer(Int(value), String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("UInt8"))])) + } + + public func encode(_ value: UInt16) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.integer(Int(value), String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("UInt16"))])) + } + + public func encode(_ value: UInt32) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.integer(Int(value), String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("UInt32"))])) + } + + public func encode(_ value: UInt64) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.integer(Int(value), String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("UInt64"))])) + } + + public func encode(_ value: Float) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.floatingPoint(Double(value), String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Float"))])) + } + + public func encode(_ value: Double) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.floatingPoint(value, String(value)), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Double"))])) + } + + public func encode(_ value: String) throws { + self.data = wrapValue(kind: LiteralExpression.Kind.staticString(value, "\""+value+"\""), type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("String"))])) + } + + public func encode(_ value: T) throws where T : Encodable { + switch value { + case is Date: + throw EncodingError.unsupportedType("Date") + case is Data: + do { + try encode(value as! Data) + } catch { + throw error + } + case is UUID: + do { + try encode(value as! UUID) + } catch { + throw error + } + case is Decimal: + do { + try encode(value as! Decimal) + } catch { + throw error + } + case is URL: + throw EncodingError.unsupportedType("URL") + case is Decimal: + throw EncodingError.unsupportedType("Decimal") + case let daa as Dictionary: + guard let (firstKey, firstValue) = daa.first else { + // FIXME - encode empty dictionary with unspecialized types + return + } + +// let keyType = bruteForceType(firstKey) // FIXME - Won't work for non-special case items. + let keyType = String(String(describing: type(of: firstKey.base)).split(separator: " ")[0]) + let valueType = String(String(describing: type(of: firstValue)).split(separator: " ")[0]) + + let ex = literal(dictionary: daa) + + self.data = wrapDictionary(keyType: keyType, valueType: valueType, literal: ex) + default: + let song = self.encoder as! SongEncoder + let t = type(of: value as Any) + let s = String("\(t)".split(separator: " ")[0]) + song.nextKeyedType=s + try value.encode(to: self.encoder) + self.data = song.nextKeyedContainer!.data + } + } + + func encode(_ value: Decimal) throws { + let name = IdentifierPattern(identifier: Identifier.name("value"), typeAnnotation: TypeAnnotation(type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Decimal"))]))) + let lit = literal(value) + let initializer: PatternInitializer = PatternInitializer(pattern: name, initializerExpression: lit) + let decl = ConstantDeclaration(initializerList: [initializer]) + let top = TopLevelDeclaration(statements: [decl], comments: [], shebang: nil) + let s = top.textDescription + self.data = s.data(using: .utf8) + } + + public func literal(_ value: Decimal) -> Expression { + let constructor = IdentifierExpression(kind: IdentifierExpression.Kind.identifier(Identifier.name("Decimal"), nil)) + let uuids = value.description + let lit = LiteralExpression(kind: LiteralExpression.Kind.staticString(uuids, "\""+uuids+"\"")) + let args = [FunctionCallExpression.Argument.namedExpression(Identifier.name("string"), lit)] + let result: Expression = FunctionCallExpression(postfixExpression: constructor, argumentClause: args) + return result + } + + func encode(_ value: UUID) throws { + let name = IdentifierPattern(identifier: Identifier.name("value"), typeAnnotation: TypeAnnotation(type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("UUID"))]))) + let lit = literal(value) + let initializer: PatternInitializer = PatternInitializer(pattern: name, initializerExpression: lit) + let decl = ConstantDeclaration(initializerList: [initializer]) + let top = TopLevelDeclaration(statements: [decl], comments: [], shebang: nil) + let s = top.textDescription + self.data = s.data(using: .utf8) + } + + public func literal(_ value: UUID) -> Expression { + let constructor = IdentifierExpression(kind: IdentifierExpression.Kind.identifier(Identifier.name("UUID"), nil)) + let uuids = value.uuidString + let lit = LiteralExpression(kind: LiteralExpression.Kind.staticString(uuids, "\""+uuids+"\"")) + let args = [FunctionCallExpression.Argument.namedExpression(Identifier.name("uuidString"), lit)] + let result: Expression = FunctionCallExpression(postfixExpression: constructor, argumentClause: args) + return result + } + + func encode(_ value: Data) throws { + let name = IdentifierPattern(identifier: Identifier.name("value"), typeAnnotation: TypeAnnotation(type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Data"))]))) + let lit = literal(value) + let initializer: PatternInitializer = PatternInitializer(pattern: name, initializerExpression: lit) + let decl = ConstantDeclaration(initializerList: [initializer]) + let top = TopLevelDeclaration(statements: [decl], comments: [], shebang: nil) + let s = top.textDescription + self.data = s.data(using: .utf8) + } + + public func literal(_ value: Data) -> Expression { + let constructor = IdentifierExpression(kind: IdentifierExpression.Kind.identifier(Identifier.name("Data"), nil)) + let b64s = value.base64EncodedString() + let b64lit = LiteralExpression(kind: LiteralExpression.Kind.staticString(b64s, "\""+b64s+"\"")) + let args = [FunctionCallExpression.Argument.namedExpression(Identifier.name("base64Encoded"), b64lit)] + let lit: Expression = FunctionCallExpression(postfixExpression: constructor, argumentClause: args) + return lit + } + + private func wrapValue(kind: LiteralExpression.Kind, type: Type) -> Data { + let name = IdentifierPattern(identifier: Identifier.name("value"), typeAnnotation: TypeAnnotation(type: type)) + let value = literal(kind: kind) + let initializer: PatternInitializer = PatternInitializer(pattern: name, initializerExpression: value) + let decl = ConstantDeclaration(initializerList: [initializer]) + let top = TopLevelDeclaration(statements: [decl], comments: [], shebang: nil) + let s = top.textDescription + let d = s.data(using: .utf8) + return d! + } + + private func wrapDictionary(keyType: String, valueType: String, literal: Expression) -> Data { + let name = IdentifierPattern(identifier: Identifier.name("value"), typeAnnotation: TypeAnnotation(type: TypeIdentifier(names: [TypeIdentifier.TypeName(name: Identifier.name("Dictionary<\(keyType), \(valueType)>"))]))) + let initializer: PatternInitializer = PatternInitializer(pattern: name, initializerExpression: literal) + let decl = ConstantDeclaration(initializerList: [initializer]) + let top = TopLevelDeclaration(statements: [decl], comments: [], shebang: nil) + let s = top.textDescription + let d = s.data(using: .utf8) + return d! + } + + public func literal(dictionary: Dictionary) -> Expression { + var entries: [DictionaryEntry] = [] + for (key, value) in dictionary { + guard key is Encodable, value is Encodable else { + continue + } + + let keyEn = key as! Encodable + let valueEn = value as! Encodable + + guard let keyEx = try? literal(any: keyEn), let valueEx = try? literal(any: valueEn) else { + continue + } + entries.append(DictionaryEntry(key: keyEx, value: valueEx)) + } + let lit = LiteralExpression(kind: LiteralExpression.Kind.dictionary(entries)) + return lit + } + + public func literal(kind: LiteralExpression.Kind) -> Expression { + let value: Expression = LiteralExpression(kind: kind) + return value + } + + public func bruteForceType(any: Any) -> String { + switch any { + case is String: + return "String" + case is Int: + return "Int" + case is Int8: + return "Int8" + case is Int16: + return "Int16" + case is Int32: + return "Int64" + case is Int64: + return "Int64" + case is UInt: + return "UInt" + case is UInt8: + return "UInt8" + case is UInt16: + return "UInt16" + case is UInt32: + return "UInt32" + case is UInt64: + return "UInt64" + case is Float: + return "Float" + case is Double: + return "Double" + case is Bool: + return "Bool" + case nil: + return "Any" + case is Date: + return "Date" + case is Data: + return "Data" + case is UUID: + return "UUID" + case is Decimal: + return "Decimal" + case is URL: + return "URL" + case is Decimal: + return "Decimal" + default: + let m = Mirror.init(reflecting: any) + return String(describing: m.subjectType) + } + } + + public func literal(any: Any) throws -> Expression { + guard let encValue = any as? Encodable else { + throw EncodingError.notEncodable + } + + switch any { + case let value as String: + return literal(kind: LiteralExpression.Kind.staticString(value, "\""+value+"\"")) + case let value as Int: + return literal(kind: LiteralExpression.Kind.integer(value, String(value))) + case let value as Int8: + return literal(kind: LiteralExpression.Kind.integer(Int(value), String(value))) + case let value as Int16: + return literal(kind: LiteralExpression.Kind.integer(Int(value), String(value))) + case let value as Int32: + return literal(kind: LiteralExpression.Kind.integer(Int(value), String(value))) + case let value as Int64: + return literal(kind: LiteralExpression.Kind.integer(Int(value), String(value))) + case let value as UInt: + return literal(kind: LiteralExpression.Kind.integer(Int(value), String(value))) + case let value as UInt8: + return literal(kind: LiteralExpression.Kind.integer(Int(value), String(value))) + case let value as UInt16: + return literal(kind: LiteralExpression.Kind.integer(Int(value), String(value))) + case let value as UInt32: + return literal(kind: LiteralExpression.Kind.integer(Int(value), String(value))) + case let value as UInt64: + return literal(kind: LiteralExpression.Kind.integer(Int(value), String(value))) + case let value as Float: + return literal(kind: LiteralExpression.Kind.floatingPoint(Double(value), String(value))) + case let value as Double: + return literal(kind: LiteralExpression.Kind.floatingPoint(value, String(value))) + case let value as Bool: + return literal(kind: LiteralExpression.Kind.boolean(value)) + case nil: + return literal(kind: LiteralExpression.Kind.`nil`) + case is Date: + throw EncodingError.unsupportedType("Date") + case is Data: + return literal(any as! Data) + case is UUID: + return literal(any as! UUID) + case is Decimal: + return literal(any as! Decimal) + case is URL: + throw EncodingError.unsupportedType("URL") + case is Decimal: + throw EncodingError.unsupportedType("Decimal") + case let daa as Dictionary: + let ex = literal(dictionary: daa) + + return ex + default: + let song = self.encoder as! SongEncoder + let t = type(of: any as Any) + let s = String("\(t)".split(separator: " ")[0]) + song.nextKeyedType=s + try encValue.encode(to: self.encoder) + return song.nextKeyedContainer!.expression! + } + } +} + +public enum EncodingError: Error { + case notEncodable + case unsupportedType(String) +} diff --git a/Sources/Song/Encoding/SongUnkeyedEncodingContainer.swift b/Sources/Song/Encoding/SongUnkeyedEncodingContainer.swift new file mode 100644 index 0000000..7970187 --- /dev/null +++ b/Sources/Song/Encoding/SongUnkeyedEncodingContainer.swift @@ -0,0 +1,123 @@ +// +// SongUnkeyedEncodingContainer.swift +// Song +// +// Created by Brandon Wiley on 12/26/17. +// + +import Foundation + +import AST + +public class SongUnkeyedEncodingContainer: UnkeyedEncodingContainer { + var encoder: Encoder + let single: SongSingleValueEncodingContainer + public var codingPath: [CodingKey] + public var count: Int { + get { + return contents.count + } + } + public var data: Data? { + get { + return wrapValue(type: type, contents: contents) + } + } + var type: Type + var contents: [Expression] = [] + + public init(encoder: Encoder, codingPath: [CodingKey], type: Type = AnyType() as Type) { + self.encoder=encoder + self.codingPath=codingPath + self.single=encoder.singleValueContainer() as! SongSingleValueEncodingContainer + self.type=type + } + + public func encodeNil() throws { + contents.append(single.literal(kind: LiteralExpression.Kind.`nil`)) + type=AnyType() as Type + } + + public func encode(_ value: Bool) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.boolean(value))) + } + + public func encode(_ value: Int) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.integer(value, String(describing: value)))) + } + + public func encode(_ value: Int8) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value)))) + } + + public func encode(_ value: Int16) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value)))) + } + + public func encode(_ value: Int32) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value)))) + } + + public func encode(_ value: Int64) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value)))) + } + + public func encode(_ value: UInt) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value)))) + } + + public func encode(_ value: UInt8) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value)))) + } + + public func encode(_ value: UInt16) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value)))) + } + + public func encode(_ value: UInt32) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value)))) + } + + public func encode(_ value: UInt64) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.integer(Int(value), String(describing: value)))) + } + + public func encode(_ value: Float) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.floatingPoint(Double(value), String(describing: value)))) + } + + public func encode(_ value: Double) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.floatingPoint(value, String(describing: value)))) + } + + public func encode(_ value: String) throws { + contents.append(single.literal(kind: LiteralExpression.Kind.staticString(value, "\""+value+"\""))) + } + + public func encode(_ value: T) throws where T : Encodable { + + } + + public func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer where NestedKey : CodingKey { + return KeyedEncodingContainer(SongKeyedEncodingContainer(encoder: encoder, codingPath: codingPath, containerType: nil)) + } + + public func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { + return SongUnkeyedEncodingContainer(encoder: encoder, codingPath: codingPath) + } + + public func superEncoder() -> Encoder { + return encoder + } + + func wrapValue(type: Type, contents: [Expression]) -> Data { + let name = IdentifierPattern(identifier: Identifier.name("value"), typeAnnotation: TypeAnnotation(type: ArrayType(elementType: type))) + let value = LiteralExpression(kind: LiteralExpression.Kind.array(contents)) + let initializer: PatternInitializer = PatternInitializer(pattern: name, initializerExpression: value) + let decl = ConstantDeclaration(initializerList: [initializer]) + let top = TopLevelDeclaration(statements: [decl], comments: [], shebang: nil) + let s = top.textDescription + let d = s.data(using: .utf8) + return d! + } +} diff --git a/Sources/choir/main.swift b/Sources/choir/main.swift new file mode 100644 index 0000000..7e95d8d --- /dev/null +++ b/Sources/choir/main.swift @@ -0,0 +1,68 @@ +import Foundation +import AST +import Parser +import Source +import Network +import Datable +import Package + +func main() +{ + let queue = DispatchQueue(label: "network") + + guard let listener = try? NWListener(using: .tcp, on: NWEndpoint.Port(integerLiteral: 1234)) else { return } + listener.newConnectionHandler = + { + conn in + + print(conn) + conn.start(queue: queue) + + conn.receive(minimumIncompleteLength: 2, maximumLength: 2) + { + (maybeData, maybeContext, isComplete, maybeError) in + + print("received \(maybeData)") + + guard maybeError == nil else { return } + guard let data = maybeData else { return } + + let length = Int(data.uint16) + + conn.receive(minimumIncompleteLength: length, maximumLength: length) + { + (maybeData, maybeContext, isComplete, maybeError) in + + print("received.. \(maybeData)") + + guard maybeError == nil else { return } + guard let data = maybeData else { return } + + let source = "import Song\n".data + data + "\n\nlet song = SongEncoder()\nlet output = try? song.encode(result)\nprint(output.string)\n".data + + let package = Package(name: "query", type: .executable) + package.update() + + let destination = URL(fileURLWithPath: "query/Sources/query/main.swift") + guard let _ = try? source.write(to: destination) else { return } + + package.build() + let result = package.run() + print("Success!") + print(result) + + let resultLength = result.count + let resultLength16 = UInt16(resultLength) + let resultLengthBytes = resultLength16.data + + let payload = resultLengthBytes + result + conn.send(content: payload, contentContext: NWConnection.ContentContext.defaultMessage, isComplete: true, completion: NWConnection.SendCompletion.idempotent) + } + } + } + listener.start(queue: queue) +} + +main() + +let _ = readLine() diff --git a/Sources/compose/main.swift b/Sources/compose/main.swift new file mode 100644 index 0000000..8229ba9 --- /dev/null +++ b/Sources/compose/main.swift @@ -0,0 +1,192 @@ +import Foundation +import AST +import Parser +import Source + +func replaceClass(source: TopLevelDeclaration, index: Int, cd: ClassDeclaration) -> TopLevelDeclaration +{ + var cls = cd + var result = source + for (mindex, member) in cd.members.enumerated() + { + switch member + { + case .declaration(let declaration): + switch "\(type(of: declaration))" + { + case "FunctionDeclaration": + print("Replacing \(mindex) \(result)") + let fd = declaration as! FunctionDeclaration + cls = replaceFunction(source: cls, index: mindex, fd: fd) + var statements = result.statements + statements[index] = cls + result = TopLevelDeclaration(statements: statements, comments: result.comments, shebang: result.shebang) + print("Replaced \(mindex) \(result)") + default: + continue + } + default: + continue + } + } + return result +} + +func replaceFunction(source: ClassDeclaration, index: Int, fd: FunctionDeclaration) -> ClassDeclaration +{ + let newFd = replaceBody(source: fd) + var members = source.members + let member = ClassDeclaration.Member.declaration(newFd) + members[index] = member + let result = ClassDeclaration(attributes: source.attributes, accessLevelModifier: source.accessLevelModifier, isFinal: source.isFinal, name: source.name, genericParameterClause: source.genericParameterClause, typeInheritanceClause: source.typeInheritanceClause, genericWhereClause: source.genericWhereClause, members: members) + return result +} + +func replaceBody(source: FunctionDeclaration) -> FunctionDeclaration +{ + print("replaceBody:") + let fc = makeFunctionCall(source: source) + let fcs = "\(fc)" + print("fcs: \(fcs)") + + var statements: [Statement] = [ + ConstantDeclaration(attributes: [], modifiers: [], initializerList: [ + PatternInitializer(pattern: IdentifierPattern(identifier: Identifier.name("code")), initializerExpression: LiteralExpression(kind: LiteralExpression.Kind.interpolatedString([], "\"\(fcs)\"")) + ) + ]), + ] + + if let fr = source.signature.result + { + print("fr: \(fr)") + statements.append( + ConstantDeclaration(attributes: [], modifiers: [], initializerList: [ + PatternInitializer(pattern: IdentifierPattern(identifier: Identifier.name("resultString")), initializerExpression: FunctionCallExpression( + postfixExpression: IdentifierExpression(kind: .identifier(Identifier.name("remoteCall"), nil)), + argumentClause: [ + .expression(IdentifierExpression(kind: .identifier(Identifier.name("code"), nil))) + ] + ) + ) + ]) + ) + + statements.append( + ConstantDeclaration(attributes: [], modifiers: [], initializerList: [ + PatternInitializer(pattern: IdentifierPattern(identifier: Identifier.name("song")), initializerExpression: FunctionCallExpression( + postfixExpression: IdentifierExpression(kind: .identifier(Identifier.name("SongDecoder"), nil)), + argumentClause: [ + ] + ) + ) + ]) + ) + + statements.append( + ConstantDeclaration(attributes: [], modifiers: [], initializerList: [ + PatternInitializer(pattern: IdentifierPattern(identifier: Identifier.name("result")), initializerExpression: + TryOperatorExpression(kind: .optional( + FunctionCallExpression( + postfixExpression: ExplicitMemberExpression( + kind: .namedType( + IdentifierExpression(kind: .identifier(Identifier.name("song"), nil)), + Identifier.name("decode") + ) + ), + argumentClause: [ + .expression( + ExplicitMemberExpression(kind: .namedType( + IdentifierExpression(kind: .identifier(Identifier.name(fr.type.description), nil)), + Identifier.name("self") + )) + ), + .namedExpression( + Identifier.name("from"), + IdentifierExpression(kind: .identifier(Identifier.name("resultString"), nil)) + ) + ] + ) + )) + ) + ]) + ) + + statements.append( + ReturnStatement(expression: IdentifierExpression(kind: .identifier(Identifier.name("result"), nil))) + ) + } + else + { + print("no fr") + statements.append( + ConstantDeclaration(attributes: [], modifiers: [], initializerList: [ + PatternInitializer(pattern: IdentifierPattern(identifier: Identifier.name("_")), initializerExpression: FunctionCallExpression( + postfixExpression: IdentifierExpression(kind: .identifier(Identifier.name("remoteCall"), nil)), + argumentClause: [ + .expression(IdentifierExpression(kind: .identifier(Identifier.name("code"), nil))) + ] + ) + ) + ]) + ) + } + + let newBody: CodeBlock? = CodeBlock(statements: statements) + let result = FunctionDeclaration(attributes: source.attributes, modifiers: source.modifiers, name: source.name, genericParameterClause: source.genericParameterClause, signature: source.signature, genericWhereClause: source.genericWhereClause, body: newBody) + print("replaceBody: \(result)") + return result +} + +func makeFunctionCall(source: FunctionDeclaration) -> ConstantDeclaration +{ + if source.signature.result == nil + { + return ConstantDeclaration(attributes: [], modifiers: [], initializerList: [ + PatternInitializer(pattern: IdentifierPattern(identifier: Identifier.name("_")), initializerExpression: FunctionCallExpression(postfixExpression: IdentifierExpression(kind: IdentifierExpression.Kind.identifier(source.name, nil)), argumentClause: [])) + ]) + } + else + { + return ConstantDeclaration(attributes: [], modifiers: [], initializerList: [ + PatternInitializer(pattern: IdentifierPattern(identifier: Identifier.name("result")), initializerExpression: FunctionCallExpression(postfixExpression: IdentifierExpression(kind: IdentifierExpression.Kind.identifier(source.name, nil)), argumentClause: [])) + ]) + } +} + +func parseTest() +{ + let path = FileManager.default.currentDirectoryPath + print(path) + + let filePath = "/Users/brandon/test.swift" + guard let sourceFile = try? SourceReader.read(at: filePath) else { return } + + let parser = Parser(source: sourceFile) + if let topLevelDecl = try? parser.parse() + { + var result = topLevelDecl + + for (index, statement) in topLevelDecl.statements.enumerated() + { + switch "\(type(of: statement))" + { + case "StructDeclaration": + print("struct!") + let sd = statement as! StructDeclaration + print(sd.name) + case "ClassDeclaration": + print("class!") + let cd = statement as! ClassDeclaration + result = replaceClass(source: result, index: index, cd: cd) + print(">>>\(result)<<<") + default: + print("Unknown statement: \(statement)") + continue + } + } + + print(result) + } +} + +parseTest() diff --git a/Tests/SongTests/SongTests.swift b/Tests/SongTests/SongTests.swift index 3120e1a..425551c 100644 --- a/Tests/SongTests/SongTests.swift +++ b/Tests/SongTests/SongTests.swift @@ -1,6 +1,7 @@ import XCTest @testable import Song import Foundation +import Composition class SongTests: XCTestCase { func testEncodeString() { @@ -212,8 +213,8 @@ class SongTests: XCTestCase { let result = try? song.encode(data) let correct = "let value: Data = Data(base64Encoded: \"c3RyaW5n\")".data(using: .utf8)! - NSLog("\(result! as! NSData)") - NSLog("\(correct as! NSData)") + NSLog("\(result! as NSData)") + NSLog("\(correct as NSData)") NSLog("\(String(bytes: result!, encoding: .utf8))") NSLog("\(String(bytes: correct, encoding: .utf8))") @@ -232,8 +233,8 @@ class SongTests: XCTestCase { let result = try? song.encode(uuid) let correct = "let value: UUID = UUID(uuidString: \"123E4567-E89B-12D3-A456-426655440000\")".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -252,8 +253,8 @@ class SongTests: XCTestCase { let result = try? song.encode(dec) let correct = "let value: Decimal = Decimal(string: \"100\")".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -272,8 +273,8 @@ class SongTests: XCTestCase { let result = try? song.encode(ints) let correct = "let value: Array = [100, 200, 300]".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -292,8 +293,8 @@ class SongTests: XCTestCase { let result = try? song.encode(ints) let correct = "let value: Array = [100, 200, 300]".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -312,8 +313,8 @@ class SongTests: XCTestCase { let result = try? song.encode(ints) let correct = "let value: Array = [100, 200, 300]".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -332,8 +333,8 @@ class SongTests: XCTestCase { let result = try? song.encode(ints) let correct = "let value: Array = [100, 200, 300]".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -352,8 +353,8 @@ class SongTests: XCTestCase { let result = try? song.encode(ints) let correct = "let value: Array = [100, 120, 126]".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -376,8 +377,8 @@ class SongTests: XCTestCase { let result = try? song.encode(ex) let correct = "let value: ExampleStruct = ExampleStruct(value: \"example string\")".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -401,8 +402,8 @@ class SongTests: XCTestCase { let result = try? song.encode(ex) let correct = "let value: ExampleStruct = ExampleStruct(value: \"example string\", index: 123)".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -426,8 +427,8 @@ class SongTests: XCTestCase { let result = try? song.encode(ex) let correct = "let value: ExampleClass = ExampleClass(value: \"example string\")".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -453,8 +454,8 @@ class SongTests: XCTestCase { let result = try? song.encode(ex) let correct = "let value: ExampleClass = ExampleClass(value: \"example string\", index: 123)".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -470,8 +471,8 @@ class SongTests: XCTestCase { let result = try? song.encode(ex) let correct = "let value: Dictionary = [\"a\": \"b\"]".data(using: .utf8)! - NSLog("result \(result! as! NSData)") - NSLog("correct \(correct as! NSData)") + NSLog("result \(result! as NSData)") + NSLog("correct \(correct as NSData)") NSLog("result \(String(bytes: result!, encoding: .utf8)!)") NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") @@ -479,7 +480,33 @@ class SongTests: XCTestCase { XCTAssertNotNil(result) XCTAssertEqual(result!, correct) } - + +// func testEncodeEnum() { +// // This is an example of a functional test case. +// // Use XCTAssert and related functions to verify your tests produce the correct +// // results. +// let song = SongEncoder() +// +// enum ExampleEnum +// { +// case a +// case b +// } +// +// let ex = ExampleEnum.a +// let result = try? song.encode(ex) +// let correct = "let value: ExampleEnum = ExampleEnum.a".data(using: .utf8)! +// +// NSLog("result \(result! as NSData)") +// NSLog("correct \(correct as NSData)") +// +// NSLog("result \(String(bytes: result!, encoding: .utf8)!)") +// NSLog("correct \(String(bytes: correct, encoding: .utf8)!)") +// +// XCTAssertNotNil(result) +// XCTAssertEqual(result!, correct) +// } + func testDecodeString() { let song = SongDecoder() let source = "let value: String = \"string\"".data(using: .utf8)! @@ -900,6 +927,35 @@ class SongTests: XCTestCase { XCTAssertEqual(r, correct) } + func testChoir() + { + let song = SongDecoder() + + let source = "let result = 123" + let correct = 123 + + let expectation = XCTestExpectation(description: "remote call succeeded") + + remoteCall(code: source) + { + result in + + print("result: \(result.string)") + + guard let value = try? song.decode(Int.self, from: result) else + { + XCTFail() + return + } + + XCTAssertEqual(value, correct) + + expectation.fulfill() + } + + wait(for: [expectation], timeout: 60) + } + // static var allTests = [ // ("testExample", testExample), // ] diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..be0da74 --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +swift package update +swift build -Xswiftc "-target" -Xswiftc "x86_64-apple-macosx10.14" diff --git a/choir.sh b/choir.sh new file mode 100755 index 0000000..8abfd97 --- /dev/null +++ b/choir.sh @@ -0,0 +1,2 @@ +./build.sh +.build/x86_64-apple-macosx/debug/choir From 5f132b563ec067761a3e246c3808747cd9b726a3 Mon Sep 17 00:00:00 2001 From: "Dr. Brandon Wiley" Date: Sun, 18 Aug 2019 21:45:35 -0500 Subject: [PATCH 2/2] Make functions public --- Sources/Song/Decoding/SongDecoder.swift | 6 +++--- Sources/Song/Encoding/SongEncoder.swift | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/Song/Decoding/SongDecoder.swift b/Sources/Song/Decoding/SongDecoder.swift index 553a063..55ab110 100644 --- a/Sources/Song/Decoding/SongDecoder.swift +++ b/Sources/Song/Decoding/SongDecoder.swift @@ -17,7 +17,7 @@ public class SongDecoder { userInfo=[:] } - func decode(_ type: [T].Type, from data: Data) throws -> [T] where T : Decodable { + public func decode(_ type: [T].Type, from data: Data) throws -> [T] where T : Decodable { NSLog("ARRAY DECODE CHOSEN") NSLog("decode data: \(data as NSData)") self.data=data @@ -185,7 +185,7 @@ public class SongDecoder { } } - func decode(_ type: T.Type, from data: Data) throws -> T where T : Decodable + public func decode(_ type: T.Type, from data: Data) throws -> T where T : Decodable { NSLog("decode data: \(data as NSData)") self.data=data @@ -245,7 +245,7 @@ public class SongDecoder { } } - func singleType(_ type: T.Type) -> Bool { + public func singleType(_ type: T.Type) -> Bool { if type == String.self { return true } diff --git a/Sources/Song/Encoding/SongEncoder.swift b/Sources/Song/Encoding/SongEncoder.swift index 3bb183a..bee8ab9 100644 --- a/Sources/Song/Encoding/SongEncoder.swift +++ b/Sources/Song/Encoding/SongEncoder.swift @@ -24,7 +24,7 @@ public class SongEncoder { userInfo=[:] } - func encode(_ value: [Key: Value]) throws -> Data where Key : Encodable & CodingKey, Value : Encodable { + public func encode(_ value: [Key: Value]) throws -> Data where Key : Encodable & CodingKey, Value : Encodable { let map = _container(keyedBy: Key.self) for (key, val) in value { do { @@ -37,7 +37,7 @@ public class SongEncoder { return map.data! } - func encode(_ value: [Value]) throws -> Data where Value : Encodable { + public func encode(_ value: [Value]) throws -> Data where Value : Encodable { if let ints = value as? [Int] { let list = self._unkeyedContainer() do { @@ -113,7 +113,7 @@ public class SongEncoder { } } - func encode(_ value: Value) throws -> Data where Value : Encodable { + public func encode(_ value: Value) throws -> Data where Value : Encodable { switch value { // case is Dictionary: // break