mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Remove old try/catch. Remove incorrect flattening. Basic asm. Start work on if-catch-switch.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user