mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This way we will be able to avoid reclassifying these nodes for syntax highlighting since we know they haven't changed.
110 lines
4.0 KiB
Swift
110 lines
4.0 KiB
Swift
//===--------------- SwiftLanguage.swift - Swift Syntax Library -----------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
// This file provides main entry point into the Syntax library.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Foundation
|
|
|
|
#if os(macOS)
|
|
import Darwin
|
|
#elseif os(Linux)
|
|
import Glibc
|
|
#endif
|
|
|
|
/// A list of possible errors that could be encountered while parsing a
|
|
/// Syntax tree.
|
|
public enum ParserError: Error, CustomStringConvertible {
|
|
case swiftcFailed(Int, String)
|
|
case invalidFile
|
|
|
|
public var description: String {
|
|
switch self{
|
|
case let .swiftcFailed(exitCode, stderr):
|
|
let stderrLines = stderr.split(separator: "\n")
|
|
return """
|
|
swiftc returned with non-zero exit code \(exitCode)
|
|
stderr:
|
|
\(stderrLines.joined(separator: "\n "))
|
|
"""
|
|
case .invalidFile:
|
|
return "swiftc created an invalid syntax file"
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Deserializes the syntax tree from its serialized form to an object tree in
|
|
/// Swift. To deserialize incrementally transferred syntax trees, the same
|
|
/// instance of the deserializer must be used for all subsequent
|
|
/// deserializations.
|
|
public final class SyntaxTreeDeserializer {
|
|
// FIXME: This lookup table just accumulates nodes, we should invalidate nodes
|
|
// that are no longer used at some point and remove them from the table
|
|
|
|
/// Syntax nodes that have already been parsed and are able to be reused if
|
|
/// they were omitted in an incremental syntax tree transfer
|
|
private var nodeLookupTable: [SyntaxNodeId: RawSyntax] = [:]
|
|
|
|
/// The IDs of the nodes that were reused as part of incremental syntax
|
|
/// parsing during the last deserialization
|
|
public var reusedNodeIds: Set<SyntaxNodeId> = []
|
|
|
|
public init() {
|
|
}
|
|
|
|
/// Decode a serialized form of SourceFileSyntax to a syntax tree.
|
|
/// - Parameter data: The UTF-8 represenation of the serialized syntax tree
|
|
/// - Returns: A top-level Syntax node representing the contents of the tree,
|
|
/// if the parse was successful.
|
|
public func deserialize(_ data: Data) throws -> SourceFileSyntax {
|
|
reusedNodeIds = []
|
|
let decoder = JSONDecoder()
|
|
decoder.userInfo[.rawSyntaxDecodedCallback] = self.addToLookupTable
|
|
decoder.userInfo[.omittedNodeLookupFunction] = self.lookupNode
|
|
let raw = try decoder.decode(RawSyntax.self, from: data)
|
|
guard let file = makeSyntax(raw) as? SourceFileSyntax else {
|
|
throw ParserError.invalidFile
|
|
}
|
|
return file
|
|
}
|
|
|
|
// MARK: Incremental deserialization helper functions
|
|
|
|
private func lookupNode(id: SyntaxNodeId) -> RawSyntax? {
|
|
reusedNodeIds.insert(id)
|
|
return nodeLookupTable[id]
|
|
}
|
|
|
|
private func addToLookupTable(_ node: RawSyntax) {
|
|
nodeLookupTable[node.id] = node
|
|
}
|
|
}
|
|
|
|
/// Namespace for functions to retrieve a syntax tree from the swift compiler
|
|
/// and deserializing it.
|
|
public enum SyntaxTreeParser {
|
|
/// Parses the Swift file at the provided URL into a full-fidelity Syntax tree
|
|
/// - Parameter url: The URL you wish to parse.
|
|
/// - Returns: A top-level Syntax node representing the contents of the tree,
|
|
/// if the parse was successful.
|
|
/// - Throws: `ParseError.couldNotFindSwiftc` if `swiftc` could not be
|
|
/// located, `ParseError.invalidFile` if the file is invalid.
|
|
/// FIXME: Fill this out with all error cases.
|
|
public static func parse(_ url: URL) throws -> SourceFileSyntax {
|
|
let swiftcRunner = try SwiftcRunner(sourceFile: url)
|
|
let result = try swiftcRunner.invoke()
|
|
let syntaxTreeData = result.stdoutData
|
|
let deserializer = SyntaxTreeDeserializer()
|
|
return try deserializer.deserialize(syntaxTreeData)
|
|
}
|
|
}
|
|
|