diff --git a/dtool/src/cppparser/cppBison.yxx b/dtool/src/cppparser/cppBison.yxx index 655432c8dc..8c0e9bf982 100644 --- a/dtool/src/cppparser/cppBison.yxx +++ b/dtool/src/cppparser/cppBison.yxx @@ -249,6 +249,8 @@ pop_struct() { %token XOREQUAL %token LSHIFTEQUAL %token RSHIFTEQUAL +%token ATTR_LEFT +%token ATTR_RIGHT %token KW_ALIGNAS %token KW_ALIGNOF @@ -874,10 +876,18 @@ storage_class: { $$ = $2 | (int)CPPInstance::SC_thread_local; } - | '[' '[' attribute_specifiers ']' ']' storage_class + | ATTR_LEFT attribute_specifiers ATTR_RIGHT storage_class { // Ignore attribute specifiers for now. - $$ = $6; + $$ = $4; +} + | KW_ALIGNAS '(' const_expr ')' storage_class +{ + $$ = $5; +} + | KW_ALIGNAS '(' type_decl ')' storage_class +{ + $$ = $5; } ; @@ -889,6 +899,7 @@ attribute_specifiers: attribute_specifier: name | name '(' formal_parameter_list ')' + | KW_USING name ':' attribute_specifier ; type_like_declaration: @@ -1272,10 +1283,10 @@ function_post: { $$ = $1; } -/* | function_post '[' '[' attribute_specifiers ']' ']' + | function_post ATTR_LEFT attribute_specifiers ATTR_RIGHT { $$ = $1; -}*/ +} ; function_operator: @@ -1443,7 +1454,8 @@ more_template_declaration: ; template_declaration: - KW_TEMPLATE + KW_EXTERN template_declaration + | KW_TEMPLATE { push_scope(new CPPTemplateScope(current_scope)); } @@ -1451,7 +1463,7 @@ template_declaration: { pop_scope(); } - | KW_TEMPLATE type_like_declaration + | KW_TEMPLATE type_like_declaration ; template_formal_parameters: @@ -1903,6 +1915,10 @@ function_parameter: | KW_REGISTER function_parameter { $$ = $2; +} + | ATTR_LEFT attribute_specifiers ATTR_RIGHT function_parameter +{ + $$ = $4; } ; @@ -2246,16 +2262,16 @@ type: { $$ = CPPType::new_type($1); } - | struct_keyword name + | struct_keyword struct_attributes name { - CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer); + CPPType *type = $3->find_type(current_scope, global_scope, false, current_lexer); if (type != NULL) { $$ = type; } else { CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) + CPPType::new_type(new CPPExtensionType($1, $3, current_scope, @1.file)) ->as_extension_type(); - CPPScope *scope = $2->get_scope(current_scope, global_scope); + CPPScope *scope = $3->get_scope(current_scope, global_scope); if (scope != NULL) { scope->define_extension_type(et); } @@ -2286,6 +2302,10 @@ type: str << *$3; yyerror("could not determine type of " + str.str(), @3); } +} + | KW_DECLTYPE '(' KW_AUTO ')' +{ + $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); } | KW_UNDERLYING_TYPE '(' full_type ')' { @@ -2343,16 +2363,16 @@ type_decl: { $$ = new CPPTypeDeclaration(CPPType::new_type($1)); } - | struct_keyword name + | struct_keyword struct_attributes name { - CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer); + CPPType *type = $3->find_type(current_scope, global_scope, false, current_lexer); if (type != NULL) { $$ = type; } else { CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) + CPPType::new_type(new CPPExtensionType($1, $3, current_scope, @1.file)) ->as_extension_type(); - CPPScope *scope = $2->get_scope(current_scope, global_scope); + CPPScope *scope = $3->get_scope(current_scope, global_scope); if (scope != NULL) { scope->define_extension_type(et); } @@ -2401,6 +2421,10 @@ type_decl: str << *$3; yyerror("could not determine type of " + str.str(), @3); } +} + | KW_DECLTYPE '(' KW_AUTO ')' +{ + $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); } | KW_UNDERLYING_TYPE '(' full_type ')' { @@ -2435,16 +2459,16 @@ predefined_type: { $$ = CPPType::new_type(new CPPTBDType($2)); } - | struct_keyword name + | struct_keyword struct_attributes name { - CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer); + CPPType *type = $3->find_type(current_scope, global_scope, false, current_lexer); if (type != NULL) { $$ = type; } else { CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) + CPPType::new_type(new CPPExtensionType($1, $3, current_scope, @1.file)) ->as_extension_type(); - CPPScope *scope = $2->get_scope(current_scope, global_scope); + CPPScope *scope = $3->get_scope(current_scope, global_scope); if (scope != NULL) { scope->define_extension_type(et); } @@ -2525,8 +2549,15 @@ full_type: } ; +struct_attributes: + empty + | struct_attributes ATTR_LEFT attribute_specifiers ATTR_RIGHT + | struct_attributes KW_ALIGNAS '(' const_expr ')' + | struct_attributes KW_ALIGNAS '(' type_decl ')' + ; + anonymous_struct: - struct_keyword '{' + struct_keyword struct_attributes '{' { CPPVisibility starting_vis = ($1 == CPPExtensionType::T_class) ? V_private : V_public; @@ -2550,19 +2581,19 @@ anonymous_struct: ; named_struct: - struct_keyword name_no_final + struct_keyword struct_attributes name_no_final { CPPVisibility starting_vis = ($1 == CPPExtensionType::T_class) ? V_private : V_public; - CPPScope *scope = $2->get_scope(current_scope, global_scope, current_lexer); + CPPScope *scope = $3->get_scope(current_scope, global_scope, current_lexer); if (scope == NULL) { scope = current_scope; } - CPPScope *new_scope = new CPPScope(scope, $2->_names.back(), + CPPScope *new_scope = new CPPScope(scope, $3->_names.back(), starting_vis); - CPPStructType *st = new CPPStructType($1, $2, current_scope, + CPPStructType *st = new CPPStructType($1, $3, current_scope, new_scope, @1.file); new_scope->set_struct_type(st); current_scope->define_extension_type(st); @@ -2945,6 +2976,7 @@ element: | SCOPE | PLUSPLUS | MINUSMINUS | TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL | OREQUAL | ANDEQUAL | XOREQUAL | LSHIFTEQUAL | RSHIFTEQUAL + | ATTR_LEFT | ATTR_RIGHT | KW_ALIGNAS | KW_ALIGNOF | KW_AUTO | KW_BOOL | KW_CATCH | KW_CHAR | KW_CHAR16_T | KW_CHAR32_T | KW_CLASS | KW_CONST | KW_CONSTEXPR | KW_CONST_CAST | KW_DECLTYPE | KW_DEFAULT @@ -3028,6 +3060,18 @@ no_angle_bracket_const_expr: | KW_SIZEOF '(' full_type ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::sizeof_func($3)); +} + | KW_SIZEOF '(' IDENTIFIER ')' %prec UNARY +{ + CPPDeclaration *arg = $3->find_symbol(current_scope, global_scope, current_lexer); + if (arg == (CPPDeclaration *)NULL) { + yyerror("undefined sizeof argument: " + $3->get_fully_scoped_name(), @3); + } else if (arg->get_subtype() == CPPDeclaration::ST_instance) { + CPPInstance *inst = arg->as_instance(); + $$ = new CPPExpression(CPPExpression::sizeof_func(inst->_type)); + } else { + $$ = new CPPExpression(CPPExpression::sizeof_func(arg->as_type())); + } } | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY { @@ -3190,6 +3234,16 @@ const_expr: } assert(type != NULL); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); +} + | TYPENAME_IDENTIFIER '{' optional_const_expr_comma '}' +{ + // Aggregate initialization. + CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); + if (type == NULL) { + yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); + } + assert(type != NULL); + $$ = new CPPExpression(CPPExpression::aggregate_init_op(type, $3)); } | KW_INT '(' optional_const_expr_comma ')' { @@ -3270,6 +3324,18 @@ const_expr: | KW_SIZEOF '(' full_type ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::sizeof_func($3)); +} + | KW_SIZEOF '(' IDENTIFIER ')' %prec UNARY +{ + CPPDeclaration *arg = $3->find_symbol(current_scope, global_scope, current_lexer); + if (arg == (CPPDeclaration *)NULL) { + yyerror("undefined sizeof argument: " + $3->get_fully_scoped_name(), @3); + } else if (arg->get_subtype() == CPPDeclaration::ST_instance) { + CPPInstance *inst = arg->as_instance(); + $$ = new CPPExpression(CPPExpression::sizeof_func(inst->_type)); + } else { + $$ = new CPPExpression(CPPExpression::sizeof_func(arg->as_type())); + } } | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY { @@ -3602,6 +3668,18 @@ formal_const_expr: | KW_SIZEOF '(' full_type ')' %prec UNARY { $$ = new CPPExpression(CPPExpression::sizeof_func($3)); +} + | KW_SIZEOF '(' IDENTIFIER ')' %prec UNARY +{ + CPPDeclaration *arg = $3->find_symbol(current_scope, global_scope, current_lexer); + if (arg == (CPPDeclaration *)NULL) { + yyerror("undefined sizeof argument: " + $3->get_fully_scoped_name(), @3); + } else if (arg->get_subtype() == CPPDeclaration::ST_instance) { + CPPInstance *inst = arg->as_instance(); + $$ = new CPPExpression(CPPExpression::sizeof_func(inst->_type)); + } else { + $$ = new CPPExpression(CPPExpression::sizeof_func(arg->as_type())); + } } | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY { @@ -3828,15 +3906,17 @@ capture_list: { $$ = new CPPClosureType(CPPClosureType::CT_by_reference); } - | capture + | capture maybe_initialize { $$ = new CPPClosureType(); + $1->_initializer = $2; $$->_captures.push_back(*$1); delete $1; } - | capture_list ',' capture + | capture_list ',' capture maybe_initialize { $$ = $1; + $3->_initializer = $4; $$->_captures.push_back(*$3); delete $3; } @@ -3884,14 +3964,6 @@ class_derivation_name: type = CPPType::new_type(new CPPTBDType($1)); } $$ = type; -} - | struct_keyword name -{ - CPPType *type = $2->find_type(current_scope, global_scope, true, current_lexer); - if (type == NULL) { - type = CPPType::new_type(new CPPTBDType($2)); - } - $$ = type; } | KW_TYPENAME name { diff --git a/dtool/src/cppparser/cppClosureType.cxx b/dtool/src/cppparser/cppClosureType.cxx index fe5d99b5ad..cf8ec31143 100755 --- a/dtool/src/cppparser/cppClosureType.cxx +++ b/dtool/src/cppparser/cppClosureType.cxx @@ -12,6 +12,7 @@ */ #include "cppClosureType.h" +#include "cppExpression.h" /** * @@ -47,7 +48,7 @@ operator = (const CPPClosureType ©) { * Adds a new capture to the beginning of the capture list. */ void CPPClosureType:: -add_capture(string name, CaptureType type) { +add_capture(string name, CaptureType type, CPPExpression *initializer) { if (type == CT_none) { if (name == "this") { type = CT_by_reference; @@ -56,7 +57,7 @@ add_capture(string name, CaptureType type) { } } - Capture capture = {move(name), type}; + Capture capture = {move(name), type, initializer}; _captures.insert(_captures.begin(), move(capture)); } @@ -117,19 +118,25 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const { Captures::const_iterator it; for (it = _captures.begin(); it != _captures.end(); ++it) { + const Capture &capture = *it; if (have_capture) { out << ", "; } - if ((*it)._name == "this") { - if ((*it)._type == CT_by_value) { + if (capture._name == "this") { + if (capture._type == CT_by_value) { out.put('*'); } } else { - if ((*it)._type == CT_by_reference) { + if (capture._type == CT_by_reference) { out.put('&'); } } - out << (*it)._name; + out << capture._name; + + if (capture._initializer != NULL) { + out << " = " << *capture._initializer; + } + have_capture = true; } out.put(']'); diff --git a/dtool/src/cppparser/cppClosureType.h b/dtool/src/cppparser/cppClosureType.h index c682c6adca..9c3533ad4a 100755 --- a/dtool/src/cppparser/cppClosureType.h +++ b/dtool/src/cppparser/cppClosureType.h @@ -37,13 +37,14 @@ public: struct Capture { string _name; CaptureType _type; + CPPExpression *_initializer; }; typedef vector Captures; Captures _captures; CaptureType _default_capture; - void add_capture(string name, CaptureType type); + void add_capture(string name, CaptureType type, CPPExpression *initializer = NULL); virtual bool is_fully_specified() const; diff --git a/dtool/src/cppparser/cppExpression.cxx b/dtool/src/cppparser/cppExpression.cxx index a891f4ecf6..0dff4f64b8 100644 --- a/dtool/src/cppparser/cppExpression.cxx +++ b/dtool/src/cppparser/cppExpression.cxx @@ -257,13 +257,12 @@ CPPExpression(CPPIdentifier *ident, CPPScope *current_scope, _u._variable = inst; return; } - // Actually, we can't scope function groups. - /*CPPFunctionGroup *fgroup = decl->as_function_group(); + CPPFunctionGroup *fgroup = decl->as_function_group(); if (fgroup != NULL) { _type = T_function; _u._fgroup = fgroup; return; - }*/ + } } _type = T_unknown_ident; @@ -347,6 +346,22 @@ construct_op(CPPType *type, CPPExpression *op1) { return expr; } +/** + * Creates an expression that represents an aggregate initialization. + */ +CPPExpression CPPExpression:: +aggregate_init_op(CPPType *type, CPPExpression *op1) { + CPPExpression expr(0); + if (op1 == NULL) { + expr._type = T_empty_aggregate_init; + } else { + expr._type = T_aggregate_init; + } + expr._u._typecast._to = type; + expr._u._typecast._op1 = op1; + return expr; +} + /** * Creates an expression that represents a use of the new operator. */ @@ -606,6 +621,8 @@ evaluate() const { case T_construct: case T_default_construct: + case T_aggregate_init: + case T_empty_aggregate_init: case T_new: case T_default_new: case T_sizeof: @@ -1029,6 +1046,8 @@ determine_type() const { case T_reinterpret_cast: case T_construct: case T_default_construct: + case T_aggregate_init: + case T_empty_aggregate_init: return _u._typecast._to; case T_new: @@ -1147,10 +1166,28 @@ determine_type() const { case 'f': // Function evaluation if (t1 != NULL) { + // Easy case, function with only a single overload. CPPFunctionType *ftype = t1->as_function_type(); if (ftype != (CPPFunctionType *)NULL) { return ftype->_return_type; } + } else if (_u._op._op1->_type == T_function) { + CPPFunctionGroup *fgroup = _u._op._op1->_u._fgroup; + if (_u._op._op2 == NULL) { + // If we are passing no args, look for an overload that has takes no + // args. + for (auto it = fgroup->_instances.begin(); it != fgroup->_instances.end(); ++it) { + CPPInstance *inst = *it; + if (inst != NULL && inst->_type != NULL) { + CPPFunctionType *type = inst->_type->as_function_type(); + if (type != NULL && type->accepts_num_parameters(0)) { + return type->_return_type; + } + } + } + } else { + //TODO + } } return NULL; @@ -1230,11 +1267,13 @@ is_fully_specified() const { case T_const_cast: case T_reinterpret_cast: case T_construct: + case T_aggregate_init: case T_new: return (_u._typecast._to->is_fully_specified() && _u._typecast._op1->is_fully_specified()); case T_default_construct: + case T_empty_aggregate_init: case T_default_new: case T_sizeof: case T_alignof: @@ -1360,6 +1399,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst, case T_const_cast: case T_reinterpret_cast: case T_construct: + case T_aggregate_init: case T_new: rep->_u._typecast._op1 = _u._typecast._op1->substitute_decl(subst, current_scope, global_scope) @@ -1368,6 +1408,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst, // fall through case T_default_construct: + case T_empty_aggregate_init: case T_default_new: case T_sizeof: case T_alignof: @@ -1462,6 +1503,8 @@ is_tbd() const { case T_const_cast: case T_reinterpret_cast: case T_construct: + case T_aggregate_init: + case T_empty_aggregate_init: case T_new: case T_default_construct: case T_default_new: @@ -1674,6 +1717,18 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const { out << "()"; break; + case T_aggregate_init: + _u._typecast._to->output(out, indent_level, scope, false); + out << "{"; + _u._typecast._op1->output(out, indent_level, scope, false); + out << "}"; + break; + + case T_empty_aggregate_init: + _u._typecast._to->output(out, indent_level, scope, false); + out << "{}"; + break; + case T_new: out << "(new "; _u._typecast._to->output(out, indent_level, scope, false); @@ -2095,11 +2150,13 @@ is_equal(const CPPDeclaration *other) const { case T_const_cast: case T_reinterpret_cast: case T_construct: + case T_aggregate_init: case T_new: return _u._typecast._to == ot->_u._typecast._to && *_u._typecast._op1 == *ot->_u._typecast._op1; case T_default_construct: + case T_empty_aggregate_init: case T_default_new: case T_sizeof: case T_alignof: @@ -2193,6 +2250,7 @@ is_less(const CPPDeclaration *other) const { case T_const_cast: case T_reinterpret_cast: case T_construct: + case T_aggregate_init: case T_new: if (_u._typecast._to != ot->_u._typecast._to) { return _u._typecast._to < ot->_u._typecast._to; @@ -2200,6 +2258,7 @@ is_less(const CPPDeclaration *other) const { return *_u._typecast._op1 < *ot->_u._typecast._op1; case T_default_construct: + case T_empty_aggregate_init: case T_default_new: case T_sizeof: case T_alignof: diff --git a/dtool/src/cppparser/cppExpression.h b/dtool/src/cppparser/cppExpression.h index 2cdb297c36..3178d4d178 100644 --- a/dtool/src/cppparser/cppExpression.h +++ b/dtool/src/cppparser/cppExpression.h @@ -48,6 +48,8 @@ public: T_reinterpret_cast, T_construct, T_default_construct, + T_aggregate_init, + T_empty_aggregate_init, T_new, T_default_new, T_sizeof, @@ -81,6 +83,7 @@ public: static CPPExpression typecast_op(CPPType *type, CPPExpression *op1, Type cast_type = T_typecast); static CPPExpression construct_op(CPPType *type, CPPExpression *op1); + static CPPExpression aggregate_init_op(CPPType *type, CPPExpression *op1); static CPPExpression new_op(CPPType *type, CPPExpression *op1 = NULL); static CPPExpression typeid_op(CPPType *type, CPPType *std_type_info); static CPPExpression typeid_op(CPPExpression *op1, CPPType *std_type_info); diff --git a/dtool/src/cppparser/cppFunctionType.cxx b/dtool/src/cppparser/cppFunctionType.cxx index d016695bf8..38eb3d98ba 100644 --- a/dtool/src/cppparser/cppFunctionType.cxx +++ b/dtool/src/cppparser/cppFunctionType.cxx @@ -66,6 +66,31 @@ operator = (const CPPFunctionType ©) { _class_owner = copy._class_owner; } +/** + * Returns true if the function accepts the given number of parameters. + */ +bool CPPFunctionType:: +accepts_num_parameters(int num_parameters) { + if (_parameters == NULL) { + return (num_parameters == 0); + } + size_t actual_num_parameters = _parameters->_parameters.size(); + // If we passed too many parameters, it must have an ellipsis. + if (num_parameters > actual_num_parameters) { + return _parameters->_includes_ellipsis; + } + + // Make sure all superfluous parameters have a default value. + for (size_t i = num_parameters; i < actual_num_parameters; ++i) { + CPPInstance *param = _parameters->_parameters[i]; + if (param->_initializer == NULL) { + return false; + } + } + + return true; +} + /** * Returns true if this declaration is an actual, factual declaration, or * false if some part of the declaration depends on a template parameter which diff --git a/dtool/src/cppparser/cppFunctionType.h b/dtool/src/cppparser/cppFunctionType.h index 1e44681f13..a5a66976b0 100644 --- a/dtool/src/cppparser/cppFunctionType.h +++ b/dtool/src/cppparser/cppFunctionType.h @@ -50,6 +50,8 @@ public: CPPFunctionType(const CPPFunctionType ©); void operator = (const CPPFunctionType ©); + bool accepts_num_parameters(int num_parameters); + CPPType *_return_type; CPPParameterList *_parameters; int _flags; diff --git a/dtool/src/cppparser/cppPreprocessor.cxx b/dtool/src/cppparser/cppPreprocessor.cxx index c6a7dd0b07..6a24d9eb69 100644 --- a/dtool/src/cppparser/cppPreprocessor.cxx +++ b/dtool/src/cppparser/cppPreprocessor.cxx @@ -209,6 +209,7 @@ CPPPreprocessor() { _state = S_eof; _paren_nesting = 0; _parsing_template_params = false; + _parsing_attribute = false; _unget = '\0'; _last_c = '\0'; _start_of_line = true; @@ -986,6 +987,13 @@ internal_get_next_token() { return CPPToken(0, loc); } } + } else if (_parsing_attribute) { + // If we're parsing an attribute, also keep track of the paren nesting. + if (c == '[' || c == '(') { + ++_paren_nesting; + } else if (c == ']' || c == ')') { + --_paren_nesting; + } } // Look for an end-of-line comment, and parse it before we finish this @@ -1090,6 +1098,20 @@ check_digraph(int c) { if (next_c == '=') return MODEQUAL; if (next_c == '>') return '}'; break; + + case '[': + if (next_c == '[' && !_parsing_attribute) { + _parsing_attribute = true; + return ATTR_LEFT; + } + break; + + case ']': + if (next_c == ']' && _parsing_attribute && _paren_nesting == 0) { + _parsing_attribute = false; + return ATTR_RIGHT; + } + break; } return 0; diff --git a/dtool/src/cppparser/cppPreprocessor.h b/dtool/src/cppparser/cppPreprocessor.h index 20f313758a..02f3715339 100644 --- a/dtool/src/cppparser/cppPreprocessor.h +++ b/dtool/src/cppparser/cppPreprocessor.h @@ -213,6 +213,7 @@ private: State _state; int _paren_nesting; bool _parsing_template_params; + bool _parsing_attribute; bool _start_of_line; int _unget; diff --git a/dtool/src/cppparser/cppToken.cxx b/dtool/src/cppparser/cppToken.cxx index 025590113a..d2e00982dc 100644 --- a/dtool/src/cppparser/cppToken.cxx +++ b/dtool/src/cppparser/cppToken.cxx @@ -252,6 +252,14 @@ output(ostream &out) const { out << "RSHIFTEQUAL"; break; + case ATTR_LEFT: + out << "ATTR_LEFT"; + break; + + case ATTR_RIGHT: + out << "ATTR_RIGHT"; + break; + case KW_BOOL: out << "KW_BOOL"; break;