cppparser: support C++11 lambda expressions

This commit is contained in:
rdb 2017-01-14 22:36:31 +01:00
parent 5aabd56697
commit e12420571b
10 changed files with 410 additions and 14 deletions

View File

@ -8,6 +8,7 @@
#include "cppBisonDefs.h"
#include "cppParser.h"
#include "cppClosureType.h"
#include "cppExpression.h"
#include "cppSimpleType.h"
#include "cppExtensionType.h"
@ -44,6 +45,7 @@ static CPPEnumType *current_enum = NULL;
static int current_storage_class = 0;
static CPPType *current_type = NULL;
static CPPExpression *current_expr = NULL;
static CPPClosureType *current_closure = NULL;
static int publish_nest_level = 0;
static CPPVisibility publish_previous;
static YYLTYPE publish_loc;
@ -363,6 +365,8 @@ pop_struct() {
%type <u.param_list> function_parameters
%type <u.param_list> formal_parameter_list
%type <u.param_list> formal_parameters
%type <u.closure_type> capture_list
%type <u.capture> capture
%type <u.expr> template_parameter_maybe_initialize
%type <u.expr> maybe_initialize
%type <u.expr> maybe_initialize_or_constructor_body
@ -1221,6 +1225,15 @@ function_post:
{
$$ = $1 | (int)CPPFunctionType::F_noexcept;
}
/* | function_post KW_NOEXCEPT '(' const_expr ')'
{
CPPExpression::Result result = $4->evaluate();
if (result._type == CPPExpression::RT_error) {
yywarning("noexcept requires a constant expression", @4);
} else if (result.as_boolean()) {
$$ = $1 | (int)CPPFunctionType::F_noexcept;
}
}*/
| function_post KW_FINAL
{
$$ = $1 | (int)CPPFunctionType::F_final;
@ -1241,6 +1254,11 @@ function_post:
{
// Used for lambdas, currently ignored.
$$ = $1;
}
| function_post KW_CONSTEXPR
{
// Used for lambdas in C++17, currently ignored.
$$ = $1;
}
| function_post KW_THROW '(' ')'
{
@ -3468,11 +3486,16 @@ const_operand:
}
| '[' capture_list ']' function_post maybe_trailing_return_type '{' code '}'
{
$$ = NULL;
$2->_flags = $4;
$2->_return_type = $5;
$$ = new CPPExpression(CPPExpression::lambda($2));
}
| '[' capture_list ']' '(' function_parameter_list ')' function_post maybe_trailing_return_type '{' code '}'
{
$$ = NULL;
$2->_parameters = $5;
$2->_flags = $7;
$2->_return_type = $8;
$$ = new CPPExpression(CPPExpression::lambda($2));
}
| KW_HAS_VIRTUAL_DESTRUCTOR '(' full_type ')'
{
@ -3794,15 +3817,63 @@ formal_const_operand:
/* The contents of the [] list preceding a lambda expression. */
capture_list:
empty
{
$$ = new CPPClosureType();
}
| '='
{
$$ = new CPPClosureType(CPPClosureType::CT_by_value);
}
| '&'
{
$$ = new CPPClosureType(CPPClosureType::CT_by_reference);
}
| capture
| capture ',' capture_list
{
$$ = new CPPClosureType();
$$->_captures.push_back(*$1);
delete $1;
}
| capture_list ',' capture
{
$$ = $1;
$$->_captures.push_back(*$3);
delete $3;
}
;
capture:
'&'
| '='
| '&' name
'&' name
{
$$ = new CPPClosureType::Capture;
$$->_name = $2->get_simple_name();
$$->_type = CPPClosureType::CT_by_reference;
}
| '&' name ELLIPSIS
{
$$ = new CPPClosureType::Capture;
$$->_name = $2->get_simple_name();
$$->_type = CPPClosureType::CT_by_reference;
}
| name
{
$$ = new CPPClosureType::Capture;
$$->_name = $1->get_simple_name();
if ($$->_name == "this") {
$$->_type = CPPClosureType::CT_by_reference;
} else {
$$->_type = CPPClosureType::CT_by_value;
}
}
| '*' name
{
$$ = new CPPClosureType::Capture;
$$->_name = $2->get_simple_name();
$$->_type = CPPClosureType::CT_by_value;
if ($$->_name != "this") {
yywarning("only capture name 'this' may be preceded by an asterisk", @2);
}
}
;
class_derivation_name:

View File

@ -23,6 +23,7 @@
#include <string>
#include "cppClosureType.h"
#include "cppExtensionType.h"
#include "cppFile.h"
@ -42,6 +43,7 @@ class CPPParameterList;
class CPPTemplateParameterList;
class CPPScope;
class CPPIdentifier;
class CPPCaptureType;
void parse_cpp(CPPParser *cp);
CPPExpression *parse_const_expr(CPPPreprocessor *pp,
@ -81,6 +83,8 @@ public:
CPPExtensionType::Type extension_enum;
CPPExpression *expr;
CPPIdentifier *identifier;
CPPClosureType *closure_type;
CPPClosureType::Capture *capture;
} u;
};
#define YYSTYPE cppyystype

View File

@ -0,0 +1,188 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file cppClosureType.cxx
* @author rdb
* @date 2017-01-14
*/
#include "cppClosureType.h"
/**
*
*/
CPPClosureType::
CPPClosureType(CaptureType default_capture) :
CPPFunctionType(NULL, NULL, 0),
_default_capture(default_capture) {
}
/**
*
*/
CPPClosureType::
CPPClosureType(const CPPClosureType &copy) :
CPPFunctionType(copy),
_captures(copy._captures),
_default_capture(copy._default_capture)
{
}
/**
*
*/
void CPPClosureType::
operator = (const CPPClosureType &copy) {
CPPFunctionType::operator = (copy);
_captures = copy._captures;
_default_capture = copy._default_capture;
}
/**
* Adds a new capture to the beginning of the capture list.
*/
void CPPClosureType::
add_capture(string name, CaptureType type) {
if (type == CT_none) {
if (name == "this") {
type = CT_by_reference;
} else {
type = CT_by_value;
}
}
Capture capture = {move(name), type};
_captures.insert(_captures.begin(), move(capture));
}
/**
* Returns true if this declaration is an actual, factual declaration, or
* false if some part of the declaration depends on a template parameter which
* has not yet been instantiated.
*/
bool CPPClosureType::
is_fully_specified() const {
return CPPFunctionType::is_fully_specified();
}
/**
* Returns true if the type is default-constructible.
*/
bool CPPClosureType::
is_default_constructible() const {
return false;
}
/**
* Returns true if the type is copy-constructible.
*/
bool CPPClosureType::
is_copy_constructible() const {
return true;
}
/**
* Returns true if the type is destructible.
*/
bool CPPClosureType::
is_destructible() const {
return true;
}
/**
*
*/
void CPPClosureType::
output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
out.put('[');
bool have_capture = false;
switch (_default_capture) {
case CT_none:
break;
case CT_by_reference:
out.put('&');
have_capture = true;
break;
case CT_by_value:
out.put('=');
have_capture = true;
break;
}
Captures::const_iterator it;
for (it = _captures.begin(); it != _captures.end(); ++it) {
if (have_capture) {
out << ", ";
}
if ((*it)._name == "this") {
if ((*it)._type == CT_by_value) {
out.put('*');
}
} else {
if ((*it)._type == CT_by_reference) {
out.put('&');
}
}
out << (*it)._name;
have_capture = true;
}
out.put(']');
if (_parameters != NULL) {
out.put('(');
_parameters->output(out, scope, true, -1);
out.put(')');
}
if (_flags & F_noexcept) {
out << " noexcept";
}
if (_return_type != NULL) {
out << " -> ";
_return_type->output(out, indent_level, scope, false);
}
out << " {}";
}
/**
*
*/
CPPDeclaration::SubType CPPClosureType::
get_subtype() const {
return ST_closure;
}
/**
*
*/
CPPClosureType *CPPClosureType::
as_closure_type() {
return this;
}
/**
* Called by CPPDeclaration() to determine whether this type is equivalent to
* another type of the same type.
*/
bool CPPClosureType::
is_equal(const CPPDeclaration *other) const {
return (this == other);
}
/**
* Called by CPPDeclaration() to determine whether this type should be ordered
* before another type of the same type, in an arbitrary but fixed ordering.
*/
bool CPPClosureType::
is_less(const CPPDeclaration *other) const {
return (this < other);
}

View File

@ -0,0 +1,64 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file cppClosureType.h
* @author rdb
* @date 2017-01-14
*/
#ifndef CPPCLOSURETYPE_H
#define CPPCLOSURETYPE_H
#include "dtoolbase.h"
#include "cppFunctionType.h"
/**
* The type of a lambda expression. This is like a function, but with
* additional captures defined.
*/
class CPPClosureType : public CPPFunctionType {
public:
enum CaptureType {
CT_none,
CT_by_reference,
CT_by_value,
};
CPPClosureType(CaptureType default_capture = CT_none);
CPPClosureType(const CPPClosureType &copy);
void operator = (const CPPClosureType &copy);
struct Capture {
string _name;
CaptureType _type;
};
typedef vector<Capture> Captures;
Captures _captures;
CaptureType _default_capture;
void add_capture(string name, CaptureType type);
virtual bool is_fully_specified() const;
virtual bool is_default_constructible() const;
virtual bool is_copy_constructible() const;
virtual bool is_destructible() const;
virtual void output(ostream &out, int indent_level, CPPScope *scope,
bool complete) const;
virtual SubType get_subtype() const;
virtual CPPClosureType *as_closure_type();
protected:
virtual bool is_equal(const CPPDeclaration *other) const;
virtual bool is_less(const CPPDeclaration *other) const;
};
#endif

View File

@ -311,6 +311,14 @@ as_make_seq() {
return (CPPMakeSeq *)NULL;
}
/**
*
*/
CPPClosureType *CPPDeclaration::
as_closure_type() {
return (CPPClosureType *)NULL;
}
/**
* Called by CPPDeclaration to determine whether this type is equivalent to
* another type of the same type.

View File

@ -48,6 +48,7 @@ class CPPEnumType;
class CPPTypeProxy;
class CPPMakeProperty;
class CPPMakeSeq;
class CPPClosureType;
class CPPClassTemplateParameter;
class CPPTBDType;
class CPPScope;
@ -85,6 +86,7 @@ public:
ST_tbd,
ST_type_proxy,
ST_typedef,
ST_closure,
};
CPPDeclaration(const CPPFile &file);
@ -140,6 +142,7 @@ public:
virtual CPPTypeProxy *as_type_proxy();
virtual CPPMakeProperty *as_make_property();
virtual CPPMakeSeq *as_make_seq();
virtual CPPClosureType *as_closure_type();
inline const CPPInstance *as_instance() const {
return ((CPPDeclaration *)this)->as_instance();
@ -207,6 +210,9 @@ public:
inline const CPPMakeSeq *as_make_seq() const {
return ((CPPDeclaration *)this)->as_make_seq();
}
inline const CPPClosureType *as_closure_type() const {
return ((CPPDeclaration *)this)->as_closure_type();
}
CPPVisibility _vis;
CPPTemplateScope *_template_scope;

View File

@ -24,6 +24,7 @@
#include "cppInstance.h"
#include "cppFunctionGroup.h"
#include "cppFunctionType.h"
#include "cppClosureType.h"
#include "cppStructType.h"
#include "cppBison.h"
#include "pdtoa.h"
@ -438,6 +439,17 @@ alignof_func(CPPType *type) {
return expr;
}
/**
*
*/
CPPExpression CPPExpression::
lambda(CPPClosureType *type) {
CPPExpression expr(0);
expr._type = T_lambda;
expr._u._closure_type = type;
return expr;
}
/**
*
*/
@ -1169,6 +1181,9 @@ determine_type() const {
case T_type_trait:
return bool_type;
case T_lambda:
return _u._closure_type;
default:
cerr << "**invalid operand**\n";
abort();
@ -1259,6 +1274,9 @@ is_fully_specified() const {
case T_type_trait:
return _u._type_trait._type->is_fully_specified();
case T_lambda:
return _u._closure_type->is_fully_specified();
default:
return true;
}
@ -1478,6 +1496,9 @@ is_tbd() const {
case T_type_trait:
return _u._type_trait._type->is_tbd();
case T_lambda:
return _u._closure_type->is_tbd();
default:
return false;
}
@ -1950,6 +1971,10 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
out << ')';
break;
case T_lambda:
_u._closure_type->output(out, indent_level, scope, false);
break;
default:
out << "(** invalid operand type " << (int)_type << " **)";
}
@ -2109,6 +2134,9 @@ is_equal(const CPPDeclaration *other) const {
return _u._type_trait._trait == ot->_u._type_trait._trait &&
_u._type_trait._type == ot->_u._type_trait._type;
case T_lambda:
return _u._closure_type == ot->_u._closure_type;
default:
cerr << "(** invalid operand type " << (int)_type << " **)";
}
@ -2216,6 +2244,9 @@ is_less(const CPPDeclaration *other) const {
}
return *_u._type_trait._type < *ot->_u._type_trait._type;
case T_lambda:
return _u._closure_type < ot->_u._closure_type;
default:
cerr << "(** invalid operand type " << (int)_type << " **)";
}

