diff --git a/shared/cplusplus/AST.cpp b/shared/cplusplus/AST.cpp index d112f9ab537ebd4d7c0264ab8dfc79147a207d8d..11be99ea48a1257371a3a584e5894b9669c55ca1 100644 --- a/shared/cplusplus/AST.cpp +++ b/shared/cplusplus/AST.cpp @@ -3898,6 +3898,8 @@ void IdentifierListAST::accept0(ASTVisitor *visitor) unsigned ObjCClassDeclarationAST::firstToken() const { + if (attributes) + return attributes->firstToken(); return class_token; } @@ -3911,12 +3913,19 @@ unsigned ObjCClassDeclarationAST::lastToken() const return it->identifier_token + 1; } + for (SpecifierAST *it = attributes; it; it = it->next) { + if (! it->next) + return it->lastToken(); + } + return class_token + 1; } ObjCClassDeclarationAST *ObjCClassDeclarationAST::clone(MemoryPool *pool) const { ObjCClassDeclarationAST *ast = new (pool) ObjCClassDeclarationAST; + if (attributes) + ast->attributes = attributes->clone(pool); ast->class_token = class_token; if (identifier_list) ast->identifier_list = identifier_list->clone(pool); @@ -3927,6 +3936,9 @@ ObjCClassDeclarationAST *ObjCClassDeclarationAST::clone(MemoryPool *pool) const void ObjCClassDeclarationAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { + for (SpecifierAST *it = attributes; it; it = it->next) { + accept(it, visitor); + } } } diff --git a/shared/cplusplus/AST.h b/shared/cplusplus/AST.h index d03cd3ff82c6fc44aac09abbc9979ced259ff7bd..6607e76805b8072094d40bc4f43551d34ff57920 100644 --- a/shared/cplusplus/AST.h +++ b/shared/cplusplus/AST.h @@ -1949,6 +1949,7 @@ protected: class CPLUSPLUS_EXPORT ObjCClassDeclarationAST: public DeclarationAST { public: + SpecifierAST *attributes; unsigned class_token; IdentifierListAST *identifier_list; unsigned semicolon_token; diff --git a/shared/cplusplus/Parser.cpp b/shared/cplusplus/Parser.cpp index 8e15a220be538f5406fe351b8a7ae3977eb24904..6911fd4f9c049189110fc077078f9e921a4576aa 100644 --- a/shared/cplusplus/Parser.cpp +++ b/shared/cplusplus/Parser.cpp @@ -403,39 +403,45 @@ bool Parser::parseDeclaration(DeclarationAST *&node) case T_EXPORT: return parseTemplateDeclaration(node); - // objc++ - case T_AT_IMPLEMENTATION: - return parseObjCClassImplementation(node); - + // ObjcC++ case T_AT_CLASS: return parseObjCClassDeclaration(node); case T_AT_INTERFACE: - return parseObjCInterfaceDeclaration(node); + return parseObjCInterface(node); case T_AT_PROTOCOL: - return parseObjCProtocolDeclaration(node); + return parseObjCProtocol(node); case T_AT_END: - return parseObjCEndDeclaration(node); - - case T_AT_COMPATIBILITY_ALIAS: - return parseObjCAliasDeclaration(node); - - case T_AT_SYNTHESIZE: - return parseObjCPropertySynthesize(node); + return parseObjCEnd(node); - case T_AT_DYNAMIC: - return parseObjCPropertyDynamic(node); + default: { + if (_objCEnabled && LA() == T___ATTRIBUTE__) { + const unsigned start = cursor(); + SpecifierAST *attributes = 0, **attr = &attributes; + while (parseAttributeSpecifier(*attr)) + attr = &(*attr)->next; + if (LA() == T_AT_INTERFACE) + return parseObjCInterface(node, attributes); + else if (LA() == T_AT_PROTOCOL) + return parseObjCProtocol(node, attributes); + else if (LA() == T_AT_PROPERTY) + return parseObjCPropertyDeclaration(node, attributes); + rewind(start); + } - default: if (LA() == T_EXTERN && LA(2) == T_TEMPLATE) return parseTemplateDeclaration(node); else if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL) return parseLinkageSpecification(node); else return parseSimpleDeclaration(node); + } break; // default + } // end switch + + return false; } bool Parser::parseLinkageSpecification(DeclarationAST *&node) @@ -2543,16 +2549,7 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node) case T_SLOT: return parseQtMethod(node); - case T_AT_ENCODE: - case T_AT_PROTOCOL: - case T_AT_SELECTOR: - case T_AT_STRING_LITERAL: - return parseObjCExpression(node); - default: { - if (_objCEnabled && LA() == T_LBRACKET) - return parseObjCExpression(node); - unsigned startOfName = cursor(); NameAST *name = 0; if (parseName(name)) { @@ -3303,513 +3300,417 @@ bool Parser::parseThrowExpression(ExpressionAST *&node) return false; } -bool Parser::parseObjCClassImplementation(DeclarationAST *&) +bool Parser::lookAtObjCSelector() const { - if (LA() != T_AT_IMPLEMENTATION) - return false; - - /*unsigned implementation_token = */ consumeToken(); - unsigned identifier_token = 0; - match(T_IDENTIFIER, &identifier_token); + switch (LA()) { + case T_IDENTIFIER: + case T_OR: + case T_AND: + case T_NOT: + case T_XOR: + case T_BITOR: + case T_COMPL: + case T_OR_EQ: + case T_AND_EQ: + case T_BITAND: + case T_NOT_EQ: + case T_XOR_EQ: + return true; - if (LA() == T_COLON) { - /*unsigned colon_token = */ consumeToken(); - unsigned superclass_name_token = 0; - match(T_IDENTIFIER, &superclass_name_token); - } else if (LA() == T_LPAREN) { - /*unsigned lparen_token = */ consumeToken(); - unsigned category_name_token = 0; - if (LA() == T_IDENTIFIER) - category_name_token = consumeToken(); - unsigned rparen_token = 0; - match(T_RPAREN, &rparen_token); - } + default: + if (tok().isKeyword()) + return true; + } // switch - _inObjCImplementationContext = true; - parseObjCMethodDefinitionList(); - return true; + return false; } +// objc-class-declaraton ::= T_AT_CLASS (T_IDENTIFIER @ T_COMMA) T_SEMICOLON +// bool Parser::parseObjCClassDeclaration(DeclarationAST *&node) { if (LA() != T_AT_CLASS) return false; - ObjCClassDeclarationAST *ast = new (_pool) ObjCClassDeclarationAST; - ast->class_token = consumeToken(); - parseObjCIdentifierList(ast->identifier_list); - match(T_SEMICOLON, &ast->semicolon_token); - node = ast; + unsigned objc_class_token = consumeToken(); + unsigned identifier_token = 0; + match(T_IDENTIFIER, &identifier_token); + while (LA() == T_COMMA) { + consumeToken(); // skip T_COMMA + match(T_IDENTIFIER, &identifier_token); + } + + unsigned semicolon_token = 0; + match(T_SEMICOLON, &semicolon_token); return true; } -bool Parser::parseObjCInterfaceDeclaration(DeclarationAST *&) +// objc-interface ::= attribute-specifier-list-opt objc-class-interface +// objc-interface ::= objc-category-interface +// +// objc-class-interface ::= T_AT_INTERFACE T_IDENTIFIER (T_COLON T_IDENTIFIER)? +// objc-protocol-refs-opt +// objc-class-instance-variables-opt +// objc-interface-declaration-list +// T_AT_END +// +// objc-category-interface ::= T_AT_INTERFACE T_IDENTIFIER +// T_LPAREN T_IDENTIFIER? T_RPAREN +// objc-protocol-refs-opt +// objc-interface-declaration-list +// T_AT_END +// +bool Parser::parseObjCInterface(DeclarationAST *&node, + SpecifierAST *attributes) { + if (! attributes && LA() == T___ATTRIBUTE__) { + SpecifierAST **attr = &attributes; + while (parseAttributeSpecifier(*attr)) + attr = &(*attr)->next; + } + if (LA() != T_AT_INTERFACE) return false; - /*unsigned interface_token = */ consumeToken(); - unsigned interface_name_token = 0; - match(T_IDENTIFIER, &interface_name_token); + unsigned objc_interface_token = consumeToken(); + unsigned identifier_token = 0; + match(T_IDENTIFIER, &identifier_token); + if (LA() == T_LPAREN) { - // category interface - /*unsigned lparen_token = */ consumeToken(); - unsigned catagory_name_token = 0; + // a category interface + + if (attributes) + _translationUnit->error(attributes->firstToken(), + "invalid attributes for category interface declaration"); + + unsigned lparen_token = 0, rparen_token = 0; + match(T_LPAREN, &lparen_token); if (LA() == T_IDENTIFIER) - catagory_name_token = consumeToken(); - unsigned rparen_token = 0; + consumeToken(); + match(T_RPAREN, &rparen_token); + parseObjCProtocolRefs(); - parseObjCClassInstanceVariables(); - parseObjCInterfaceDeclList(); - unsigned end_token = 0; - match(T_AT_END, &end_token); - return true; - } else { - // class interface - unsigned colon_token = 0; - unsigned super_class_token = 0; - if (LA() == T_COLON) { - colon_token = consumeToken(); - match(T_IDENTIFIER, &super_class_token); + while (parseObjCInterfaceMemberDeclaration()) { } - parseObjCProtocolRefs(); - parseObjCInterfaceDeclList(); - unsigned end_token = 0; - match(T_AT_END, &end_token); + unsigned objc_end_token = 0; + match(T_AT_END, &objc_end_token); return true; } - return false; -} - -bool Parser::parseObjCProtocolDeclaration(DeclarationAST *&) -{ - return false; -} - -bool Parser::parseObjCEndDeclaration(DeclarationAST *&) -{ - if (LA() != T_AT_END) - return false; - - unsigned end_token = consumeToken(); - if (! _inObjCImplementationContext) { - _translationUnit->warning(end_token, - "@end must appear in an @implementation context"); + // a class interface declaration + if (LA() == T_COLON) { + consumeToken(); + unsigned identifier_token = 0; + match(T_IDENTIFIER, &identifier_token); } - _inObjCImplementationContext = false; + parseObjCProtocolRefs(); + parseObjClassInstanceVariables(); + while (parseObjCInterfaceMemberDeclaration()) { + } + unsigned objc_end_token = 0; + match(T_AT_END, &objc_end_token); return true; } -bool Parser::parseObjCAliasDeclaration(DeclarationAST *&) +// objc-protocol ::= T_AT_PROTOCOL (T_IDENTIFIER @ T_COMMA) T_SEMICOLON +// +bool Parser::parseObjCProtocol(DeclarationAST *&node, + SpecifierAST *attributes) { - return false; -} + if (! attributes && LA() == T___ATTRIBUTE__) { + SpecifierAST **attr = &attributes; + while (parseAttributeSpecifier(*attr)) + attr = &(*attr)->next; + } -bool Parser::parseObjCPropertySynthesize(DeclarationAST *&) -{ - return false; -} + if (LA() != T_AT_PROTOCOL) + return false; -bool Parser::parseObjCPropertyDynamic(DeclarationAST *&) -{ - return false; -} + unsigned objc_protocol_token = consumeToken(); + unsigned identifier_token = 0; + match(T_IDENTIFIER, &identifier_token); + + if (LA() == T_COMMA || LA() == T_SEMICOLON) { + // a protocol forward declaration -bool Parser::parseObjCIdentifierList(IdentifierListAST *&node) -{ - if (LA() == T_IDENTIFIER) { - IdentifierListAST **it = &node; - IdentifierListAST *id = new (_pool) IdentifierListAST; - id->identifier_token = consumeToken(); - *it = id; while (LA() == T_COMMA) { consumeToken(); - if (LA() == T_IDENTIFIER) { - it = &(*it)->next; - IdentifierListAST *id = new (_pool) IdentifierListAST; - id->identifier_token = consumeToken(); - *it = id; - } + match(T_IDENTIFIER, &identifier_token); } + unsigned semicolon_token = 0; + match(T_SEMICOLON, &semicolon_token); return true; } - return false; -} -bool Parser::parseObjCProtocolRefs() -{ - return false; -} + // a protocol definition + parseObjCProtocolRefs(); -bool Parser::parseObjCClassInstanceVariables() -{ - return false; -} - -bool Parser::parseObjCInterfaceDeclList() -{ - unsigned saved = cursor(); - while (LA() != T_AT_END && parseObjCInterfaceMemberDeclaration()) { - if (saved == cursor()) - consumeToken(); // skip a token + while (parseObjCInterfaceMemberDeclaration()) { } - return true; -} - -bool Parser::parseObjCInterfaceMemberDeclaration() -{ - switch (LA()) { - case T_SEMICOLON: - consumeToken(); - return true; - - case T_AT_REQUIRED: - case T_AT_OPTIONAL: - consumeToken(); - return true; - - case T_PLUS: - case T_MINUS: - return parseObjCMethodPrototype(); - - default: { - DeclarationAST *declaration = 0; - if (parseDeclaration(declaration)) - return true; - } // default - } // switch + unsigned objc_end_token = 0; + match(T_AT_END, &objc_end_token); - return false; + return true; } -bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&) -{ - return false; -} -bool Parser::parseObjCMethodPrototype() +// objc-protocol-refs ::= T_LESS (T_IDENTIFIER @ T_COMMA) T_GREATER +// +bool Parser::parseObjCProtocolRefs() { - if (LA() != T_PLUS && LA() != T_MINUS) + if (LA() != T_LESS) return false; - - // instance or class method? - /*unsigned method_type_token = */ consumeToken(); - - SpecifierAST *attributes = 0, **attr = &attributes; - while (parseAttributeSpecifier(*attr)) - attr = &(*attr)->next; - - return false; + unsigned less_token = 0, greater_token = 0; + unsigned identifier_token = 0; + match(T_LESS, &less_token); + match(T_IDENTIFIER, &identifier_token); + while (LA() == T_COMMA) { + consumeToken(); + match(T_IDENTIFIER, &identifier_token); + } + match(T_GREATER, &greater_token); + return true; } -bool Parser::parseObjCExpression(ExpressionAST *&node) +// objc-class-instance-variables ::= T_LBRACE +// objc-instance-variable-decl-list-opt +// T_RBRACE +// +bool Parser::parseObjClassInstanceVariables() { - switch (LA()) { - case T_LBRACKET: - return parseObjCMessageExpression(node); + if (LA() != T_LBRACE) + return false; - case T_AT_STRING_LITERAL: - return parseObjCStringLiteral(node); + unsigned lbrace_token = 0, rbrace_token = 0; - case T_AT_ENCODE: - return parseObjCEncodeExpression(node); + match(T_LBRACE, &lbrace_token); + while (LA()) { + if (LA() == T_RBRACE) + break; - case T_AT_PROTOCOL: - return parseObjCProtocolExpression(node); + const unsigned start = cursor(); - case T_AT_SELECTOR: - return parseObjCSelectorExpression(node); - } - return false; -} + DeclarationAST *declaration = 0; + parseObjCInstanceVariableDeclaration(declaration); -bool Parser::parseObjCMessageExpression(ExpressionAST *&) -{ - if (LA() != T_LBRACKET) - return false; + if (start == cursor()) { + // skip stray token. + _translationUnit->error(cursor(), "skip stray token `%s'", tok().spell()); + consumeToken(); + } + } - /*unsigned lbracket_token = */ consumeToken(); - ExpressionAST *receiver = 0; - parseObjCMessageReceiver(receiver); - parseObjCMessageArguments(); - unsigned rbracket_token = 0; - match(T_RBRACKET, &rbracket_token); + match(T_RBRACE, &rbrace_token); return true; } -bool Parser::parseObjCStringLiteral(ExpressionAST *&) +// objc-interface-declaration ::= T_AT_REQUIRED +// objc-interface-declaration ::= T_AT_OPTIONAL +// objc-interface-declaration ::= T_SEMICOLON +// objc-interface-declaration ::= objc-property-declaration +// objc-interface-declaration ::= objc-method-prototype +bool Parser::parseObjCInterfaceMemberDeclaration() { - if (LA() != T_AT_STRING_LITERAL) - return false; - - do { + switch (LA()) { + case T_AT_REQUIRED: + case T_AT_OPTIONAL: consumeToken(); - } while (LA() == T_AT_STRING_LITERAL); + return true; - return true; -} + case T_SEMICOLON: + consumeToken(); + return true; -bool Parser::parseObjCEncodeExpression(ExpressionAST *&) -{ - if (LA() != T_AT_ENCODE) - return false; + case T_AT_PROPERTY: { + DeclarationAST *declaration = 0; + return parseObjCPropertyDeclaration(declaration); + } - /*unsigned encode_token = */ consumeToken(); - unsigned lparen_token = 0, rparen_token = 0; - match(T_LPAREN, &lparen_token); - SpecifierAST *type_specifier = 0; - parseSimpleTypeSpecifier(type_specifier); - match(T_RPAREN, &rparen_token); - return true; -} + case T_PLUS: + case T_MINUS: + return parseObjCMethodPrototype(); -bool Parser::parseObjCProtocolExpression(ExpressionAST *&) -{ - if (LA() != T_AT_PROTOCOL) + default: return false; - - /*unsigned protocol_token = */ consumeToken(); - unsigned protocol_name_token = 0, lparen_token = 0, rparen_token = 0; - match(T_LPAREN, &lparen_token); - match(T_IDENTIFIER, &protocol_name_token); - match(T_RPAREN, &rparen_token); - return true; + } } -bool Parser::parseObjCSelectorExpression(ExpressionAST *&) +// objc-instance-variable-declaration ::= objc-visibility-specifier +// objc-instance-variable-declaration ::= block-declaration +// +bool Parser::parseObjCInstanceVariableDeclaration(DeclarationAST *&node) { - if (LA() != T_AT_SELECTOR) - return false; + switch (LA()) { + case T_AT_PRIVATE: + case T_AT_PROTECTED: + case T_AT_PUBLIC: + case T_AT_PACKAGE: + consumeToken(); + return true; - /*unsigned selector_token = */ consumeToken(); - unsigned lparen_token = 0, rparen_token = 0; - match(T_LPAREN, &lparen_token); - while (LA(1) == T_IDENTIFIER && LA(2) == T_COLON) { - /*unsigned identifier_token = */ consumeToken(); - /*unsigned colon_token = */ consumeToken(); + default: + return parseBlockDeclaration(node); } - match(T_RPAREN, &rparen_token); - return true; -} - -bool Parser::parseObjCMessageReceiver(ExpressionAST *&node) -{ - // ### expression or simple-type-specifier. - return parseExpression(node); } -bool Parser::parseObjCMessageArguments() +// objc-property-declaration ::= +// T_AT_PROPERTY T_LPAREN (property-attribute @ T_COMMA) T_RPAREN simple-declaration +// +bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&, SpecifierAST *) { - if (LA() != T_IDENTIFIER && LA() != T_COLON) + if (LA() != T_AT_PROPERTY) return false; - unsigned selector_name_token = 0; - - if (LA() == T_IDENTIFIER) - selector_name_token = consumeToken(); - - if (LA() == T_COLON) { - /*unsigned colon_token = */ consumeToken(); - - ExpressionAST *expr = 0; - parseAssignmentExpression(expr); - - while ((LA() == T_IDENTIFIER && LA(2) == T_COLON) || LA() == T_COLON) { - if (LA() == T_IDENTIFIER) - consumeToken(); + unsigned objc_property_token = consumeToken(); - if (LA() == T_COLON) - consumeToken(); - - parseAssignmentExpression(expr); - } - - while (LA() == T_COMMA) { - consumeToken(); - parseAssignmentExpression(expr); + if (LA() == T_LPAREN) { + unsigned lparen_token = 0, rparen_token = 0; + match(T_LPAREN, &lparen_token); + while (parseObjCPropertyAttribute()) { } + match(T_RPAREN, &rparen_token); } + DeclarationAST *simple_declaration = 0; + parseSimpleDeclaration(simple_declaration, /*accept-struct-declarators = */ false); return true; } -bool Parser::parseObjCMethodDefinitionList() +// objc-method-prototype ::= (T_PLUS | T_MINUS) objc-method-decl objc-method-attrs-opt +// +// objc-method-decl ::= objc-type-name? objc-selector +// objc-method-decl ::= objc-type-name? objc-keyword-decl-list objc-parmlist-opt +// +bool Parser::parseObjCMethodPrototype() { - bool done = false; - while (! done) { - switch (LA()) { - case T_EOF_SYMBOL: - case T_AT_END: - done = true; - break; + if (LA() != T_PLUS && LA() != T_MINUS) + return false; - case T_PLUS: - case T_MINUS: - parseObjCMethodSignature(); - if (LA() == T_SEMICOLON) - consumeToken(); - break; + unsigned method_type_token = consumeToken(); - case T_AT_PROPERTY: - parseObjCAtProperty(); - break; - - case T_SEMICOLON: - consumeToken(); - break; + parseObjCTypeName(); - case T_AT_OPTIONAL: - consumeToken(); - break; + if ((lookAtObjCSelector() && LA(2) == T_COLON) || LA() == T_COLON) { + while (parseObjCKeywordDeclaration()) { + } - case T_AT_REQUIRED: + while (LA() == T_COMMA) { consumeToken(); - break; - case T_TEMPLATE: - case T_NAMESPACE: { - DeclarationAST *declaration = 0; - parseDeclaration(declaration); - } break; - - default: { - unsigned start = cursor(); - DeclarationAST *declaration = 0; - if (LA(1) == T_EXTERN && LA(2) == T_STRING_LITERAL) { - parseLinkageSpecification(declaration); - } else if (parseBlockDeclaration(declaration)) { - // ### accept the declaration. - } else { - if (cursor() == start) { - _translationUnit->error(cursor(), - "stray `%s' between Objective-C++ methods", - tok().spell()); - consumeToken(); - } + if (LA() == T_DOT_DOT_DOT) { + consumeToken(); + break; } - } break; // default - } // switch + DeclarationAST *parameter_declaration = 0; + parseParameterDeclaration(parameter_declaration); + } + } else if (lookAtObjCSelector()) { + parseObjCSelector(); + } else { + _translationUnit->error(cursor(), "expected a selector"); } + SpecifierAST *attributes = 0, **attr = &attributes; + while (parseAttributeSpecifier(*attr)) + attr = &(*attr)->next; + return true; } -bool Parser::parseObjCMethodSignature() +// objc-property-attribute ::= getter '=' identifier +// objc-property-attribute ::= setter '=' identifier ':' +// objc-property-attribute ::= readonly +// objc-property-attribute ::= readwrite +// objc-property-attribute ::= assign +// objc-property-attribute ::= retain +// objc-property-attribute ::= copy +// objc-property-attribute ::= nonatomic +bool Parser::parseObjCPropertyAttribute() { - if (LA() != T_PLUS && LA() != T_MINUS) + if (LA() != T_IDENTIFIER) return false; - /*unsigned method_type_token = */ consumeToken(); - parseObjCTypeName(); - - bool first = true; - - while (lookAtObjCSelector() || LA() == T_COLON) { - if (LA() != T_COLON) - /*selector_name_token = */ consumeToken(); - - SpecifierAST *attributes = 0, **attr = &attributes; - while (parseAttributeSpecifier(*attr)) - attr = &(*attr)->next; - - if (first) { - first = false; - - if (LA() != T_COLON) - break; - } - - unsigned colon_token = 0; - match(T_COLON, &colon_token); - - parseObjCTypeName(); - - unsigned identifier_token = 0; - match(T_IDENTIFIER, &identifier_token); - - while (parseAttributeSpecifier(*attr)) - attr = &(*attr)->next; - } - - // parse the method tail parameters. - while (LA() == T_COMMA) { + unsigned identifier_token = 0; + match(T_IDENTIFIER, &identifier_token); + if (LA() == T_EQUAL) { consumeToken(); - - if (LA() == T_DOT_DOT_DOT) { + match(T_IDENTIFIER, &identifier_token); + if (LA() == T_COLON) consumeToken(); - break; - } - - DeclarationAST *parameter_declaration = 0; - parseParameterDeclaration(parameter_declaration); } return true; } +// objc-type-name ::= T_LPAREN objc-type-qualifiers-opt type-id T_RPAREN +// bool Parser::parseObjCTypeName() { if (LA() != T_LPAREN) return false; - /*unsigned lparen_token = */ consumeToken(); - - parseObjCProtocolQualifiers(); - + unsigned lparen_token = 0, rparen_token = 0; + match(T_LPAREN, &lparen_token); + parseObjCTypeQualifiers(); ExpressionAST *type_id = 0; - if (LA() != T_RPAREN) - parseTypeId(type_id); + parseTypeId(type_id); + match(T_RPAREN, &rparen_token); + return true; +} - SpecifierAST *attributes = 0, **attr = &attributes; - while (parseAttributeSpecifier(*attr)) - attr = &(*attr)->next; +// objc-selector ::= T_IDENTIFIER | keyword +// +bool Parser::parseObjCSelector() +{ + if (! lookAtObjCSelector()) + return false; - unsigned rparen_token = 0; - match(T_RPAREN, &rparen_token); + consumeToken(); return true; } -bool Parser::parseObjCAtProperty() +// objc-keyword-decl ::= objc-selector? T_COLON objc-type-name? objc-keyword-attributes-opt T_IDENTIFIER +// +bool Parser::parseObjCKeywordDeclaration() { - if (LA() != T_AT_PROPERTY) + if (! (LA() == T_COLON || (lookAtObjCSelector() && LA(2) == T_COLON))) return false; - /*unsigned property_token = */ consumeToken(); + parseObjCSelector(); + + unsigned colon_token = 0; + match(T_COLON, &colon_token); + + parseObjCTypeName(); + + SpecifierAST *attributes = 0, **attr = &attributes; + while (parseAttributeSpecifier(*attr)) + attr = &(*attr)->next; + + unsigned identifier_token = 0; + match(T_IDENTIFIER, &identifier_token); + return true; } -bool Parser::parseObjCProtocolQualifiers() +bool Parser::parseObjCTypeQualifiers() { return false; } -bool Parser::lookAtObjCSelector() const +// objc-end: T_AT_END +bool Parser::parseObjCEnd(DeclarationAST *&) { - switch (LA()) { - case T_IDENTIFIER: - case T_OR: - case T_AND: - case T_NOT: - case T_XOR: - case T_BITOR: - case T_COMPL: - case T_OR_EQ: - case T_AND_EQ: - case T_BITAND: - case T_NOT_EQ: - case T_XOR_EQ: - return true; - - default: - if (tok().isKeyword()) - return true; - } // switch + if (LA() != T_AT_END) + return false; - return false; + consumeToken(); + return true; } + + CPLUSPLUS_END_NAMESPACE diff --git a/shared/cplusplus/Parser.h b/shared/cplusplus/Parser.h index c943664afe1b6428e511bce4e13f52ee146bb7c0..5132ec5732f58d97da94976a507571b5755bf29a 100644 --- a/shared/cplusplus/Parser.h +++ b/shared/cplusplus/Parser.h @@ -206,46 +206,32 @@ public: bool parseUsingDirective(DeclarationAST *&node); bool parseWhileStatement(StatementAST *&node); + // Qt MOC run + bool parseQtMethod(ExpressionAST *&node); + // ObjC++ - bool parseObjCClassImplementation(DeclarationAST *&node); bool parseObjCClassDeclaration(DeclarationAST *&node); - bool parseObjCInterfaceDeclaration(DeclarationAST *&node); - bool parseObjCProtocolDeclaration(DeclarationAST *&node); - bool parseObjCEndDeclaration(DeclarationAST *&node); - bool parseObjCAliasDeclaration(DeclarationAST *&node); - bool parseObjCPropertySynthesize(DeclarationAST *&node); - bool parseObjCPropertyDynamic(DeclarationAST *&node); + bool parseObjCInterface(DeclarationAST *&node, + SpecifierAST *attributes = 0); + bool parseObjCProtocol(DeclarationAST *&node, + SpecifierAST *attributes = 0); - bool parseObjCIdentifierList(IdentifierListAST *&node); - - bool parseObjCPropertyDeclaration(DeclarationAST *&node); bool parseObjCProtocolRefs(); - bool parseObjCClassInstanceVariables(); + bool parseObjClassInstanceVariables(); bool parseObjCInterfaceMemberDeclaration(); - bool parseObjCInterfaceDeclList(); + bool parseObjCInstanceVariableDeclaration(DeclarationAST *&node); + bool parseObjCPropertyDeclaration(DeclarationAST *&node, + SpecifierAST *attributes = 0); bool parseObjCMethodPrototype(); - - bool parseObjCExpression(ExpressionAST *&node); - bool parseObjCMessageExpression(ExpressionAST *&node); - bool parseObjCStringLiteral(ExpressionAST *&node); - bool parseObjCEncodeExpression(ExpressionAST *&node); - bool parseObjCProtocolExpression(ExpressionAST *&node); - bool parseObjCSelectorExpression(ExpressionAST *&node); - - bool parseObjCMessageReceiver(ExpressionAST *&node); - bool parseObjCMessageArguments(); - - bool parseObjCMethodSignature(); - bool parseObjCMethodDefinitionList(); - bool parseObjCAtProperty(); + bool parseObjCPropertyAttribute(); bool parseObjCTypeName(); - bool parseObjCProtocolQualifiers(); + bool parseObjCSelector(); + bool parseObjCKeywordDeclaration(); + bool parseObjCTypeQualifiers(); + bool parseObjCEnd(DeclarationAST *&node); bool lookAtObjCSelector() const; - // Qt MOC run - bool parseQtMethod(ExpressionAST *&node); - bool skipUntil(int token); bool skipUntilDeclaration(); bool skipUntilStatement(); diff --git a/shared/cplusplus/Token.h b/shared/cplusplus/Token.h index d5b6f1a1c0eab08279942cd3bae67c78708ae394..fdc3298202f697f35604cebcb74ecc75ea36dbf5 100644 --- a/shared/cplusplus/Token.h +++ b/shared/cplusplus/Token.h @@ -201,9 +201,9 @@ enum Kind { T___TYPEOF__, // obj c++ @ keywords - T_FIRST_OBJC_KEYWORD, + T_FIRST_OBJC_AT_KEYWORD, - T_AT_CATCH = T_FIRST_OBJC_KEYWORD, + T_AT_CATCH = T_FIRST_OBJC_AT_KEYWORD, T_AT_CLASS, T_AT_COMPATIBILITY_ALIAS, T_AT_DEFS, @@ -228,7 +228,9 @@ enum Kind { T_AT_THROW, T_AT_TRY, - T_FIRST_QT_KEYWORD, + T_LAST_OBJC_AT_KEYWORD, + + T_FIRST_QT_KEYWORD = T_LAST_OBJC_AT_KEYWORD, // Qt keywords T_SIGNAL = T_FIRST_QT_KEYWORD, @@ -295,6 +297,9 @@ public: inline bool isKeyword() const { return kind >= T_FIRST_KEYWORD && kind < T_FIRST_QT_KEYWORD; } + inline bool isObjCAtKeyword() const + { return kind >= T_FIRST_OBJC_AT_KEYWORD && kind < T_LAST_OBJC_AT_KEYWORD; } + static const char *name(int kind); public: diff --git a/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp index 969f1ac5ae16453edd8be26484adf4e4aaaf0768..5756d2dd2245053c564ee73eea2f9dca11b70da0 100644 --- a/tests/auto/cplusplus/ast/tst_ast.cpp +++ b/tests/auto/cplusplus/ast/tst_ast.cpp @@ -20,11 +20,15 @@ public: { StringLiteral *fileId = control.findOrInsertFileName("<stdin>"); TranslationUnit *unit = new TranslationUnit(&control, fileId); + unit->setObjCEnabled(true); unit->setSource(source.constData(), source.length()); unit->parse(mode); return unit; } + TranslationUnit *parseDeclaration(const QByteArray &source) + { return parse(source, TranslationUnit::ParseDeclaration); } + TranslationUnit *parseExpression(const QByteArray &source) { return parse(source, TranslationUnit::ParseExpression); } @@ -43,6 +47,11 @@ private slots: void while_condition_statement(); void for_statement(); void cpp_initializer_or_function_declaration(); + + // objc++ + void objc_attributes_followed_by_at_keyword(); + void objc_protocol_forward_declaration_1(); + void objc_protocol_definition_1(); }; void tst_AST::simple_name() @@ -293,6 +302,31 @@ void tst_AST::cpp_initializer_or_function_declaration() QCOMPARE(param->type_specifier->asNamedTypeSpecifier()->name->asSimpleName()->identifier_token, 4U); } +void tst_AST::objc_attributes_followed_by_at_keyword() +{ + QSharedPointer<TranslationUnit> unit(parseDeclaration("\n" +"__attribute__((deprecated)) @interface foo <bar>\n" +"{\n" +" int a, b;\n" +"}\n" +"+ (id) init;\n" +"- (id) init:(int)a foo:(int)b, c;\n" +"@end\n" + )); + AST *ast = unit->ast(); +} + +void tst_AST::objc_protocol_forward_declaration_1() +{ + QSharedPointer<TranslationUnit> unit(parseDeclaration("\n@protocol foo;")); + AST *ast = unit->ast(); +} + +void tst_AST::objc_protocol_definition_1() +{ + QSharedPointer<TranslationUnit> unit(parseDeclaration("\n@protocol foo <ciao, bar> @end")); + AST *ast = unit->ast(); +} QTEST_APPLESS_MAIN(tst_AST) #include "tst_ast.moc" diff --git a/tests/manual/cplusplus/main.cpp b/tests/manual/cplusplus/main.cpp index c33bcbbeff7fc8accdb3e923f63e4ed7fb6867cc..4292fe929f62d933063ff6e13ef8bd7cf257c54f 100644 --- a/tests/manual/cplusplus/main.cpp +++ b/tests/manual/cplusplus/main.cpp @@ -248,6 +248,7 @@ int main(int argc, char *argv[]) Control control; StringLiteral *fileId = control.findOrInsertFileName("<stdin>"); TranslationUnit unit(&control, fileId); + unit.setObjCEnabled(true); unit.setSource(source.constData(), source.size()); unit.parse(); if (! unit.ast())