diff --git a/.github/workflows/main2.yml b/.github/workflows/main2.yml new file mode 100644 index 000000000..333897a82 --- /dev/null +++ b/.github/workflows/main2.yml @@ -0,0 +1,40 @@ +# This is a basic workflow to help you get started with Actions + +name: CI + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Build & Test + uses: ashutoshvarma/action-cmake-build@master + with: + build-dir: ${{ runner.workspace }}/build + # will set the CC & CXX for cmake + cc: gcc + cxx: g++ + build-type: Release + # Extra options pass to cmake while configuring project + configure-options: -DCMAKE_C_FLAGS=-w32 -DPNG_INCLUDE=OFF + run-test: true + ctest-options: -R mytest + # install the build using cmake --install + install-build: true + # run build using '-j [parallel]' to use multiple threads to build + parallel: 14 diff --git a/resources/grammar.y b/resources/grammar.y index c18d2e698..5fd2a730e 100644 --- a/resources/grammar.y +++ b/resources/grammar.y @@ -9,24 +9,25 @@ int yylex(void); void yyerror(char *s); %} -%token IDENT CT_IDENT CONSTANT CONST_IDENT TYPE_IDENT STRING_LITERAL SIZEOF +%token IDENT CT_IDENT CT_TYPE_IDENT CONSTANT CT_CONST_IDENT CONST_IDENT TYPE_IDENT STRING_LITERAL SIZEOF %token INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP %token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN %token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN +%token ADD_MOD SUB_MOD MULT_MOD ADD_MOD_ASSIGN SUB_MOD_ASSIGN +%token MULT_MOD_ASSIGN NEG_MOD %token XOR_ASSIGN OR_ASSIGN VAR NIL ELVIS HASH_IDENT NEXT -%token AT %token TYPEDEF MODULE IMPORT %token CHAR SHORT INT LONG FLOAT DOUBLE CONST VOLATILE VOID %token BYTE USHORT UINT ULONG BOOL +%token TYPEID %token STRUCT UNION ENUM ELLIPSIS AS LOCAL %token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN -%token TYPE FUNC ERROR MACRO GENERIC CTIF CTELIF CTENDIF CTELSE CTSWITCH CTCASE CTDEFAULT CTFOR +%token FUNC ERROR MACRO GENERIC CTIF CTELIF CTENDIF CTELSE CTSWITCH CTCASE CTDEFAULT CTFOR %token THROWS THROW TRY CATCH SCOPE PUBLIC DEFER ATTRIBUTE IN %token FN_BLOCK_START FN_BLOCK_END -%token MULTW ADDW SUBW %token AUTO %start translation_unit @@ -46,6 +47,7 @@ ident_expression : CONST_IDENT | IDENT | CT_IDENT + | CT_CONST_IDENT ; primary_expression @@ -55,8 +57,10 @@ primary_expression | path ident_expression | ident_expression | base_type initializer_list - | base_type '.' IDENT - | TYPE '(' type_expression ')' + | type '.' IDENT + | type '.' TYPEID + | '(' type ')' '.' IDENT + | '(' type ')' '.' TYPEID | '(' expression ')' | FN_BLOCK_START statement_list FN_BLOCK_END ; @@ -81,7 +85,6 @@ unary_expression | INC_OP unary_expression | DEC_OP unary_expression | unary_operator unary_expression - | SIZEOF '(' type_expression ')' ; unary_operator @@ -89,7 +92,7 @@ unary_operator | '*' | '+' | '-' - | SUBW + | NEG_MOD | '~' | '!' | '@' @@ -99,7 +102,7 @@ unary_operator multiplicative_expression : unary_expression | multiplicative_expression '*' unary_expression - | multiplicative_expression MULTW unary_expression + | multiplicative_expression MULT_MOD unary_expression | multiplicative_expression '/' unary_expression | multiplicative_expression '%' unary_expression ; @@ -120,9 +123,9 @@ bit_expression additive_expression : bit_expression | additive_expression '+' bit_expression - | additive_expression ADDW bit_expression + | additive_expression ADD_MOD bit_expression | additive_expression '-' bit_expression - | additive_expression SUBW bit_expression + | additive_expression SUB_MOD bit_expression ; relational_expression @@ -172,6 +175,9 @@ assignment_operator | AND_ASSIGN | XOR_ASSIGN | OR_ASSIGN + | MULT_MOD_ASSIGN + | ADD_MOD_ASSIGN + | SUB_MOD_ASSIGN ; constant_expression @@ -201,8 +207,8 @@ identifier_list macro_argument : CT_IDENT | IDENT - | type_expression IDENT - | type_expression CT_IDENT + | type IDENT + | type CT_IDENT ; macro_argument_list @@ -211,20 +217,20 @@ macro_argument_list ; declaration - : type_expression IDENT '=' initializer - | type_expression IDENT + : type IDENT '=' initializer + | type IDENT ; param_declaration - : type_expression - | type_expression IDENT - | type_expression IDENT '=' initializer + : type + | type IDENT + | type IDENT '=' initializer ; parameter_type_list : parameter_list | parameter_list ',' ELLIPSIS - | parameter_list ',' type_expression ELLIPSIS + | parameter_list ',' type ELLIPSIS ; opt_parameter_type_list @@ -253,15 +259,15 @@ base_type | DOUBLE | TYPE_IDENT | path TYPE_IDENT - | TYPE '(' constant_expression ')' + | CT_TYPE_IDENT ; -type_expression +type : base_type - | type_expression '*' - | type_expression '[' constant_expression ']' - | type_expression '[' ']' - | type_expression '[' '+' ']' + | type '*' + | type '[' constant_expression ']' + | type '[' ']' + | type '[' '+' ']' ; initializer @@ -345,7 +351,7 @@ defer_statement ; catch_statement - : CATCH '(' type_expression IDENT ')' defer_catch_body + : CATCH '(' type IDENT ')' defer_catch_body | CATCH '(' ERROR IDENT ')' defer_catch_body ; @@ -437,8 +443,8 @@ path_ident ; attribute - : AT path_ident - | AT path_ident '(' constant_expression ')' + : '@' path_ident + | '@' path_ident '(' constant_expression ')' ; attribute_list @@ -479,7 +485,7 @@ func_name ; func_declaration - : FUNC type_expression func_name opt_parameter_type_list opt_attributes opt_throw_declaration + : FUNC type func_name opt_parameter_type_list opt_attributes opt_throw_declaration ; func_definition @@ -488,7 +494,7 @@ func_definition ; macro_declaration - : MACRO type_expression IDENT '(' macro_argument_list ')' compound_statement + : MACRO type IDENT '(' macro_argument_list ')' compound_statement : MACRO IDENT '(' macro_argument_list ')' compound_statement ; @@ -512,13 +518,13 @@ struct_declaration_list ; struct_member_declaration - : type_expression identifier_list opt_attributes ';' + : type identifier_list opt_attributes ';' | struct_or_union IDENT opt_attributes struct_body | struct_or_union opt_attributes struct_body ; enum_declaration - : ENUM TYPE_IDENT ':' type_expression opt_attributes '{' enumerator_list '}' + : ENUM TYPE_IDENT ':' type opt_attributes '{' enumerator_list '}' | ENUM TYPE_IDENT opt_attributes '{' enumerator_list '}' ; @@ -537,8 +543,8 @@ error_declaration ; type_list - : type_expression - | type_list ',' type_expression + : type + | type_list ',' type ; generics_case @@ -551,20 +557,20 @@ generics_body generics_declaration : GENERIC IDENT '(' macro_argument_list ')' '{' generics_body '}' - | GENERIC type_expression IDENT '(' macro_argument_list ')' '{' generics_body '}' + | GENERIC type IDENT '(' macro_argument_list ')' '{' generics_body '}' ; const_declaration - : CONST CT_IDENT '=' initializer ';' - | CONST type_expression IDENT '=' initializer ';' + : CONST CT_CONST_IDENT '=' initializer ';' + | CONST type CONST_IDENT '=' initializer ';' ; func_typedef - : FUNC type_expression opt_parameter_type_list opt_throw_declaration + : FUNC type opt_parameter_type_list opt_throw_declaration ; typedef_declaration - : TYPEDEF type_expression AS TYPE_IDENT ';' + : TYPEDEF type AS TYPE_IDENT ';' | TYPEDEF func_typedef AS TYPE_IDENT ';' ; @@ -590,8 +596,8 @@ attribute_declaration ; global_declaration - : type_expression IDENT ';' - | type_expression IDENT '=' initializer ';' + : type IDENT ';' + | type IDENT '=' initializer ';' ; ct_if @@ -640,6 +646,7 @@ module_param : CT_IDENT | HASH_IDENT | TYPE_IDENT + | CT_TYPE_IDENT | IDENT ; @@ -656,12 +663,11 @@ module specified_import : IDENT AS IDENT | IDENT - | TYPE - | CONST - | MACRO - | TYPE AS TYPE - | CONST AS CONST - | MACRO AS MACRO + | CONST_IDENT + | '@' IDENT + | TYPE_IDENT AS TYPE_IDENT + | CONST_IDENT AS CONST_IDENT + | '@' IDENT AS '@' IDENT ; specified_import_list diff --git a/resources/lib/system/builtin.c3 b/resources/lib/system/builtin.c3 new file mode 100644 index 000000000..1d2c90974 --- /dev/null +++ b/resources/lib/system/builtin.c3 @@ -0,0 +1,99 @@ +module system::builtin; + +enum TypeKind +{ + VOID, + BOOL, + FLOAT, + INTEGER, + STRUCT, + UNION, + ERROR, + ENUM, + ARRAY, + POINTER, + VAR_ARRAY, + SUBARRAY, + OPAQUE + // ALIAS, +} + +struct TypeData +{ + typeid typeId; + TypeKind kind; + int size; + int alignment; + char* name; + char* fullName; +} + +struct TypeAlias +{ + TypeData; + typeid aliasType; +} + +struct TypeError +{ + TypeData; + TypeErrorValue[] errors; +} + +struct TypeArray +{ + TypeData; + typeid elementType; + ulong elements; +} + +struct TypeVarArray +{ + TypeData; + typeid elementType; +} + +struct TypeSubarray +{ + TypeData; + typeid elementType; +} + +struct TypePointer +{ + TypeData; + typeid baseType; +} + +struct TypeStruct +{ + TypeData; + TypeData*[] fields; +} + +struct TypeUnion +{ + TypeData; + TypeData*[] variants; +} + +struct TypeEnum +{ + TypeData; + typeid valueType; + TypeData*[] associated_value_types; +} + + +struct TypeEnumValue +{ + char* name; + ulong value; + void*[] associated_values; +} + +struct TypeErrorValue +{ + char* name; + ulong value; +} diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index 4efb10b98..5b6c99ece 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -607,24 +607,25 @@ struct WithArray { int[4] x; } -/* + error Err { TEST_ERR1 } -*/ -/* + + func int testThrow(int x) throws Err { if (x < 0) throw Err.TEST_ERR1; return x * x; } -*/ + func void testErrors() { - //int x = try testThrow(20) else 0; - int x = 0; + int x = try testThrow(20) else 1; printf("Value was %d, expected 400.\n", x); + x = try testThrow(-1) else 20; + printf("Value was %d, expected 20.\n", x); } func void testArray() @@ -683,9 +684,18 @@ JUMP: printf("6"); } +func void testType() +{ + printf("Test type\n"); + typeid x = WithArray.typeid; + int y = 0; + Teob b; + typeid structSize = typeof(b); +} func int main(int x) { + printf("Helo!\n"); testErrors(); testDefault(y = 99); @@ -695,6 +705,7 @@ func int main(int x) testAnonStruct(); testSimpleStruct(0); testUnion(); + testType(); int efd = 9; uint fefoek = 1; printf("Helo: %d\n", efd + cast(fefoek, int)); diff --git a/src/compiler/ast.c b/src/compiler/ast.c index f59a129af..1dfa02a81 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -553,10 +553,10 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) fprint_expr_common(file, expr, indent + 1); fprint_expr_recursive(file, expr->access_expr.parent, indent + 1); break; - case EXPR_TYPE: - fprintf_indented(file, indent, "(type\n"); + case EXPR_TYPEID: + fprintf_indented(file, indent, "(typeid \n"); fprint_expr_common(file, expr, indent + 1); - fprint_type_info_recursive(file, expr->type_expr.type, indent + 1); + fprint_type_info_recursive(file, expr->typeid_expr, indent + 1); break; case EXPR_GROUP: fprintf_indented(file, indent, "(group\n"); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 3b8d3ea86..1f2fcb8bd 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -183,6 +183,7 @@ struct _Type const char *name; Type **type_cache; void *backend_type; + void *backend_typeid; void *backend_debug_type; union { @@ -438,7 +439,7 @@ typedef struct Token name; Decl *method; }; -} ExprTypeRef; +} ExprTypeAccess; typedef struct { @@ -505,11 +506,6 @@ typedef struct Decl *decl; } ExprIdentifier; -typedef struct -{ - TypeInfo *type; -} ExprType; - typedef struct { @@ -575,10 +571,11 @@ struct _Expr ExprDesignatedInit designated_init_expr; Expr *group_expr; ExprCast cast_expr; + Expr *typeof_expr; ExprConst const_expr; ExprRange range_expr; ExprStructValue struct_value_expr; - ExprTypeRef type_access; + ExprTypeAccess type_access; ExprTry try_expr; Expr* macro_expr; ExprBinary binary_expr; @@ -589,7 +586,7 @@ struct _Expr ExprSubscript subscript_expr; ExprAccess access_expr; ExprIdentifier identifier_expr; - ExprType type_expr; + TypeInfo *typeid_expr; ExprInitializer expr_initializer; ExprCompoundLiteral expr_compound_literal; Expr** expression_list; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 31d5a660a..d99193c23 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -216,17 +216,17 @@ typedef enum EXPR_TERNARY, EXPR_UNARY, EXPR_POST_UNARY, - EXPR_TYPE, + EXPR_TYPEID, EXPR_IDENTIFIER, EXPR_TYPE_ACCESS, EXPR_CALL, EXPR_GROUP, - EXPR_SIZEOF, EXPR_SUBSCRIPT, EXPR_ACCESS, EXPR_INITIALIZER_LIST, EXPR_EXPRESSION_LIST, EXPR_CAST, + EXPR_TYPEOF, EXPR_SCOPED_EXPR, EXPR_MACRO_EXPR, EXPR_EXPR_BLOCK, @@ -375,6 +375,7 @@ typedef enum TOKEN_USHORT, TOKEN_USIZE, TOKEN_QUAD, + TOKEN_TYPEID, // C types TOKEN_C_SHORT, @@ -393,10 +394,11 @@ typedef enum TOKEN_CONST_IDENT, // Any purely upper case ident, TOKEN_TYPE_IDENT, // Any ident on the format FooBar or __FooBar - // We want to parse #foo / $foo separately. + // We want to parse $foo separately. // Otherwise we allow things like "# foo" which would be pretty bad. - TOKEN_HASH_IDENT, // #foobar TOKEN_CT_IDENT, // $foobar + TOKEN_CT_CONST_IDENT, // $FOOBAR + TOKEN_CT_TYPE_IDENT, // $Foobar TOKEN_STRING, // "Teststring" TOKEN_INTEGER, // 123 0x23 0b10010 0o327 @@ -444,13 +446,13 @@ typedef enum TOKEN_THROWS, TOKEN_TRUE, TOKEN_TRY, - TOKEN_TYPE, // Reserved TOKEN_TYPEDEF, TOKEN_UNION, TOKEN_UNTIL, TOKEN_VAR, // Reserved TOKEN_VOLATILE, TOKEN_WHILE, + TOKEN_TYPEOF, TOKEN_CT_CASE, // $case TOKEN_CT_DEFAULT, // $default diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 638d2244f..20ceb2030 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -240,11 +240,14 @@ static inline Token scan_prefixed_ident(Lexer *lexer, TokenType type, TokenType // Parses identifiers. Note that this is a bit complicated here since // we split identifiers into 2 types + find keywords. -static inline Token scan_ident(Lexer *lexer) +static inline Token scan_ident(Lexer *lexer, TokenType normal, TokenType const_token, TokenType type_token, char prefix) { - TokenType type = 0; uint32_t hash = FNV1_SEED; + if (prefix) + { + hash = FNV1a(prefix, hash); + } while (peek(lexer) == '_') { hash = FNV1a(next(lexer), hash); @@ -261,11 +264,11 @@ static inline Token scan_ident(Lexer *lexer) case 'z': if (!type) { - type = TOKEN_IDENT; + type = normal; } - else if (type == TOKEN_CONST_IDENT) + else if (type == const_token) { - type = TOKEN_TYPE_IDENT; + type = type_token; } break; case 'A': case 'B': case 'C': case 'D': case 'E': @@ -274,7 +277,7 @@ static inline Token scan_ident(Lexer *lexer) case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': - if (!type) type = TOKEN_CONST_IDENT; + if (!type) type = const_token; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': @@ -286,6 +289,11 @@ static inline Token scan_ident(Lexer *lexer) } hash = FNV1a(next(lexer), hash); } + // Allow bang! + if (peek(lexer) == '!' && type == normal) + { + hash = FNV1a(next(lexer), hash); + } EXIT:; uint32_t len = lexer->current - lexer->lexing_start; const char* interned_string = symtab_add(lexer->lexing_start, len, hash, &type); @@ -485,9 +493,9 @@ Token lexer_scan_token(Lexer *lexer) case '"': return scan_string(lexer); case '#': - return scan_prefixed_ident(lexer, TOKEN_HASH_IDENT, TOKEN_HASH, false, "#"); + return make_token(lexer, TOKEN_HASH, "#"); case '$': - return scan_prefixed_ident(lexer, TOKEN_CT_IDENT, TOKEN_DOLLAR, false, "$"); + return scan_ident(lexer, TOKEN_CT_TYPE_IDENT, TOKEN_CT_CONST_IDENT, TOKEN_CT_TYPE_IDENT, '$'); case ',': return make_token(lexer, TOKEN_COMMA, ","); case ';': @@ -556,7 +564,7 @@ Token lexer_scan_token(Lexer *lexer) if (is_alphanum_(c)) { backtrack(lexer); - return is_digit(c) ? scan_digit(lexer) : scan_ident(lexer); + return is_digit(c) ? scan_digit(lexer) : scan_ident(lexer, TOKEN_IDENT, TOKEN_CONST_IDENT, TOKEN_TYPE_IDENT, 0); } if (c < 0) { @@ -610,12 +618,7 @@ Token lexer_scan_ident_test(Lexer *lexer, const char *scan) if (scan[0] == '$') { next(lexer); - return scan_prefixed_ident(lexer, TOKEN_CT_IDENT, TOKEN_DOLLAR, false, "$"); + return scan_ident(lexer, TOKEN_CT_IDENT, TOKEN_CT_CONST_IDENT, TOKEN_CT_TYPE_IDENT, '$'); } - if (scan[0] == '#') - { - next(lexer); - return scan_prefixed_ident(lexer, TOKEN_HASH_IDENT, TOKEN_HASH, false, "#"); - } - return scan_ident(lexer); + return scan_ident(lexer, TOKEN_IDENT, TOKEN_CONST_IDENT, TOKEN_TYPE_IDENT, 0); } diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 100a7b147..8292ec42e 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -254,6 +254,73 @@ void llvm_codegen_setup() intrinsics_setup = true; } +void gencontext_emit_struct_decl(GenContext *context, Decl *decl) +{ + llvm_type(decl->type); + LLVMValueRef global_name = LLVMAddGlobal(context->module, llvm_type(type_bool), decl->name); + LLVMSetLinkage(global_name, LLVMInternalLinkage); + LLVMSetGlobalConstant(global_name, 1); + LLVMSetInitializer(global_name, LLVMConstInt(llvm_type(type_bool), 1, false)); + + decl->type->backend_typeid = global_name; + switch (decl->visibility) + { + case VISIBLE_MODULE: + LLVMSetVisibility(decl->var.backend_ref, LLVMProtectedVisibility); + break; + case VISIBLE_PUBLIC: + LLVMSetVisibility(decl->var.backend_ref, LLVMDefaultVisibility); + break; + case VISIBLE_EXTERN: + case VISIBLE_LOCAL: + LLVMSetVisibility(decl->var.backend_ref, LLVMHiddenVisibility); + break; + } +} + +static void gencontext_emit_decl(GenContext *context, Decl *decl) +{ + switch (decl->decl_kind) + { + case DECL_POISONED: + UNREACHABLE; + case DECL_FUNC: + // TODO + break; + case DECL_VAR: + // TODO + break; + case DECL_TYPEDEF: + break; + case DECL_ENUM_CONSTANT: + // TODO + break;; + case DECL_STRUCT: + case DECL_UNION: + gencontext_emit_struct_decl(context, decl); + break; + case DECL_ENUM: + // TODO + break; + case DECL_ERROR: + // TODO + break;; + case DECL_ERROR_CONSTANT: + //TODO + break;; + case DECL_ARRAY_VALUE: + case DECL_IMPORT: + case DECL_MACRO: + case DECL_GENERIC: + case DECL_CT_IF: + case DECL_CT_ELSE: + case DECL_CT_ELIF: + case DECL_ATTRIBUTE: + case DECL_THROWS: + UNREACHABLE + } +} + void llvm_codegen(Context *context) { assert(intrinsics_setup); @@ -269,6 +336,10 @@ void llvm_codegen(Context *context) { gencontext_emit_function_decl(&gen_context, context->functions[i]); } + VECEACH(context->types, i) + { + gencontext_emit_decl(&gen_context, context->types[i]); + } VECEACH(context->functions, i) { Decl *decl = context->functions[i]; diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 845e39d5d..30ead7207 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -6,6 +6,15 @@ #include "compiler_internal.h" #include "bigint.h" +static inline LLVMValueRef gencontext_emit_const_int(GenContext *context, Type *type, uint64_t val) +{ + type = type->canonical; + assert(type_is_any_integer(type) || type->type_kind == TYPE_BOOL); + return LLVMConstInt(llvm_type(type), val, type_is_signed_integer(type)); +} + +#define llvm_int(_type, _val) gencontext_emit_const_int(context, _type, _val) + static inline LLVMValueRef gencontext_emit_add_int(GenContext *context, Type *type, bool use_mod, LLVMValueRef left, LLVMValueRef right) { if (use_mod) @@ -88,7 +97,7 @@ static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, E case TYPE_ARRAY: { // TODO insert trap on overflow. - LLVMValueRef zero = LLVMConstInt(llvm_type(type_int), 0, false); + LLVMValueRef zero = llvm_int(type_int, 0); LLVMValueRef indices[2] = { zero, index_value, @@ -172,6 +181,7 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr) case EXPR_DESIGNATED_INITIALIZER: // Should only appear when generating designated initializers. UNREACHABLE + case EXPR_IDENTIFIER: return expr->identifier_expr.decl->var.backend_ref; case EXPR_UNARY: @@ -188,10 +198,9 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr) case EXPR_GROUP: return gencontext_emit_address(context, expr->group_expr); case EXPR_CONST: - case EXPR_TYPE: + case EXPR_TYPEID: case EXPR_POISONED: case EXPR_TRY: - case EXPR_SIZEOF: case EXPR_BINARY: case EXPR_TERNARY: case EXPR_POST_UNARY: @@ -201,6 +210,7 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr) case EXPR_EXPRESSION_LIST: case EXPR_CAST: case EXPR_MACRO_EXPR: + case EXPR_TYPEOF: UNREACHABLE } UNREACHABLE @@ -345,7 +355,7 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr_addr(GenContext case DESIGNATED_SUBSCRIPT: { // TODO range, more arrays - LLVMValueRef zero = LLVMConstInt(llvm_type(type_int), 0, false); + LLVMValueRef zero = llvm_int(type_int, 0); LLVMValueRef index = gencontext_emit_expr(context, path->index_expr); LLVMValueRef indices[2] = { zero, @@ -418,7 +428,8 @@ LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr) case UNARYOP_ERROR: FATAL_ERROR("Illegal unary op %s", expr->unary_expr.operator); case UNARYOP_NOT: - return LLVMBuildXor(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), LLVMConstInt(llvm_type(type_bool), 1, 0), "not"); + return LLVMBuildXor(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), + llvm_int(type_bool, 1), "not"); case UNARYOP_BITNEG: return LLVMBuildNot(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "bnot"); case UNARYOP_NEGMOD: @@ -431,7 +442,7 @@ LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr) assert(!type_is_unsigned(type)); { LLVMValueRef to_negate = gencontext_emit_expr(context, expr->unary_expr.expr); - LLVMValueRef zero = LLVMConstInt(llvm_type(expr->unary_expr.expr->type->canonical), 0, false); + LLVMValueRef zero = llvm_int(expr->unary_expr.expr->type, 0); if (build_options.debug_mode) { LLVMTypeRef type_to_use = llvm_type(type->canonical); @@ -491,7 +502,7 @@ static LLVMValueRef gencontext_emit_logical_and_or(GenContext *context, Expr *ex LLVMValueRef phi = LLVMBuildPhi(context->builder, llvm_type(type_bool), "val"); // Simplify for LLVM by entering the constants we already know of. - LLVMValueRef result_on_skip = LLVMConstInt(LLVMInt1TypeInContext(context->context), op == BINARYOP_AND ? 0 : 1, false); + LLVMValueRef result_on_skip = llvm_int(type_bool, op == BINARYOP_AND ? 0 : 1); LLVMValueRef logic_values[2] = { result_on_skip, rhs }; LLVMBasicBlockRef blocks[2] = { start_block, rhs_block }; LLVMAddIncoming(phi, logic_values, blocks, 2); @@ -591,7 +602,7 @@ static LLVMValueRef gencontext_emit_int_comparison(GenContext *context, Type *lh if (rhs_signed) return comp_value; // Otherwise, special handling for left side signed, right side unsigned. - LLVMValueRef zero = LLVMConstInt(llvm_type(lhs_type), 0, true); + LLVMValueRef zero = llvm_int(lhs_type, 0); switch (binary_op) { case BINARYOP_EQ: @@ -773,6 +784,12 @@ LLVMValueRef gencontext_emit_post_unary_expr(GenContext *context, Expr *expr) return gencontext_emit_post_inc_dec(context, expr->post_expr.expr, expr->post_expr.operator == POSTUNARYOP_INC ? 1 : -1, false); } +LLVMValueRef gencontext_emit_typeid(GenContext *context, Expr *expr) +{ + assert(expr->typeid_expr->type->backend_typeid); + return expr->typeid_expr->type->backend_typeid; +} + LLVMValueRef gencontext_emit_try_expr(GenContext *context, Expr *expr) { if (expr->try_expr.else_expr) @@ -884,27 +901,27 @@ LLVMValueRef gencontext_emit_ternary_expr(GenContext *context, Expr *expr) LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr) { - LLVMTypeRef type = llvm_type(type_reduced_from_expr(expr)); + Type *type = type_reduced_from_expr(expr)->canonical; switch (expr->const_expr.kind) { case ALL_INTS: - if (type_is_unsigned(expr->type->canonical)) + if (type_is_unsigned(type)) { - return LLVMConstInt(type, bigint_as_unsigned(&expr->const_expr.i), false); + return llvm_int(type, bigint_as_unsigned(&expr->const_expr.i)); } else { - return LLVMConstInt(type, (uint64_t)bigint_as_signed(&expr->const_expr.i), false); + return llvm_int(type, bigint_as_signed(&expr->const_expr.i)); } case ALL_FLOATS: - return LLVMConstReal(type, (double) expr->const_expr.f); + return LLVMConstReal(llvm_type(type), (double) expr->const_expr.f); case TYPE_POINTER: - return LLVMConstNull(type); + return LLVMConstNull(llvm_type(type)); case TYPE_BOOL: - return LLVMConstInt(type, expr->const_expr.b ? 1 : 0, false); + return llvm_int(type, expr->const_expr.b ? 1 : 0); case TYPE_STRING: { - LLVMValueRef global_name = LLVMAddGlobal(context->module, type, "string"); + LLVMValueRef global_name = LLVMAddGlobal(context->module, llvm_type(type), "string"); LLVMSetLinkage(global_name, LLVMInternalLinkage); LLVMSetGlobalConstant(global_name, 1); LLVMSetInitializer(global_name, LLVMConstStringInContext(context->context, @@ -918,9 +935,9 @@ LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr) } } -static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRef value) +static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRef value, Type *error_type) { - LLVMBasicBlockRef after_block = gencontext_create_free_block(context, ""); + LLVMBasicBlockRef after_block = gencontext_create_free_block(context, "throwafter"); size_t catch_index = context->catch_stack_index; while (catch_index > 0) { @@ -929,7 +946,9 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe Catch *current_catch = &context->catch_stack[catch_index]; if (!current_catch->decl) { - gencontext_emit_cond_br(context, value, current_catch->catch_block, after_block); + + LLVMValueRef comparison = LLVMBuildICmp(context->builder, LLVMIntNE, llvm_int(error_type, 0), value, "checkerr"); + gencontext_emit_cond_br(context, comparison, current_catch->catch_block, after_block); gencontext_emit_block(context, after_block); return; } @@ -979,11 +998,11 @@ LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr) { LLVMValueRef maybe_error = gencontext_emit_load(context, type_error_union, error_param); TODO // Incorrect, must get subset if this is 128 bits - gencontext_emit_throw_branch(context, maybe_error); + gencontext_emit_throw_branch(context, maybe_error, type_error_union); } else { - gencontext_emit_throw_branch(context, call); + gencontext_emit_throw_branch(context, call, type_reduced(type_error)); } } // If we used a return param, then load that info here. @@ -1102,10 +1121,11 @@ NESTED_RETRY: return gencontext_emit_post_unary_expr(context, expr); case EXPR_TRY: return gencontext_emit_try_expr(context, expr); - case EXPR_TYPE: - case EXPR_SIZEOF: + case EXPR_TYPEID: + return gencontext_emit_typeid(context, expr); case EXPR_TYPE_ACCESS: case EXPR_MACRO_EXPR: + case EXPR_TYPEOF: // These are folded in the semantic analysis step. UNREACHABLE case EXPR_IDENTIFIER: diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 17539f60a..99c92383c 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -231,6 +231,8 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl) } } + + void gencontext_emit_extern_decl(GenContext *context, Decl *decl) { switch (decl->decl_kind) @@ -253,6 +255,7 @@ void gencontext_emit_extern_decl(GenContext *context, Decl *decl) case DECL_STRUCT: case DECL_UNION: llvm_type(decl->type); + TODO // Fix typeid break; case DECL_ENUM: TODO diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index a8cc9d058..988afa20e 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -76,6 +76,7 @@ typedef struct LLVMBasicBlockRef expr_block_exit; bool current_block_is_target : 1; bool did_call_stack_save : 1; + LLVMTypeRef type_data_definitions[TYPE_KINDS]; } GenContext; extern unsigned sadd_overflow_intrinsic_id; diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index 1237a2769..66428d6b8 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -10,6 +10,8 @@ static inline LLVMTypeRef gencontext_create_basic_llvm_type(GenContext *context, { switch (type->type_kind) { + case TYPE_META_TYPE: + return LLVMIntTypeInContext(context->context, type->builtin.bitsize); case TYPE_BOOL: return LLVMInt1TypeInContext(context->context); case TYPE_I8: diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 1b7e8c1f3..f7266d02a 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -167,9 +167,10 @@ LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type) switch (type->type_kind) { case TYPE_POISONED: - case TYPE_META_TYPE: case TYPE_ERROR: UNREACHABLE; + case TYPE_META_TYPE: + return type->backend_type = LLVMIntTypeInContext(context, type->builtin.bitsize); case TYPE_TYPEDEF: return type->backend_type = llvm_get_type(context, type->canonical); case TYPE_ENUM: diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 9042a4b00..8b1de94a1 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -96,9 +96,8 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type) sema_error_range(start, "Did not expect a type here, only expressions."); return false; } - expr = expr_new(EXPR_TYPE, start); + expr = expr_new(EXPR_TYPEID, type->span); RANGE_EXTEND_PREV(expr); - expr->type_expr.type = type; } vec_add(*result, expr); if (!try_consume(context, TOKEN_COMMA)) @@ -144,7 +143,7 @@ Expr *parse_expression_list(Context *context) static Expr *parse_type_identifier(Context *context, Expr *left) { assert(!left && "Unexpected left hand side"); - return parse_type_identifier_with_path(context, NULL); + return parse_type_expression_with_path(context, NULL); } static Expr *parse_cast_expr(Context *context, Expr *left) { @@ -154,7 +153,17 @@ static Expr *parse_cast_expr(Context *context, Expr *left) CONSUME_OR(TOKEN_LPAREN, poisoned_expr); expr->cast_expr.expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr); CONSUME_OR(TOKEN_COMMA, poisoned_expr); - expr->cast_expr.type_info = TRY_TYPE_OR(parse_type_expression(context), poisoned_expr); + expr->cast_expr.type_info = TRY_TYPE_OR(parse_type(context), poisoned_expr); + CONSUME_OR(TOKEN_RPAREN, poisoned_expr); + return expr; +} +static Expr *parse_typeof_expr(Context *context, Expr *left) +{ + assert(!left && "Unexpected left hand side"); + Expr *expr = EXPR_NEW_TOKEN(EXPR_TYPEOF, context->tok); + advance_and_verify(context, TOKEN_TYPEOF); + CONSUME_OR(TOKEN_LPAREN, poisoned_expr); + expr->typeof_expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr); CONSUME_OR(TOKEN_RPAREN, poisoned_expr); return expr; } @@ -365,17 +374,6 @@ static Expr *parse_identifier(Context *context, Expr *left) return parse_identifier_with_path(context, NULL); } -static Expr *parse_type_expr(Context *context, Expr *left) -{ - assert(!left && "Unexpected left hand side"); - Expr *expr = EXPR_NEW_TOKEN(EXPR_TYPE, context->tok); - advance_and_verify(context, TOKEN_TYPE); - CONSUME_OR(TOKEN_LPAREN, poisoned_expr); - TypeInfo *type = TRY_TYPE_OR(parse_type_expression(context), poisoned_expr); - CONSUME_OR(TOKEN_RPAREN, poisoned_expr); - expr->type_expr.type = type; - return expr; -} static Expr *parse_maybe_scope(Context *context, Expr *left) { @@ -388,7 +386,7 @@ static Expr *parse_maybe_scope(Context *context, Expr *left) case TOKEN_CONST_IDENT: return parse_identifier_with_path(context, path); case TOKEN_TYPE_IDENT: - return parse_type_identifier_with_path(context, path); + return parse_type_expression_with_path(context, path); default: SEMA_TOKEN_ERROR(context->tok, "Expected a type, function or constant."); return poisoned_expr; @@ -721,6 +719,63 @@ static Expr *parse_nil(Context *context, Expr *left) return number; } +Expr *parse_type_compound_literal_expr_after_type(Context *context, TypeInfo *type_info) +{ + Expr *expr = expr_new(EXPR_COMPOUND_LITERAL, type_info->span); + expr->expr_compound_literal.type_info = type_info; + expr->expr_compound_literal.initializer = TRY_EXPR_OR(parse_initializer_list(context), poisoned_expr); + RANGE_EXTEND_PREV(expr); + return expr; +} + +Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info) +{ + switch (context->tok.type) + { + case TOKEN_TYPEID: + case TOKEN_IDENT: + case TOKEN_CONST_IDENT: + break; + default: + SEMA_TOKEN_ERROR(context->tok, "Expected the name of a type property here."); + return poisoned_expr; + } + Expr *expr = expr_new(EXPR_TYPE_ACCESS, type_info->span); + expr->type_access.type = type_info; + expr->type_access.name = context->tok; + advance(context); + RANGE_EXTEND_PREV(expr); + return expr; +} + + +/** + * type_identifier + * : TYPE_IDENT initializer_list + * | TYPE_IDENT method_ref + * ; + * + * @param left must be null. + * @return Expr* + */ +Expr *parse_type_expression_with_path(Context *context, Path *path) +{ + TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER, path ? path->span : context->tok.span ); + type->unresolved.path = path; + type->unresolved.name_loc = context->tok; + advance_and_verify(context, TOKEN_TYPE_IDENT); + RANGE_EXTEND_PREV(type); + if (context->tok.type == TOKEN_LBRACE) + { + return parse_type_compound_literal_expr_after_type(context, type); + } + CONSUME_OR(TOKEN_DOT, poisoned_expr); + return parse_type_access_expr_after_type(context, type); +} + + + + /** * function_block * : '({' stmt_list '})' @@ -746,10 +801,9 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_MINUSMINUS] = { parse_unary_expr, parse_post_unary, PREC_CALL }, [TOKEN_LPAREN] = { parse_grouping_expr, parse_call_expr, PREC_CALL }, [TOKEN_LPARBRA] = { parse_expr_block, NULL, PREC_NONE }, - [TOKEN_TYPE] = { parse_type_expr, NULL, PREC_NONE }, [TOKEN_CAST] = { parse_cast_expr, NULL, PREC_NONE }, + [TOKEN_TYPEOF] = { parse_typeof_expr, NULL, PREC_NONE }, [TOKEN_TRY] = { parse_try_expr, NULL, PREC_TRY }, - //[TOKEN_SIZEOF] = { parse_sizeof, NULL, PREC_NONE }, [TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL }, [TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE }, [TOKEN_MINUS_MOD] = { parse_unary_expr, parse_binary, PREC_ADDITIVE }, diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 46891319d..411d85de8 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -91,7 +91,7 @@ static inline Ast* parse_catch_stmt(Context *context) TypeInfo *type = NULL; if (!try_consume(context, TOKEN_ERROR_TYPE)) { - type = TRY_TYPE_OR(parse_type_expression(context), poisoned_ast); + type = TRY_TYPE_OR(parse_type(context), poisoned_ast); } EXPECT_IDENT_FOR_OR("error parameter", poisoned_ast); Decl *decl = decl_new_var(context->tok, type, VARDECL_PARAM, VISIBLE_LOCAL); @@ -569,7 +569,7 @@ static inline Ast* parse_ct_switch_stmt(Context *context) advance(context); while (1) { - TypeInfo *type = TRY_TYPE_OR(parse_type_expression(context), poisoned_ast); + TypeInfo *type = TRY_TYPE_OR(parse_type(context), poisoned_ast); vec_add(stmt->ct_case_stmt.types, type); if (!try_consume(context, TOKEN_COMMA)) break; } @@ -632,17 +632,19 @@ Ast *parse_stmt(Context *context) case TOKEN_C_UINT: case TOKEN_C_ULONG: case TOKEN_C_ULONGLONG: + case TOKEN_TYPEID: + case TOKEN_CT_TYPE_IDENT: case TOKEN_TYPE_IDENT: if (context->next_tok.type == TOKEN_DOT || context->next_tok.type == TOKEN_LBRACE) { return parse_expr_stmt(context); } return parse_declaration_stmt(context); + case TOKEN_TYPEOF: + TODO case TOKEN_LOCAL: // Local means declaration! case TOKEN_CONST: // Const means declaration! return parse_declaration_stmt(context); - case TOKEN_TYPE: - return parse_decl_or_expr_stmt(context); case TOKEN_CONST_IDENT: if (context->next_tok.type == TOKEN_COLON) { @@ -725,7 +727,7 @@ Ast *parse_stmt(Context *context) case TOKEN_PLUS: case TOKEN_MINUSMINUS: case TOKEN_PLUSPLUS: - case TOKEN_HASH_IDENT: + case TOKEN_CT_CONST_IDENT: case TOKEN_CT_IDENT: case TOKEN_STRING: case TOKEN_REAL: diff --git a/src/compiler/parser.c b/src/compiler/parser.c index b30e6929b..f4f1b48d5 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -304,7 +304,7 @@ Path *parse_path_prefix(Context *context) * | DOUBLE * | TYPE_IDENT * | ident_scope TYPE_IDENT - * | TYPE '(' constant_expression ')' + * | CT_TYPE_IDENT * ; * * Assume prev_token is the type. @@ -329,18 +329,10 @@ static inline TypeInfo *parse_base_type(Context *context) switch (context->tok.type) { case TOKEN_TYPE_IDENT: + case TOKEN_CT_TYPE_IDENT: type_info = type_info_new(TYPE_INFO_IDENTIFIER, context->tok.span); type_info->unresolved.name_loc = context->tok; break; - case TOKEN_TYPE: - type_info = type_info_new(TYPE_INFO_IDENTIFIER, context->tok.span); - advance_and_verify(context, TOKEN_TYPE); - CONSUME_OR(TOKEN_LPAREN, poisoned_type_info); - type_info->resolve_status = RESOLVE_NOT_DONE; - type_info->unresolved_type_expr = TRY_EXPR_OR(parse_initializer(context), poisoned_type_info); - EXPECT_OR(TOKEN_RPAREN, poisoned_type_info); - RANGE_EXTEND_PREV(type_info); - break; case TOKEN_VOID: type_found = type_void; break; @@ -407,6 +399,9 @@ static inline TypeInfo *parse_base_type(Context *context) case TOKEN_C_ULONGLONG: type_found = type_c_ulonglong; break; + case TOKEN_TYPEID: + type_found = type_typeid; + break; default: SEMA_TOKEN_ERROR(context->tok, "A type name was expected here."); return poisoned_type_info; @@ -463,16 +458,15 @@ static inline TypeInfo *parse_array_type_index(Context *context, TypeInfo *type) } /** - * type_expression* + * type * : base_type - * | type_expression '*' - * | type_expression '&' - * | type_expression array_type_index + * | type '*' + * | type array_type_index * * Assume already stepped into. * @return Type, poisoned if parsing is invalid. */ -TypeInfo *parse_type_expression(Context *context) +TypeInfo *parse_type(Context *context) { TypeInfo *type_info = parse_base_type(context); while (type_info_ok(type_info)) @@ -548,7 +542,7 @@ Decl *parse_decl(Context *context) bool constant = context->tok.type == TOKEN_CONST; if (local || constant) advance(context); - TypeInfo *type_info = parse_type_expression(context); + TypeInfo *type_info = parse_type(context); TypeInfo *type = TRY_TYPE_OR(type_info, poisoned_decl); Decl *decl = TRY_DECL_OR(parse_decl_after_type(context, local, type), poisoned_decl); @@ -582,7 +576,7 @@ static inline Decl *parse_const_declaration(Context *context, Visibility visibil else { if (!consume_const_name(context, "constant")) return poisoned_decl; - decl->var.type_info = TRY_TYPE_OR(parse_type_expression(context), poisoned_decl); + decl->var.type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl); } CONSUME_OR(TOKEN_EQ, poisoned_decl); @@ -604,7 +598,7 @@ static inline Decl *parse_const_declaration(Context *context, Visibility visibil */ static inline Decl *parse_global_declaration(Context *context, Visibility visibility) { - TypeInfo *type = TRY_TYPE_OR(parse_type_expression(context), poisoned_decl); + TypeInfo *type = TRY_TYPE_OR(parse_type(context), poisoned_decl); Decl *decl = decl_new_var(context->tok, type, VARDECL_GLOBAL, visibility); @@ -681,6 +675,21 @@ static inline bool is_expr_after_type_ident(Context *context) return context->next_tok.type == TOKEN_DOT || context->next_tok.type == TOKEN_LPAREN; } +bool parse_type_or_expr_after_type(Context *context, Expr **expr_ptr, TypeInfo **type_ptr) +{ + if (!type_info_ok(*type_ptr)) return false; + if (try_consume(context, TOKEN_DOT)) + { + *expr_ptr = parse_type_access_expr_after_type(context, *type_ptr); + *type_ptr = NULL; + return expr_ok(*expr_ptr); + } + if (context->tok.type == TOKEN_LBRACE) + { + return parse_type_compound_literal_expr_after_type(context, *type_ptr); + } + return true; +} bool parse_type_or_expr(Context *context, Expr **expr_ptr, TypeInfo **type_ptr) { switch (context->tok.type) @@ -709,9 +718,10 @@ bool parse_type_or_expr(Context *context, Expr **expr_ptr, TypeInfo **type_ptr) case TOKEN_C_ULONG: case TOKEN_C_ULONGLONG: case TOKEN_TYPE_IDENT: - if (context->next_tok.type == TOKEN_DOT || context->next_tok.type == TOKEN_LPAREN) break; - *type_ptr = parse_type_expression(context); - return type_info_ok(*type_ptr); + case TOKEN_CT_TYPE_IDENT: + *type_ptr = parse_type(context); + return parse_type_or_expr_after_type(context, expr_ptr, type_ptr); + return true; case TOKEN_IDENT: if (context->next_tok.type == TOKEN_SCOPE) { @@ -721,35 +731,15 @@ bool parse_type_or_expr(Context *context, Expr **expr_ptr, TypeInfo **type_ptr) { advance(context); advance(context); } while (context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE); - if (context->tok.type == TOKEN_TYPE_IDENT && !is_expr_after_type_ident(context)) + if (context->tok.type == TOKEN_TYPE_IDENT) { context_restore_lexer_state(context); - *type_ptr = parse_type_expression(context); - return type_info_ok(*type_ptr); + *type_ptr = parse_type(context); + return parse_type_or_expr_after_type(context, expr_ptr, type_ptr); } context_restore_lexer_state(context); } break; - case TOKEN_TYPE: - { - SourceRange start = context->tok.span; - advance_and_verify(context, TOKEN_TYPE); - CONSUME_OR(TOKEN_LPAREN, false); - Expr* inner_expr = NULL; - TypeInfo* inner_type = NULL; - if (!parse_type_or_expr(context, &inner_expr, &inner_type)) return false; - CONSUME_OR(TOKEN_RPAREN, false); - if (inner_expr) - { - *type_ptr = type_info_new(TYPE_INFO_EXPRESSION, inner_expr->span); - (**type_ptr).unresolved_type_expr = inner_expr; - return true; - } - Expr *type_expr = expr_new(EXPR_TYPE, start); - type_expr->type_expr.type = inner_type; - *expr_ptr = parse_precedence_with_left_side(context, type_expr, PREC_ASSIGNMENT); - return expr_ok(*expr_ptr); - } default: break; } @@ -877,7 +867,7 @@ static inline bool parse_opt_throw_declaration(Context *context, Visibility visi */ static inline bool parse_param_decl(Context *context, Visibility parent_visibility, Decl*** parameters, bool type_only) { - TypeInfo *type = TRY_TYPE_OR(parse_type_expression(context), false); + TypeInfo *type = TRY_TYPE_OR(parse_type(context), false); Decl *param = decl_new_var(context->tok, type, VARDECL_PARAM, parent_visibility); param->span = type->span; if (!try_consume(context, TOKEN_IDENT)) @@ -1020,7 +1010,7 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *visible_parent) } continue; } - TypeInfo *type = TRY_TYPE_OR(parse_type_expression(context), false); + TypeInfo *type = TRY_TYPE_OR(parse_type(context), false); while (1) { @@ -1116,7 +1106,7 @@ static inline Decl *parse_generics_declaration(Context *context, Visibility visi TypeInfo *rtype = NULL; if (context->tok.type != TOKEN_IDENT) { - rtype = TRY_TYPE_OR(parse_type_expression(context), poisoned_decl); + rtype = TRY_TYPE_OR(parse_type(context), poisoned_decl); } Path *path = parse_path_prefix(context); Decl *decl = decl_new(DECL_GENERIC, context->tok, visibility); @@ -1147,7 +1137,7 @@ static inline Decl *parse_generics_declaration(Context *context, Visibility visi TypeInfo **types = NULL; while (!try_consume(context, TOKEN_COLON)) { - TypeInfo *type = TRY_TYPE_OR(parse_type_expression(context), poisoned_decl); + TypeInfo *type = TRY_TYPE_OR(parse_type(context), poisoned_decl); types = VECADD(types, type); if (!try_consume(context, TOKEN_COMMA) && context->tok.type != TOKEN_COLON) { @@ -1258,7 +1248,7 @@ static inline bool parse_func_typedef(Context *context, Decl *decl, Visibility v { decl->typedef_decl.is_func = true; advance_and_verify(context, TOKEN_FUNC); - TypeInfo *type_info = TRY_TYPE_OR(parse_type_expression(context), false); + TypeInfo *type_info = TRY_TYPE_OR(parse_type(context), false); decl->typedef_decl.function_signature.rtype = type_info; if (!parse_opt_parameter_type_list(context, visibility, &(decl->typedef_decl.function_signature), true)) { @@ -1278,7 +1268,7 @@ static inline Decl *parse_typedef_declaration(Context *context, Visibility visib } else { - decl->typedef_decl.type_info = TRY_TYPE_OR(parse_type_expression(context), poisoned_decl); + decl->typedef_decl.type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl); decl->typedef_decl.is_func = false; } CONSUME_OR(TOKEN_AS, poisoned_decl); @@ -1297,7 +1287,7 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil TypeInfo *rtype = NULL; if (context->tok.type != TOKEN_IDENT) { - rtype = TRY_TYPE_OR(parse_type_expression(context), poisoned_decl); + rtype = TRY_TYPE_OR(parse_type(context), poisoned_decl); } Decl *decl = decl_new(DECL_MACRO, context->tok, visibility); @@ -1314,7 +1304,6 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil { case TOKEN_IDENT: case TOKEN_CT_IDENT: - case TOKEN_HASH_IDENT: break; default: if (parm_type) @@ -1322,7 +1311,7 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil SEMA_TOKEN_ERROR(context->tok, "Expected a macro parameter"); return poisoned_decl; } - parm_type = TRY_TYPE_OR(parse_type_expression(context), poisoned_decl); + parm_type = TRY_TYPE_OR(parse_type(context), poisoned_decl); goto TEST_TYPE; } Decl *param = decl_new_var(context->tok, parm_type, VARDECL_PARAM, visibility); @@ -1511,7 +1500,7 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit { advance_and_verify(context, TOKEN_FUNC); - TypeInfo *return_type = TRY_TYPE_OR(parse_type_expression(context), poisoned_decl); + TypeInfo *return_type = TRY_TYPE_OR(parse_type(context), poisoned_decl); Decl *func = decl_new(DECL_FUNC, context->tok, visibility); func->func.function_signature.rtype = return_type; @@ -1695,7 +1684,7 @@ static inline Decl *parse_top_level(Context *context) return parse_error_declaration(context, visibility); case TOKEN_TYPEDEF: return parse_typedef_declaration(context, visibility); - case TOKEN_TYPE: + case TOKEN_CT_TYPE_IDENT: case TOKEN_TYPE_IDENT: // All of these start type return parse_global_declaration(context, visibility); @@ -1757,7 +1746,6 @@ static inline bool parse_optional_module_params(Context *context, Token **tokens sema_error_range(context->next_tok.span, "Unexpected ','"); return false; case TOKEN_CT_IDENT: - case TOKEN_HASH_IDENT: case TOKEN_TYPE_IDENT: break; default: @@ -1824,13 +1812,14 @@ static inline void parse_module(Context *context) * : IDENT * | TYPE * | MACRO - * | CONST + * | CONST_IDENT * ; * * @return true if import succeeded */ static inline bool parse_import_selective(Context *context, Path *path) { + // TODO constident, @ etc if (!token_is_symbol(context->tok.type)) { SEMA_TOKEN_ERROR(context->tok, "Expected a symbol name here, the syntax is 'import : '."); @@ -1981,37 +1970,6 @@ static Expr *parse_type_access(Context *context, TypeInfo *type) } -/** - * type_identifier - * : TYPE_IDENT initializer_list - * | TYPE_IDENT method_ref - * ; - * - * @param left must be null. - * @return Expr* - */ -Expr *parse_type_identifier_with_path(Context *context, Path *path) -{ - TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER, path ? path->span : context->tok.span ); - type->unresolved.path = path; - type->unresolved.name_loc = context->tok; - advance_and_verify(context, TOKEN_TYPE_IDENT); - RANGE_EXTEND_PREV(type); - if (context->tok.type == TOKEN_LBRACE) - { - Expr *expr = expr_new(EXPR_COMPOUND_LITERAL, type->span); - expr->expr_compound_literal.type_info = type; - expr->expr_compound_literal.initializer = TRY_EXPR_OR(parse_initializer_list(context), poisoned_expr); - RANGE_EXTEND_PREV(expr); - return expr; - } - EXPECT_OR(TOKEN_DOT, poisoned_expr); - return parse_type_access(context, type); -} - - - - diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index cd19cf51e..13fe74ddc 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -31,9 +31,9 @@ SEMA_TOKEN_ERROR(context->tok, "Expected ',' or ')'"); return _res; } } while(0) Ast *parse_stmt(Context *context); Path *parse_path_prefix(Context *context); -Expr *parse_type_identifier_with_path(Context *context, Path *path); +Expr *parse_type_expression_with_path(Context *context, Path *path); Expr *parse_expr(Context *context); -TypeInfo *parse_type_expression(Context *context); +TypeInfo *parse_type(Context *context); Expr* parse_constant_expr(Context *context); Expr *parse_initializer_list(Context *context); Expr *parse_initializer(Context *context); @@ -44,7 +44,8 @@ Expr *parse_expression_list(Context *context); bool parse_type_or_expr(Context *context, Expr **expr_ptr, TypeInfo **type_ptr); Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type); bool parse_param_list(Context *context, Expr ***result, bool allow_type); - +Expr *parse_type_compound_literal_expr_after_type(Context *context, TypeInfo *type_info); +Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info); void error_at_current(Context *context, const char* message, ...); bool try_consume(Context *context, TokenType type); bool consume(Context *context, TokenType type, const char *message, ...); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index a0671c38f..06473b9dc 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -11,6 +11,19 @@ * - Disallow jumping in and out of an expression block. */ +static Expr **expr_copy_expr_list_from_macro(Context *context, Expr *macro, Expr **expr_list); +static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_expr); +static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source); +static Ast **ast_copy_list_from_macro(Context *context, Expr *macro, Ast **to_copy); + +#define MACRO_COPY_EXPR(x) x = expr_copy_from_macro(context, macro, x) +#define MACRO_COPY_TYPE(x) x = type_info_copy_from_macro(context, macro, x) +#define MACRO_COPY_TYPE_LIST(x) x = type_info_copy_list_from_macro(context, macro, x) +#define MACRO_COPY_EXPR_LIST(x) x = expr_copy_expr_list_from_macro(context, macro, x) +#define MACRO_COPY_AST_LIST(x) x = ast_copy_list_from_macro(context, macro, x) +#define MACRO_COPY_AST(x) x = ast_copy_from_macro(context, macro, x) + + static inline bool is_const(Expr *expr) { return expr->expr_kind == EXPR_CONST; @@ -514,6 +527,14 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp TypeInfo *type_info = expr->type_access.type; if (!sema_resolve_type_info(context, type_info)) return false; Type *canonical = type_info->type->canonical; + if (expr->type_access.name.type == TOKEN_TYPEID) + { + expr->type = type_typeid; + expr->expr_kind = EXPR_TYPEID; + expr->typeid_expr = type_info; + expr->resolve_status = RESOLVE_DONE; + return true; + } if (!type_may_have_method_functions(canonical)) { SEMA_ERROR(expr, "'%s' does not have method functions.", type_to_error_string(type_info->type)); @@ -932,10 +953,7 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to return false; } -static inline bool sema_expr_analyse_sizeof(Context *context, Type *to, Expr *expr) -{ - TODO -} + static inline bool sema_expr_analyse_expr_list(Context *context, Type *to, Expr *expr) { @@ -2219,10 +2237,6 @@ static Expr *expr_shallow_copy(Expr *source) } -static Expr **expr_copy_expr_list_from_macro(Context *context, Expr *macro, Expr **expr_list); -static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_expr); -static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source); -static void ast_copy_list_from_macro(Context *context, Expr *macro, Ast ***to_convert); static TypeInfo *type_info_copy_from_macro(Context *context, Expr *macro, TypeInfo *source) { @@ -2259,106 +2273,103 @@ static TypeInfo *type_info_copy_from_macro(Context *context, Expr *macro, TypeIn } -static void ast_copy_list_from_macro(Context *context, Expr *macro, Ast ***to_convert) +static Ast** ast_copy_list_from_macro(Context *context, Expr *macro, Ast **to_copy) { Ast **result = NULL; - Ast **list = *to_convert; - VECEACH(list, i) + VECEACH(to_copy, i) { - vec_add(result, ast_copy_from_macro(context, macro, list[i])); + vec_add(result, ast_copy_from_macro(context, macro, to_copy[i])); } - *to_convert = result; + return result; } static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_expr) { -#define EXPR_COPY(x) x = expr_copy_from_macro(context, macro, x) if (!source_expr) return NULL; Expr *expr = expr_shallow_copy(source_expr); switch (source_expr->expr_kind) { + case EXPR_TYPEOF: + MACRO_COPY_EXPR(expr->typeof_expr); + return expr; case EXPR_COMPOUND_LITERAL: - EXPR_COPY(expr->expr_compound_literal.initializer); - expr->expr_compound_literal.type_info = type_info_copy_from_macro(context, macro, expr->expr_compound_literal.type_info); + MACRO_COPY_EXPR(expr->expr_compound_literal.initializer); + MACRO_COPY_TYPE(expr->expr_compound_literal.type_info); return expr; case EXPR_DESIGNATED_INITIALIZER: // Created during semantic analysis UNREACHABLE case EXPR_RANGE: - EXPR_COPY(expr->range_expr.left); - EXPR_COPY(expr->range_expr.right); + MACRO_COPY_EXPR(expr->range_expr.left); + MACRO_COPY_EXPR(expr->range_expr.right); return expr; case EXPR_EXPR_BLOCK: - ast_copy_list_from_macro(context, macro, &expr->expr_block.stmts); + MACRO_COPY_AST_LIST(expr->expr_block.stmts); return expr; case EXPR_POISONED: return source_expr; case EXPR_TRY: - EXPR_COPY(expr->try_expr.expr); - EXPR_COPY(expr->try_expr.else_expr); + MACRO_COPY_EXPR(expr->try_expr.expr); + MACRO_COPY_EXPR(expr->try_expr.else_expr); return expr; case EXPR_CONST: return expr; case EXPR_BINARY: - EXPR_COPY(expr->binary_expr.left); - EXPR_COPY(expr->binary_expr.right); + MACRO_COPY_EXPR(expr->binary_expr.left); + MACRO_COPY_EXPR(expr->binary_expr.right); return expr; case EXPR_TERNARY: - EXPR_COPY(expr->ternary_expr.cond); - EXPR_COPY(expr->ternary_expr.then_expr); - EXPR_COPY(expr->ternary_expr.else_expr); + MACRO_COPY_EXPR(expr->ternary_expr.cond); + MACRO_COPY_EXPR(expr->ternary_expr.then_expr); + MACRO_COPY_EXPR(expr->ternary_expr.else_expr); return expr; case EXPR_UNARY: - EXPR_COPY(expr->unary_expr.expr); + MACRO_COPY_EXPR(expr->unary_expr.expr); return expr; case EXPR_POST_UNARY: - EXPR_COPY(expr->post_expr.expr); + MACRO_COPY_EXPR(expr->post_expr.expr); return expr; - case EXPR_TYPE: - expr->type_expr.type = type_info_copy_from_macro(context, macro, expr->type_expr.type); + case EXPR_TYPEID: + MACRO_COPY_TYPE(expr->typeid_expr); return expr; case EXPR_IDENTIFIER: TODO break; case EXPR_TYPE_ACCESS: - expr->type_access.type = type_info_copy_from_macro(context, macro, expr->type_expr.type); + MACRO_COPY_TYPE(expr->type_access.type); return expr; case EXPR_CALL: - EXPR_COPY(expr->call_expr.function); - expr->call_expr.arguments = expr_copy_expr_list_from_macro(context, macro, expr->call_expr.arguments); + MACRO_COPY_EXPR(expr->call_expr.function); + MACRO_COPY_EXPR_LIST(expr->call_expr.arguments); return expr; - case EXPR_SIZEOF: - TODO - break; case EXPR_SUBSCRIPT: - EXPR_COPY(expr->subscript_expr.expr); - EXPR_COPY(expr->subscript_expr.index); + MACRO_COPY_EXPR(expr->subscript_expr.expr); + MACRO_COPY_EXPR(expr->subscript_expr.index); return expr; case EXPR_GROUP: - EXPR_COPY(expr->group_expr->group_expr); + MACRO_COPY_EXPR(expr->group_expr->group_expr); return expr; case EXPR_ACCESS: - EXPR_COPY(expr->access_expr.parent); + MACRO_COPY_EXPR(expr->access_expr.parent); return expr; case EXPR_INITIALIZER_LIST: - expr->expr_initializer.initializer_expr = expr_copy_expr_list_from_macro(context, macro, expr->expr_initializer.initializer_expr); + MACRO_COPY_EXPR_LIST(expr->expr_initializer.initializer_expr); return expr; case EXPR_EXPRESSION_LIST: - expr->expression_list = expr_copy_expr_list_from_macro(context, macro, expr->expression_list); + MACRO_COPY_EXPR_LIST(expr->expression_list); return expr; case EXPR_CAST: - EXPR_COPY(expr->cast_expr.expr); - expr->cast_expr.type_info = type_info_copy_from_macro(context, macro, expr->cast_expr.type_info); + MACRO_COPY_EXPR(expr->cast_expr.expr); + MACRO_COPY_TYPE(expr->cast_expr.type_info); return expr; case EXPR_SCOPED_EXPR: - EXPR_COPY(expr->expr_scope.expr); + MACRO_COPY_EXPR(expr->expr_scope.expr); return expr; case EXPR_MACRO_EXPR: - EXPR_COPY(expr->macro_expr); + MACRO_COPY_EXPR(expr->macro_expr); return expr; } -#undef EXPR_COPY UNREACHABLE } @@ -2373,21 +2384,18 @@ static Expr **expr_copy_expr_list_from_macro(Context *context, Expr *macro, Expr } -static void type_info_copy_list_from_macro(Context *context, Expr *macro, TypeInfo ***to_convert) +static TypeInfo** type_info_copy_list_from_macro(Context *context, Expr *macro, TypeInfo **to_copy) { TypeInfo **result = NULL; - TypeInfo **list = *to_convert; - VECEACH(list, i) + VECEACH(to_copy, i) { - vec_add(result, type_info_copy_from_macro(context, macro, list[i])); + vec_add(result, type_info_copy_from_macro(context, macro, to_copy[i])); } - *to_convert = result; + return result; } static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source) { -#define EXPR_COPY(x) x = expr_copy_from_macro(context, macro, x) -#define AST_COPY(x) x = ast_copy_from_macro(context, macro, x) Ast *ast = ast_shallow_copy(source); switch (source->ast_kind) { @@ -2400,87 +2408,87 @@ static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source) case AST_BREAK_STMT: return ast; case AST_CASE_STMT: - AST_COPY(ast->case_stmt.body); - EXPR_COPY(ast->case_stmt.expr); + MACRO_COPY_AST(ast->case_stmt.body); + MACRO_COPY_EXPR(ast->case_stmt.expr); return ast; break; case AST_CATCH_STMT: - AST_COPY(ast->catch_stmt.body); + MACRO_COPY_AST(ast->catch_stmt.body); return ast; case AST_COMPOUND_STMT: - ast_copy_list_from_macro(context, macro, &ast->compound_stmt.stmts); + MACRO_COPY_AST_LIST(ast->compound_stmt.stmts); return ast; case AST_CONTINUE_STMT: return ast; case AST_CT_IF_STMT: - EXPR_COPY(ast->ct_if_stmt.expr); - AST_COPY(ast->ct_if_stmt.elif); - AST_COPY(ast->ct_if_stmt.then); + MACRO_COPY_EXPR(ast->ct_if_stmt.expr); + MACRO_COPY_AST(ast->ct_if_stmt.elif); + MACRO_COPY_AST(ast->ct_if_stmt.then); return ast; case AST_CT_ELIF_STMT: - EXPR_COPY(ast->ct_elif_stmt.expr); - AST_COPY(ast->ct_elif_stmt.then); - AST_COPY(ast->ct_elif_stmt.elif); + MACRO_COPY_EXPR(ast->ct_elif_stmt.expr); + MACRO_COPY_AST(ast->ct_elif_stmt.then); + MACRO_COPY_AST(ast->ct_elif_stmt.elif); return ast; case AST_CT_ELSE_STMT: - AST_COPY(ast->ct_else_stmt); + MACRO_COPY_AST(ast->ct_else_stmt); return ast; case AST_CT_FOR_STMT: - AST_COPY(ast->ct_for_stmt.body); - EXPR_COPY(ast->ct_for_stmt.expr); + MACRO_COPY_AST(ast->ct_for_stmt.body); + MACRO_COPY_EXPR(ast->ct_for_stmt.expr); return ast; case AST_CT_SWITCH_STMT: - EXPR_COPY(ast->ct_switch_stmt.cond); - ast_copy_list_from_macro(context, macro, &ast->ct_switch_stmt.body); + MACRO_COPY_EXPR(ast->ct_switch_stmt.cond); + MACRO_COPY_AST_LIST(ast->ct_switch_stmt.body); return ast; case AST_CT_DEFAULT_STMT: - AST_COPY(ast->ct_default_stmt); + MACRO_COPY_AST(ast->ct_default_stmt); return ast; case AST_CT_CASE_STMT: - AST_COPY(ast->ct_case_stmt.body); - type_info_copy_list_from_macro(context, macro, &ast->ct_case_stmt.types); + MACRO_COPY_AST(ast->ct_case_stmt.body); + MACRO_COPY_TYPE_LIST(ast->ct_case_stmt.types); return ast; case AST_DECLARE_STMT: TODO return ast; case AST_DEFAULT_STMT: - AST_COPY(ast->case_stmt.body); + MACRO_COPY_AST(ast->case_stmt.body); return ast; case AST_DEFER_STMT: assert(!ast->defer_stmt.prev_defer); - AST_COPY(ast->defer_stmt.body); + MACRO_COPY_AST(ast->defer_stmt.body); return ast; case AST_DO_STMT: - AST_COPY(ast->do_stmt.body); - EXPR_COPY(ast->do_stmt.expr); + MACRO_COPY_AST(ast->do_stmt.body); + MACRO_COPY_EXPR(ast->do_stmt.expr); return ast; case AST_EXPR_STMT: - EXPR_COPY(ast->expr_stmt); + MACRO_COPY_EXPR(ast->expr_stmt); return ast; case AST_FOR_STMT: - EXPR_COPY(ast->for_stmt.cond); - EXPR_COPY(ast->for_stmt.incr); - AST_COPY(ast->for_stmt.body); - AST_COPY(ast->for_stmt.init); + MACRO_COPY_EXPR(ast->for_stmt.cond); + MACRO_COPY_EXPR(ast->for_stmt.incr); + MACRO_COPY_AST(ast->for_stmt.body); + MACRO_COPY_AST(ast->for_stmt.init); return ast; case AST_GENERIC_CASE_STMT: - AST_COPY(ast->generic_case_stmt.body); + MACRO_COPY_AST(ast->generic_case_stmt.body); // ast->generic_case_stmt.types = ... TODO return ast; case AST_GENERIC_DEFAULT_STMT: - AST_COPY(ast->generic_default_stmt); + MACRO_COPY_AST(ast->generic_default_stmt); return ast; case AST_GOTO_STMT: - AST_COPY(ast->goto_stmt.label); + MACRO_COPY_AST(ast->goto_stmt.label); // TODO fixup name, which needs to be macro local. TODO return ast; case AST_IF_STMT: - AST_COPY(ast->if_stmt.cond); - AST_COPY(ast->if_stmt.decl); - AST_COPY(ast->if_stmt.else_body); - AST_COPY(ast->if_stmt.then_body); + MACRO_COPY_AST(ast->if_stmt.cond); + MACRO_COPY_AST(ast->if_stmt.decl); + MACRO_COPY_AST(ast->if_stmt.else_body); + MACRO_COPY_AST(ast->if_stmt.then_body); return ast; case AST_LABEL: assert(!ast->label_stmt.defer); @@ -2491,23 +2499,23 @@ static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source) case AST_NOP_STMT: return ast; case AST_RETURN_STMT: - EXPR_COPY(ast->return_stmt.expr); + MACRO_COPY_EXPR(ast->return_stmt.expr); // TODO handle conversions? TODO return ast; case AST_DECL_EXPR_LIST: - ast_copy_list_from_macro(context, macro, &ast->decl_expr_stmt); + MACRO_COPY_AST_LIST(ast->decl_expr_stmt); return ast; case AST_SWITCH_STMT: - AST_COPY(ast->switch_stmt.decl); - AST_COPY(ast->switch_stmt.cond); - ast_copy_list_from_macro(context, macro, &ast->switch_stmt.cases); + MACRO_COPY_AST(ast->switch_stmt.decl); + MACRO_COPY_AST(ast->switch_stmt.cond); + MACRO_COPY_AST_LIST(ast->switch_stmt.cases); return ast; case AST_THROW_STMT: - EXPR_COPY(ast->throw_stmt.throw_value); + MACRO_COPY_EXPR(ast->throw_stmt.throw_value); return ast; case AST_TRY_STMT: - AST_COPY(ast->try_stmt); + MACRO_COPY_AST(ast->try_stmt); return ast; case AST_NEXT_STMT: TODO @@ -2516,17 +2524,15 @@ static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source) TODO return ast; case AST_WHILE_STMT: - AST_COPY(ast->while_stmt.cond); - AST_COPY(ast->while_stmt.decl); - AST_COPY(ast->while_stmt.body); + MACRO_COPY_AST(ast->while_stmt.cond); + MACRO_COPY_AST(ast->while_stmt.decl); + MACRO_COPY_AST(ast->while_stmt.body); return ast; case AST_SCOPED_STMT: - AST_COPY(ast->scoped_stmt.stmt); + MACRO_COPY_AST(ast->scoped_stmt.stmt); return ast; } UNREACHABLE; -#undef EXPR_COPY -#undef AST_COPY } static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *macro, Expr *inner) { @@ -2602,11 +2608,11 @@ static inline bool sema_expr_analyse_macro_expr(Context *context, Type *to, Expr static inline bool sema_expr_analyse_type(Context *context, Type *to, Expr *expr) { - if (!sema_resolve_type_info(context, expr->type_expr.type)) + if (!sema_resolve_type_info(context, expr->typeid_expr)) { return expr_poison(expr); } - expr->type = type_get_meta(expr->type_expr.type->type); + expr->type = type_typeid; return true; } @@ -2750,6 +2756,16 @@ static inline bool sema_expr_analyse_compound_literal(Context *context, Type *to return true; } +static inline bool sema_expr_analyse_typeof(Context *context, Expr *expr) +{ + if (!sema_analyse_expr(context, NULL, expr->typeof_expr)) return false; + Type *type = expr->typeof_expr->type->canonical; + expr->expr_kind = EXPR_TYPEID; + expr->typeid_expr = type_info_new_base(type, expr->typeof_expr->span); + expr->type = type_typeid; + return true; +} + static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *expr) { switch (expr->expr_kind) @@ -2761,6 +2777,8 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr * UNREACHABLE case EXPR_SCOPED_EXPR: UNREACHABLE + case EXPR_TYPEOF: + return sema_expr_analyse_typeof(context, expr); case EXPR_COMPOUND_LITERAL: return sema_expr_analyse_compound_literal(context, to, expr); case EXPR_EXPR_BLOCK: @@ -2781,7 +2799,7 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr * return sema_expr_analyse_unary(context, to, expr); case EXPR_POST_UNARY: return sema_expr_analyse_post_unary(context, to, expr); - case EXPR_TYPE: + case EXPR_TYPEID: return sema_expr_analyse_type(context, to, expr); case EXPR_IDENTIFIER: return sema_expr_analyse_identifier(context, to, expr); @@ -2789,8 +2807,6 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr * return sema_expr_analyse_type_access(context, to, expr); case EXPR_CALL: return sema_expr_analyse_call(context, to, expr); - case EXPR_SIZEOF: - return sema_expr_analyse_sizeof(context, to, expr); case EXPR_SUBSCRIPT: return sema_expr_analyse_subscript(context, to, expr); case EXPR_GROUP: diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index 204008990..51ccf5f89 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -140,10 +140,12 @@ const char *token_type_to_string(TokenType type) // Identifiers case TOKEN_IDENT: return "IDENT"; - case TOKEN_HASH_IDENT: - return "HASH_IDENT"; case TOKEN_CT_IDENT: return "CT_IDENT"; + case TOKEN_CT_CONST_IDENT: + return "CT_CONST_IDENT"; + case TOKEN_CT_TYPE_IDENT: + return "CT_TYPE_IDENT"; case TOKEN_CONST_IDENT: return "CONST_IDENT"; case TOKEN_TYPE_IDENT: @@ -240,8 +242,10 @@ const char *token_type_to_string(TokenType type) return "true"; case TOKEN_TRY: return "try"; - case TOKEN_TYPE: - return "type"; + case TOKEN_TYPEID: + return "typeid"; + case TOKEN_TYPEOF: + return "typeof"; case TOKEN_TYPEDEF: return "typedef"; case TOKEN_UNION: diff --git a/src/compiler/types.c b/src/compiler/types.c index fbf1e87b7..17307dd26 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -43,11 +43,9 @@ Type *type_c_uint = &t_cui; Type *type_c_ulong = &t_cul; Type *type_c_ulonglong = &t_cull; - -#define META_OFFSET 0 -#define PTR_OFFSET 1 -#define VAR_ARRAY_OFFSET 2 -#define ARRAY_OFFSET 3 +#define PTR_OFFSET 0 +#define VAR_ARRAY_OFFSET 1 +#define ARRAY_OFFSET 2 Type *type_signed_int_by_bitsize(unsigned bytesize) { @@ -196,8 +194,6 @@ size_t type_size(Type *canonical) case TYPE_POISONED: case TYPE_TYPEDEF: UNREACHABLE; - case TYPE_META_TYPE: - return 0; case TYPE_ENUM: return canonical->decl->enums.type_info->type->canonical->builtin.bytesize; case TYPE_ERROR: @@ -208,6 +204,7 @@ size_t type_size(Type *canonical) case TYPE_VOID: return 1; case TYPE_BOOL: + case TYPE_META_TYPE: case ALL_INTS: case ALL_FLOATS: return canonical->builtin.bytesize; @@ -235,8 +232,6 @@ unsigned int type_abi_alignment(Type *canonical) case TYPE_TYPEDEF: case TYPE_VOID: UNREACHABLE; - case TYPE_META_TYPE: - return 0; case TYPE_ENUM: return canonical->decl->enums.type_info->type->canonical->builtin.abi_alignment; case TYPE_ERROR: @@ -244,6 +239,7 @@ unsigned int type_abi_alignment(Type *canonical) case TYPE_STRUCT: case TYPE_UNION: return canonical->decl->strukt.abi_alignment; + case TYPE_META_TYPE: case TYPE_BOOL: case ALL_INTS: case ALL_FLOATS: @@ -298,31 +294,6 @@ static Type *type_generate_ptr(Type *ptr_type, bool canonical) return ptr; } -static Type *type_generate_meta(Type *type, bool canonical) -{ - if (canonical) type = type->canonical; - if (!type->type_cache) - { - create_type_cache(type); - } - - Type *meta = type->type_cache[META_OFFSET]; - if (meta == NULL) - { - meta = type_new(TYPE_META_TYPE, strformat("type %s", type->name)); - meta->child = type; - type->type_cache[META_OFFSET] = meta; - if (type == type->canonical) - { - meta->canonical = meta; - } - else - { - meta->canonical = type_generate_meta(type->canonical, true); - } - } - return meta; -} Type *type_get_ptr(Type *ptr_type) @@ -330,11 +301,6 @@ Type *type_get_ptr(Type *ptr_type) return type_generate_ptr(ptr_type, false); } -Type *type_get_meta(Type *meta_type) -{ - return type_generate_meta(meta_type, false); -} - Type *type_get_indexed_type(Type *type) { switch (type->type_kind) @@ -472,6 +438,7 @@ type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target- #undef DEF_TYPE + type_create("typeid", &t_typeid, TYPE_META_TYPE, target->width_pointer, target->align_pref_pointer, target->align_pointer); type_create("void*", &t_voidstar, TYPE_POINTER, target->width_pointer, target->align_pref_pointer, target->align_pointer); create_type_cache(type_void); type_void->type_cache[0] = &t_voidstar; @@ -491,7 +458,6 @@ type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target- type_create_alias("c_int", &t_ci, type_signed_int_by_bitsize(target->width_c_int)); // TODO fix error size type_create_alias("error", &t_err, type_signed_int_by_bitsize(target->width_c_int)); - type_create_alias("typeid", &t_typeid, type_signed_int_by_bitsize(target->width_pointer)); type_create_alias("c_long", &t_cl, type_signed_int_by_bitsize(target->width_c_long)); type_create_alias("c_longlong", &t_cll, type_signed_int_by_bitsize(target->width_c_long_long));