@@ -147,17 +147,21 @@ static td::RefInt256 parse_vertex_string_const_as_int(V<ast_string_const> v) {
147
147
}
148
148
}
149
149
150
+ static ConstantValue parse_vertex_string_const (V<ast_string_const> v) {
151
+ return v->is_bitslice ()
152
+ ? ConstantValue (parse_vertex_string_const_as_slice (v))
153
+ : ConstantValue (parse_vertex_string_const_as_int (v));
154
+ }
155
+
150
156
151
157
struct ConstantEvaluator {
152
158
static bool is_overflow (const td::RefInt256& intval) {
153
159
return intval.is_null () || !intval->signed_fits_bits (257 );
154
160
}
155
161
156
162
static ConstantValue handle_unary_operator (V<ast_unary_operator> v, const ConstantValue& rhs) {
157
- if (!rhs.is_int ()) {
158
- v->error (" invalid operator, expecting integer" );
159
- }
160
- td::RefInt256 intval = std::get<td::RefInt256>(rhs.value );
163
+ tolk_assert (rhs.is_int ()); // type inferring has passed before, so it's int/bool
164
+ td::RefInt256 intval = rhs.as_int ();
161
165
162
166
switch (v->tok ) {
163
167
case tok_minus:
@@ -167,7 +171,7 @@ struct ConstantEvaluator {
167
171
break ;
168
172
case tok_bitwise_not:
169
173
intval = ~intval;
170
- break ;
174
+ break ;
171
175
case tok_logical_not:
172
176
intval = td::make_refint (intval == 0 ? -1 : 0 );
173
177
break ;
@@ -178,15 +182,13 @@ struct ConstantEvaluator {
178
182
if (is_overflow (intval)) {
179
183
v->error (" integer overflow" );
180
184
}
181
- return ConstantValue::from_int (std::move (intval));
185
+ return ConstantValue (std::move (intval));
182
186
}
183
187
184
188
static ConstantValue handle_binary_operator (V<ast_binary_operator> v, const ConstantValue& lhs, const ConstantValue& rhs) {
185
- if (!lhs.is_int () || !rhs.is_int ()) {
186
- v->error (" invalid operator, expecting integer" );
187
- }
188
- td::RefInt256 lhs_intval = std::get<td::RefInt256>(lhs.value );
189
- td::RefInt256 rhs_intval = std::get<td::RefInt256>(rhs.value );
189
+ tolk_assert (lhs.is_int () && rhs.is_int ()); // type inferring has passed before, so they are int/bool
190
+ td::RefInt256 lhs_intval = lhs.as_int ();
191
+ td::RefInt256 rhs_intval = rhs.as_int ();
190
192
td::RefInt256 intval;
191
193
192
194
switch (v->tok ) {
@@ -238,39 +240,41 @@ struct ConstantEvaluator {
238
240
case tok_neq:
239
241
intval = td::make_refint (lhs_intval != rhs_intval ? -1 : 0 );
240
242
break ;
243
+ case tok_logical_and:
244
+ intval = td::make_refint (lhs_intval != 0 && rhs_intval != 0 ? -1 : 0 );
245
+ break ;
246
+ case tok_logical_or:
247
+ intval = td::make_refint (lhs_intval != 0 || rhs_intval != 0 ? -1 : 0 );
248
+ break ;
241
249
default :
242
250
v->error (" unsupported binary operator in constant expression" );
243
251
}
244
252
245
253
if (is_overflow (intval)) {
246
254
v->error (" integer overflow" );
247
255
}
248
- return ConstantValue::from_int (std::move (intval));
256
+ return ConstantValue (std::move (intval));
249
257
}
250
258
259
+ // `const a = 1 + b`, we met `b`
251
260
static ConstantValue handle_reference (V<ast_reference> v) {
252
- // todo better handle "appears, directly or indirectly, in its own initializer"
253
- std::string_view name = v->get_name ();
254
- const Symbol* sym = lookup_global_symbol (name);
255
- if (!sym) {
256
- v->error (" undefined symbol `" + static_cast <std::string>(name) + " `" );
257
- }
258
- GlobalConstPtr const_ref = sym->try_as <GlobalConstPtr>();
261
+ GlobalConstPtr const_ref = v->sym ->try_as <GlobalConstPtr>();
259
262
if (!const_ref) {
260
- v->error (" symbol `" + static_cast <std::string>(name ) + " ` is not a constant" );
263
+ v->error (" symbol `" + static_cast <std::string>(v-> get_name () ) + " ` is not a constant" );
261
264
}
262
- if (v->has_instantiationTs ()) { // SOME_CONST<int>
263
- v->error (" constant is not a generic" );
265
+
266
+ if (!const_ref->value .initialized ()) { // maybe, `b` was already calculated
267
+ eval_and_assign_const_init_value (const_ref); // if not, dig recursively into `b`
264
268
}
265
- return { const_ref->value } ;
269
+ return const_ref->value ;
266
270
}
267
271
268
272
static ConstantValue visit (AnyExprV v) {
269
273
if (auto v_int = v->try_as <ast_int_const>()) {
270
- return ConstantValue::from_int (v_int->intval );
274
+ return ConstantValue (v_int->intval );
271
275
}
272
276
if (auto v_bool = v->try_as <ast_bool_const>()) {
273
- return ConstantValue::from_int (v_bool->bool_val ? -1 : 0 );
277
+ return ConstantValue (v_bool->bool_val ? -1 : 0 );
274
278
}
275
279
if (auto v_unop = v->try_as <ast_unary_operator>()) {
276
280
return handle_unary_operator (v_unop, visit (v_unop->get_rhs ()));
@@ -284,34 +288,32 @@ struct ConstantEvaluator {
284
288
if (auto v_par = v->try_as <ast_parenthesized_expression>()) {
285
289
return visit (v_par->get_expr ());
286
290
}
287
- if (v->try_as <ast_string_const>()) {
288
- return eval_const_init_value (v);
291
+ if (auto v_cast_to = v->try_as <ast_cast_as_operator>()) {
292
+ return visit (v_cast_to->get_expr ());
293
+ }
294
+ if (auto v_string = v->try_as <ast_string_const>()) {
295
+ return parse_vertex_string_const (v_string);
289
296
}
290
297
v->error (" not a constant expression" );
291
298
}
292
299
293
- static ConstantValue eval_const_init_value (AnyExprV init_value) {
294
- // it init_value is incorrect, an exception is thrown
295
- return visit (init_value);
300
+ // evaluate `const a = 2 + 3` into 5
301
+ // type inferring has already passed, to types are correct, `const a = 1 + ""` can not occur
302
+ // recursive initializers `const a = b; const b = a` also 100% don't exist, checked on type inferring
303
+ // if init_value is not a constant expression like `const a = foo()`, an exception is thrown
304
+ static ConstantValue eval_const_init_value (GlobalConstPtr const_ref) {
305
+ return visit (const_ref->init_value );
296
306
}
297
307
};
298
308
299
- ConstantValue eval_const_init_value (AnyExprV init_value) {
300
- // at first, handle most simple cases, not to launch heavy computation algorithm: just a number, just a string
301
- // just `c = 1` or `c = 0xFF`
302
- if (auto v_int = init_value->try_as <ast_int_const>()) {
303
- return {v_int->intval };
304
- }
305
- // just `c = "strval"`, probably with modifier (address, etc.)
306
- if (auto v_string = init_value->try_as <ast_string_const>()) {
307
- if (v_string->is_bitslice ()) {
308
- return {parse_vertex_string_const_as_slice (v_string)};
309
- } else {
310
- return {parse_vertex_string_const_as_int (v_string)};
311
- }
312
- }
313
- // something more complex, like `c = anotherC` or `c = 1 << 8`
314
- return ConstantEvaluator::eval_const_init_value (init_value);
309
+ ConstantValue eval_string_const_considering_modifier (AnyExprV v_string) {
310
+ tolk_assert (v_string->type == ast_string_const);
311
+ return parse_vertex_string_const (v_string->as <ast_string_const>());
312
+ }
313
+
314
+ void eval_and_assign_const_init_value (GlobalConstPtr const_ref) {
315
+ ConstantValue init_value = ConstantEvaluator::eval_const_init_value (const_ref);
316
+ const_ref->mutate ()->assign_const_value (std::move (init_value));
315
317
}
316
318
317
319
} // namespace tolk
0 commit comments