@@ -371,8 +371,14 @@ t_whisker_generator::make_prototype_for_const_value(
371371 const prototype_database& proto) const {
372372 prototype_builder<h_const_value> def;
373373 using cv = t_const_value::t_const_value_kind;
374- def.property (" type" , [&proto](const t_const_value& self) {
375- return resolve_derived_t_type (proto, self.ttype ().deref ());
374+ def.property (" type" , [this , &proto](const t_const_value& self) {
375+ // Prioritize AST populated ttype, fallback to inferred expected type in
376+ // context
377+ const t_type_ref& type = self.ttype ().empty ()
378+ ? context ().get_const_value_type (self)
379+ : self.ttype ();
380+ return type.empty () ? whisker::make::null
381+ : resolve_derived_t_type (proto, type.deref ());
376382 });
377383 def.property (" bool?" , [](const t_const_value& self) {
378384 return self.kind () == cv::CV_BOOL;
@@ -501,6 +507,20 @@ t_whisker_generator::make_prototype_for_const_value(
501507 }
502508 return w::array (result);
503509 });
510+ def.property (" owner" , mem_fn (&t_const_value::get_owner, proto.of <t_const>()));
511+ def.function (
512+ " referenceable_from?" ,
513+ [](const t_const_value& self, function::context ctx) {
514+ ctx.declare_arity (1 );
515+ ctx.declare_named_arguments ({});
516+ const t_const* from_const =
517+ ctx.raw ().positional_arguments ()[0 ].is_null ()
518+ ? nullptr
519+ : ctx.argument <whisker::native_handle<t_const>>(0 ).ptr ().get ();
520+ // value can be referenced if it is not anonymous, and is being
521+ // referenced from any const that's not the owner
522+ return self.get_owner () != nullptr && self.get_owner () != from_const;
523+ });
504524
505525 return std::move (def).make ();
506526}
@@ -1095,4 +1115,73 @@ void t_whisker_generator::render_to_file(
10951115 write_to_file (output_file, render (template_file, context));
10961116}
10971117
1118+ void whisker_generator_context::register_visitors (
1119+ t_whisker_generator::context_visitor& visitor) {
1120+ using context = t_whisker_generator::whisker_generator_visitor_context;
1121+ visitor.add_interface_visitor (
1122+ [this ](const context&, const t_interface& node) {
1123+ for (const t_function& function : node.functions ()) {
1124+ function_parents_[&function] = &node;
1125+ }
1126+ });
1127+ visitor.add_structured_definition_visitor (
1128+ [this ](const context&, const t_structured& node) {
1129+ for (const t_field& field : node.fields ()) {
1130+ field_parents_[&field] = &node;
1131+ }
1132+ });
1133+
1134+ visitor.add_const_visitor ([this ](const context&, const t_const& node) {
1135+ if (node.value () != nullptr ) {
1136+ visit_const_value (node.value (), node.type_ref ());
1137+ }
1138+ });
1139+ visitor.add_field_visitor ([this ](const context&, const t_field& node) {
1140+ if (node.default_value () != nullptr ) {
1141+ visit_const_value (node.default_value (), node.type ());
1142+ }
1143+ });
1144+ visitor.add_function_param_visitor (
1145+ [this ](const context&, const t_field& node) {
1146+ if (node.default_value () != nullptr ) {
1147+ visit_const_value (node.default_value (), node.type ());
1148+ }
1149+ });
1150+ }
1151+
1152+ void whisker_generator_context::visit_const_value (
1153+ const t_const_value* value, const t_type_ref& expected_type) {
1154+ if (value == nullptr || expected_type.empty ()) {
1155+ return ;
1156+ }
1157+
1158+ const_value_types_[value] = expected_type;
1159+ if (const auto * map = expected_type->try_as <t_map>();
1160+ map != nullptr && value->kind () == t_const_value::CV_MAP) {
1161+ for (const auto & [key, val] : value->get_map ()) {
1162+ visit_const_value (key, map->key_type ());
1163+ visit_const_value (val, map->val_type ());
1164+ }
1165+ } else if (const auto * list = expected_type->try_as <t_list>();
1166+ list != nullptr && value->kind () == t_const_value::CV_LIST) {
1167+ for (const t_const_value* val : value->get_list ()) {
1168+ visit_const_value (val, list->elem_type ());
1169+ }
1170+ } else if (const auto * set = expected_type->try_as <t_set>();
1171+ set != nullptr && value->kind () == t_const_value::CV_LIST) {
1172+ for (const t_const_value* val : value->get_list ()) {
1173+ visit_const_value (val, set->elem_type ());
1174+ }
1175+ } else if (const auto * structured = expected_type->try_as <t_structured>();
1176+ structured != nullptr && value->kind () == t_const_value::CV_MAP) {
1177+ for (const auto & [key, val] : value->get_map ()) {
1178+ if (const t_field* field = key->kind () == t_const_value::CV_STRING
1179+ ? structured->get_field_by_name (key->get_string ())
1180+ : nullptr ) {
1181+ visit_const_value (val, field->type ());
1182+ }
1183+ }
1184+ }
1185+ }
1186+
10981187} // namespace apache::thrift::compiler
0 commit comments