| %{ |
| from gyb_syntax_support import * |
| # -*- mode: C++ -*- |
| # Ignore the following admonition; it applies to the resulting .cpp file only |
| }% |
| //// Automatically Generated From SyntaxClassifier.cpp.gyb. |
| //// Do Not Edit Directly! |
| //===----- SyntaxClassifier.cpp - Syntax Classifier implementations -------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the Syntax Classifier, which walks the syntax tree and |
| // creates a classification table for all tokens in the syntax tree, mapping it |
| // to a \c SyntaxClassification by its ID. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/Basic/EditorPlaceholder.h" |
| #include "swift/Syntax/SyntaxClassifier.h" |
| |
| using namespace swift; |
| using namespace swift::syntax; |
| |
| % for node in SYNTAX_NODES: |
| % if is_visitable(node): |
| void SyntaxClassifier::visit(${node.name} Node) { |
| % if node.is_unknown() or node.is_syntax_collection(): |
| SyntaxVisitor::visit(Node); |
| % else: |
| % for child in node.children: |
| % if child.classification: |
| visit(Node.get${child.name}(), SyntaxClassification::${child.classification}, ${"true" if child.force_classification else "false"}); |
| % else: |
| visit(Node.get${child.name}()); |
| % end |
| % end |
| % end |
| } |
| % end |
| % end |
| |
| /// Returns the SyntaxClassficiation a token node should receive if it is not |
| /// inside a special context. Returns \c None if the token has no context-free |
| /// classification and should always inherit from the context. |
| llvm::Optional<SyntaxClassification> |
| getContextFreeClassificationForToken(TokenSyntax TokenNode) { |
| switch (TokenNode.getTokenKind()) { |
| #define KEYWORD(KW) case tok::kw_##KW: return SyntaxClassification::Keyword; |
| #define POUND_KEYWORD(KW) case tok::pound_##KW: return SyntaxClassification::Keyword; |
| #define POUND_OBJECT_LITERAL(KW, desc, proto) case tok::pound_##KW: return SyntaxClassification::ObjectLiteral; |
| #define POUND_DIRECTIVE_KEYWORD(KW) case tok::pound_##KW: return SyntaxClassification::PoundDirectiveKeyword; |
| #define POUND_COND_DIRECTIVE_KEYWORD(KW) case tok::pound_##KW: return SyntaxClassification::BuildConfigKeyword; |
| #include "swift/Syntax/TokenKinds.def" |
| // Punctuators |
| case tok::l_paren: |
| case tok::r_paren: |
| case tok::l_brace: |
| case tok::r_brace: |
| case tok::l_square: |
| case tok::r_square: |
| case tok::l_angle: |
| case tok::r_angle: |
| case tok::period: |
| case tok::period_prefix: |
| case tok::comma: |
| case tok::colon: |
| case tok::semi: |
| case tok::equal: |
| case tok::pound: |
| case tok::amp_prefix: |
| case tok::arrow: |
| case tok::backtick: |
| case tok::backslash: |
| case tok::exclaim_postfix: |
| case tok::question_postfix: |
| case tok::question_infix: |
| case tok::sil_dollar: |
| case tok::sil_exclamation: |
| return SyntaxClassification::None; |
| case tok::string_quote: |
| case tok::multiline_string_quote: |
| return SyntaxClassification::StringLiteral; |
| case tok::at_sign: |
| return SyntaxClassification::Attribute; |
| |
| // Literals |
| case tok::integer_literal: |
| return SyntaxClassification::IntegerLiteral; |
| case tok::floating_literal: |
| return SyntaxClassification::FloatingLiteral; |
| case tok::string_literal: |
| return SyntaxClassification::StringLiteral; |
| |
| // Miscelaneous |
| case tok::identifier: { |
| if (isEditorPlaceholder(TokenNode.getText())) { |
| return SyntaxClassification::EditorPlaceholder; |
| } else { |
| return llvm::None; |
| } |
| } |
| case tok::unknown: |
| if (TokenNode.getText().startswith("\"")) { |
| // Unterminated string literal |
| return SyntaxClassification::StringLiteral; |
| } else { |
| return SyntaxClassification::None; |
| } |
| break; |
| case tok::eof: |
| case tok::code_complete: |
| case tok::oper_binary_unspaced: |
| case tok::oper_binary_spaced: |
| case tok::oper_postfix: |
| case tok::oper_prefix: |
| return SyntaxClassification::None; |
| case tok::dollarident: |
| return SyntaxClassification::DollarIdentifier; |
| case tok::sil_local_name: |
| return SyntaxClassification::None; |
| case tok::comment: |
| llvm_unreachable("Comments should be in trivia"); |
| case tok::contextual_keyword: |
| return SyntaxClassification::Keyword; |
| case tok::string_segment: |
| return SyntaxClassification::StringLiteral; |
| case tok::string_interpolation_anchor: |
| return SyntaxClassification::StringInterpolationAnchor; |
| case tok::NUM_TOKENS: |
| llvm_unreachable(""); |
| } |
| } |
| |
| void SyntaxClassifier::visit(TokenSyntax TokenNode) { |
| SyntaxClassification Classification = ContextStack.top().Classification; |
| bool ForceClassification = ContextStack.top().ForceClassification; |
| if (!ForceClassification) { |
| auto NativeClassification = getContextFreeClassificationForToken(TokenNode); |
| if (NativeClassification.hasValue()) { |
| Classification = NativeClassification.getValue(); |
| } |
| if (Classification == SyntaxClassification::None && |
| TokenNode.getTokenKind() == tok::identifier) { |
| Classification = SyntaxClassification::Identifier; |
| } |
| } |
| |
| assert(ClassifiedTokens.count(TokenNode.getId()) == 0 && |
| "Token already classified"); |
| ClassifiedTokens[TokenNode.getId()] = Classification; |
| } |