panda3d/dtool/src/cppparser/cppExpression.cxx

1846 lines
48 KiB
C++

// Filename: cppExpression.cxx
// Created by: drose (25Oct99)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#include "cppExpression.h"
#include "cppToken.h"
#include "cppIdentifier.h"
#include "cppType.h"
#include "cppSimpleType.h"
#include "cppPointerType.h"
#include "cppConstType.h"
#include "cppArrayType.h"
#include "cppPreprocessor.h"
#include "cppInstance.h"
#include "cppFunctionGroup.h"
#include "cppFunctionType.h"
#include "cppBison.h"
#include "pdtoa.h"
#include <assert.h>
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Result::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::Result::
Result() {
_type = RT_error;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Result::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::Result::
Result(int value) {
_type = RT_integer;
_u._integer = value;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Result::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::Result::
Result(double value) {
_type = RT_real;
_u._real = value;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Result::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::Result::
Result(void *value) {
_type = RT_pointer;
_u._pointer = value;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Result::as_integer
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
int CPPExpression::Result::
as_integer() const {
switch (_type) {
case RT_integer:
return _u._integer;
case RT_real:
return (int)_u._real;
case RT_pointer:
// We don't mind if this loses precision.
return (int)reinterpret_cast<long>(_u._pointer);
default:
cerr << "Invalid type\n";
assert(false);
return 0;
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Result::as_real
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
double CPPExpression::Result::
as_real() const {
switch (_type) {
case RT_integer:
return (double)_u._integer;
case RT_real:
return _u._real;
case RT_pointer:
// We don't mind if this loses precision.
return (double)reinterpret_cast<long>(_u._pointer);
default:
cerr << "Invalid type\n";
assert(false);
return 0.0;
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Result::as_pointer
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void *CPPExpression::Result::
as_pointer() const {
switch (_type) {
case RT_integer:
return reinterpret_cast<void*>((long)_u._integer);
case RT_real:
return reinterpret_cast<void*>((long)_u._real);
case RT_pointer:
return _u._pointer;
default:
cerr << "Invalid type\n";
assert(false);
return (void *)NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Result::as_boolean
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool CPPExpression::Result::
as_boolean() const {
switch (_type) {
case RT_integer:
return (_u._integer != 0);
case RT_real:
return (_u._real != 0.0);
case RT_pointer:
return (_u._pointer != NULL);
default:
cerr << "Invalid type\n";
assert(false);
return false;
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Result::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void CPPExpression::Result::
output(ostream &out) const {
switch (_type) {
case RT_integer:
out << _u._integer;
break;
case RT_real:
out << _u._real;
break;
case RT_pointer:
out << _u._pointer;
break;
case RT_error:
out << "(error)";
break;
default:
out << "(**invalid type**)\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(unsigned long long value) :
CPPDeclaration(CPPFile())
{
_type = T_integer;
_u._integer = value;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(int value) :
CPPDeclaration(CPPFile())
{
_type = T_integer;
_u._integer = value;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(long double value) :
CPPDeclaration(CPPFile())
{
_type = T_real;
_u._real = value;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(const string &value) :
CPPDeclaration(CPPFile())
{
_type = T_string;
_str = value;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(CPPIdentifier *ident, CPPScope *current_scope,
CPPScope *global_scope, CPPPreprocessor *error_sink) :
CPPDeclaration(CPPFile())
{
CPPDeclaration *decl =
ident->find_symbol(current_scope, global_scope);
if (decl != NULL) {
CPPInstance *inst = decl->as_instance();
if (inst != NULL) {
_type = T_variable;
_u._variable = inst;
return;
}
CPPFunctionGroup *fgroup = decl->as_function_group();
if (fgroup != NULL) {
_type = T_function;
_u._fgroup = fgroup;
return;
}
}
_type = T_unknown_ident;
_u._ident = ident;
_u._ident->_native_scope = current_scope;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(int unary_operator, CPPExpression *op1) :
CPPDeclaration(CPPFile())
{
_type = T_unary_operation;
_u._op._operator = unary_operator;
_u._op._op1 = op1;
_u._op._op2 = NULL;
_u._op._op3 = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(int binary_operator, CPPExpression *op1, CPPExpression *op2) :
CPPDeclaration(CPPFile())
{
_type = T_binary_operation;
_u._op._operator = binary_operator;
_u._op._op1 = op1;
_u._op._op2 = op2;
_u._op._op3 = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(int trinary_operator, CPPExpression *op1, CPPExpression *op2,
CPPExpression *op3) :
CPPDeclaration(CPPFile())
{
_type = T_trinary_operation;
_u._op._operator = trinary_operator;
_u._op._op1 = op1;
_u._op._op2 = op2;
_u._op._op3 = op3;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named typecast_op constructor
// Access: Public, Static
// Description: Creates an expression that represents a typecast
// operation.
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
typecast_op(CPPType *type, CPPExpression *op1) {
CPPExpression expr(0);
expr._type = T_typecast;
expr._u._typecast._to = type;
expr._u._typecast._op1 = op1;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named construct_op constructor
// Access: Public, Static
// Description: Creates an expression that represents a constructor
// call.
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
construct_op(CPPType *type, CPPExpression *op1) {
CPPExpression expr(0);
if (op1 == NULL) {
// A default constructor call--no parameters.
expr._type = T_default_construct;
expr._u._typecast._to = type;
expr._u._typecast._op1 = NULL;
} else {
// A normal constructor call, with parameters.
expr._type = T_construct;
expr._u._typecast._to = type;
expr._u._typecast._op1 = op1;
}
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named new_op constructor
// Access: Public, Static
// Description: Creates an expression that represents a use of the
// new operator.
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
new_op(CPPType *type, CPPExpression *op1) {
CPPExpression expr(0);
if (op1 == NULL) {
// A default new operation--no parameters.
expr._type = T_default_new;
expr._u._typecast._to = type;
expr._u._typecast._op1 = NULL;
} else {
// A normal new operation, with parameters.
expr._type = T_new;
expr._u._typecast._to = type;
expr._u._typecast._op1 = op1;
}
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named sizeof_func constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
sizeof_func(CPPType *type) {
CPPExpression expr(0);
expr._type = T_sizeof;
expr._u._typecast._to = type;
expr._u._typecast._op1 = NULL;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named alignof_func constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
alignof_func(CPPType *type) {
CPPExpression expr(0);
expr._type = T_alignof;
expr._u._typecast._to = type;
expr._u._typecast._op1 = NULL;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
literal(unsigned long long value, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_literal;
expr._u._literal._value = new CPPExpression(value);
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
literal(long double value, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_literal;
expr._u._literal._value = new CPPExpression(value);
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
literal(CPPExpression *value, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_literal;
expr._u._literal._value = value;
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named raw_literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
raw_literal(const string &raw, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_raw_literal;
expr._str = raw;
expr._u._literal._value = (CPPExpression *)NULL;
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::get_nullptr
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
const CPPExpression &CPPExpression::
get_nullptr() {
static CPPExpression expr(0);
expr._type = T_nullptr;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
~CPPExpression() {
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::evaluate
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::Result CPPExpression::
evaluate() const {
Result r1, r2;
switch (_type) {
case T_nullptr:
return Result((void *)0);
case T_integer:
return Result((int)_u._integer);
case T_real:
return Result((double)_u._real);
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return Result();
case T_variable:
if (_u._variable->_type != NULL &&
_u._variable->_initializer != NULL) {
// A const variable. Fetch its assigned value.
CPPConstType *const_type = _u._variable->_type->as_const_type();
if (const_type != NULL) {
return _u._variable->_initializer->evaluate();
}
}
return Result();
case T_function:
return Result();
case T_unknown_ident:
return Result();
case T_typecast:
assert(_u._typecast._op1 != NULL);
r1 = _u._typecast._op1->evaluate();
if (r1._type != RT_error) {
CPPSimpleType *stype = _u._typecast._to->as_simple_type();
if (stype != NULL) {
if (stype->_type == CPPSimpleType::T_int) {
return Result(r1.as_integer());
} else if (stype->_type == CPPSimpleType::T_float ||
stype->_type == CPPSimpleType::T_double) {
return Result(r1.as_real());
}
}
if (_u._typecast._to->as_pointer_type()) {
return Result(r1.as_pointer());
}
}
return Result();
case T_construct:
case T_default_construct:
case T_new:
case T_default_new:
case T_sizeof:
return Result();
case T_alignof:
if (_u._typecast._to != NULL) {
// Check if the type is defined with an alignas. TODO: this should
// probably be moved to a virtual getter on CPPType.
CPPExtensionType *etype = _u._typecast._to->as_extension_type();
if (etype != NULL && etype->_alignment != NULL) {
return etype->_alignment->evaluate();
}
}
return Result();
case T_binary_operation:
assert(_u._op._op2 != NULL);
r2 = _u._op._op2->evaluate();
// The operators && and || are special cases: these are
// shirt-circuiting operators. Thus, if we are using either of
// these it might be acceptable for the second operand to be
// invalid, since we might never evaluate it.
// In all other cases, both operands must be valid in order for
// the operation to be valid.
if (r2._type == RT_error &&
(_u._op._operator != OROR && _u._op._operator != ANDAND)) {
return r2;
}
// Fall through
case T_trinary_operation:
// The trinary operator is also a short-circuiting operator: we
// don't test the second or third operands until we need them.
// The only critical one is the first operand.
// Fall through
case T_unary_operation:
assert(_u._op._op1 != NULL);
r1 = _u._op._op1->evaluate();
if (r1._type == RT_error) {
// Here's one more special case: if the first operand is
// invalid, it really means we don't know how to evaluate it.
// However, if the operator is ||, then it might not matter as
// long as we can evaluate the second one *and* that comes out
// to be true.
if (_u._op._operator == OROR && r2._type == RT_integer &&
r2.as_integer() != 0) {
return r2;
}
// Ditto for the operator being && and the second one coming out
// false.
if (_u._op._operator == ANDAND && r2._type == RT_integer &&
r2.as_integer() == 0) {
return r2;
}
return r1;
}
switch (_u._op._operator) {
case UNARY_NOT:
return Result(!r1.as_integer());
case UNARY_NEGATE:
return Result(~r1.as_integer());
case UNARY_MINUS:
return (r1._type == RT_real) ? Result(-r1.as_real()) : Result(-r1.as_integer());
case UNARY_STAR:
case UNARY_REF:
return Result();
case '*':
if (r1._type == RT_real || r2._type == RT_real) {
return Result(r1.as_real() * r2.as_real());
} else {
return Result(r1.as_integer() * r2.as_integer());
}
case '/':
if (r1._type == RT_real || r2._type == RT_real) {
return Result(r1.as_real() / r2.as_real());
} else {
return Result(r1.as_integer() / r2.as_integer());
}
case '%':
return Result(r1.as_integer() % r2.as_integer());
case '+':
if (r1._type == RT_real || r2._type == RT_real) {
return Result(r1.as_real() + r2.as_real());
} else {
return Result(r1.as_integer() + r2.as_integer());
}
case '-':
if (r1._type == RT_real || r2._type == RT_real) {
return Result(r1.as_real() - r2.as_real());
} else {
return Result(r1.as_integer() - r2.as_integer());
}
case '|':
return Result(r1.as_integer() | r2.as_integer());
case '&':
return Result(r1.as_integer() & r2.as_integer());
case OROR:
if (r1.as_integer()) {
return r1;
} else {
return r2;
}
case ANDAND:
if (r1.as_integer()) {
return r2;
} else {
return r1;
}
case EQCOMPARE:
if (r1._type == RT_real || r2._type == RT_real) {
return Result(r1.as_real() == r2.as_real());
} else {
return Result(r1.as_integer() == r2.as_integer());
}
case NECOMPARE:
if (r1._type == RT_real || r2._type == RT_real) {
return Result(r1.as_real() != r2.as_real());
} else {
return Result(r1.as_integer() != r2.as_integer());
}
case LECOMPARE:
if (r1._type == RT_real || r2._type == RT_real) {
return Result(r1.as_real() <= r2.as_real());
} else {
return Result(r1.as_integer() <= r2.as_integer());
}
case GECOMPARE:
if (r1._type == RT_real || r2._type == RT_real) {
return Result(r1.as_real() >= r2.as_real());
} else {
return Result(r1.as_integer() >= r2.as_integer());
}
case '<':
if (r1._type == RT_real || r2._type == RT_real) {
return Result(r1.as_real() < r2.as_real());
} else {
return Result(r1.as_integer() < r2.as_integer());
}
case '>':
if (r1._type == RT_real || r2._type == RT_real) {
return Result(r1.as_real() > r2.as_real());
} else {
return Result(r1.as_integer() > r2.as_integer());
}
case LSHIFT:
return Result(r1.as_integer() << r2.as_integer());
case RSHIFT:
return Result(r1.as_integer() >> r2.as_integer());
case '?':
return r1.as_integer() ?
_u._op._op2->evaluate() : _u._op._op3->evaluate();
case '.':
case POINTSAT:
return Result();
case '[': // Array element reference
return Result();
case 'f': // Function evaluation
return Result();
case ',':
return r2;
default:
cerr << "**unexpected operator**\n";
abort();
}
case T_literal:
case T_raw_literal:
return Result();
default:
cerr << "**invalid operand**\n";
abort();
}
return Result(); // Compiler kludge; can't get here.
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::determine_type
// Access: Public
// Description: Returns the type of the expression, if it is known,
// or NULL if the type cannot be determined.
////////////////////////////////////////////////////////////////////
CPPType *CPPExpression::
determine_type() const {
CPPType *t1 = (CPPType *)NULL;
CPPType *t2 = (CPPType *)NULL;
static CPPType *nullptr_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_nullptr));
static CPPType *int_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int));
static CPPType *unsigned_long_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_unsigned |
CPPSimpleType::F_long));
static CPPType *bool_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_bool));
static CPPType *float_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_double));
static CPPType *char_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char));
static CPPType *wchar_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t));
static CPPType *char16_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char16_t));
static CPPType *char32_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char32_t));
static CPPType *char_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(char_type))));
static CPPType *wchar_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(wchar_type))));
static CPPType *char16_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(char16_type))));
static CPPType *char32_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(char32_type))));
switch (_type) {
case T_nullptr:
return nullptr_type;
case T_integer:
return int_type;
case T_real:
return float_type;
case T_string:
return char_str_type;
case T_wstring:
return wchar_str_type;
case T_u8string:
return char_str_type;
case T_u16string:
return char16_str_type;
case T_u32string:
return char32_str_type;
case T_variable:
return _u._variable->_type;
case T_function:
if (_u._fgroup->get_return_type() == (CPPType *)NULL) {
// There are multiple functions by this name that have different
// return types. We could attempt to differentiate them based
// on the parameter list, but that's a lot of work. Let's just
// give up.
return (CPPType *)NULL;
}
return _u._fgroup->_instances.front()->_type;
case T_unknown_ident:
return (CPPType *)NULL;
case T_typecast:
case T_construct:
case T_default_construct:
return _u._typecast._to;
case T_new:
case T_default_new:
return CPPType::new_type(new CPPPointerType(_u._typecast._to));
case T_sizeof:
case T_alignof:
// Note: this should actually be size_t, but that is defined as a
// typedef in parser-inc. We could try to resolve it, but that's
// hacky. Eh, it's probably not worth the effort to get this right.
return unsigned_long_type;
case T_binary_operation:
case T_trinary_operation:
assert(_u._op._op2 != NULL);
t2 = _u._op._op2->determine_type();
// Fall through
case T_unary_operation:
assert(_u._op._op1 != NULL);
t1 = _u._op._op1->determine_type();
switch (_u._op._operator) {
case UNARY_NOT:
return bool_type;
case UNARY_NEGATE:
return int_type;
case UNARY_MINUS:
return t1;
case UNARY_STAR:
case '[': // Array element reference
if (t1 != NULL) {
if (t1->as_pointer_type()) {
return t1->as_pointer_type()->_pointing_at;
}
if (t1->as_array_type()) {
return t1->as_array_type()->_element_type;
}
}
return NULL;
case UNARY_REF:
return t1;
case '*':
case '/':
case '+':
case '-':
if (t1 == NULL) {
return t2;
} else if (t2 == NULL) {
return t1;
} else if (t1->as_pointer_type()) {
if (t2->as_pointer_type()) {
return int_type;
}
return t1;
}
return elevate_type(t1, t2);
case '%':
case '|':
case '&':
case LSHIFT:
case RSHIFT:
return int_type;
case OROR:
case ANDAND:
case EQCOMPARE:
case NECOMPARE:
case LECOMPARE:
case GECOMPARE:
case '<':
case '>':
return bool_type;
case '?':
return t2;
case '.':
case POINTSAT:
return NULL;
case 'f': // Function evaluation
if (t1 != NULL) {
CPPFunctionType *ftype = t1->as_function_type();
if (ftype != (CPPFunctionType *)NULL) {
return ftype->_return_type;
}
}
return NULL;
case ',':
return t2;
default:
cerr << "**unexpected operator**\n";
abort();
}
case T_literal:
case T_raw_literal:
if (_u._literal._operator != NULL) {
CPPType *type = _u._literal._operator->_type;
CPPFunctionType *ftype = type->as_function_type();
if (ftype != (CPPFunctionType *)NULL) {
return ftype->_return_type;
}
}
return NULL;
default:
cerr << "**invalid operand**\n";
abort();
}
return NULL; // Compiler kludge; can't get here.
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::is_fully_specified
// Access: Public, Virtual
// Description: 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 CPPExpression::
is_fully_specified() const {
if (!CPPDeclaration::is_fully_specified()) {
return false;
}
switch (_type) {
case T_nullptr:
case T_integer:
case T_real:
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return false;
case T_variable:
return _u._variable->is_fully_specified();
case T_function:
return _u._fgroup->is_fully_specified();
case T_unknown_ident:
return _u._ident->is_fully_specified();
case T_typecast:
case T_construct:
case T_new:
return (_u._typecast._to->is_fully_specified() &&
_u._typecast._op1->is_fully_specified());
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to->is_fully_specified();
case T_trinary_operation:
if (!_u._op._op3->is_fully_specified()) {
return false;
}
// Fall through
case T_binary_operation:
if (!_u._op._op2->is_fully_specified()) {
return false;
}
// Fall through
case T_unary_operation:
return _u._op._op1->is_fully_specified();
case T_literal:
return _u._literal._value->is_fully_specified() &&
_u._literal._operator->is_fully_specified();
case T_raw_literal:
return _u._literal._value->is_fully_specified();
default:
return true;
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::substitute_decl
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CPPDeclaration *CPPExpression::
substitute_decl(CPPDeclaration::SubstDecl &subst,
CPPScope *current_scope, CPPScope *global_scope) {
CPPDeclaration *top =
CPPDeclaration::substitute_decl(subst, current_scope, global_scope);
if (top != this) {
return top;
}
CPPExpression *rep = new CPPExpression(*this);
bool any_changed = false;
CPPDeclaration *decl;
switch (_type) {
case T_variable:
decl = _u._variable->substitute_decl(subst, current_scope, global_scope);
if (decl != rep->_u._variable) {
if (decl->as_instance()) {
// Replacing the variable reference with another variable reference.
rep->_u._variable = decl->as_instance();
any_changed = true;
} else if (decl->as_expression()) {
// Replacing the variable reference with an expression.
delete rep;
rep = decl->as_expression();
any_changed = true;
}
}
break;
case T_unknown_ident:
rep->_u._ident = _u._ident->substitute_decl(subst, current_scope, global_scope);
any_changed = any_changed || (rep->_u._ident != _u._ident);
// See if we can define it now.
decl = rep->_u._ident->find_symbol(current_scope, global_scope, subst);
if (decl != NULL) {
CPPInstance *inst = decl->as_instance();
if (inst != NULL) {
rep->_type = T_variable;
rep->_u._variable = inst;
any_changed = true;
decl = inst->substitute_decl(subst, current_scope, global_scope);
if (decl != inst) {
if (decl->as_instance()) {
// Replacing the variable reference with another variable reference.
rep->_u._variable = decl->as_instance();
} else if (decl->as_expression()) {
// Replacing the variable reference with an expression.
delete rep;
rep = decl->as_expression();
}
}
break;
}
CPPFunctionGroup *fgroup = decl->as_function_group();
if (fgroup != NULL) {
rep->_type = T_function;
rep->_u._fgroup = fgroup;
any_changed = true;
}
}
break;
case T_typecast:
case T_construct:
case T_new:
rep->_u._typecast._op1 =
_u._typecast._op1->substitute_decl(subst, current_scope, global_scope)
->as_expression();
any_changed = any_changed || (rep->_u._typecast._op1 != _u._typecast._op1);
// fall through
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
rep->_u._typecast._to =
_u._typecast._to->substitute_decl(subst, current_scope, global_scope)
->as_type();
any_changed = any_changed || (rep->_u._typecast._to != _u._typecast._to);
break;
case T_trinary_operation:
rep->_u._op._op3 =
_u._op._op3->substitute_decl(subst, current_scope, global_scope)
->as_expression();
any_changed = any_changed || (rep->_u._op._op3 != _u._op._op3);
// fall through
case T_binary_operation:
rep->_u._op._op2 =
_u._op._op2->substitute_decl(subst, current_scope, global_scope)
->as_expression();
any_changed = any_changed || (rep->_u._op._op2 != _u._op._op2);
// fall through
case T_unary_operation:
rep->_u._op._op1 =
_u._op._op1->substitute_decl(subst, current_scope, global_scope)
->as_expression();
any_changed = any_changed || (rep->_u._op._op1 != _u._op._op1);
break;
default:
break;
}
if (!any_changed) {
delete rep;
rep = this;
}
subst.insert(SubstDecl::value_type(this, rep));
return rep;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::is_tbd
// Access: Public
// Description: Returns true if any type within the expression list is
// a CPPTBDType and thus isn't fully determined right
// now.
////////////////////////////////////////////////////////////////////
bool CPPExpression::
is_tbd() const {
switch (_type) {
case T_variable:
if (_u._variable->_type != NULL &&
_u._variable->_initializer != NULL) {
CPPConstType *const_type = _u._variable->_type->as_const_type();
if (const_type != NULL) {
return false;
}
}
return true;
case T_unknown_ident:
return true;
case T_typecast:
case T_construct:
case T_new:
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to->is_tbd();
case T_trinary_operation:
if (_u._op._op3->is_tbd()) {
return true;
}
// fall through
case T_binary_operation:
if (_u._op._op2->is_tbd()) {
return true;
}
// fall through
case T_unary_operation:
if (_u._op._op1->is_tbd()) {
return true;
}
return false;
default:
return false;
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void CPPExpression::
output(ostream &out, int indent_level, CPPScope *scope, bool) const {
switch (_type) {
case T_nullptr:
out << "nullptr";
break;
case T_integer:
out << _u._integer;
break;
case T_real:
{
// We use our own dtoa implementation here because it guarantees
// to never format the number as an integer.
char buffer[32];
pdtoa(_u._real, buffer);
out << buffer;
}
break;
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
{
switch (_type) {
case T_wstring:
out << 'L';
break;
case T_u8string:
out << "u8";
break;
case T_u16string:
out << "u";
break;
case T_u32string:
out << "U";
break;
default:
break;
}
// We don't really care about preserving the encoding for now.
out << '"';
string::const_iterator si;
for (si = _str.begin(); si != _str.end(); ++si) {
switch (*si) {
case '\n':
out << "\\n";
break;
case '\t':
out << "\\t";
break;
case '\r':
out << "\\r";
break;
case '\a':
out << "\\a";
break;
case '"':
out << "\\\"";
break;
default:
if (isprint(*si)) {
out << *si;
} else {
out << '\\' << oct << setw(3) << setfill('0') << (int)(*si)
<< dec << setw(0);
}
}
}
}
out << '"';
break;
case T_variable:
// We can just refer to the variable by name, except if it's a
// private constant, in which case we have to compute the value,
// since we may have to use it in generated code.
if (_u._variable->_type != NULL &&
_u._variable->_initializer != NULL &&
_u._variable->_vis > V_public) {
// A const variable. Fetch its assigned value.
CPPConstType *const_type = _u._variable->_type->as_const_type();
if (const_type != NULL) {
_u._variable->_initializer->output(out, indent_level, scope, false);
break;
}
}
_u._variable->_ident->output(out, scope);
break;
case T_function:
out << _u._fgroup->_name;
break;
case T_unknown_ident:
_u._ident->output(out, scope);
break;
case T_typecast:
out << "(";
_u._typecast._to->output(out, indent_level, scope, false);
out << ")(";
_u._typecast._op1->output(out, indent_level, scope, false);
out << ")";
break;
case T_construct:
_u._typecast._to->output(out, indent_level, scope, false);
out << "(";
_u._typecast._op1->output(out, indent_level, scope, false);
out << ")";
break;
case T_default_construct:
_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);
out << "(";
_u._typecast._op1->output(out, indent_level, scope, false);
out << "))";
break;
case T_default_new:
out << "(new ";
_u._typecast._to->output(out, indent_level, scope, false);
out << "())";
break;
case T_sizeof:
out << "sizeof(";
_u._typecast._to->output(out, indent_level, scope, false);
out << ")";
break;
case T_alignof:
out << "alignof(";
_u._typecast._to->output(out, indent_level, scope, false);
out << ")";
break;
case T_unary_operation:
switch (_u._op._operator) {
case UNARY_NOT:
out << "(! ";
_u._op._op1->output(out, indent_level, scope, false);
out << ")";
break;
case UNARY_NEGATE:
out << "(~ ";
_u._op._op1->output(out, indent_level, scope, false);
out << ")";
break;
case UNARY_MINUS:
out << '-';
_u._op._op1->output(out, indent_level, scope, false);
break;
case UNARY_STAR:
out << "(* ";
_u._op._op1->output(out, indent_level, scope, false);
out << ")";
break;
case UNARY_REF:
out << "(& ";
_u._op._op1->output(out, indent_level, scope, false);
out << ")";
break;
case 'f': // Function evaluation, no parameters.
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << "())";
break;
default:
out << "(" << (char)_u._op._operator << " ";
_u._op._op1->output(out, indent_level, scope, false);
out << ")";
break;
}
break;
case T_binary_operation:
switch (_u._op._operator) {
case OROR:
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << " || ";
_u._op._op2->output(out, indent_level, scope, false);
out << ")";
break;
case ANDAND:
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << " && ";
_u._op._op2->output(out, indent_level, scope, false);
out << ")";
break;
case EQCOMPARE:
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << " == ";
_u._op._op2->output(out, indent_level, scope, false);
out << ")";
break;
case NECOMPARE:
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << " != ";
_u._op._op2->output(out, indent_level, scope, false);
out << ")";
break;
case LECOMPARE:
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << " <= ";
_u._op._op2->output(out, indent_level, scope, false);
out << ")";
break;
case GECOMPARE:
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << " >= ";
_u._op._op2->output(out, indent_level, scope, false);
out << ")";
break;
case LSHIFT:
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << " << ";
_u._op._op2->output(out, indent_level, scope, false);
out << ")";
break;
case RSHIFT:
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << " >> ";
_u._op._op2->output(out, indent_level, scope, false);
out << ")";
break;
case '.':
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << ".";
_u._op._op2->output(out, indent_level, scope, false);
out << ")";
break;
case POINTSAT:
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << "->";
_u._op._op2->output(out, indent_level, scope, false);
out << ")";
break;
case '[': // Array element reference
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << "[";
_u._op._op2->output(out, indent_level, scope, false);
out << "])";
break;
case 'f': // Function evaluation
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << "(";
_u._op._op2->output(out, indent_level, scope, false);
out << "))";
break;
case ',': // Comma, no parens are used
_u._op._op1->output(out, indent_level, scope, false);
out << ", ";
_u._op._op2->output(out, indent_level, scope, false);
break;
default:
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << " " << (char)_u._op._operator << " ";
_u._op._op2->output(out, indent_level, scope, false);
out << ")";
}
break;
case T_trinary_operation:
out << "(";
_u._op._op1->output(out, indent_level, scope, false);
out << " ? ";
_u._op._op2->output(out, indent_level, scope, false);
out << " : ";
_u._op._op3->output(out, indent_level, scope, false);
out << ")";
break;
case T_literal:
_u._literal._value->output(out, indent_level, scope, false);
if (_u._literal._operator != NULL) {
string name = _u._literal._operator->get_simple_name();
assert(name.substr(0, 12) == "operator \"\" ");
out << name.substr(12);
}
break;
case T_raw_literal:
out << _str;
if (_u._literal._operator != NULL) {
string name = _u._literal._operator->get_simple_name();
assert(name.substr(0, 12) == "operator \"\" ");
out << name.substr(12);
}
break;
default:
out << "(** invalid operand type " << (int)_type << " **)";
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::get_subtype
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CPPDeclaration::SubType CPPExpression::
get_subtype() const {
return ST_expression;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::as_expression
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression *CPPExpression::
as_expression() {
return this;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::elevate_type
// Access: Public, Static
// Description: Returns the most general of the two given types.
////////////////////////////////////////////////////////////////////
CPPType *CPPExpression::
elevate_type(CPPType *t1, CPPType *t2) {
CPPSimpleType *st1 = t1->as_simple_type();
CPPSimpleType *st2 = t2->as_simple_type();
if (st1 == NULL || st2 == NULL) {
// Nothing we can do about this. Who knows?
return NULL;
}
if (st1->_type == st2->_type) {
// They have the same type, so return the one with the largest
// flag bits.
if (st1->_flags & CPPSimpleType::F_longlong) {
return st1;
} else if (st2->_flags & CPPSimpleType::F_longlong) {
return st2;
} else if (st1->_flags & CPPSimpleType::F_long) {
return st1;
} else if (st2->_flags & CPPSimpleType::F_long) {
return st2;
} else if (st1->_flags & CPPSimpleType::F_short) {
return st2;
} else if (st2->_flags & CPPSimpleType::F_short) {
return st1;
}
return st1;
}
// They have different types.
if (st1->_type == CPPSimpleType::T_float ||
st1->_type == CPPSimpleType::T_double) {
return st1;
} else if (st2->_type == CPPSimpleType::T_float ||
st2->_type == CPPSimpleType::T_double) {
return st2;
} else if (st1->_type == CPPSimpleType::T_int) {
return st1;
} else if (st2->_type == CPPSimpleType::T_int) {
return st2;
} else if (st1->_type == CPPSimpleType::T_bool) {
return st1;
} else if (st2->_type == CPPSimpleType::T_bool) {
return st2;
}
return st1;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::is_equal
// Access: Protected, Virtual
// Description: Called by CPPDeclaration to determine whether this
// expr is equivalent to another expr.
////////////////////////////////////////////////////////////////////
bool CPPExpression::
is_equal(const CPPDeclaration *other) const {
const CPPExpression *ot = ((CPPDeclaration *)other)->as_expression();
assert(ot != NULL);
if (_type != ot->_type) {
return false;
}
switch (_type) {
case T_nullptr:
return true;
case T_integer:
return _u._integer == ot->_u._integer;
case T_real:
return _u._real == ot->_u._real;
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return _str == ot->_str;
case T_variable:
return _u._variable == ot->_u._variable;
case T_function:
return _u._fgroup == ot->_u._fgroup;
case T_unknown_ident:
return *_u._ident == *ot->_u._ident;
case T_typecast:
case T_construct:
case T_new:
return _u._typecast._to == ot->_u._typecast._to &&
*_u._typecast._op1 == *ot->_u._typecast._op1;
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to == ot->_u._typecast._to;
case T_unary_operation:
return *_u._op._op1 == *ot->_u._op._op1;
case T_binary_operation:
return *_u._op._op1 == *ot->_u._op._op1 &&
*_u._op._op2 == *ot->_u._op._op2;
case T_trinary_operation:
return *_u._op._op1 == *ot->_u._op._op1 &&
*_u._op._op2 == *ot->_u._op._op2;
case T_literal:
return *_u._literal._value == *ot->_u._literal._value &&
_u._literal._operator == ot->_u._literal._operator;
case T_raw_literal:
return _str == ot->_str &&
_u._literal._operator == ot->_u._literal._operator;
default:
cerr << "(** invalid operand type " << (int)_type << " **)";
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::is_less
// Access: Protected, Virtual
// Description: Called by CPPDeclaration to determine whether this
// expr should be ordered before another expr of the
// same type, in an arbitrary but fixed ordering.
////////////////////////////////////////////////////////////////////
bool CPPExpression::
is_less(const CPPDeclaration *other) const {
const CPPExpression *ot = ((CPPDeclaration *)other)->as_expression();
assert(ot != NULL);
if (_type != ot->_type) {
return (int)_type < (int)ot->_type;
}
switch (_type) {
case T_nullptr:
return false;
case T_integer:
return _u._integer < ot->_u._integer;
case T_real:
return _u._real < ot->_u._real;
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return _str < ot->_str;
case T_variable:
return _u._variable < ot->_u._variable;
case T_function:
return *_u._fgroup < *ot->_u._fgroup;
case T_unknown_ident:
return *_u._ident < *ot->_u._ident;
case T_typecast:
case T_construct:
case T_new:
if (_u._typecast._to != ot->_u._typecast._to) {
return _u._typecast._to < ot->_u._typecast._to;
}
return *_u._typecast._op1 < *ot->_u._typecast._op1;
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to < ot->_u._typecast._to;
case T_trinary_operation:
if (*_u._op._op3 != *ot->_u._op._op3) {
return *_u._op._op3 < *ot->_u._op._op3;
}
// Fall through
case T_binary_operation:
if (*_u._op._op2 != *ot->_u._op._op2) {
return *_u._op._op2 < *ot->_u._op._op2;
}
// Fall through
case T_unary_operation:
return *_u._op._op1 < *ot->_u._op._op1;
case T_literal:
if (_u._literal._operator != ot->_u._literal._operator) {
return _u._literal._operator < ot->_u._literal._operator;
}
return *_u._literal._value < *ot->_u._literal._value;
case T_raw_literal:
if (_u._literal._operator != ot->_u._literal._operator) {
return _u._literal._operator < ot->_u._literal._operator;
}
return _str < ot->_str;
default:
cerr << "(** invalid operand type " << (int)_type << " **)";
}
return false;
}