Skip to content

Commit 10025bd

Browse files
committed
- Add a.$eval($field) as a variant of a.$field.
1 parent 0ff7564 commit 10025bd

6 files changed

Lines changed: 25 additions & 18 deletions

File tree

releasenotes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Changes / improvements
66
- Add `$$PROJECT_PATH`, accessible through `env::PROJECT_PATH`.
77
- Deprecate `$field.get(a)` and `$field.set(a, b)`. Replaced by `a.$field` and `a.$field = b`.
8+
- Add `a.$eval($field)` as a variant of `a.$field`.
89

910
### Stdlib changes
1011
- Add math::TAU / math::TWO_PI

src/compiler/sema_expr.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -370,22 +370,27 @@ Expr *sema_resolve_string_ident(SemaContext *context, Expr *inner, bool report_m
370370
return NULL;
371371
}
372372

373-
Expr *sema_ct_eval_expr(SemaContext *context, CtEvalKind eval_kind, Expr *inner, bool report_missing)
373+
Expr *sema_ct_eval_expr(SemaContext *context, CtEvalKind eval_kind, Expr *inner, bool report_missing, bool* was_reflect)
374374
{
375375
if (!sema_analyse_ct_expr(context, inner)) return NULL;
376376
if (!expr_is_const_string(inner))
377377
{
378+
if (was_reflect && inner->resolve_status == RESOLVE_DONE && expr_is_const_reflection(inner))
379+
{
380+
*was_reflect = true;
381+
return inner;
382+
}
378383
switch (eval_kind)
379384
{
380385
case CT_EVAL_IDENTIFIER:
381386
RETURN_VAL_SEMA_ERROR(poisoned_expr, inner, "'$eval' expects a constant string as the argument.");
382387
case CT_EVAL_IMPLICIT_IDENTIFIER:
383-
if (inner->resolve_status == RESOLVE_DONE && expr_is_const_reflection(inner)) return inner;
384388
RETURN_VAL_SEMA_ERROR(poisoned_expr, inner, "A constant string was expected as the argument.");
385389
default:
386390
UNREACHABLE
387391
}
388392
}
393+
if (was_reflect) *was_reflect = false;
389394
return sema_resolve_string_ident(context, inner, report_missing);
390395
}
391396

@@ -3646,7 +3651,7 @@ INLINE bool sema_expr_analyse_lookup(SemaContext *context, Expr *expr, Expr *tag
36463651
if (!sema_analyse_expr_rvalue(context, key)) return false;
36473652
ArrayIndex index;
36483653

3649-
Expr *ident = sema_expr_resolve_access_child(context, args[0], NULL, false);
3654+
Expr *ident = sema_expr_resolve_access_child(context, args[0], NULL, NULL);
36503655
if (!ident) return false;
36513656
if (ident->expr_kind != EXPR_UNRESOLVED_IDENTIFIER) RETURN_SEMA_ERROR(expr, "This is not a field.");
36523657
const char *child = ident->unresolved_ident_expr.ident;
@@ -4987,7 +4992,7 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr)
49874992
* 5. .$ident -> resolve as `$eval($ident)`
49884993
* 6. .$Type -> It is a child to resolve as CT type param
49894994
*/
4990-
Expr *sema_expr_resolve_access_child(SemaContext *context, Expr *child, bool *missing, bool allow_reflect)
4995+
Expr *sema_expr_resolve_access_child(SemaContext *context, Expr *child, bool *missing, bool *was_reflect)
49914996
{
49924997
SourceLocId loc = child->loc;
49934998
bool in_hash = false;
@@ -5009,15 +5014,15 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr)
50095014
return child;
50105015
case EXPR_CT_IDENT:
50115016
{
5012-
Expr *result = sema_ct_eval_expr(context, CT_EVAL_IMPLICIT_IDENTIFIER, child, missing == NULL);
5017+
Expr *result = sema_ct_eval_expr(context, CT_EVAL_IMPLICIT_IDENTIFIER, child, missing == NULL, was_reflect);
50135018
if (!expr_ok(result)) return NULL;
50145019
if (!result)
50155020
{
50165021
if (missing) *missing = true;
50175022
return NULL;
50185023
}
50195024
expr_replace(child, result);
5020-
if (result->resolve_status == RESOLVE_DONE && expr_is_const_reflection(result)) return child;
5025+
if (was_reflect && *was_reflect) return child;
50215026
goto RETRY;
50225027
}
50235028
case EXPR_TYPEINFO:
@@ -5027,14 +5032,15 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr)
50275032
{
50285033
ASSERT_SPAN(child, child->resolve_status != RESOLVE_DONE);
50295034
// Only report missing if missing var is NULL
5030-
Expr *result = sema_ct_eval_expr(context, CT_EVAL_IDENTIFIER, child->inner_expr, missing == NULL);
5035+
Expr *result = sema_ct_eval_expr(context, CT_EVAL_IDENTIFIER, child->inner_expr, missing == NULL, was_reflect);
50315036
if (!expr_ok(result)) return NULL;
50325037
if (!result)
50335038
{
50345039
if (missing) *missing = true;
50355040
return NULL;
50365041
}
50375042
expr_replace(child, result);
5043+
if (was_reflect && *was_reflect) return child;
50385044
goto RETRY;
50395045
}
50405046
default:
@@ -6718,15 +6724,16 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr, bo
67186724
if (child->expr_kind == EXPR_TYPEINFO) RETURN_SEMA_ERROR(child, "A type can't appear here.");
67196725

