in compiler/cpp/src/thrift/main.cc [733:856]
void validate_const_rec(std::string name, t_type* type, t_const_value* value) {
if (type->is_void()) {
throw "type error: cannot declare a void const: " + name;
}
if (type->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
switch (tbase) {
case t_base_type::TYPE_STRING:
if (value->get_type() != t_const_value::CV_STRING) {
throw "type error: const \"" + name + "\" was declared as string";
}
break;
case t_base_type::TYPE_UUID:
if (value->get_type() != t_const_value::CV_STRING) {
throw "type error: const \"" + name + "\" was declared as uuid";
}
value->set_uuid(value->get_uuid()); // validates constant
break;
case t_base_type::TYPE_BOOL:
if (value->get_type() != t_const_value::CV_INTEGER) {
throw "type error: const \"" + name + "\" was declared as bool";
}
break;
case t_base_type::TYPE_I8:
if (value->get_type() != t_const_value::CV_INTEGER) {
throw "type error: const \"" + name + "\" was declared as byte";
}
break;
case t_base_type::TYPE_I16:
if (value->get_type() != t_const_value::CV_INTEGER) {
throw "type error: const \"" + name + "\" was declared as i16";
}
break;
case t_base_type::TYPE_I32:
if (value->get_type() != t_const_value::CV_INTEGER) {
throw "type error: const \"" + name + "\" was declared as i32";
}
break;
case t_base_type::TYPE_I64:
if (value->get_type() != t_const_value::CV_INTEGER) {
throw "type error: const \"" + name + "\" was declared as i64";
}
break;
case t_base_type::TYPE_DOUBLE:
if (value->get_type() != t_const_value::CV_INTEGER
&& value->get_type() != t_const_value::CV_DOUBLE) {
throw "type error: const \"" + name + "\" was declared as double";
}
break;
default:
throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase) + name;
}
} else if (type->is_enum()) {
if (value->get_type() != t_const_value::CV_IDENTIFIER) {
throw "type error: const \"" + name + "\" was declared as enum";
}
// see if there's a dot in the identifier
std::string name_portion = value->get_identifier_name();
const vector<t_enum_value*>& enum_values = ((t_enum*)type)->get_constants();
vector<t_enum_value*>::const_iterator c_iter;
bool found = false;
for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
if ((*c_iter)->get_name() == name_portion) {
found = true;
break;
}
}
if (!found) {
throw "type error: const " + name + " was declared as type " + type->get_name()
+ " which is an enum, but " + value->get_identifier()
+ " is not a valid value for that enum";
}
} else if (type->is_struct() || type->is_xception()) {
if (value->get_type() != t_const_value::CV_MAP) {
throw "type error: const \"" + name + "\" was declared as struct/xception";
}
const vector<t_field*>& fields = ((t_struct*)type)->get_members();
vector<t_field*>::const_iterator f_iter;
const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
if (v_iter->first->get_type() != t_const_value::CV_STRING) {
throw "type error: " + name + " struct key must be string";
}
t_type* field_type = nullptr;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if ((*f_iter)->get_name() == v_iter->first->get_string()) {
field_type = (*f_iter)->get_type();
}
}
if (field_type == nullptr) {
throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
}
validate_const_rec(name + "." + v_iter->first->get_string(), field_type, v_iter->second);
}
} else if (type->is_map()) {
t_type* k_type = ((t_map*)type)->get_key_type();
t_type* v_type = ((t_map*)type)->get_val_type();
const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
validate_const_rec(name + "<key>", k_type, v_iter->first);
validate_const_rec(name + "<val>", v_type, v_iter->second);
}
} else if (type->is_list() || type->is_set()) {
t_type* e_type;
if (type->is_list()) {
e_type = ((t_list*)type)->get_elem_type();
} else {
e_type = ((t_set*)type)->get_elem_type();
}
const vector<t_const_value*>& val = value->get_list();
vector<t_const_value*>::const_iterator v_iter;
for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
validate_const_rec(name + "<elem>", e_type, *v_iter);
}
}
}