From 01f7343945ac8e683c0db37ab1d8dc62d501121b Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 28 Apr 2021 19:51:42 +0200 Subject: [PATCH] Parsing of interface. Fix to unpacking arraypointers. Fix accidental unsplat. --- src/compiler/ast.c | 13 ++++++ src/compiler/compiler_internal.h | 10 ++++ src/compiler/context.c | 4 ++ src/compiler/enums.h | 9 ++++ src/compiler/headers.c | 4 ++ src/compiler/llvm_codegen.c | 7 ++- src/compiler/llvm_codegen_c_abi_x64.c | 13 +++++- src/compiler/llvm_codegen_c_abi_x86.c | 4 ++ src/compiler/llvm_codegen_debug_info.c | 3 ++ src/compiler/llvm_codegen_expr.c | 9 +++- src/compiler/llvm_codegen_function.c | 1 + src/compiler/llvm_codegen_type.c | 25 ++++++++++ src/compiler/parse_expr.c | 10 ++-- src/compiler/parse_global.c | 63 +++++++++++++++++++++++++- src/compiler/parse_stmt.c | 2 + src/compiler/sema_casts.c | 25 +++++++++- src/compiler/sema_decls.c | 8 ++++ src/compiler/sema_expr.c | 7 +++ src/compiler/sema_types.c | 1 + src/compiler/tokens.c | 4 ++ src/compiler/types.c | 27 +++++++++-- test/test_suite/virtual/virtual.c3 | 11 +++++ 22 files changed, 245 insertions(+), 15 deletions(-) create mode 100644 test/test_suite/virtual/virtual.c3 diff --git a/src/compiler/ast.c b/src/compiler/ast.c index a28f64ad1..3ce3aa1ac 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -67,6 +67,9 @@ Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility TypeKind kind = TYPE_POISONED; switch (decl_type) { + case DECL_INTERFACE: + kind = TYPE_VIRTUAL; + break; case DECL_FUNC: kind = TYPE_FUNC; break; @@ -381,6 +384,12 @@ void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent) case ALL_REAL_FLOATS: DUMPF("(%s)", type->name); return; + case TYPE_VIRTUAL_ANY: + DUMP("(virtual*)"); + return; + case TYPE_VIRTUAL: + DUMPF("(virtual %s*)", type->name); + return; case TYPE_IXX: DUMP("(ct int)"); return; @@ -773,6 +782,10 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent) if (!decl) return; switch (decl->decl_kind) { + case DECL_INTERFACE: + DUMPF("(interface %s", decl->name); + DUMPDECLS(decl->interface_decl.functions); + DUMPEND(); case DECL_VAR: DUMPF("(var-%s %s", decl_var_to_string(decl->var.kind), decl->name ? decl->name : "anon"); DUMPTI(decl->var.type_info); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 1ad7513b3..abd0a5e2e 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -239,6 +239,7 @@ struct _Type struct _TypeInfo { ResolveStatus resolve_status : 2; + bool virtual_type : 1; Type *type; TypeInfoKind kind; SourceSpan span; @@ -403,6 +404,12 @@ typedef struct }; } TypedefDecl; + +typedef struct +{ + Decl **functions; +} InterfaceDecl; + typedef struct { union @@ -503,6 +510,7 @@ typedef struct _Decl FuncDecl func; AttrDecl attr; TypedefDecl typedef_decl; + InterfaceDecl interface_decl; DistinctDecl distinct_decl; MacroDecl macro_decl; GenericDecl generic_decl; @@ -1218,6 +1226,7 @@ typedef struct _Context Decl **functions; Decl **macros; Decl **generics; + Decl **interfaces; Decl **methods; Decl **vars; Decl **incr_array; @@ -1386,6 +1395,7 @@ extern Type *type_compint, *type_compfloat; extern Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong; extern Type *type_c_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong; extern Type *type_typeid, *type_error, *type_typeinfo, *type_varheader; +extern Type *type_virtual, *type_virtual_generic; extern const char *attribute_list[NUMBER_OF_ATTRIBUTES]; diff --git a/src/compiler/context.c b/src/compiler/context.c index 08ebcb064..d213f7f46 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -95,6 +95,10 @@ void context_register_global_decl(Context *context, Decl *decl) { case DECL_POISONED: break; + case DECL_INTERFACE: + vec_add(context->interfaces, decl); + decl_set_external_name(decl); + break; case DECL_GENERIC: vec_add(context->generics, decl); decl_set_external_name(decl); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index cdea2c4bb..f9db93c48 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -119,6 +119,9 @@ typedef enum CAST_SAPTR, CAST_SABOOL, CAST_STST, + CAST_VRPTR, + CAST_PTRVR, + CAST_VRBOOL, } CastKind; typedef enum @@ -154,6 +157,7 @@ typedef enum DECL_CT_CASE, DECL_ATTRIBUTE, DECL_DEFINE, + DECL_INTERFACE, } DeclKind; #define NON_TYPE_DECLS DECL_ARRAY_VALUE: case DECL_IMPORT: case DECL_MACRO: \ @@ -418,6 +422,7 @@ typedef enum TOKEN_GENERIC, TOKEN_IF, TOKEN_IMPORT, + TOKEN_INTERFACE, TOKEN_LOCAL, TOKEN_MACRO, TOKEN_MODULE, @@ -433,6 +438,7 @@ typedef enum TOKEN_TYPEOF, TOKEN_UNION, TOKEN_VAR, // Reserved + TOKEN_VIRTUAL, TOKEN_VOLATILE, TOKEN_WHILE, @@ -504,6 +510,8 @@ typedef enum TYPE_MEMBER, TYPE_VECTOR, TYPE_COMPLEX, + TYPE_VIRTUAL, + TYPE_VIRTUAL_ANY, TYPE_LAST = TYPE_MEMBER } TypeKind; @@ -572,6 +580,7 @@ typedef enum ATTR_ERROR = 1 << 6, ATTR_TYPEDEF = 1 << 7, ATTR_MEMBER = 1 << 8, + ATTR_INTERFACE = 1 << 9, } AttributeDomain; typedef enum diff --git a/src/compiler/headers.c b/src/compiler/headers.c index 6dcebb3b4..099cb87b3 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -116,6 +116,9 @@ static void header_print_type(FILE *file, Type *type) break; case TYPE_VARARRAY: break; + case TYPE_VIRTUAL: + case TYPE_VIRTUAL_ANY: + break; case TYPE_SUBARRAY: break; case TYPE_TYPEINFO: @@ -208,6 +211,7 @@ static void header_gen_decl(FILE *file, int indent, Decl *decl) case DECL_CT_CASE: case DECL_ATTRIBUTE: case DECL_DEFINE: + case DECL_INTERFACE: UNREACHABLE case DECL_FUNC: TODO diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 7e028226b..10d71de4b 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -846,7 +846,7 @@ void llvm_value_rvalue(GenContext *c, BEValue *value) } -static void gencontext_emit_decl(GenContext *context, Decl *decl) +static void gencontext_emit_type_decls(GenContext *context, Decl *decl) { switch (decl->decl_kind) { @@ -871,6 +871,9 @@ static void gencontext_emit_decl(GenContext *context, Decl *decl) case DECL_ERR: gencontext_emit_introspection_type(context, decl); break; + case DECL_INTERFACE: + // TODO + break; case DECL_ENUM: // TODO break; @@ -958,7 +961,7 @@ void *llvm_gen(Context *context) } VECEACH(context->types, i) { - gencontext_emit_decl(gen_context, context->types[i]); + gencontext_emit_type_decls(gen_context, context->types[i]); } VECEACH(context->vars, i) { diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index 1330fd958..c06674cf2 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -128,7 +128,7 @@ ABIArgInfo *x64_indirect_result(Type *type, unsigned free_int_regs) ABIArgInfo *x64_classify_reg_call_struct_type_check(Type *type, Registers *needed_registers) { - if (type->type_kind == TYPE_ERR_UNION || type->type_kind == TYPE_SUBARRAY) + if (type->type_kind == TYPE_ERR_UNION || type->type_kind == TYPE_SUBARRAY || type->type_kind == TYPE_VIRTUAL || type->type_kind == TYPE_VIRTUAL_ANY) { needed_registers->int_registers += 2; return abi_arg_new_direct(); @@ -448,6 +448,8 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X case TYPE_U128: case TYPE_ERR_UNION: case TYPE_SUBARRAY: + case TYPE_VIRTUAL: + case TYPE_VIRTUAL_ANY: *lo_class = CLASS_INTEGER; *hi_class = CLASS_INTEGER; break; @@ -610,6 +612,13 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty case TYPE_ERR_UNION: if (offset < 16) return abi_type_new_plain(type_usize); break; + case TYPE_VIRTUAL_ANY: + if (offset < 8) return abi_type_new_plain(type_typeid); + if (offset < 16) return abi_type_new_plain(type_voidptr); + break; + case TYPE_VIRTUAL: + if (offset < 16) return abi_type_new_plain(type_voidptr); + break; case TYPE_SUBARRAY: if (offset < 8) return abi_type_new_plain(type_usize); if (offset < 16) return abi_type_new_plain(type_voidptr); @@ -876,6 +885,8 @@ bool x64_type_is_structure(Type *type) case TYPE_ERRTYPE: case TYPE_ERR_UNION: case TYPE_SUBARRAY: + case TYPE_VIRTUAL_ANY: + case TYPE_VIRTUAL: return true; default: return false; diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index 36a71fc5b..2e6445ed1 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -128,6 +128,8 @@ static bool x86_should_return_type_in_reg(Type *type) case TYPE_ERR_UNION: case TYPE_SUBARRAY: case TYPE_ERRTYPE: + case TYPE_VIRTUAL_ANY: + case TYPE_VIRTUAL: case TYPE_COMPLEX: return true; case TYPE_ARRAY: @@ -608,6 +610,8 @@ static ABIArgInfo *x86_classify_argument(CallConvention call, Regs *regs, Type * case TYPE_STRUCT: case TYPE_UNION: case TYPE_SUBARRAY: + case TYPE_VIRTUAL_ANY: + case TYPE_VIRTUAL: case TYPE_ARRAY: case TYPE_ERR_UNION: case TYPE_COMPLEX: diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 80780aa0a..39c6b413b 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -588,6 +588,9 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * return type->backend_debug_type = llvm_debug_subarray_type(c, type); case TYPE_ERR_UNION: return type->backend_debug_type = llvm_debug_errunion_type(c, type); + case TYPE_VIRTUAL: + case TYPE_VIRTUAL_ANY: + TODO } UNREACHABLE } diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 55089e267..8e64bb034 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -350,6 +350,11 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ switch (cast_kind) { + case CAST_VRBOOL: + case CAST_VRPTR: + case CAST_PTRVR: + TODO + case CAST_CXBOOL: TODO case CAST_XIERR: @@ -2314,6 +2319,8 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM case TYPE_COMPLEX: case TYPE_SUBARRAY: case TYPE_VECTOR: + case TYPE_VIRTUAL_ANY: + case TYPE_VIRTUAL: TODO break; } @@ -2540,7 +2547,7 @@ static void llvm_emit_unpacked_variadic_arg(GenContext *c, Expr *expr, BEValue * // Load the pointer llvm_value_rvalue(c, &value); llvm_store_bevalue_raw(c, &len_addr, llvm_const_int(c, type_usize, type->pointer->array.len)); - llvm_store_bevalue_raw(c, &pointer_addr, llvm_emit_bitcast(c, value.value, type_get_ptr(type->array.base))); + llvm_store_bevalue_raw(c, &pointer_addr, llvm_emit_bitcast(c, value.value, type_get_ptr(type->pointer->array.base))); return; case TYPE_SUBARRAY: *subarray = value; diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index b8065449e..902e4600a 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -636,6 +636,7 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl) case DECL_ENUM: TODO case NON_TYPE_DECLS: + case DECL_INTERFACE: return; } } diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 95c29b780..47b979e74 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -14,6 +14,7 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl) case DECL_ENUM_CONSTANT: case DECL_POISONED: case NON_TYPE_DECLS: + case DECL_INTERFACE: UNREACHABLE case DECL_FUNC: { @@ -381,6 +382,30 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) LLVMStructSetBody(array_type, types, 2, false); return any_type->backend_type = array_type; } + case TYPE_VIRTUAL_ANY: + { + LLVMTypeRef pointer_type = llvm_get_type(c, type_voidptr); + LLVMTypeRef type_type = llvm_get_type(c, type_typeid); + LLVMTypeRef virtual_type = LLVMStructCreateNamed(c->context, any_type->name); + LLVMTypeRef types[2] = { pointer_type, type_type }; + LLVMStructSetBody(virtual_type, types, 2, false); + return any_type->backend_type = virtual_type; + } + case TYPE_VIRTUAL: + // Copy off the generic type. + if (any_type != type_virtual_generic) + { + return any_type->backend_type = llvm_get_type(c, type_virtual_generic); + } + else + { + LLVMTypeRef pointer_type = llvm_get_type(c, type_voidptr); + LLVMTypeRef type_type = llvm_get_type(c, type_typeid); + LLVMTypeRef virtual_type = LLVMStructCreateNamed(c->context, "virtual$"); + LLVMTypeRef types[2] = { pointer_type, type_type }; + LLVMStructSetBody(virtual_type, types, 2, false); + return any_type->backend_type = virtual_type; + } case TYPE_VARARRAY: { LLVMTypeRef size_type = llvm_get_type(c, type_usize); diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 673639166..801f4ab17 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -458,7 +458,7 @@ static Expr *parse_call_expr(Context *context, Expr *left) Expr **params = NULL; advance_and_verify(context, TOKEN_LPAREN); - bool unsplat; + bool unsplat = false; if (!TOKEN_IS(TOKEN_RPAREN)) { if (!parse_param_list(context, ¶ms, TOKEN_RPAREN, &unsplat)) return poisoned_expr; @@ -949,10 +949,7 @@ Expr *parse_type_compound_literal_expr_after_type(Context *context, TypeInfo *ty /** - * type_identifier - * : TYPE_IDENT initializer_list - * | TYPE_IDENT method_ref - * ; + * type_identifier ::= VIRTUAL? TYPE_IDENT initializer_list? * * @param left must be null. * @return Expr* @@ -973,7 +970,7 @@ Expr *parse_type_expression_with_path(Context *context, Path *path) { type = TRY_TYPE_OR(parse_type(context), poisoned_expr); } - if (TOKEN_IS(TOKEN_LPAREN) && context->next_tok.type == TOKEN_LBRACE) + if (!type->virtual_type && TOKEN_IS(TOKEN_LPAREN) && context->next_tok.type == TOKEN_LBRACE) { return parse_type_compound_literal_expr_after_type(context, type); } @@ -1005,6 +1002,7 @@ static Expr* parse_expr_block(Context *context, Expr *left) } ParseRule rules[TOKEN_EOF + 1] = { + [TOKEN_VIRTUAL] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_BOOL] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_CHAR] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_ICHAR] = { parse_type_identifier, NULL, PREC_NONE }, diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 2f812ef29..c834eec22 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -79,6 +79,7 @@ void recover_top_level(Context *context) case TOKEN_PUBLIC: case TOKEN_TYPEDEF: case TOKEN_STRUCT: + case TOKEN_INTERFACE: case TOKEN_IMPORT: case TOKEN_UNION: case TOKEN_EXTERN: @@ -524,6 +525,7 @@ Path *parse_path_prefix(Context *context, bool *had_error) * | TYPE_IDENT * | ident_scope TYPE_IDENT * | CT_TYPE_IDENT + * | VIRTUAL (ident_scope TYPE_IDENT)? * ; * * Assume prev_token is the type. @@ -531,6 +533,7 @@ Path *parse_path_prefix(Context *context, bool *had_error) */ static inline TypeInfo *parse_base_type(Context *context) { + bool virtual = try_consume(context, TOKEN_VIRTUAL); SourceSpan range = source_span_from_token_id(context->tok.id); bool had_error; Path *path = parse_path_prefix(context, &had_error); @@ -540,7 +543,9 @@ static inline TypeInfo *parse_base_type(Context *context) TypeInfo *type_info = type_info_new(TYPE_INFO_IDENTIFIER, range); type_info->unresolved.path = path; type_info->unresolved.name_loc = context->tok.id; + type_info->virtual_type = virtual; if (!consume_type_name(context, "type")) return poisoned_type_info; + if (virtual) TRY_CONSUME_OR(TOKEN_STAR, "Expected '*' after virtual name.", poisoned_type_info); RANGE_EXTEND_PREV(type_info); return type_info; } @@ -615,17 +620,36 @@ static inline TypeInfo *parse_base_type(Context *context) type_found = type_typeid; break; default: + // Special case: "virtual *" + if (virtual && context->tok.type == TOKEN_STAR) + { + type_info = type_info_new(TYPE_INFO_IDENTIFIER, source_span_from_token_id(context->prev_tok)); + advance(context); + type_info->resolve_status = RESOLVE_DONE; + type_info->type = type_virtual; + type_info->virtual_type = true; + RANGE_EXTEND_PREV(type_info); + return type_info; + } SEMA_TOKEN_ERROR(context->tok, "A type name was expected here."); return poisoned_type_info; } if (type_found) { + if (virtual) + { + SEMA_TOKEN_ERROR(context->tok, "Expected an interface name."); + advance(context); + return poisoned_type_info; + } assert(!type_info); type_info = type_info_new(TYPE_INFO_IDENTIFIER, source_span_from_token_id(context->tok.id)); type_info->resolve_status = RESOLVE_DONE; type_info->type = type_found; } + type_info->virtual_type = virtual; advance(context); + if (virtual) TRY_CONSUME_OR(TOKEN_STAR, "Expected '*' after virtual name.", poisoned_type_info); RANGE_EXTEND_PREV(type_info); return type_info; } @@ -1289,6 +1313,7 @@ static inline Decl *parse_struct_declaration(Context *context, Visibility visibi return decl; } + static inline Decl *parse_top_level_const_declaration(Context *context, Visibility visibility) { Decl *decl = TRY_DECL_OR(parse_const_declaration(context, visibility), poisoned_decl); @@ -1470,6 +1495,7 @@ static AttributeDomain TOKEN_TO_ATTR[TOKEN_EOF + 1] = { [TOKEN_VAR] = ATTR_VAR, [TOKEN_ENUM] = ATTR_ENUM, [TOKEN_STRUCT] = ATTR_STRUCT, + [TOKEN_INTERFACE] = ATTR_INTERFACE, [TOKEN_UNION] = ATTR_UNION, [TOKEN_CONST] = ATTR_CONST, [TOKEN_TYPEDEF] = ATTR_TYPEDEF, @@ -1834,7 +1860,7 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit { if (TOKEN_IS(TOKEN_LBRACE)) { - SEMA_TOKEN_ERROR(context->next_tok, "Functions bodies are not allowed in interface files."); + SEMA_TOKEN_ERROR(context->next_tok, "A function body is not allowed here."); return poisoned_decl; } TRY_CONSUME_OR(TOKEN_EOS, "Expected ';' after function declaration.", poisoned_decl); @@ -1850,6 +1876,38 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit } +/** + * interface_declaration ::= INTERFACE TYPE '{' func_decl* '}' + * + * @param visibility + */ +static inline Decl *parse_interface_declaration(Context *context, Visibility visibility) +{ + advance_and_verify(context, TOKEN_INTERFACE); + + TokenId name = context->tok.id; + + if (!consume_type_name(context, "interface")) return poisoned_decl; + Decl *decl = decl_new_with_type(name, DECL_INTERFACE, visibility); + + if (!parse_attributes(context, decl)) + { + return poisoned_decl; + } + + CONSUME_OR(TOKEN_LBRACE, poisoned_decl); + + while (TOKEN_IS(TOKEN_FUNC)) + { + Decl *function = TRY_DECL_OR(parse_func_definition(context, visibility, true), poisoned_decl); + vec_add(decl->interface_decl.functions, function); + } + + CONSUME_OR(TOKEN_RBRACE, poisoned_decl); + DEBUG_LOG("Parsed interface %s completely.", TOKSTR(name)); + return decl; +} + static inline bool check_no_visibility_before(Context *context, Visibility visibility) { switch (visibility) @@ -2131,6 +2189,9 @@ Decl *parse_top_level_statement(Context *context) case TOKEN_CONST: decl = TRY_DECL_OR(parse_top_level_const_declaration(context, visibility), poisoned_decl); break; + case TOKEN_INTERFACE: + decl = TRY_DECL_OR(parse_interface_declaration(context, visibility), poisoned_decl); + break; case TOKEN_STRUCT: case TOKEN_UNION: decl = TRY_DECL_OR(parse_struct_declaration(context, visibility), poisoned_decl); diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index bdf7324c8..292293515 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -994,6 +994,7 @@ Ast *parse_stmt(Context *context) case TOKEN_UPTRDIFF: case TOKEN_IPTR: case TOKEN_UPTR: + case TOKEN_VIRTUAL: case TOKEN_TYPEID: case TOKEN_CT_TYPE_IDENT: case TOKEN_HASH_TYPE_IDENT: @@ -1147,6 +1148,7 @@ Ast *parse_stmt(Context *context) case TOKEN_PUBLIC: case TOKEN_EXTERN: case TOKEN_STRUCT: + case TOKEN_INTERFACE: case TOKEN_TYPEDEF: case TOKEN_UNION: case TOKEN_ATTRIBUTE: diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index f099eeaf3..172e134d8 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -417,6 +417,9 @@ CastKind cast_to_bool_kind(Type *type) case TYPE_DISTINCT: case TYPE_INFERRED_ARRAY: UNREACHABLE + case TYPE_VIRTUAL_ANY: + case TYPE_VIRTUAL: + return CAST_VRBOOL; case TYPE_BOOL: return CAST_BOOLBOOL; case TYPE_ERR_UNION: @@ -499,6 +502,9 @@ bool cast_may_explicit(Type *from_type, Type *to_type) // Special subarray conversion: someType[N]* -> someType[] if (to_kind == TYPE_SUBARRAY && from->pointer->type_kind == TYPE_ARRAY && from->pointer->array.base == to->array.base) return true; return false; + case TYPE_VIRTUAL_ANY: + case TYPE_VIRTUAL: + return to_kind == TYPE_POINTER; case TYPE_ERRTYPE: // Allow only MyError.A -> error return to->type_kind == TYPE_ERR_UNION; @@ -652,7 +658,20 @@ bool cast_may_implicit(Type *from_type, Type *to_type) return cast_to_bool_kind(from) != CAST_ERROR; } - // 9. Substruct cast, if the first member is inline, see if we can cast to this member. + // 9. Virtual any cast + if (to->type_kind == TYPE_VIRTUAL_ANY) + { + return from_type->type_kind == TYPE_POINTER; + } + + // 10. Virtual cast + if (to->type_kind == TYPE_VIRTUAL) + { + TODO +// + } + + // 11. Substruct cast, if the first member is inline, see if we can cast to this member. if (type_is_substruct(from)) { return cast_may_implicit(from->decl->strukt.members[0]->type, to); @@ -826,6 +845,10 @@ bool cast(Expr *expr, Type *to_type) if (canonical->type_kind == TYPE_VARARRAY) return insert_cast(expr, CAST_PTRVAR, to_type); if (canonical->type_kind == TYPE_SUBARRAY) return insert_cast(expr, CAST_APTSA, to_type); break; + case TYPE_VIRTUAL: + case TYPE_VIRTUAL_ANY: + if (canonical->type_kind == TYPE_POINTER) return insert_cast(expr, CAST_VRPTR, to_type); + break; case TYPE_ENUM: if (type_is_integer(canonical)) return enum_to_integer(expr, from_type, canonical, to_type); if (type_is_float(canonical)) return enum_to_float(expr, from_type, canonical, to_type); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 6f82f5321..3e53ce36c 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -476,6 +476,10 @@ static inline bool sema_analyse_distinct(Context *context, Decl *decl) case TYPE_MEMBER: UNREACHABLE return false; + case TYPE_VIRTUAL_ANY: + case TYPE_VIRTUAL: + SEMA_ERROR(decl, "You cannot create a distinct type from a virtual type."); + return false; case TYPE_ERRTYPE: SEMA_ERROR(decl, "You cannot create a distinct type from an error."); return false; @@ -628,6 +632,8 @@ static const char *attribute_domain_to_string(AttributeDomain domain) { switch (domain) { + case ATTR_INTERFACE: + return "interface"; case ATTR_MEMBER: return "member"; case ATTR_FUNC: @@ -1064,6 +1070,8 @@ bool sema_analyse_decl(Context *context, Decl *decl) decl->module = context->module; switch (decl->decl_kind) { + case DECL_INTERFACE: + TODO case DECL_STRUCT: case DECL_UNION: if (!sema_analyse_struct_union(context, decl)) return decl_poison(decl); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index c2012b723..c4e9eb64e 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -198,6 +198,9 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr case DECL_LABEL: SEMA_ERROR(expr, "Did you intend to use the label '%s' here?", decl->name); return expr_poison(expr); + case DECL_INTERFACE: + SEMA_ERROR(expr, "Expected interface followed by '.'."); + return expr_poison(expr); case DECL_STRUCT: SEMA_ERROR(expr, "Expected struct followed by (...) or '.'."); return expr_poison(expr); @@ -3993,6 +3996,8 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp case TYPE_VARARRAY: case TYPE_SUBARRAY: case TYPE_TYPEID: + case TYPE_VIRTUAL_ANY: + case TYPE_VIRTUAL: // Only != and == allowed. goto ERR; case ALL_INTS: @@ -4327,6 +4332,8 @@ static bool sema_expr_analyse_not(Expr *expr, Expr *inner) case TYPE_FUNC: case TYPE_ARRAY: case TYPE_POINTER: + case TYPE_VIRTUAL: + case TYPE_VIRTUAL_ANY: case TYPE_VARARRAY: case TYPE_SUBARRAY: case TYPE_COMPLEX: diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 30ee4e0b5..9f235019b 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -120,6 +120,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) case DECL_ENUM: case DECL_TYPEDEF: case DECL_DISTINCT: + case DECL_INTERFACE: type_info->type = decl->type; type_info->resolve_status = RESOLVE_DONE; DEBUG_LOG("Resolved %s.", TOKSTR(type_info->unresolved.name_loc)); diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index 593cd7ad4..51907297a 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -224,6 +224,8 @@ const char *token_type_to_string(TokenType type) return "if"; case TOKEN_IMPORT: return "import"; + case TOKEN_INTERFACE: + return "interface"; case TOKEN_LOCAL: return "local"; case TOKEN_MACRO: @@ -262,6 +264,8 @@ const char *token_type_to_string(TokenType type) return "volatile"; // Named types + case TOKEN_VIRTUAL: + return "virtual"; case TOKEN_VOID: return "void"; case TOKEN_BOOL: diff --git a/src/compiler/types.c b/src/compiler/types.c index 36538e1b1..b1a05ff59 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -11,11 +11,13 @@ static Type t_usz, t_isz, t_uptr, t_iptr, t_uptrdiff, t_iptrdiff; static Type t_cus, t_cui, t_cul, t_cull; static Type t_cs, t_ci, t_cl, t_cll; static Type t_voidstar, t_typeid, t_error, t_typeinfo; -static Type t_str, t_varheader; +static Type t_str, t_varheader, t_virtual, t_virtual_generic; Type *type_bool = &t_u1; Type *type_void = &t_u0; Type *type_voidptr = &t_voidstar; +Type *type_virtual = &t_virtual; +Type *type_virtual_generic = &t_virtual_generic; Type *type_half = &t_f16; Type *type_float = &t_f32; Type *type_double = &t_f64; @@ -116,6 +118,8 @@ const char *type_to_error_string(Type *type) case TYPE_UNION: case TYPE_ERRTYPE: case TYPE_DISTINCT: + case TYPE_VIRTUAL_ANY: + case TYPE_VIRTUAL: return type->name; case TYPE_FUNC: { @@ -237,7 +241,10 @@ ByteSize type_size(Type *type) case ALL_INTS: case ALL_FLOATS: case TYPE_ERR_UNION: + case TYPE_VIRTUAL_ANY: return type->builtin.bytesize; + case TYPE_VIRTUAL: + return type_virtual_generic->builtin.bytesize; case TYPE_STRLIT: case TYPE_FUNC: case TYPE_POINTER: @@ -378,6 +385,8 @@ bool type_is_abi_aggregate(Type *type) case TYPE_ARRAY: case TYPE_ERR_UNION: case TYPE_COMPLEX: + case TYPE_VIRTUAL: + case TYPE_VIRTUAL_ANY: return true; case TYPE_TYPEINFO: case TYPE_MEMBER: @@ -519,11 +528,13 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements) case TYPE_INFERRED_ARRAY: return false; case TYPE_ERR_UNION: - *base = type_usize->canonical; + case TYPE_VIRTUAL: + case TYPE_VIRTUAL_ANY: + *base = type_iptr->canonical; *elements = 2; return true; case TYPE_ERRTYPE: - *base = type_usize->canonical; + *base = type_iptr->canonical; *elements = 1; return true; case TYPE_TYPEDEF: @@ -670,7 +681,10 @@ AlignSize type_abi_alignment(Type *type) case ALL_INTS: case ALL_FLOATS: case TYPE_ERR_UNION: + case TYPE_VIRTUAL_ANY: return type->builtin.abi_alignment; + case TYPE_VIRTUAL: + return type_virtual_generic->builtin.abi_alignment; case TYPE_FUNC: case TYPE_POINTER: case TYPE_VARARRAY: @@ -1073,6 +1087,9 @@ type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target- create_type_cache(type_void); type_void->type_cache[0] = &t_voidstar; t_voidstar.pointer = type_void; + type_create("virtual*", &t_virtual, TYPE_VIRTUAL_ANY, target->width_pointer * 2, target->align_pref_pointer, target->align_pointer); + type_create("virtual_generic", &t_virtual_generic, TYPE_VIRTUAL, target->width_pointer * 2, target->align_pref_pointer, target->align_pointer); + type_create("compint", &t_ixx, TYPE_IXX, 0, 0, 0); type_create("compfloat", &t_fxx, TYPE_FXX, 0, 0, 0); @@ -1129,6 +1146,8 @@ bool type_is_scalar(Type *type) case TYPE_ERR_UNION: case TYPE_VARARRAY: case TYPE_COMPLEX: + case TYPE_VIRTUAL: + case TYPE_VIRTUAL_ANY: return true; case TYPE_DISTINCT: type = type->decl->distinct_decl.base_type; @@ -1338,6 +1357,8 @@ Type *type_find_max_type(Type *type, Type *other) case TYPE_BOOL: case TYPE_TYPEINFO: case TYPE_MEMBER: + case TYPE_VIRTUAL: + case TYPE_VIRTUAL_ANY: return NULL; case TYPE_IXX: if (other->type_kind == TYPE_DISTINCT && type_is_numeric(other->decl->distinct_decl.base_type)) return other; diff --git a/test/test_suite/virtual/virtual.c3 b/test/test_suite/virtual/virtual.c3 new file mode 100644 index 000000000..0b1a13f05 --- /dev/null +++ b/test/test_suite/virtual/virtual.c3 @@ -0,0 +1,11 @@ +module foo; + +extern func void test_virtual3(virtual* y); + +interface Baz +{ + func void open(); + func int close(); +} + +extern func void test_virtual2(virtual Baz* z);