Files
swift-mirror/lib/Syntax/SyntaxClassifier.cpp.gyb
John McCall 7a4aeed570 Implement generalized accessors using yield-once coroutines.
For now, the accessors have been underscored as `_read` and `_modify`.
I'll prepare an evolution proposal for this feature which should allow
us to remove the underscores or, y'know, rename them to `purple` and
`lettuce`.

`_read` accessors do not make any effort yet to avoid copying the
value being yielded.  I'll work on it in follow-up patches.

Opaque accesses to properties and subscripts defined with `_modify`
accessors will use an inefficient `materializeForSet` pattern that
materializes the value to a temporary instead of accessing it in-place.
That will be fixed by migrating to `modify` over `materializeForSet`,
which is next up after the `read` optimizations.

SIL ownership verification doesn't pass yet for the test cases here
because of a general fault in SILGen where borrows can outlive their
borrowed value due to being cleaned up on the general cleanup stack
when the borrowed value is cleaned up on the formal-access stack.
Michael, Andy, and I discussed various ways to fix this, but it seems
clear to me that it's not in any way specific to coroutine accesses.

rdar://35399664
2018-07-23 18:59:58 -04:00

161 lines
5.4 KiB
C++

%{
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:
case tok::kw_yield:
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;
}