blob: 6930c0f4fe389ff8c5d6951bbfd046c8fe5a20fd [file] [log] [blame]
Andreas Huber1aec3972016-08-26 09:26:32 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Yifan Hong52165692016-08-12 18:06:40 -070017#include "ConstantExpression.h"
18
Yifan Hong57886972016-08-17 10:42:15 -070019#include <android-base/logging.h>
Timur Iskhakovb58f4182017-08-29 15:19:24 -070020#include <android-base/parseint.h>
21#include <stdio.h>
22#include <algorithm>
Timur Iskhakove8ee6a02017-09-06 11:42:10 -070023#include <iostream>
Yifan Hong57886972016-08-17 10:42:15 -070024#include <sstream>
Timur Iskhakovb58f4182017-08-29 15:19:24 -070025#include <string>
Yifan Hong57886972016-08-17 10:42:15 -070026
Yifan Hongf24fa852016-09-23 11:03:15 -070027#include "EnumType.h"
Timur Iskhakov7296af12017-08-09 21:52:48 +000028#include "Scope.h" // LocalIdentifier
Yifan Hongf24fa852016-09-23 11:03:15 -070029
Yifan Hong57886972016-08-17 10:42:15 -070030// The macros are really nasty here. Consider removing
31// as many macros as possible.
32
Timur Iskhakovd27580c2017-08-09 20:14:52 -070033#define OPEQ(__y__) (std::string(mOp) == std::string(__y__))
34#define COMPUTE_UNARY(__op__) if (op == std::string(#__op__)) return __op__ val;
35#define COMPUTE_BINARY(__op__) if (op == std::string(#__op__)) return lval __op__ rval;
Yifan Hong57886972016-08-17 10:42:15 -070036#define OP_IS_BIN_ARITHMETIC (OPEQ("+") || OPEQ("-") || OPEQ("*") || OPEQ("/") || OPEQ("%"))
37#define OP_IS_BIN_BITFLIP (OPEQ("|") || OPEQ("^") || OPEQ("&"))
38#define OP_IS_BIN_COMP (OPEQ("<") || OPEQ(">") || OPEQ("<=") || OPEQ(">=") || OPEQ("==") || OPEQ("!="))
39#define OP_IS_BIN_SHIFT (OPEQ(">>") || OPEQ("<<"))
40#define OP_IS_BIN_LOGICAL (OPEQ("||") || OPEQ("&&"))
41#define SK(__x__) ScalarType::Kind::KIND_##__x__
Yifan Hongf24fa852016-09-23 11:03:15 -070042#define SHOULD_NOT_REACH() CHECK(false) << __LINE__ << ": should not reach here: "
Yifan Hong57886972016-08-17 10:42:15 -070043
Chih-Hung Hsieh306cc4b2017-08-02 14:59:25 -070044// NOLINT to suppress missing parentheses warnings about __def__.
Yifan Hong57886972016-08-17 10:42:15 -070045#define SWITCH_KIND(__cond__, __action__, __def__) \
Yifan Hong2bd3c1f2016-09-22 13:20:05 -070046 switch(__cond__) { \
47 case SK(BOOL): __action__(bool) \
48 case SK(UINT8): __action__(uint8_t) \
49 case SK(INT8): __action__(int8_t) \
50 case SK(UINT16): __action__(uint16_t) \
51 case SK(INT16): __action__(int16_t) \
52 case SK(UINT32): __action__(uint32_t) \
53 case SK(INT32): __action__(int32_t) \
54 case SK(UINT64): __action__(uint64_t) \
55 case SK(INT64): __action__(int64_t) \
Chih-Hung Hsieh306cc4b2017-08-02 14:59:25 -070056 default: __def__ /* NOLINT */ \
57 }
Yifan Hong52165692016-08-12 18:06:40 -070058
59namespace android {
60
Yifan Hongf24fa852016-09-23 11:03:15 -070061static inline bool isSupported(ScalarType::Kind kind) {
Timur Iskhakov63f39902017-08-29 15:47:29 -070062 return SK(BOOL) == kind || ScalarType(kind, nullptr /* parent */).isValidEnumStorageType();
Yifan Hongf24fa852016-09-23 11:03:15 -070063}
64
Yifan Hong57886972016-08-17 10:42:15 -070065/* See docs at the end for details on integral promotion. */
66ScalarType::Kind integralPromotion(ScalarType::Kind in) {
Yifan Hong2bd3c1f2016-09-22 13:20:05 -070067 return SK(INT32) < in ? in : SK(INT32); // note that KIND_INT32 < KIND_UINT32
Yifan Hong52165692016-08-12 18:06:40 -070068}
69
Yifan Hong57886972016-08-17 10:42:15 -070070/* See docs at the end for details on usual arithmetic conversion. */
Yifan Hong2bd3c1f2016-09-22 13:20:05 -070071ScalarType::Kind usualArithmeticConversion(ScalarType::Kind lft,
72 ScalarType::Kind rgt) {
Yifan Hongf24fa852016-09-23 11:03:15 -070073 CHECK(isSupported(lft) && isSupported(rgt));
Yifan Hong2bd3c1f2016-09-22 13:20:05 -070074 // Kinds in concern: bool, (u)int[8|16|32|64]
75 if(lft == rgt) return lft; // easy case
76 if(lft == SK(BOOL)) return rgt;
77 if(rgt == SK(BOOL)) return lft;
78 bool isLftSigned = (lft == SK(INT8)) || (lft == SK(INT16))
79 || (lft == SK(INT32)) || (lft == SK(INT64));
80 bool isRgtSigned = (rgt == SK(INT8)) || (rgt == SK(INT16))
81 || (rgt == SK(INT32)) || (rgt == SK(INT64));
82 if(isLftSigned == isRgtSigned) return lft < rgt ? rgt : lft;
83 ScalarType::Kind unsignedRank = isLftSigned ? rgt : lft;
84 ScalarType::Kind signedRank = isLftSigned ? lft : rgt;
85 if(unsignedRank >= signedRank) return unsignedRank;
86 if(signedRank > unsignedRank) return signedRank;
Yifan Hong57886972016-08-17 10:42:15 -070087
Yifan Hong2bd3c1f2016-09-22 13:20:05 -070088 // Although there is such rule to return "the unsigned counterpart of
89 // the signed operand", it should not reach here in our HIDL grammar.
Steven Morelandcbff5612017-10-11 17:01:54 -070090 CHECK(false) << "Could not do usual arithmetic conversion for type " << lft << "and" << rgt;
Yifan Hong2bd3c1f2016-09-22 13:20:05 -070091 switch(signedRank) {
92 case SK(INT8): return SK(UINT8);
93 case SK(INT16): return SK(UINT16);
94 case SK(INT32): return SK(UINT32);
95 case SK(INT64): return SK(UINT64);
96 default: return SK(UINT64);
97 }
Yifan Hong52165692016-08-12 18:06:40 -070098}
Yifan Hong57886972016-08-17 10:42:15 -070099
100template <class T>
Timur Iskhakov7296af12017-08-09 21:52:48 +0000101T handleUnary(const std::string& op, T val) {
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700102 COMPUTE_UNARY(+)
103 COMPUTE_UNARY(-)
104 COMPUTE_UNARY(!)
Yifan Hong2ddbe4b2020-02-20 17:30:00 -0800105
106// bitwise negation of a boolean expression always evaluates to 'true'
107#pragma clang diagnostic push
108#pragma clang diagnostic ignored "-Wbool-operation"
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700109 COMPUTE_UNARY(~)
Yifan Hong2ddbe4b2020-02-20 17:30:00 -0800110#pragma clang diagnostic pop
111
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700112 // Should not reach here.
Yifan Hongf24fa852016-09-23 11:03:15 -0700113 SHOULD_NOT_REACH() << "Could not handleUnary for " << op << " " << val;
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700114 return static_cast<T>(0xdeadbeef);
Yifan Hong57886972016-08-17 10:42:15 -0700115}
116
117template <class T>
Timur Iskhakov7296af12017-08-09 21:52:48 +0000118T handleBinaryCommon(T lval, const std::string& op, T rval) {
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700119 COMPUTE_BINARY(+)
120 COMPUTE_BINARY(-)
121 COMPUTE_BINARY(*)
122 COMPUTE_BINARY(/)
123 COMPUTE_BINARY(%)
124 COMPUTE_BINARY(|)
125 COMPUTE_BINARY(^)
126 COMPUTE_BINARY(&)
127 // comparison operators: return 0 or 1 by nature.
128 COMPUTE_BINARY(==)
129 COMPUTE_BINARY(!=)
130 COMPUTE_BINARY(<)
131 COMPUTE_BINARY(>)
132 COMPUTE_BINARY(<=)
133 COMPUTE_BINARY(>=)
134 // Should not reach here.
Yifan Hongf24fa852016-09-23 11:03:15 -0700135 SHOULD_NOT_REACH() << "Could not handleBinaryCommon for "
136 << lval << " " << op << " " << rval;
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700137 return static_cast<T>(0xdeadbeef);
Yifan Hong57886972016-08-17 10:42:15 -0700138}
139
Yi Kongd5f12082022-02-28 15:56:28 +0800140// The compiler doesn't know T is at least KIND_INT32, and will instantiate bool
141// version of this function, and will warn about converting the result of '<<'
142// to a boolean.
143#pragma GCC diagnostic push
144#pragma GCC diagnostic ignored "-Wint-in-bool-context"
Yifan Hong57886972016-08-17 10:42:15 -0700145template <class T>
Timur Iskhakov7296af12017-08-09 21:52:48 +0000146T handleShift(T lval, const std::string& op, int64_t rval) {
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700147 // just cast rval to int64_t and it should fit.
148 COMPUTE_BINARY(>>)
149 COMPUTE_BINARY(<<)
150 // Should not reach here.
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700151 SHOULD_NOT_REACH() << "Could not handleShift for "
Yifan Hongf24fa852016-09-23 11:03:15 -0700152 << lval << " " << op << " " << rval;
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700153 return static_cast<T>(0xdeadbeef);
Yifan Hong57886972016-08-17 10:42:15 -0700154}
Yi Kongd5f12082022-02-28 15:56:28 +0800155#pragma GCC diagnostic pop
Yifan Hong57886972016-08-17 10:42:15 -0700156
Timur Iskhakov7296af12017-08-09 21:52:48 +0000157bool handleLogical(bool lval, const std::string& op, bool rval) {
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700158 COMPUTE_BINARY(||);
159 COMPUTE_BINARY(&&);
160 // Should not reach here.
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700161 SHOULD_NOT_REACH() << "Could not handleLogical for "
Yifan Hongf24fa852016-09-23 11:03:15 -0700162 << lval << " " << op << " " << rval;
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700163 return false;
Yifan Hong57886972016-08-17 10:42:15 -0700164}
165
Timur Iskhakov7296af12017-08-09 21:52:48 +0000166std::unique_ptr<ConstantExpression> ConstantExpression::Zero(ScalarType::Kind kind) {
167 return ValueOf(kind, 0);
Yifan Hongf24fa852016-09-23 11:03:15 -0700168}
169
Timur Iskhakov7296af12017-08-09 21:52:48 +0000170std::unique_ptr<ConstantExpression> ConstantExpression::One(ScalarType::Kind kind) {
171 return ValueOf(kind, 1);
Yifan Hongf24fa852016-09-23 11:03:15 -0700172}
173
Timur Iskhakov7296af12017-08-09 21:52:48 +0000174std::unique_ptr<ConstantExpression> ConstantExpression::ValueOf(ScalarType::Kind kind,
175 uint64_t value) {
176 return std::make_unique<LiteralConstantExpression>(kind, value);
Yifan Hong30b5d1f2017-04-03 12:19:25 -0700177}
178
Neel Mehta3b414a82019-07-02 15:47:48 -0700179ConstantExpression::ConstantExpression(const std::string& expr) : mExpr(expr) {}
180
Timur Iskhakov7296af12017-08-09 21:52:48 +0000181bool ConstantExpression::isEvaluated() const {
182 return mIsEvaluated;
183}
184
Neel Mehta3b414a82019-07-02 15:47:48 -0700185LiteralConstantExpression::LiteralConstantExpression(ScalarType::Kind kind, uint64_t value,
186 const std::string& expr)
187 : ConstantExpression(expr) {
Steven Morelandd9d6dcb2017-09-20 15:55:39 -0700188 CHECK(!expr.empty());
Yifan Hong30b5d1f2017-04-03 12:19:25 -0700189 CHECK(isSupported(kind));
Neel Mehta3b414a82019-07-02 15:47:48 -0700190
Steven Moreland77943692018-08-09 12:53:42 -0700191 mTrivialDescription = std::to_string(value) == expr;
Timur Iskhakov7296af12017-08-09 21:52:48 +0000192 mValueKind = kind;
193 mValue = value;
194 mIsEvaluated = true;
Yifan Hongf24fa852016-09-23 11:03:15 -0700195}
196
Steven Morelandd9d6dcb2017-09-20 15:55:39 -0700197LiteralConstantExpression::LiteralConstantExpression(ScalarType::Kind kind, uint64_t value)
198 : LiteralConstantExpression(kind, value, std::to_string(value)) {}
199
200LiteralConstantExpression* LiteralConstantExpression::tryParse(const std::string& value) {
Timur Iskhakov7296af12017-08-09 21:52:48 +0000201 CHECK(!value.empty());
Yifan Hongf24fa852016-09-23 11:03:15 -0700202
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700203 bool isLong = false, isUnsigned = false;
Timur Iskhakov7296af12017-08-09 21:52:48 +0000204 bool isHex = (value[0] == '0' && value.length() > 1 && (value[1] == 'x' || value[1] == 'X'));
205
206 auto rbegin = value.rbegin();
207 auto rend = value.rend();
208 for (; rbegin != rend && (*rbegin == 'u' || *rbegin == 'U' || *rbegin == 'l' || *rbegin == 'L');
209 ++rbegin) {
210 isUnsigned |= (*rbegin == 'u' || *rbegin == 'U');
211 isLong |= (*rbegin == 'l' || *rbegin == 'L');
Yifan Hong57886972016-08-17 10:42:15 -0700212 }
Timur Iskhakov7296af12017-08-09 21:52:48 +0000213 std::string newVal(value.begin(), rbegin.base());
214 CHECK(!newVal.empty());
Steven Morelandd9d6dcb2017-09-20 15:55:39 -0700215
216 uint64_t rawValue = 0;
217
218 bool parseOK = base::ParseUint(newVal, &rawValue);
219 if (!parseOK) {
220 return nullptr;
221 }
222
223 ScalarType::Kind kind;
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700224
225 // guess literal type.
226 if(isLong) {
227 if(isUnsigned) // ul
Steven Morelandd9d6dcb2017-09-20 15:55:39 -0700228 kind = SK(UINT64);
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700229 else // l
Steven Morelandd9d6dcb2017-09-20 15:55:39 -0700230 kind = SK(INT64);
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700231 } else { // no l suffix
232 if(isUnsigned) { // u
Steven Morelandd9d6dcb2017-09-20 15:55:39 -0700233 if(rawValue <= UINT32_MAX)
234 kind = SK(UINT32);
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700235 else
Steven Morelandd9d6dcb2017-09-20 15:55:39 -0700236 kind = SK(UINT64);
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700237 } else { // no suffix
238 if(isHex) {
Steven Morelandd9d6dcb2017-09-20 15:55:39 -0700239 if(rawValue <= INT32_MAX) // rawValue always >= 0
240 kind = SK(INT32);
241 else if(rawValue <= UINT32_MAX)
242 kind = SK(UINT32);
243 else if(rawValue <= INT64_MAX) // rawValue always >= 0
244 kind = SK(INT64);
245 else if(rawValue <= UINT64_MAX)
246 kind = SK(UINT64);
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700247 else
Steven Morelandd9d6dcb2017-09-20 15:55:39 -0700248 return nullptr;
249 } else {
250 if(rawValue <= INT32_MAX) // rawValue always >= 0
251 kind = SK(INT32);
252 else
253 kind = SK(INT64);
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700254 }
255 }
256 }
Steven Morelandd9d6dcb2017-09-20 15:55:39 -0700257
258 return new LiteralConstantExpression(kind, rawValue, value);
Yifan Hong57886972016-08-17 10:42:15 -0700259}
260
Timur Iskhakov7296af12017-08-09 21:52:48 +0000261void LiteralConstantExpression::evaluate() {
262 // Evaluated in constructor
263 CHECK(isEvaluated());
264}
Yifan Hongf24fa852016-09-23 11:03:15 -0700265
Timur Iskhakov7296af12017-08-09 21:52:48 +0000266void UnaryConstantExpression::evaluate() {
267 if (isEvaluated()) return;
Timur Iskhakov891a8662017-08-25 21:53:48 -0700268 CHECK(mUnary->isEvaluated());
Timur Iskhakov7296af12017-08-09 21:52:48 +0000269 mIsEvaluated = true;
270
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700271 mValueKind = mUnary->mValueKind;
Timur Iskhakov7296af12017-08-09 21:52:48 +0000272
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700273#define CASE_UNARY(__type__) \
274 mValue = handleUnary(mOp, static_cast<__type__>(mUnary->mValue)); \
Timur Iskhakov7296af12017-08-09 21:52:48 +0000275 return;
Yifan Hong57886972016-08-17 10:42:15 -0700276
Yifan Hongf24fa852016-09-23 11:03:15 -0700277 SWITCH_KIND(mValueKind, CASE_UNARY, SHOULD_NOT_REACH(); return;)
Yifan Hong52165692016-08-12 18:06:40 -0700278}
Yifan Hong57886972016-08-17 10:42:15 -0700279
Timur Iskhakov7296af12017-08-09 21:52:48 +0000280void BinaryConstantExpression::evaluate() {
281 if (isEvaluated()) return;
Timur Iskhakov891a8662017-08-25 21:53:48 -0700282 CHECK(mLval->isEvaluated());
283 CHECK(mRval->isEvaluated());
Timur Iskhakov7296af12017-08-09 21:52:48 +0000284 mIsEvaluated = true;
285
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700286 bool isArithmeticOrBitflip = OP_IS_BIN_ARITHMETIC || OP_IS_BIN_BITFLIP;
287
288 // CASE 1: + - * / % | ^ & < > <= >= == !=
289 if(isArithmeticOrBitflip || OP_IS_BIN_COMP) {
290 // promoted kind for both operands.
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700291 ScalarType::Kind promoted = usualArithmeticConversion(integralPromotion(mLval->mValueKind),
292 integralPromotion(mRval->mValueKind));
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700293 // result kind.
294 mValueKind = isArithmeticOrBitflip
295 ? promoted // arithmetic or bitflip operators generates promoted type
296 : SK(BOOL); // comparison operators generates bool
297
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700298#define CASE_BINARY_COMMON(__type__) \
299 mValue = handleBinaryCommon(static_cast<__type__>(mLval->mValue), mOp, \
300 static_cast<__type__>(mRval->mValue)); \
Timur Iskhakov7296af12017-08-09 21:52:48 +0000301 return;
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700302
Yifan Hongf24fa852016-09-23 11:03:15 -0700303 SWITCH_KIND(promoted, CASE_BINARY_COMMON, SHOULD_NOT_REACH(); return;)
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700304 }
305
306 // CASE 2: << >>
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700307 std::string newOp = mOp;
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700308 if(OP_IS_BIN_SHIFT) {
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700309 mValueKind = integralPromotion(mLval->mValueKind);
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700310 // instead of promoting rval, simply casting it to int64 should also be good.
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700311 int64_t numBits = mRval->cast<int64_t>();
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700312 if(numBits < 0) {
313 // shifting with negative number of bits is undefined in C. In HIDL it
314 // is defined as shifting into the other direction.
Timur Iskhakov7296af12017-08-09 21:52:48 +0000315 newOp = OPEQ("<<") ? std::string(">>") : std::string("<<");
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700316 numBits = -numBits;
317 }
318
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700319#define CASE_SHIFT(__type__) \
320 mValue = handleShift(static_cast<__type__>(mLval->mValue), newOp, numBits); \
Timur Iskhakov7296af12017-08-09 21:52:48 +0000321 return;
Yifan Hong57886972016-08-17 10:42:15 -0700322
Yifan Hongf24fa852016-09-23 11:03:15 -0700323 SWITCH_KIND(mValueKind, CASE_SHIFT, SHOULD_NOT_REACH(); return;)
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700324 }
Yifan Hong57886972016-08-17 10:42:15 -0700325
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700326 // CASE 3: && ||
327 if(OP_IS_BIN_LOGICAL) {
328 mValueKind = SK(BOOL);
329 // easy; everything is bool.
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700330 mValue = handleLogical(mLval->mValue, mOp, mRval->mValue);
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700331 return;
332 }
Yifan Hong57886972016-08-17 10:42:15 -0700333
Yifan Hongf24fa852016-09-23 11:03:15 -0700334 SHOULD_NOT_REACH();
Yifan Hong57886972016-08-17 10:42:15 -0700335}
336
Timur Iskhakov7296af12017-08-09 21:52:48 +0000337void TernaryConstantExpression::evaluate() {
338 if (isEvaluated()) return;
Timur Iskhakov891a8662017-08-25 21:53:48 -0700339 CHECK(mCond->isEvaluated());
340 CHECK(mTrueVal->isEvaluated());
341 CHECK(mFalseVal->isEvaluated());
Timur Iskhakov7296af12017-08-09 21:52:48 +0000342 mIsEvaluated = true;
343
Timur Iskhakov891a8662017-08-25 21:53:48 -0700344 // note: for ?:, unlike arithmetic ops, integral promotion is not processed.
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700345 mValueKind = usualArithmeticConversion(mTrueVal->mValueKind, mFalseVal->mValueKind);
Yifan Hong57886972016-08-17 10:42:15 -0700346
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700347#define CASE_TERNARY(__type__) \
348 mValue = mCond->mValue ? (static_cast<__type__>(mTrueVal->mValue)) \
349 : (static_cast<__type__>(mFalseVal->mValue)); \
Timur Iskhakov7296af12017-08-09 21:52:48 +0000350 return;
Yifan Hong57886972016-08-17 10:42:15 -0700351
Yifan Hongf24fa852016-09-23 11:03:15 -0700352 SWITCH_KIND(mValueKind, CASE_TERNARY, SHOULD_NOT_REACH(); return;)
Yifan Hong52165692016-08-12 18:06:40 -0700353}
354
Timur Iskhakov7296af12017-08-09 21:52:48 +0000355void ReferenceConstantExpression::evaluate() {
356 if (isEvaluated()) return;
Timur Iskhakov891a8662017-08-25 21:53:48 -0700357 CHECK(mReference->constExpr() != nullptr);
Timur Iskhakov7296af12017-08-09 21:52:48 +0000358
Timur Iskhakovd27580c2017-08-09 20:14:52 -0700359 ConstantExpression* expr = mReference->constExpr();
Timur Iskhakov891a8662017-08-25 21:53:48 -0700360 CHECK(expr->isEvaluated());
Timur Iskhakov7296af12017-08-09 21:52:48 +0000361
362 mValueKind = expr->mValueKind;
363 mValue = expr->mValue;
364 mIsEvaluated = true;
Yifan Hong52165692016-08-12 18:06:40 -0700365}
Yifan Hong57886972016-08-17 10:42:15 -0700366
Steven Moreland12f0ab12018-11-02 17:27:37 -0700367status_t AttributeConstantExpression::validate() const {
368 if (mTag == "len") {
369 if (!mReference->isEnum()) {
370 std::cerr << "ERROR: " << mExpr << " refers to " << mReference->typeName()
371 << " but should refer to an enum." << std::endl;
372 return UNKNOWN_ERROR;
373 }
374 } else {
375 std::cerr << "ERROR: " << mExpr << " is not a supported tag" << std::endl;
376 return UNKNOWN_ERROR;
377 }
378
379 return OK;
380}
381
382void AttributeConstantExpression::evaluate() {
383 if (isEvaluated()) return;
384
385 CHECK(mTag == "len");
386 CHECK(mReference->isEnum());
387
388 EnumType* enumType = static_cast<EnumType*>(mReference.get());
389 mValue = enumType->numValueNames();
390
391 if (mValue <= INT32_MAX)
392 mValueKind = SK(INT32);
393 else
394 mValueKind = SK(INT64);
395
396 mIsEvaluated = true;
397}
398
Timur Iskhakov7296af12017-08-09 21:52:48 +0000399std::unique_ptr<ConstantExpression> ConstantExpression::addOne(ScalarType::Kind baseKind) {
400 auto ret = std::make_unique<BinaryConstantExpression>(
401 this, "+", ConstantExpression::One(baseKind).release());
Timur Iskhakov7296af12017-08-09 21:52:48 +0000402 return ret;
Yifan Hongf24fa852016-09-23 11:03:15 -0700403}
404
Yifan Hongfc610cd2016-09-22 13:34:45 -0700405std::string ConstantExpression::value() const {
Steven Morelandf21962d2018-08-09 12:44:40 -0700406 return value(mValueKind);
Yifan Hongf24fa852016-09-23 11:03:15 -0700407}
408
Yifan Hongc07b2022016-11-08 12:44:24 -0800409std::string ConstantExpression::value(ScalarType::Kind castKind) const {
Timur Iskhakov7296af12017-08-09 21:52:48 +0000410 CHECK(isEvaluated());
Steven Morelandf21962d2018-08-09 12:44:40 -0700411 return rawValue(castKind) + descriptionSuffix();
Yifan Hongc07b2022016-11-08 12:44:24 -0800412}
413
Yifan Hongf24fa852016-09-23 11:03:15 -0700414std::string ConstantExpression::cppValue() const {
415 return cppValue(mValueKind);
Yifan Hong52165692016-08-12 18:06:40 -0700416}
417
Yifan Hongfc610cd2016-09-22 13:34:45 -0700418std::string ConstantExpression::cppValue(ScalarType::Kind castKind) const {
Timur Iskhakov7296af12017-08-09 21:52:48 +0000419 CHECK(isEvaluated());
Yifan Hongf24fa852016-09-23 11:03:15 -0700420 std::string literal(rawValue(castKind));
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700421 // this is a hack to translate
422 // enum x : int64_t { y = 1l << 63 };
423 // into
424 // enum class x : int64_t { y = (int64_t)-9223372036854775808ull };
425 // by adding the explicit cast.
426 // Because 9223372036854775808 is uint64_t, and
427 // -(uint64_t)9223372036854775808 == 9223372036854775808 could not
428 // be narrowed to int64_t.
429 if(castKind == SK(INT64) && (int64_t)mValue == INT64_MIN) {
Steven Morelandf21962d2018-08-09 12:44:40 -0700430 literal = "static_cast<" +
431 ScalarType(SK(INT64), nullptr /* parent */).getCppStackType() // "int64_t"
432 + ">(" + literal + "ull)";
433 } else {
434 // add suffix if necessary.
435 if (castKind == SK(UINT32) || castKind == SK(UINT64)) literal += "u";
436 if (castKind == SK(UINT64) || castKind == SK(INT64)) literal += "ll";
Yifan Hong2bd3c1f2016-09-22 13:20:05 -0700437 }
Yifan Hong57886972016-08-17 10:42:15 -0700438
Steven Morelandf21962d2018-08-09 12:44:40 -0700439 return literal + descriptionSuffix();
Yifan Hong57886972016-08-17 10:42:15 -0700440}
441
Yifan Hongf24fa852016-09-23 11:03:15 -0700442std::string ConstantExpression::javaValue() const {
443 return javaValue(mValueKind);
Yifan Hong19ca75a2016-08-31 10:20:03 -0700444}
445
Yifan Hongf24fa852016-09-23 11:03:15 -0700446std::string ConstantExpression::javaValue(ScalarType::Kind castKind) const {
Timur Iskhakov7296af12017-08-09 21:52:48 +0000447 CHECK(isEvaluated());
Steven Morelandf21962d2018-08-09 12:44:40 -0700448 std::string literal;
449
Yifan Hongf24fa852016-09-23 11:03:15 -0700450 switch(castKind) {
Steven Morelandf21962d2018-08-09 12:44:40 -0700451 case SK(UINT64):
452 literal = rawValue(SK(INT64)) + "L";
453 break;
454 case SK(INT64):
455 literal = rawValue(SK(INT64)) + "L";
456 break;
457 case SK(UINT32):
458 literal = rawValue(SK(INT32));
459 break;
460 case SK(UINT16):
461 literal = rawValue(SK(INT16));
462 break;
463 case SK(UINT8):
464 literal = rawValue(SK(INT8));
465 break;
Yifan Hongf24fa852016-09-23 11:03:15 -0700466 case SK(BOOL) :
Steven Morelandf21962d2018-08-09 12:44:40 -0700467 literal = this->cast<bool>() ? "true" : "false";
468 break;
469 default:
470 literal = rawValue(castKind);
471 break;
Yifan Hongf24fa852016-09-23 11:03:15 -0700472 }
Steven Morelandf21962d2018-08-09 12:44:40 -0700473
474 return literal + descriptionSuffix();
475}
476
477const std::string& ConstantExpression::expression() const {
Steven Morelandf21962d2018-08-09 12:44:40 -0700478 return mExpr;
479}
480
481std::string ConstantExpression::rawValue() const {
482 return rawValue(mValueKind);
Yifan Hongf24fa852016-09-23 11:03:15 -0700483}
484
485std::string ConstantExpression::rawValue(ScalarType::Kind castKind) const {
Timur Iskhakov7296af12017-08-09 21:52:48 +0000486 CHECK(isEvaluated());
Yifan Hong57886972016-08-17 10:42:15 -0700487
Yifan Hongfc610cd2016-09-22 13:34:45 -0700488#define CASE_STR(__type__) return std::to_string(this->cast<__type__>());
Yifan Hong57886972016-08-17 10:42:15 -0700489
Yi Kongd7f8ab32018-07-24 11:27:02 -0700490 SWITCH_KIND(castKind, CASE_STR, SHOULD_NOT_REACH(); return nullptr; );
Yifan Hong57886972016-08-17 10:42:15 -0700491}
492
Yifan Hong19ca75a2016-08-31 10:20:03 -0700493template<typename T>
494T ConstantExpression::cast() const {
Timur Iskhakov7296af12017-08-09 21:52:48 +0000495 CHECK(isEvaluated());
Yifan Hong57886972016-08-17 10:42:15 -0700496
Yifan Hong19ca75a2016-08-31 10:20:03 -0700497#define CASE_CAST_T(__type__) return static_cast<T>(static_cast<__type__>(mValue));
Yifan Hong57886972016-08-17 10:42:15 -0700498
Yifan Hongf24fa852016-09-23 11:03:15 -0700499 SWITCH_KIND(mValueKind, CASE_CAST_T, SHOULD_NOT_REACH(); return 0; );
Yifan Hong57886972016-08-17 10:42:15 -0700500}
501
Steven Morelandf21962d2018-08-09 12:44:40 -0700502std::string ConstantExpression::descriptionSuffix() const {
503 CHECK(isEvaluated());
504
505 if (!mTrivialDescription) {
506 CHECK(!mExpr.empty());
507
508 return " /* " + mExpr + " */";
509 }
510 return "";
511}
512
Yifan Honge77ca132016-09-27 10:49:05 -0700513size_t ConstantExpression::castSizeT() const {
Timur Iskhakov7296af12017-08-09 21:52:48 +0000514 CHECK(isEvaluated());
Yifan Honge77ca132016-09-27 10:49:05 -0700515 return this->cast<size_t>();
516}
517
Timur Iskhakova6d33882017-09-01 13:02:09 -0700518bool ConstantExpression::isReferenceConstantExpression() const {
519 return false;
520}
521
Steven Moreland12f0ab12018-11-02 17:27:37 -0700522status_t ConstantExpression::validate() const {
523 return OK;
524}
525
Timur Iskhakovb58f4182017-08-29 15:19:24 -0700526std::vector<ConstantExpression*> ConstantExpression::getConstantExpressions() {
527 const auto& constRet = static_cast<const ConstantExpression*>(this)->getConstantExpressions();
528 std::vector<ConstantExpression*> ret(constRet.size());
529 std::transform(constRet.begin(), constRet.end(), ret.begin(),
530 [](const auto* ce) { return const_cast<ConstantExpression*>(ce); });
531 return ret;
532}
533
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700534std::vector<Reference<LocalIdentifier>*> ConstantExpression::getReferences() {
535 const auto& constRet = static_cast<const ConstantExpression*>(this)->getReferences();
536 std::vector<Reference<LocalIdentifier>*> ret(constRet.size());
537 std::transform(constRet.begin(), constRet.end(), ret.begin(),
538 [](const auto* ce) { return const_cast<Reference<LocalIdentifier>*>(ce); });
539 return ret;
540}
541
542std::vector<const Reference<LocalIdentifier>*> ConstantExpression::getReferences() const {
543 return {};
544}
545
Steven Moreland12f0ab12018-11-02 17:27:37 -0700546std::vector<Reference<Type>*> ConstantExpression::getTypeReferences() {
547 const auto& constRet = static_cast<const ConstantExpression*>(this)->getTypeReferences();
548 std::vector<Reference<Type>*> ret(constRet.size());
549 std::transform(constRet.begin(), constRet.end(), ret.begin(),
550 [](const auto* ce) { return const_cast<Reference<Type>*>(ce); });
551 return ret;
552}
553
554std::vector<const Reference<Type>*> ConstantExpression::getTypeReferences() const {
555 return {};
556}
557
Timur Iskhakov891a8662017-08-25 21:53:48 -0700558status_t ConstantExpression::recursivePass(const std::function<status_t(ConstantExpression*)>& func,
Timur Iskhakov82c048e2017-09-09 01:20:53 -0700559 std::unordered_set<const ConstantExpression*>* visited,
560 bool processBeforeDependencies) {
Timur Iskhakov35930c42017-08-28 18:49:54 -0700561 if (mIsPostParseCompleted) return OK;
562
Timur Iskhakov891a8662017-08-25 21:53:48 -0700563 if (visited->find(this) != visited->end()) return OK;
564 visited->insert(this);
565
Timur Iskhakov82c048e2017-09-09 01:20:53 -0700566 if (processBeforeDependencies) {
567 status_t err = func(this);
568 if (err != OK) return err;
569 }
570
Timur Iskhakov891a8662017-08-25 21:53:48 -0700571 for (auto* nextCE : getConstantExpressions()) {
Timur Iskhakov82c048e2017-09-09 01:20:53 -0700572 status_t err = nextCE->recursivePass(func, visited, processBeforeDependencies);
Timur Iskhakov891a8662017-08-25 21:53:48 -0700573 if (err != OK) return err;
574 }
575
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700576 for (auto* nextRef : getReferences()) {
577 auto* nextCE = nextRef->shallowGet()->constExpr();
578 CHECK(nextCE != nullptr) << "Local identifier is not a constant expression";
Timur Iskhakov82c048e2017-09-09 01:20:53 -0700579 status_t err = nextCE->recursivePass(func, visited, processBeforeDependencies);
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700580 if (err != OK) return err;
581 }
582
Timur Iskhakov82c048e2017-09-09 01:20:53 -0700583 if (!processBeforeDependencies) {
584 status_t err = func(this);
585 if (err != OK) return err;
586 }
Timur Iskhakov891a8662017-08-25 21:53:48 -0700587
588 return OK;
589}
590
Timur Iskhakovb58f4182017-08-29 15:19:24 -0700591status_t ConstantExpression::recursivePass(
592 const std::function<status_t(const ConstantExpression*)>& func,
Timur Iskhakov82c048e2017-09-09 01:20:53 -0700593 std::unordered_set<const ConstantExpression*>* visited, bool processBeforeDependencies) const {
Timur Iskhakovb58f4182017-08-29 15:19:24 -0700594 if (mIsPostParseCompleted) return OK;
595
596 if (visited->find(this) != visited->end()) return OK;
597 visited->insert(this);
598
Timur Iskhakov82c048e2017-09-09 01:20:53 -0700599 if (processBeforeDependencies) {
600 status_t err = func(this);
601 if (err != OK) return err;
602 }
603
Timur Iskhakovb58f4182017-08-29 15:19:24 -0700604 for (const auto* nextCE : getConstantExpressions()) {
Timur Iskhakov82c048e2017-09-09 01:20:53 -0700605 status_t err = nextCE->recursivePass(func, visited, processBeforeDependencies);
Timur Iskhakovb58f4182017-08-29 15:19:24 -0700606 if (err != OK) return err;
607 }
608
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700609 for (const auto* nextRef : getReferences()) {
610 const auto* nextCE = nextRef->shallowGet()->constExpr();
611 CHECK(nextCE != nullptr) << "Local identifier is not a constant expression";
Timur Iskhakov82c048e2017-09-09 01:20:53 -0700612 status_t err = nextCE->recursivePass(func, visited, processBeforeDependencies);
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700613 if (err != OK) return err;
614 }
615
Timur Iskhakov82c048e2017-09-09 01:20:53 -0700616 if (!processBeforeDependencies) {
617 status_t err = func(this);
618 if (err != OK) return err;
619 }
Timur Iskhakovb58f4182017-08-29 15:19:24 -0700620
621 return OK;
622}
623
Timur Iskhakova6d33882017-09-01 13:02:09 -0700624ConstantExpression::CheckAcyclicStatus::CheckAcyclicStatus(
625 status_t status, const ConstantExpression* cycleEnd,
626 const ReferenceConstantExpression* lastReference)
627 : status(status), cycleEnd(cycleEnd), lastReference(lastReference) {
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700628 CHECK(cycleEnd == nullptr || status != OK);
Timur Iskhakova6d33882017-09-01 13:02:09 -0700629 CHECK((cycleEnd == nullptr) == (lastReference == nullptr));
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700630}
631
632ConstantExpression::CheckAcyclicStatus ConstantExpression::checkAcyclic(
633 std::unordered_set<const ConstantExpression*>* visited,
634 std::unordered_set<const ConstantExpression*>* stack) const {
635 if (stack->find(this) != stack->end()) {
Timur Iskhakova6d33882017-09-01 13:02:09 -0700636 CHECK(isReferenceConstantExpression())
637 << "Only reference constant expression could be the cycle end";
638
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700639 std::cerr << "ERROR: Cyclic declaration:\n";
Timur Iskhakova6d33882017-09-01 13:02:09 -0700640 return CheckAcyclicStatus(UNKNOWN_ERROR, this,
641 static_cast<const ReferenceConstantExpression*>(this));
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700642 }
643
644 if (visited->find(this) != visited->end()) return CheckAcyclicStatus(OK);
645 visited->insert(this);
646 stack->insert(this);
647
648 for (const auto* nextCE : getConstantExpressions()) {
649 auto err = nextCE->checkAcyclic(visited, stack);
650 if (err.status != OK) {
651 return err;
652 }
653 }
654
655 for (const auto* nextRef : getReferences()) {
656 const auto* nextCE = nextRef->shallowGet()->constExpr();
657 CHECK(nextCE != nullptr) << "Local identifier is not a constant expression";
658 auto err = nextCE->checkAcyclic(visited, stack);
659
660 if (err.status != OK) {
661 if (err.cycleEnd == nullptr) return err;
662
663 // Only ReferenceConstantExpression has references,
Timur Iskhakova6d33882017-09-01 13:02:09 -0700664 CHECK(isReferenceConstantExpression())
665 << "Only reference constant expression could have refereneces";
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700666
Timur Iskhakova6d33882017-09-01 13:02:09 -0700667 // mExpr is defined explicitly before evaluation
668 std::cerr << " '" << err.lastReference->mExpr << "' in '" << mExpr << "' at "
669 << nextRef->location() << "\n";
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700670
671 if (err.cycleEnd == this) {
672 return CheckAcyclicStatus(err.status);
673 }
Timur Iskhakova6d33882017-09-01 13:02:09 -0700674 return CheckAcyclicStatus(err.status, err.cycleEnd,
675 static_cast<const ReferenceConstantExpression*>(this));
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700676 }
677 }
678
679 CHECK(stack->find(this) != stack->end());
680 stack->erase(this);
681 return CheckAcyclicStatus(OK);
682}
683
Timur Iskhakov35930c42017-08-28 18:49:54 -0700684void ConstantExpression::setPostParseCompleted() {
685 CHECK(!mIsPostParseCompleted);
686 mIsPostParseCompleted = true;
687}
688
Neel Mehta1ca3e782019-07-18 15:16:22 -0700689void ConstantExpression::surroundWithParens() {
690 mExpr = "(" + mExpr + ")";
691}
692
Timur Iskhakovb58f4182017-08-29 15:19:24 -0700693std::vector<const ConstantExpression*> LiteralConstantExpression::getConstantExpressions() const {
Timur Iskhakov891a8662017-08-25 21:53:48 -0700694 return {};
695}
696
Timur Iskhakov7296af12017-08-09 21:52:48 +0000697UnaryConstantExpression::UnaryConstantExpression(const std::string& op, ConstantExpression* value)
Neel Mehta1ca3e782019-07-18 15:16:22 -0700698 : ConstantExpression(op + value->mExpr), mUnary(value), mOp(op) {}
Timur Iskhakov7296af12017-08-09 21:52:48 +0000699
Timur Iskhakovb58f4182017-08-29 15:19:24 -0700700std::vector<const ConstantExpression*> UnaryConstantExpression::getConstantExpressions() const {
Timur Iskhakov891a8662017-08-25 21:53:48 -0700701 return {mUnary};
702}
703
Timur Iskhakov7296af12017-08-09 21:52:48 +0000704BinaryConstantExpression::BinaryConstantExpression(ConstantExpression* lval, const std::string& op,
705 ConstantExpression* rval)
Neel Mehta1ca3e782019-07-18 15:16:22 -0700706 : ConstantExpression(lval->mExpr + " " + op + " " + rval->mExpr),
Neel Mehta3b414a82019-07-02 15:47:48 -0700707 mLval(lval),
708 mRval(rval),
709 mOp(op) {}
Timur Iskhakov7296af12017-08-09 21:52:48 +0000710
Timur Iskhakovb58f4182017-08-29 15:19:24 -0700711std::vector<const ConstantExpression*> BinaryConstantExpression::getConstantExpressions() const {
Timur Iskhakov891a8662017-08-25 21:53:48 -0700712 return {mLval, mRval};
713}
714
Timur Iskhakov7296af12017-08-09 21:52:48 +0000715TernaryConstantExpression::TernaryConstantExpression(ConstantExpression* cond,
716 ConstantExpression* trueVal,
717 ConstantExpression* falseVal)
Neel Mehta1ca3e782019-07-18 15:16:22 -0700718 : ConstantExpression(cond->mExpr + "?" + trueVal->mExpr + ":" + falseVal->mExpr),
Neel Mehta3b414a82019-07-02 15:47:48 -0700719 mCond(cond),
720 mTrueVal(trueVal),
721 mFalseVal(falseVal) {}
Timur Iskhakov7296af12017-08-09 21:52:48 +0000722
Timur Iskhakovb58f4182017-08-29 15:19:24 -0700723std::vector<const ConstantExpression*> TernaryConstantExpression::getConstantExpressions() const {
Timur Iskhakov891a8662017-08-25 21:53:48 -0700724 return {mCond, mTrueVal, mFalseVal};
725}
726
Timur Iskhakov7296af12017-08-09 21:52:48 +0000727ReferenceConstantExpression::ReferenceConstantExpression(const Reference<LocalIdentifier>& value,
728 const std::string& expr)
Neel Mehta3b414a82019-07-02 15:47:48 -0700729 : ConstantExpression(expr), mReference(value) {
Timur Iskhakov505e5612017-08-27 18:26:48 -0700730 mTrivialDescription = mExpr.empty();
Timur Iskhakov7296af12017-08-09 21:52:48 +0000731}
732
Timur Iskhakova6d33882017-09-01 13:02:09 -0700733bool ReferenceConstantExpression::isReferenceConstantExpression() const {
734 return true;
735}
736
Timur Iskhakovb58f4182017-08-29 15:19:24 -0700737std::vector<const ConstantExpression*> ReferenceConstantExpression::getConstantExpressions() const {
Timur Iskhakov77dd65c2017-08-31 22:46:56 -0700738 // Returns reference instead
739 return {};
740}
741
742std::vector<const Reference<LocalIdentifier>*> ReferenceConstantExpression::getReferences() const {
743 return {&mReference};
Timur Iskhakov891a8662017-08-25 21:53:48 -0700744}
745
Steven Moreland12f0ab12018-11-02 17:27:37 -0700746AttributeConstantExpression::AttributeConstantExpression(const Reference<Type>& value,
747 const std::string& fqname,
748 const std::string& tag)
Neel Mehta3b414a82019-07-02 15:47:48 -0700749 : ConstantExpression(fqname + "#" + tag), mReference(value), mTag(tag) {}
Steven Moreland12f0ab12018-11-02 17:27:37 -0700750
751std::vector<const ConstantExpression*> AttributeConstantExpression::getConstantExpressions() const {
752 // Returns reference instead
753 return {};
754}
755
756std::vector<const Reference<Type>*> AttributeConstantExpression::getTypeReferences() const {
757 return {&mReference};
758}
759
Yifan Hong57886972016-08-17 10:42:15 -0700760/*
761
762Evaluating expressions in HIDL language
763
764The following rules are mostly like that in:
765http://en.cppreference.com/w/cpp/language/operator_arithmetic
766http://en.cppreference.com/w/cpp/language/operator_logical
767http://en.cppreference.com/w/cpp/language/operator_comparison
768http://en.cppreference.com/w/cpp/language/operator_other
769
770The type of literal is the first type which the value
771can fit from the list of types depending on the suffix and bases.
772
773suffix decimal bases hexadecimal bases
774no suffix int32_t int32_t
775 int64_t uint32_t
776 int64_t
777 uint64_t
778
779u/U uint32_t (same as left)
780 uint64_t
781
782l/L int64_t int64_t
783
784ul/UL/uL/Ul uint64_t uint64_t
785
786
787Note: There are no negative integer literals.
788 -1 is the unary minus applied to 1.
789
790Unary arithmetic and bitwise operators (~ + -):
791 don't change the type of the argument.
792 (so -1u = -(1u) has type uint32_t)
793
794Binary arithmetic and bitwise operators (except shifts) (+ - * / % & | ^):
7951. Integral promotion is first applied on both sides.
7962. If both operands have the same type, no promotion is necessary.
7973. Usual arithmetic conversions.
798
799Integral promotion: if an operand is of a type with less than 32 bits,
800(including bool), it is promoted to int32_t.
801
802Usual arithmetic conversions:
8031. If operands are both signed or both unsigned, lesser conversion rank is
804 converted to greater conversion rank.
8052. Otherwise, if unsigned's rank >= signed's rank, -> unsigned's type
8063. Otherwise, if signed's type can hold all values in unsigned's type,
807 -> signed's type
8084. Otherwise, both converted to the unsigned counterpart of the signed operand's
809 type.
810rank: bool < int8_t < int16_t < int32_t < int64_t
811
812
813Shift operators (<< >>):
8141. Integral promotion is applied on both sides.
8152. For unsigned a, a << b discards bits that shifts out.
816 For signed non-negative a, a << b is legal if no bits shifts out, otherwise error.
817 For signed negative a, a << b gives error.
8183. For unsigned and signed non-negative a, a >> b discards bits that shifts out.
819 For signed negative a, a >> b discards bits that shifts out, and the signed
820 bit gets extended. ("arithmetic right shift")
8214. Shifting with negative number of bits is undefined. (Currently, the
822 parser will shift into the other direction. This behavior may change.)
8235. Shifting with number of bits exceeding the width of the type is undefined.
824 (Currently, 1 << 32 == 1. This behavior may change.)
825
826Logical operators (!, &&, ||):
8271. Convert first operand to bool. (true if non-zero, false otherwise)
8282. If short-circuited, return the result as type bool, value 1 or 0.
8293. Otherwise, convert second operand to bool, evaluate the result, and return
830 the result in the same fashion.
831
832Arithmetic comparison operators (< > <= >= == !=):
8331. Promote operands in the same way as binary arithmetic and bitwise operators.
834 (Integral promotion + Usual arithmetic conversions)
8352. Return type bool, value 0 or 1 the same way as logical operators.
836
837Ternary conditional operator (?:):
8381. Evaluate the conditional and evaluate the operands.
8392. Return type of expression is the type under usual arithmetic conversions on
840 the second and third operand. (No integral promotions necessary.)
841
842*/
843
Yifan Hong52165692016-08-12 18:06:40 -0700844} // namespace android
845