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;
52 std::function<std::optional<Type>(
const std::vector<Expression>&,
const std::vector<Expression>&)>>;
53 inline std::optional<Type> type(
const OperandType& t,
const std::vector<Expression>& orig_ops,
54 const std::vector<Expression>& resolved_ops) {
55 if (
const auto& f = std::get_if<
56 std::function<std::optional<Type>(
const std::vector<Expression>&,
const std::vector<Expression>&)>>(&t) )
57 return (*f)(orig_ops, resolved_ops);
59 return std::get<Type>(t);
62 inline auto operandType(
unsigned int op,
const char* doc =
"<no-doc>") {
63 return [=](
const std::vector<Expression>& ,
64 const std::vector<Expression>& resolved_ops) -> std::optional<Type> {
65 if ( resolved_ops.empty() )
68 if ( op >= resolved_ops.size() )
69 logger().internalError(
util::fmt(
"operandType(): index %d out of range, only %" PRIu64
" ops available", op,
70 resolved_ops.size()));
72 return resolved_ops[op].type();
76 inline auto elementType(
unsigned int op,
const char* doc =
"<type of element>",
bool infer_const =
true) {
77 return [=](
const std::vector<Expression>& ,
78 const std::vector<Expression>& resolved_ops) -> std::optional<Type> {
79 if ( resolved_ops.empty() )
82 if ( op >= resolved_ops.size() )
83 logger().internalError(
util::fmt(
"elementType(): index %d out of range, only %" PRIu64
" ops available", op,
84 resolved_ops.size()));
86 if ( type::isIterable(resolved_ops[op].type()) ) {
87 auto t = resolved_ops[op].type().elementType();
88 return (infer_const && resolved_ops[op].isConstant()) ? type::constant(t) : std::move(t);
95 inline auto constantElementType(
unsigned int op,
const char* doc =
"<type of element>") {
96 return [=](
const std::vector<Expression>& ,
97 const std::vector<Expression>& resolved_ops) -> std::optional<Type> {
98 if ( resolved_ops.empty() )
101 if ( op >= resolved_ops.size() )
102 logger().internalError(
util::fmt(
"elementType(): index %d out of range, only %" PRIu64
" ops available", op,
103 resolved_ops.size()));
105 if ( type::isIterable(resolved_ops[op].type()) )
106 return type::constant(resolved_ops[op].type().elementType());
112 inline auto iteratorType(
unsigned int op,
bool const_,
const char* doc =
"<iterator>") {
113 return [=](
const std::vector<Expression>& ,
114 const std::vector<Expression>& resolved_ops) -> std::optional<Type> {
115 if ( resolved_ops.empty() )
118 if ( op >= resolved_ops.size() )
119 logger().internalError(
util::fmt(
"iteratorType(): index %d out of range, only %" PRIu64
" ops available",
120 op, resolved_ops.size()));
122 if ( type::isIterable(resolved_ops[op].type()) )
123 return resolved_ops[op].type().iteratorType(const_);
129 inline auto dereferencedType(
unsigned int op,
const char* doc =
"<dereferenced type>",
bool infer_const =
true) {
130 return [=](
const std::vector<Expression>& ,
131 const std::vector<Expression>& resolved_ops) -> std::optional<Type> {
132 if ( resolved_ops.empty() )
135 if ( op >= resolved_ops.size() )
136 logger().internalError(
util::fmt(
"dereferencedType(): index %d out of range, only %" PRIu64
138 op, resolved_ops.size()));
140 if ( type::isDereferencable(resolved_ops[op].type()) ) {
141 auto t = resolved_ops[op].type().dereferencedType();
142 return (infer_const && resolved_ops[op].isConstant()) ? type::constant(t) : std::move(t);
149 inline auto sameTypeAs(
unsigned int op,
const char* doc =
"<no-doc>") {
150 return [=](
const std::vector<Expression>& ,
151 const std::vector<Expression>& resolved_ops) -> std::optional<Type> {
152 if ( resolved_ops.empty() )
155 if ( op >= resolved_ops.size() )
156 logger().internalError(
util::fmt(
"sameTypeAs(): index %d out of range, only %" PRIu64
" ops available", op,
157 resolved_ops.size()));
159 return resolved_ops[op].type();
163 inline auto typedType(
unsigned int op,
const char* doc =
"<type>") {
164 return [=](
const std::vector<Expression>& ,
165 const std::vector<Expression>& resolved_ops) -> std::optional<Type> {
166 if ( resolved_ops.empty() )
169 if ( op >= resolved_ops.size() )
170 logger().internalError(
util::fmt(
"typedType(): index %d out of range, only %" PRIu64
" ops available", op,
171 resolved_ops.size()));
173 return type::effectiveType(resolved_ops[op].type().as<type::Type_>().typeValue());
179 std::optional<ID>
id;
181 bool optional =
false;
182 std::optional<Expression> default_ = {};
183 std::optional<std::string>
doc;
185 bool operator==(
const Operand& other)
const {
186 if (
this == &other )
189 if ( ! (std::holds_alternative<Type>(type) && std::holds_alternative<Type>(other.
type)) )
192 return std::get<Type>(type) == std::get<Type>(other.
type) &&
id == other.
id && optional == other.
optional &&
197 inline std::ostream& operator<<(std::ostream& out,
const Operand& op) {
198 if (
auto t = std::get_if<Type>(&op.
type) )
201 out <<
"<inferred type>";
204 out <<
' ' << *op.
id;
209 out <<
" (optional)";
214 using ResultType = OperandType;
286 constexpr
auto isCommutative(Kind k) {
294 case Kind::Sum:
return true;
300 case Kind::DecrPostfix:
301 case Kind::DecrPrefix:
304 case Kind::Difference:
305 case Kind::DifferenceAssign:
307 case Kind::DivisionAssign:
310 case Kind::GreaterEqual:
311 case Kind::HasMember:
313 case Kind::IncrPostfix:
314 case Kind::IncrPrefix:
316 case Kind::IndexAssign:
318 case Kind::LowerEqual:
320 case Kind::MemberCall:
322 case Kind::MultipleAssign:
326 case Kind::ShiftLeft:
327 case Kind::ShiftRight:
331 case Kind::SumAssign:
332 case Kind::TryMember:
335 case Kind::Unset:
return false;
343 {Kind::Begin,
"begin"},
347 {Kind::Call,
"call"},
348 {Kind::Cast,
"cast"},
349 {Kind::DecrPostfix,
"--"},
350 {Kind::DecrPrefix,
"--"},
351 {Kind::Delete,
"delete"},
353 {Kind::Division,
"/"},
354 {Kind::DivisionAssign,
"/="},
357 {Kind::Greater,
">"},
358 {Kind::GreaterEqual,
">="},
359 {Kind::HasMember,
"?."},
361 {Kind::IncrPostfix,
"++"},
362 {Kind::IncrPrefix,
"++"},
363 {Kind::Index,
"index"},
364 {Kind::IndexAssign,
"index_assign"},
366 {Kind::LowerEqual,
"<="},
368 {Kind::MemberCall,
"method call"},
371 {Kind::Difference,
"-"},
372 {Kind::DifferenceAssign,
"-="},
374 {Kind::Multiple,
"*"},
375 {Kind::MultipleAssign,
"*="},
377 {Kind::SumAssign,
"+="},
379 {Kind::ShiftLeft,
"<<"},
380 {Kind::ShiftRight,
">>"},
381 {Kind::SignNeg,
"-"},
382 {Kind::SignPos,
"+"},
383 {Kind::Size,
"size"},
384 {Kind::TryMember,
".?"},
385 {Kind::Unequal,
"!="},
386 {Kind::Unknown,
"<unknown>"},
387 {Kind::Unpack,
"unpack"},
388 {Kind::Unset,
"unset"}};
396 constexpr
auto to_string(Kind m) {
return util::enum_::to_string(m, detail::kinds); }
401 #include <hilti/autogen/__operator.h> 406 using Operator = operator_::detail::Operator;
408 inline bool operator==(
const Operator& x,
const Operator& y) {
412 return x.typename_() == y.typename_();
Definition: operator.h:178
OperandType type
Definition: operator.h:180
Definition: doc-only.h:19
std::optional< std::string > doc
Definition: operator.h:183
Definition: visitor-types.h:26
std::optional< Expression > default_
Definition: operator.h:182
Definition: operator.h:38
ResultType result
Definition: operator.h:228
void cannot_be_reached() __attribute__((noreturn))
Definition: util.cc:33
ID id
Definition: operator.h:229
std::optional< ID > id
Definition: operator.h:179
std::string fmt(const char *fmt, const Args &... args)
Definition: util.h:80
std::vector< Operand > args
Definition: operator.h:230
std::string doc
Definition: operator.h:231
bool optional
Definition: operator.h:181
Definition: operator.h:224