diff --git a/src/eval/eval.mdesk b/src/eval/eval.mdesk index b4760fca..3b8d0588 100644 --- a/src/eval/eval.mdesk +++ b/src/eval/eval.mdesk @@ -90,7 +90,7 @@ E_ExprKindTable: { Deref UnaryPrefix 2 "*" "" "" "" } { Address UnaryPrefix 2 "&" "" "" "" } - { Cast Null 1 "(" ")" "" "" } + { Cast Null 1 "cast(" ")" "" "" } { Sizeof UnaryPrefix 1 "sizeof " "" "" "" } { Typeof UnaryPrefix 1 "typeof " "" "" "" } { ByteSwap UnaryPrefix 1 "bswap " "" "" "" } diff --git a/src/eval/eval_parse.c b/src/eval/eval_parse.c index 782b16eb..7fa4e4aa 100644 --- a/src/eval/eval_parse.c +++ b/src/eval/eval_parse.c @@ -873,7 +873,7 @@ e_push_parse_from_string_tokens__prec(Arena *arena, String8 text, E_TokenArray t String8 token_string = str8_substr(text, token.range); S64 prefix_unary_precedence = 0; E_ExprKind prefix_unary_kind = 0; - Rng1U64 range = {0}; + E_Expr *prefix_unary_cast_expr = &e_expr_nil; // rjf: try op table for EachNonZeroEnumVal(E_ExprKind, k) @@ -887,6 +887,23 @@ e_push_parse_from_string_tokens__prec(Arena *arena, String8 text, E_TokenArray t } } + // rjf: if we found a symbolic prefix unary operator, but we are + // looking for a casted expression, then we need to abort this + // path. C-style casts are only legal in very simple and unambiguous + // cases, e.g. (x)123, but they cannot be made legal in more + // complex cases like (x) * y, because this is fundamentally ambiguous + // (the meaning / tree shape / etc. is entirely different depending on + // the type / mode of `x`). + // + // because of things like hover-evaluation we do actually want to + // support basic C-style casts. but past a certain point of complexity, + // we will simply require usage of the explicit `cast` operator. + // + if(prefix_unary_precedence != 0 && atom_is_maybe_cast) + { + break; + } + // rjf: try 'unsigned' marker if(str8_match(token_string, str8_lit("unsigned"), 0)) { @@ -894,13 +911,46 @@ e_push_parse_from_string_tokens__prec(Arena *arena, String8 text, E_TokenArray t prefix_unary_precedence = 2; } + // rjf: try explicit cast + if(str8_match(token_string, str8_lit("cast"), 0)) + { + // rjf: consume cast & open paren + E_Token open_paren_maybe = e_token_at_it(it+1, &tokens); + String8 open_paren_maybe_string = str8_substr(text, open_paren_maybe.range); + if(!str8_match(open_paren_maybe_string, str8_lit("("), 0)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Expected `(` following `cast`."); + goto end_cast_parse; + } + it += 2; + + // rjf: parse type expression + E_Parse type_parse = e_push_parse_from_string_tokens__prec(arena, text, e_token_array_make_first_opl(it, it_opl), e_max_precedence, 1); + e_msg_list_concat_in_place(&result.msgs, &type_parse.msgs); + it = type_parse.last_token; + + // rjf: expect ) + E_Token close_paren_maybe = e_token_at_it(it, &tokens); + String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); + if(close_paren_maybe.kind != E_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit(")"), 0)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Missing `)`."); + } + + // rjf: fill prefix unary info + prefix_unary_kind = E_ExprKind_Cast; + prefix_unary_precedence = 2; + prefix_unary_cast_expr = type_parse.expr; + end_cast_parse:; + } + // rjf: push prefix unary if we got one if(prefix_unary_precedence != 0) { - range = token.range; PrefixUnaryTask *prefix_unary_task = push_array(scratch.arena, PrefixUnaryTask, 1); prefix_unary_task->kind = prefix_unary_kind; - prefix_unary_task->range = range; + prefix_unary_task->range = token.range; + prefix_unary_task->cast_type_expr = prefix_unary_cast_expr; SLLQueuePush(first_prefix_unary, last_prefix_unary, prefix_unary_task); it += 1; } diff --git a/src/eval/generated/eval.meta.c b/src/eval/generated/eval.meta.c index 85f28611..28c61a6b 100644 --- a/src/eval/generated/eval.meta.c +++ b/src/eval/generated/eval.meta.c @@ -205,7 +205,7 @@ E_OpInfo e_expr_kind_op_info_table[49] = { E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp("."), str8_lit_comp(""), str8_lit_comp("") }, { E_OpKind_UnaryPrefix, 2, str8_lit_comp("*"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, { E_OpKind_UnaryPrefix, 2, str8_lit_comp("&"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, -{ E_OpKind_Null, 1, str8_lit_comp("("), str8_lit_comp(")"), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 1, str8_lit_comp("cast("), str8_lit_comp(")"), str8_lit_comp(""), str8_lit_comp("") }, { E_OpKind_UnaryPrefix, 1, str8_lit_comp("sizeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, { E_OpKind_UnaryPrefix, 1, str8_lit_comp("typeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, { E_OpKind_UnaryPrefix, 1, str8_lit_comp("bswap "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },