11 #include <hilti/ast/expression.h> 12 #include <hilti/ast/operator.h> 13 #include <hilti/ast/types/doc-only.h> 14 #include <hilti/ast/types/type.h> 15 #include <hilti/base/logger.h> 16 #include <hilti/base/type_erase.h> 17 #include <hilti/base/util.h> 18 #include <hilti/base/visitor-types.h> 24 namespace expression {
25 namespace resolved_operator {
28 class ResolvedOperator;
32 using ResolvedOperator = resolved_operator::detail::ResolvedOperator;
41 namespace expression {
42 class UnresolvedOperator;
51 const hilti::node::Range<Expression>&)>>;
53 inline std::optional<Type> type(
const OperandType& t,
const hilti::node::Range<Expression>& orig_ops,
54 const hilti::node::Range<Expression>& resolved_ops) {
55 if (
const auto& f = std::get_if<std::function<std::optional<Type>(
const hilti::node::Range<Expression>&,
56 const hilti::node::Range<Expression>&)>>(&t) )
57 return (*f)(orig_ops, resolved_ops);
59 return std::get<Type>(t);
62 inline std::optional<Type> type(
const OperandType& t,
const hilti::node::Range<Expression>& orig_ops,
63 const std::vector<Expression>& resolved_ops) {
64 auto resolved_ops_as_nodes = hilti::nodes(resolved_ops);
65 return type(t, orig_ops, hilti::node::Range<Expression>(resolved_ops_as_nodes));
68 inline std::optional<Type> type(
const OperandType& t,
const std::vector<Expression>& orig_ops,
69 const std::vector<Expression>& resolved_ops) {
70 auto orig_ops_as_nodes = hilti::nodes(orig_ops);
71 return type(t, hilti::node::Range<Expression>(orig_ops_as_nodes), resolved_ops);
74 inline auto operandType(
unsigned int op,
const char* doc =
"<no-doc>") {
75 return [=](
const hilti::node::Range<Expression>& ,
76 const hilti::node::Range<Expression>& resolved_ops) -> std::optional<Type> {
77 if ( resolved_ops.empty() )
80 if ( op >= resolved_ops.size() )
81 logger().internalError(
util::fmt(
"operandType(): index %d out of range, only %" PRIu64
" ops available", op,
82 resolved_ops.size()));
84 return resolved_ops[op].type();
88 inline auto elementType(
unsigned int op,
const char* doc =
"<type of element>",
bool infer_const =
true) {
89 return [=](
const hilti::node::Range<Expression>& ,
90 const hilti::node::Range<Expression>& resolved_ops) -> std::optional<Type> {
91 if ( resolved_ops.empty() )
94 if ( op >= resolved_ops.size() )
95 logger().internalError(
util::fmt(
"elementType(): index %d out of range, only %" PRIu64
" ops available", op,
96 resolved_ops.size()));
98 if ( type::isIterable(resolved_ops[op].type()) ) {
99 auto t = resolved_ops[op].type().elementType();
100 return (infer_const && resolved_ops[op].isConstant()) ? type::constant(t) : std::move(t);
107 inline auto constantElementType(
unsigned int op,
const char* doc =
"<type of element>") {
108 return [=](
const hilti::node::Range<Expression>& ,
109 const hilti::node::Range<Expression>& resolved_ops) -> std::optional<Type> {
110 if ( resolved_ops.empty() )
113 if ( op >= resolved_ops.size() )
114 logger().internalError(
util::fmt(
"elementType(): index %d out of range, only %" PRIu64
" ops available", op,
115 resolved_ops.size()));
117 if ( type::isIterable(resolved_ops[op].type()) )
118 return type::constant(resolved_ops[op].type().elementType());
124 inline auto iteratorType(
unsigned int op,
bool const_,
const char* doc =
"<iterator>") {
125 return [=](
const hilti::node::Range<Expression>& ,
126 const hilti::node::Range<Expression>& resolved_ops) -> std::optional<Type> {
127 if ( resolved_ops.empty() )
130 if ( op >= resolved_ops.size() )
131 logger().internalError(
util::fmt(
"iteratorType(): index %d out of range, only %" PRIu64
" ops available",
132 op, resolved_ops.size()));
134 if ( type::isIterable(resolved_ops[op].type()) )
135 return resolved_ops[op].type().iteratorType(const_);
141 inline auto dereferencedType(
unsigned int op,
const char* doc =
"<dereferenced type>",
bool infer_const =
true) {
142 return [=](
const hilti::node::Range<Expression>& ,
143 const hilti::node::Range<Expression>& resolved_ops) -> std::optional<Type> {
144 if ( resolved_ops.empty() )
147 if ( op >= resolved_ops.size() )
148 logger().internalError(
util::fmt(
"dereferencedType(): index %d out of range, only %" PRIu64
150 op, resolved_ops.size()));
152 if ( type::isDereferenceable(resolved_ops[op].type()) ) {
153 auto t = resolved_ops[op].type().dereferencedType();
158 return resolved_ops[op].isConstant() ? type::constant(t) : type::nonConstant(t);
165 inline auto sameTypeAs(
unsigned int op,
const char* doc =
"<no-doc>") {
166 return [=](
const hilti::node::Range<Expression>& ,
167 const hilti::node::Range<Expression>& resolved_ops) -> std::optional<Type> {
168 if ( resolved_ops.empty() )
171 if ( op >= resolved_ops.size() )
172 logger().internalError(
util::fmt(
"sameTypeAs(): index %d out of range, only %" PRIu64
" ops available", op,
173 resolved_ops.size()));
175 return resolved_ops[op].type();
179 inline auto typedType(
unsigned int op,
const char* doc =
"<type>") {
180 return [=](
const hilti::node::Range<Expression>& ,
181 const hilti::node::Range<Expression>& resolved_ops) -> std::optional<Type> {
182 if ( resolved_ops.empty() )
185 if ( op >= resolved_ops.size() )
186 logger().internalError(
util::fmt(
"typedType(): index %d out of range, only %" PRIu64
" ops available", op,
187 resolved_ops.size()));
189 return resolved_ops[op].type().as<
type::Type_>().typeValue();
195 std::optional<ID>
id;
197 bool optional =
false;
198 std::optional<Expression> default_ = {};
199 std::optional<std::string>
doc;
201 bool operator==(
const Operand& other)
const {
202 if (
this == &other )
205 if ( ! (std::holds_alternative<Type>(type) && std::holds_alternative<Type>(other.
type)) )
208 return std::get<Type>(type) == std::get<Type>(other.
type) &&
id == other.
id && optional == other.
optional &&
213 inline std::ostream& operator<<(std::ostream& out,
const Operand& op) {
214 if (
auto t = std::get_if<Type>(&op.
type) )
217 out <<
"<inferred type>";
220 out <<
' ' << *op.
id;
225 out <<
" (optional)";
230 using ResultType = OperandType;
233 enum Priority { Low, Normal };
247 Priority priority = Priority::Low;
307 constexpr
auto isCommutative(Kind k) {
315 case Kind::Sum:
return true;
321 case Kind::CustomAssign:
322 case Kind::DecrPostfix:
323 case Kind::DecrPrefix:
326 case Kind::Difference:
327 case Kind::DifferenceAssign:
329 case Kind::DivisionAssign:
332 case Kind::GreaterEqual:
333 case Kind::HasMember:
335 case Kind::IncrPostfix:
336 case Kind::IncrPrefix:
338 case Kind::IndexAssign:
340 case Kind::LowerEqual:
342 case Kind::MemberCall:
344 case Kind::MultipleAssign:
348 case Kind::ShiftLeft:
349 case Kind::ShiftRight:
353 case Kind::SumAssign:
354 case Kind::TryMember:
357 case Kind::Unset:
return false;
365 {Kind::BitAnd,
"&"}, {Kind::BitOr,
"|"},
366 {Kind::BitXor,
"^"}, {Kind::Call,
"call"},
367 {Kind::Cast,
"cast"}, {Kind::CustomAssign,
"="},
368 {Kind::DecrPostfix,
"--"}, {Kind::DecrPrefix,
"--"},
369 {Kind::Delete,
"delete"}, {Kind::Deref,
"*"},
370 {Kind::Division,
"/"}, {Kind::DivisionAssign,
"/="},
371 {Kind::Equal,
"=="}, {Kind::End,
"end"},
372 {Kind::Greater,
">"}, {Kind::GreaterEqual,
">="},
373 {Kind::HasMember,
"?."}, {Kind::In,
"in"},
374 {Kind::IncrPostfix,
"++"}, {Kind::IncrPrefix,
"++"},
375 {Kind::Index,
"index"}, {Kind::IndexAssign,
"index_assign"},
376 {Kind::Lower,
"<"}, {Kind::LowerEqual,
"<="},
377 {Kind::Member,
"."}, {Kind::MemberCall,
"method call"},
378 {Kind::Negate,
"~"}, {Kind::New,
"new"},
379 {Kind::Difference,
"-"}, {Kind::DifferenceAssign,
"-="},
380 {Kind::Modulo,
"%"}, {Kind::Multiple,
"*"},
381 {Kind::MultipleAssign,
"*="}, {Kind::Sum,
"+"},
382 {Kind::SumAssign,
"+="}, {Kind::Power,
"**"},
383 {Kind::ShiftLeft,
"<<"}, {Kind::ShiftRight,
">>"},
384 {Kind::SignNeg,
"-"}, {Kind::SignPos,
"+"},
385 {Kind::Size,
"size"}, {Kind::TryMember,
".?"},
386 {Kind::Unequal,
"!="}, {Kind::Unknown,
"<unknown>"},
387 {Kind::Unpack,
"unpack"}, {Kind::Unset,
"unset"}};
395 constexpr
auto to_string(Kind m) {
return util::enum_::to_string(m, detail::kinds); }
400 #include <hilti/autogen/__operator.h> 405 using Operator = operator_::detail::Operator;
407 inline bool operator==(
const Operator& x,
const Operator& y) {
411 return x.typename_() == y.typename_();
Definition: operator.h:194
OperandType type
Definition: operator.h:196
Definition: doc-only.h:19
std::optional< std::string > doc
Definition: operator.h:199
Definition: visitor-types.h:28
std::optional< Expression > default_
Definition: operator.h:198
Definition: operator.h:38
ResultType result
Definition: operator.h:248
void cannot_be_reached() __attribute__((noreturn))
Definition: util.cc:33
ID id
Definition: operator.h:249
std::optional< ID > id
Definition: operator.h:195
std::string fmt(const char *fmt, const Args &... args)
Definition: util.h:80
std::vector< Operand > args
Definition: operator.h:250
std::string doc
Definition: operator.h:251
bool optional
Definition: operator.h:197
Definition: operator.h:243