Spicy
resolved-operator.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <utility>
6 #include <vector>
7 
8 #include <hilti/ast/expression.h>
9 #include <hilti/ast/expressions/unresolved-operator.h>
10 #include <hilti/ast/node.h>
11 #include <hilti/ast/operator.h>
12 #include <hilti/ast/types/id.h>
13 
14 namespace hilti {
15 
16 namespace trait {
18 } // namespace trait
19 
20 namespace expression {
21 namespace resolved_operator {
22 namespace detail {
23 #include <hilti/autogen/__resolved-operator.h>
24 
25 inline Node to_node(ResolvedOperator t) { return Node(std::move(t)); }
26 
27 inline std::ostream& operator<<(std::ostream& out, ResolvedOperator i) { return out << to_node(std::move(i)); }
28 
29 } // namespace detail
30 } // namespace resolved_operator
31 
32 using ResolvedOperator = resolved_operator::detail::ResolvedOperator;
33 using resolved_operator::detail::to_node;
34 
35 namespace detail {
36 
37 // Generally we want to compute the result type of operators dynamically
38 // because updates to their child nodes may lead to changes. For unresolved
39 // IDs, however, we need to store the type in the AST for it get to resolved.
40 // This function implements that distinction.
41 inline Type type_to_store(Type t) {
42  if ( t.isA<type::UnresolvedID>() )
43  return t;
44  else
45  return type::unknown;
46 }
47 
48 } // namespace detail
49 
56 public:
57  ResolvedOperatorBase(const Operator& op, const std::vector<Expression>& operands, Meta meta = Meta())
58  : NodeBase(nodes(detail::type_to_store(op.result(operands)), operands), std::move(meta)), _operator(op) {}
59 
60  const auto& operator_() const { return _operator; }
61  auto kind() const { return _operator.kind(); }
62 
63  // ResolvedOperator interface with common implementation.
64  const auto& operands() const {
65  if ( _cache.operands.empty() )
66  _cache.operands = childs<Expression>(1, -1);
67 
68  return _cache.operands;
69  }
70 
71  const auto& result() const {
72  if ( _cache.result )
73  return *_cache.result;
74 
75  if ( ! childs()[0].isA<type::Unknown>() )
76  _cache.result = child<Type>(0);
77  else
78  // If the result wasn't stored at instantiation time, try again.
79  _cache.result = _operator.result(operands());
80 
81  return *_cache.result;
82  }
83 
84  const auto& op0() const { return child<Expression>(1); }
85  const auto& op1() const { return child<Expression>(2); }
86  const auto& op2() const { return child<Expression>(3); }
87  auto hasOp0() const { return ! childs().empty(); }
88  auto hasOp1() const { return childs().size() >= 3; }
89  auto hasOp2() const { return childs().size() >= 4; }
90  void setOp0(const Expression& e) { childs()[1] = e; }
91  void setOp1(const Expression& e) { childs()[2] = e; }
92  void setOp2(const Expression& e) { childs()[3] = e; }
93 
94  bool operator==(const ResolvedOperator& other) const {
95  return operator_() == other.operator_() && operands() == other.operands();
96  }
97 
99  bool isLhs() const { return operator_().isLhs(); }
101  bool isTemporary() const { return isLhs(); }
103  auto type() const { return type::effectiveType(result()); }
105  auto isEqual(const Expression& other) const { return node::isEqual(this, other); }
106 
108  bool isConstant() const { return type::isConstant(type()); }
109 
111  auto properties() const { return node::Properties{{"kind", to_string(_operator.kind())}}; }
113  void clearCache() {
114  _cache.result.reset();
115  _cache.operands.clear();
116  }
117 
118 private:
119  ::hilti::operator_::detail::Operator _operator;
120 
121  mutable struct {
122  std::optional<Type> result;
123  std::vector<Expression> operands;
124  } _cache;
125 };
126 
127 namespace resolved_operator {
128 
136 inline hilti::Expression setOp0(const expression::ResolvedOperator& r, Expression e) {
137  auto x = r._clone().as<expression::ResolvedOperator>();
138  x.setOp0(std::move(e));
139  return x;
140 }
141 
149 inline hilti::Expression setOp1(const expression::ResolvedOperator& r, Expression e) {
150  auto x = r._clone().as<expression::ResolvedOperator>();
151  x.setOp1(std::move(e));
152  return x;
153 }
154 
162 inline hilti::Expression setOp2(const expression::ResolvedOperator& r, Expression e) {
163  auto x = r._clone().as<expression::ResolvedOperator>();
164  x.setOp2(std::move(e));
165  return x;
166 }
167 
168 } // namespace resolved_operator
169 } // namespace expression
170 } // namespace hilti
auto isEqual(const Expression &other) const
Definition: resolved-operator.h:105
bool isTemporary() const
Definition: resolved-operator.h:101
Definition: expression.h:16
Definition: id.h:53
auto properties() const
Definition: resolved-operator.h:111
Definition: meta.h:18
void clearCache()
Definition: resolved-operator.h:113
auto type() const
Definition: resolved-operator.h:103
Definition: resolved-operator.h:55
std::map< std::string, node::detail::PropertyValue > Properties
Definition: node.h:83
bool isLhs() const
Definition: resolved-operator.h:99
bool isConstant() const
Definition: resolved-operator.h:108
Definition: node.h:97
Definition: resolved-operator.h:17
Definition: node.h:318