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

Support try expression #20

Merged
merged 1 commit into from
Dec 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 58 additions & 10 deletions Sources/SwiftPowerAssertCore/Instrumentor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,12 @@ class Instrumentor {
let tokens = formatter.tokenize(source: expression.source)

let column = columnInFunctionCall(column: childExpression.range.end.column, startLine: childExpression.range.start.line, endLine: childExpression.range.end.line, tokens: tokens, child: childExpression, parent: expression)
values[column] = formatter.format(tokens: formatter.tokenize(source: source))

if source.hasPrefix(".") {
values[column] = childExpression.type + formatter.format(tokens: formatter.tokenize(source: source))
} else {
values[column] = formatter.format(tokens: formatter.tokenize(source: source))
}
}
if childExpression.rawValue == "string_literal_expr" {
let source = stringLiteralExpression(childExpression, expression)
Expand All @@ -152,16 +157,29 @@ class Instrumentor {
let tokens = formatter.tokenize(source: expression.source)

let column = columnInFunctionCall(column: childExpression.location.column, startLine: childExpression.location.line, endLine: childExpression.location.line, tokens: tokens, child: childExpression, parent: expression)
values[column] = formatter.format(tokens: formatter.tokenize(source: source))

// FIXME
if !childExpression.expressions.isEmpty && childExpression.expressions[0].type.contains("throws") {
values[column] = "try! " + formatter.format(tokens: formatter.tokenize(source: source))
} else {
values[column] = formatter.format(tokens: formatter.tokenize(source: source))
}
}
if childExpression.rawValue == "binary_expr" {
let source = binaryExpression(childExpression, expression)

let formatter = Formatter()
let tokens = formatter.tokenize(source: expression.source)

var containsThrowsFunction = false
traverse(childExpression) {
guard !containsThrowsFunction else { return }
containsThrowsFunction = $0.type.contains("throws") // FIXME: It should check 'throws' or 'nothrow' in 'call_expr'
}

// FIXME
let column = columnInFunctionCall(column: childExpression.location.column, startLine: childExpression.location.line, endLine: childExpression.location.line, tokens: tokens, child: childExpression, parent: expression)
values[column] = formatter.format(tokens: formatter.tokenize(source: source))
values[column] = (containsThrowsFunction ? "try! " : "") + formatter.format(tokens: formatter.tokenize(source: source))
}
}