67206726
// 3. Find the actual token.
6721-
Expr *identifier = sema_expr_resolve_access_child(context, child, missing_ref, true);
6727+
bool is_reflect = false;
6728+
Expr *identifier = sema_expr_resolve_access_child(context, child, missing_ref, &is_reflect);
67226729
if (!identifier) return false;
67236730
Decl *member;
67246731
Decl *decl;
67256732
Expr *current_parent;
67266733
bool optional;
67276734
const char *kw;
67286735
Type *underlying_type;
6729-
if (identifier->resolve_status == RESOLVE_DONE && expr_is_const_reflection(identifier))
6736+
if (is_reflect)
67306737
{
67316738
Expr *reflect = identifier->const_expr.reflection;
67326739
if (!expr_is_const_member(reflect)) RETURN_SEMA_ERROR(identifier, "Expected a member reference.");
@@ -10717,7 +10724,7 @@ static inline bool sema_expr_analyse_decl_element(SemaContext *context, Designat
1071710724
*member_ref = NULL;
1071810725
return true;
1071910726
}
10720-
Expr *field = sema_expr_resolve_access_child(context, element->field_expr, is_missing, false);
10727+
Expr *field = sema_expr_resolve_access_child(context, element->field_expr, is_missing, NULL);
1072110728
if (!field) return false;
1072210729
if (field->expr_kind != EXPR_UNRESOLVED_IDENTIFIER) RETURN_SEMA_ERROR(field, "Expected an identifier here.");
1072310730
const char *kw = field->unresolved_ident_expr.ident;
@@ -11480,7 +11487,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
1148011487
}
1148111488
case EXPR_CT_EVAL:
1148211489
{
11483-
Expr *eval = sema_ct_eval_expr(active_context, CT_EVAL_IDENTIFIER, main_expr->inner_expr, false);
11490+
Expr *eval = sema_ct_eval_expr(active_context, CT_EVAL_IDENTIFIER, main_expr->inner_expr, false, NULL);
1148411491
if (!expr_ok(eval)) return false;
1148511492
if (eval)
1148611493
{
@@ -11785,7 +11792,7 @@ static inline bool sema_expr_analyse_ct_stringify(SemaContext *context, Expr *ex
1178511792

1178611793
static inline bool sema_expr_resolve_ct_eval(SemaContext *context, Expr *expr)
1178711794
{
11788-
Expr *result = sema_ct_eval_expr(context, CT_EVAL_IDENTIFIER, expr->inner_expr, true);
11795+
Expr *result = sema_ct_eval_expr(context, CT_EVAL_IDENTIFIER, expr->inner_expr, true, NULL);
1178911796
if (!result) return false;
1179011797
if (result->expr_kind == EXPR_TYPEINFO)
1179111798
{

src/compiler/sema_initializers.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1416,7 +1416,7 @@ static Decl *sema_resolve_element_for_name(SemaContext *context, Decl **decls, D
14161416
{
14171417
DesignatorElement *element = (*elements_ref)[*index];
14181418

1419-
Expr *field = sema_expr_resolve_access_child(context, element->field_expr, NULL, false);
1419+
Expr *field = sema_expr_resolve_access_child(context, element->field_expr, NULL, NULL);
14201420
if (!field) return poisoned_decl;
14211421

14221422
if (field->expr_kind != EXPR_UNRESOLVED_IDENTIFIER)

src/compiler/sema_internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ void sema_analysis_pass_lambda(Module *module);
8888
void sema_analyze_stage(Module *module, AnalysisStage stage);
8989
void sema_trace_liveness(void);
9090

91-
Expr *sema_expr_resolve_access_child(SemaContext *context, Expr *child, bool *missing, bool allow_reflect);
91+
Expr *sema_expr_resolve_access_child(SemaContext *context, Expr *child, bool *missing, bool *was_reflect);
9292

9393
bool sema_analyse_expr_lvalue(SemaContext *context, Expr *expr, bool *failed_ref);
9494

@@ -110,7 +110,7 @@ void sema_add_methods_to_decl_stack(SemaContext *context, Decl *decl);
110110
bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool call_var_optional, bool *no_match_ref);
111111
Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr);
112112

113-
Expr *sema_ct_eval_expr(SemaContext *context, CtEvalKind eval_kind, Expr *inner, bool report_missing);
113+
Expr *sema_ct_eval_expr(SemaContext *context, CtEvalKind eval_kind, Expr *inner, bool report_missing, bool *was_reflect);
114114
Expr *sema_resolve_string_ident(SemaContext *context, Expr *inner, bool report_missing);
115115
bool sema_analyse_asm(SemaContext *context, AsmInlineBlock *block, Ast *asm_stmt);
116116
bool sema_expr_analyse_sprintf(SemaContext *context, Expr *expr, Expr *format_string, Expr **args, unsigned num_args);

test/test_suite/bitstruct/bitstruct_with_get_set.c3t

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ fn sz? Foo.to_format(&self, Formatter *f) @dynamic => io::struct_to_format(*self
1111
fn int main()
1212
{
1313
Foo d = { 1, 11 };
14-
var $member = Foo::members[0];
15-
d.$member = 3;
14+
d.$eval(Foo::members[0]) = 3;
1615
return 0;
1716
}
1817

test/test_suite/compile_time_introspection/membersof_enum.c3t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn int main()
1313
var $member0 = Foo::members[0];
1414
var $member1 = Foo::members[1];
1515
$assert Foo.ABC.$member0 == "Hello";
16-
$assert Foo.DEF.$member0 == "World";
16+
$assert Foo.DEF.$eval(Foo::members[0]) == "World";
1717
$assert Foo.ABC.$member1 == 3;
1818
$assert Foo.DEF.$member1 == -100;
1919
$assert Foo::members[0].type == String;

0 commit comments

Comments
 (0)