Skip to content

Commit

Permalink
Merge pull request #59 from angelolloqui/feature/fixes
Browse files Browse the repository at this point in the history
Feature/fixes
  • Loading branch information
angelolloqui committed Dec 10, 2017
2 parents b324950 + 8b94a81 commit f115fce
Show file tree
Hide file tree
Showing 17 changed files with 219 additions and 18 deletions.
3 changes: 2 additions & 1 deletion Sources/SwiftKotlinApp/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class ViewController: NSViewController {
let swiftTokenizer = SwiftTokenizer()
let kotlinTokenizer = KotlinTokenizer(
tokenTransformPlugins: [
XCTTestToJUnitTokenTransformPlugin()
XCTTestToJUnitTokenTransformPlugin(),
FoundationMethodsTransformPlugin()
]
)

Expand Down
7 changes: 6 additions & 1 deletion Sources/SwiftKotlinCommandLine/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
import Foundation
import SwiftKotlinFramework

let kotlinTokenizer = KotlinTokenizer()
let kotlinTokenizer = KotlinTokenizer(
tokenTransformPlugins: [
XCTTestToJUnitTokenTransformPlugin(),
FoundationMethodsTransformPlugin()
]
)
let version = "0.1.0"
let arguments = [
"output",
Expand Down
32 changes: 31 additions & 1 deletion Sources/SwiftKotlinFramework/KotlinTokenizer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,13 @@ public class KotlinTokenizer: SwiftTokenizer {
case let .case(itemList, stmts):
let prefix = itemList.count > 1 ? [statement.newToken(.keyword, "in", node), statement.newToken(.space, " ", node)] : []
let conditions = itemList.map { tokenize($0, node: node) }.joined(token: statement.newToken(.delimiter, ", ", node))
let statements = stmts.count > 1 ? tokenize(CodeBlock(statements: stmts)) : tokenize(stmts, node: node)
var statements = tokenize(stmts, node: node)
if stmts.count > 1 || statements.filter({ $0.kind == .linebreak }).count > 1 {
let linebreak = statement.newToken(.linebreak, "\n", node)
statements = [statement.newToken(.startOfScope, "{", node), linebreak] +
indent(statements) +
[linebreak, statement.newToken(.endOfScope, "}", node)]
}
return prefix + conditions + separatorTokens + statements

case .default(let stmts):
Expand Down Expand Up @@ -484,6 +490,30 @@ public class KotlinTokenizer: SwiftTokenizer {
}

// MARK: - Expressions
open override func tokenize(_ expression: ExplicitMemberExpression) -> [Token] {
switch expression.kind {
case let .namedType(postfixExpr, identifier):
let postfixTokens = tokenize(postfixExpr)
var delimiters = [expression.newToken(.delimiter, ".")]

if postfixTokens.last?.value != "?" &&
postfixTokens.removingOtherScopes().contains(where: {
$0.value == "?" && $0.origin is OptionalChainingExpression
}) {
delimiters = delimiters.prefix(with: expression.newToken(.symbol, "?"))
}
return postfixTokens + delimiters + expression.newToken(.identifier, identifier)
default:
return super.tokenize(expression)
}
}

open override func tokenize(_ expression: AssignmentOperatorExpression) -> [Token] {
guard expression.leftExpression is WildcardExpression else {
return super.tokenize(expression)
}
return tokenize(expression.rightExpression)
}

open override func tokenize(_ expression: LiteralExpression) -> [Token] {
switch expression.kind {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// FoundationMethodsTransformPlugin.swift
// SwiftKotlinPackageDescription
//
// Created by Angel Luis Garcia on 10/12/2017.
//

import Foundation
import Transform
import AST

public class FoundationMethodsTransformPlugin: TokenTransformPlugin {
public var name: String {
return "Foundation transformations"
}

public var description: String {
return "Transforms methods on lists, maps,... like `first`, `count`... to their Kotlin variant"
}

public init() {}

public func transform(tokens: [Token], topDeclaration: TopLevelDeclaration) throws -> [Token] {
var newTokens = [Token]()

for token in tokens {
if token.kind == .identifier,
let memberExpression = token.origin as? ExplicitMemberExpression,
case ExplicitMemberExpression.Kind.namedType(let expression, let identifier) = memberExpression.kind,
let inferredType = inferTypeFor(expression: expression, topDeclaration: topDeclaration),
let replace = memberStringMappings[inferredType]?[identifier] {
newTokens.append(memberExpression.newToken(.identifier, replace))
} else if token.kind == .identifier, token.value == "fatalError", let origin = token.origin, let node = token.node {
newTokens.append(origin.newToken(.keyword, "throw", node))
newTokens.append(origin.newToken(.space, " ", node))
newTokens.append(origin.newToken(.identifier, "Exception", node))
} else {
newTokens.append(token)
}
}

return newTokens
}

func inferTypeFor(expression: PostfixExpression, topDeclaration: TopLevelDeclaration) -> String? {
// TODO: Right now there is no way to infer types. Will be fixed in future versions of AST
return "List"
}

let memberStringMappings = [
"List": [
"first": "firstOrNull()",
"last": "lastOrNull()",
"count": "size",
"isEmpty": "isEmpty()"
],
"String": [
"count": "length",
"uppercased": "toUpperCase",
"lowercased": "toLowerCase"
]
]

// TODO: How to map regex expressions that affect multiple tokens?
let memberRegexMappings = [
"List": [
"index(of: \\(.+))": "indexOf($1)",
"append(\\(.+))": "add($1)",
"remove(at: \\(.+))": "removeAt($1)",
"sorted(by: \\(.+))": "sortedWith(comparator = Comparator($1))",
"joined(separator: \\(.+))": "joinToString(separator = $1)"
]
]
}
18 changes: 18 additions & 0 deletions Sources/SwiftKotlinFramework/utils/Token+Operations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,24 @@ extension Array where Iterator.Element == Token {
}
return nil
}

public func removingOtherScopes() -> [Token] {
var tokens = [Token]()
var scope = 0
for token in self {
if token.kind == .endOfScope {
scope -= 1
}
if scope == 0 {
tokens.append(token)
}
if token.kind == .startOfScope {
scope += 1
}
}
return tokens
}

}

extension ASTTokenizable {
Expand Down
4 changes: 4 additions & 0 deletions SwiftKotlin.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
789D79041F927B63009ED628 /* AST+Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 789D79011F927A66009ED628 /* AST+Operations.swift */; };
78CAB0CF1F92808E009E2608 /* XCTTestToJUnitTokenTransformPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CAB0CE1F92808E009E2608 /* XCTTestToJUnitTokenTransformPlugin.swift */; };
78CAB0D61F92843C009E2608 /* TransformPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CAB0D51F92843C009E2608 /* TransformPluginTests.swift */; };
78FE79801FDDABC000B64A2C /* FoundationMethodsTransformPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78FE797E1FDDAB5900B64A2C /* FoundationMethodsTransformPlugin.swift */; };
OBJ_265 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; };
OBJ_271 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_39 /* Package.swift */; };
OBJ_277 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_230 /* Package.swift */; };
Expand Down Expand Up @@ -1027,6 +1028,7 @@
78CAB0CE1F92808E009E2608 /* XCTTestToJUnitTokenTransformPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTTestToJUnitTokenTransformPlugin.swift; sourceTree = "<group>"; };
78CAB0D41F9283D6009E2608 /* Tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Tests; sourceTree = "<group>"; };
78CAB0D51F92843C009E2608 /* TransformPluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransformPluginTests.swift; sourceTree = "<group>"; };
78FE797E1FDDAB5900B64A2C /* FoundationMethodsTransformPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FoundationMethodsTransformPlugin.swift; sourceTree = "<group>"; };
OBJ_100 /* AssignmentOperatorExpression.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssignmentOperatorExpression.swift; sourceTree = "<group>"; };
OBJ_101 /* BinaryOperatorExpression.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryOperatorExpression.swift; sourceTree = "<group>"; };
OBJ_102 /* ClosureExpression.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClosureExpression.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1444,6 +1446,7 @@
children = (
789D78F91F92792E009ED628 /* TransformPlugin.swift */,
78CAB0CE1F92808E009E2608 /* XCTTestToJUnitTokenTransformPlugin.swift */,
78FE797E1FDDAB5900B64A2C /* FoundationMethodsTransformPlugin.swift */,
);
path = plugins;
sourceTree = "<group>";
Expand Down Expand Up @@ -2501,6 +2504,7 @@
buildActionMask = 0;
files = (
78314DD61FC8B64700539A2D /* TokenizationResult.swift in Sources */,
78FE79801FDDABC000B64A2C /* FoundationMethodsTransformPlugin.swift in Sources */,
OBJ_358 /* KotlinTokenizer.swift in Sources */,
789D78FB1F927957009ED628 /* TransformPlugin.swift in Sources */,
OBJ_360 /* TransformOptions.swift in Sources */,
Expand Down
7 changes: 6 additions & 1 deletion Tests/SwiftKotlinFrameworkTests/KotlinTokenizerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import XCTest
import SwiftKotlinFramework

class KotlinTokenizerTests: XCTestCase {
let kotlinTokenizer = KotlinTokenizer()
let kotlinTokenizer = KotlinTokenizer(
tokenTransformPlugins: [
XCTTestToJUnitTokenTransformPlugin(),
FoundationMethodsTransformPlugin()
]
)

func testAll() {
let files = try! FileManager().contentsOfDirectory(atPath: self.testFilePath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ val obj = obj as? Movie
if (obj != null) {}
val movie = obj2 as? Movie
if (movie != null) {}
if (numbers.flatMap({ it % 2 }).count == 1) {}
if (numbers.flatMap({ it % 2 }).size == 1) {}
for (current in someObjects) {}
for (i in 0 until count) {}
for (i in 1 .. 3) {}
Expand Down Expand Up @@ -67,7 +67,3 @@ when (nb) {
}
else -> print("three or more digits")
}
val value = if (isTrue) "yes" else "no"
val label = if (x > 0) "Positive" else "negative"
button.color = if (item.deleted) red else green
val text = label ?: "default"
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,3 @@ switch nb {
default: print("three or more digits")
}

// Ternary and coalescing operators
let value = isTrue ? "yes" : "no"
let label = x > 0 ? "Positive" : "negative"
button.color = item.deleted ? red : green
let text = label ?? "default"


11 changes: 11 additions & 0 deletions Tests/SwiftKotlinFrameworkTests/Tests/KotlinTokenizer/enums.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,14 @@ when (enumValue) {
.resetPasswordSendEmail -> return (category: "ResetPassword", name: "sendEmail", label: null)
.paymentSelectorOpen -> return (category: "PaymentSelector", name: "open", label: "${tenant.name} - ${option.duration}min")
}
when (exception) {
.qrCode -> {
val message = serverMessage
if (message != null) {
trackError(name = name, message = message)
} else {
trackError(name = name, message = R.string.localizable.network_error())
}
}
else -> trackError(name = "generic", message = R.string.localizable.generic_error())
}
11 changes: 11 additions & 0 deletions Tests/SwiftKotlinFrameworkTests/Tests/KotlinTokenizer/enums.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,14 @@ case .resetPasswordSendEmail:
case .paymentSelectorOpen(_, let tenant, _, let option):
return (category: "PaymentSelector", name: "open", label: "\(tenant.name) - \(option.duration)min")
}

switch exception {
case .qrCode(_):
if let message = serverMessage {
trackError(name: name, message: message)
} else {
trackError(name: name, message: R.string.localizable.network_error())
}
default:
trackError(name: "generic", message: R.string.localizable.generic_error())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

val value = if (isTrue) "yes" else "no"
val label = if (x > 0) "Positive" else "negative"
button.color = if (item.deleted) red else green
val text = label ?: "default"
service.deleteObject()
this.service.fetchData()?.user?.name?.size
this.data.filter { it.item?.value == 1 }.map { it.key }.firstOrNull()?.name?.size
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@


// Ternary and coalescing operators
let value = isTrue ? "yes" : "no"
let label = x > 0 ? "Positive" : "negative"
button.color = item.deleted ? red : green
let text = label ?? "default"

// Wilcard assignments
_ = service.deleteObject()

// Optional chaning
self.service.fetchData()?.user.name?.count
self.data.filter { $0.item?.value == 1 }.map { $0.key }.first?.name.count
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ userService.updateUser(picture = picture).always {
userService.autoLinkTenant(tenantId = tenant.id).then { _ ->
this?.startPayment(paymentMethod, true)
}.catchError { _ ->
val intent = this?.coordinator.autoRegisterIntent(tenant = tenant, onComplete = { this?.startPayment(paymentMethod, true) })
this?.navigationManager.show(intent, animation = .push)
val intent = this?.coordinator?.autoRegisterIntent(tenant = tenant, onComplete = { this?.startPayment(paymentMethod, true) })
this?.navigationManager?.show(intent, animation = .push)
}
item.selectCallback = { option ->
presenter.selectPaymentMethod(option)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
val list = listOf(1, 2, 3)
list.firstOrNull()
list.lastOrNull()
list.size
list.isEmpty()
throw Exception("An error ${error} occurred")
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
let list = [1, 2, 3]

list.first
list.last
list.count
list.isEmpty
//list.index(of: a) --> list.indexOf(a)
//list.append(element) --> list.add(element)
//list.remove(at: index) --> list.removeAt(index)
//list.sorted(by: lambda) --> sortedWith(comparator = Comparator(lambda))
//list.joined(separator: joiner) --> elements. joinToString(separator = joiner)

//let string = "A string"
//string.count --> string.length
//string.uppercased() --> string.toUpperCase()
//string.lowercased() --> string.toLowerCase()

fatalError("An error \(error) occurred")

6 changes: 6 additions & 0 deletions Tests/SwiftKotlinFrameworkTests/TransformPluginTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ class TransformPluginTests: XCTestCase {
file: "XCTTestToJUnitTokenTransformPlugin")
}

func testFoundationTransformPlugin() {
try! testTokenTransformPlugin(
plugin: FoundationMethodsTransformPlugin(),
file: "FoundationMethodsTransformPlugin")
}

}

extension TransformPluginTests {
Expand Down

0 comments on commit f115fce

Please sign in to comment.