Spicy
tuple.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <memory>
6 #include <string>
7 #include <vector>
8 
9 #include <hilti/ast/operators/common.h>
10 #include <hilti/ast/types/tuple.h>
11 
12 namespace hilti {
13 namespace operator_ {
14 
15 STANDARD_OPERATOR_2(tuple, Equal, type::Bool(), type::constant(type::Tuple(type::Wildcard())),
16  operator_::sameTypeAs(0, "tuple<*>"), "Compares two tuples element-wise.");
17 STANDARD_OPERATOR_2(tuple, Unequal, type::Bool(), type::constant(type::Tuple(type::Wildcard())),
18  operator_::sameTypeAs(0, "tuple<*>"), "Compares two tuples element-wise.");
19 
20 BEGIN_OPERATOR_CUSTOM(tuple, Index)
21  Type result(const std::vector<Expression>& ops) const {
22  if ( ops.empty() )
23  return type::DocOnly("<type of element>");
24 
25  if ( ops.size() < 2 )
26  return type::unknown;
27 
28  auto ctor = ops[1].tryAs<expression::Ctor>();
29  if ( ! ctor )
30  return type::unknown;
31 
32  auto i = ctor->ctor().tryAs<ctor::UnsignedInteger>();
33  if ( ! i )
34  return type::unknown;
35 
36  const auto& types = ops[0].type().as<type::Tuple>().types();
37 
38  if ( types.size() <= i->value() )
39  return type::unknown;
40 
41  return types[i->value()];
42  }
43 
44  bool isLhs() const { return true; }
45 
46  std::vector<Operand> operands() const {
47  return {{.type = type::Tuple(type::Wildcard())}, {.type = type::UnsignedInteger(64)}};
48  }
49 
50  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
51  if ( auto ec = i.op1().tryAs<expression::Ctor>() )
52  if ( auto c = ec->ctor().tryAs<ctor::UnsignedInteger>() ) {
53  if ( c->value() < 0 || c->value() >= i.op0().type().as<type::Tuple>().types().size() )
54  p.node.addError("tuple index out of range");
55 
56  return;
57  }
58 
59  p.node.addError("tuple index must be an integer constant");
60  }
61 
62  std::string doc() const {
63  return "Extracts the tuple element at the given index. The index must be a constant unsigned integer.";
64  }
65 END_OPERATOR_CUSTOM
66 
67 BEGIN_OPERATOR_CUSTOM(tuple, Member)
68  Type result(const std::vector<Expression>& ops) const {
69  if ( ops.empty() )
70  return type::DocOnly("<type of element>");
71 
72  auto id = ops[1].as<expression::Member>().id();
73  auto elem = ops[0].type().as<type::Tuple>().elementByID(id);
74  if ( ! elem )
75  return type::unknown;
76 
77  return elem->second;
78  }
79 
80  bool isLhs() const { return true; }
81 
82  std::vector<Operand> operands() const {
83  return {{.type = type::Tuple(type::Wildcard())}, {.type = type::Member(type::Wildcard()), .doc = "<id>"}};
84  }
85 
86  void validate(const expression::ResolvedOperator& i, operator_::position_t p) const {
87  auto id = i.operands()[1].as<expression::Member>().id();
88  auto elem = i.operands()[0].type().as<type::Tuple>().elementByID(id);
89 
90  if ( ! elem )
91  p.node.addError("unknown tuple element");
92  }
93 
94  std::string doc() const { return "Extracts the tuple element corresponding to the given ID."; }
95 END_OPERATOR_CUSTOM_x
96 
97 
98 } // namespace operator_
99 } // namespace hilti