Remove old try/catch. Remove incorrect flattening. Basic asm. Start work on if-catch-switch.

This commit is contained in:
Christoffer Lerno
2021-08-24 12:41:20 +02:00
parent f7803fd192
commit 1751e7ece5
17 changed files with 160 additions and 508 deletions

View File

@@ -1191,11 +1191,6 @@ static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int ind
DUMPEXPR(ast->assert_stmt.expr);
DUMPEXPR(ast->assert_stmt.message);
DUMPEND();
case AST_TRY_STMT:
DUMP("(try");
DUMPEXPR(ast->try_old_stmt.decl_expr);
DUMPAST(ast->try_old_stmt.body);
DUMPEND();
case AST_COMPOUND_STMT:
if (!ast->compound_stmt.stmts)
{
@@ -1312,6 +1307,11 @@ static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int ind
DUMPEXPR(ast->switch_stmt.cond);
DUMPASTS(ast->switch_stmt.cases);
DUMPEND();
case AST_IF_CATCH_SWITCH_STMT:
DUMP("(if-catch-switch");
DUMPEXPR(ast->switch_stmt.cond);
DUMPASTS(ast->switch_stmt.cases);
DUMPEND();
case AST_CASE_STMT:
DUMP("(case");
if (ast->case_stmt.is_type)
@@ -1335,11 +1335,6 @@ static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int ind
DUMP("(asm");
// TODO
DUMPEND();
case AST_CATCH_STMT:
DUMP("(catch");
DUMPEXPR(ast->catch_stmt.catchable);
DUMPAST(ast->catch_stmt.body);
DUMPEND();
case AST_CT_IF_STMT:
DUMP("(ct-if");
DUMPEXPR(ast->ct_if_stmt.expr);

View File

@@ -1124,25 +1124,6 @@ typedef struct
} codegen;
} AstDeferStmt;
typedef struct
{
FlowCommon flow;
bool is_switch : 1;
bool has_err_var : 1;
Ast* scope_defer;
AstId defer;
union
{
Expr *catchable;
Decl *err_var;
};
union
{
Ast *body;
Ast **cases;
};
void *block;
} AstCatchStmt;
typedef struct AstCtIfStmt_
@@ -1216,12 +1197,6 @@ typedef struct
TokenId constraints;
} AsmOperand;
typedef struct
{
Expr *decl_expr;
Ast *body;
} AstTryStmt;
typedef struct
{
AsmOperand *inputs;
@@ -1236,7 +1211,7 @@ typedef struct
bool is_inline : 1;
bool is_goto : 1;
AsmParams *params;
TokenId **instructions;
Expr *body;
} AstAsmStmt;
typedef struct
@@ -1286,7 +1261,6 @@ typedef struct Ast_
Ast** ct_compound_stmt;
Decl *declare_stmt; // 8
Expr *expr_stmt; // 8
AstTryStmt try_old_stmt;
Ast *try_stmt;
Decl *define_stmt; // 8
Ast *volatile_stmt; // 8
@@ -1300,7 +1274,6 @@ typedef struct Ast_
AstCtSwitchStmt ct_switch_stmt; // 16
AstContinueBreakStmt contbreak_stmt; // 8
AstNextStmt next_stmt; // 16
AstCatchStmt catch_stmt; // 32
AstForStmt for_stmt; // 32
AstForeachStmt foreach_stmt;
AstCtIfStmt ct_if_stmt; // 24
@@ -2258,10 +2231,6 @@ static inline Type *type_flatten(Type *type)
type = type->decl->enums.type_info->type;
continue;
}
if (type->type_kind == TYPE_ANYERR || type->type_kind == TYPE_ERRTYPE)
{
type = type_iptr->canonical;
}
return type;
}
}
@@ -2314,6 +2283,7 @@ static inline Type *type_lowering(Type *type)
Type *canonical = type_flatten(type);
if (canonical->type_kind == TYPE_ENUM) return canonical->decl->enums.type_info->type->canonical;
if (canonical->type_kind == TYPE_TYPEID) return type_iptr->canonical;
if (canonical->type_kind == TYPE_ANYERR) return type_iptr->canonical;
if (canonical->type_kind == TYPE_ERRTYPE) return type_iptr->canonical;
if (canonical->type_kind == TYPE_BITSTRUCT) return type_lowering(canonical->decl->bitstruct.base_type->type);
return canonical;

View File

@@ -272,25 +272,6 @@ Ast *copy_ast(Ast *source)
MACRO_COPY_EXPR(ast->case_stmt.expr);
}
return ast;
case AST_CATCH_STMT:
copy_flow(ast);
if (ast->catch_stmt.has_err_var)
{
MACRO_COPY_DECL(ast->catch_stmt.err_var);
}
else
{
MACRO_COPY_EXPR(ast->catch_stmt.catchable);
}
if (ast->catch_stmt.is_switch)
{
MACRO_COPY_AST_LIST(ast->catch_stmt.cases);
}
else
{
MACRO_COPY_AST(ast->catch_stmt.body);
}
return ast;
case AST_COMPOUND_STMT:
MACRO_COPY_AST_LIST(ast->compound_stmt.stmts);
return ast;
@@ -377,14 +358,11 @@ Ast *copy_ast(Ast *source)
MACRO_COPY_AST(ast->scoped_stmt.stmt);
return ast;
case AST_SWITCH_STMT:
case AST_IF_CATCH_SWITCH_STMT:
copy_flow(ast);
MACRO_COPY_EXPR(ast->switch_stmt.cond);
MACRO_COPY_AST_LIST(ast->switch_stmt.cases);
return ast;
case AST_TRY_STMT:
MACRO_COPY_EXPR(ast->try_old_stmt.decl_expr);
MACRO_COPY_AST(ast->try_old_stmt.body);
return ast;
case AST_UNREACHABLE_STMT:
return ast;
case AST_VOLATILE_STMT:

