mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
146 lines
4.8 KiB
Swift
146 lines
4.8 KiB
Swift
%{
|
|
from gyb_syntax_support import *
|
|
# -*- mode: Swift -*-
|
|
# Ignore the following admonition it applies to the resulting .swift file only
|
|
}%
|
|
//// Automatically Generated From SyntaxClassifier.swift.gyb.
|
|
//// Do Not Edit Directly!
|
|
//===------------ SyntaxClassifier.swift.gyb - Syntax Collection ----------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2018 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
public enum SyntaxClassification {
|
|
% for classification in SYNTAX_CLASSIFICATIONS:
|
|
% for line in dedented_lines(classification.description):
|
|
% if line:
|
|
/// ${line}
|
|
% end
|
|
% end
|
|
case ${classification.swift_name}
|
|
% end
|
|
}
|
|
|
|
fileprivate class _SyntaxClassifier: SyntaxVisitor {
|
|
|
|
/// Don't classify nodes with these IDs or any of their children
|
|
var skipNodeIds: Set<SyntaxNodeId> = []
|
|
|
|
/// The top of the `contextStack` determines the classification for all tokens
|
|
/// encountered that do not have a native classification. If `force` is `true`
|
|
/// the top of the stack also determines the classification of tokens with a
|
|
/// native classification
|
|
private var contextStack: [(classification: SyntaxClassification, force: Bool)] =
|
|
[(classification: .none, force: false)]
|
|
|
|
/// The classifications that have determined so far are collected in this
|
|
/// dictionary
|
|
var classifications: [TokenSyntax: SyntaxClassification] = [:]
|
|
|
|
private func visit(
|
|
_ node: Syntax,
|
|
classification: SyntaxClassification,
|
|
force: Bool = false
|
|
) {
|
|
contextStack.append((classification: classification, force: force))
|
|
visit(node)
|
|
contextStack.removeLast()
|
|
}
|
|
|
|
private func getContextFreeClassificationForTokenKind(_ tokenKind: TokenKind)
|
|
-> SyntaxClassification? {
|
|
switch (tokenKind) {
|
|
% for token in SYNTAX_TOKENS:
|
|
case .${token.swift_kind()}:
|
|
% if token.classification:
|
|
return SyntaxClassification.${token.classification.swift_name}
|
|
% else:
|
|
return nil
|
|
% end
|
|
% end
|
|
case .eof:
|
|
return SyntaxClassification.none
|
|
}
|
|
}
|
|
|
|
override func visit(_ token: TokenSyntax) {
|
|
// FIXME: We need to come up with some way in which the SyntaxClassifier can
|
|
// classify trivia (i.e. comments). In particular we need to be able to
|
|
// look into the comments to find things like URLs or keywords like MARK.
|
|
var classification = contextStack.last!.classification
|
|
if !contextStack.last!.force {
|
|
if let contextFreeClassification =
|
|
getContextFreeClassificationForTokenKind(token.tokenKind) {
|
|
classification = contextFreeClassification
|
|
}
|
|
if case .unknown = token.tokenKind, token.text.starts(with: "\"") {
|
|
classification = .stringLiteral
|
|
} else if case .identifier = token.tokenKind,
|
|
token.text.starts(with: "<#") && token.text.hasSuffix("#>") {
|
|
classification = .editorPlaceholder
|
|
}
|
|
}
|
|
assert(classifications[token] == nil,
|
|
"\(token) has already been classified")
|
|
classifications[token] = classification
|
|
}
|
|
|
|
% for node in SYNTAX_NODES:
|
|
% if is_visitable(node):
|
|
override func visit(_ node: ${node.name}) {
|
|
if skipNodeIds.contains(node.raw.id) {
|
|
return
|
|
}
|
|
% if node.is_unknown() or node.is_syntax_collection():
|
|
super.visit(node)
|
|
% else:
|
|
% for child in node.children:
|
|
% if child.is_optional:
|
|
if let ${child.swift_name} = node.${child.swift_name} {
|
|
% if child.classification:
|
|
visit(${child.swift_name},
|
|
classification: .${child.classification.swift_name},
|
|
force: ${"true" if child.force_classification else "false"})
|
|
% else:
|
|
visit(${child.swift_name})
|
|
% end
|
|
}
|
|
% else:
|
|
% if child.classification:
|
|
visit(node.${child.swift_name},
|
|
classification: .${child.classification.swift_name},
|
|
force: ${"true" if child.force_classification else "false"})
|
|
% else:
|
|
visit(node.${child.swift_name})
|
|
% end
|
|
% end
|
|
% end
|
|
% end
|
|
|
|
}
|
|
% end
|
|
% end
|
|
}
|
|
|
|
public enum SyntaxClassifier {
|
|
/// Classify all tokens in the given syntax tree for syntax highlighting.
|
|
/// If a `IncrementalTreeTransferSession` is passed, only nodes that have
|
|
/// changed since the last transfer will be classified.
|
|
public static func classifyTokensInTree(
|
|
_ syntaxTree: SourceFileSyntax,
|
|
skipNodes: Set<SyntaxNodeId> = []
|
|
) -> [TokenSyntax: SyntaxClassification] {
|
|
let classifier = _SyntaxClassifier()
|
|
classifier.skipNodeIds = skipNodes
|
|
classifier.visit(syntaxTree)
|
|
return classifier.classifications
|
|
}
|
|
}
|