diff --git a/README.md b/README.md index 23884a635..f20c388d9 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,6 @@ There are some small work being done on the parser here, but most of the structu - `$switch` and `$for` not handled. - Enums not correctly handled. - Type resolution not complete for all types. -- `type` not handled. -- Identifier analysis incomplete. - Macro call not handled completely. #### What's missing overall diff --git a/missing.txt b/missing.txt index 11ffdfdd2..3d0ab5c7d 100644 --- a/missing.txt +++ b/missing.txt @@ -29,7 +29,7 @@ Things missing: - Strings - Array - Slice -- Values: size, alignment, name, qualifiedName +- Values: alignment, name, qualifiedName - Functions: offsetof - Distinct types - Simd types? @@ -46,7 +46,6 @@ Things missing: * Struct / union - Cast to union? - Structural typed anonymous structs and casts to them. -- Auto deref on access. * Expressions - Disallow x >= 0 and x < 0 on unsigned types unless in a macro. diff --git a/resources/examples/acornvm/avm_array.c3 b/resources/examples/acornvm/avm_array.c3 index d23a62bca..64c9c7998 100644 --- a/resources/examples/acornvm/avm_array.c3 +++ b/resources/examples/acornvm/avm_array.c3 @@ -8,6 +8,10 @@ module acorn::arr; * See Copyright Notice in avm.h */ +error SearchError +{ + NOT_FOUND +} /* Return a new Array, allocating len slots for Values. */ func Value new(Value th, Value *dest, Value type, AuintIdx len) { diff --git a/resources/examples/acornvm/parser.c3 b/resources/examples/acornvm/parser.c3 index 85c48f93c..aae251d97 100644 --- a/resources/examples/acornvm/parser.c3 +++ b/resources/examples/acornvm/parser.c3 @@ -50,7 +50,7 @@ int findBlockVar(Value th, Value locvars, Value varnm) } /* Look for local variable. Returns idx if found, -1 otherwise. */ -func int CompInfo.findLocalVar(CompInfo *comp, Value varnm) +func int CompInfo.findLocalVar(CompInfo *comp, Value varnm) throws SearchError { assert(varnm.isSym()); @@ -68,7 +68,7 @@ func int CompInfo.findLocalVar(CompInfo *comp, Value varnm) } locvars = arrGet(th, locvars, 0); // link to prior local variables } while (locvars != aNull); - return -1; + throw SearchError.NOT_FOUND; } /* Look for closure variable. Returns idx if found, -1 otherwise. */ diff --git a/resources/examples/gameoflife.c3 b/resources/examples/gameoflife.c3 index 4c8c2bd2f..f8ab75cef 100644 --- a/resources/examples/gameoflife.c3 +++ b/resources/examples/gameoflife.c3 @@ -1,5 +1,8 @@ module game_of_life; +extern func void printf(char *fmt, ...); +extern func int atoi(char *val); + struct GameBoard { int h; @@ -8,19 +11,27 @@ struct GameBoard byte* temp; } +extern void *__stdoutp; +extern func void fflush(void *std); +extern func int rand(); +extern func void* malloc(usize size); +extern func void usleep(int time); + func void GameBoard.show(GameBoard *board) { - printf("\033[H"); + + printf("\e[H"); byte* current = board.world; for (int y = 0; y < board.h; y++) { for (int x = 0; x < board.w; x++) { - printf(*current ? "\033[07m \033[m" : " "); + printf(*current ? "\e[07m \e[m" : " "); + current++; } - printf("\033[E"); + printf("\e[E"); } - stdout.fflush(); + fflush(__stdoutp); } func void GameBoard.evolve(GameBoard *board) @@ -34,24 +45,26 @@ func void GameBoard.evolve(GameBoard *board) { for (int x1 = x - 1; x1 <= x + 1; x1++) { - int actualX = (x1 + w) % w; - int actualY = (y1 + h) % h; - if (board.world[x + y * w]) n++; + int actualX = (x1 + board.w) % board.w; + int actualY = (y1 + board.h) % board.h; + if (board.world[actualX + actualY * board.w]) n++; } } - if (board.world(x + y * w)) n--; - board.temp[x + y * w] = (n == 3 || (n == 2 && board.world(x + y * w))); + if (board.world[x + y * board.w]) n--; + board.temp[x + y * board.w] = cast(n == 3 || (n == 2 && board.world[x + y * board.w]), byte); } } - for (int i = 0; i < w * h; i++) + for (int i = 0; i < board.w * board.h; i++) { board.world[i] = board.temp[i]; } } -int main(int c, string[] v) + +func int main(int c, char** v) { - int w = 0, h = 0; + int w = 0; + int h = 0; if (c > 1) w = atoi(v[1]); if (c > 2) h = atoi(v[2]); if (w <= 0) w = 30; @@ -60,18 +73,18 @@ int main(int c, string[] v) GameBoard board; board.w = w; board.h = h; - board.board = malloc(h * w); - board.temp = malloc(h * w); + board.world = malloc(cast(h * w, ulong)); + board.temp = malloc(cast(h * w, ulong)); for (int i = h * w - 1; i >= 0; i--) { - board.world[i] = rand() < RAND_MAX / 10 ? 1 : 0; + board.world[i] = rand() % 10 == 0 ? 1 : 0; } - while (1) + for (int j = 0; j < 1000; j++) { - board.show(); board.evolve(); usleep(200000); } + return 1; } \ No newline at end of file diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index a9c6b41db..6f81152ff 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -882,6 +882,7 @@ func void testErrors() printf("Throws: %d\n", throwsDone.times); printf("End of errors\n"); } + macro void arrayCallMacro($x) { printf("Array call: %d, %d\n", $x[0], $x[1]); @@ -1089,8 +1090,155 @@ func void testTypeValues() printf("Testunion.a sizeof: %d = 2\n", TestUnionSize.a.sizeof); } +func int testTypeofHelp() +{ + return 2; +} + +func void testTypeof() +{ + typeid y = typeof(1 + testTypeofHelp()); +} + +macro void printMessage($x) +{ + for (int i = 0; i < $x; i++) + { + printf("print message! %d\n", i); + } + $x = $x + 1; +} + +func void testMacros() +{ + int i = 3; + @printMessage(i); + printf("i: %d\n", i); +} + +const char[] LUT_ENC = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', +}; + +const byte ERR = 0xFF; + +const byte[256] LUT_DEC = { + // '+', ',', '-', '.', '/', '0', '1', '2' + 62, ERR, ERR, ERR, 63, 52, 53, 54, + // '3', '4', '5', '6', '7', '8', '9', ':' + 55, 56, 57, 58, 59, 60, 61, ERR, + // ';', '<', '=', '>', '?', '@', 'A', 'B' + ERR, ERR, ERR, ERR, ERR, ERR, 0, 1, + // 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' + 2, 3, 4, 5, 6, 7, 8, 9, + // 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R' + 10, 11, 12, 13, 14, 15, 16, 17, + // 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' + 18, 19, 20, 21, 22, 23, 24, 25, + // '[', '\', ']', '^', '_', '`', 'a', 'b' + ERR, ERR, ERR, ERR, ERR, ERR, 26, 27, + // 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' + 28, 29, 30, 31, 32, 33, 34, 35, + // 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r' + 36, 37, 38, 39, 40, 41, 42, 43, + // 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' + 44, 45, 46, 47, 48, 49, 50, 51, +}; + + +const char PAD = '='; +const char FIRST = '+'; +const char LAST = 'z'; + +public error Base64Error +{ + INVALID_CHARACTER +} + +public func void encode(byte[] in, string *out) +{ + int j = 0; + + for (int i = 0; i < in.len; i++); + { + switch (i % 3) + { + case 0: + out[j++] = LUT_ENC[(in[i] >> 2) & 0x3F]; + case 1: + out[j++] = LUT_ENC[(in[i-1] & 0x3) << 4 + ((in[i] >> 4) & 0xF)]; + case 2: + out[j++] = LUT_ENC[(in[i-1] & 0xF) << 2 + ((in[i] >> 6) & 0x3)]; + out[j++] = LUT_ENC[in[i] & 0x3F]; + } + i++; + } + + // move back + int last = in.len - 1; + + // check the last and add padding + switch (last % 3) + { + case 0: + out[j++] = LUT_ENC[(in[last] & 0x3) << 4]; + out[j++] = PAD; + out[j++] = PAD; + case 1: + out[j++] = LUT_ENC[(in[last] & 0xF) << 2]; + out[j++] = PAD; + } +} + +public func int decode(char[] in, byte[] out) throws Base64Error +{ + int j = 0; + + for (int i = 0; i < len; i++) + { + char value = in[i]; + + if (value == PAD) return j; + + if (value < FIRST || in[i] > LAST) throw INVALID_CHARACTER; + byte c = LUT_DEC[in[i] - FIRST); + if (c == ERR) throw INVALID_CHARACTER; + + switch (i % 4) + { + case 0: + out[j] = c << 2; + case 1: + out[j++] += (c >> 4) & 0x3; + // if not last char with padding + if (i < (len - 3) || in[len - 2] != PAD) + { + out[j] = (c & 0xF) << 4; + } + case 2: + out[j++] += (c >> 2) & 0xF; + if (i < (len -2) || in[len -1] != PAD) + { + out[j] = (c & 0x3) << 6; + } + case 3: + out[j++] += c; + } + } + return j; +} + func int main(int x) { + testMacros(); + testTypeof(); testSimple(); testErrorBug(); testErrors(); diff --git a/resources/testproject/bar.c3 b/resources/testproject/bar.c3 index 3ced5c41f..5721cc930 100644 --- a/resources/testproject/bar.c3 +++ b/resources/testproject/bar.c3 @@ -1,6 +1,6 @@ module bar; -import baz::foo; +import baz.foo; import testbaz; public func void test() diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 55939f42c..ec3865c89 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -492,9 +492,21 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) switch (expr->expr_kind) { case EXPR_IDENTIFIER: - DUMPF("(ident %s", expr->identifier_expr.identifier); + if (expr->identifier_expr.is_macro) + { + DUMPF("(ident @%s", expr->identifier_expr.identifier); + } + else + { + DUMPF("(ident %s", expr->identifier_expr.identifier); + } DUMPEXPC(expr); DUMPEND(); + case EXPR_MACRO_BLOCK: + DUMP("(macro_block"); + DUMPASTS(expr->macro_block.stmts); + DUMPDECLS(expr->macro_block.params); + DUMPEND(); case EXPR_EXPR_BLOCK: if (!expr->expr_block.stmts) { @@ -655,10 +667,6 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) DUMPEXPR(expr->expr_scope.expr); // TODO defers. DUMPEND(); - case EXPR_MACRO_EXPR: - DUMP("(macro-expr"); - DUMPEXPR(expr->macro_expr); - DUMPEND(); case EXPR_RANGE: DUMP("(range"); DUMPEXPR(expr->range_expr.left); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 280f664c1..2d3b769b0 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -257,6 +257,7 @@ typedef struct _VarDecl { unsigned id : 16; VarDeclKind kind : 3; + bool constant : 1; TypeInfo *type_info; Expr *init_expr; void *backend_debug_ref; @@ -569,6 +570,7 @@ typedef struct Path *path; const char *identifier; bool is_ref; + bool is_macro; Decl *decl; } ExprIdentifier; @@ -595,6 +597,13 @@ typedef struct Ast **stmts; } ExprFuncBlock; +typedef struct +{ + Ast **stmts; + Expr **args; + Decl **params; +} ExprMacroBlock; + typedef struct { Expr *left; @@ -643,7 +652,6 @@ struct _Expr ExprStructValue struct_value_expr; ExprTypeAccess type_access; ExprTry try_expr; - Expr* macro_expr; ExprBinary binary_expr; ExprTernary ternary_expr; ExprUnary unary_expr; @@ -658,6 +666,7 @@ struct _Expr Expr** expression_list; ExprScope expr_scope; ExprFuncBlock expr_block; + ExprMacroBlock macro_block; }; }; @@ -987,9 +996,9 @@ typedef struct _Context { bool in_macro_call : 1; bool in_macro : 1; + Decl **macro_locals_start; int macro_counter; int macro_nesting; - Expr *first_macro_call; }; Decl *locals[MAX_LOCALS]; DynamicScope scopes[MAX_SCOPE_DEPTH]; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 2fddbe1cd..7e21a49b3 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -232,8 +232,8 @@ typedef enum EXPR_CAST, EXPR_TYPEOF, EXPR_SCOPED_EXPR, - EXPR_MACRO_EXPR, EXPR_EXPR_BLOCK, + EXPR_MACRO_BLOCK, EXPR_RANGE, EXPR_DESIGNATED_INITIALIZER, EXPR_COMPOUND_LITERAL, @@ -267,6 +267,7 @@ typedef enum SCOPE_NEXT = 1 << 2, SCOPE_DEFER = 1 << 3, SCOPE_EXPR_BLOCK = 1 << 4, + SCOPE_MACRO = 1 << 5 } ScopeFlags; typedef enum diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index dcc63bc9a..8dbec4c2d 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -173,7 +173,8 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr) case EXPR_DESIGNATED_INITIALIZER: // Should only appear when generating designated initializers. UNREACHABLE - + case EXPR_MACRO_BLOCK: + TODO case EXPR_IDENTIFIER: return expr->identifier_expr.decl->ref; case EXPR_UNARY: @@ -201,7 +202,6 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr) case EXPR_INITIALIZER_LIST: case EXPR_EXPRESSION_LIST: case EXPR_CAST: - case EXPR_MACRO_EXPR: case EXPR_TYPEOF: UNREACHABLE } @@ -522,16 +522,23 @@ static LLVMValueRef gencontext_emit_logical_and_or(GenContext *context, Expr *ex gencontext_emit_block(context, rhs_block); LLVMValueRef rhs = gencontext_emit_expr(context, expr->binary_expr.right); + LLVMBasicBlockRef end_block = context->current_block; gencontext_emit_br(context, phi_block); - // Generate phi + // Generate phi gencontext_emit_block(context, phi_block); - 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 = llvm_int(type_bool, op == BINARYOP_AND ? 0 : 1); + + // One possibility here is that a return happens inside of the expression. + if (!end_block) + { + return result_on_skip; + } + LLVMValueRef phi = LLVMBuildPhi(context->builder, llvm_type(type_bool), "val"); LLVMValueRef logic_values[2] = { result_on_skip, rhs }; - LLVMBasicBlockRef blocks[2] = { start_block, rhs_block }; + LLVMBasicBlockRef blocks[2] = { start_block, end_block }; LLVMAddIncoming(phi, logic_values, blocks, 2); return phi; @@ -823,6 +830,10 @@ LLVMValueRef gencontext_emit_post_unary_expr(GenContext *context, Expr *expr) LLVMValueRef gencontext_emit_typeid(GenContext *context, Expr *expr) { + if (type_is_builtin(expr->typeid_expr->type->type_kind)) + { + return gencontext_emit_const_int(context, type_usize, expr->typeid_expr->type->type_kind); + } assert(expr->typeid_expr->type->backend_typeid); return expr->typeid_expr->type->backend_typeid; } @@ -1356,6 +1367,47 @@ static inline LLVMValueRef gencontext_emit_expr_block(GenContext *context, Expr return return_out ? gencontext_emit_load(context, expr->type, return_out) : NULL; } +static inline LLVMValueRef gencontext_emit_macro_block(GenContext *context, Expr *expr) +{ + LLVMValueRef old_ret_out = context->return_out; + LLVMBasicBlockRef saved_expr_block = context->expr_block_exit; + + LLVMBasicBlockRef expr_block = gencontext_create_free_block(context, "expr_block.exit"); + context->expr_block_exit = expr_block; + + LLVMValueRef return_out = NULL; + if (expr->type != type_void) + { + return_out = gencontext_emit_alloca(context, llvm_type(expr->type), "blockret"); + } + context->return_out = return_out; + + Ast **stmts = expr->macro_block.stmts; + VECEACH(expr->macro_block.params, i) + { + // In case we have a constant, we never do an emit. The value is already folded. + if (!expr->macro_block.args[i]) continue; + Decl *decl = expr->macro_block.params[i]; + decl->ref = gencontext_emit_alloca(context, llvm_type(decl->type), decl->name); + LLVMValueRef value = gencontext_emit_expr(context, expr->macro_block.args[i]); + LLVMBuildStore(context->builder, value, decl->ref); + } + + VECEACH(stmts, i) + { + gencontext_emit_stmt(context, stmts[i]); + } + gencontext_emit_br(context, expr_block); + + // Emit the exit block. + gencontext_emit_block(context, expr_block); + + context->return_out = old_ret_out; + context->expr_block_exit = saved_expr_block; + + return return_out ? gencontext_emit_load(context, expr->type, return_out) : NULL; +} + LLVMValueRef gencontext_emit_call_intrinsic(GenContext *context, unsigned intrinsic_id, LLVMTypeRef *types, LLVMValueRef *values, unsigned arg_count) { @@ -1392,6 +1444,8 @@ NESTED_RETRY: case EXPR_DESIGNATED_INITIALIZER: // Should only appear when generating designated initializers. UNREACHABLE + case EXPR_MACRO_BLOCK: + return gencontext_emit_macro_block(context, expr); case EXPR_COMPOUND_LITERAL: expr = expr->expr_compound_literal.initializer; goto NESTED_RETRY; @@ -1416,7 +1470,6 @@ NESTED_RETRY: 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 diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 95e801703..1c6be4279 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -211,8 +211,7 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl) } gencontext_add_attribute(context, function, nounwind_attribute, -1); - // TODO only for windows. - if (decl->func.attr_stdcall) + if (decl->func.attr_stdcall && (build_target.os == OS_TYPE_WIN32)) { LLVMSetFunctionCallConv(function, LLVMX86StdcallCallConv); LLVMSetDLLStorageClass(function, LLVMDLLImportStorageClass); diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 321f03eac..c65591fc8 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -97,13 +97,19 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type) } } -static Expr *parse_macro_expr(Context *context, Expr *left) +static Expr *parse_macro_ident(Context *context, Expr *left) { assert(!left && "Unexpected left hand side"); - Expr *macro_expr = EXPR_NEW_TOKEN(EXPR_MACRO_EXPR, context->tok); + Expr *macro_ident = EXPR_NEW_TOKEN(EXPR_IDENTIFIER, context->tok); + macro_ident->identifier_expr.is_macro = true; advance_and_verify(context, TOKEN_AT); - macro_expr->macro_expr = TRY_EXPR_OR(parse_precedence(context, PREC_UNARY + 1), poisoned_expr); - return macro_expr; + bool had_error = false; + macro_ident->identifier_expr.path = parse_path_prefix(context, &had_error); + if (had_error) return poisoned_expr; + macro_ident->identifier_expr.identifier = context->tok.string; + CONSUME_OR(TOKEN_IDENT, poisoned_expr); + RANGE_EXTEND_PREV(macro_ident); + return macro_ident; } @@ -381,7 +387,9 @@ static Expr *parse_identifier(Context *context, Expr *left) static Expr *parse_maybe_scope(Context *context, Expr *left) { assert(!left && "Unexpected left hand side"); - Path *path = parse_path_prefix(context); + bool had_error; + Path *path = parse_path_prefix(context, &had_error); + if (had_error) return poisoned_expr; switch (context->tok.type) { case TOKEN_IDENT: @@ -707,7 +715,13 @@ static Expr *parse_string_literal(Context *context, Expr *left) if (context->tok.string[i] == '\\') { i++; - i += append_esc_string_token(str, context->tok.string + i, &len) - 1; + int scanned = append_esc_string_token(str, context->tok.string + i, &len) - 1; + if (scanned < -1) + { + SEMA_TOKEN_ERROR(context->tok, "Invalid escape in string."); + return poisoned_expr; + } + i += scanned; continue; } str[len++] = context->tok.string[i]; @@ -861,7 +875,7 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_IDENT] = { parse_maybe_scope, NULL, PREC_NONE }, [TOKEN_TYPE_IDENT] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_CT_IDENT] = { parse_identifier, NULL, PREC_NONE }, - [TOKEN_AT] = { parse_macro_expr, NULL, PREC_UNARY }, + [TOKEN_AT] = { parse_macro_ident, NULL, PREC_NONE }, [TOKEN_CONST_IDENT] = { parse_identifier, NULL, PREC_NONE }, [TOKEN_STRING] = { parse_string_literal, NULL, PREC_NONE }, [TOKEN_REAL] = { parse_double, NULL, PREC_NONE }, diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index eebbb5e0b..6b9f3c156 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -632,8 +632,6 @@ Ast *parse_stmt(Context *context) { return parse_expr_stmt(context); } - case TOKEN_TYPEOF: - TODO case TOKEN_LOCAL: // Local means declaration! case TOKEN_CONST: // Const means declaration! return parse_declaration_stmt(context); @@ -743,6 +741,7 @@ Ast *parse_stmt(Context *context) case TOKEN_NIL: case TOKEN_TRUE: case TOKEN_LPARBRA: + case TOKEN_TYPEOF: return parse_expr_stmt(context); case TOKEN_INVALID_TOKEN: advance(context); diff --git a/src/compiler/parser.c b/src/compiler/parser.c index c60e329e6..246168c25 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -245,8 +245,9 @@ static inline Path *parse_module_path(Context *context) return path_create_from_string(scratch_ptr, offset, span); } -Path *parse_path_prefix(Context *context) +Path *parse_path_prefix(Context *context, bool *had_error) { + *had_error = false; if (context->tok.type != TOKEN_IDENT || context->next_tok.type != TOKEN_SCOPE) return NULL; char *scratch_ptr = context->path_scratch; @@ -277,6 +278,7 @@ Path *parse_path_prefix(Context *context) if (type != TOKEN_IDENT) { sema_error_range(path->span, "A module name was expected here."); + *had_error = true; return NULL; } @@ -312,7 +314,9 @@ Path *parse_path_prefix(Context *context) static inline TypeInfo *parse_base_type(Context *context) { SourceRange range = context->tok.span; - Path *path = parse_path_prefix(context); + bool had_error; + Path *path = parse_path_prefix(context, &had_error); + if (had_error) return poisoned_type_info; if (path) { TypeInfo *type_info = type_info_new(TYPE_INFO_IDENTIFIER, range); @@ -587,8 +591,11 @@ static inline Decl *parse_const_declaration(Context *context, Visibility visibil } else { + if (token_is_type(context->tok.type) || context->tok.type == TOKEN_CT_TYPE_IDENT || context->tok.type == TOKEN_TYPE_IDENT) + { + decl->var.type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl); + } if (!consume_const_name(context, "constant")) return poisoned_decl; - decl->var.type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl); } CONSUME_OR(TOKEN_EQ, poisoned_decl); @@ -755,7 +762,9 @@ static inline bool parse_attributes(Context *context, Decl *parent_decl) while (try_consume(context, TOKEN_AT)) { - Path *path = parse_path_prefix(context); + bool had_error; + Path *path = parse_path_prefix(context, &had_error); + if (had_error) return false; Attr *attr = malloc_arena(sizeof(Attr)); @@ -859,6 +868,11 @@ static inline bool parse_param_decl(Context *context, Visibility parent_visibili { if (context->tok.type != TOKEN_COMMA && context->tok.type != TOKEN_RPAREN) { + if (context->tok.type == TOKEN_CT_IDENT) + { + SEMA_TOKEN_ERROR(context->tok, "Compile time identifiers are only allowed as macro parameters."); + return false; + } sema_error_at(context->prev_tok_end, "Unexpected end of the parameter list, did you forget an ')'?"); return false; } @@ -1098,7 +1112,9 @@ static inline Decl *parse_generics_declaration(Context *context, Visibility visi { rtype = TRY_TYPE_OR(parse_type(context), poisoned_decl); } - Path *path = parse_path_prefix(context); + bool had_error; + Path *path = parse_path_prefix(context, &had_error); + if (had_error) return poisoned_decl; Decl *decl = decl_new(DECL_GENERIC, context->tok, visibility); decl->generic_decl.path = path; if (!consume_ident(context, "generic function name")) return poisoned_decl; @@ -1495,7 +1511,9 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit func->func.function_signature.rtype = return_type; SourceRange start = context->tok.span; - Path *path = parse_path_prefix(context); + bool had_error; + Path *path = parse_path_prefix(context, &had_error); + if (had_error) return poisoned_decl; if (path || context->tok.type == TOKEN_TYPE_IDENT) { // Special case, actually an extension diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index 5d0ad3efd..8d6776002 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -10,7 +10,7 @@ #define TRY_EXPECT_OR(_tok, _message, _type) do { if (context->tok.type != _tok) { SEMA_TOKEN_ERROR(context->tok, _message); return _type; } } while(0) #define TRY_CONSUME_OR(_tok, _message, _type) do { if (!consume(context, _tok, _message)) return _type; } while(0) #define TRY_CONSUME(_tok, _message) TRY_CONSUME_OR(_tok, _message, poisoned_ast) -#define TRY_CONSUME_EOS_OR(_res) TRY_CONSUME_OR(TOKEN_EOS, "Expected ';'", _res) +#define TRY_CONSUME_EOS_OR(_res) do { if (context->tok.type != TOKEN_EOS) { sema_error_at(context->prev_tok_end, "Expected ';'"); return _res; } advance(context); } while(0) #define TRY_CONSUME_EOS() TRY_CONSUME_EOS_OR(poisoned_ast) #define RETURN_AFTER_EOS(_ast) extend_ast_with_prev_token(context, ast); TRY_CONSUME_EOS_OR(poisoned_ast); return _ast #define TRY_CONSUME_LBRACE() TRY_CONSUME(TOKEN_LBRACE, "Expected '{'") @@ -30,7 +30,7 @@ SEMA_TOKEN_ERROR(context->tok, "Expected ',' or ')'"); return _res; } } while(0) Ast *parse_stmt(Context *context); -Path *parse_path_prefix(Context *context); +Path *parse_path_prefix(Context *context, bool *had_error); Expr *parse_type_expression_with_path(Context *context, Path *path); Expr *parse_expr(Context *context); TypeInfo *parse_type(Context *context); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 6cb95c242..bfd6de10a 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -8,6 +8,10 @@ #define EXIT_T_MISMATCH() return sema_type_mismatch(left, canonical, cast_type) #define IS_EXPLICT() #define RETURN_NON_CONST_CAST(kind) do { if (left->expr_kind != EXPR_CONST) { insert_cast(left, kind, canonical); return true; } } while (0) +#define REQUIRE_EXPLICIT_CAST(_cast_type)\ + do { if (_cast_type == CAST_TYPE_EXPLICIT) break;\ + if (_cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;\ + EXIT_T_MISMATCH(); } while (0) static inline void insert_cast(Expr *expr, CastKind kind, Type *canonical) { @@ -71,13 +75,9 @@ bool erro(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ bool ptxi(Expr *left, Type *canonical, Type *type, CastType cast_type) { - if (cast_type != CAST_TYPE_EXPLICIT) - { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - EXIT_T_MISMATCH(); - } - RETURN_NON_CONST_CAST(CAST_PTRXI); + REQUIRE_EXPLICIT_CAST(cast_type); + RETURN_NON_CONST_CAST(CAST_PTRXI); assert(left->const_expr.kind == TYPE_POINTER); expr_const_set_int(&left->const_expr, 0, type->type_kind); left->type = type; @@ -110,16 +110,6 @@ static inline bool may_implicitly_cast_ptr_to_ptr(Type *current_type, Type *targ } -bool ptfu(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - -bool fupt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) -{ - TODO -} - bool stst(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { TODO @@ -206,6 +196,7 @@ void const_int_to_fp_cast(Expr *left, Type *canonical, Type *type) */ bool boxi(Expr *left, Type *canonical, Type *type, CastType cast_type) { + if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); RETURN_NON_CONST_CAST(CAST_BOOLINT); assert(left->const_expr.kind == TYPE_BOOL); @@ -281,8 +272,8 @@ bool fpfp(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ */ bool fpxi(Expr *left, Type *canonical, Type *type, CastType cast_type) { - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); + REQUIRE_EXPLICIT_CAST(cast_type); + RETURN_NON_CONST_CAST(CAST_FPUI); assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_U64); @@ -343,8 +334,7 @@ bool ixxen(Expr *left, Type *canonical, Type *type, CastType cast_type) bool ixxer(Expr *left, Type *canonical, Type *type, CastType cast_type) { // Assigning zero = no value is always ok. - if (cast_type == CAST_TYPE_IMPLICIT) EXIT_T_MISMATCH(); - if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; + REQUIRE_EXPLICIT_CAST(cast_type); if (left->expr_kind == EXPR_CONST) { @@ -459,7 +449,7 @@ bool uisi(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastTyp */ bool siui(Expr *left, Type *canonical, Type *type, CastType cast_type) { - if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); + REQUIRE_EXPLICIT_CAST(cast_type); RETURN_NON_CONST_CAST(CAST_SIUI); @@ -891,7 +881,6 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type) if (type_is_integer(canonical)) return ptxi(expr, canonical, to_type, cast_type); if (canonical->type_kind == TYPE_BOOL) return ptbo(expr, canonical, to_type, cast_type); if (canonical->type_kind == TYPE_POINTER) return ptpt(expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_FUNC) return ptfu(expr, from_type, canonical, to_type, cast_type); if (canonical->type_kind == TYPE_VARARRAY) return ptva(expr, from_type, canonical, to_type, cast_type); if (canonical->type_kind == TYPE_SUBARRAY) return ptsa(expr, from_type, canonical, to_type, cast_type); break; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 004016072..9b48fddc3 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -447,7 +447,8 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib [ATTRIBUTE_NORETURN] = ATTR_FUNC, [ATTRIBUTE_ALIGN] = ATTR_FUNC | ATTR_CONST | ATTR_VAR | ATTR_STRUCT | ATTR_UNION, [ATTRIBUTE_INLINE] = ATTR_FUNC, - [ATTRIBUTE_OPAQUE] = ATTR_STRUCT | ATTR_UNION + [ATTRIBUTE_OPAQUE] = ATTR_STRUCT | ATTR_UNION, + [ATTRIBUTE_STDCALL] = ATTR_FUNC }; if ((attribute_domain[type] & domain) != domain) @@ -457,6 +458,8 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib } switch (type) { + case ATTRIBUTE_STDCALL: + return type; case ATTRIBUTE_ALIGN: if (!attr->expr) { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 5eacc256a..af3dfb4a6 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -11,18 +11,20 @@ * - 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); +static Expr **expr_copy_expr_list_from_macro(Context *context, Expr **expr_list); +static Expr *expr_copy_from_macro(Context *context, Expr *source_expr); +static Ast *ast_copy_from_macro(Context *context, Ast *source); +static Ast **ast_copy_list_from_macro(Context *context, Ast **to_copy); static bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr); +static Decl *decl_copy_local_from_macro(Context *context, Decl *to_copy); +static TypeInfo *type_info_copy_from_macro(Context *context, TypeInfo *source); -#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) +#define MACRO_COPY_EXPR(x) x = expr_copy_from_macro(context, x) +#define MACRO_COPY_TYPE(x) x = type_info_copy_from_macro(context, x) +#define MACRO_COPY_TYPE_LIST(x) x = type_info_copy_list_from_macro(context, x) +#define MACRO_COPY_EXPR_LIST(x) x = expr_copy_expr_list_from_macro(context, x) +#define MACRO_COPY_AST_LIST(x) x = ast_copy_list_from_macro(context, x) +#define MACRO_COPY_AST(x) x = ast_copy_from_macro(context, x) bool sema_analyse_expr_may_be_function(Context *context, Expr *expr); @@ -165,6 +167,15 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e return true; } +static inline Decl *decl_copy_local_from_macro(Context *context, Decl *to_copy) +{ + assert(to_copy->decl_kind == DECL_VAR); + Decl *copy = malloc_arena(sizeof(Decl)); + memcpy(copy, to_copy, sizeof(Decl)); + MACRO_COPY_TYPE(copy->var.type_info); + MACRO_COPY_EXPR(copy->var.init_expr); + return copy; +} static inline bool sema_expr_analyse_enum_constant(Expr *expr, const char *name, Decl *decl) { @@ -255,7 +266,7 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr } if (decl->decl_kind == DECL_MACRO) { - if (!context->in_macro_call) + if (!expr->identifier_expr.is_macro) { SEMA_ERROR(expr, "Macro expansions must be prefixed with '@', try using '@%s(...)' instead.", decl->name); return false; @@ -264,6 +275,17 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr expr->type = type_void; return true; } + if (expr->identifier_expr.is_macro) + { + SEMA_ERROR(expr, "Only macro expansions can be prefixed with '@', please try to remove it.", decl->name); + } + if (decl->decl_kind == DECL_VAR && decl->var.constant) + { + assert(decl->var.init_expr && decl->var.init_expr->resolve_status == RESOLVE_DONE); + // Todo, maybe make a copy? + expr_replace(expr, decl->var.init_expr); + return true; + } assert(decl->type); expr->identifier_expr.decl = decl; expr->type = decl->type; @@ -472,6 +494,109 @@ static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr return sema_expr_analyse_func_invocation(context, &decl->func.function_signature, expr, decl, to, struct_var); } +static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_expr, Decl *decl) +{ + if (context->macro_nesting >= MAX_MACRO_NESTING) + { + SEMA_ERROR(call_expr, "Too deep nesting (more than %d levels) when evaluating this macro.", MAX_MACRO_NESTING); + return false; + } + + Expr **args = call_expr->call_expr.arguments; + Decl **func_params = decl->macro_decl.parameters; + + unsigned num_args = vec_size(args); + for (unsigned i = 0; i < num_args; i++) + { + Expr *arg = args[i]; + Decl *param = func_params[i]; + if (!sema_analyse_expr(context, param->type, arg)) + { + return false; + } + if (param->var.type_info) + { + if (!sema_resolve_type_info(context, param->var.type_info)) + { + return false; + } + param->type = param->var.type_info->type; + } + else + { + param->type = arg->type; + } + } + + context->macro_nesting++; + context->macro_counter++; + Decl **old_macro_locals_start = context->macro_locals_start; + context->macro_locals_start = context->last_local; + + bool ok = true; + + Ast *body = ast_copy_from_macro(context, decl->macro_decl.body); + + call_expr->type = type_void; + + Ast **saved_returns = context_push_returns(context); + context->expected_block_type = to; + context_push_scope_with_flags(context, SCOPE_MACRO); + + for (unsigned i = 0; i < num_args; i++) + { + Decl *param = func_params[i]; + if (args[i]->expr_kind == EXPR_CONST) + { + param = decl_copy_local_from_macro(context, param); + param->var.constant = true; + param->var.init_expr = args[i]; + args[i] = NULL; + } + sema_add_local(context, param); + } + + VECEACH(body->compound_stmt.stmts, i) + { + if (!sema_analyse_statement(context, body->compound_stmt.stmts[i])) + { + ok = false; + goto EXIT; + } + } + + if (!vec_size(context->returns)) + { + if (to) + { + SEMA_ERROR(decl, "Missing return in macro that evaluates to %s.", type_to_error_string(to)); + ok = false; + goto EXIT; + } + } + + Expr *first_return_expr = context->returns[0]->return_stmt.expr; + Type *left_canonical = first_return_expr ? first_return_expr->type->canonical : type_void; + // Let's unify the return statements. + left_canonical = unify_returns(context, left_canonical); + if (!left_canonical) + { + ok = false; + goto EXIT; + } + call_expr->type = left_canonical; + call_expr->expr_kind = EXPR_MACRO_BLOCK; + call_expr->macro_block.stmts = body->compound_stmt.stmts; + call_expr->macro_block.params = func_params; + call_expr->macro_block.args = args; + EXIT: + context_pop_scope(context); + context_pop_returns(context, saved_returns); + context->macro_nesting--; + context->macro_locals_start = old_macro_locals_start; + return ok; +} + static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr) { Expr *func_expr = expr->call_expr.function; @@ -509,8 +634,7 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr case DECL_FUNC: return sema_expr_analyse_func_call(context, to, expr, decl, struct_var); case DECL_MACRO: - SEMA_ERROR(expr, "Macro calls must be preceeded by '@'."); - return false; + return sema_expr_analyse_macro_call(context, to, expr, decl); case DECL_GENERIC: return sema_expr_analyse_generic_call(context, to, expr); case DECL_POISONED: @@ -2611,7 +2735,7 @@ static Expr *expr_shallow_copy(Expr *source) -static TypeInfo *type_info_copy_from_macro(Context *context, Expr *macro, TypeInfo *source) +static TypeInfo *type_info_copy_from_macro(Context *context, TypeInfo *source) { if (!source) return NULL; TypeInfo *copy = malloc_arena(sizeof(TypeInfo)); @@ -2621,50 +2745,50 @@ static TypeInfo *type_info_copy_from_macro(Context *context, Expr *macro, TypeIn case TYPE_INFO_POISON: return copy; case TYPE_INFO_IDENTIFIER: - assert(source->resolve_status == RESOLVE_NOT_DONE); - TODO - break; + return copy; case TYPE_INFO_EXPRESSION: assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->unresolved_type_expr = expr_copy_from_macro(context, macro, source->unresolved_type_expr); + copy->unresolved_type_expr = expr_copy_from_macro(context, source->unresolved_type_expr); return copy; case TYPE_INFO_ARRAY: assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->array.len = expr_copy_from_macro(context, macro, source->array.len); - copy->array.base = type_info_copy_from_macro(context, macro, source->array.base); + copy->array.len = expr_copy_from_macro(context, source->array.len); + copy->array.base = type_info_copy_from_macro(context, source->array.base); return copy; case TYPE_INFO_INC_ARRAY: case TYPE_INFO_VARARRAY: case TYPE_INFO_SUBARRAY: assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->array.base = type_info_copy_from_macro(context, macro, source->array.base); + copy->array.base = type_info_copy_from_macro(context, source->array.base); return copy; case TYPE_INFO_POINTER: assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->pointer = type_info_copy_from_macro(context, macro, source->pointer); + copy->pointer = type_info_copy_from_macro(context, source->pointer); return copy; } UNREACHABLE } -static Ast** ast_copy_list_from_macro(Context *context, Expr *macro, Ast **to_copy) +static Ast** ast_copy_list_from_macro(Context *context, Ast **to_copy) { Ast **result = NULL; VECEACH(to_copy, i) { - vec_add(result, ast_copy_from_macro(context, macro, to_copy[i])); + vec_add(result, ast_copy_from_macro(context, to_copy[i])); } return result; } -static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_expr) +static Expr *expr_copy_from_macro(Context *context, Expr *source_expr) { if (!source_expr) return NULL; Expr *expr = expr_shallow_copy(source_expr); switch (source_expr->expr_kind) { + case EXPR_MACRO_BLOCK: + UNREACHABLE case EXPR_TYPEOF: MACRO_COPY_EXPR(expr->typeof_expr); return expr; @@ -2709,8 +2833,8 @@ static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_ex MACRO_COPY_TYPE(expr->typeid_expr); return expr; case EXPR_IDENTIFIER: - TODO - break; + // TODO + return expr; case EXPR_TYPE_ACCESS: MACRO_COPY_TYPE(expr->type_access.type); return expr; @@ -2741,35 +2865,32 @@ static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_ex case EXPR_SCOPED_EXPR: MACRO_COPY_EXPR(expr->expr_scope.expr); return expr; - case EXPR_MACRO_EXPR: - MACRO_COPY_EXPR(expr->macro_expr); - return expr; } UNREACHABLE } -static Expr **expr_copy_expr_list_from_macro(Context *context, Expr *macro, Expr **expr_list) +static Expr **expr_copy_expr_list_from_macro(Context *context, Expr **expr_list) { Expr **result = NULL; VECEACH(expr_list, i) { - vec_add(result, expr_copy_from_macro(context, macro, expr_list[i])); + vec_add(result, expr_copy_from_macro(context, expr_list[i])); } return result; } -static TypeInfo** type_info_copy_list_from_macro(Context *context, Expr *macro, TypeInfo **to_copy) +static TypeInfo** type_info_copy_list_from_macro(Context *context, TypeInfo **to_copy) { TypeInfo **result = NULL; VECEACH(to_copy, i) { - vec_add(result, type_info_copy_from_macro(context, macro, to_copy[i])); + vec_add(result, type_info_copy_from_macro(context, to_copy[i])); } return result; } -static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source) +static Ast *ast_copy_from_macro(Context *context, Ast *source) { Ast *ast = ast_shallow_copy(source); switch (source->ast_kind) @@ -2822,7 +2943,7 @@ static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source) MACRO_COPY_TYPE_LIST(ast->ct_case_stmt.types); return ast; case AST_DECLARE_STMT: - TODO + ast->declare_stmt = decl_copy_local_from_macro(context, ast->declare_stmt); return ast; case AST_DEFAULT_STMT: MACRO_COPY_AST(ast->case_stmt.body); @@ -2905,89 +3026,6 @@ static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source) UNREACHABLE; } -static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *macro, Expr *inner) -{ - if (context->macro_nesting > MAX_MACRO_NESTING) - { - SEMA_ERROR(context->first_macro_call, "Too deep nesting (more than %d levels) when evaluating this macro.", MAX_MACRO_NESTING); - return false; - } - - Expr *func_expr = inner->call_expr.function; - bool was_in_macro_call = context->in_macro_call; - context->in_macro_call = true; - bool ok = sema_analyse_expr(context, NULL, inner->call_expr.function); - context->in_macro_call = was_in_macro_call; - if (!ok) return ok; - - Decl *decl; - switch (inner->call_expr.function->expr_kind) - { - case EXPR_IDENTIFIER: - decl = func_expr->identifier_expr.decl; - break; - default: - SEMA_ERROR(inner, "Expected a macro identifier here"); - return false; - } - if (decl->decl_kind != DECL_MACRO) - { - SEMA_ERROR(macro, "A macro was expected here."); - return false; - } - Expr **args =func_expr->call_expr.arguments; - Decl **func_params = decl->macro_decl.parameters; - - unsigned num_args = vec_size(args); - for (unsigned i = 0; i < num_args; i++) - { - Expr *arg = args[i]; - Decl *param = func_params[i]; - if (!sema_analyse_expr(context, param->type, arg)) return false; - } - - Ast *body = ast_copy_from_macro(context, inner, decl->macro_decl.body); - - ok = true; - macro->type = type_void; - - Ast **saved_returns = context_push_returns(context); - context->expected_block_type = to; - context_push_scope_with_flags(context, SCOPE_EXPR_BLOCK); - VECEACH(body->compound_stmt.stmts, i) - { - if (!sema_analyse_statement(context, body->compound_stmt.stmts[i])) - { - ok = false; - goto EXIT; - } - } - - if (!vec_size(context->returns)) - { - if (to) - { - SEMA_ERROR(decl, "Missing return in macro that evaluates to %s.", type_to_error_string(to)); - ok = false; - } - goto EXIT; - } - - Expr *first_return_expr = context->returns[0]->return_stmt.expr; - Type *left_canonical = first_return_expr ? first_return_expr->type->canonical : type_void; - // Let's unify the return statements. - left_canonical = unify_returns(context, left_canonical); - if (!left_canonical) - { - ok = false; - goto EXIT; - } - macro->type = left_canonical; - EXIT: - context_pop_scope(context); - context_pop_returns(context, saved_returns); - return ok; -} static inline bool sema_expr_analyse_macro_call2(Context *context, Type *to, Expr *expr, Decl *macro) { @@ -3007,9 +3045,11 @@ static inline bool sema_expr_analyse_macro_call2(Context *context, Type *to, Exp return success; } -static inline bool sema_expr_analyse_macro_expr(Context *context, Type *to, Expr *expr) +static inline bool sema_expr_analyse_macro_ident(Context *context, Type *to, Expr *expr) { - Expr *inner = expr->macro_expr; + return false; + /* + Expr *inner = expr->macro_ident; switch (inner->expr_kind) { case EXPR_CALL: @@ -3020,7 +3060,7 @@ static inline bool sema_expr_analyse_macro_expr(Context *context, Type *to, Expr default: SEMA_ERROR(expr, "Expected a macro name after '@'"); return false; - } + }*/ } static inline bool sema_expr_analyse_type(Context *context, Type *to, Expr *expr) @@ -3112,6 +3152,7 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr * case EXPR_DESIGNATED_INITIALIZER: // Created during semantic analysis UNREACHABLE + case EXPR_MACRO_BLOCK: case EXPR_SCOPED_EXPR: UNREACHABLE case EXPR_TYPEOF: @@ -3120,8 +3161,6 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr * return sema_expr_analyse_compound_literal(context, to, expr); case EXPR_EXPR_BLOCK: return sema_expr_analyse_expr_block(context, to, expr); - case EXPR_MACRO_EXPR: - return sema_expr_analyse_macro_expr(context, to, expr); case EXPR_TRY: return sema_expr_analyse_try(context, to, expr); case EXPR_RANGE: diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index fd2533ad2..f9871ce1f 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -75,6 +75,7 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl if (context->current_scope) { Decl **first = &context->locals[0]; + if (context->macro_nesting) first = context->macro_locals_start; Decl **current = context->last_local - 1; while (current >= first) { @@ -141,4 +142,15 @@ bool sema_add_local(Context *context, Decl *decl) return true; } +bool sema_add_macro_local(Context *context, Decl *decl) +{ + if (context->last_local == &context->locals[MAX_LOCALS - 1]) + { + SEMA_ERROR(decl, "Reached the maximum number of locals."); + return false; + } + context->last_local[0] = decl; + context->last_local++; + return true; +} diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 68266c3ac..62c27e073 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -28,6 +28,10 @@ void context_push_scope_with_flags(Context *context, ScopeFlags flags) { context->current_scope->flags = previous_flags | flags; } + if (previous_flags & SCOPE_MACRO) + { + context->current_scope->flags = previous_flags | SCOPE_MACRO; + } context->current_scope->flags_created = flags; } diff --git a/src/compiler/types.c b/src/compiler/types.c index 93eac5bf0..69a729db2 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -194,6 +194,7 @@ static void type_append_signature_name_user_defined(Decl *decl, char *dst, size_ } void type_append_signature_name(Type *type, char *dst, size_t *offset) { + type = type->canonical; assert(*offset < MAX_FUNCTION_SIGNATURE_SIZE); const char *name; switch (type->type_kind) diff --git a/src/utils/lib.h b/src/utils/lib.h index eadad2522..defecf7b0 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -112,8 +112,8 @@ static inline bool is_digit(char c) static inline int char_to_nibble(char c) { if (c >= '0' && c <= '9') return c - '0'; - if (c <= 'F') return c - 'A'; - if (c <= 'f') return c - 'f'; + if (c <= 'F') return c - 'A' + 10; + if (c <= 'f') return c - 'a' + 10; return -1; }