Fixes bug handling chained && ||. Work towards more macro functionality. Correctly emit stdcall. Corrected character parsing in escaped string entries.

This commit is contained in:
Christoffer Lerno
2020-06-11 15:45:58 +02:00
parent f96ab76195
commit 50c36789bf
23 changed files with 517 additions and 206 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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)
{

View File

@@ -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. */

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -1,6 +1,6 @@
module bar;
import baz::foo;
import baz.foo;
import testbaz;
public func void test()

View File

@@ -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);

View File

@@ -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];

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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 },

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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;
}