diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index d3d2eccd4f2..8a7dad836f0 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -17,6 +17,7 @@ #ifndef SWIFT_DECL_H #define SWIFT_DECL_H +#include "swift/AST/Attr.h" #include "swift/AST/DeclContext.h" #include "swift/AST/Identifier.h" #include "swift/AST/Type.h" @@ -1555,7 +1556,152 @@ public: using DeclContext::operator new; }; + +/// Abstract base class of operator declarations. +class OperatorDecl : public Decl { + SourceLoc OperatorLoc, NameLoc, LBraceLoc, RBraceLoc; + + Identifier name; +public: + OperatorDecl(DeclKind kind, + DeclContext *DC, + SourceLoc OperatorLoc, + Identifier Name, + SourceLoc NameLoc, + SourceLoc LBraceLoc, + SourceLoc RBraceLoc) + : Decl(kind, DC), + OperatorLoc(OperatorLoc), NameLoc(NameLoc), + LBraceLoc(LBraceLoc), RBraceLoc(RBraceLoc) {} + + SourceLoc getLoc() const { return NameLoc; } + SourceRange getSourceRange() const { return {OperatorLoc, RBraceLoc}; } + + SourceLoc getOperatorLoc() const { return OperatorLoc; } + SourceLoc getLBraceLoc() const { return LBraceLoc; } + SourceLoc getRBraceLoc() const { return RBraceLoc; } + Identifier getName() const { return name; } + + static bool classof(const Decl *D) { + return D->getKind() >= DeclKind::First_OperatorDecl + && D->getKind() <= DeclKind::Last_OperatorDecl; + } +}; + +/// Declares the behavior of an infix operator. For example: +/// +/// \code +/// operator infix /+/ { +/// associativity left +/// precedence 123 +/// } +/// \endcode +class InfixOperatorDecl : public OperatorDecl { + SourceLoc InfixLoc, + AssociativityLoc, AssociativityValueLoc, + PrecedenceLoc, PrecedenceValueLoc; + + InfixData infixData; +public: + InfixOperatorDecl(DeclContext *DC, + SourceLoc OperatorLoc, + SourceLoc InfixLoc, + Identifier Name, + SourceLoc NameLoc, + SourceLoc LBraceLoc, + SourceLoc AssociativityLoc, + SourceLoc AssociativityValueLoc, + SourceLoc PrecedenceLoc, + SourceLoc PrecedenceValueLoc, + SourceLoc RBraceLoc, + InfixData InfixData) + : OperatorDecl(DeclKind::InfixOperator, DC, + OperatorLoc, + Name, + NameLoc, + LBraceLoc, + RBraceLoc), + InfixLoc(InfixLoc), + AssociativityLoc(AssociativityLoc), + AssociativityValueLoc(AssociativityValueLoc), + PrecedenceLoc(PrecedenceLoc), + PrecedenceValueLoc(PrecedenceValueLoc), + infixData(InfixData) {} + + SourceLoc getInfixLoc() const { return InfixLoc; } + SourceLoc getAssociativityLoc() const { return AssociativityLoc; } + SourceLoc getAssociativityValueLoc() const { return AssociativityValueLoc; } + SourceLoc getPrecedenceLoc() const { return PrecedenceLoc; } + SourceLoc getPrecedenceValueLoc() const { return PrecedenceValueLoc; } + + InfixData getInfixData() const { return infixData; } + + static bool classof(const Decl *D) { + return D->getKind() == DeclKind::InfixOperator; + } +}; + +/// Declares the behavior of a prefix operator. For example: +/// +/// \code +/// operator prefix /+/ {} +/// \endcode +class PrefixOperatorDecl : public OperatorDecl { + SourceLoc PrefixLoc; +public: + PrefixOperatorDecl(DeclContext *DC, + SourceLoc OperatorLoc, + SourceLoc PrefixLoc, + Identifier Name, + SourceLoc NameLoc, + SourceLoc LBraceLoc, + SourceLoc RBraceLoc) + : OperatorDecl(DeclKind::InfixOperator, DC, + OperatorLoc, + Name, + NameLoc, + LBraceLoc, + RBraceLoc), + PrefixLoc(PrefixLoc) {} + + SourceLoc getPrefixLoc() const { return PrefixLoc; } + + static bool classof(const Decl *D) { + return D->getKind() == DeclKind::PrefixOperator; + } +}; + +/// Declares the behavior of a postfix operator. For example: +/// +/// \code +/// operator postfix /+/ {} +/// \endcode +class PostfixOperatorDecl : public OperatorDecl { + SourceLoc PostfixLoc; +public: + PostfixOperatorDecl(DeclContext *DC, + SourceLoc OperatorLoc, + SourceLoc PostfixLoc, + Identifier Name, + SourceLoc NameLoc, + SourceLoc LBraceLoc, + SourceLoc RBraceLoc) + : OperatorDecl(DeclKind::InfixOperator, DC, + OperatorLoc, + Name, + NameLoc, + LBraceLoc, + RBraceLoc), + PostfixLoc(PostfixLoc) {} + + SourceLoc getPostfixLoc() const { return PostfixLoc; } + + static bool classof(const Decl *D) { + return D->getKind() == DeclKind::PostfixOperator; + } +}; + inline void GenericParam::setDeclContext(DeclContext *DC) { TypeParam->setDeclContext(DC); } diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index c1f2ce489ab..6730913ce8d 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -147,7 +147,7 @@ public: void *operator new(size_t Bytes, ASTContext &C, unsigned Alignment = alignof(DeclContext)); }; - + } // end namespace swift #endif diff --git a/include/swift/AST/DeclNodes.def b/include/swift/AST/DeclNodes.def index 1266c3cfee8..62891880e02 100644 --- a/include/swift/AST/DeclNodes.def +++ b/include/swift/AST/DeclNodes.def @@ -38,6 +38,13 @@ #define VALUE_DECL(Id, Parent) DECL(Id, Parent) #endif +/// OPERATOR_DECL(Id, Parent) +/// Used for subclasses of OperatorDecl. The default behavior is to do +/// the same as for Decl. +#ifndef OPERATOR_DECL +#define OPERATOR_DECL(Id, Parent) DECL(Id, Parent) +#endif + /// NOMINAL_TYPE_DECL(Id, Parent) /// Used for subclasses of NominalTypeDecl. The default behavior is /// to do the same as for ValueDecl. @@ -55,6 +62,13 @@ DECL(Import, Decl) DECL(Extension, Decl) DECL(PatternBinding, Decl) DECL(TopLevelCode, Decl) + +ABSTRACT_DECL(Operator, Decl) + OPERATOR_DECL(InfixOperator, Decl) + OPERATOR_DECL(PrefixOperator, Decl) + OPERATOR_DECL(PostfixOperator, Decl) + DECL_RANGE(Operator, InfixOperator, PostfixOperator) + ABSTRACT_DECL(Value, Decl) ABSTRACT_DECL(Type, Decl) VALUE_DECL(TypeAlias, TypeDecl) diff --git a/include/swift/AST/Diagnostics.def b/include/swift/AST/Diagnostics.def index 9eec7e78ea7..709c8e606e8 100644 --- a/include/swift/AST/Diagnostics.def +++ b/include/swift/AST/Diagnostics.def @@ -286,6 +286,32 @@ ERROR(destructor_decl_outside_class,decl_parsing,none, ERROR(expected_lbrace_destructor,decl_parsing,none, "expected '{' for destructor", ()) +// Operator +ERROR(operator_decl_inner_scope,decl_parsing,none, + "'operator' may only be declared at file scope", ()) +ERROR(expected_operator_name_after_operator,decl_parsing,none, + "expected operator name after fixity in 'operator' declaration", ()) +ERROR(expected_lbrace_after_operator,decl_parsing,none, + "expected '{' after operator name in 'operator' declaration", ()) +ERROR(expected_operator_attribute,decl_parsing,none, + "expected operator attribute identifier in 'operator' declaration body", ()) +ERROR(unknown_prefix_operator_attribute,decl_parsing,none, + "'%0' is not a valid prefix operator attribute", (StringRef)) +ERROR(unknown_postfix_operator_attribute,decl_parsing,none, + "'%0' is not a valid postfix operator attribute", (StringRef)) +ERROR(unknown_infix_operator_attribute,decl_parsing,none, + "'%0' is not a valid infix operator attribute", (StringRef)) +ERROR(operator_associativity_redeclared,decl_parsing,none, + "'associativity' for infix operator declared multiple times", ()) +ERROR(expected_infix_operator_associativity,decl_parsing,none, + "expected identifier after 'associativity' in 'operator' declaration body", ()) +ERROR(unknown_infix_operator_associativity,decl_parsing,none, + "'%0' is not a valid infix operator associativity; must be 'none', 'left', or 'right'", (StringRef)) +ERROR(operator_precedence_redeclared,decl_parsing,none, + "'precedence' for infix operator declared multiple times", ()) +ERROR(expected_infix_operator_precedence,decl_parsing,none, + "expected integer literal after 'precedence' in 'operator' declaration body", ()) + //------------------------------------------------------------------------------ // Type parsing diagnostics diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 6c9391b2b3a..4e2bce90921 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -566,6 +566,45 @@ void PrintAST::visitDestructorDecl(DestructorDecl *decl) { visit(decl->getBody()); } +void PrintAST::visitInfixOperatorDecl(InfixOperatorDecl *decl) { + recordDeclLoc(decl); + OS << "operator infix " << decl->getName() << "{\n"; + { + IndentRAII indentMore(*this); + if (decl->getAssociativityLoc().isValid()) { + indent(); + OS << "associativity "; + switch (decl->getInfixData().getAssociativity()) { + case Associativity::None: + OS << "none\n"; + break; + case Associativity::Left: + OS << "left\n"; + break; + case Associativity::Right: + OS << "right\n"; + break; + } + } + if (decl->getPrecedenceLoc().isValid()) { + indent(); + OS << "precedence " << decl->getInfixData().getPrecedence() << '\n'; + } + } + indent(); + OS << "}"; +} + +void PrintAST::visitPrefixOperatorDecl(PrefixOperatorDecl *decl) { + recordDeclLoc(decl); + OS << "operator prefix " << decl->getName() << "{\n}"; +} + +void PrintAST::visitPostfixOperatorDecl(PostfixOperatorDecl *decl) { + recordDeclLoc(decl); + OS << "operator postfix " << decl->getName() << "{\n}"; +} + void PrintAST::visitAssignStmt(AssignStmt *stmt) { // FIXME: lhs OS << " = "; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 8dcf4d8fd7c..3febb51bd71 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -345,6 +345,9 @@ bool ValueDecl::isDefinition() const { case DeclKind::TopLevelCode: case DeclKind::Constructor: case DeclKind::Destructor: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: llvm_unreachable("non-value decls shouldn't get here"); case DeclKind::Func: @@ -371,6 +374,9 @@ bool ValueDecl::isInstanceMember() const { case DeclKind::Extension: case DeclKind::PatternBinding: case DeclKind::TopLevelCode: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: llvm_unreachable("Not a ValueDecl"); case DeclKind::Class: diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 1e40bb83356..0887fe039e0 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -731,6 +731,9 @@ void IRGenModule::emitClassDecl(ClassDecl *D) { case DeclKind::Protocol: case DeclKind::OneOfElement: case DeclKind::Extension: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: llvm_unreachable("decl not allowed in class!"); // We can have meaningful initializers for variables, but diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 3175d6415cb..dc3e038ff27 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -784,6 +784,12 @@ void IRGenFunction::emitGlobalDecl(Decl *D) { return emitIgnored(Body.get()); return emitStmt(Body.get()); } + + // Operator decls aren't needed for IRGen. + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: + return; } llvm_unreachable("bad decl kind!"); @@ -803,6 +809,9 @@ void IRGenFunction::emitExternalDefinition(Decl *D) { case DeclKind::Import: case DeclKind::Subscript: case DeclKind::Destructor: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: llvm_unreachable("Not a valid external definition for IRgen"); case DeclKind::Func: @@ -1434,6 +1443,9 @@ void IRGenModule::emitExtension(ExtensionDecl *ext) { case DeclKind::Protocol: case DeclKind::Extension: case DeclKind::Destructor: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: llvm_unreachable("decl not allowed in extension!"); // PatternBindingDecls don't really make sense here, but we @@ -1507,6 +1519,9 @@ void IRGenFunction::emitLocal(Decl *D) { case DeclKind::OneOfElement: case DeclKind::Constructor: case DeclKind::Destructor: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: llvm_unreachable("declaration cannot appear in local scope"); case DeclKind::OneOf: diff --git a/lib/IRGen/GenOneOf.cpp b/lib/IRGen/GenOneOf.cpp index 3d2387025e2..936eafb23a5 100644 --- a/lib/IRGen/GenOneOf.cpp +++ b/lib/IRGen/GenOneOf.cpp @@ -512,6 +512,9 @@ void IRGenModule::emitOneOfDecl(OneOfDecl *oneof) { case DeclKind::Protocol: case DeclKind::Extension: case DeclKind::Destructor: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: llvm_unreachable("decl not allowed in struct!"); // We can't have meaningful initializers for variables; these just show diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 30c12e09f45..b52c80a4236 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -595,6 +595,9 @@ namespace { case DeclKind::OneOfElement: case DeclKind::Constructor: case DeclKind::Destructor: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: llvm_unreachable("declaration not legal as a protocol member"); case DeclKind::Func: diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index eba0ba39c7f..874a1fb9016 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -232,6 +232,9 @@ void IRGenModule::emitStructDecl(StructDecl *st) { case DeclKind::Extension: case DeclKind::Destructor: case DeclKind::OneOfElement: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: llvm_unreachable("decl not allowed in struct!"); // We can have meaningful initializers for variables, but diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 6620fa348f7..810c1bc2689 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -257,6 +257,9 @@ void IRGenSILFunction::emitLocalDecls(BraceStmt *body) { case DeclKind::OneOfElement: case DeclKind::Constructor: case DeclKind::Destructor: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: llvm_unreachable("declaration cannot appear in local scope"); case DeclKind::TypeAlias: diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index fd8342dce02..7b9d6018185 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -357,6 +357,13 @@ bool Parser::parseAttributeListPresent(DeclAttributes &Attributes) { return HadError; } +bool Parser::isStartOfOperatorDecl(const Token &Tok, const Token &Tok2) { + return Tok.isContextualKeyword("operator") + && (Tok2.isContextualKeyword("prefix") + || Tok2.isContextualKeyword("postfix") + || Tok2.isContextualKeyword("infix")); +} + /// parseDecl - Parse a single syntactic declaration and return a list of decl /// ASTs. This can return multiple results for var decls that bind to multiple /// values, structs that define a struct decl and a constructor, etc. @@ -371,15 +378,11 @@ bool Parser::parseAttributeListPresent(DeclAttributes &Attributes) { /// decl-oneof /// decl-struct /// decl-import +/// decl-operator /// bool Parser::parseDecl(SmallVectorImpl &Entries, unsigned Flags) { bool HadParseError = false; switch (Tok.getKind()) { - default: - ParseError: - diagnose(Tok, diag::expected_decl); - HadParseError = true; - break; case tok::semi: // FIXME: Add a fixit to remove the semicolon. diagnose(Tok, diag::disallowed_semi); @@ -416,6 +419,7 @@ bool Parser::parseDecl(SmallVectorImpl &Entries, unsigned Flags) { case tok::kw_protocol: Entries.push_back(parseDeclProtocol(Flags)); break; + case tok::kw_static: if (peekToken().isNot(tok::kw_func)) goto ParseError; @@ -423,11 +427,24 @@ bool Parser::parseDecl(SmallVectorImpl &Entries, unsigned Flags) { case tok::kw_func: Entries.push_back(parseDeclFunc(Flags)); break; + case tok::kw_subscript: HadParseError = parseDeclSubscript(Flags & PD_HasContainerType, !(Flags & PD_DisallowFuncDef), Entries); break; + + case tok::identifier: + if (isStartOfOperatorDecl(Tok, peekToken())) { + Entries.push_back(parseDeclOperator(Flags & PD_AllowTopLevel)); + break; + } + [[clang::fallthrough]]; + default: + ParseError: + diagnose(Tok, diag::expected_decl); + HadParseError = true; + break; } if (!HadParseError && Tok.is(tok::semi)) @@ -503,7 +520,6 @@ bool Parser::parseInheritance(SmallVectorImpl &Inherited) { return false; } - /// parseDeclExtension - Parse an 'extension' declaration. /// extension: /// 'extension' type-identifier inheritance? '{' decl* '}' @@ -1836,3 +1852,196 @@ DestructorDecl *Parser::parseDeclDestructor(unsigned Flags) { return DD; } + +OperatorDecl *Parser::parseDeclOperator(bool AllowTopLevel) { + assert(Tok.isContextualKeyword("operator") && + "no 'operator' at start of operator decl?!"); + + + SourceLoc OperatorLoc = consumeToken(tok::identifier); + + auto kind = llvm::StringSwitch>(Tok.getText()) + .Case("prefix", DeclKind::PrefixOperator) + .Case("postfix", DeclKind::PostfixOperator) + .Case("infix", DeclKind::InfixOperator) + .Default(Nothing); + + assert(kind && "no fixity after 'operator'?!"); + + SourceLoc KindLoc = consumeToken(tok::identifier); + + if (!Tok.isAnyOperator()) { + diagnose(Tok, diag::expected_operator_name_after_operator); + return nullptr; + } + + Identifier Name = Context.getIdentifier(Tok.getText()); + SourceLoc NameLoc = consumeToken(); + + if (!Tok.is(tok::l_brace)) { + diagnose(Tok, diag::expected_lbrace_after_operator); + return nullptr; + } + + OperatorDecl *result; + + switch (*kind) { + case DeclKind::PrefixOperator: + result = parseDeclPrefixOperator(OperatorLoc, KindLoc, Name, NameLoc); + break; + case DeclKind::PostfixOperator: + result = parseDeclPostfixOperator(OperatorLoc, KindLoc, Name, NameLoc); + break; + case DeclKind::InfixOperator: + result = parseDeclInfixOperator(OperatorLoc, KindLoc, Name, NameLoc); + break; + default: + llvm_unreachable("impossible"); + } + + if (Tok.is(tok::r_brace)) + consumeToken(); + + if (!AllowTopLevel) { + diagnose(OperatorLoc, diag::operator_decl_inner_scope); + return nullptr; + } + + return result; +} + +OperatorDecl *Parser::parseDeclPrefixOperator(SourceLoc OperatorLoc, + SourceLoc PrefixLoc, + Identifier Name, + SourceLoc NameLoc) { + SourceLoc LBraceLoc = consumeToken(tok::l_brace); + + while (!Tok.is(tok::r_brace)) { + // Currently there are no operator attributes for prefix operators. + if (Tok.is(tok::identifier)) + diagnose(Tok, diag::unknown_prefix_operator_attribute, Tok.getText()); + else + diagnose(Tok, diag::expected_operator_attribute); + skipUntilDeclRBrace(); + return nullptr; + } + + SourceLoc RBraceLoc = Tok.getLoc(); + + return new (Context) PrefixOperatorDecl(CurDeclContext, + OperatorLoc, + PrefixLoc, + Name, NameLoc, + LBraceLoc, RBraceLoc); +} + +OperatorDecl *Parser::parseDeclPostfixOperator(SourceLoc OperatorLoc, + SourceLoc PostfixLoc, + Identifier Name, + SourceLoc NameLoc) { + SourceLoc LBraceLoc = consumeToken(tok::l_brace); + + while (!Tok.is(tok::r_brace)) { + // Currently there are no operator attributes for postfix operators. + if (Tok.is(tok::identifier)) + diagnose(Tok, diag::unknown_postfix_operator_attribute, Tok.getText()); + else + diagnose(Tok, diag::expected_operator_attribute); + skipUntilDeclRBrace(); + return nullptr; + } + + SourceLoc RBraceLoc = Tok.getLoc(); + + return new (Context) PostfixOperatorDecl(CurDeclContext, + OperatorLoc, + PostfixLoc, + Name, NameLoc, + LBraceLoc, RBraceLoc); +} + +OperatorDecl *Parser::parseDeclInfixOperator(SourceLoc OperatorLoc, + SourceLoc InfixLoc, + Identifier Name, + SourceLoc NameLoc) { + SourceLoc LBraceLoc = consumeToken(tok::l_brace); + + // Initialize InfixData with default attributes: + // precedence 100, associativity none + unsigned precedence = 100; + Associativity associativity = Associativity::None; + + SourceLoc AssociativityLoc, AssociativityValueLoc, + PrecedenceLoc, PrecedenceValueLoc; + + while (!Tok.is(tok::r_brace)) { + if (!Tok.is(tok::identifier)) { + diagnose(Tok, diag::expected_operator_attribute); + skipUntilDeclRBrace(); + return nullptr; + } + + if (Tok.getText().equals("associativity")) { + if (AssociativityLoc.isValid()) { + diagnose(Tok, diag::operator_associativity_redeclared); + skipUntilDeclRBrace(); + return nullptr; + } + AssociativityLoc = consumeToken(); + if (!Tok.is(tok::identifier)) { + diagnose(Tok, diag::expected_infix_operator_associativity); + skipUntilDeclRBrace(); + return nullptr; + } + auto parsedAssociativity + = llvm::StringSwitch>(Tok.getText()) + .Case("none", Associativity::None) + .Case("left", Associativity::Left) + .Case("right", Associativity::Right) + .Default(Nothing); + if (!parsedAssociativity) { + diagnose(Tok, diag::unknown_infix_operator_associativity, Tok.getText()); + skipUntilDeclRBrace(); + return nullptr; + } + associativity = *parsedAssociativity; + + AssociativityValueLoc = consumeToken(); + continue; + } + + if (Tok.getText().equals("precedence")) { + if (PrecedenceLoc.isValid()) { + diagnose(Tok, diag::operator_precedence_redeclared); + skipUntilDeclRBrace(); + return nullptr; + } + PrecedenceLoc = consumeToken(); + if (!Tok.is(tok::integer_literal)) { + diagnose(Tok, diag::expected_infix_operator_precedence); + skipUntilDeclRBrace(); + return nullptr; + } + bool error = Tok.getText().getAsInteger(0, precedence); + assert(!error && "integer literal precedence did not parse as integer?!"); + + PrecedenceValueLoc = consumeToken(); + continue; + } + + diagnose(Tok, diag::unknown_infix_operator_attribute, Tok.getText()); + skipUntilDeclRBrace(); + return nullptr; + } + + SourceLoc RBraceLoc = Tok.getLoc(); + + return new (Context) InfixOperatorDecl(CurDeclContext, + OperatorLoc, InfixLoc, + Name, NameLoc, + LBraceLoc, + AssociativityLoc, AssociativityValueLoc, + PrecedenceLoc, PrecedenceValueLoc, + RBraceLoc, + InfixData(precedence, associativity)); +} diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 69e318bac05..a0d91a33ecb 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -81,7 +81,7 @@ bool Parser::isStartOfDecl(const Token &Tok, const Token &Tok2) { case tok::kw_protocol: return !(Tok2.isAnyOperator() && Tok2.getText().equals("<")); default: - return false; + return isStartOfOperatorDecl(Tok, Tok2); } } diff --git a/lib/Parse/Parser.h b/lib/Parse/Parser.h index 237bc48a4eb..cde0bb57b44 100644 --- a/lib/Parse/Parser.h +++ b/lib/Parse/Parser.h @@ -238,6 +238,7 @@ public: //===--------------------------------------------------------------------===// // Decl Parsing static bool isStartOfDecl(const Token &Tok, const Token &Tok2); + static bool isStartOfOperatorDecl(const Token &Tok, const Token &Tok2); void parseTranslationUnit(TranslationUnit *TU); bool parseDecl(SmallVectorImpl &Entries, unsigned Flags); @@ -292,6 +293,20 @@ public: ConstructorDecl *parseDeclConstructor(bool HasContainerType); DestructorDecl *parseDeclDestructor(unsigned Flags); + + OperatorDecl *parseDeclOperator(bool AllowTopLevel); + OperatorDecl *parseDeclPrefixOperator(SourceLoc OperatorLoc, + SourceLoc PrefixLoc, + Identifier Name, + SourceLoc NameLoc); + OperatorDecl *parseDeclPostfixOperator(SourceLoc OperatorLoc, + SourceLoc PostfixLoc, + Identifier Name, + SourceLoc NameLoc); + OperatorDecl *parseDeclInfixOperator(SourceLoc OperatorLoc, + SourceLoc InfixLoc, + Identifier Name, + SourceLoc NameLoc); //===--------------------------------------------------------------------===// // Type Parsing diff --git a/lib/SIL/SILGen/SILGenDecl.cpp b/lib/SIL/SILGen/SILGenDecl.cpp index 406e408b654..ce9d4996651 100644 --- a/lib/SIL/SILGen/SILGenDecl.cpp +++ b/lib/SIL/SILGen/SILGenDecl.cpp @@ -725,6 +725,9 @@ void SILGenModule::emitExternalDefinition(Decl *d) { case DeclKind::Import: case DeclKind::Subscript: case DeclKind::Destructor: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: llvm_unreachable("Not a valid external definition for SILGen"); } } diff --git a/test/Parse/operator_decl.swift b/test/Parse/operator_decl.swift new file mode 100644 index 00000000000..91046c92ba5 --- /dev/null +++ b/test/Parse/operator_decl.swift @@ -0,0 +1,61 @@ +// RUN: %swift -parse -verify %s + +operator prefix +++ {} +operator postfix +++ {} +operator infix +++ {} +operator infix +++= { + associativity right +} +operator infix *** { + precedence 123 +} +operator infix --- { + precedence 123 + associativity left +} +operator infix >>> { + precedence 123 + associativity right +} +operator infix &&& { + associativity none + precedence 123 +} + + +operator prefix %%% { + associativity none // expected-error{{'associativity' is not a valid prefix operator attribute}} +} +operator postfix %%% { + associativity none // expected-error{{'associativity' is not a valid postfix operator attribute}} +} + +operator infix !!! { + associativity none + associativity left // expected-error{{'associativity' for infix operator declared multiple times}} +} + +operator infix ^^^ { + precedence 22 + precedence 44 // expected-error{{'precedence' for infix operator declared multiple times}} +} + +operator infix === { + associativity free // expected-error{{'free' is not a valid infix operator associativity}} +} + +operator infix !== { + associativity 123 // expected-error{{expected identifier after 'associativity' in 'operator' declaration body}} +} + +operator infix !!= { + precedence blah // expected-error{{expected integer literal after 'precedence' in 'operator' declaration body}} +} + +operator infix !<> { + runcibility 12 // expected-error{{'runcibility' is not a valid infix operator attribute}} +} + +class Foo { + operator infix ||| {} // expected-error{{'operator' may only be declared at file scope}} +}