Skip to content

[Syntax] Parse: add support for TupleType and FunctionType #13412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions include/swift/Syntax/SyntaxBuilders.h.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,12 @@ class ${node.name}Builder {

public:
% for child in node.children:
${node.name}Builder &use${child.name}(${child.type_name} ${child.name});
% child_node = NODE_MAP.get(child.syntax_kind)
% if child_node and child_node.is_syntax_collection():
% child_elt = child_node.collection_element_name
% child_elt_type = child_node.collection_element_type
${node.name}Builder &add${child_elt}(${child_elt_type} ${child_elt});
% else:
${node.name}Builder &use${child.name}(${child.type_name} ${child.name});
% end
% end

Expand Down
41 changes: 32 additions & 9 deletions lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
diag::rethrowing_function_type : diag::throw_in_function_type;
diagnose(Tok.getLoc(), DiagID)
.fixItReplace(Tok.getLoc(), "throws");
if (Tok.is(tok::kw_throw))
Tok.setKind(tok::kw_throws);
}
throwsLoc = consumeToken();
}
Expand All @@ -440,6 +442,27 @@ ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
return makeParserCodeCompletionResult<TypeRepr>();
if (SecondHalf.isNull())
return nullptr;

if (SyntaxContext->isEnabled()) {
FunctionTypeSyntaxBuilder Builder;
Builder.useReturnType(SyntaxContext->popIf<TypeSyntax>().getValue());
Builder.useArrow(SyntaxContext->popToken());
if (throwsLoc.isValid())
Builder.useThrowsOrRethrowsKeyword(SyntaxContext->popToken());

auto InputNode = SyntaxContext->popIf<TypeSyntax>().getValue();
if (auto TupleTypeNode = InputNode.getAs<TupleTypeSyntax>()) {
// Decompose TupleTypeSyntax and repack into FunctionType.
Builder
.useLeftParen(TupleTypeNode->getLeftParen())
.useArguments(TupleTypeNode->getElements())
.useRightParen(TupleTypeNode->getRightParen());
} else {
Builder
.addTupleTypeElement(SyntaxFactory::makeTupleTypeElement(InputNode));
}
SyntaxContext->addSyntax(Builder.build());
}
tyR = new (Context) FunctionTypeRepr(generics, tyR, throwsLoc, arrowLoc,
SecondHalf.get());
} else if (generics) {
Expand Down Expand Up @@ -719,7 +742,6 @@ Parser::parseAnyType() {
/// type-identifier
/// type-composition-list-deprecated ',' type-identifier
ParserResult<TypeRepr> Parser::parseOldStyleProtocolComposition() {
SyntaxParsingContext TypeContext(SyntaxContext, SyntaxContextKind::Type);
assert(Tok.is(tok::kw_protocol) && startsWithLess(peekToken()));

// Start a context for creating type syntax.
Expand Down Expand Up @@ -829,7 +851,7 @@ ParserResult<TypeRepr> Parser::parseOldStyleProtocolComposition() {
/// identifier ':' type
/// type
ParserResult<TupleTypeRepr> Parser::parseTypeTupleBody() {
SyntaxParsingContext TypeContext(SyntaxContext, SyntaxContextKind::Type);
SyntaxParsingContext TypeContext(SyntaxContext, SyntaxKind::TupleType);
Parser::StructureMarkerRAII ParsingTypeTuple(*this, Tok);
SourceLoc RPLoc, LPLoc = consumeToken(tok::l_paren);
SourceLoc EllipsisLoc;
Expand All @@ -839,7 +861,7 @@ ParserResult<TupleTypeRepr> Parser::parseTypeTupleBody() {
ParserStatus Status = parseList(tok::r_paren, LPLoc, RPLoc,
/*AllowSepAfterLast=*/false,
diag::expected_rparen_tuple_type_list,
SyntaxKind::Unknown,
SyntaxKind::TupleTypeElementList,
[&] () -> ParserStatus {
TupleTypeReprElement element;

Expand Down Expand Up @@ -877,8 +899,9 @@ ParserResult<TupleTypeRepr> Parser::parseTypeTupleBody() {
// Consume the ':'.
if (!consumeIf(tok::colon, element.ColonLoc))
diagnose(Tok, diag::expected_parameter_colon);

} else if (Backtracking) {
// If we don't have labels, 'inout' is not a deprecated use.
// If we don't have labels, 'inout' is not a obsoleted use.
ObsoletedInOutLoc = SourceLoc();
}
Backtracking.reset();
Expand Down Expand Up @@ -925,6 +948,7 @@ ParserResult<TupleTypeRepr> Parser::parseTypeTupleBody() {
// Parse '= expr' here so we can complain about it directly, rather
// than dying when we see it.
if (Tok.is(tok::equal)) {
SyntaxParsingContext InitContext(SyntaxContext, SyntaxKind::Initializer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are using Initializer, can we refactor the part in FunctionParameter to initializer too? they are now equal+expr.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing. I'll do that in follow up PR 👍

SourceLoc equalLoc = consumeToken(tok::equal);
auto init = parseExpr(diag::expected_init_value);
auto inFlight = diagnose(equalLoc, diag::tuple_type_init);
Expand All @@ -943,12 +967,11 @@ ParserResult<TupleTypeRepr> Parser::parseTypeTupleBody() {
if (EllipsisLoc.isInvalid())
EllipsisIdx = ElementsR.size();

// If there were any labels, figure out which labels should go into the type
// representation.

bool isFunctionType = Tok.isAny(tok::arrow, tok::kw_throws,
tok::kw_rethrows);

// If there were any labels, figure out which labels should go into the type
// representation.
for (auto &element : ElementsR) {
// True tuples have labels.
if (!isFunctionType) {
Expand Down Expand Up @@ -981,11 +1004,11 @@ ParserResult<TupleTypeRepr> Parser::parseTypeTupleBody() {
diag.fixItReplace(SourceRange(element.NameLoc), "_");
}

if (element.NameLoc.isValid() || element.SecondNameLoc.isValid()) {
if (element.SecondNameLoc.isValid()) {
// Form the named parameter type representation.
element.UnderscoreLoc = element.NameLoc;
element.Name = element.SecondName;
element.NameLoc = element.SecondNameLoc;
element.UnderscoreLoc = element.NameLoc;
}
}

Expand Down
3 changes: 3 additions & 0 deletions lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,8 @@ static SyntaxKind getListElementKind(SyntaxKind ListKind) {
return SyntaxKind::TupleElement;
case SyntaxKind::FunctionParameterList:
return SyntaxKind::FunctionParameter;
case SyntaxKind::TupleTypeElementList:
return SyntaxKind::TupleTypeElement;
default:
return SyntaxKind::Unknown;
}
Expand All @@ -858,6 +860,7 @@ Parser::parseList(tok RightK, SourceLoc LeftLoc, SourceLoc &RightLoc,
SyntaxKind ElementKind = getListElementKind(Kind);

if (Tok.is(RightK)) {
ListContext.reset();
RightLoc = consumeToken(RightK);
return makeParserSuccess();
}
Expand Down
15 changes: 7 additions & 8 deletions lib/Syntax/SyntaxBuilders.cpp.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ using namespace swift::syntax;
% for node in SYNTAX_NODES:
% if node.is_buildable():
% for child in node.children:
${node.name}Builder &
${node.name}Builder::use${child.name}(${child.type_name} ${child.name}) {
Layout[cursorIndex(${node.name}::Cursor::${child.name})] =
${child.name}.getRaw();
return *this;
}
% child_node = NODE_MAP.get(child.syntax_kind)
% if child_node and child_node.is_syntax_collection():
% child_elt = child_node.collection_element_name
Expand All @@ -38,13 +44,6 @@ ${node.name}Builder::add${child_elt}(${child_elt_type} ${child_elt}) {
raw = raw->append(${child_elt}.getRaw());
return *this;
}
% else:
${node.name}Builder &
${node.name}Builder::use${child.name}(${child.type_name} ${child.name}) {
Layout[cursorIndex(${node.name}::Cursor::${child.name})] =
${child.name}.getRaw();
return *this;
}
% end
% end
${node.name}
Expand All @@ -55,4 +54,4 @@ ${node.name}Builder::build() {
}

% end
% end
% end
25 changes: 16 additions & 9 deletions lib/Syntax/SyntaxFactory.cpp.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ SyntaxFactory::getUnknownKind(SyntaxKind Kind) {
% Result = 'SyntaxKind::UnknownDecl'
% elif node.syntax_kind.endswith('Token'):
% Result = 'SyntaxKind::UnknownToken'
% elif node.syntax_kind.endswith('Type'):
% Result = 'SyntaxKind::UnknownType'
% elif node.syntax_kind.endswith('Pattern'):
Copy link
Member Author

@rintaro rintaro Dec 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use isTypeKind(Kind) API et al here (instead of name based heuristics).
E.g. SimpleTypeIdentifier is Type kind.
TODO for follow up PR.

% Result = 'SyntaxKind::UnknownPattern'
% else:
% Result = 'SyntaxKind::Unknown'
% end
Expand Down Expand Up @@ -307,17 +311,20 @@ TupleTypeSyntax SyntaxFactory::makeVoidTupleType() {
makeRightParenToken({}, {}));
}

TupleTypeElementSyntax SyntaxFactory::makeTupleTypeElement(
llvm::Optional<TokenSyntax> Label,
llvm::Optional<TokenSyntax> Colon, TypeSyntax Type,
llvm::Optional<TokenSyntax> TrailingComma) {
auto annotation = makeTypeAnnotation(makeBlankAttributeList(), None, Type);
return makeTupleTypeElement(Label, Colon, annotation, TrailingComma);
TupleTypeElementSyntax
SyntaxFactory::makeTupleTypeElement(llvm::Optional<TokenSyntax> Label,
llvm::Optional<TokenSyntax> Colon,
TypeSyntax Type,
llvm::Optional<TokenSyntax> TrailingComma) {
return makeTupleTypeElement(None, Label, None, Colon, Type, None, None,
TrailingComma);
}

TupleTypeElementSyntax SyntaxFactory::makeTupleTypeElement(TypeSyntax Type,
llvm::Optional<TokenSyntax> TrailingComma) {
return makeTupleTypeElement(None, None, Type, TrailingComma);
TupleTypeElementSyntax
SyntaxFactory::makeTupleTypeElement(TypeSyntax Type,
llvm::Optional<TokenSyntax> TrailingComma) {
return makeTupleTypeElement(None, None, None, None, Type, None, None,
TrailingComma);
}

GenericParameterSyntax
Expand Down
6 changes: 4 additions & 2 deletions test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@ class C {<FunctionDecl>
}

typealias A = <SimpleTypeIdentifier>Any</SimpleTypeIdentifier>
typealias B = (<MemberTypeIdentifier><SimpleTypeIdentifier>Array<GenericArgumentClause><<GenericArgument><SimpleTypeIdentifier>Array<GenericArgumentClause><<GenericArgument><SimpleTypeIdentifier>Any</SimpleTypeIdentifier></GenericArgument>></GenericArgumentClause></SimpleTypeIdentifier></GenericArgument>></GenericArgumentClause></SimpleTypeIdentifier>.Element</MemberTypeIdentifier>)
typealias B = <TupleType>(<TupleTypeElement><MemberTypeIdentifier><SimpleTypeIdentifier>Array<GenericArgumentClause><<GenericArgument><SimpleTypeIdentifier>Array<GenericArgumentClause><<GenericArgument><SimpleTypeIdentifier>Any</SimpleTypeIdentifier></GenericArgument>></GenericArgumentClause></SimpleTypeIdentifier></GenericArgument>></GenericArgumentClause></SimpleTypeIdentifier>.Element</MemberTypeIdentifier>, </TupleTypeElement><TupleTypeElement>x: <SimpleTypeIdentifier>Int</SimpleTypeIdentifier></TupleTypeElement>)</TupleType>
typealias C = <ArrayType>[<SimpleTypeIdentifier>Int</SimpleTypeIdentifier>]</ArrayType>
typealias D = <DictionaryType>[<SimpleTypeIdentifier>Int</SimpleTypeIdentifier>: <SimpleTypeIdentifier>String</SimpleTypeIdentifier>]</DictionaryType>
typealias E = <MetatypeType><OptionalType><SimpleTypeIdentifier>Int</SimpleTypeIdentifier>?</OptionalType>.Protocol</MetatypeType>
typealias F = <MetatypeType><ImplicitlyUnwrappedOptionalType><ArrayType>[<SimpleTypeIdentifier>Int</SimpleTypeIdentifier>]</ArrayType>!</ImplicitlyUnwrappedOptionalType>.Type</MetatypeType><StructDecl>
typealias F = <MetatypeType><ImplicitlyUnwrappedOptionalType><ArrayType>[<SimpleTypeIdentifier>Int</SimpleTypeIdentifier>]</ArrayType>!</ImplicitlyUnwrappedOptionalType>.Type</MetatypeType>
typealias G = <FunctionType>(<TupleTypeElement>a x: <SimpleTypeIdentifier>Int</SimpleTypeIdentifier>, </TupleTypeElement><TupleTypeElement>_ y: <SimpleTypeIdentifier>Int </SimpleTypeIdentifier>... <Initializer>= <IntegerLiteralExpr>1</IntegerLiteralExpr></Initializer></TupleTypeElement>) throw -> <FunctionType>() -> <TupleType>()</TupleType></FunctionType></FunctionType>
typealias H = <FunctionType>() rethrows -> <TupleType>()</TupleType></FunctionType><StructDecl>

struct foo <MemberDeclBlock>{<StructDecl>
struct foo <MemberDeclBlock>{<StructDecl>
Expand Down
4 changes: 3 additions & 1 deletion test/Syntax/round_trip_parse_gen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@ class C {
}

typealias A = Any
typealias B = (Array<Array<Any>>.Element)
typealias B = (Array<Array<Any>>.Element, x: Int)
typealias C = [Int]
typealias D = [Int: String]
typealias E = Int?.Protocol
typealias F = [Int]!.Type
typealias G = (a x: Int, _ y: Int ... = 1) throw -> () -> ()
typealias H = () rethrows -> ()

struct foo {
struct foo {
Expand Down
19 changes: 8 additions & 11 deletions tools/SwiftSyntax/SyntaxFactory.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -120,21 +120,18 @@ public enum SyntaxFactory {
rightParen: makeRightParenToken())
}

public static func makeTupleTypeElement(label: TokenSyntax?,
public static func makeTupleTypeElement(name: TokenSyntax?,
colon: TokenSyntax?, type: TypeSyntax,
comma: TokenSyntax?) -> TupleTypeElementSyntax {
let annotation = makeTypeAnnotation(attributes: makeBlankAttributeList(),
inOutKeyword: nil,
type: type)
return makeTupleTypeElement(label: label, colon: colon,
typeAnnotation: annotation,
comma: comma)
trailingComma: TokenSyntax?) -> TupleTypeElementSyntax {
return makeTupleTypeElement(inOut: nil, name: name, secondName: nil,
colon: colon, type: type, ellipsis: nil,
initializer: nil, trailingComma: trailingComma)
}

public static func makeTupleTypeElement(type: TypeSyntax,
comma: TokenSyntax?) -> TupleTypeElementSyntax {
return makeTupleTypeElement(label: nil, colon: nil,
type: type, comma: comma)
trailingComma: TokenSyntax?) -> TupleTypeElementSyntax {
return makeTupleTypeElement(name: nil, colon: nil,
type: type, trailingComma: trailingComma)
}

public static func makeGenericParameter(name: TokenSyntax,
Expand Down
Loading