9 #include <hilti/ast/ctors/tuple.h> 10 #include <hilti/ast/operators/common.h> 11 #include <hilti/ast/types/tuple.h> 16 STANDARD_OPERATOR_2(tuple, Equal, type::Bool(), type::constant(type::Tuple(type::Wildcard())),
17 operator_::sameTypeAs(0,
"tuple<*>"),
"Compares two tuples element-wise.");
18 STANDARD_OPERATOR_2(tuple, Unequal, type::Bool(), type::constant(type::Tuple(type::Wildcard())),
19 operator_::sameTypeAs(0,
"tuple<*>"),
"Compares two tuples element-wise.");
21 BEGIN_OPERATOR_CUSTOM(tuple, Index)
24 return type::DocOnly(
"<type of element>");
29 auto ctor = ops[1].tryAs<expression::Ctor>();
33 auto i = ctor->ctor().tryAs<ctor::UnsignedInteger>();
37 const auto& elements = ops[0].type().as<type::Tuple>().elements();
39 if ( static_cast<uint64_t>(elements.size()) <= i->value() )
42 return elements[i->value()].type();
45 bool isLhs()
const {
return true; }
47 std::vector<Operand> operands()
const {
48 return {{.type = type::Tuple(type::Wildcard())}, {.type = type::UnsignedInteger(64)}};
51 void validate(
const expression::ResolvedOperator& i, operator_::position_t p)
const {
52 if (
auto ec = i.op1().tryAs<expression::Ctor>() )
53 if (
auto c = ec->ctor().tryAs<ctor::UnsignedInteger>() ) {
54 if ( c->value() < 0 ||
55 c->value() >=
static_cast<uint64_t
>(i.op0().type().as<type::Tuple>().elements().size()) )
56 p.node.addError(
"tuple index out of range");
61 p.node.addError(
"tuple index must be an integer constant");
64 std::string doc()
const {
65 return "Extracts the tuple element at the given index. The index must be a constant unsigned integer.";
69 BEGIN_OPERATOR_CUSTOM(tuple, Member)
72 return type::DocOnly(
"<type of element>");
74 auto id = ops[1].as<expression::Member>().
id();
75 auto elem = ops[0].type().as<type::Tuple>().elementByID(
id);
79 return elem->second->type();
82 bool isLhs()
const {
return true; }
84 std::vector<Operand> operands()
const {
85 return {{.type = type::Tuple(type::Wildcard())}, {.type = type::Member(type::Wildcard()), .doc =
"<id>"}};
88 void validate(
const expression::ResolvedOperator& i, operator_::position_t p)
const {
89 auto id = i.operands()[1].as<expression::Member>().
id();
90 auto elem = i.operands()[0].type().as<type::Tuple>().elementByID(
id);
93 p.node.addError(
"unknown tuple element");
96 std::string doc()
const {
return "Extracts the tuple element corresponding to the given ID."; }
99 BEGIN_OPERATOR_CUSTOM(tuple, CustomAssign)
102 return type::DocOnly(
"<tuple>");
104 return ops[0].type();
107 bool isLhs()
const {
return false; }
109 std::vector<Operand> operands()
const {
112 .type = type::Member(type::Wildcard()),
113 .doc =
"(x, ..., y)",
115 {.type = type::Tuple(type::Wildcard()), .doc =
"<tuple>"}};
119 void validate(
const expression::ResolvedOperator& i, operator_::position_t p)
const {
120 auto lhs = i.operands()[0].as<expression::Ctor>().ctor().as<ctor::Tuple>();
121 auto lhs_type = lhs.type().as<type::Tuple>();
122 auto rhs_type = i.operands()[1].type().tryAs<type::Tuple>();
124 p.node.addError(
"rhs is not a tuple");
128 if ( lhs_type.elements().size() != rhs_type->elements().size() ) {
129 p.node.addError(
"cannot assign tuples of different length");
133 for (
auto i = 0u; i < lhs_type.elements().size(); i++ ) {
134 const auto& lhs_elem = lhs.value()[i];
135 const auto& lhs_elem_type = lhs_type.elements()[i].type();
136 const auto& rhs_elem_type = rhs_type->elements()[i].type();
138 if ( ! lhs_elem.isLhs() )
139 p.node.addError(
util::fmt(
"cannot assign to expression: %s", to_node(lhs_elem)));
141 if ( ! type::sameExceptForConstness(lhs_elem_type, rhs_elem_type) )
142 p.node.addError(
util::fmt(
"type mismatch for element %d in assignment, expected type %s but got %s", i,
143 lhs_elem_type, rhs_elem_type));
147 std::string doc()
const {
return "Assigns element-wise to the left-hand-side tuple"; }
148 END_OPERATOR_CUSTOM_x
std::string fmt(const char *fmt, const Args &... args)
Definition: util.h:80