View File

@ -61,6 +61,7 @@ public:
T_typeid_type,
T_typeid_expr,
T_type_trait,
T_lambda,
// These are used when parsing =default and =delete methods.
T_default,
@ -87,6 +88,7 @@ public:
static CPPExpression sizeof_func(CPPType *type);
static CPPExpression sizeof_ellipsis_func(CPPIdentifier *ident);
static CPPExpression alignof_func(CPPType *type);
static CPPExpression lambda(CPPClosureType *type);
static CPPExpression literal(unsigned long long value, CPPInstance *lit_op);
static CPPExpression literal(long double value, CPPInstance *lit_op);
@ -150,6 +152,7 @@ public:
CPPInstance *_variable;
CPPFunctionGroup *_fgroup;
CPPIdentifier *_ident;
CPPClosureType *_closure_type;
struct {
union {
CPPType *_type;

View File

@ -31,7 +31,8 @@ CPPFunctionType(CPPType *return_type, CPPParameterList *parameters,
// If the parameter list contains just the token "void", it means no
// parameters.
if (_parameters->_parameters.size() == 1 &&
if (_parameters != NULL &&
_parameters->_parameters.size() == 1 &&
_parameters->_parameters.front()->_type->as_simple_type() != NULL &&
_parameters->_parameters.front()->_type->as_simple_type()->_type ==
CPPSimpleType::T_void &&
@ -95,8 +96,10 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
->as_type();
}
rep->_parameters =
_parameters->substitute_decl(subst, current_scope, global_scope);
if (_parameters != NULL) {
rep->_parameters =
_parameters->substitute_decl(subst, current_scope, global_scope);
}
if (rep->_return_type == _return_type &&
rep->_parameters == _parameters) {
@ -117,8 +120,12 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
CPPType *CPPFunctionType::
resolve_type(CPPScope *current_scope, CPPScope *global_scope) {
CPPType *rtype = _return_type->resolve_type(current_scope, global_scope);
CPPParameterList *params =
_parameters->resolve_type(current_scope, global_scope);
CPPParameterList *params;
if (_parameters == NULL) {
params = NULL;
} else {
params = _parameters->resolve_type(current_scope, global_scope);
}
if (rtype != _return_type || params != _parameters) {
CPPFunctionType *rep = new CPPFunctionType(*this);
@ -139,7 +146,7 @@ is_tbd() const {
if (_return_type->is_tbd()) {
return true;
}
return _parameters->is_tbd();
return _parameters == NULL || _parameters->is_tbd();
}
/**
@ -294,6 +301,10 @@ get_num_default_parameters() const {
// The trick is just to count, beginning from the end and working towards
// the front, the number of parameters that have some initializer.
if (_parameters == NULL) {
return 0;
}
const CPPParameterList::Parameters &params = _parameters->_parameters;
CPPParameterList::Parameters::const_reverse_iterator pi;
int count = 0;
@ -362,7 +373,11 @@ is_equal(const CPPDeclaration *other) const {
if (_flags != ot->_flags) {
return false;
}
if (*_parameters != *ot->_parameters) {
if (_parameters == ot->_parameters) {
return true;
}
if (_parameters == NULL || ot->_parameters == NULL ||
*_parameters != *ot->_parameters) {
return false;
}
return true;
@ -384,6 +399,11 @@ is_less(const CPPDeclaration *other) const {
if (_flags != ot->_flags) {
return _flags < ot->_flags;
}
if (_parameters == ot->_parameters) {
return 0;
}
if (_parameters == NULL || ot->_parameters == NULL) {
return _parameters < ot->_parameters;
}
return *_parameters < *ot->_parameters;
}

View File

@ -2,6 +2,7 @@
#include "cppFunctionType.cxx"
#include "cppGlobals.cxx"
#include "cppCommentBlock.cxx"
#include "cppClosureType.cxx"
#include "cppConstType.cxx"
#include "cppDeclaration.cxx"
#include "cppMakeProperty.cxx"