Skip to content
This repository has been archived by the owner on Feb 2, 2022. It is now read-only.

Commit

Permalink
Add type inference + test
Browse files Browse the repository at this point in the history
  • Loading branch information
Jakob Mygind committed Mar 10, 2020
1 parent 5927e68 commit 9d86aed
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 20 deletions.
16 changes: 14 additions & 2 deletions Model Boiler.xcodeproj/project.pbxproj
Expand Up @@ -334,6 +334,7 @@
};
BD07E6B124166E110003C21C = {
CreatedOnToolsVersion = 11.3.1;
TestTargetID = 3092679B1B77EBE700DFE5A1;
};
};
};
Expand Down Expand Up @@ -455,7 +456,8 @@
01ECF1041C43FDD700C23397 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_IDENTITY = "Apple Development";
DEVELOPMENT_TEAM = M92A6H7EPZ;
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
Expand All @@ -466,8 +468,9 @@
01ECF1051C43FDD700C23397 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_IDENTITY = "Apple Development";
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = M92A6H7EPZ;
GCC_DYNAMIC_NO_PIC = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
Expand Down Expand Up @@ -547,6 +550,7 @@
"$(PROJECT_DIR)/Carthage/Build/Mac",
"$(PROJECT_DIR)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
INFOPLIST_FILE = "$(SRCROOT)/Model Boiler/Supporting Files/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand Down Expand Up @@ -648,12 +652,14 @@
BD07E6BA24166E110003C21C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = M92A6H7EPZ;
Expand All @@ -667,19 +673,23 @@
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = Nodes.ModelBoilerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Model Boiler.app/Contents/MacOS/Model Boiler";
};
name = Release;
};
BD07E6BB24166E110003C21C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
Expand All @@ -700,8 +710,10 @@
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = Nodes.ModelBoilerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Model Boiler.app/Contents/MacOS/Model Boiler";
};
name = Debug;
};
Expand Down
Expand Up @@ -24,8 +24,8 @@
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
Expand Down
47 changes: 32 additions & 15 deletions Model Boiler/Classes/Helpers/CodableGenerator.swift
Expand Up @@ -45,20 +45,37 @@ class Generator {
codingKeys.append(" case \(name) = \"\(name)\"")
}

func generate() throws -> String {
var collector = DeclarationCollector()
let tree = try SyntaxParser.parse(source: source)
tree.walk(&collector)

for v in collector.variables {
addNode(name: v.name, type: v.typeAnnotation!, isOptional: v.typeAnnotation!.contains("?"))
}

encode.append("}\n")
initStrings.append("}")
codingKeys.append("}\n")

return codingKeys.joined(separator: "\n") + encode.joined(separator: "\n") + initStrings.joined(separator: "\n")
}
func generate() throws -> String {
var collector = DeclarationCollector()
let tree = try SyntaxParser.parse(source: source)
tree.walk(&collector)


for v in collector.variables {
let typeString: String

switch (v.typeAnnotation, v.initializedValue) {
case (.some(let type), _):
typeString = type
case (_, .some(let value)) where value.contains("\""):
typeString = "String"
case (_, .some(let value)) where value.contains(".") && Double(value) != nil:
typeString = "Double"
case (_, .some(let value)) where Int(value) != nil:
typeString = "Int"
case (_, .some(let value)) where Set(value.unicodeScalars).contains(where: CharacterSet.init(charactersIn: "()").contains):
typeString = value.replacingOccurrences(of: "()", with: "")
default: throw NSError(domain: "dk.nodes.modelboiler", code: 1, userInfo: ["error": "Could not generate type for \(v)"])

}
addNode(name: v.name, type: typeString, isOptional: typeString.contains("?"))
}

encode.append("}\n")
initStrings.append("}")
codingKeys.append("}\n")

return codingKeys.joined(separator: "\n") + encode.joined(separator: "\n") + initStrings.joined(separator: "\n")
}
}

63 changes: 62 additions & 1 deletion ModelBoilerTests/ModelBoilerTests.swift
Expand Up @@ -7,10 +7,11 @@
//

import XCTest
@testable import Model_Boiler

class ModelBoilerTests: XCTestCase {

func testExample() throws {
func testParsing() throws {
struct TestStruct: Codable, Equatable {
init(
string: String,
Expand Down Expand Up @@ -83,4 +84,64 @@ class ModelBoilerTests: XCTestCase {

}

func testEmbedded() {
struct TestStruct: Codable, Equatable {
init(
string: String,
optionalString: String?,
dictionary: [String : Int],
optionalDictionary: [String : Int]?
) {
self.string = string
self.optionalString = optionalString
self.dictionary = dictionary
self.optionalDictionary = optionalDictionary
}

let string: String
let optionalString: String?
let dictionary: [String: Int]
let optionalDictionary: [String: Int]?
}
}

func testTypeInference() throws {
let str = """
struct Test {
var custom = CustomType()
var custom2 = [CustomType]()
var intVal = 1
var doubleVal = 2.33
var stringVal = "Hello"
}
"""

let expected = """
enum CodingKeys: String, CodingKey {
case custom = "custom"
case custom2 = "custom2"
case intVal = "intVal"
case doubleVal = "doubleVal"
case stringVal = "stringVal"
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(custom, forKey: .custom)
try container.encode(custom2, forKey: .custom2)
try container.encode(intVal, forKey: .intVal)
try container.encode(doubleVal, forKey: .doubleVal)
try container.encode(stringVal, forKey: .stringVal)
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
custom = try container.decode(CustomType.self, forKey: .custom)
custom2 = try container.decode([CustomType].self, forKey: .custom2)
intVal = try container.decode(Int.self, forKey: .intVal)
doubleVal = try container.decode(Double.self, forKey: .doubleVal)
stringVal = try container.decode(String.self, forKey: .stringVal)
}
"""
let res = try XCTUnwrap(try Generator(source: str).generate())
XCTAssertEqual(res, expected)
}
}

0 comments on commit 9d86aed

Please sign in to comment.