Skip to content

Commit

Permalink
Support nested type parser
Browse files Browse the repository at this point in the history
  • Loading branch information
kawoou committed Jan 15, 2020
1 parent fcf50b8 commit 9f38942
Show file tree
Hide file tree
Showing 20 changed files with 981 additions and 731 deletions.
76 changes: 67 additions & 9 deletions Binary/Sources/Deli/Runner/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//

import Foundation
import Regex
import SourceKittenFramework

final class Parser: Runnable {
Expand All @@ -14,14 +15,15 @@ final class Parser: Runnable {
static let allowKinds = [
SwiftDeclarationKind.class.rawValue,
SwiftDeclarationKind.struct.rawValue,
SwiftDeclarationKind.protocol.rawValue,
SwiftDeclarationKind.typealias.rawValue
SwiftDeclarationKind.protocol.rawValue
]
static let allowAccessLevels = [
Structure.AccessLevel.open,
Structure.AccessLevel.public,
Structure.AccessLevel.internal
]

static let typealiasRegex = "typealias[\\s]+([^\\s=]+)[\\s]*=[\\s]*([^\\n]+)".r!
}

// MARK: - Property
Expand All @@ -31,20 +33,62 @@ final class Parser: Runnable {
// MARK: - Private

private var inheritanceMap = [String: InheritanceInfo]()

private func parseTypealias(structure: Structure, content: String) -> String? {
guard let data = content.utf8[Int(structure.offset)..<Int(structure.offset + structure.length)] else { return nil }
guard let typeMatch = Constant.typealiasRegex.findFirst(in: data) else {
Logger.log(.debug("Failed to parse file content for 'typealias' keyword"))
return nil
}
guard let typeName = typeMatch.group(at: 1) else { return nil }
guard let typeResult = typeMatch.group(at: 2) else { return nil }
guard typeName == structure.name else {
Logger.log(.debug(
"Type dismatch between SourceKitten and file content " +
"(SourceKitten: \(structure.name ?? ""), file content: \(typeName))"
))
return nil
}
return typeResult
}

private func parse(structure: Structure, content: String, prefix: String = "") throws -> [Results] {
guard let name = structure.name.map({ prefix + $0 }) else { return [] }
private func parse(
structure: Structure,
content: String,
typePrefix: String = "",
typealiasMap: [String: String] = [:]
) throws -> [Results] {
guard let name = structure.name.map({ typePrefix + $0 }) else { return [] }

/// Compare allowed keywords
guard Constant.allowKinds.contains(structure.kind) else { return [] }

/// Compares allowed AccessLevels
guard Constant.allowAccessLevels.contains(structure.accessLevel) else { return [] }

/// Saved typealias
var typealiasMap = typealiasMap
structure.substructures
.filter { $0.kind == SwiftDeclarationKind.typealias.rawValue }
.forEach { structure in
guard let typeName = structure.name else { return }
guard let typeResult = parseTypealias(structure: structure, content: content) else { return }

typealiasMap[typeName] = typeResult
typealiasMap["\(name).\(typeName)"] = typeResult
}

/// Find nested type
let results = try structure.substructures
.flatMap { try parse(structure: $0, content: content, prefix: "\(name).") }

.flatMap {
try parse(
structure: $0,
content: content,
typePrefix: "\(name).",
typealiasMap: typealiasMap
)
}

/// Save inheritance information
inheritanceMap[name] = InheritanceInfo(
name: name,
Expand All @@ -54,18 +98,32 @@ final class Parser: Runnable {
)

/// Parsing
return try moduleList
let parseResults = try moduleList
.flatMap { parsable -> [Results] in
let dependencies = try parsable.dependency
.flatMap { try $0.parse(by: structure, fileContent: content) }
.flatMap {
try $0.parse(
by: structure,
fileContent: content,
typePrefix: typePrefix,
typealiasMap: typealiasMap
)
}

return try parsable
.parse(by: structure, fileContent: content)
.parse(
by: structure,
fileContent: content,
typePrefix: typePrefix,
typealiasMap: typealiasMap
)
.map { result in
result.dependencies.append(contentsOf: dependencies)
return result
}
} + results

return parseResults
}

private func parse(path: String) throws -> [Results] {
Expand Down
13 changes: 9 additions & 4 deletions Binary/Sources/Deli/Runner/Parser/AutowiredFactoryParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,13 @@ final class AutowiredFactoryParser: Parsable {

// MARK: - Public

func parse(by source: Structure, fileContent: String) throws -> [Results] {
guard let name = source.name else {
func parse(
by source: Structure,
fileContent: String,
typePrefix: String,
typealiasMap: [String: String]
) throws -> [Results] {
guard let name = source.name.map({ typePrefix + $0 }) else {
Logger.log(.assert("Unknown structure name."))
return []
}
Expand Down Expand Up @@ -111,7 +116,7 @@ final class AutowiredFactoryParser: Parsable {
return Dependency(
parent: name,
target: constructor,
name: arrayType,
name: typealiasMap[arrayType] ?? arrayType,
type: .array,
qualifier: qualifier,
qualifierBy: qualifierBy
Expand All @@ -120,7 +125,7 @@ final class AutowiredFactoryParser: Parsable {
return Dependency(
parent: name,
target: constructor,
name: dependencyName,
name: typealiasMap[dependencyName] ?? dependencyName,
qualifier: qualifier,
qualifierBy: qualifierBy
)
Expand Down
13 changes: 9 additions & 4 deletions Binary/Sources/Deli/Runner/Parser/AutowiredParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,13 @@ final class AutowiredParser: Parsable {

// MARK: - Public

func parse(by source: Structure, fileContent: String) throws -> [Results] {
guard let name = source.name else {
func parse(
by source: Structure,
fileContent: String,
typePrefix: String,
typealiasMap: [String: String]
) throws -> [Results] {
guard let name = source.name.map({ typePrefix + $0 }) else {
Logger.log(.assert("Unknown structure name."))
return []
}
Expand Down Expand Up @@ -100,7 +105,7 @@ final class AutowiredParser: Parsable {
return Dependency(
parent: name,
target: constructor,
name: arrayType,
name: typealiasMap[arrayType] ?? arrayType,
type: .array,
qualifier: qualifier,
qualifierBy: qualifierBy
Expand All @@ -109,7 +114,7 @@ final class AutowiredParser: Parsable {
return Dependency(
parent: name,
target: constructor,
name: dependencyName,
name: typealiasMap[dependencyName] ?? dependencyName,
qualifier: qualifier,
qualifierBy: qualifierBy
)
Expand Down
9 changes: 7 additions & 2 deletions Binary/Sources/Deli/Runner/Parser/ComponentParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ final class ComponentParser: Parsable {

// MARK: - Public

func parse(by source: Structure, fileContent: String) throws -> [Results] {
guard let name = source.name else { return [] }
func parse(
by source: Structure,
fileContent: String,
typePrefix: String,
typealiasMap: [String: String]
) throws -> [Results] {
guard let name = source.name.map({ typePrefix + $0 }) else { return [] }
guard source.inheritedTypes.contains(Constant.inheritanceName) else { return [] }

let scope = try parseScope(source, fileContent: fileContent)
Expand Down
21 changes: 18 additions & 3 deletions Binary/Sources/Deli/Runner/Parser/ConfigPropertyParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ final class ConfigPropertyParser: Parsable {

// MARK: - Private

private func convert(_ source: Structure, fileContent: String) throws -> ConfigPropertyResult {
private func convert(
_ source: Structure,
fileContent: String,
typealiasMap: [String: String]
) throws -> ConfigPropertyResult {
guard let name = source.name else {
throw ParserError.unknown
}
Expand Down Expand Up @@ -75,13 +79,24 @@ final class ConfigPropertyParser: Parsable {

// MARK: - Public

func parse(by source: Structure, fileContent: String) throws -> [Results] {
func parse(
by source: Structure,
fileContent: String,
typePrefix: String,
typealiasMap: [String: String]
) throws -> [Results] {
guard source.name != nil else {
Logger.log(.assert("Unknown structure name."))
return []
}
guard source.inheritedTypes.contains(Constant.inheritanceName) else { return [] }

return [try convert(source, fileContent: fileContent)]
return [
try convert(
source,
fileContent: fileContent,
typealiasMap: typealiasMap
)
]
}
}
37 changes: 31 additions & 6 deletions Binary/Sources/Deli/Runner/Parser/ConfigurationParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ final class ConfigurationParser: Parsable {

private let injectParser = InjectParser()

private func convert(_ source: Structure, parent: Structure, fileContent: String) throws -> ConfigFunctionResult {
private func convert(
_ source: Structure,
parent: Structure,
fileContent: String,
typePrefix: String,
typealiasMap: [String: String]
) throws -> ConfigFunctionResult {
guard let name = parent.name else {
throw ParserError.unknown
}
Expand Down Expand Up @@ -88,7 +94,7 @@ final class ConfigurationParser: Parsable {
return Dependency(
parent: name,
target: source,
name: dependencyName
name: typealiasMap[dependencyName] ?? dependencyName
)
}

Expand Down Expand Up @@ -124,7 +130,13 @@ final class ConfigurationParser: Parsable {
.findAll(in: fileContent)
.compactMap { $0.group(at: 1) }

let injectResults = try injectParser.parse(by: source, fileContent: fileContent, isInheritanceCheck: false)
let injectResults = try injectParser.parse(
by: source,
fileContent: fileContent,
isInheritanceCheck: false,
typePrefix: typePrefix,
typealiasMap: typealiasMap
)

/// Result
return ConfigFunctionResult(
Expand All @@ -147,16 +159,29 @@ final class ConfigurationParser: Parsable {

// MARK: - Public

func parse(by source: Structure, fileContent: String) throws -> [Results] {
guard let name = source.name else {
func parse(
by source: Structure,
fileContent: String,
typePrefix: String,
typealiasMap: [String: String]
) throws -> [Results] {
guard let name = source.name.map({ typePrefix + $0 }) else {
Logger.log(.assert("Unknown structure name."))
return []
}
guard source.inheritedTypes.contains(Constant.inheritanceName) else { return [] }

return try source.substructures
.filter { validFunction($0) }
.map { try convert($0, parent: source, fileContent: fileContent) } +
.map {
try convert(
$0,
parent: source,
fileContent: fileContent,
typePrefix: typePrefix,
typealiasMap: typealiasMap
)
} +
[
ConfigurationResult(
name,
Expand Down
Loading

0 comments on commit 9f38942

Please sign in to comment.