diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 905a217f4..1eab3a948 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -583,8 +583,9 @@ TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source) case TYPE_INFO_CT_IDENTIFIER: case TYPE_INFO_IDENTIFIER: return copy; + case TYPE_INFO_TYPEFROM: case TYPE_INFO_EVALTYPE: - case TYPE_INFO_EXPRESSION: + case TYPE_INFO_TYPEOF: case TYPE_INFO_VATYPE: assert(source->resolve_status == RESOLVE_NOT_DONE); copy->unresolved_type_expr = copy_expr(c, source->unresolved_type_expr); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 47a26f77c..b12b678eb 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -359,9 +359,10 @@ typedef enum TYPE_INFO_POISON, TYPE_INFO_IDENTIFIER, TYPE_INFO_CT_IDENTIFIER, - TYPE_INFO_EXPRESSION, + TYPE_INFO_TYPEOF, TYPE_INFO_VATYPE, TYPE_INFO_EVALTYPE, + TYPE_INFO_TYPEFROM, TYPE_INFO_ARRAY, TYPE_INFO_VECTOR, TYPE_INFO_INFERRED_ARRAY, @@ -563,6 +564,7 @@ typedef enum TOKEN_CT_SIZEOF, // $sizeof TOKEN_CT_STRINGIFY, // $stringify TOKEN_CT_SWITCH, // $switch + TOKEN_CT_TYPEFROM, // $typefrom TOKEN_CT_TYPEOF, // $typeof TOKEN_CT_CONVERTIBLE, // $convertible TOKEN_CT_CASTABLE, // $castable @@ -592,7 +594,7 @@ typedef enum #define TYPE_TOKENS NON_VOID_TYPE_TOKENS: case TOKEN_VOID #define TYPELIKE_TOKENS TYPE_TOKENS: case TOKEN_TYPE_IDENT: \ case TOKEN_CT_TYPE_IDENT: case TOKEN_CT_TYPEOF: case TOKEN_CT_EVALTYPE: \ - case TOKEN_CT_VATYPE + case TOKEN_CT_VATYPE: case TOKEN_CT_TYPEFROM // Note that ordering matters here. If ordering is changed, // So must type_find_max_type and friends. diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index b81d48afe..1b581d228 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -875,7 +875,7 @@ static Expr *parse_ct_sizeof(ParseContext *c, Expr *left) ASSIGN_EXPR_OR_RET(Expr *inner, parse_expr(c), poisoned_expr); CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr); Expr *typeof_expr = expr_new(EXPR_TYPEINFO, inner->span); - TypeInfo *type_info = type_info_new(TYPE_INFO_EXPRESSION, inner->span); + TypeInfo *type_info = type_info_new(TYPE_INFO_TYPEOF, inner->span); type_info->unresolved_type_expr = inner; typeof_expr->type_expr = type_info; access->access_expr.parent = typeof_expr; @@ -1767,6 +1767,7 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_CT_OFFSETOF] = { parse_ct_call, NULL, PREC_NONE }, [TOKEN_CT_NAMEOF] = { parse_ct_call, NULL, PREC_NONE }, [TOKEN_CT_QNAMEOF] = { parse_ct_call, NULL, PREC_NONE }, + [TOKEN_CT_TYPEFROM] = { parse_type_expr, NULL, PREC_NONE }, [TOKEN_CT_TYPEOF] = { parse_type_expr, NULL, PREC_NONE }, [TOKEN_CT_STRINGIFY] = { parse_ct_stringify, NULL, PREC_NONE }, [TOKEN_CT_EVALTYPE] = { parse_type_expr, NULL, PREC_NONE }, diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index eb1bea44c..b3afd7609 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -482,9 +482,18 @@ Path *parse_path_prefix(ParseContext *c, bool *had_error) */ static inline TypeInfo *parse_base_type(ParseContext *c) { + if (try_consume(c, TOKEN_CT_TYPEFROM)) + { + TypeInfo *type_info = type_info_new(TYPE_INFO_TYPEFROM, c->prev_span); + CONSUME_OR_RET(TOKEN_LPAREN, poisoned_type_info); + ASSIGN_EXPR_OR_RET(type_info->unresolved_type_expr, parse_expr(c), poisoned_type_info); + CONSUME_OR_RET(TOKEN_RPAREN, poisoned_type_info); + RANGE_EXTEND_PREV(type_info); + return type_info; + } if (try_consume(c, TOKEN_CT_TYPEOF)) { - TypeInfo *type_info = type_info_new(TYPE_INFO_EXPRESSION, c->prev_span); + TypeInfo *type_info = type_info_new(TYPE_INFO_TYPEOF, c->prev_span); CONSUME_OR_RET(TOKEN_LPAREN, poisoned_type_info); ASSIGN_EXPR_OR_RET(type_info->unresolved_type_expr, parse_expr(c), poisoned_type_info); CONSUME_OR_RET(TOKEN_RPAREN, poisoned_type_info); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index e64f57820..0b6f65b0f 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -7857,7 +7857,8 @@ RETRY: case TYPE_INFO_VATYPE: if (!sema_resolve_type_info(context, type_info)) return poisoned_type; return type_info->type->canonical; - case TYPE_INFO_EXPRESSION: + case TYPE_INFO_TYPEFROM: + case TYPE_INFO_TYPEOF: if (!sema_resolve_type_info(context, type_info)) return poisoned_type; return type_info->type; case TYPE_INFO_EVALTYPE: diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 9b2933f2a..98dff387e 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -308,7 +308,7 @@ RETRY: return type_info_poison(type_info); } } - case TYPE_INFO_EXPRESSION: + case TYPE_INFO_TYPEOF: { Expr *expr = type_info->unresolved_type_expr; if (!sema_analyse_expr(context, expr)) @@ -320,6 +320,23 @@ RETRY: assert(!type_info->failable); goto APPEND_QUALIFIERS; } + case TYPE_INFO_TYPEFROM: + { + Expr *expr = type_info->unresolved_type_expr; + if (!sema_analyse_expr(context, expr)) + { + return type_info_poison(type_info); + } + if (!expr_is_const(expr) || expr->const_expr.const_kind != CONST_TYPEID) + { + SEMA_ERROR(expr, "Expected a constant typeid value."); + return type_info_poison(type_info); + } + type_info->type = expr->const_expr.typeid; + type_info->resolve_status = RESOLVE_DONE; + assert(!type_info->failable); + goto APPEND_QUALIFIERS; + } case TYPE_INFO_INFERRED_ARRAY: case TYPE_INFO_INFERRED_VECTOR: if (!allow_inferred_type) diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index eace82709..fdb7d5818 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -382,6 +382,8 @@ const char *token_type_to_string(TokenType type) return "$sizeof"; case TOKEN_CT_SWITCH: return "$switch"; + case TOKEN_CT_TYPEFROM: + return "$typefrom"; case TOKEN_CT_TYPEOF: return "$typeof"; case TOKEN_CT_CONVERTIBLE: diff --git a/src/version.h b/src/version.h index c1e422147..f8be48792 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.49" \ No newline at end of file +#define COMPILER_VERSION "0.3.50" \ No newline at end of file diff --git a/test/test_suite/compile_time/stringify2.c3t b/test/test_suite/compile_time/stringify2.c3t new file mode 100644 index 000000000..aca9f6a4f --- /dev/null +++ b/test/test_suite/compile_time/stringify2.c3t @@ -0,0 +1,20 @@ +// #target: macos-x64 +module test; +import std::io; + +fn void main() +{ + var $s1 = $stringify(1 + 2); + char[*] s2 = $stringify($s1); + char[] s3 = $s1; + + io::printfln("$s1 == %s", $s1); + io::printfln("s2 == %s", &s2); + io::printfln("s3 == %s", s3); +} + +/* #expect: test.ll + +c"$s1\00", align 1 +c"1 + 2\00", align 1 +c"1 + 2\00", align 1 \ No newline at end of file diff --git a/test/test_suite/compile_time/typefrom.c3t b/test/test_suite/compile_time/typefrom.c3t new file mode 100644 index 000000000..8955f105e --- /dev/null +++ b/test/test_suite/compile_time/typefrom.c3t @@ -0,0 +1,15 @@ +// #target: macos-x64 + +module test; + + +fn int main() +{ + var $foo = double.typeid; + $typefrom($foo) a = 123.0; + return (int)a; +} + +/* #expect: test.ll + + %a = alloca double, align 8 \ No newline at end of file diff --git a/test/test_suite/compile_time/typefrom_errors.c3t b/test/test_suite/compile_time/typefrom_errors.c3t new file mode 100644 index 000000000..37cb68d96 --- /dev/null +++ b/test/test_suite/compile_time/typefrom_errors.c3t @@ -0,0 +1,13 @@ + +fn void test() +{ + typeid x; + $typefrom(2 > 1 ? int.typeid : double.typeid) xf; + $typefrom(x) a; // #error: Expected a constant +} + +fn void test2() +{ + var $x = 1; + $typefrom($x) a; // #error: Expected a constant +} \ No newline at end of file diff --git a/test/test_suite2/compile_time/stringify2.c3t b/test/test_suite2/compile_time/stringify2.c3t new file mode 100644 index 000000000..aca9f6a4f --- /dev/null +++ b/test/test_suite2/compile_time/stringify2.c3t @@ -0,0 +1,20 @@ +// #target: macos-x64 +module test; +import std::io; + +fn void main() +{ + var $s1 = $stringify(1 + 2); + char[*] s2 = $stringify($s1); + char[] s3 = $s1; + + io::printfln("$s1 == %s", $s1); + io::printfln("s2 == %s", &s2); + io::printfln("s3 == %s", s3); +} + +/* #expect: test.ll + +c"$s1\00", align 1 +c"1 + 2\00", align 1 +c"1 + 2\00", align 1 \ No newline at end of file diff --git a/test/test_suite2/compile_time/typefrom.c3t b/test/test_suite2/compile_time/typefrom.c3t new file mode 100644 index 000000000..8955f105e --- /dev/null +++ b/test/test_suite2/compile_time/typefrom.c3t @@ -0,0 +1,15 @@ +// #target: macos-x64 + +module test; + + +fn int main() +{ + var $foo = double.typeid; + $typefrom($foo) a = 123.0; + return (int)a; +} + +/* #expect: test.ll + + %a = alloca double, align 8 \ No newline at end of file diff --git a/test/test_suite2/compile_time/typefrom_errors.c3t b/test/test_suite2/compile_time/typefrom_errors.c3t new file mode 100644 index 000000000..37cb68d96 --- /dev/null +++ b/test/test_suite2/compile_time/typefrom_errors.c3t @@ -0,0 +1,13 @@ + +fn void test() +{ + typeid x; + $typefrom(2 > 1 ? int.typeid : double.typeid) xf; + $typefrom(x) a; // #error: Expected a constant +} + +fn void test2() +{ + var $x = 1; + $typefrom($x) a; // #error: Expected a constant +} \ No newline at end of file