Expand Down Expand Up @@ -194,7 +212,7 @@ class Instrumentor {
print(string, terminator: \"\")
current += string.count
}
print(\"\(formatter.format(tokens: formatter.tokenize(source: expression.source)).replacingOccurrences(of: "\"", with: "\\\""))\")
print(\"\(formatter.escaped(tokens: formatter.tokenize(source: expression.source)))\")
var values = Array(valueColumns).sorted { $0.0 < $1.0 }
var current = 0
for value in values {
Expand Down Expand Up @@ -333,13 +351,20 @@ class Instrumentor {

loop: for token in tokens {
switch token.type {
case .token, .string:
case .token:
if lineIndex < endLineIndex {
columnIndex += token.value.count
} else if lineIndex == endLineIndex {
columnIndex += column
break loop
}
case .string:
if lineIndex < endLineIndex {
columnIndex += ("\"" + token.value + "\"").count
} else if lineIndex == endLineIndex {
columnIndex += column
break loop
}
case .indent(let count):
if lineIndex == endLineIndex {
indent += count
Expand Down Expand Up @@ -384,7 +409,6 @@ class Instrumentor {
switch character {
case "\"":
state.mode = .string
state.storage = "\""
case "\n":
state.tokens.append(Token(type: .newline, value: String(character)))
state.mode = .newline
Expand All @@ -399,7 +423,7 @@ class Instrumentor {
case .token:
switch character {
case "\"":
state.tokens.append(Token(type: .token, value: state.storage + "\""))
state.tokens.append(Token(type: .token, value: state.storage))
state.mode = .string
state.storage = ""
case " ":
Expand All @@ -415,14 +439,15 @@ class Instrumentor {
case "(", ")", "[", "]", "{", "}", ",", ".", ":", ";":
state.tokens.append(Token(type: .token, value: state.storage))
state.tokens.append(Token(type: .token, value: String(character)))
state.mode = .plain
state.storage = ""
default:
state.storage += String(character)
}
case .string:
switch character {
case "\"":
state.tokens.append(Token(type: .string, value: state.storage + "\""))
state.tokens.append(Token(type: .string, value: state.storage))
state.mode = .plain
state.storage = ""
case "\\":
Expand All @@ -434,7 +459,7 @@ class Instrumentor {
switch character {
case "\"", "\\":
state.mode = .string
state.storage += String(character)
state.storage += "\\" + String(character)
case "n":
state.mode = .string
state.storage += "\n"
Expand All @@ -446,6 +471,10 @@ class Instrumentor {
}
case .indent:
switch character {
case "\"":
state.tokens.append(Token(type: .indent(state.storage.count), value: state.storage))
state.mode = .string
state.storage = ""
case " ", "\t":
state.storage += " "
case "\n":
Expand Down Expand Up @@ -498,8 +527,27 @@ class Instrumentor {
var formatted = ""
for token in tokens {
switch token.type {
case .token, .string:
case .token:
formatted += token.value
case .string:
formatted += "\"" + token.value + "\""
case .indent(_):
break
case .newline:
formatted += " "
}
}
return formatted
}

func escaped(tokens: [Token]) -> String {
var formatted = ""
for token in tokens {
switch token.type {
case .token:
formatted += token.value
case .string:
formatted += "\\\"" + token.value.replacingOccurrences(of: "\"", with: "\\\\\"") + "\\\""
case .indent(_):
break
case .newline:
Expand Down
15 changes: 14 additions & 1 deletion Sources/SwiftPowerAssertCore/SwiftPowerAssert.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,22 @@ public final class SwiftPowerAssert {
compile.launch()

let result = String(data: pipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8)!
var lines = [String]()
result.enumerateLines { (line, stop) in
let trimmed = line.trimmingCharacters(in: .whitespaces)
if trimmed.hasPrefix("(normal_conformance") ||
trimmed.hasPrefix("(abstract_conformance") ||
trimmed.hasPrefix("(specialized_conformance") ||
trimmed.hasPrefix("(assoc_type") ||
trimmed.hasPrefix("(value req") ||
!trimmed.hasPrefix("(") {
return
}
lines.append(line)
}

let tokenizer = Tokenizer()
let tokens = tokenizer.tokenize(source: result)
let tokens = tokenizer.tokenize(source: lines.joined(separator: "\n"))

let lexer = Lexer()
let node = lexer.lex(tokens: tokens)
Expand Down
61 changes: 61 additions & 0 deletions Tests/SwiftPowerAssertTests/SwiftPowerAssertTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -656,4 +656,65 @@ class SwiftPowerAssertTests: XCTestCase {
let result = try TestRunner().run(source: source)
XCTAssertEqual(expected, result)
}

func testTryExpression() throws {
let source = """
import XCTest

struct Coordinate: Codable {
var latitude: Double
var longitude: Double
}

struct Landmark: Codable {
var name: String
var foundingYear: Int
var location: Coordinate
}

class Tests: XCTestCase {
@objc dynamic func testMethod() {
let landmark = Landmark(name: \"Tokyo Tower\",
foundingYear: 1957,
location: Coordinate(latitude: 35.658581, longitude: 139.745438))
assert(try! JSONEncoder().encode(landmark) ==
"{ name: \\"Tokyo Tower\\" }".data(using: String.Encoding.utf8))
assert(try! JSONEncoder().encode(landmark) ==
"{ name: \\"Tokyo Tower\\" }".data(using: .utf8))
assert(try! "{ name: \\"Tokyo Tower\\" }".data(using: String.Encoding.utf8) ==
JSONEncoder().encode(landmark))
}
}

Tests().testMethod()
"""

let expected = """
assert(try! JSONEncoder().encode(landmark) == "{ name: \\"Tokyo Tower\\" }".data(using: String.Encoding.utf8))
| | | | | | |
| | | | { name: "Tokyo Tower" } 23 bytes Unicode (UTF-8)
| | | false
| | Landmark(name: "Tokyo Tower", foundingYear: 1957, location: main.Coordinate(latitude: 35.658580999999998, longitude: 139.74543800000001))
| 99 bytes
Foundation.JSONEncoder
assert(try! JSONEncoder().encode(landmark) == "{ name: \\"Tokyo Tower\\" }".data(using: .utf8))
| | | | | | |
| | | | { name: "Tokyo Tower" } 23 bytes Unicode (UTF-8)
| | | false
| | Landmark(name: "Tokyo Tower", foundingYear: 1957, location: main.Coordinate(latitude: 35.658580999999998, longitude: 139.74543800000001))
| 99 bytes
Foundation.JSONEncoder
assert(try! "{ name: \\"Tokyo Tower\\" }".data(using: String.Encoding.utf8) == JSONEncoder().encode(landmark))
| | | | | | |
{ name: "Tokyo Tower" } 23 bytes | | | | Landmark(name: "Tokyo Tower", foundingYear: 1957, location: main.Coordinate(latitude: 35.658580999999998, longitude: 139.74543800000001))
| | | 99 bytes
| | Foundation.JSONEncoder
| false
Unicode (UTF-8)

"""

let result = try TestRunner().run(source: source)
XCTAssertEqual(expected, result)
}
}