1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <iomanip>
20 #include <map>
21 #include <memory>
22 #include <sstream>
23 #include <string>
24 #include <type_traits>
25 #include <unordered_map>
26 #include <utility>
27 #include <vector>
28 
29 #include <thrift/compiler/detail/mustache/mstch.h>
30 #include <thrift/compiler/generate/t_generator.h>
31 
32 namespace apache {
33 namespace thrift {
34 namespace compiler {
35 
36 class mstch_base;
37 class mstch_generators;
38 
39 enum ELEMENT_POSITION {
40   NONE = 0,
41   FIRST = 1,
42   LAST = 2,
43   FIRST_AND_LAST = 3,
44 };
45 
46 struct mstch_cache {
47   std::map<std::string, std::string> parsed_options_;
48   std::unordered_map<std::string, std::shared_ptr<mstch_base>> enums_;
49   std::unordered_map<std::string, std::shared_ptr<mstch_base>> structs_;
50   std::unordered_map<std::string, std::shared_ptr<mstch_base>> services_;
51   std::unordered_map<std::string, std::shared_ptr<mstch_base>> programs_;
52 
clearmstch_cache53   void clear() {
54     enums_.clear();
55     structs_.clear();
56     services_.clear();
57     programs_.clear();
58   }
59 };
60 
61 class enum_value_generator {
62  public:
63   virtual ~enum_value_generator() = default;
64   virtual std::shared_ptr<mstch_base> generate(
65       t_enum_value const* enum_value,
66       std::shared_ptr<mstch_generators const> generators,
67       std::shared_ptr<mstch_cache> cache,
68       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
69       int32_t index = 0) const;
70 };
71 
72 class enum_generator {
73  public:
74   virtual ~enum_generator() = default;
75   virtual std::shared_ptr<mstch_base> generate(
76       t_enum const* enm,
77       std::shared_ptr<mstch_generators const> generators,
78       std::shared_ptr<mstch_cache> cache,
79       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
80       int32_t index = 0) const;
81 };
82 
83 class const_value_generator {
84  public:
85   const_value_generator() = default;
86   virtual ~const_value_generator() = default;
87   virtual std::shared_ptr<mstch_base> generate(
88       t_const_value const* const_value,
89       std::shared_ptr<mstch_generators const> generators,
90       std::shared_ptr<mstch_cache> cache,
91       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
92       int32_t index = 0,
93       t_const const* current_const = nullptr,
94       t_type const* expected_type = nullptr) const;
95   virtual std::shared_ptr<mstch_base> generate(
96       std::pair<t_const_value*, t_const_value*> const& value_pair,
97       std::shared_ptr<mstch_generators const> generators,
98       std::shared_ptr<mstch_cache> cache,
99       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
100       int32_t index = 0,
101       t_const const* current_const = nullptr,
102       std::pair<const t_type*, const t_type*> const& expected_types = {
103           nullptr, nullptr}) const;
104 };
105 
106 class type_generator {
107  public:
108   type_generator() = default;
109   virtual ~type_generator() = default;
110   virtual std::shared_ptr<mstch_base> generate(
111       t_type const* type,
112       std::shared_ptr<mstch_generators const> generators,
113       std::shared_ptr<mstch_cache> cache,
114       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
115       int32_t index = 0) const;
116 };
117 
118 struct field_generator_context {
119   const t_struct* strct = nullptr;
120   const t_field* prev = nullptr;
121   const t_field* next = nullptr;
122   int isset_index = -1;
123 };
124 
125 class field_generator {
126  public:
127   field_generator() = default;
128   virtual ~field_generator() = default;
129   virtual std::shared_ptr<mstch_base> generate(
130       t_field const* field,
131       std::shared_ptr<mstch_generators const> generators,
132       std::shared_ptr<mstch_cache> cache,
133       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
134       int32_t index = 0,
135       field_generator_context const* field_context = nullptr) const;
136 };
137 
138 class annotation_generator {
139  public:
140   annotation_generator() = default;
141   virtual ~annotation_generator() = default;
142   virtual std::shared_ptr<mstch_base> generate(
143       const t_annotation& annotation,
144       std::shared_ptr<mstch_generators const> generators,
145       std::shared_ptr<mstch_cache> cache,
146       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
147       int32_t index = 0) const;
148 };
149 
150 class structured_annotation_generator {
151  public:
152   structured_annotation_generator() = default;
153   virtual ~structured_annotation_generator() = default;
154   virtual std::shared_ptr<mstch_base> generate(
155       const t_const* annotValue,
156       std::shared_ptr<mstch_generators const> generators,
157       std::shared_ptr<mstch_cache> cache,
158       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
159       int32_t index = 0) const;
160 };
161 
162 class struct_generator {
163  public:
164   struct_generator() = default;
165   virtual ~struct_generator() = default;
166   virtual std::shared_ptr<mstch_base> generate(
167       t_struct const* strct,
168       std::shared_ptr<mstch_generators const> generators,
169       std::shared_ptr<mstch_cache> cache,
170       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
171       int32_t index = 0) const;
172 };
173 
174 class function_generator {
175  public:
176   function_generator() = default;
177   virtual ~function_generator() = default;
178   virtual std::shared_ptr<mstch_base> generate(
179       t_function const* function,
180       std::shared_ptr<mstch_generators const> generators,
181       std::shared_ptr<mstch_cache> cache,
182       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
183       int32_t index = 0) const;
184 };
185 
186 class service_generator {
187  public:
188   service_generator() = default;
189   virtual ~service_generator() = default;
190   virtual std::shared_ptr<mstch_base> generate(
191       t_service const* service,
192       std::shared_ptr<mstch_generators const> generators,
193       std::shared_ptr<mstch_cache> cache,
194       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
195       int32_t index = 0) const;
196 
197   std::shared_ptr<mstch_base> generate_cached(
198       t_program const* program,
199       t_service const* service,
200       std::shared_ptr<mstch_generators const> generators,
201       std::shared_ptr<mstch_cache> cache,
202       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
203       int32_t index = 0) const {
204     std::string service_id = program->path() + service->get_name();
205     auto itr = cache->services_.find(service_id);
206     if (itr == cache->services_.end()) {
207       itr = cache->services_.emplace_hint(
208           itr, service_id, generate(service, generators, cache, pos, index));
209     }
210     return itr->second;
211   }
212 };
213 
214 class typedef_generator {
215  public:
216   typedef_generator() = default;
217   virtual ~typedef_generator() = default;
218   virtual std::shared_ptr<mstch_base> generate(
219       t_typedef const* typedf,
220       std::shared_ptr<mstch_generators const> generators,
221       std::shared_ptr<mstch_cache> cache,
222       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
223       int32_t index = 0) const;
224 };
225 
226 class const_generator {
227  public:
228   const_generator() = default;
229   virtual ~const_generator() = default;
230   virtual std::shared_ptr<mstch_base> generate(
231       t_const const* cnst,
232       std::shared_ptr<mstch_generators const> generators,
233       std::shared_ptr<mstch_cache> cache,
234       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
235       int32_t index = 0,
236       t_const const* current_const = nullptr,
237       t_type const* expected_type = nullptr,
238       t_field const* field = nullptr) const;
239 };
240 
241 class program_generator {
242  public:
243   program_generator() = default;
244   virtual ~program_generator() = default;
245   virtual std::shared_ptr<mstch_base> generate(
246       t_program const* program,
247       std::shared_ptr<mstch_generators const> generators,
248       std::shared_ptr<mstch_cache> cache,
249       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
250       int32_t index = 0) const;
251 
252   std::shared_ptr<mstch_base> generate_cached(
253       t_program const* program,
254       std::shared_ptr<mstch_generators const> generators,
255       std::shared_ptr<mstch_cache> cache,
256       ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
257       int32_t index = 0) {
258     const auto& id = program->path();
259     auto itr = cache->programs_.find(id);
260     if (itr == cache->programs_.end()) {
261       itr = cache->programs_.emplace_hint(
262           itr, id, generate(program, generators, cache, pos, index));
263     }
264     return itr->second;
265   }
266 };
267 
268 class mstch_generators {
269  public:
mstch_generators()270   mstch_generators()
271       : enum_value_generator_(std::make_unique<enum_value_generator>()),
272         enum_generator_(std::make_unique<enum_generator>()),
273         const_value_generator_(std::make_unique<const_value_generator>()),
274         type_generator_(std::make_unique<type_generator>()),
275         field_generator_(std::make_unique<field_generator>()),
276         annotation_generator_(std::make_unique<annotation_generator>()),
277         structured_annotation_generator_(
278             std::make_unique<structured_annotation_generator>()),
279         struct_generator_(std::make_unique<struct_generator>()),
280         function_generator_(std::make_unique<function_generator>()),
281         service_generator_(std::make_unique<service_generator>()),
282         typedef_generator_(std::make_unique<typedef_generator>()),
283         const_generator_(std::make_unique<const_generator>()),
284         program_generator_(std::make_unique<program_generator>()) {}
285   ~mstch_generators() = default;
286 
set_enum_value_generator(std::unique_ptr<enum_value_generator> g)287   void set_enum_value_generator(std::unique_ptr<enum_value_generator> g) {
288     enum_value_generator_ = std::move(g);
289   }
290 
set_enum_generator(std::unique_ptr<enum_generator> g)291   void set_enum_generator(std::unique_ptr<enum_generator> g) {
292     enum_generator_ = std::move(g);
293   }
294 
set_const_value_generator(std::unique_ptr<const_value_generator> g)295   void set_const_value_generator(std::unique_ptr<const_value_generator> g) {
296     const_value_generator_ = std::move(g);
297   }
298 
set_type_generator(std::unique_ptr<type_generator> g)299   void set_type_generator(std::unique_ptr<type_generator> g) {
300     type_generator_ = std::move(g);
301   }
302 
set_field_generator(std::unique_ptr<field_generator> g)303   void set_field_generator(std::unique_ptr<field_generator> g) {
304     field_generator_ = std::move(g);
305   }
306 
set_annotation_generator(std::unique_ptr<annotation_generator> g)307   void set_annotation_generator(std::unique_ptr<annotation_generator> g) {
308     annotation_generator_ = std::move(g);
309   }
310 
set_struct_generator(std::unique_ptr<struct_generator> g)311   void set_struct_generator(std::unique_ptr<struct_generator> g) {
312     struct_generator_ = std::move(g);
313   }
314 
set_function_generator(std::unique_ptr<function_generator> g)315   void set_function_generator(std::unique_ptr<function_generator> g) {
316     function_generator_ = std::move(g);
317   }
318 
set_service_generator(std::unique_ptr<service_generator> g)319   void set_service_generator(std::unique_ptr<service_generator> g) {
320     service_generator_ = std::move(g);
321   }
322 
set_typedef_generator(std::unique_ptr<typedef_generator> g)323   void set_typedef_generator(std::unique_ptr<typedef_generator> g) {
324     typedef_generator_ = std::move(g);
325   }
326 
set_const_generator(std::unique_ptr<const_generator> g)327   void set_const_generator(std::unique_ptr<const_generator> g) {
328     const_generator_ = std::move(g);
329   }
330 
set_program_generator(std::unique_ptr<program_generator> g)331   void set_program_generator(std::unique_ptr<program_generator> g) {
332     program_generator_ = std::move(g);
333   }
334 
335   std::unique_ptr<enum_value_generator> enum_value_generator_;
336   std::unique_ptr<enum_generator> enum_generator_;
337   std::unique_ptr<const_value_generator> const_value_generator_;
338   std::unique_ptr<type_generator> type_generator_;
339   std::unique_ptr<field_generator> field_generator_;
340   std::unique_ptr<annotation_generator> annotation_generator_;
341   std::unique_ptr<structured_annotation_generator>
342       structured_annotation_generator_;
343   std::unique_ptr<struct_generator> struct_generator_;
344   std::unique_ptr<function_generator> function_generator_;
345   std::unique_ptr<service_generator> service_generator_;
346   std::unique_ptr<typedef_generator> typedef_generator_;
347   std::unique_ptr<const_generator> const_generator_;
348   std::unique_ptr<program_generator> program_generator_;
349 };
350 
351 class mstch_base : public mstch::object {
352  protected:
353   // A range of t_field* to avoid copying between std::vector<t_field*>
354   // and std::vector<t_field const*>.
355   class field_range {
356    public:
field_range(const std::vector<t_field * > & fields)357     /* implicit */ field_range(const std::vector<t_field*>& fields) noexcept
358         : begin_(const_cast<const t_field* const*>(fields.data())),
359           end_(const_cast<const t_field* const*>(
360               fields.data() + fields.size())) {}
field_range(const std::vector<t_field const * > & fields)361     /* implicit */ field_range(
362         const std::vector<t_field const*>& fields) noexcept
363         : begin_(fields.data()), end_(fields.data() + fields.size()) {}
size()364     constexpr size_t size() const noexcept { return end_ - begin_; }
begin()365     constexpr const t_field* const* begin() const noexcept { return begin_; }
end()366     constexpr const t_field* const* end() const noexcept { return end_; }
367 
368    private:
369     const t_field* const* begin_;
370     const t_field* const* end_;
371   };
372 
373  public:
mstch_base(std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION const pos)374   mstch_base(
375       std::shared_ptr<mstch_generators const> generators,
376       std::shared_ptr<mstch_cache> cache,
377       ELEMENT_POSITION const pos)
378       : generators_(generators), cache_(cache), pos_(pos) {
379     register_methods(
380         this,
381         {
382             {"first?", &mstch_base::first},
383             {"last?", &mstch_base::last},
384         });
385   }
386   virtual ~mstch_base() = default;
387 
first()388   mstch::node first() {
389     return pos_ == ELEMENT_POSITION::FIRST ||
390         pos_ == ELEMENT_POSITION::FIRST_AND_LAST;
391   }
last()392   mstch::node last() {
393     return pos_ == ELEMENT_POSITION::LAST ||
394         pos_ == ELEMENT_POSITION::FIRST_AND_LAST;
395   }
396 
annotations(t_named const * annotated)397   mstch::node annotations(t_named const* annotated) {
398     return generate_annotations(annotated->annotations());
399   }
400 
structured_annotations(t_named const * annotated)401   mstch::node structured_annotations(t_named const* annotated) {
402     return generate_elements(
403         annotated->structured_annotations(),
404         generators_->structured_annotation_generator_.get());
405   }
406 
element_position(size_t index,size_t length)407   static ELEMENT_POSITION element_position(size_t index, size_t length) {
408     ELEMENT_POSITION pos = ELEMENT_POSITION::NONE;
409     if (index == 0) {
410       pos = ELEMENT_POSITION::FIRST;
411     }
412     if (index == length - 1) {
413       pos = ELEMENT_POSITION::LAST;
414     }
415     if (length == 1) {
416       pos = ELEMENT_POSITION::FIRST_AND_LAST;
417     }
418     return pos;
419   }
420 
421   template <typename Container, typename Generator, typename... Args>
generate_elements(Container const & container,Generator const * generator,Args const &...args)422   mstch::array generate_elements(
423       Container const& container,
424       Generator const* generator,
425       Args const&... args) {
426     mstch::array a;
427     size_t i = 0;
428     for (auto&& element : container) {
429       auto pos = element_position(i, container.size());
430       a.push_back(
431           generator->generate(element, generators_, cache_, pos, i, args...));
432       ++i;
433     }
434     return a;
435   }
436 
437   template <typename C, typename... Args>
generate_services(C const & container,Args const &...args)438   mstch::array generate_services(C const& container, Args const&... args) {
439     return generate_elements(
440         container, generators_->service_generator_.get(), args...);
441   }
442 
443   template <typename C, typename... Args>
generate_annotations(C const & container,Args const &...args)444   mstch::array generate_annotations(C const& container, Args const&... args) {
445     return generate_elements(
446         container, generators_->annotation_generator_.get(), args...);
447   }
448 
449   template <typename C, typename... Args>
generate_enum_values(C const & container,Args const &...args)450   mstch::array generate_enum_values(C const& container, Args const&... args) {
451     return generate_elements(
452         container, generators_->enum_value_generator_.get(), args...);
453   }
454 
455   template <typename C, typename... Args>
generate_consts(C const & container,Args const &...args)456   mstch::array generate_consts(C const& container, Args const&... args) {
457     return generate_elements(
458         container, generators_->const_value_generator_.get(), args...);
459   }
460 
generate_fields(const field_range & fields)461   virtual mstch::array generate_fields(const field_range& fields) {
462     return generate_elements(fields, generators_->field_generator_.get());
463   }
464 
465   template <typename C, typename... Args>
generate_functions(C const & container,Args const &...args)466   mstch::array generate_functions(C const& container, Args const&... args) {
467     return generate_elements(
468         container, generators_->function_generator_.get(), args...);
469   }
470 
471   template <typename C, typename... Args>
generate_typedefs(C const & container,Args const &...args)472   mstch::array generate_typedefs(C const& container, Args const&... args) {
473     return generate_elements(
474         container, generators_->typedef_generator_.get(), args...);
475   }
476 
477   template <typename C, typename... Args>
generate_types(C const & container,Args const &...args)478   mstch::array generate_types(C const& container, Args const&... args) {
479     return generate_elements(
480         container, generators_->type_generator_.get(), args...);
481   }
482 
483   template <typename Item, typename Generator, typename Cache>
generate_element_cached(Item const & item,Generator const * generator,Cache & c,std::string const & id,size_t element_index,size_t element_count)484   mstch::node generate_element_cached(
485       Item const& item,
486       Generator const* generator,
487       Cache& c,
488       std::string const& id,
489       size_t element_index,
490       size_t element_count) {
491     std::string elem_id = id + item->get_name();
492     auto pos = element_position(element_index, element_count);
493     auto itr = c.find(elem_id);
494     if (itr == c.end()) {
495       itr = c.emplace_hint(
496           itr,
497           elem_id,
498           generator->generate(item, generators_, cache_, pos, element_index));
499     }
500     return itr->second;
501   }
502 
503   template <typename Container, typename Generator, typename Cache>
generate_elements_cached(Container const & container,Generator const * generator,Cache & c,std::string const & id)504   mstch::array generate_elements_cached(
505       Container const& container,
506       Generator const* generator,
507       Cache& c,
508       std::string const& id) {
509     mstch::array a;
510     for (size_t i = 0; i < container.size(); ++i) {
511       a.push_back(generate_element_cached(
512           container[i], generator, c, id, i, container.size()));
513     }
514     return a;
515   }
516 
517   bool has_option(const std::string& option) const;
518   std::string get_option(const std::string& option) const;
519 
520   // Registers has_option(option) under the given name.
521   void register_has_option(std::string key, std::string option);
522 
523  protected:
524   std::shared_ptr<mstch_generators const> generators_;
525   std::shared_ptr<mstch_cache> cache_;
526   ELEMENT_POSITION const pos_;
527 };
528 
529 class mstch_enum_value : public mstch_base {
530  public:
531   using node_type = t_enum_value;
mstch_enum_value(t_enum_value const * enm_value,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos)532   mstch_enum_value(
533       t_enum_value const* enm_value,
534       std::shared_ptr<mstch_generators const> generators,
535       std::shared_ptr<mstch_cache> cache,
536       ELEMENT_POSITION pos)
537       : mstch_base(generators, cache, pos), enm_value_(enm_value) {
538     register_methods(
539         this,
540         {
541             {"enum_value:name", &mstch_enum_value::name},
542             {"enum_value:value", &mstch_enum_value::value},
543         });
544   }
name()545   mstch::node name() { return enm_value_->get_name(); }
value()546   mstch::node value() { return std::to_string(enm_value_->get_value()); }
547 
548  protected:
549   t_enum_value const* enm_value_;
550 };
551 
552 class mstch_enum : public mstch_base {
553  public:
554   using node_type = t_enum;
mstch_enum(t_enum const * enm,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos)555   mstch_enum(
556       t_enum const* enm,
557       std::shared_ptr<mstch_generators const> generators,
558       std::shared_ptr<mstch_cache> cache,
559       ELEMENT_POSITION pos)
560       : mstch_base(generators, cache, pos), enm_(enm) {
561     register_methods(
562         this,
563         {
564             {"enum:name", &mstch_enum::name},
565             {"enum:values", &mstch_enum::values},
566             {"enum:structured_annotations",
567              &mstch_enum::structured_annotations},
568         });
569   }
570 
name()571   mstch::node name() { return enm_->get_name(); }
572   mstch::node values();
structured_annotations()573   mstch::node structured_annotations() {
574     return mstch_base::structured_annotations(enm_);
575   }
576 
577  protected:
578   t_enum const* enm_;
579 };
580 
581 class mstch_const_value : public mstch_base {
582  public:
583   using cv = t_const_value::t_const_value_type;
mstch_const_value(t_const_value const * const_value,t_const const * current_const,t_type const * expected_type,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t index)584   mstch_const_value(
585       t_const_value const* const_value,
586       t_const const* current_const,
587       t_type const* expected_type,
588       std::shared_ptr<mstch_generators const> generators,
589       std::shared_ptr<mstch_cache> cache,
590       ELEMENT_POSITION pos,
591       int32_t index)
592       : mstch_base(generators, cache, pos),
593         const_value_(const_value),
594         current_const_(current_const),
595         expected_type_(expected_type),
596         type_(const_value->get_type()),
597         index_(index) {
598     register_methods(
599         this,
600         {
601             {"value:bool?", &mstch_const_value::is_bool},
602             {"value:double?", &mstch_const_value::is_double},
603             {"value:integer?", &mstch_const_value::is_integer},
604             {"value:enum?", &mstch_const_value::is_enum},
605             {"value:enum_value?", &mstch_const_value::has_enum_value},
606             {"value:string?", &mstch_const_value::is_string},
607             {"value:string_multi_line?",
608              &mstch_const_value::is_string_multi_line},
609             {"value:base?", &mstch_const_value::is_base},
610             {"value:map?", &mstch_const_value::is_map},
611             {"value:list?", &mstch_const_value::is_list},
612             {"value:container?", &mstch_const_value::is_container},
613             {"value:empty_container?", &mstch_const_value::is_empty_container},
614             {"value:value", &mstch_const_value::value},
615             {"value:integer_value", &mstch_const_value::integer_value},
616             {"value:double_value", &mstch_const_value::double_value},
617             {"value:bool_value", &mstch_const_value::bool_value},
618             {"value:nonzero?", &mstch_const_value::is_non_zero},
619             {"value:enum_name", &mstch_const_value::enum_name},
620             {"value:enum_value_name", &mstch_const_value::enum_value_name},
621             {"value:string_value", &mstch_const_value::string_value},
622             {"value:list_elements", &mstch_const_value::list_elems},
623             {"value:map_elements", &mstch_const_value::map_elems},
624             {"value:const_struct", &mstch_const_value::const_struct},
625             {"value:const_struct?", &mstch_const_value::is_const_struct},
626             {"value:const_struct_type", &mstch_const_value::const_struct_type},
627             {"value:referenceable?", &mstch_const_value::referenceable},
628             {"value:owning_const", &mstch_const_value::owning_const},
629             {"value:enable_referencing",
630              &mstch_const_value::enable_referencing},
631         });
632   }
633 
format_double_string(const double d)634   std::string format_double_string(const double d) {
635     std::ostringstream oss;
636     oss << std::setprecision(std::numeric_limits<double>::digits10) << d;
637     return oss.str();
638   }
is_bool()639   mstch::node is_bool() { return type_ == cv::CV_BOOL; }
is_double()640   mstch::node is_double() { return type_ == cv::CV_DOUBLE; }
is_integer()641   mstch::node is_integer() {
642     return type_ == cv::CV_INTEGER && !const_value_->is_enum();
643   }
is_enum()644   mstch::node is_enum() {
645     return type_ == cv::CV_INTEGER && const_value_->is_enum();
646   }
has_enum_value()647   mstch::node has_enum_value() {
648     return const_value_->get_enum_value() != nullptr;
649   }
is_string()650   mstch::node is_string() { return type_ == cv::CV_STRING; }
is_string_multi_line()651   mstch::node is_string_multi_line() {
652     return type_ == cv::CV_STRING &&
653         const_value_->get_string().find("\n") != std::string::npos;
654   }
is_base()655   mstch::node is_base() {
656     return type_ == cv::CV_BOOL || type_ == cv::CV_DOUBLE ||
657         type_ == cv::CV_INTEGER || type_ == cv::CV_STRING;
658   }
is_map()659   mstch::node is_map() { return type_ == cv::CV_MAP; }
is_list()660   mstch::node is_list() { return type_ == cv::CV_LIST; }
is_container()661   mstch::node is_container() {
662     return type_ == cv::CV_MAP || type_ == cv::CV_LIST;
663   }
is_empty_container()664   mstch::node is_empty_container() {
665     return (type_ == cv::CV_MAP && const_value_->get_map().empty()) ||
666         (type_ == cv::CV_LIST && const_value_->get_list().empty());
667   }
668   mstch::node value();
669   mstch::node integer_value();
670   mstch::node double_value();
671   mstch::node bool_value();
672   mstch::node is_non_zero();
673   mstch::node enum_name();
674   mstch::node enum_value_name();
675   mstch::node string_value();
676   mstch::node list_elems();
677   mstch::node map_elems();
678   mstch::node const_struct();
referenceable()679   mstch::node referenceable() {
680     return current_const_ && const_value_->get_owner() &&
681         current_const_ != const_value_->get_owner() && same_type_as_expected();
682   }
683   mstch::node owning_const();
enable_referencing()684   mstch::node enable_referencing() {
685     return mstch::map{{"value:enable_referencing?", true}};
686   }
687   mstch::node is_const_struct();
688   mstch::node const_struct_type();
689 
690  protected:
691   t_const_value const* const_value_;
692   t_const const* current_const_;
693   t_type const* expected_type_;
694   cv const type_;
695   int32_t index_;
696 
same_type_as_expected()697   virtual bool same_type_as_expected() const { return false; }
698 };
699 
700 class mstch_const_value_key_mapped_pair : public mstch_base {
701  public:
mstch_const_value_key_mapped_pair(std::pair<t_const_value *,t_const_value * > const & pair_values,t_const const * current_const,std::pair<const t_type *,const t_type * > const & expected_types,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t index)702   mstch_const_value_key_mapped_pair(
703       std::pair<t_const_value*, t_const_value*> const& pair_values,
704       t_const const* current_const,
705       std::pair<const t_type*, const t_type*> const& expected_types,
706       std::shared_ptr<mstch_generators const> generators,
707       std::shared_ptr<mstch_cache> cache,
708       ELEMENT_POSITION pos,
709       int32_t index)
710       : mstch_base(generators, cache, pos),
711         pair_(pair_values),
712         current_const_(current_const),
713         expected_types_(expected_types),
714         index_(index) {
715     register_methods(
716         this,
717         {
718             {"element:key", &mstch_const_value_key_mapped_pair::element_key},
719             {"element:value",
720              &mstch_const_value_key_mapped_pair::element_value},
721         });
722   }
723   mstch::node element_key();
724   mstch::node element_value();
725 
726  protected:
727   std::pair<t_const_value*, t_const_value*> const pair_;
728   t_const const* current_const_;
729   std::pair<const t_type*, const t_type*> const expected_types_;
730   int32_t index_;
731 };
732 
733 class mstch_type : public mstch_base {
734  public:
mstch_type(t_type const * type,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos)735   mstch_type(
736       t_type const* type,
737       std::shared_ptr<mstch_generators const> generators,
738       std::shared_ptr<mstch_cache> cache,
739       ELEMENT_POSITION pos)
740       : mstch_base(generators, cache, pos),
741         type_(type),
742         resolved_type_(type->get_true_type()) {
743     register_methods(
744         this,
745         {
746             {"type:name", &mstch_type::name},
747             {"type:void?", &mstch_type::is_void},
748             {"type:string?", &mstch_type::is_string},
749             {"type:binary?", &mstch_type::is_binary},
750             {"type:bool?", &mstch_type::is_bool},
751             {"type:byte?", &mstch_type::is_byte},
752             {"type:i16?", &mstch_type::is_i16},
753             {"type:i32?", &mstch_type::is_i32},
754             {"type:i64?", &mstch_type::is_i64},
755             {"type:double?", &mstch_type::is_double},
756             {"type:float?", &mstch_type::is_float},
757             {"type:floating_point?", &mstch_type::is_floating_point},
758             {"type:struct?", &mstch_type::is_struct},
759             {"type:union?", &mstch_type::is_union},
760             {"type:enum?", &mstch_type::is_enum},
761             {"type:sink?", &mstch_type::is_sink},
762             {"type:sink_has_first_response?",
763              &mstch_type::sink_has_first_response},
764             {"type:stream_or_sink?", &mstch_type::is_stream_or_sink},
765             {"type:streamresponse?", &mstch_type::is_streamresponse},
766             {"type:stream_has_first_response?",
767              &mstch_type::stream_has_first_response},
768             {"type:service?", &mstch_type::is_service},
769             {"type:base?", &mstch_type::is_base},
770             {"type:container?", &mstch_type::is_container},
771             {"type:list?", &mstch_type::is_list},
772             {"type:set?", &mstch_type::is_set},
773             {"type:map?", &mstch_type::is_map},
774             {"type:typedef?", &mstch_type::is_typedef},
775             {"type:struct", &mstch_type::get_struct},
776             {"type:enum", &mstch_type::get_enum},
777             {"type:list_elem_type", &mstch_type::get_list_type},
778             {"type:set_elem_type", &mstch_type::get_set_type},
779             {"type:sink_elem_type", &mstch_type::get_sink_elem_type},
780             {"type:sink_final_response_type",
781              &mstch_type::get_sink_final_reponse_type},
782             {"type:sink_first_response_type",
783              &mstch_type::get_sink_first_response_type},
784             {"type:stream_elem_type", &mstch_type::get_stream_elem_type},
785             {"type:stream_first_response_type",
786              &mstch_type::get_stream_first_response_type},
787             {"type:key_type", &mstch_type::get_key_type},
788             {"type:value_type", &mstch_type::get_value_type},
789             {"type:typedef_type", &mstch_type::get_typedef_type},
790             {"type:typedef", &mstch_type::get_typedef},
791             {"type:interaction?", &mstch_type::is_interaction},
792         });
793   }
794 
name()795   mstch::node name() { return type_->get_name(); }
is_void()796   mstch::node is_void() { return resolved_type_->is_void(); }
is_string()797   mstch::node is_string() { return resolved_type_->is_string(); }
is_binary()798   mstch::node is_binary() { return resolved_type_->is_binary(); }
is_bool()799   mstch::node is_bool() { return resolved_type_->is_bool(); }
is_byte()800   mstch::node is_byte() { return resolved_type_->is_byte(); }
is_i16()801   mstch::node is_i16() { return resolved_type_->is_i16(); }
is_i32()802   mstch::node is_i32() { return resolved_type_->is_i32(); }
is_i64()803   mstch::node is_i64() { return resolved_type_->is_i64(); }
is_double()804   mstch::node is_double() { return resolved_type_->is_double(); }
is_float()805   mstch::node is_float() { return resolved_type_->is_float(); }
is_floating_point()806   mstch::node is_floating_point() {
807     return resolved_type_->is_floating_point();
808   }
is_struct()809   mstch::node is_struct() {
810     return resolved_type_->is_struct() || resolved_type_->is_xception();
811   }
is_union()812   mstch::node is_union() { return resolved_type_->is_union(); }
is_enum()813   mstch::node is_enum() { return resolved_type_->is_enum(); }
is_sink()814   mstch::node is_sink() { return resolved_type_->is_sink(); }
sink_has_first_response()815   mstch::node sink_has_first_response() {
816     return resolved_type_->is_sink() &&
817         dynamic_cast<const t_sink*>(resolved_type_)->sink_has_first_response();
818   }
is_stream_or_sink()819   mstch::node is_stream_or_sink() {
820     return resolved_type_->is_streamresponse() || resolved_type_->is_sink();
821   }
is_streamresponse()822   mstch::node is_streamresponse() {
823     return resolved_type_->is_streamresponse();
824   }
stream_has_first_response()825   mstch::node stream_has_first_response() {
826     return resolved_type_->is_streamresponse() &&
827         dynamic_cast<const t_stream_response*>(resolved_type_)
828             ->first_response_type() != boost::none;
829   }
is_service()830   mstch::node is_service() { return resolved_type_->is_service(); }
is_base()831   mstch::node is_base() { return resolved_type_->is_base_type(); }
is_container()832   mstch::node is_container() { return resolved_type_->is_container(); }
is_list()833   mstch::node is_list() { return resolved_type_->is_list(); }
is_set()834   mstch::node is_set() { return resolved_type_->is_set(); }
is_map()835   mstch::node is_map() { return resolved_type_->is_map(); }
is_typedef()836   mstch::node is_typedef() { return type_->is_typedef(); }
get_type_namespace(t_program const *)837   virtual std::string get_type_namespace(t_program const*) { return ""; }
838   mstch::node get_struct();
839   mstch::node get_enum();
840   mstch::node get_list_type();
841   mstch::node get_set_type();
842   mstch::node get_key_type();
843   mstch::node get_value_type();
844   mstch::node get_typedef_type();
845   mstch::node get_typedef();
846   mstch::node get_sink_first_response_type();
847   mstch::node get_sink_elem_type();
848   mstch::node get_sink_final_reponse_type();
849   mstch::node get_stream_elem_type();
850   mstch::node get_stream_first_response_type();
is_interaction()851   mstch::node is_interaction() { return type_->is_service(); }
852 
853  protected:
854   t_type const* type_;
855   t_type const* resolved_type_;
856 };
857 
858 class mstch_field : public mstch_base {
859  public:
mstch_field(t_field const * field,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t index,field_generator_context const * field_context)860   mstch_field(
861       t_field const* field,
862       std::shared_ptr<mstch_generators const> generators,
863       std::shared_ptr<mstch_cache> cache,
864       ELEMENT_POSITION pos,
865       int32_t index,
866       field_generator_context const* field_context)
867       : mstch_base(generators, cache, pos),
868         field_(field),
869         index_(index),
870         field_context_(field_context) {
871     register_methods(
872         this,
873         {
874             {"field:name", &mstch_field::name},
875             {"field:key", &mstch_field::key},
876             {"field:value", &mstch_field::value},
877             {"field:type", &mstch_field::type},
878             {"field:index", &mstch_field::index},
879             {"field:required?", &mstch_field::is_required},
880             {"field:optional?", &mstch_field::is_optional},
881             {"field:opt_in_req_out?", &mstch_field::is_optInReqOut},
882             {"field:annotations", &mstch_field::annotations},
883             {"field:structured_annotations",
884              &mstch_field::structured_annotations},
885         });
886   }
name()887   mstch::node name() { return field_->get_name(); }
key()888   mstch::node key() { return std::to_string(field_->get_key()); }
889   mstch::node value();
890   mstch::node type();
index()891   mstch::node index() { return std::to_string(index_); }
is_required()892   mstch::node is_required() {
893     return field_->get_req() == t_field::e_req::required;
894   }
is_optional()895   mstch::node is_optional() {
896     return field_->get_req() == t_field::e_req::optional;
897   }
is_optInReqOut()898   mstch::node is_optInReqOut() {
899     return field_->get_req() == t_field::e_req::opt_in_req_out;
900   }
annotations()901   mstch::node annotations() { return mstch_base::annotations(field_); }
structured_annotations()902   mstch::node structured_annotations() {
903     return mstch_base::structured_annotations(field_);
904   }
905 
906  protected:
907   t_field const* field_;
908   int32_t index_;
909   field_generator_context const* field_context_;
910 };
911 
912 class mstch_annotation : public mstch_base {
913  public:
mstch_annotation(const std::string & key,const annotation_value & val,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t index)914   mstch_annotation(
915       const std::string& key,
916       const annotation_value& val,
917       std::shared_ptr<mstch_generators const> generators,
918       std::shared_ptr<mstch_cache> cache,
919       ELEMENT_POSITION pos,
920       int32_t index)
921       : mstch_base(generators, cache, pos),
922         key_(key),
923         val_(val),
924         index_(index) {
925     register_methods(
926         this,
927         {
928             {"annotation:key", &mstch_annotation::key},
929             {"annotation:value", &mstch_annotation::value},
930         });
931   }
key()932   mstch::node key() { return key_; }
value()933   mstch::node value() { return val_.value; }
934 
935  protected:
936   const std::string key_;
937   const annotation_value val_;
938   int32_t index_;
939 };
940 
941 class mstch_structured_annotation : public mstch_base {
942  public:
mstch_structured_annotation(const t_const & cnst,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t index)943   mstch_structured_annotation(
944       const t_const& cnst,
945       std::shared_ptr<mstch_generators const> generators,
946       std::shared_ptr<mstch_cache> cache,
947       ELEMENT_POSITION pos,
948       int32_t index)
949       : mstch_base(generators, cache, pos), cnst_(cnst), index_(index) {
950     register_methods(
951         this,
952         {{"structured_annotation:const",
953           &mstch_structured_annotation::constant},
954          {"structured_annotation:const_struct?",
955           &mstch_structured_annotation::is_const_struct}});
956   }
constant()957   mstch::node constant() {
958     return generators_->const_generator_->generate(
959         &cnst_,
960         generators_,
961         cache_,
962         pos_,
963         index_,
964         &cnst_,
965         cnst_.type()->get_true_type());
966   }
967 
is_const_struct()968   mstch::node is_const_struct() {
969     return cnst_.type()->get_true_type()->is_struct();
970   }
971 
972  protected:
973   const t_const& cnst_;
974   int32_t index_;
975 };
976 
977 class mstch_struct : public mstch_base {
978  public:
mstch_struct(t_struct const * strct,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos)979   mstch_struct(
980       t_struct const* strct,
981       std::shared_ptr<mstch_generators const> generators,
982       std::shared_ptr<mstch_cache> cache,
983       ELEMENT_POSITION pos)
984       : mstch_base(generators, cache, pos), strct_(strct) {
985     register_methods(
986         this,
987         {
988             {"struct:name", &mstch_struct::name},
989             {"struct:fields?", &mstch_struct::has_fields},
990             {"struct:fields", &mstch_struct::fields},
991             {"struct:exception?", &mstch_struct::is_exception},
992             {"struct:union?", &mstch_struct::is_union},
993             {"struct:plain?", &mstch_struct::is_plain},
994             {"struct:annotations", &mstch_struct::annotations},
995             {"struct:thrift_uri", &mstch_struct::thrift_uri},
996             {"struct:structured_annotations",
997              &mstch_struct::structured_annotations},
998             {"struct:exception_kind", &mstch_struct::exception_kind},
999             {"struct:exception_safety", &mstch_struct::exception_safety},
1000             {"struct:exception_blame", &mstch_struct::exception_blame},
1001         });
1002 
1003     // Populate field_context_generator for each field.
1004     auto ctx = field_generator_context{};
1005     ctx.strct = strct_;
1006     auto fields = strct->fields();
1007     for (auto it = fields.begin(); it != fields.end(); it++) {
1008       const auto* field = &*it;
1009       if (cpp2::field_has_isset(field)) {
1010         ctx.isset_index++;
1011       }
1012       ctx.next = (it + 1) != fields.end() ? &*(it + 1) : nullptr;
1013       context_map[field] = ctx;
1014       ctx.prev = field;
1015     }
1016   }
name()1017   mstch::node name() { return strct_->get_name(); }
has_fields()1018   mstch::node has_fields() { return strct_->has_fields(); }
1019   mstch::node fields();
is_exception()1020   mstch::node is_exception() { return strct_->is_xception(); }
is_union()1021   mstch::node is_union() { return strct_->is_union(); }
is_plain()1022   mstch::node is_plain() {
1023     return !strct_->is_xception() && !strct_->is_union();
1024   }
annotations()1025   mstch::node annotations() { return mstch_base::annotations(strct_); }
1026   mstch::node thrift_uri();
structured_annotations()1027   mstch::node structured_annotations() {
1028     return mstch_base::structured_annotations(strct_);
1029   }
1030 
1031   mstch::node exception_safety();
1032 
1033   mstch::node exception_blame();
1034 
1035   mstch::node exception_kind();
1036 
generate_fields(const field_range & fields)1037   mstch::array generate_fields(const field_range& fields) override {
1038     mstch::array a;
1039     size_t i = 0;
1040     for (const auto* field : fields) {
1041       auto pos = element_position(i, fields.size());
1042       a.push_back(generators_->field_generator_.get()->generate(
1043           field, generators_, cache_, pos, i, &context_map[field]));
1044       ++i;
1045     }
1046     return a;
1047   }
1048 
1049  protected:
1050   t_struct const* strct_;
1051   // Although mstch_fields can be generated from different orders than the IDL
1052   // order, field_generator_context should be always computed in the IDL order,
1053   // as the context does not change by reordering. Without the map, each
1054   // different reordering recomputes field_generator_context, and each
1055   // field takes O(N) to loop through node_list_view<t_field> or
1056   // std::vector<t_field*> to find the exact t_field to compute
1057   // field_generator_context.
1058   std::unordered_map<t_field const*, field_generator_context> context_map;
1059 };
1060 
1061 class mstch_function : public mstch_base {
1062  public:
mstch_function(t_function const * function,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos)1063   mstch_function(
1064       t_function const* function,
1065       std::shared_ptr<mstch_generators const> generators,
1066       std::shared_ptr<mstch_cache> cache,
1067       ELEMENT_POSITION pos)
1068       : mstch_base(generators, cache, pos), function_(function) {
1069     register_methods(
1070         this,
1071         {
1072             {"function:name", &mstch_function::name},
1073             {"function:oneway?", &mstch_function::oneway},
1074             {"function:return_type", &mstch_function::return_type},
1075             {"function:exceptions", &mstch_function::exceptions},
1076             {"function:stream_exceptions", &mstch_function::stream_exceptions},
1077             {"function:sink_exceptions", &mstch_function::sink_exceptions},
1078             {"function:sink_final_response_exceptions",
1079              &mstch_function::sink_final_response_exceptions},
1080             {"function:exceptions?", &mstch_function::has_exceptions},
1081             {"function:stream_exceptions?",
1082              &mstch_function::has_streamexceptions},
1083             {"function:sink_exceptions?", &mstch_function::has_sinkexceptions},
1084             {"function:sink_final_response_exceptions?",
1085              &mstch_function::has_sink_final_response_exceptions},
1086             {"function:args", &mstch_function::arg_list},
1087             {"function:comma", &mstch_function::has_args},
1088             {"function:priority", &mstch_function::priority},
1089             {"function:returns_sink?", &mstch_function::returns_sink},
1090             {"function:returns_streams?", &mstch_function::returns_stream},
1091             {"function:returns_stream?", &mstch_function::returns_stream},
1092             {"function:stream_has_first_response?",
1093              &mstch_function::stream_has_first_response},
1094             {"function:annotations", &mstch_function::annotations},
1095             {"function:starts_interaction?",
1096              &mstch_function::starts_interaction},
1097             {"function:structured_annotations",
1098              &mstch_function::structured_annotations},
1099             {"function:qualifier", &mstch_function::qualifier},
1100         });
1101   }
1102 
name()1103   mstch::node name() { return function_->get_name(); }
oneway()1104   mstch::node oneway() {
1105     return function_->qualifier() == t_function_qualifier::one_way;
1106   }
has_exceptions()1107   mstch::node has_exceptions() {
1108     return function_->get_xceptions()->has_fields();
1109   }
has_streamexceptions()1110   mstch::node has_streamexceptions() {
1111     return function_->get_stream_xceptions()->has_fields();
1112   }
has_sinkexceptions()1113   mstch::node has_sinkexceptions() {
1114     return function_->get_sink_xceptions()->has_fields();
1115   }
has_sink_final_response_exceptions()1116   mstch::node has_sink_final_response_exceptions() {
1117     return function_->get_sink_final_response_xceptions()->has_fields();
1118   }
stream_has_first_response()1119   mstch::node stream_has_first_response() {
1120     const auto& rettype = *function_->return_type();
1121     auto stream = dynamic_cast<const t_stream_response*>(&rettype);
1122     return stream && stream->first_response_type() != boost::none;
1123   }
has_args()1124   mstch::node has_args() {
1125     if (function_->get_paramlist()->has_fields()) {
1126       return std::string(", ");
1127     }
1128     return std::string();
1129   }
priority()1130   mstch::node priority() {
1131     return function_->get_annotation("priority", "NORMAL");
1132   }
returns_sink()1133   mstch::node returns_sink() { return function_->returns_sink(); }
annotations()1134   mstch::node annotations() { return mstch_base::annotations(function_); }
1135 
1136   mstch::node return_type();
1137   mstch::node exceptions();
1138   mstch::node stream_exceptions();
1139   mstch::node sink_exceptions();
1140   mstch::node sink_final_response_exceptions();
1141   mstch::node arg_list();
1142   mstch::node returns_stream();
starts_interaction()1143   mstch::node starts_interaction() {
1144     return function_->get_returntype()->is_service();
1145   }
1146 
structured_annotations()1147   mstch::node structured_annotations() {
1148     return mstch_base::structured_annotations(function_);
1149   }
1150 
qualifier()1151   mstch::node qualifier() {
1152     auto q = function_->qualifier();
1153     switch (q) {
1154       case t_function_qualifier::one_way:
1155         return std::string("OneWay");
1156       case t_function_qualifier::idempotent:
1157         return std::string("Idempotent");
1158       case t_function_qualifier::read_only:
1159         return std::string("ReadOnly");
1160       default:
1161         return std::string("Unspecified");
1162     }
1163   }
1164 
1165  protected:
1166   t_function const* function_;
1167 };
1168 
1169 class mstch_service : public mstch_base {
1170  public:
mstch_service(t_service const * service,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos)1171   mstch_service(
1172       t_service const* service,
1173       std::shared_ptr<mstch_generators const> generators,
1174       std::shared_ptr<mstch_cache> cache,
1175       ELEMENT_POSITION pos)
1176       : mstch_base(generators, cache, pos), service_(service) {
1177     register_methods(
1178         this,
1179         {
1180             {"service:name", &mstch_service::name},
1181             {"service:functions", &mstch_service::functions},
1182             {"service:functions?", &mstch_service::has_functions},
1183             {"service:extends", &mstch_service::extends},
1184             {"service:extends?", &mstch_service::has_extends},
1185             {"service:streams?", &mstch_service::has_streams},
1186             {"service:sinks?", &mstch_service::has_sinks},
1187             {"service:annotations", &mstch_service::annotations},
1188             {"service:parent", &mstch_service::parent},
1189             {"service:interaction?", &mstch_service::is_interaction},
1190             {"service:interactions", &mstch_service::interactions},
1191             {"service:interactions?", &mstch_service::has_interactions},
1192             {"service:structured_annotations",
1193              &mstch_service::structured_annotations},
1194             {"interaction:serial?", &mstch_service::is_serial_interaction},
1195         });
1196   }
1197 
get_service_namespace(t_program const *)1198   virtual std::string get_service_namespace(t_program const*) { return {}; }
1199 
name()1200   mstch::node name() { return service_->get_name(); }
has_functions()1201   mstch::node has_functions() { return !get_functions().empty(); }
has_extends()1202   mstch::node has_extends() { return service_->get_extends() != nullptr; }
1203   mstch::node functions();
1204   mstch::node extends();
annotations()1205   mstch::node annotations() { return mstch_base::annotations(service_); }
1206 
parent()1207   mstch::node parent() {
1208     return cache_->parsed_options_["parent_service_name"];
1209   }
1210 
has_streams()1211   mstch::node has_streams() {
1212     auto& funcs = get_functions();
1213     return std::any_of(funcs.cbegin(), funcs.cend(), [](auto const& func) {
1214       return func->returns_stream();
1215     });
1216   }
1217 
has_sinks()1218   mstch::node has_sinks() {
1219     auto& funcs = get_functions();
1220     return std::any_of(funcs.cbegin(), funcs.cend(), [](auto const& func) {
1221       return func->returns_sink();
1222     });
1223   }
1224 
has_interactions()1225   mstch::node has_interactions() {
1226     auto& funcs = get_functions();
1227     return std::any_of(funcs.cbegin(), funcs.cend(), [](auto const& func) {
1228       return func->get_returntype()->is_service();
1229     });
1230   }
interactions()1231   mstch::node interactions() {
1232     if (!service_->is_interaction()) {
1233       cache_->parsed_options_["parent_service_name"] = service_->get_name();
1234     }
1235     std::vector<t_service const*> interactions;
1236     for (auto const* function : get_functions()) {
1237       if (function->get_returntype()->is_service()) {
1238         interactions.push_back(
1239             dynamic_cast<t_service const*>(function->get_returntype()));
1240       }
1241     }
1242     return generate_services(interactions);
1243   }
structured_annotations()1244   mstch::node structured_annotations() {
1245     return mstch_base::structured_annotations(service_);
1246   }
is_interaction()1247   mstch::node is_interaction() { return service_->is_interaction(); }
is_serial_interaction()1248   mstch::node is_serial_interaction() {
1249     return service_->is_serial_interaction();
1250   }
1251 
1252   virtual ~mstch_service() = default;
1253 
1254  protected:
1255   t_service const* service_;
1256 
1257   mstch::node generate_cached_extended_service(const t_service* service);
get_functions()1258   virtual const std::vector<t_function*>& get_functions() const {
1259     return service_->get_functions();
1260   }
1261 };
1262 
1263 class mstch_typedef : public mstch_base {
1264  public:
mstch_typedef(t_typedef const * typedf,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos)1265   mstch_typedef(
1266       t_typedef const* typedf,
1267       std::shared_ptr<mstch_generators const> generators,
1268       std::shared_ptr<mstch_cache> cache,
1269       ELEMENT_POSITION pos)
1270       : mstch_base(generators, cache, pos), typedf_(typedf) {
1271     register_methods(
1272         this,
1273         {
1274             {"typedef:type", &mstch_typedef::type},
1275             {"typedef:is_same_type", &mstch_typedef::is_same_type},
1276             {"typedef:name", &mstch_typedef::name},
1277             {"typedef:structured_annotations",
1278              &mstch_typedef::structured_annotations},
1279         });
1280   }
1281   mstch::node type();
name()1282   mstch::node name() { return typedf_->name(); }
is_same_type()1283   mstch::node is_same_type() {
1284     return typedf_->get_name() == typedf_->get_type()->get_name();
1285   }
structured_annotations()1286   mstch::node structured_annotations() {
1287     return mstch_base::structured_annotations(typedf_);
1288   }
1289 
1290  protected:
1291   t_typedef const* typedf_;
1292 };
1293 
1294 class mstch_const : public mstch_base {
1295  public:
mstch_const(t_const const * cnst,t_const const * current_const,t_type const * expected_type,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t index,t_field const * field)1296   mstch_const(
1297       t_const const* cnst,
1298       t_const const* current_const,
1299       t_type const* expected_type,
1300       std::shared_ptr<mstch_generators const> generators,
1301       std::shared_ptr<mstch_cache> cache,
1302       ELEMENT_POSITION pos,
1303       int32_t index,
1304       t_field const* field)
1305       : mstch_base(generators, cache, pos),
1306         cnst_(cnst),
1307         current_const_(current_const),
1308         expected_type_(expected_type),
1309         index_(index),
1310         field_(field) {
1311     register_methods(
1312         this,
1313         {
1314             {"constant:name", &mstch_const::name},
1315             {"constant:index", &mstch_const::index},
1316             {"constant:type", &mstch_const::type},
1317             {"constant:value", &mstch_const::value},
1318             {"constant:program", &mstch_const::program},
1319         });
1320   }
name()1321   mstch::node name() { return cnst_->get_name(); }
index()1322   mstch::node index() { return index_; }
1323   mstch::node type();
1324   mstch::node value();
1325   mstch::node program();
1326 
1327  protected:
1328   t_const const* cnst_;
1329   t_const const* current_const_;
1330   t_type const* expected_type_;
1331   int32_t index_;
1332   t_field const* field_;
1333 };
1334 
1335 class mstch_program : public mstch_base {
1336  public:
mstch_program(t_program const * program,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos)1337   mstch_program(
1338       t_program const* program,
1339       std::shared_ptr<mstch_generators const> generators,
1340       std::shared_ptr<mstch_cache> cache,
1341       ELEMENT_POSITION pos)
1342       : mstch_base(generators, cache, pos), program_(program) {
1343     register_methods(
1344         this,
1345         {
1346             {"program:name", &mstch_program::name},
1347             {"program:path", &mstch_program::path},
1348             {"program:includePrefix", &mstch_program::include_prefix},
1349             {"program:structs", &mstch_program::structs},
1350             {"program:enums", &mstch_program::enums},
1351             {"program:services", &mstch_program::services},
1352             {"program:typedefs", &mstch_program::typedefs},
1353             {"program:constants", &mstch_program::constants},
1354             {"program:enums?", &mstch_program::has_enums},
1355             {"program:structs?", &mstch_program::has_structs},
1356             {"program:unions?", &mstch_program::has_unions},
1357             {"program:services?", &mstch_program::has_services},
1358             {"program:typedefs?", &mstch_program::has_typedefs},
1359             {"program:constants?", &mstch_program::has_constants},
1360             {"program:thrift_uris?", &mstch_program::has_thrift_uris},
1361         });
1362     register_has_option("program:frozen?", "frozen");
1363     register_has_option("program:json?", "json");
1364     register_has_option("program:nimble?", "nimble");
1365     register_has_option("program:any?", "any");
1366     register_has_option(
1367         "program:unstructured_annotations_in_metadata?",
1368         "deprecated_unstructured_annotations_in_metadata");
1369   }
1370 
get_program_namespace(t_program const *)1371   virtual std::string get_program_namespace(t_program const*) { return {}; }
1372 
name()1373   mstch::node name() { return program_->name(); }
path()1374   mstch::node path() { return program_->path(); }
include_prefix()1375   mstch::node include_prefix() { return program_->include_prefix(); }
has_enums()1376   mstch::node has_enums() { return !program_->enums().empty(); }
has_structs()1377   mstch::node has_structs() {
1378     return !program_->structs().empty() || !program_->xceptions().empty();
1379   }
has_services()1380   mstch::node has_services() { return !program_->services().empty(); }
has_typedefs()1381   mstch::node has_typedefs() { return !program_->typedefs().empty(); }
has_constants()1382   mstch::node has_constants() { return !program_->consts().empty(); }
has_unions()1383   mstch::node has_unions() {
1384     auto& structs = program_->structs();
1385     return std::any_of(
1386         structs.cbegin(), structs.cend(), std::mem_fn(&t_struct::is_union));
1387   }
1388 
1389   mstch::node has_thrift_uris();
1390   mstch::node structs();
1391   mstch::node enums();
1392   mstch::node services();
1393   mstch::node typedefs();
1394   mstch::node constants();
1395 
1396  protected:
1397   t_program const* program_;
1398 
1399   virtual const std::vector<t_struct*>& get_program_objects();
1400   virtual const std::vector<t_enum*>& get_program_enums();
1401 };
1402 
1403 } // namespace compiler
1404 } // namespace thrift
1405 } // namespace apache
1406