View File

@@ -48,7 +48,6 @@ typedef enum
AST_ASSERT_STMT,
AST_BREAK_STMT,
AST_CASE_STMT,
AST_CATCH_STMT,
AST_COMPOUND_STMT,
AST_CONTINUE_STMT,
AST_DEFINE_STMT,
@@ -66,9 +65,9 @@ typedef enum
AST_DOC_DIRECTIVE,
AST_DOCS,
AST_EXPR_STMT,
AST_TRY_STMT,
AST_FOR_STMT,
AST_FOREACH_STMT,
AST_IF_CATCH_SWITCH_STMT,
AST_IF_STMT,
AST_NOP_STMT,
AST_RETURN_STMT,
@@ -421,7 +420,6 @@ typedef enum
TOKEN_BITSTRUCT,
TOKEN_BREAK,
TOKEN_CASE,
TOKEN_CATCH_OLD,
TOKEN_CATCH,
TOKEN_CONST,
TOKEN_CONTINUE,
@@ -451,7 +449,6 @@ typedef enum
TOKEN_STRUCT,
TOKEN_SWITCH,
TOKEN_TRUE,
TOKEN_TRY_OLD,
TOKEN_TRY,
TOKEN_UNION,
TOKEN_VAR, // Reserved

View File

@@ -777,7 +777,7 @@ void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value)
void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type)
{
type = type_flatten(type);
type = type_lowering(type);
assert(llvm_value || type == type_void);
value->value = llvm_value;
value->alignment = type_abi_alignment(type);
@@ -795,7 +795,7 @@ void llvm_value_set_address_align(BEValue *value, LLVMValueRef llvm_value, Type
value->value = llvm_value;
value->alignment = alignment;
value->kind = BE_ADDRESS;
value->type = type_flatten(type);
value->type = type_lowering(type);
}
void llvm_value_set_decl_address(BEValue *value, Decl *decl)
{
@@ -812,7 +812,7 @@ void llvm_value_set_decl_address(BEValue *value, Decl *decl)
void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type)
{
llvm_value_set_address_align(value, llvm_value, type_flatten(type), type_abi_alignment(type));
llvm_value_set_address_align(value, llvm_value, type_lowering(type), type_abi_alignment(type));
}
void llvm_value_fold_failable(GenContext *c, BEValue *value)

View File

@@ -539,7 +539,7 @@ AbiType *x64_get_sse_type_at_offset(Type *type, unsigned ir_offset, Type *source
*/
AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_type, unsigned source_offset)
{
type = type_flatten(type);
type = type_lowering(type);
switch (type->type_kind)
{
case TYPE_U64:

View File

@@ -373,13 +373,10 @@ static LLVMMetadataRef llvm_debug_subarray_type(GenContext *c, Type *type)
static LLVMMetadataRef llvm_debug_errunion_type(GenContext *c, Type *type)
{
LLVMMetadataRef forward = llvm_debug_forward_comp(c, type, type->name, NULL, NULL, LLVMDIFlagZero);
type->backend_debug_type = forward;
LLVMMetadataRef elements[2] = {
llvm_get_debug_member(c, type_usize, "domain", 0, NULL, forward, LLVMDIFlagZero),
llvm_get_debug_member(c, type_usize, "err", 0, NULL, forward, LLVMDIFlagZero)
};
return llvm_get_debug_struct(c, type, type->name, elements, 2, NULL, NULL, LLVMDIFlagZero);
return LLVMDIBuilderCreateTypedef(c->debug.builder,
llvm_get_debug_type(c, type_iptr->canonical),
type->name, strlen(type->name),
NULL, 0, NULL, 0);
}
static LLVMMetadataRef llvm_debug_array_type(GenContext *c, Type *type)
@@ -537,7 +534,6 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *
case TYPE_SUBARRAY:
return type->backend_debug_type = llvm_debug_subarray_type(c, type);
case TYPE_ANYERR:
// TODO
return type->backend_debug_type = llvm_debug_errunion_type(c, type);
case TYPE_VIRTUAL:
case TYPE_VIRTUAL_ANY:

View File

@@ -338,7 +338,7 @@ static void llvm_emit_array_bounds_check(GenContext *c, BEValue *index, LLVMValu
static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, BEValue *parent, BEValue *index, SourceLocation *loc)
{
assert(llvm_value_is_addr(parent));
Type *type = type_flatten(parent->type);
Type *type = type_lowering(parent->type);
switch (type->type_kind)
{
case TYPE_POINTER:
@@ -450,7 +450,7 @@ static inline void gencontext_emit_access_addr(GenContext *context, BEValue *be_
llvm_emit_expr(context, be_value, parent);
Decl *member = expr->access_expr.ref;
gencontext_emit_member_addr(context, be_value, type_flatten(parent->type)->decl, member);
gencontext_emit_member_addr(context, be_value, type_lowering(parent->type)->decl, member);
}
static void gencontext_emit_scoped_expr(GenContext *context, BEValue *value, Expr *expr)
@@ -500,16 +500,39 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
switch (cast_kind)
{
case CAST_ERBOOL:
case CAST_EUINT:
case CAST_ERINT:
to_type = type_lowering(to_type);
from_type = type_lowering(from_type);
llvm_value_rvalue(c, value);
if (type_convert_will_trunc(to_type, from_type))
{
value->value = LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "errinttrunc");
}
else
{
value->value = type_is_signed(to_type)
? LLVMBuildSExt(c->builder, value->value, llvm_get_type(c, to_type), "errsiext")
: LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "erruiext");
}
break;
case CAST_VRBOOL:
case CAST_VRPTR:
case CAST_PTRVR:
TODO
case CAST_XIERR:
// TODO Insert zero check.
to_type = type_lowering(to_type);
from_type = type_lowering(from_type);
llvm_value_rvalue(c, value);
if (type_convert_will_trunc(to_type, from_type))
{
value->value = LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "interrtrunc");
}
else
{
value->value = LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "erruiext");
}
break;
case CAST_ERROR:
UNREACHABLE
@@ -555,23 +578,14 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
case CAST_ARRPTR:
TODO
case CAST_EREU:
// This is a no op.
assert(type_lowering(to_type) == type_lowering(from_type));
break;
case CAST_EUER:
TODO // gencontext_emit_value_bitcast(c, value->value, to_type, from_type);
case CAST_ERBOOL:
case CAST_EUBOOL:
if (value->kind == BE_VALUE)
{
value->value = LLVMBuildExtractValue(c->builder, value->value, 0, "");
}
else
{
value->value = LLVMBuildStructGEP2(c->builder, llvm_get_type(c, type_anyerr), value->value, 0, "");
value->value = llvm_emit_load_aligned(c,
llvm_get_type(c, type_usize),
value->value,
type_abi_alignment(type_usize),
"");
}
value->value = LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, type_usize), "eubool");
value->value = llvm_emit_int_comparison(c, type_anyerr, type_anyerr, llvm_value_rvalue_store(c, value), llvm_get_zero(c, type_anyerr), BINARYOP_NE);
value->kind = BE_BOOLEAN;
break;
case CAST_PTRBOOL:
@@ -874,7 +888,7 @@ static inline void llvm_emit_initialize_reference_const(GenContext *c, BEValue *
static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *ref, Expr *expr)
{
// Getting ready to initialize, get the real type.
Type *real_type = type_flatten(ref->type);
Type *real_type = type_lowering(ref->type);
Expr **elements = expr->initializer_expr.initializer_expr;
// Make sure we have an address.
@@ -1029,7 +1043,7 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_
static inline void llvm_emit_initialize_reference_designated(GenContext *c, BEValue *ref, Expr *expr)
{
// Getting ready to initialize, get the real type.
Type *real_type = type_flatten(ref->type);
Type *real_type = type_lowering(ref->type);
Expr **elements = expr->initializer_expr.initializer_expr;
assert(vec_size(elements));
@@ -1245,7 +1259,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
llvm_value_addr(c, value);
// Transform to value
value->kind = BE_VALUE;
value->type = type_flatten(expr->type);
value->type = type_lowering(expr->type);
return;
case UNARYOP_DEREF:
llvm_emit_expr(c, value, expr->unary_expr.expr);
@@ -1253,7 +1267,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
llvm_value_rvalue(c, value);
// Convert pointer to address
value->kind = BE_ADDRESS;
value->type = type_flatten(expr->type);
value->type = type_lowering(expr->type);
return;
case UNARYOP_INC:
llvm_emit_pre_inc_dec(c, value, expr->unary_expr.expr, 1, false);
@@ -2573,7 +2587,7 @@ static void gencontext_expand_struct_to_args(GenContext *context, Type *param_ty
static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values)
{
REDO:
switch (type_flatten(param_type)->type_kind)
switch (type_lowering(param_type)->type_kind)
{
case TYPE_POISONED:
case TYPE_VOID:

View File

@@ -4,8 +4,6 @@
#include "llvm_codegen_internal.h"
void gencontext_emit_try_stmt(GenContext *context, Ast *pAst);
static bool ast_is_not_empty(Ast *ast)
{
@@ -94,7 +92,7 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
}
else
{
Type *type = type_flatten(decl->type);
Type *type = type_lowering(decl->type);
// Normal case, zero init.
if (type_is_builtin(type->type_kind) || type->type_kind == TYPE_POINTER)
{
@@ -144,7 +142,7 @@ void gencontext_emit_decl_expr_list(GenContext *context, BEValue *be_value, Expr
}
if (bool_cast)
{
type = type_flatten(type);
type = type_lowering(type);
if (type->type_kind != TYPE_BOOL)
{
CastKind cast = cast_to_bool_kind(type);
@@ -471,7 +469,7 @@ static void llvm_emit_foreach_stmt(GenContext *c, Ast *ast)
LLVMTypeRef actual_type_llvm = llvm_get_type(c, actual_type);
llvm_emit_local_var_alloca(c, ast->foreach_stmt.variable);
Type *var_type = type_flatten(ast->foreach_stmt.variable->type);
Type *var_type = type_lowering(ast->foreach_stmt.variable->type);
LLVMTypeRef var_type_llvm = llvm_get_type(c, var_type);
BEValue var;
llvm_value_set_address(&var, ast->foreach_stmt.variable->backend_ref, var_type);
@@ -955,52 +953,6 @@ void gencontext_emit_scoped_stmt(GenContext *context, Ast *ast)
llvm_emit_defer(context, ast->scoped_stmt.defers.start, ast->scoped_stmt.defers.end);
}
void gencontext_emit_try_stmt(GenContext *c, Ast *ast)
{
// Create after try block
LLVMBasicBlockRef after_try = llvm_basic_block_new(c, "after_try");
EMIT_LOC(c, ast);
// Store catch/error var
PUSH_ERROR();
// Set the catch/error var
c->error_var = NULL;
c->catch_block = after_try;
// Emit the checks, which will create jumps like we want them.
TODO
Ast **decl_expr = NULL; // ast->try_old_stmt.decl_expr->dexpr_list_expr;
BEValue be_value;
VECEACH(decl_expr, i)
{
Ast *dexpr = decl_expr[i];
switch (dexpr->ast_kind)
{
case AST_EXPR_STMT:
llvm_emit_expr(c, &be_value, dexpr->expr_stmt);
llvm_value_rvalue(c, &be_value);
break;
case AST_DECLARE_STMT:
//TODO llvm_emit_local_decl(c, dexpr);
break;
default:
UNREACHABLE
}
}
// Restore.
POP_ERROR();
// Emit the statement
llvm_emit_stmt(c, ast->try_old_stmt.body);
// Jump to after.
llvm_emit_br(c, after_try);
llvm_emit_block(c, after_try);
}
static inline void llvm_emit_assume(GenContext *c, Expr *expr)
{
@@ -1077,6 +1029,41 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast)
llvm_emit_assume(c, ast->assert_stmt.expr);
}
static inline void add_target_clobbers_to_buffer(GenContext *c)
{
switch (platform_target.arch)
{
case ARCH_TYPE_X86_64:
case ARCH_TYPE_X86:
scratch_buffer_append("~{dirflag},~{fpsr},~{flags}");
break;
case ARCH_TYPE_MIPS:
case ARCH_TYPE_MIPS64:
case ARCH_TYPE_MIPS64EL:
case ARCH_TYPE_MIPSEL:
// Currently Clang does this
scratch_buffer_append("~{$1}");
break;
default:
// In Clang no other platform has automatic clobbers
break;
}
}
static inline void llvm_emit_asm_stmt(GenContext *c, Ast *ast)
{
LLVMTypeRef asm_fn_type = LLVMFunctionType(llvm_get_type(c, type_void), NULL, 0, 0);
scratch_buffer_clear();
add_target_clobbers_to_buffer(c);
LLVMValueRef asm_fn = LLVMGetInlineAsm(asm_fn_type,
(char *)ast->asm_stmt.body->const_expr.string.chars,
ast->asm_stmt.body->const_expr.string.len,
scratch_buffer_to_string(), global_context.scratch_buffer_len,
ast->asm_stmt.is_volatile,
true,
LLVMInlineAsmDialectIntel);
LLVMBuildCall2(c->builder, asm_fn_type, asm_fn, NULL, 0, "");
}
static inline void gencontext_emit_unreachable_stmt(GenContext *context, Ast *ast)
{
SourceLocation *loc = TOKLOC(ast->span.loc);
@@ -1110,67 +1097,6 @@ void gencontext_emit_expr_stmt(GenContext *c, Ast *ast)
llvm_value_rvalue(c, &value);
}
void gencontext_emit_catch_stmt(GenContext *c, Ast *ast)
{
Expr *catch_expr;
LLVMValueRef error_result = NULL;
if (ast->catch_stmt.has_err_var)
{
Decl *error_var = ast->catch_stmt.err_var;
assert(error_var->type->canonical == type_anyerr);
error_result = llvm_emit_alloca_aligned(c, type_anyerr, error_var->name);
error_var->backend_ref = error_result;
catch_expr = error_var->var.init_expr;
}
else
{
if (ast->catch_stmt.is_switch)
{
error_result = llvm_emit_alloca_aligned(c, type_anyerr, "catchval");
}
catch_expr = ast->catch_stmt.catchable;
}
// Create catch block.
LLVMBasicBlockRef catch_block = llvm_basic_block_new(c, "catch");
// Store catch/error var
PUSH_ERROR();
// Set the catch/error var
c->error_var = error_result;
c->catch_block = catch_block;
// Emit the catch, which will create jumps like we want them.
BEValue value;
llvm_emit_expr(c, &value, catch_expr);
llvm_value_fold_failable(c, &value);
// Restore.
POP_ERROR();
// Create the bloch after and jump to it.
LLVMBasicBlockRef after_catch = llvm_basic_block_new(c, "after_catch");
llvm_emit_br(c, after_catch);
// Emit catch.
llvm_emit_block(c, catch_block);
if (ast->catch_stmt.is_switch)
{
LLVMValueRef ref = llvm_emit_bitcast(c, error_result, type_get_ptr(type_typeid));
gencontext_emit_if_switch_body(c, gencontext_emit_load(c, type_typeid, ref), ast->catch_stmt.cases);
}
else
{
llvm_emit_stmt(c, ast->catch_stmt.body);
}
// Jump to after.
llvm_emit_br(c, after_catch);
llvm_emit_block(c, after_catch);
}
static LLVMValueRef llvm_emit_string(GenContext *c, const char *str)
{
LLVMTypeRef char_type = llvm_get_type(c, type_char);
@@ -1327,10 +1253,8 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
case AST_DOC_DIRECTIVE:
case AST_POISONED:
case AST_DEFINE_STMT:
case AST_IF_CATCH_SWITCH_STMT:
UNREACHABLE
case AST_TRY_STMT:
gencontext_emit_try_stmt(c, ast);
break;
case AST_SCOPED_STMT:
gencontext_emit_scoped_stmt(c, ast);
break;
@@ -1376,11 +1300,9 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
case AST_DEFER_STMT:
case AST_NOP_STMT:
break;
case AST_CATCH_STMT:
gencontext_emit_catch_stmt(c, ast);
break;
case AST_ASM_STMT:
TODO
llvm_emit_asm_stmt(c, ast);
break;
case AST_ASSERT_STMT:
llvm_emit_assert_stmt(c, ast);
break;;

View File

@@ -314,7 +314,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
case TYPE_TYPEID:
case TYPE_ANYERR:
case TYPE_ERRTYPE:
return any_type->backend_type = llvm_get_type(c, type_iptr);
return any_type->backend_type = llvm_get_type(c, type_iptr->canonical);
case TYPE_TYPEDEF:
return any_type->backend_type = llvm_get_type(c, any_type->canonical);
case TYPE_DISTINCT:

View File

@@ -137,46 +137,22 @@ static inline bool parse_asm_params(Context *context, Ast *asm_ast)
TODO
}
/**
* asm { ... }
* asm ::= 'asm' '(' string ')'
* @param context
* @return
*/
static inline Ast* parse_asm_stmt(Context *context)
{
TODO
/*
Ast *ast = AST_NEW_TOKEN(AST_ASM_STMT, context->tok);
advance_and_verify(context, TOKEN_ASM);
if (try_consume(context, TOKEN_LPAREN))
{
if (!parse_asm_params(context, ast)) return poisoned_ast;
}
if (!TOKEN_IS(TOKEN_LBRACE))
{
SEMA_TOKEN_ERROR(context->tok, "Expected '{' to start asm segment.");
return poisoned_ast;
}
context->lexer.current = context->next_tok->span.loc + context->lexer.file_begin;
while (1)
{
TODO
//context->tok = lexer_scan_asm(&context->lexer);
TokenType type = context->tok.type;
if (type == TOKEN_RBRACE || type == TOKEN_EOF) break;
context->prev_tok_end = context->token->span.end_loc;
vec_add(ast->asm_stmt.instructions, context->token);
}
if (TOKEN_IS(TOKEN_EOF))
{
sema_error_at(context->prev_tok_end, "Unexpected end of file while parsing asm, did you forget a '}'?");
return poisoned_ast;
}
assert(TOKEN_IS(TOKEN_RBRACE));
//context->tok = lexer_scan_token(&context->lexer);
//context->next_tok = lexer_scan_token(&context->lexer);
ast->asm_stmt.is_volatile = try_consume(context, TOKEN_VOLATILE);
CONSUME_OR(TOKEN_LPAREN, poisoned_ast);
ast->asm_stmt.body = TRY_EXPR_OR(parse_expr(context), poisoned_ast);
ast->asm_stmt.is_volatile = true;
CONSUME_OR(TOKEN_RPAREN, poisoned_ast);
RANGE_EXTEND_PREV(ast);
CONSUME_OR(TOKEN_EOS, poisoned_ast);
return ast;
*/
}
@@ -222,36 +198,6 @@ static inline Ast *parse_case_stmts(Context *context, TokenType case_type, Token
}
/**
* catch_stmt
* : CATCH '(' expression ')' catch_body
* | CATCH '(' expression ')' compound_stmt
* ;
*/
static inline Ast* parse_catch_stmt(Context *context)
{
Ast *catch_stmt = AST_NEW_TOKEN(AST_CATCH_STMT, context->tok);
advance_and_verify(context, TOKEN_CATCH_OLD);
catch_stmt->catch_stmt.flow.label = TRY_DECL_OR(parse_optional_label(context, catch_stmt), false);
CONSUME_OR(TOKEN_LPAREN, poisoned_ast);
catch_stmt->catch_stmt.catchable = TRY_EXPR_OR(parse_expr(context), poisoned_ast);
CONSUME_OR(TOKEN_RPAREN, poisoned_ast);
if (TOKEN_IS(TOKEN_LBRACE) && (context->next_tok.type == TOKEN_CASE || context->next_tok.type == TOKEN_DEFAULT))
{
catch_stmt->catch_stmt.is_switch = true;
if (!parse_switch_body(context, &catch_stmt->catch_stmt.cases, TOKEN_CASE, TOKEN_DEFAULT, false)) return poisoned_ast;
return catch_stmt;
}
catch_stmt->catch_stmt.body = TRY_AST(parse_stmt(context));
return catch_stmt;
}
/**
* defer_stmt
@@ -310,8 +256,19 @@ static inline Ast* parse_if_stmt(Context *context)
CONSUME_OR(TOKEN_LPAREN, poisoned_ast);
if_ast->if_stmt.cond = TRY_EXPR_OR(parse_cond(context), poisoned_ast);
CONSUME_OR(TOKEN_RPAREN, poisoned_ast);
Ast *stmt = TRY_AST(parse_stmt(context));
if_ast->if_stmt.then_body = stmt;
// Special case, we might have if ( ) { case ... }
if (tok_is(context, TOKEN_LBRACE) && (context->next_tok.type == TOKEN_CASE || context->next_tok.type == TOKEN_DEFAULT))
{
Ast *stmt = AST_NEW_TOKEN(AST_IF_CATCH_SWITCH_STMT, context->tok);
Ast **cases = NULL;
if (!parse_switch_body(context, &cases, TOKEN_CASE, TOKEN_DEFAULT, true)) return poisoned_ast;
stmt->switch_stmt.cases = cases;
if_ast->if_stmt.then_body = stmt;
}
else
{
if_ast->if_stmt.then_body = TRY_AST(parse_stmt(context));
}
if (!try_consume(context, TOKEN_ELSE))
{
return if_ast;
@@ -635,22 +592,6 @@ static inline Ast *parse_expr_stmt(Context *context)
}
/**
* try_stmt
* : try '(' decl_expr ')' statement
* ;
*/
static inline Ast *parse_try_stmt(Context *context)
{
Ast *stmt = AST_NEW_TOKEN(AST_TRY_STMT, context->tok);
advance_and_verify(context, TOKEN_TRY_OLD);
TRY_CONSUME(TOKEN_LPAREN, "Expected a '(' after 'try'.");
stmt->try_old_stmt.decl_expr = TRY_EXPR_OR(parse_cond(context), poisoned_ast);
TRY_CONSUME(TOKEN_RPAREN, "Expected a ')' after 'try'.");
stmt->try_old_stmt.body = TRY_AST(parse_stmt(context));
return stmt;
}
static inline Ast *parse_decl_or_expr_stmt(Context *context)
{
@@ -963,8 +904,6 @@ Ast *parse_stmt(Context *context)
case TOKEN_IDENT:
case TOKEN_CONST_IDENT:
return parse_decl_or_expr_stmt(context);
case TOKEN_TRY_OLD:
return parse_try_stmt(context);
case TOKEN_DEFINE:
return parse_define_stmt(context);
case TOKEN_STATIC: // Static means declaration!
@@ -991,8 +930,6 @@ Ast *parse_stmt(Context *context)
return parse_for_stmt(context);
case TOKEN_FOREACH:
return parse_foreach_stmt(context);
case TOKEN_CATCH_OLD:
return parse_catch_stmt(context);
case TOKEN_CONTINUE:
{
Ast *ast = TRY_AST(parse_continue(context));

View File

@@ -769,7 +769,7 @@ bool cast_implicit_bit_width(Expr *expr, Type *to_type)
bool cast(Expr *expr, Type *to_type)
{
Type *from_type = type_flatten(expr->type->canonical);
Type *canonical = type_lowering(to_type);
Type *canonical = type_flatten(to_type);
if (from_type == canonical)
{
expr_set_type(expr, to_type);

View File

@@ -1335,7 +1335,7 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
success = false;
}
}
if (success && statement->if_stmt.then_body->ast_kind != AST_COMPOUND_STMT)
if (success && statement->if_stmt.then_body->ast_kind != AST_COMPOUND_STMT && statement->if_stmt.then_body->ast_kind != AST_IF_CATCH_SWITCH_STMT)
{
SourceLocation *end_of_cond = TOKLOC(cond->span.end_loc);
SourceLocation *start_of_then = TOKLOC(statement->if_stmt.then_body->span.loc);
@@ -1387,9 +1387,16 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
static bool sema_analyse_asm_stmt(Context *context __unused, Ast *statement __unused)
static bool sema_analyse_asm_stmt(Context *context, Ast *stmt)
{
TODO
if (!sema_analyse_expr(context, NULL, stmt->asm_stmt.body)) return false;
if (stmt->asm_stmt.body->expr_kind != EXPR_CONST
|| stmt->asm_stmt.body->const_expr.kind != TYPE_STRLIT)
{
SEMA_ERROR(stmt->asm_stmt.body, "The asm statement requires a constant string here.");
return false;
}
return true;
}
static inline Decl *sema_analyse_label(Context *context, Ast *stmt)
@@ -1486,20 +1493,13 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement)
}
parent = astptr(target->label.parent);
AstKind kind = parent->ast_kind;
if (kind != AST_SWITCH_STMT && kind != AST_CATCH_STMT)
if (kind != AST_SWITCH_STMT)
{
SEMA_TOKID_ERROR(statement->next_stmt.label.span, "Expected the label to match a 'switch' or 'catch' statement.");
return false;
}
bool defer_mismatch = false;
if (parent->ast_kind == AST_SWITCH_STMT)
{
defer_mismatch = context->active_scope.in_defer != parent->switch_stmt.scope_defer;
}
else
{
defer_mismatch = context->active_scope.in_defer != parent->catch_stmt.scope_defer;
}
defer_mismatch = context->active_scope.in_defer != parent->switch_stmt.scope_defer;
if (defer_mismatch)
{
SEMA_ERROR(statement, "This 'next' would jump out of a defer which is not allowed.");
@@ -1526,22 +1526,14 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement)
{
if (!sema_resolve_type_info(context, statement->next_stmt.type_info)) return false;
Ast **cases;
if (parent->ast_kind == AST_SWITCH_STMT)
statement->next_stmt.defers.end = parent->switch_stmt.defer;
if (parent->switch_stmt.cond->type->canonical != type_typeid)
{
statement->next_stmt.defers.end = parent->switch_stmt.defer;
if (parent->switch_stmt.cond->type->canonical != type_typeid)
{
SEMA_ERROR(statement, "Unexpected 'type' in as an 'next' destination.");
SEMA_PREV(statement, "The 'switch' here uses expected a type '%s'.", type_to_error_string(parent->switch_stmt.cond->type));
return false;
}
cases = parent->switch_stmt.cases;
}
else
{
statement->next_stmt.defers.end = parent->catch_stmt.defer;
cases = parent->catch_stmt.cases;
SEMA_ERROR(statement, "Unexpected 'type' in as an 'next' destination.");
SEMA_PREV(statement, "The 'switch' here uses expected a type '%s'.", type_to_error_string(parent->switch_stmt.cond->type));
return false;
}
cases = parent->switch_stmt.cases;
Ast *default_stmt = NULL;
VECEACH(cases, i)
@@ -1806,13 +1798,13 @@ static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceSpa
switch (switch_type_flattened->type_kind)
{
case TYPE_TYPEID:
case TYPE_ANYERR:
use_type_id = true;
break;
case ALL_INTS:
assert(switch_type->type_kind != TYPE_IXX);
case TYPE_BOOL:
case TYPE_ENUM:
case TYPE_ANYERR:
break;
case TYPE_DISTINCT:
UNREACHABLE
@@ -1985,21 +1977,31 @@ static bool sema_analyse_ct_switch_stmt(Context *context, Ast *statement)
static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
{
statement->switch_stmt.scope_defer = context->active_scope.in_defer;
SCOPE_START_WITH_LABEL(statement->switch_stmt.flow.label);
Expr *cond = statement->switch_stmt.cond;
if (!sema_analyse_cond(context, cond, false)) return false;
Type *switch_type;
if (statement->ast_kind == AST_SWITCH_STMT)
{
if (!sema_analyse_cond(context, cond, false)) return false;
switch_type = VECLAST(cond->cond_expr)->type->canonical;
}
else
{
switch_type = type_anyerr;
}
Type *switch_type = VECLAST(cond->cond_expr)->type->canonical;
statement->switch_stmt.defer = context->active_scope.defer_last;
if (!sema_analyse_switch_body(context, statement, cond->span,
if (!sema_analyse_switch_body(context, statement, cond ? cond->span : statement->span,
switch_type->canonical,
statement->switch_stmt.cases))
{
return SCOPE_POP_ERROR();
}
context_pop_defers_and_replace_ast(context, statement);
SCOPE_END;
if (statement->flow.no_exit && !statement->flow.has_break)
@@ -2009,159 +2011,7 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
return true;
}
/**
* Handle the catch statement
* @return true if error checking succeeds.
*/
static bool sema_analyse_catch_stmt(Context *context, Ast *statement)
{
Expr *catch_expr = statement->catch_stmt.catchable;
Decl *error_var = NULL;
Expr *error_expr = catch_expr;
Decl *unwrapped = NULL;
statement->catch_stmt.scope_defer = context->active_scope.in_defer;
SCOPE_START_WITH_LABEL(statement->catch_stmt.flow.label);
statement->catch_stmt.defer = context->active_scope.defer_last;
if (catch_expr->expr_kind == EXPR_BINARY && catch_expr->binary_expr.operator == BINARYOP_ASSIGN)
{
Expr *left = catch_expr->binary_expr.left;
if (left->expr_kind == EXPR_IDENTIFIER)
{
Decl *ambiguous_decl;
Decl *dummy;
Decl *error_var_decl = sema_resolve_normal_symbol(context,
left->identifier_expr.identifier,
left->identifier_expr.path, false);
if (!error_var_decl)
{
error_var = decl_new_var(left->span.loc, type_info_new_base(type_anyerr, left->span), VARDECL_LOCAL,
VISIBLE_LOCAL);
error_var->type = type_anyerr;
Expr *right = catch_expr->binary_expr.right;
error_var->var.init_expr = right;
error_expr = right;
statement->catch_stmt.has_err_var = true;
statement->catch_stmt.err_var = error_var;
}
}
}
if (!sema_analyse_expr(context, NULL, error_expr)) return SCOPE_POP_ERROR();
if (error_var)
{
sema_add_local(context, error_var);
}
if (!error_expr->failable)
{
const char *error_type = type_to_error_string(error_expr->type);
if (error_expr->expr_kind == EXPR_IDENTIFIER
&& error_expr->identifier_expr.decl->decl_kind == DECL_VAR
&& error_expr->identifier_expr.decl->var.kind == VARDECL_UNWRAPPED)
{
SEMA_ERROR(error_expr,
"'%s' is unwrapped to '%s' here, so it cannot be caught.",
error_expr->identifier_expr.decl->name,
error_type);
}
else
{
SEMA_ERROR(error_expr, "Expected a failable '%s!' not '%s'.", error_type, error_type);
}
return SCOPE_POP_ERROR();
}
if (catch_expr->expr_kind == EXPR_IDENTIFIER)
{
unwrapped = catch_expr->identifier_expr.decl;
}
else if (error_var)
{
Expr *right = catch_expr->binary_expr.right;
if (right->expr_kind == EXPR_IDENTIFIER) unwrapped = right->identifier_expr.decl;
}
if (statement->catch_stmt.is_switch)
{
if (!sema_analyse_switch_body(context,
statement,
error_expr->span,
type_anyerr,
statement->catch_stmt.cases))
{
return SCOPE_POP_ERROR();
}
}
else
{
if (!sema_analyse_statement(context, statement->catch_stmt.body)) return SCOPE_POP_ERROR();
if (context->active_scope.jump_end) statement->flow.no_exit = true;
}
context_pop_defers_and_replace_ast(context, statement);
SCOPE_END;
if (unwrapped && !statement->flow.has_break && statement->flow.no_exit)
{
Decl *decl = decl_copy(unwrapped);
decl->var.kind = VARDECL_UNWRAPPED;
decl->var.alias = unwrapped;
decl->var.failable = false;
sema_unwrap_var(context, decl);
}
return true;
}
static bool sema_analyse_try_stmt(Context *context, Ast *stmt)
{
assert(stmt->try_old_stmt.decl_expr->expr_kind == EXPR_COND);
Expr **dexprs = stmt->try_old_stmt.decl_expr->cond_expr;
TODO
/*TODO
SCOPE_START
unsigned entries = vec_size(dexprs);
for (unsigned i = 0; i < entries; i++)
{
Ast *ast = dexprs[i];
if (ast->ast_kind == AST_DECLARE_STMT)
{
ast->declare_stmt->var.unwrap = true;
if (!sema_analyse_statement(context, ast)) return SCOPE_POP_ERROR();
continue;
}
if (!sema_analyse_statement(context, ast)) return SCOPE_POP_ERROR();
Expr *expr = ast->expr_stmt;
if (!expr->failable)
{
SEMA_ERROR(expr, "The expression to 'try' must be failable.");
return SCOPE_POP_ERROR();
}
if (expr->expr_kind == EXPR_IDENTIFIER)
{
Decl *var = expr->identifier_expr.decl;
Decl *decl = decl_copy(var);
decl->var.kind = VARDECL_ALIAS;
decl->var.alias = var;
decl->var.failable = false;
sema_unwrap_var(context, decl);
}
}
if (!sema_analyse_statement(context, stmt->try_old_stmt.body))
{
return SCOPE_POP_ERROR();
}
SCOPE_END;
*/
return true;
}
static bool sema_analyse_volatile_stmt(Context *context, Ast *statement)
{
@@ -2285,8 +2135,6 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
case AST_CASE_STMT:
SEMA_ERROR(statement, "Unexpected 'case' outside of switch");
return false;
case AST_CATCH_STMT:
return sema_analyse_catch_stmt(context, statement);
case AST_COMPOUND_STMT:
return sema_analyse_compound_stmt(context, statement);
case AST_CONTINUE_STMT:
@@ -2314,8 +2162,6 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
return sema_analyse_foreach_stmt(context, statement);
case AST_FOR_STMT:
return sema_analyse_for_stmt(context, statement);
case AST_TRY_STMT:
return sema_analyse_try_stmt(context, statement);
case AST_IF_STMT:
return sema_analyse_if_stmt(context, statement);
case AST_NOP_STMT:
@@ -2323,6 +2169,7 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
case AST_RETURN_STMT:
return sema_analyse_return_stmt(context, statement);
case AST_SWITCH_STMT:
case AST_IF_CATCH_SWITCH_STMT:
return sema_analyse_switch_stmt(context, statement);
case AST_NEXT_STMT:
return sema_analyse_next_stmt(context, statement);

View File

@@ -194,8 +194,6 @@ const char *token_type_to_string(TokenType type)
return "break";
case TOKEN_CASE:
return "case";
case TOKEN_CATCH_OLD:
return "catchx";
case TOKEN_CATCH:
return "catch";
case TOKEN_CONST:
@@ -254,8 +252,6 @@ const char *token_type_to_string(TokenType type)
return "switch";
case TOKEN_TRUE:
return "true";
case TOKEN_TRY_OLD:
return "tryx";
case TOKEN_TRY:
return "try";
case TOKEN_TYPEID:

View File

@@ -256,13 +256,13 @@ bool type_is_union_struct(Type *type)
bool type_is_empty_field(Type *type, bool allow_array)
{
type = type_flatten(type);
type = type_lowering(type);
if (allow_array)
{
while (type->type_kind == TYPE_ARRAY)
{
if (type->array.len == 0) return true;
type = type_flatten(type->array.base);
type = type_lowering(type->array.base);
}
}
return type_is_empty_record(type, allow_array);
@@ -303,7 +303,7 @@ Type *type_abi_find_single_struct_element(Type *type)
Decl **members = type->decl->strukt.members;
VECEACH(members, i)
{
Type *field_type = type_flatten(members[i]->type);
Type *field_type = type_lowering(members[i]->type);
// Ignore empty arrays
if (type_is_empty_field(field_type, true)) continue;
@@ -626,7 +626,7 @@ AlignSize type_alloca_alignment(Type *type)
{
if (platform_target.abi == ABI_X64)
{
type = type_flatten(type);
type = type_lowering(type);
if (type->type_kind == TYPE_ARRAY && type_size(type) >= 16) return 16;
}
return type_abi_alignment(type);

View File

@@ -139,8 +139,8 @@ after_check17: ; preds = %testblock
end_block: ; preds = %after_check17, %error
%13 = load i64, i64* %e, align 8
%intbool = icmp ne i64 %13, 0
br i1 %intbool, label %if.then18, label %if.exit19
%neq = icmp ne i64 %13, 0
br i1 %neq, label %if.then18, label %if.exit19
if.then18: ; preds = %end_block
%14 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0))

View File

@@ -82,8 +82,8 @@ after.errcheck: ; preds = %testblock1
end_block: ; preds = %after.errcheck, %error3, %error
%2 = load i64, i64* %err, align 8
%intbool = icmp ne i64 %2, 0
br i1 %intbool, label %if.then, label %if.else
%neq = icmp ne i64 %2, 0
br i1 %neq, label %if.then, label %if.else
if.then: ; preds = %end_block
%3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i32 0, i32 0))