Spicy
struct.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <algorithm>
6 #include <optional>
7 #include <utility>
8 #include <vector>
9 
10 #include <hilti/ast/attribute.h>
11 #include <hilti/ast/expression.h>
12 #include <hilti/ast/function.h>
13 #include <hilti/ast/id.h>
14 #include <hilti/ast/type.h>
15 #include <hilti/ast/types/function.h>
16 #include <hilti/ast/types/unknown.h>
17 
18 namespace hilti {
19 namespace type {
20 
21 namespace struct_ {
23 class Field : public NodeBase {
24 public:
25  Field() : NodeBase({ID("<no id>"), type::unknown, node::none, node::none}, Meta()) {}
26  Field(ID id, Type t, std::optional<AttributeSet> attrs = {}, Meta m = Meta())
27  : NodeBase(nodes(std::move(id), std::move(t), node::none, std::move(attrs), node::none), std::move(m)) {}
28  Field(ID id, Type t, Type aux_type, std::optional<AttributeSet> attrs, Meta m = Meta())
29  : NodeBase(nodes(std::move(id), std::move(t), std::move(aux_type), std::move(attrs), node::none),
30  std::move(m)) {}
31  Field(ID id, ::hilti::function::CallingConvention cc, type::Function ft, std::optional<AttributeSet> attrs = {},
32  Meta m = Meta())
33  : NodeBase(nodes(std::move(id), std::move(ft), node::none, std::move(attrs), node::none), std::move(m)),
34  _cc(cc) {}
35  Field(ID id, hilti::Function inline_func, std::optional<AttributeSet> attrs = {}, Meta m = Meta())
36  : NodeBase(nodes(std::move(id), node::none, node::none, std::move(attrs), std::move(inline_func)),
37  std::move(m)),
38  _cc(inline_func.callingConvention()) {}
39 
40  const auto& id() const { return child<ID>(0); }
41 
42  auto callingConvention() const { return _cc; }
43  auto inlineFunction() const { return childs()[4].tryReferenceAs<hilti::Function>(); }
44  auto attributes() const { return childs()[3].tryReferenceAs<AttributeSet>(); }
45 
46  Type type() const {
47  if ( ! _cache.type ) {
48  if ( auto func = inlineFunction() )
49  _cache.type = func->type();
50  else
51  _cache.type = type::effectiveType(child<Type>(1));
52  }
53 
54  return *_cache.type;
55  }
56 
63  std::optional<Type> auxType() const {
64  if ( auto t = childs()[2].tryAs<Type>() )
65  return type::effectiveType(*t);
66  else
67  return {};
68  }
69 
70  std::optional<Expression> default_() const {
71  if ( auto a = AttributeSet::find(attributes(), "&default") )
72  return *a->valueAs<Expression>();
73 
74  return {};
75  }
76 
77  auto isInternal() const { return AttributeSet::find(attributes(), "&internal").has_value(); }
78  auto isOptional() const { return AttributeSet::find(attributes(), "&optional").has_value(); }
79  auto isStatic() const { return AttributeSet::find(attributes(), "&static").has_value(); }
80  auto isNoEmit() const { return AttributeSet::find(attributes(), "&no-emit").has_value(); }
81 
83  auto& _typeNode() { return childs()[1]; }
84 
86  auto properties() const { return node::Properties{{"cc", to_string(_cc)}}; }
87 
88  bool operator==(const Field& other) const {
89  return id() == other.id() && type() == other.type() && attributes() == other.attributes() && _cc == other._cc;
90  }
91 
99  static Field setAttributes(const Field& f, const AttributeSet& attrs) {
100  auto x = Field(f);
101  x.childs()[3] = attrs;
102  return x;
103  }
104 
105  void clearCache() { _cache.type.reset(); }
106 
107 private:
108  ::hilti::function::CallingConvention _cc = ::hilti::function::CallingConvention::Standard;
109 
110  mutable struct { std::optional<Type> type; } _cache;
111 }; // namespace struct_
112 
113 inline Node to_node(Field f) { return Node(std::move(f)); }
114 
115 } // namespace struct_
116 
119 public:
120  Struct(std::vector<struct_::Field> fields, Meta m = Meta())
121  : TypeBase(nodes(node::none, std::move(fields)), std::move(m)) {
122  _state().flags += type::Flag::NoInheritScope;
123  }
124 
125  Struct(std::vector<type::function::Parameter> params, std::vector<struct_::Field> fields, Meta m = Meta())
126  : TypeBase(nodes(node::none, std::move(fields),
127  util::transform(params,
128  [](const auto& p) {
130  })),
131  std::move(m)) {
132  _state().flags += type::Flag::NoInheritScope;
133  }
134 
135  Struct(Wildcard /*unused*/, Meta m = Meta()) : TypeBase(nodes(node::none), std::move(m)), _wildcard(true) {
136  _state().flags += type::Flag::NoInheritScope;
137  }
138 
139  auto hasFinalizer() const { return field("~finally").has_value(); }
140 
141  auto parameters() const { return childsOfType<type::function::Parameter>(); }
142 
143  std::vector<NodeRef> parameterNodes() {
144  std::vector<NodeRef> params;
145  for ( auto& c : childs() ) {
146  if ( c.isA<type::function::Parameter>() )
147  params.emplace_back(NodeRef(c));
148  }
149  return params;
150  }
151 
152  auto fields() const { return childsOfType<struct_::Field>(); }
153 
154  auto types() const {
155  std::vector<Type> types;
156  for ( auto c = ++childs().begin(); c != childs().end(); c++ )
157  types.push_back(c->as<struct_::Field>().type());
158 
159  return types;
160  }
161 
162  auto ids() const {
163  std::vector<ID> ids;
164  for ( auto c = ++childs().begin(); c != childs().end(); c++ )
165  ids.push_back(c->as<struct_::Field>().id());
166 
167  return ids;
168  }
169 
170  std::optional<struct_::Field> field(const ID& id) const {
171  for ( auto f : fields() ) {
172  if ( f.id() == id )
173  return f;
174  }
175 
176  return {};
177  }
178 
179  auto fields(const ID& id) const {
180  std::vector<struct_::Field> x;
181 
182  for ( const auto& f : fields() ) {
183  if ( f.id() == id )
184  x.push_back(f);
185  }
186 
187  return x;
188  }
189 
190  bool operator==(const Struct& other) const {
191  if ( typeID() && other.typeID() )
192  return *typeID() == *other.typeID();
193 
194  return fields() == other.fields();
195  }
196 
198  auto _fieldNodes() { return nodesOfType<struct_::Field>(); }
199 
201  auto isEqual(const Type& other) const { return node::isEqual(this, other); }
203  auto typeParameters() const {
204  std::vector<Node> params;
205  for ( auto c = ++childs().begin(); c != childs().end(); c++ )
206  params.emplace_back(c->as<struct_::Field>().type());
207  return params;
208  }
210  auto isWildcard() const { return _wildcard; }
211 
213  auto properties() const { return node::Properties{}; }
214 
222  static Struct addField(const Struct& s, struct_::Field f) {
223  auto x = Type(s)._clone().as<Struct>();
224  x.addChild(std::move(f));
225  return x;
226  }
227 
228 private:
229  bool _wildcard = false;
230 };
231 
232 } // namespace type
233 } // namespace hilti
Definition: function.h:69
std::optional< Type > auxType() const
Definition: struct.h:63
auto & _typeNode()
Definition: struct.h:83
auto & childs() const
Definition: node.h:445
static Declaration setIsStructParameter(const Parameter &d)
Definition: parameter.h:119
const Node none
Definition: node.cc:12
Definition: struct.h:23
type::Flags flags() const
Definition: type.h:159
void addChild(Node n)
Definition: node.h:434
Definition: struct.h:118
auto isWildcard() const
Definition: struct.h:210
auto properties() const
Definition: struct.h:86
auto properties() const
Definition: struct.h:213
auto isEqual(const Type &other) const
Definition: struct.h:201
Definition: function.h:44
Definition: type.h:27
static Struct addField(const Struct &s, struct_::Field f)
Definition: struct.h:222
Definition: meta.h:18
Definition: attribute.h:159
auto typeParameters() const
Definition: struct.h:203
Definition: parameter.h:45
static Field setAttributes(const Field &f, const AttributeSet &attrs)
Definition: struct.h:99
std::map< std::string, node::detail::PropertyValue > Properties
Definition: node.h:83
std::optional< ID > typeID() const
Definition: type.h:163
Definition: type.h:152
std::optional< Attribute > find(std::string_view tag) const
Definition: attribute.h:190
Definition: node.h:97
Definition: node_ref.h:44
Definition: type.h:23
Definition: type.h:249
auto transform(const std::vector< X > &x, F f)
Definition: util.h:86
auto _fieldNodes()
Definition: struct.h:198
Definition: id.h:18
Definition: node.h:318