Skip to content

Commit

Permalink
Progress converting SwiftAST to SwiftSyntax.
Browse files Browse the repository at this point in the history
  • Loading branch information
tjprescott committed Nov 23, 2022
1 parent fa40b84 commit 4bc1a57
Show file tree
Hide file tree
Showing 50 changed files with 1,379 additions and 1,118 deletions.
40 changes: 24 additions & 16 deletions src/swift/SwiftAPIViewCore/Sources/APIViewManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@
//
// --------------------------------------------------------------------------

import AST
import Foundation
import OrderedCollections
import Parser
import Source
import SwiftSyntax
import SwiftSyntaxParser
import SourceKittenFramework


Expand Down Expand Up @@ -59,18 +58,21 @@ public class APIViewConfiguration {
}

/// Handles the generation of APIView JSON files.
public class APIViewManager {
public class APIViewManager: SyntaxVisitor {

// MARK: Properties

var config = APIViewConfiguration()

var mode: APIViewManagerMode

var statements = OrderedDictionary<Int, CodeBlockItemSyntax.Item>()

// MARK: Initializer

public init(mode: APIViewManagerMode = .commandLine) {
self.mode = mode
super.init(viewMode: .all)
}

// MARK: Methods
Expand Down Expand Up @@ -116,9 +118,9 @@ public class APIViewManager {
}

/// Handles automatic processing of swiftinterface file, if supplied
func process(filePath: String) throws -> SourceFile {
func process(filePath: String) throws -> String {
if filePath.hasSuffix("swift") || filePath.hasSuffix("swifttxt") || filePath.hasSuffix("swiftinterface") {
return try SourceReader.read(at: filePath)
return try String(contentsOfFile: filePath)
}
if filePath.hasSuffix("h") {
let args = [String]()
Expand All @@ -136,7 +138,7 @@ public class APIViewManager {
let tempUrl = sourceDir.appendingPathComponent(tempFilename)
try sourceCode.write(to: tempUrl, atomically: true, encoding: .utf8)
defer { try! FileManager.default.removeItem(at: tempUrl) }
return try SourceReader.read(at: tempUrl.path)
return try String(contentsOfFile: tempUrl.path)
}
}
throw ToolError.client("Unsupported file type: \(filePath)")
Expand Down Expand Up @@ -197,7 +199,6 @@ public class APIViewManager {
SharedLogger.fail("\(sourceUrl.path) does not exist.")
}

var statements = OrderedDictionary<Int, Statement>()
var filePaths = [String]()
if isDir.boolValue {
packageName = config.packageName ?? extractPackageName(from: sourceUrl)
Expand All @@ -210,15 +211,11 @@ public class APIViewManager {
}
for filePath in filePaths {
do {
let sourceFile = try process(filePath: filePath)
let topLevelDecl = try Parser(source: sourceFile).parse()

// hash top-level statement text to eliminate duplicates
topLevelDecl.statements.forEach { statement in
statements[statement.description.hash] = statement
}
let source = try process(filePath: filePath)
let rootNode = try SyntaxParser.parse(source: source);
self.walk(rootNode)
} catch let error {
SharedLogger.warn(error.localizedDescription)
SharedLogger.warn("\(error)")
}
}
// Ensure that package name and version can be resolved
Expand All @@ -239,4 +236,15 @@ public class APIViewManager {
let apiView = APIViewModel(name: apiViewName, packageName: packageName!, versionString: packageVersion!, statements: Array(statements.values))
return apiView
}

// MARK: SyntaxVisitor

public override func visit(_ node: SourceFileSyntax) -> SyntaxVisitorContinueKind {
for statement in node.statements {
let tokens = Array(statement.item.tokens(viewMode: .all))
statements[tokens.hashValue] = statement.item
}
return .skipChildren
}
}

10 changes: 6 additions & 4 deletions src/swift/SwiftAPIViewCore/Sources/Models/APIViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
// --------------------------------------------------------------------------

import Foundation
import AST
import SwiftSyntax


class APIViewModel: Tokenizable, Encodable {

Expand Down Expand Up @@ -60,7 +61,8 @@ class APIViewModel: Tokenizable, Encodable {
let indentSpaces = 4

/// Access modifier to expose via APIView
static let publicModifiers: [AccessLevelModifier] = [.public, .open]
// FIXME: Fix this!
// static let publicModifiers: [AccessLevelModifierSyntax] = [.public, .open]

/// Tracks assigned definition IDs so they can be linked
private var definitionIds = Set<String>()
Expand All @@ -72,7 +74,7 @@ class APIViewModel: Tokenizable, Encodable {

// MARK: Initializers

init(name: String, packageName: String, versionString: String, statements: [Statement]) {
init(name: String, packageName: String, versionString: String, statements: [CodeBlockItemSyntax.Item]) {
self.name = name
self.versionString = versionString
self.packageName = packageName
Expand Down Expand Up @@ -304,7 +306,7 @@ class APIViewModel: Tokenizable, Encodable {
SharedLogger.fail("Definition ID should not contain whitespace: \(defId)")
}
if self.definitionIds.contains(defId) {
// FIXME: Change back to fail
// FIXME: Change back to fail when extensions are fixed
SharedLogger.warn("Duplicate definition ID: \(defId). Will result in duplicate comments.")
}
definitionIds.insert(defId)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation
import SwiftSyntax


/// Grammar Summary:
/// actor-declaration → attributes opt access-level-modifier opt actor actor-name generic-parameter-clause opt type-inheritance-clause opt generic-where-clause opt actor-body
/// actor-name → identifier
/// actor-body → { actor-members opt }
/// actor-members → actor-member actor-members opt
/// actor-member → declaration | compiler-control-statement
class ActorModel: Tokenizable {//, Linkable, Commentable, Extensible, AccessLevelProtocol {
// FIXME: Restore
// var definitionId: String?
// var lineId: String?
// var parent: Linkable?
// var attributes: AttributesModel
// var accessLevel: AccessLevelModifier
// var isFinal: Bool
// var name: String
// var genericParamClause: GenericParameterModel?
// var typeInheritanceClause: TypeInheritanceModel?
// var genericWhereClause: GenericWhereModel?
// var members: [Tokenizable]
// var extensions: [ExtensionModel]

init(from decl: ActorDeclSyntax) {//, parent: Linkable) {
// FIXME: Restore
// self.parent = parent
// let name = decl.name.textDescription
// definitionId = identifier(forName: name, withPrefix: parent.definitionId)
// lineId = nil
// attributes = AttributesModel(from: decl.attributes)
// accessLevel = decl.accessLevel ?? .internal
// self.name = name
// isFinal = decl.isFinal
// genericParamClause = GenericParameterModel(from: decl.genericParameterClause)
// typeInheritanceClause = TypeInheritanceModel(from: decl.typeInheritanceClause)
// genericWhereClause = GenericWhereModel(from: decl.genericWhereClause)
// extensions = [ExtensionModel]()
// members = [Tokenizable]()
// decl.members.forEach { member in
// switch member {
// case let .declaration(decl):
// if let model = decl.toTokenizable(withParent: self) {
// if let model = model as? ExtensionModel {
// // TODO: Place the extension in the appropriate location
// extensions.append(model)
// } else {
// members.append(model)
// }
// }
// case let .compilerControl(statement):
// SharedLogger.warn("Unsupported compiler control statement: \(statement)")
// }
// }
}

func tokenize(apiview a: APIViewModel) {
// FIXME: Restore
// guard APIViewModel.publicModifiers.contains(accessLevel) else { return }
// attributes.tokenize(apiview: a)
// a.keyword(accessLevel.textDescription, postfixSpace: true)
// if isFinal {
// a.keyword("final", postfixSpace: true)
// }
// a.keyword("class", postfixSpace: true)
// a.typeDeclaration(name: name, definitionId: definitionId)
// genericParamClause?.tokenize(apiview: a)
// typeInheritanceClause?.tokenize(apiview: a)
// genericWhereClause?.tokenize(apiview: a)
// a.punctuation("{", prefixSpace: true)
// a.newline()
// a.indent {
// members.forEach { member in
// member.tokenize(apiview: a)
// }
// extensions.forEach { ext in
// ext.tokenize(apiview: a)
// }
// }
// a.punctuation("}")
// a.newline()
// a.blankLines(set: 1)
}

func navigationTokenize(apiview a: APIViewModel) {
// FIXME: Restore
// guard APIViewModel.publicModifiers.contains(accessLevel) else { return }
// a.add(token: NavigationToken(name: name, prefix: parent?.name, typeKind: .class))
// for member in members {
// guard let member = member as? Linkable else { continue }
// member.navigationTokenize(apiview: a)
// }
}
}
Loading

0 comments on commit 4bc1a57

Please sign in to comment.