mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fixed a lot of while/if/for. ?: now works.
This commit is contained in:
@@ -560,21 +560,21 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXPR_CONDITIONAL:
|
||||
if (!expr->conditional_expr.then_expr)
|
||||
case EXPR_TERNARY:
|
||||
if (!expr->ternary_expr.then_expr)
|
||||
{
|
||||
fprintf_indented(file, indent, "(elvis\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->conditional_expr.cond, indent + 1);
|
||||
fprint_expr_recursive(file, expr->ternary_expr.cond, indent + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf_indented(file, indent, "(cond\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->conditional_expr.cond, indent + 1);
|
||||
fprint_expr_recursive(file, expr->conditional_expr.then_expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->ternary_expr.cond, indent + 1);
|
||||
fprint_expr_recursive(file, expr->ternary_expr.then_expr, indent + 1);
|
||||
}
|
||||
fprint_expr_recursive(file, expr->conditional_expr.else_expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->ternary_expr.else_expr, indent + 1);
|
||||
break;
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
fprintf_indented(file, indent, "(initializerlist\n");
|
||||
@@ -613,6 +613,15 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
|
||||
fprint_type_info_recursive(file, expr->cast_expr.type_info, indent + 1);
|
||||
fprint_expr_recursive(file, expr->cast_expr.expr, indent + 1);
|
||||
break;
|
||||
case EXPR_EXPRESSION_LIST:
|
||||
fprintf_indented(file, indent, "(expression-list\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_type_info_recursive(file, expr->struct_value_expr.type, indent + 1);
|
||||
VECEACH(expr->expression_list, i)
|
||||
{
|
||||
fprint_expr_recursive(file, expr->expression_list[i], indent + 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf_indented(file, indent, "(TODOEXPR)\n");
|
||||
return;
|
||||
@@ -826,6 +835,12 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent)
|
||||
fprint_asts_recursive(file, ast->compound_stmt.stmts, indent + 1);
|
||||
}
|
||||
break;
|
||||
case AST_DECL_EXPR_LIST:
|
||||
fprintf(file, "(declexprlist\n");
|
||||
{
|
||||
fprint_asts_recursive(file, ast->decl_expr_stmt, indent + 1);
|
||||
}
|
||||
break;
|
||||
case AST_DECLARE_STMT:
|
||||
fprintf(file, "(declare\n");
|
||||
fprint_decl_recursive(file, ast->declare_stmt, indent + 1);
|
||||
@@ -856,10 +871,6 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent)
|
||||
fprint_ast_recursive(file, ast->do_stmt.body, indent + 1);
|
||||
fprint_expr_recursive(file, ast->do_stmt.expr, indent + 1);
|
||||
break;
|
||||
case AST_STMT_LIST:
|
||||
fprintf(file, "(stmtlist\n");
|
||||
fprint_asts_recursive(file, ast->stmt_list, indent + 1);
|
||||
break;
|
||||
case AST_RETURN_STMT:
|
||||
if (ast->return_stmt.expr)
|
||||
{
|
||||
@@ -884,25 +895,19 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent)
|
||||
case AST_DEFAULT_STMT:
|
||||
fprintf(file, "(default)\n");
|
||||
return;
|
||||
case AST_COND_STMT:
|
||||
fprintf(file, "(cond\n");
|
||||
if (ast->cond_stmt.expr)
|
||||
{
|
||||
fprint_expr_recursive(file, ast->cond_stmt.expr, indent + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprint_indent(file, indent);
|
||||
fprintf(file, "(noexpr)");
|
||||
}
|
||||
fprint_asts_recursive(file, ast->cond_stmt.stmts, indent + 1);
|
||||
break;
|
||||
case AST_FOR_STMT:
|
||||
fprintf(file, "(for\n");
|
||||
fprint_ast_recursive(file, ast->for_stmt.cond, indent + 1);
|
||||
if (ast->for_stmt.init)
|
||||
{
|
||||
fprint_ast_recursive(file, ast->for_stmt.init, indent + 1);
|
||||
}
|
||||
if (ast->for_stmt.cond)
|
||||
{
|
||||
fprint_expr_recursive(file, ast->for_stmt.cond, indent + 1);
|
||||
}
|
||||
if (ast->for_stmt.incr)
|
||||
{
|
||||
fprint_ast_recursive(file, ast->for_stmt.incr, indent + 1);
|
||||
fprint_expr_recursive(file, ast->for_stmt.incr, indent + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1012,3 +1017,4 @@ void fprint_decl(FILE *file, Decl *dec)
|
||||
}
|
||||
Module poisoned_module = { .name = "INVALID" };
|
||||
Decl all_error = { .decl_kind = DECL_ERROR, .name = { .type = TOKEN_INVALID_TOKEN, .string = NULL } };
|
||||
|
||||
|
||||
@@ -562,6 +562,49 @@ bool cast_implicit(Expr *expr, Type *to_type)
|
||||
return cast(expr, to_type, CAST_TYPE_IMPLICIT);
|
||||
}
|
||||
|
||||
CastKind cast_to_bool_kind(Type *type)
|
||||
{
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_TYPEDEF:
|
||||
return cast_to_bool_kind(type->canonical);
|
||||
case TYPE_POISONED:
|
||||
case TYPE_VOID:
|
||||
case TYPE_ERROR_UNION:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_STRING:
|
||||
case TYPE_ERROR:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_FUNC:
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_VARARRAY:
|
||||
case TYPE_SUBARRAY:
|
||||
// Improve consider vararray / subarray conversion to boolean.
|
||||
return CAST_ERROR;
|
||||
case TYPE_BOOL:
|
||||
UNREACHABLE
|
||||
case TYPE_I8:
|
||||
case TYPE_I16:
|
||||
case TYPE_I32:
|
||||
case TYPE_I64:
|
||||
case TYPE_IXX:
|
||||
case TYPE_U8:
|
||||
case TYPE_U16:
|
||||
case TYPE_U32:
|
||||
case TYPE_U64:
|
||||
case TYPE_UXX:
|
||||
return CAST_INTBOOL;
|
||||
case TYPE_F32:
|
||||
case TYPE_F64:
|
||||
case TYPE_FXX:
|
||||
return CAST_FPBOOL;
|
||||
case TYPE_POINTER:
|
||||
return CAST_PTRBOOL;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
bool cast(Expr *expr, Type *to_type, CastType cast_type)
|
||||
{
|
||||
Type *from_type = expr->type->canonical;
|
||||
|
||||
@@ -444,6 +444,7 @@ typedef struct
|
||||
};
|
||||
} ExprCast;
|
||||
|
||||
|
||||
struct _Expr
|
||||
{
|
||||
ExprKind expr_kind : 8;
|
||||
@@ -458,7 +459,7 @@ struct _Expr
|
||||
ExprTry try_expr;
|
||||
ExprBinary binary_expr;
|
||||
ExprAssign assign_expr;
|
||||
ExprTernary conditional_expr;
|
||||
ExprTernary ternary_expr;
|
||||
ExprUnary unary_expr;
|
||||
ExprUnary post_expr;
|
||||
ExprCall call_expr;
|
||||
@@ -500,6 +501,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Ast *decl;
|
||||
Ast *cond;
|
||||
Ast *body;
|
||||
} AstWhileStmt;
|
||||
@@ -512,6 +514,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Ast *decl;
|
||||
Ast *cond;
|
||||
Ast *then_body;
|
||||
Ast *else_body;
|
||||
@@ -536,6 +539,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Ast *decl;
|
||||
Ast *cond;
|
||||
Ast *body;
|
||||
Ast **cases;
|
||||
@@ -543,19 +547,13 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Ast **init;
|
||||
Ast *cond;
|
||||
Ast *incr;
|
||||
Ast *init;
|
||||
Expr *cond;
|
||||
Expr *incr;
|
||||
Ast *body;
|
||||
} AstForStmt;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Ast **stmts;
|
||||
Expr *expr;
|
||||
} AstCondStmt;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -652,14 +650,13 @@ typedef struct _Ast
|
||||
AstCatchStmt catch_stmt;
|
||||
AstGotoStmt goto_stmt;
|
||||
AstForStmt for_stmt;
|
||||
AstCondStmt cond_stmt;
|
||||
AstCtIfStmt ct_if_stmt;
|
||||
AstCtIfStmt ct_elif_stmt;
|
||||
Ast *ct_else_stmt;
|
||||
AstCtForStmt ct_for_stmt;
|
||||
AstGenericCaseStmt generic_case_stmt;
|
||||
Ast *generic_default_stmt;
|
||||
Ast** stmt_list;
|
||||
Ast** decl_expr_stmt;
|
||||
};
|
||||
} Ast;
|
||||
|
||||
@@ -826,7 +823,7 @@ static inline ConstType sign_from_type(Type *type)
|
||||
bool cast_implicit(Expr *expr, Type *to_type);
|
||||
bool cast(Expr *expr, Type *to_type, CastType cast_type);
|
||||
bool cast_binary_arithmetic(Expr *left, Expr *right, const char *action);
|
||||
|
||||
CastKind cast_to_bool_kind(Type *type);
|
||||
bool cast_to_runtime(Expr *expr);
|
||||
|
||||
void llvm_codegen(Context *context);
|
||||
|
||||
@@ -74,7 +74,6 @@ typedef enum
|
||||
AST_CASE_STMT,
|
||||
AST_CATCH_STMT,
|
||||
AST_COMPOUND_STMT,
|
||||
AST_COND_STMT,
|
||||
AST_CONTINUE_STMT,
|
||||
AST_CT_IF_STMT,
|
||||
AST_CT_ELIF_STMT,
|
||||
@@ -96,7 +95,7 @@ typedef enum
|
||||
AST_LABEL,
|
||||
AST_NOP_STMT,
|
||||
AST_RETURN_STMT,
|
||||
AST_STMT_LIST,
|
||||
AST_DECL_EXPR_LIST,
|
||||
AST_SWITCH_STMT,
|
||||
AST_THROW_STMT,
|
||||
AST_TRY_STMT,
|
||||
@@ -227,7 +226,7 @@ typedef enum
|
||||
EXPR_TRY,
|
||||
EXPR_CONST,
|
||||
EXPR_BINARY,
|
||||
EXPR_CONDITIONAL,
|
||||
EXPR_TERNARY,
|
||||
EXPR_UNARY,
|
||||
EXPR_POST_UNARY,
|
||||
EXPR_TYPE,
|
||||
@@ -279,7 +278,7 @@ typedef enum
|
||||
{
|
||||
PREC_NONE,
|
||||
PREC_ASSIGNMENT, // =, *=, /=, %=, ...
|
||||
PREC_CONDITIONAL, // ?:
|
||||
PREC_TERNARY, // ?:
|
||||
PREC_LOGICAL, // && ||
|
||||
PREC_RELATIONAL, // < > <= >= == !=
|
||||
PREC_ADDITIVE, // + -
|
||||
|
||||
@@ -43,12 +43,30 @@ static inline bool sema_type_error_on_binop(Expr *expr)
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_expr_analyse_conditional(Context *context, Type *to, Expr *expr)
|
||||
static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *expr)
|
||||
{
|
||||
if (!sema_analyse_expr(context, type_bool, expr->conditional_expr.cond)) return expr_poison(expr);
|
||||
Expr *left = expr->conditional_expr.then_expr;
|
||||
Expr *right = expr->conditional_expr.else_expr;
|
||||
if (!sema_analyse_expr(context, to, left)) return expr_poison(expr);
|
||||
Expr *left = expr->ternary_expr.then_expr;
|
||||
Expr *cond = expr->ternary_expr.cond;
|
||||
// Normal
|
||||
if (left)
|
||||
{
|
||||
if (!sema_analyse_expr(context, type_bool, cond)) return expr_poison(expr);
|
||||
if (!sema_analyse_expr(context, to, left)) return expr_poison(expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Elvis
|
||||
if (!sema_analyse_expr(context, to, cond)) return expr_poison(expr);
|
||||
Type *type = cond->type->canonical;
|
||||
if (type->type_kind != TYPE_BOOL && cast_to_bool_kind(type) == CAST_ERROR)
|
||||
{
|
||||
SEMA_ERROR(cond->loc, "Cannot convert expression to boolean.");
|
||||
return false;
|
||||
}
|
||||
left = cond;
|
||||
}
|
||||
|
||||
Expr *right = expr->ternary_expr.else_expr;
|
||||
if (!sema_analyse_expr(context, to, right)) return expr_poison(expr);
|
||||
|
||||
Type *left_canonical = left->type->canonical;
|
||||
@@ -452,7 +470,7 @@ static inline bool sema_expr_analyse_expr_list(Context *context, Type *to, Expr
|
||||
size_t last = vec_size(expr->expression_list) - 1;
|
||||
VECEACH(expr->expression_list, i)
|
||||
{
|
||||
success &= sema_analyse_expr(context, i == last ? to : NULL, expr);
|
||||
success &= sema_analyse_expr(context, i == last ? to : NULL, expr->expression_list[i]);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -1291,6 +1309,8 @@ static inline bool sema_expr_analyse_incdec(Context *context, Type *to, Expr *ex
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline bool sema_expr_analyse_binary(Context *context, Type *to, Expr *expr)
|
||||
{
|
||||
assert(expr->resolve_status == RESOLVE_RUNNING);
|
||||
@@ -1446,8 +1466,8 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
|
||||
return true;
|
||||
case EXPR_BINARY:
|
||||
return sema_expr_analyse_binary(context, to, expr);
|
||||
case EXPR_CONDITIONAL:
|
||||
return sema_expr_analyse_conditional(context, to, expr);
|
||||
case EXPR_TERNARY:
|
||||
return sema_expr_analyse_ternary(context, to, expr);
|
||||
case EXPR_UNARY:
|
||||
return sema_expr_analyse_unary(context, to, expr);
|
||||
case EXPR_POST_UNARY:
|
||||
|
||||
@@ -50,7 +50,7 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
|
||||
case EXPR_TRY:
|
||||
case EXPR_SIZEOF:
|
||||
case EXPR_BINARY:
|
||||
case EXPR_CONDITIONAL:
|
||||
case EXPR_TERNARY:
|
||||
case EXPR_POST_UNARY:
|
||||
case EXPR_TYPE_ACCESS:
|
||||
case EXPR_CALL:
|
||||
@@ -64,17 +64,16 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *expr)
|
||||
LLVMValueRef gencontext_emit_cast(GenContext *context, CastKind cast_kind, LLVMValueRef value, Type *type, Type *target_type)
|
||||
{
|
||||
LLVMValueRef rhs = gencontext_emit_expr(context, expr->cast_expr.expr);
|
||||
switch (expr->cast_expr.kind)
|
||||
switch (cast_kind)
|
||||
{
|
||||
case CAST_ERROR:
|
||||
UNREACHABLE
|
||||
case CAST_PTRPTR:
|
||||
return LLVMBuildPointerCast(context->builder, rhs, BACKEND_TYPE(expr->type), "ptrptr");
|
||||
return LLVMBuildPointerCast(context->builder, value, BACKEND_TYPE(type), "ptrptr");
|
||||
case CAST_PTRXI:
|
||||
return LLVMBuildPtrToInt(context->builder, rhs, BACKEND_TYPE(expr->type), "ptrxi");
|
||||
return LLVMBuildPtrToInt(context->builder, value, BACKEND_TYPE(type), "ptrxi");
|
||||
case CAST_VARRPTR:
|
||||
TODO
|
||||
case CAST_ARRPTR:
|
||||
@@ -82,49 +81,54 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
|
||||
case CAST_STRPTR:
|
||||
TODO
|
||||
case CAST_PTRBOOL:
|
||||
return LLVMBuildICmp(context->builder, LLVMIntNE, rhs, LLVMConstPointerNull(BACKEND_TYPE(expr->type->canonical->pointer)), "ptrbool");
|
||||
return LLVMBuildICmp(context->builder, LLVMIntNE, value, LLVMConstPointerNull(BACKEND_TYPE(type->canonical->pointer)), "ptrbool");
|
||||
case CAST_BOOLINT:
|
||||
return LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "boolsi");
|
||||
return LLVMBuildTrunc(context->builder, value, BACKEND_TYPE(type), "boolsi");
|
||||
case CAST_FPBOOL:
|
||||
return LLVMBuildFCmp(context->builder, LLVMRealUNE, rhs, LLVMConstNull(LLVMTypeOf(rhs)), "fpbool");
|
||||
return LLVMBuildFCmp(context->builder, LLVMRealUNE, value, LLVMConstNull(LLVMTypeOf(value)), "fpbool");
|
||||
case CAST_BOOLFP:
|
||||
return LLVMBuildSIToFP(context->builder, rhs, BACKEND_TYPE(expr->type), "boolfp");
|
||||
return LLVMBuildSIToFP(context->builder, value, BACKEND_TYPE(type), "boolfp");
|
||||
case CAST_INTBOOL:
|
||||
return LLVMBuildICmp(context->builder, LLVMIntNE, rhs, LLVMConstNull(LLVMTypeOf(rhs)), "intbool");
|
||||
return LLVMBuildICmp(context->builder, LLVMIntNE, value, LLVMConstNull(LLVMTypeOf(value)), "intbool");
|
||||
case CAST_FPFP:
|
||||
return type_convert_will_trunc(expr->type, expr->cast_expr.expr->type)
|
||||
? LLVMBuildFPTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "fpfptrunc")
|
||||
: LLVMBuildFPExt(context->builder, rhs, BACKEND_TYPE(expr->type), "fpfpext");
|
||||
return type_convert_will_trunc(type, target_type)
|
||||
? LLVMBuildFPTrunc(context->builder, value, BACKEND_TYPE(type), "fpfptrunc")
|
||||
: LLVMBuildFPExt(context->builder, value, BACKEND_TYPE(type), "fpfpext");
|
||||
case CAST_FPSI:
|
||||
return LLVMBuildFPToSI(context->builder, rhs, BACKEND_TYPE(expr->type), "fpsi");
|
||||
return LLVMBuildFPToSI(context->builder, value, BACKEND_TYPE(type), "fpsi");
|
||||
case CAST_FPUI:
|
||||
return LLVMBuildFPToUI(context->builder, rhs, BACKEND_TYPE(expr->type), "fpui");
|
||||
return LLVMBuildFPToUI(context->builder, value, BACKEND_TYPE(type), "fpui");
|
||||
case CAST_SISI:
|
||||
return type_convert_will_trunc(expr->type, expr->cast_expr.expr->type)
|
||||
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "sisitrunc")
|
||||
: LLVMBuildSExt(context->builder, rhs, BACKEND_TYPE(expr->type), "sisiext");
|
||||
return type_convert_will_trunc(type, target_type)
|
||||
? LLVMBuildTrunc(context->builder, value, BACKEND_TYPE(type), "sisitrunc")
|
||||
: LLVMBuildSExt(context->builder, value, BACKEND_TYPE(type), "sisiext");
|
||||
case CAST_SIUI:
|
||||
return type_convert_will_trunc(expr->type, expr->cast_expr.expr->type)
|
||||
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "siuitrunc")
|
||||
: LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "siuiext");
|
||||
return type_convert_will_trunc(type, target_type)
|
||||
? LLVMBuildTrunc(context->builder, value, BACKEND_TYPE(type), "siuitrunc")
|
||||
: LLVMBuildZExt(context->builder, value, BACKEND_TYPE(type), "siuiext");
|
||||
case CAST_SIFP:
|
||||
return LLVMBuildSIToFP(context->builder, rhs, BACKEND_TYPE(expr->type), "sifp");
|
||||
return LLVMBuildSIToFP(context->builder, value, BACKEND_TYPE(type), "sifp");
|
||||
case CAST_XIPTR:
|
||||
return LLVMBuildIntToPtr(context->builder, rhs, BACKEND_TYPE(expr->type), "xiptr");
|
||||
return LLVMBuildIntToPtr(context->builder, value, BACKEND_TYPE(type), "xiptr");
|
||||
case CAST_UISI:
|
||||
return type_convert_will_trunc(expr->type, expr->cast_expr.expr->type)
|
||||
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "uisitrunc")
|
||||
: LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "uisiext");
|
||||
return type_convert_will_trunc(type, target_type)
|
||||
? LLVMBuildTrunc(context->builder, value, BACKEND_TYPE(type), "uisitrunc")
|
||||
: LLVMBuildZExt(context->builder, value, BACKEND_TYPE(type), "uisiext");
|
||||
case CAST_UIUI:
|
||||
return type_convert_will_trunc(expr->type, expr->cast_expr.expr->type)
|
||||
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "uiuitrunc")
|
||||
: LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "uiuiext");
|
||||
return type_convert_will_trunc(type, target_type)
|
||||
? LLVMBuildTrunc(context->builder, value, BACKEND_TYPE(type), "uiuitrunc")
|
||||
: LLVMBuildZExt(context->builder, value, BACKEND_TYPE(type), "uiuiext");
|
||||
case CAST_UIFP:
|
||||
return LLVMBuildUIToFP(context->builder, rhs, BACKEND_TYPE(expr->type), "uifp");
|
||||
return LLVMBuildUIToFP(context->builder, value, BACKEND_TYPE(type), "uifp");
|
||||
case CAST_ENUMSI:
|
||||
TODO
|
||||
}
|
||||
}
|
||||
static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
LLVMValueRef rhs = gencontext_emit_expr(context, expr->cast_expr.expr);
|
||||
return gencontext_emit_cast(context, expr->cast_expr.kind, rhs, expr->type->canonical, expr->cast_expr.expr->type->canonical);
|
||||
}
|
||||
|
||||
LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
@@ -403,24 +407,59 @@ static LLVMValueRef gencontext_emit_binary_expr(GenContext *context, Expr *expr)
|
||||
return gencontext_emit_binary(context, expr, false, binary_op);
|
||||
}
|
||||
|
||||
LLVMValueRef gencontext_emit_conditional_expr(GenContext *context, Expr *expr)
|
||||
LLVMValueRef gencontext_emit_elvis_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
LLVMBasicBlockRef current_block = context->current_block;
|
||||
LLVMBasicBlockRef phi_block = LLVMCreateBasicBlockInContext(context->context, "cond.phi");
|
||||
LLVMBasicBlockRef rhs_block = LLVMCreateBasicBlockInContext(context->context, "cond.rhs");
|
||||
|
||||
// Generate condition and conditional branch
|
||||
LLVMValueRef lhs = gencontext_emit_expr(context, expr->ternary_expr.cond);
|
||||
LLVMValueRef cond = lhs;
|
||||
Type *cond_type = expr->ternary_expr.cond->type->canonical;
|
||||
if (cond_type != type_bool)
|
||||
{
|
||||
CastKind cast = cast_to_bool_kind(cond_type);
|
||||
cond = gencontext_emit_cast(context, cast, cond, cond_type, type_bool);
|
||||
}
|
||||
|
||||
gencontext_emit_cond_br(context, cond, phi_block, rhs_block);
|
||||
|
||||
gencontext_emit_block(context, rhs_block);
|
||||
LLVMValueRef rhs = gencontext_emit_expr(context, expr->ternary_expr.else_expr);
|
||||
gencontext_emit_br(context, phi_block);
|
||||
|
||||
// Generate phi
|
||||
gencontext_emit_block(context, phi_block);
|
||||
LLVMValueRef phi = LLVMBuildPhi(context->builder, expr->type->backend_type, "val");
|
||||
|
||||
LLVMValueRef logicValues[2] = { lhs, rhs };
|
||||
LLVMBasicBlockRef blocks[2] = { current_block, rhs_block };
|
||||
LLVMAddIncoming(phi, logicValues, blocks, 2);
|
||||
|
||||
return phi;
|
||||
}
|
||||
|
||||
LLVMValueRef gencontext_emit_ternary_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
if (expr->ternary_expr.then_expr == NULL) return gencontext_emit_elvis_expr(context, expr);
|
||||
|
||||
// Set up basic blocks, following Cone
|
||||
LLVMBasicBlockRef phi_block = LLVMCreateBasicBlockInContext(context->context, "cond.phi");
|
||||
LLVMBasicBlockRef lhs_block = LLVMCreateBasicBlockInContext(context->context, "cond.lhs");
|
||||
LLVMBasicBlockRef rhs_block = LLVMCreateBasicBlockInContext(context->context, "cond.rhs");
|
||||
|
||||
// Generate condition and conditional branch
|
||||
LLVMValueRef cond = gencontext_emit_expr(context, expr->conditional_expr.cond);
|
||||
LLVMValueRef cond = gencontext_emit_expr(context, expr->ternary_expr.cond);
|
||||
|
||||
gencontext_emit_cond_br(context, cond, lhs_block, rhs_block);
|
||||
|
||||
gencontext_emit_block(context, lhs_block);
|
||||
LLVMValueRef lhs = gencontext_emit_expr(context, expr->conditional_expr.then_expr);
|
||||
LLVMValueRef lhs = gencontext_emit_expr(context, expr->ternary_expr.then_expr);
|
||||
gencontext_emit_br(context, phi_block);
|
||||
|
||||
gencontext_emit_block(context, rhs_block);
|
||||
LLVMValueRef rhs = gencontext_emit_expr(context, expr->conditional_expr.else_expr);
|
||||
LLVMValueRef rhs = gencontext_emit_expr(context, expr->ternary_expr.else_expr);
|
||||
gencontext_emit_br(context, phi_block);
|
||||
|
||||
// Generate phi
|
||||
@@ -521,10 +560,6 @@ static inline LLVMValueRef gencontext_emit_struct_init_values_expr(GenContext *c
|
||||
TODO
|
||||
}
|
||||
|
||||
static inline LLVMValueRef gencontext_load_expr(GenContext *context, LLVMValueRef value)
|
||||
{
|
||||
return LLVMBuildLoad(context->builder, value, "");
|
||||
}
|
||||
|
||||
LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
@@ -538,8 +573,8 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
|
||||
return gencontext_emit_const_expr(context, expr);
|
||||
case EXPR_BINARY:
|
||||
return gencontext_emit_binary_expr(context, expr);
|
||||
case EXPR_CONDITIONAL:
|
||||
return gencontext_emit_conditional_expr(context, expr);
|
||||
case EXPR_TERNARY:
|
||||
return gencontext_emit_ternary_expr(context, expr);
|
||||
case EXPR_POST_UNARY:
|
||||
return gencontext_emit_post_unary_expr(context, expr);
|
||||
case EXPR_TYPE:
|
||||
|
||||
@@ -89,9 +89,12 @@ static inline LLVMBasicBlockRef gencontext_create_free_block(GenContext *context
|
||||
void gencontext_emit_function_decl(GenContext *context, Decl *decl);
|
||||
LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr);
|
||||
#define LLVMTYPE(type) type->backend_type
|
||||
|
||||
static inline LLVMValueRef gencontext_load_expr(GenContext *context, LLVMValueRef value)
|
||||
{
|
||||
return LLVMBuildLoad(context->builder, value, "");
|
||||
}
|
||||
LLVMTypeRef gencontext_get_llvm_type(GenContext *context, Type *type);
|
||||
|
||||
LLVMValueRef gencontext_emit_cast(GenContext *context, CastKind cast_kind, LLVMValueRef value, Type *type, Type *target_type);
|
||||
static inline bool gencontext_use_debug(GenContext *context)
|
||||
{
|
||||
return context && context->debug.builder != NULL;
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
#include "llvm_codegen_internal.h"
|
||||
|
||||
static void gencontext_pop_break_continue(GenContext *context);
|
||||
static void
|
||||
gencontext_push_break_continue(GenContext *context, LLVMBasicBlockRef break_block, LLVMBasicBlockRef continue_block,
|
||||
static void gencontext_push_break_continue(GenContext *context, LLVMBasicBlockRef break_block, LLVMBasicBlockRef continue_block,
|
||||
LLVMBasicBlockRef next_block);
|
||||
|
||||
void gencontext_emit_compound_stmt(GenContext *context, Ast *ast)
|
||||
@@ -18,41 +17,6 @@ void gencontext_emit_compound_stmt(GenContext *context, Ast *ast)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gencontext_emit_stmt_list(GenContext *context, Ast *ast)
|
||||
{
|
||||
assert(ast->ast_kind == AST_STMT_LIST);
|
||||
VECEACH(ast->stmt_list, i)
|
||||
{
|
||||
gencontext_emit_stmt(context, ast->stmt_list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gencontext_emit_return(GenContext *context, Ast *ast)
|
||||
{
|
||||
// Ensure we are on a branch that is non empty.
|
||||
if (!gencontext_check_block_branch_emit(context)) return;
|
||||
if (!ast->return_stmt.expr)
|
||||
{
|
||||
LLVMBuildRetVoid(context->builder);
|
||||
return;
|
||||
}
|
||||
LLVMValueRef returnValue = gencontext_emit_expr(context, ast->return_stmt.expr);
|
||||
LLVMBuildRet(context->builder, returnValue);
|
||||
context->current_block = NULL;
|
||||
LLVMBasicBlockRef post_ret_block = gencontext_create_free_block(context, "ret");
|
||||
gencontext_emit_block(context, post_ret_block);
|
||||
|
||||
}
|
||||
|
||||
static inline LLVMValueRef gencontext_emit_cond(GenContext *context, Ast *ast)
|
||||
{
|
||||
assert(ast->ast_kind == AST_COND_STMT);
|
||||
VECEACH(ast->cond_stmt.stmts, i)
|
||||
{
|
||||
gencontext_emit_stmt(context, ast->cond_stmt.stmts[i]);
|
||||
}
|
||||
return gencontext_emit_expr(context, ast->cond_stmt.expr);
|
||||
}
|
||||
|
||||
static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
|
||||
{
|
||||
@@ -84,17 +48,75 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
|
||||
return decl->var.backend_ref;
|
||||
}
|
||||
|
||||
void gencontext_emit_decl_expr_list_ignore_result(GenContext *context, Ast *ast)
|
||||
{
|
||||
assert(ast->ast_kind == AST_DECL_EXPR_LIST);
|
||||
VECEACH(ast->decl_expr_stmt, i)
|
||||
{
|
||||
gencontext_emit_stmt(context, ast->decl_expr_stmt[i]);
|
||||
}
|
||||
}
|
||||
|
||||
LLVMValueRef gencontext_emit_decl_expr_list(GenContext *context, Ast *ast, bool bool_cast)
|
||||
{
|
||||
assert(ast->ast_kind == AST_DECL_EXPR_LIST);
|
||||
size_t size = vec_size(ast->decl_expr_stmt);
|
||||
size_t last_index = size - 1;
|
||||
for (size_t i = 0; i < last_index; i++)
|
||||
{
|
||||
gencontext_emit_stmt(context, ast->decl_expr_stmt[i]);
|
||||
}
|
||||
Ast *last = ast->decl_expr_stmt[last_index];
|
||||
LLVMValueRef result;
|
||||
Type *type;
|
||||
switch (last->ast_kind)
|
||||
{
|
||||
case AST_EXPR_STMT:
|
||||
type = last->expr_stmt->type;
|
||||
result = gencontext_emit_expr(context, last->expr_stmt);
|
||||
break;
|
||||
case AST_DECLARE_STMT:
|
||||
type = last->declare_stmt->var.type_info->type;
|
||||
result = gencontext_load_expr(context, gencontext_emit_decl(context, last));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (bool_cast)
|
||||
{
|
||||
type = type->canonical;
|
||||
if (type->type_kind != TYPE_BOOL)
|
||||
{
|
||||
CastKind cast = cast_to_bool_kind(type);
|
||||
result = gencontext_emit_cast(context, cast, result, type, type_bool);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static inline void gencontext_emit_return(GenContext *context, Ast *ast)
|
||||
{
|
||||
// Ensure we are on a branch that is non empty.
|
||||
if (!gencontext_check_block_branch_emit(context)) return;
|
||||
if (!ast->return_stmt.expr)
|
||||
{
|
||||
LLVMBuildRetVoid(context->builder);
|
||||
return;
|
||||
}
|
||||
LLVMValueRef returnValue = gencontext_emit_expr(context, ast->return_stmt.expr);
|
||||
LLVMBuildRet(context->builder, returnValue);
|
||||
context->current_block = NULL;
|
||||
LLVMBasicBlockRef post_ret_block = gencontext_create_free_block(context, "ret");
|
||||
gencontext_emit_block(context, post_ret_block);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void gencontext_emit_if(GenContext *context, Ast *ast)
|
||||
{
|
||||
// In the case of something like if (foo = 1, int bar = 2; b > 0) { ... }
|
||||
// Let's first emit foo = 1, int bar = 2
|
||||
// IMPROVE Consider whether these should be lowered or not.
|
||||
Ast **stmts = ast->if_stmt.cond->cond_stmt.stmts;
|
||||
VECEACH(stmts, i)
|
||||
{
|
||||
gencontext_emit_stmt(context, stmts[i]);
|
||||
}
|
||||
if (ast->if_stmt.decl) gencontext_emit_decl_expr_list_ignore_result(context, ast->if_stmt.decl);
|
||||
|
||||
// We need at least the exit block and the "then" block.
|
||||
LLVMBasicBlockRef exit_block = LLVMCreateBasicBlockInContext(context->context, "if.exit");
|
||||
@@ -107,10 +129,8 @@ void gencontext_emit_if(GenContext *context, Ast *ast)
|
||||
else_block = LLVMCreateBasicBlockInContext(context->context, "if.else");
|
||||
}
|
||||
|
||||
assert(ast->if_stmt.cond->cond_stmt.expr->type->type_kind == TYPE_BOOL);
|
||||
|
||||
// Output boolean value and switch.
|
||||
LLVMValueRef value = gencontext_emit_expr(context, ast->if_stmt.cond->cond_stmt.expr);
|
||||
LLVMValueRef value = gencontext_emit_decl_expr_list(context, ast->if_stmt.cond, true);
|
||||
gencontext_emit_cond_br(context, value, then_block, else_block ? else_block : exit_block);
|
||||
|
||||
// Emit the 'then' code.
|
||||
@@ -169,12 +189,7 @@ void gencontext_emit_for_stmt(GenContext *context, Ast *ast)
|
||||
{
|
||||
// First, emit all inits.
|
||||
|
||||
Ast **init_stmts = ast->for_stmt.init;
|
||||
|
||||
VECEACH(init_stmts, i)
|
||||
{
|
||||
gencontext_emit_stmt(context, init_stmts[i]);
|
||||
}
|
||||
if (ast->for_stmt.init) gencontext_emit_decl_expr_list_ignore_result(context, ast->for_stmt.init);
|
||||
|
||||
// We have 3 optional parts, which makes this code bit complicated.
|
||||
LLVMBasicBlockRef exit_block = gencontext_create_free_block(context, "for.exit");
|
||||
@@ -203,7 +218,7 @@ void gencontext_emit_for_stmt(GenContext *context, Ast *ast)
|
||||
// Emit cond
|
||||
gencontext_emit_br(context, cond_block);
|
||||
gencontext_emit_block(context, cond_block);
|
||||
value = gencontext_emit_expr(context, ast->for_stmt.cond->cond_stmt.expr);
|
||||
value = gencontext_emit_expr(context, ast->for_stmt.cond);
|
||||
// If we have a body, conditionally jump to it.
|
||||
if (body_block)
|
||||
{
|
||||
@@ -236,7 +251,7 @@ void gencontext_emit_for_stmt(GenContext *context, Ast *ast)
|
||||
{
|
||||
// Emit the block
|
||||
gencontext_emit_block(context, inc_block);
|
||||
gencontext_emit_stmt(context, ast->for_stmt.incr);
|
||||
gencontext_emit_expr(context, ast->for_stmt.incr);
|
||||
}
|
||||
|
||||
// Loop back.
|
||||
@@ -247,6 +262,48 @@ void gencontext_emit_for_stmt(GenContext *context, Ast *ast)
|
||||
gencontext_pop_break_continue(context);
|
||||
}
|
||||
|
||||
void gencontext_emit_while_stmt(GenContext *context, Ast *ast)
|
||||
{
|
||||
// First, emit all inits.
|
||||
|
||||
if (ast->while_stmt.decl) gencontext_emit_decl_expr_list_ignore_result(context, ast->while_stmt.decl);
|
||||
|
||||
|
||||
LLVMBasicBlockRef exit_block = gencontext_create_free_block(context, "while.exit");
|
||||
LLVMBasicBlockRef begin_block = gencontext_create_free_block(context, "while.begin");
|
||||
LLVMBasicBlockRef body_block = ast->while_stmt.body->compound_stmt.stmts ? gencontext_create_free_block(context, "while.body") : NULL;
|
||||
|
||||
gencontext_push_break_continue(context, exit_block, begin_block, NULL);
|
||||
|
||||
// Emit cond
|
||||
gencontext_emit_br(context, begin_block);
|
||||
gencontext_emit_block(context, begin_block);
|
||||
LLVMValueRef value = gencontext_emit_decl_expr_list(context, ast->while_stmt.cond, true);
|
||||
// If we have a body, conditionally jump to it.
|
||||
if (body_block)
|
||||
{
|
||||
gencontext_emit_cond_br(context, value, body_block, exit_block);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise jump to inc or cond depending on what's available.
|
||||
gencontext_emit_cond_br(context, value, begin_block, exit_block);
|
||||
}
|
||||
|
||||
if (body_block)
|
||||
{
|
||||
gencontext_emit_block(context, body_block);
|
||||
gencontext_emit_stmt(context, ast->while_stmt.body);
|
||||
}
|
||||
|
||||
// Loop back.
|
||||
gencontext_emit_br(context, begin_block);
|
||||
|
||||
// And insert exit block
|
||||
gencontext_emit_block(context, exit_block);
|
||||
gencontext_pop_break_continue(context);
|
||||
}
|
||||
|
||||
void gencontext_emit_do_stmt(GenContext *context, Ast *ast)
|
||||
{
|
||||
LLVMBasicBlockRef exit_block = gencontext_create_free_block(context, "do.exit");
|
||||
@@ -305,7 +362,8 @@ void gencontext_emit_label(GenContext *context, Ast *ast)
|
||||
|
||||
void gencontext_emit_switch(GenContext *context, Ast *ast)
|
||||
{
|
||||
LLVMValueRef switch_value = gencontext_emit_cond(context, ast->switch_stmt.cond);
|
||||
if (ast->switch_stmt.decl) gencontext_emit_decl_expr_list_ignore_result(context, ast->switch_stmt.decl);
|
||||
LLVMValueRef switch_value = gencontext_emit_decl_expr_list(context, ast->switch_stmt.cond, false);
|
||||
|
||||
size_t cases = vec_size(ast->switch_stmt.cases);
|
||||
if (!cases)
|
||||
@@ -426,6 +484,9 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
|
||||
case AST_FOR_STMT:
|
||||
gencontext_emit_for_stmt(context, ast);
|
||||
break;
|
||||
case AST_WHILE_STMT:
|
||||
gencontext_emit_while_stmt(context, ast);
|
||||
break;
|
||||
case AST_DO_STMT:
|
||||
gencontext_emit_do_stmt(context, ast);
|
||||
break;
|
||||
@@ -435,7 +496,6 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
|
||||
break;
|
||||
case AST_NOP_STMT:
|
||||
break;
|
||||
case AST_WHILE_STMT:
|
||||
case AST_CATCH_STMT:
|
||||
case AST_DEFER_STMT:
|
||||
case AST_TRY_STMT:
|
||||
@@ -445,7 +505,6 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
|
||||
case AST_ASM_STMT:
|
||||
TODO
|
||||
case AST_ATTRIBUTE:
|
||||
case AST_COND_STMT:
|
||||
case AST_CT_IF_STMT:
|
||||
case AST_CT_ELIF_STMT:
|
||||
case AST_CT_ELSE_STMT:
|
||||
@@ -455,6 +514,7 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
|
||||
case AST_CT_CASE_STMT:
|
||||
case AST_GENERIC_CASE_STMT:
|
||||
case AST_GENERIC_DEFAULT_STMT:
|
||||
case AST_DECL_EXPR_LIST:
|
||||
UNREACHABLE
|
||||
case AST_LABEL:
|
||||
gencontext_emit_label(context, ast);
|
||||
@@ -462,9 +522,6 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
|
||||
case AST_GOTO_STMT:
|
||||
gencontext_emit_jmp(context, ast->goto_stmt.label->label_stmt.backend_value);
|
||||
break;
|
||||
case AST_STMT_LIST:
|
||||
gencontext_emit_stmt_list(context, ast);
|
||||
break;
|
||||
case AST_SWITCH_STMT:
|
||||
gencontext_emit_switch(context, ast);
|
||||
break;
|
||||
|
||||
@@ -436,6 +436,12 @@ static TypeInfo *parse_type_expression(void)
|
||||
return type_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse ident ('=' expr)?
|
||||
* @param local
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
static inline Decl *parse_decl_after_type(bool local, TypeInfo *type)
|
||||
{
|
||||
if (tok.type == TOKEN_LPAREN)
|
||||
@@ -450,66 +456,19 @@ static inline Decl *parse_decl_after_type(bool local, TypeInfo *type)
|
||||
|
||||
Visibility visibility = local ? VISIBLE_LOCAL : VISIBLE_MODULE;
|
||||
Decl *decl = decl_new_var(name, type, VARDECL_LOCAL, visibility);
|
||||
Decl *main_decl = decl;
|
||||
|
||||
while (1)
|
||||
if (tok.type == TOKEN_EQ)
|
||||
{
|
||||
if (tok.type == TOKEN_RPAREN || tok.type == TOKEN_EOS)
|
||||
if (!decl)
|
||||
{
|
||||
if (!decl)
|
||||
{
|
||||
SEMA_ERROR(tok, "Expected an identifier before '%s'.", token_type_to_string(tok.type));
|
||||
return &poisoned_decl;
|
||||
}
|
||||
return main_decl;
|
||||
SEMA_ERROR(tok, "Expected an identifier before '='.");
|
||||
return &poisoned_decl;
|
||||
}
|
||||
|
||||
if (tok.type == TOKEN_EQ)
|
||||
{
|
||||
if (!decl)
|
||||
{
|
||||
SEMA_ERROR(tok, "Expected an identifier before '='.");
|
||||
return &poisoned_decl;
|
||||
}
|
||||
advance_and_verify(TOKEN_EQ);
|
||||
decl->var.init_expr = TRY_EXPR_OR(parse_initializer(), &poisoned_decl);
|
||||
decl = NULL;
|
||||
if (try_consume(TOKEN_COMMA)) continue;
|
||||
return main_decl;
|
||||
}
|
||||
|
||||
if (tok.type == TOKEN_COMMA)
|
||||
{
|
||||
if (!decl)
|
||||
{
|
||||
SEMA_ERROR(tok, "Expected identifier.");
|
||||
return &poisoned_decl;
|
||||
}
|
||||
advance();
|
||||
decl = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tok.type == TOKEN_IDENT)
|
||||
{
|
||||
Decl *new_decl = decl_new_var(tok, type, VARDECL_LOCAL, visibility);
|
||||
advance();
|
||||
if (main_decl->decl_kind == DECL_MULTI_DECL)
|
||||
{
|
||||
main_decl->multi_decl = VECADD(main_decl->multi_decl, new_decl);
|
||||
decl = new_decl;
|
||||
continue;
|
||||
}
|
||||
Decl *multi = decl_new(DECL_MULTI_DECL, main_decl->name, visibility);
|
||||
multi->multi_decl = VECADD(multi->multi_decl, main_decl);
|
||||
multi->multi_decl = VECADD(multi->multi_decl, new_decl);
|
||||
main_decl = multi;
|
||||
decl = new_decl;
|
||||
continue;
|
||||
}
|
||||
|
||||
type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl);
|
||||
advance_and_verify(TOKEN_EQ);
|
||||
decl->var.init_expr = TRY_EXPR_OR(parse_initializer(), &poisoned_decl);
|
||||
}
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -578,56 +537,52 @@ static Ast *parse_expr_stmt(void)
|
||||
* ;
|
||||
* @return Ast *
|
||||
*/
|
||||
static inline Ast *parse_expression_list(void)
|
||||
static inline Expr *parse_expression_list(void)
|
||||
{
|
||||
Ast *statement_list = new_ast(AST_STMT_LIST, tok);
|
||||
Ast **stmts = NULL;
|
||||
Expr *expr_list = expr_new(EXPR_EXPRESSION_LIST, tok);
|
||||
do
|
||||
{
|
||||
Expr *expr = TRY_EXPR_OR(parse_expr(), &poisoned_ast);
|
||||
Ast *ast = new_ast(AST_EXPR_STMT, expr->loc);
|
||||
ast->expr_stmt = expr;
|
||||
stmts = VECADD(stmts, ast);
|
||||
Expr *expr = TRY_EXPR_OR(parse_expr(), &poisoned_expr);
|
||||
vec_add(expr_list->expression_list, expr);
|
||||
} while (try_consume(TOKEN_COMMA));
|
||||
statement_list->stmt_list = stmts;
|
||||
return statement_list;
|
||||
return expr_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* decl_or_expr_list
|
||||
* : expression_list
|
||||
* | declaration_list
|
||||
* ;
|
||||
* decl_expr_list
|
||||
* : expression
|
||||
* | declaration
|
||||
* | decl_expr_list ',' expression
|
||||
* | decl_expr_list ',' declaration
|
||||
* ;
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static inline bool parse_decl_expr_list(Ast ***stmt_list)
|
||||
static inline Ast *parse_decl_expr_list(void)
|
||||
{
|
||||
Expr *expr = NULL;
|
||||
TypeInfo *type = NULL;
|
||||
|
||||
if (!parse_type_or_expr(&expr, &type)) return false;
|
||||
|
||||
|
||||
if (expr)
|
||||
Ast *decl_expr = new_ast(AST_DECL_EXPR_LIST, tok);
|
||||
decl_expr->decl_expr_stmt = NULL;
|
||||
while (1)
|
||||
{
|
||||
while (1)
|
||||
Expr *expr = NULL;
|
||||
TypeInfo *type = NULL;
|
||||
if (!parse_type_or_expr(&expr, &type)) return false;
|
||||
if (expr)
|
||||
{
|
||||
Ast *stmt = new_ast(AST_EXPR_STMT, expr->loc);
|
||||
stmt->expr_stmt = expr;
|
||||
*stmt_list = VECADD(*stmt_list, stmt);
|
||||
if (!try_consume(TOKEN_COMMA)) break;
|
||||
expr = TRY_EXPR_OR(parse_expr(), &poisoned_ast);
|
||||
vec_add(decl_expr->decl_expr_stmt, stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
Decl *decl = TRY_DECL_OR(parse_decl_after_type(false, type), &poisoned_ast);
|
||||
Ast *stmt = new_ast(AST_DECLARE_STMT, decl->name);
|
||||
stmt->declare_stmt = decl;
|
||||
vec_add(decl_expr->decl_expr_stmt, stmt);
|
||||
}
|
||||
if (!try_consume(TOKEN_COMMA)) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Decl *decl = TRY_DECL_OR(parse_decl_after_type(false, type), &poisoned_ast);
|
||||
Ast *stmt = new_ast(AST_DECLARE_STMT, decl->name);
|
||||
stmt->declare_stmt = decl;
|
||||
*stmt_list = VECADD(*stmt_list, stmt);
|
||||
}
|
||||
return true;
|
||||
return decl_expr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -636,34 +591,23 @@ static inline bool parse_decl_expr_list(Ast ***stmt_list)
|
||||
* | declaration_list ';' decl_or_expr_list
|
||||
* ;
|
||||
*
|
||||
* @return Ast*
|
||||
* @return true if it succeeds
|
||||
*/
|
||||
static inline Ast *parse_control_expression()
|
||||
static inline bool parse_control_expression(Ast **decls, Ast **exprs)
|
||||
{
|
||||
Ast *stmt_list = AST_NEW(AST_STMT_LIST, tok);
|
||||
|
||||
Ast ***stmt_ref = &stmt_list->stmt_list;
|
||||
|
||||
if (!parse_decl_expr_list(stmt_ref)) return &poisoned_ast;
|
||||
|
||||
assert(*stmt_ref != NULL);
|
||||
if (VECLAST(*stmt_ref)->ast_kind == AST_EXPR_STMT)
|
||||
{
|
||||
if (tok.type == TOKEN_EOS)
|
||||
{
|
||||
SEMA_ERROR(tok, "Unexpected ';'.");
|
||||
return &poisoned_ast;
|
||||
}
|
||||
return stmt_list;
|
||||
}
|
||||
*exprs = TRY_AST_OR(parse_decl_expr_list(), false);
|
||||
|
||||
if (!try_consume(TOKEN_EOS))
|
||||
{
|
||||
return stmt_list;
|
||||
*decls = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!parse_decl_expr_list(stmt_ref)) return &poisoned_ast;
|
||||
return stmt_list;
|
||||
*decls = *exprs;
|
||||
|
||||
*exprs = TRY_AST_OR(parse_decl_expr_list(), false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -679,10 +623,9 @@ static inline Ast* parse_if_stmt(void)
|
||||
Ast *if_ast = AST_NEW(AST_IF_STMT, tok);
|
||||
advance_and_verify(TOKEN_IF);
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_ast);
|
||||
Ast *cond = TRY_AST(parse_control_expression());
|
||||
if (!parse_control_expression(&if_ast->if_stmt.decl, &if_ast->if_stmt.cond)) return &poisoned_ast;
|
||||
CONSUME_OR(TOKEN_RPAREN, &poisoned_ast);
|
||||
Ast *stmt = TRY_AST(parse_stmt());
|
||||
if_ast->if_stmt.cond = cond;
|
||||
if_ast->if_stmt.then_body = stmt;
|
||||
if (stmt->ast_kind != AST_COMPOUND_STMT || tok.type != TOKEN_ELSE)
|
||||
{
|
||||
@@ -704,7 +647,7 @@ static inline Ast* parse_while_stmt(void)
|
||||
|
||||
advance_and_verify(TOKEN_WHILE);
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_ast);
|
||||
while_ast->while_stmt.cond = TRY_AST(parse_control_expression());
|
||||
if (!parse_control_expression(&while_ast->while_stmt.decl, &while_ast->while_stmt.cond)) return &poisoned_ast;
|
||||
CONSUME_OR(TOKEN_RPAREN, &poisoned_ast);
|
||||
while_ast->while_stmt.body = TRY_AST(parse_stmt());
|
||||
return while_ast;
|
||||
@@ -793,7 +736,7 @@ static inline Ast* parse_switch_stmt(void)
|
||||
Ast *switch_ast = AST_NEW(AST_SWITCH_STMT, tok);
|
||||
advance_and_verify(TOKEN_SWITCH);
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_ast);
|
||||
switch_ast->switch_stmt.cond = TRY_AST(parse_control_expression());
|
||||
if (!parse_control_expression(&switch_ast->switch_stmt.decl, &switch_ast->switch_stmt.cond)) return &poisoned_ast;
|
||||
CONSUME_OR(TOKEN_RPAREN, &poisoned_ast);
|
||||
switch_ast->switch_stmt.body = TRY_AST(parse_compound_stmt());
|
||||
return switch_ast;
|
||||
@@ -801,13 +744,12 @@ static inline Ast* parse_switch_stmt(void)
|
||||
|
||||
/**
|
||||
* for_statement
|
||||
* : FOR '(' decl_or_expr_list ';' expression_statement ')' statement
|
||||
* | FOR '(' decl_or_expr_list ';' expression_statement expression_list ')' statement
|
||||
* ;
|
||||
*
|
||||
* decl_or_expr_list
|
||||
* : expression_list
|
||||
* | declaration_list
|
||||
* : FOR '(' decl_expr_list ';' expression ';' ')' statement
|
||||
* | FOR '(' decl_expr_list ';' ';' expression_list ')' statement
|
||||
* | FOR '(' decl_expr_list ';' expression ';' expression_list ')' statement
|
||||
* | FOR '(' ';' expression ';' ')' statement
|
||||
* | FOR '(' ';' ';' expression_list ')' statement
|
||||
* | FOR '(' ';' expression ';' expression_list ')' statement
|
||||
* ;
|
||||
*
|
||||
* @return Ast*
|
||||
@@ -818,31 +760,32 @@ static inline Ast* parse_for_stmt(void)
|
||||
advance_and_verify(TOKEN_FOR);
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_ast);
|
||||
|
||||
Ast *cond = new_ast(AST_COND_STMT, tok);
|
||||
|
||||
if (!parse_decl_expr_list(&cond->cond_stmt.stmts)) return &poisoned_ast;
|
||||
|
||||
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
|
||||
if (tok.type != TOKEN_EOS)
|
||||
{
|
||||
cond->cond_stmt.expr = TRY_EXPR_OR(parse_expr(), &poisoned_ast);
|
||||
ast->for_stmt.init = TRY_AST(parse_decl_expr_list());
|
||||
}
|
||||
else
|
||||
{
|
||||
ast->for_stmt.init = NULL;
|
||||
}
|
||||
|
||||
ast->for_stmt.cond = cond;
|
||||
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
|
||||
|
||||
if (!try_consume(TOKEN_RPAREN))
|
||||
{
|
||||
ast->for_stmt.incr = parse_expression_list();
|
||||
CONSUME_OR(TOKEN_RPAREN, &poisoned_ast);
|
||||
}
|
||||
ast->for_stmt.cond = tok.type == TOKEN_EOS ? NULL : TRY_EXPR_OR(parse_expr(), &poisoned_ast);
|
||||
|
||||
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
|
||||
|
||||
ast->for_stmt.incr = tok.type == TOKEN_RPAREN ? NULL : TRY_EXPR_OR(parse_expression_list(), &poisoned_ast);
|
||||
|
||||
CONSUME_OR(TOKEN_RPAREN, &poisoned_ast);
|
||||
|
||||
ast->for_stmt.body = TRY_AST(parse_stmt());
|
||||
return ast;
|
||||
}
|
||||
|
||||
static inline Expr* parse_constant_expr(void)
|
||||
{
|
||||
return parse_precedence(PREC_CONDITIONAL);
|
||||
return parse_precedence(PREC_TERNARY);
|
||||
}
|
||||
/**
|
||||
* case_stmt
|
||||
@@ -2677,27 +2620,27 @@ void parse_file(Context *context)
|
||||
|
||||
#define CHECK_EXPR(_expr) do { if (!expr_ok(_expr)) return _expr; } while(0)
|
||||
|
||||
static Expr *parse_conditional_expr(Expr *left_side)
|
||||
static Expr *parse_ternary_expr(Expr *left_side)
|
||||
{
|
||||
assert(expr_ok(left_side));
|
||||
Expr *expr_ternary = EXPR_NEW_EXPR(EXPR_CONDITIONAL, left_side);
|
||||
expr_ternary->conditional_expr.cond = left_side;
|
||||
Expr *expr_ternary = EXPR_NEW_EXPR(EXPR_TERNARY, left_side);
|
||||
expr_ternary->ternary_expr.cond = left_side;
|
||||
|
||||
// Check for elvis
|
||||
if (try_consume(TOKEN_ELVIS))
|
||||
{
|
||||
expr_ternary->conditional_expr.then_expr = NULL;
|
||||
expr_ternary->ternary_expr.then_expr = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
advance_and_verify(TOKEN_QUESTION);
|
||||
Expr *true_expr = TRY_EXPR_OR(parse_precedence(PREC_CONDITIONAL + 1), &poisoned_expr);
|
||||
expr_ternary->conditional_expr.then_expr = true_expr;
|
||||
Expr *true_expr = TRY_EXPR_OR(parse_precedence(PREC_TERNARY + 1), &poisoned_expr);
|
||||
expr_ternary->ternary_expr.then_expr = true_expr;
|
||||
CONSUME_OR(TOKEN_COLON, &poisoned_expr);
|
||||
}
|
||||
|
||||
Expr *false_expr = TRY_EXPR_OR(parse_precedence(PREC_CONDITIONAL + 1), &poisoned_expr);
|
||||
expr_ternary->conditional_expr.else_expr = false_expr;
|
||||
Expr *false_expr = TRY_EXPR_OR(parse_precedence(PREC_TERNARY + 1), &poisoned_expr);
|
||||
expr_ternary->ternary_expr.else_expr = false_expr;
|
||||
return expr_ternary;
|
||||
}
|
||||
|
||||
@@ -3302,8 +3245,8 @@ static Expr *parse_cast_expr(Expr *left)
|
||||
}
|
||||
|
||||
ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_QUESTION] = { NULL, parse_conditional_expr, PREC_CONDITIONAL },
|
||||
[TOKEN_ELVIS] = { NULL, parse_conditional_expr, PREC_CONDITIONAL },
|
||||
[TOKEN_QUESTION] = { NULL, parse_ternary_expr, PREC_TERNARY },
|
||||
[TOKEN_ELVIS] = { NULL, parse_ternary_expr, PREC_TERNARY },
|
||||
[TOKEN_PLUSPLUS] = { parse_unary_expr, parse_post_unary, PREC_CALL },
|
||||
[TOKEN_MINUSMINUS] = { parse_unary_expr, parse_post_unary, PREC_CALL },
|
||||
[TOKEN_LPAREN] = { parse_grouping_expr, parse_call_expr, PREC_CALL },
|
||||
|
||||
@@ -6,7 +6,20 @@
|
||||
|
||||
typedef bool(*AstAnalysis)(Context *, Ast*);
|
||||
|
||||
bool sema_analyse_stmt_list(Context *context, Ast *statement);
|
||||
static inline Type *ast_cond_type(Ast *ast)
|
||||
{
|
||||
assert(ast->ast_kind == AST_DECL_EXPR_LIST);
|
||||
Ast *last = VECLAST(ast->decl_expr_stmt);
|
||||
switch (last->ast_kind)
|
||||
{
|
||||
case AST_EXPR_STMT:
|
||||
return last->expr_stmt->type;
|
||||
case AST_DECLARE_STMT:
|
||||
return last->declare_stmt->var.type_info->type;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
|
||||
void sema_init(File *file)
|
||||
{
|
||||
@@ -440,35 +453,6 @@ static inline bool decl_or_expr_to_expr_stmt(Context *context, Ast *stmt)
|
||||
assert(stmt->ast_kind == AST_DECLARE_STMT);
|
||||
stmt->ast_kind = AST_EXPR_STMT;
|
||||
Decl *decl = stmt->declare_stmt;
|
||||
if (decl->decl_kind == DECL_MULTI_DECL)
|
||||
{
|
||||
Expr *list = expr_new(EXPR_EXPRESSION_LIST, stmt->token);
|
||||
Expr **exprs = NULL;
|
||||
VECEACH(decl->multi_decl, i)
|
||||
{
|
||||
Decl *var = decl->multi_decl[i];
|
||||
assert(var->decl_kind == DECL_VAR);
|
||||
assert(var->decl_kind == VARDECL_LOCAL);
|
||||
if (var->var.init_expr == NULL)
|
||||
{
|
||||
SEMA_ERROR(var->name, "'%s' needs to be assigned.", var->name.string);
|
||||
return false;
|
||||
}
|
||||
Expr *assign_expr = expr_new(EXPR_BINARY, stmt->token);
|
||||
assign_expr->resolve_status = RESOLVE_DONE;
|
||||
assign_expr->binary_expr.operator = BINARYOP_ASSIGN;
|
||||
Expr *identifier = expr_new(EXPR_IDENTIFIER, var->name);
|
||||
identifier->resolve_status = RESOLVE_DONE;
|
||||
identifier->identifier_expr.decl = var;
|
||||
identifier->type = var->var.type_info->type;
|
||||
assign_expr->binary_expr.left = identifier;
|
||||
assign_expr->binary_expr.right = var->var.init_expr;
|
||||
exprs = VECADD(exprs, assign_expr);
|
||||
}
|
||||
list->expression_list = exprs;
|
||||
stmt->expr_stmt = list;
|
||||
return true;
|
||||
}
|
||||
assert(decl->decl_kind == DECL_VAR);
|
||||
assert(decl->decl_kind == VARDECL_LOCAL);
|
||||
if (decl->var.init_expr == NULL)
|
||||
@@ -480,53 +464,75 @@ static inline bool decl_or_expr_to_expr_stmt(Context *context, Ast *stmt)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_flatten_cond(Context *context, Ast *stmt, bool cast_to_bool)
|
||||
static inline bool sema_analyse_decl_expr_list(Context *context, Ast *stmt)
|
||||
{
|
||||
assert(stmt->ast_kind == AST_STMT_LIST);
|
||||
assert(vec_size(stmt->stmt_list) > 0);
|
||||
assert(stmt->ast_kind == AST_DECL_EXPR_LIST);
|
||||
|
||||
// The common case:
|
||||
if (vec_size(stmt->stmt_list) == 1 && stmt->stmt_list[0]->ast_kind == AST_EXPR_STMT)
|
||||
VECEACH(stmt->decl_expr_stmt, i)
|
||||
{
|
||||
Expr *expr = stmt->stmt_list[0]->expr_stmt;
|
||||
if (cast_to_bool && !cast(expr, type_bool, CAST_TYPE_IMPLICIT)) return false;
|
||||
stmt->ast_kind = AST_COND_STMT;
|
||||
stmt->cond_stmt.expr = expr;
|
||||
stmt->cond_stmt.stmts = NULL;
|
||||
return true;
|
||||
if (!sema_analyse_statement(context, stmt->decl_expr_stmt[i])) return false;
|
||||
}
|
||||
Ast **new_list = NULL;
|
||||
Expr *last = NULL;
|
||||
|
||||
unsigned last_index = vec_size(stmt->stmt_list) - 1;
|
||||
VECEACH(stmt->stmt_list, i)
|
||||
{
|
||||
if (!convert_stmt_for_cond(context, stmt->stmt_list[i], &new_list, &last, last_index == i)) return false;
|
||||
}
|
||||
if (cast_to_bool && !cast(last, type_bool, CAST_TYPE_IMPLICIT)) return false;
|
||||
stmt->ast_kind = AST_COND_STMT;
|
||||
stmt->cond_stmt.expr = last;
|
||||
stmt->cond_stmt.stmts = new_list;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_cond(Context *context, Ast *stmt, bool cast_to_bool)
|
||||
{
|
||||
assert(stmt->ast_kind == AST_DECL_EXPR_LIST);
|
||||
|
||||
size_t size = vec_size(stmt->decl_expr_stmt);
|
||||
if (!size)
|
||||
{
|
||||
SEMA_ERROR(stmt->token, "Expected a boolean expression");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sema_analyse_decl_expr_list(context, stmt)) return false;
|
||||
|
||||
Ast *last = stmt->decl_expr_stmt[size - 1];
|
||||
switch (last->ast_kind)
|
||||
{
|
||||
case AST_EXPR_STMT:
|
||||
if (cast_to_bool)
|
||||
{
|
||||
if (!cast_implicit(last->expr_stmt, type_bool)) return false;
|
||||
}
|
||||
return true;
|
||||
case AST_DECLARE_STMT:
|
||||
{
|
||||
Expr *init = last->declare_stmt->var.init_expr;
|
||||
if (!init)
|
||||
{
|
||||
SEMA_ERROR(last->token, "Expected a declaration with initializer.");
|
||||
return false;
|
||||
}
|
||||
if (cast_to_bool && init->type->type_kind != TYPE_BOOL &&
|
||||
cast_to_bool_kind(last->declare_stmt->var.type_info->type) == CAST_ERROR)
|
||||
{
|
||||
SEMA_ERROR(last->declare_stmt->var.init_expr->loc, "The expression needs to be convertible to a boolean.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_while_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
Ast *decl = statement->while_stmt.decl;
|
||||
Ast *cond = statement->while_stmt.cond;
|
||||
Ast *body = statement->while_stmt.body;
|
||||
assert(cond && cond->ast_kind == AST_STMT_LIST);
|
||||
context_push_scope_with_flags(context, SCOPE_CONTROL);
|
||||
bool success = sema_analyse_statement(context, cond);
|
||||
success = success && sema_flatten_cond(context, cond, true);
|
||||
bool success = !decl || sema_analyse_statement(context, decl);
|
||||
success = success && sema_analyse_cond(context, cond, true);
|
||||
|
||||
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise)
|
||||
success = success && sema_analyse_statement(context, body);
|
||||
context_pop_scope(context);
|
||||
context_pop_scope(context);
|
||||
if (!success) return false;
|
||||
statement->ast_kind = AST_FOR_STMT;
|
||||
statement->for_stmt.cond = cond;
|
||||
statement->for_stmt.incr = NULL;
|
||||
statement->for_stmt.body = body;
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -563,10 +569,6 @@ static inline bool sema_analyse_multi_decl(Context *context, Ast *statement)
|
||||
static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
Decl *decl = statement->declare_stmt;
|
||||
if (decl->decl_kind == DECL_MULTI_DECL)
|
||||
{
|
||||
return sema_analyse_multi_decl(context, statement);
|
||||
}
|
||||
return sema_analyse_var_decl(context, decl);
|
||||
}
|
||||
|
||||
@@ -599,21 +601,14 @@ static inline bool sema_analyse_default_stmt(Context *context, Ast *statement)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sema_analyse_stmt_list(Context *context, Ast *statement)
|
||||
{
|
||||
VECEACH(statement->stmt_list, i)
|
||||
{
|
||||
if (!sema_analyse_statement(context, statement->stmt_list[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
context_push_scope_with_flags(context, SCOPE_CONTROL);
|
||||
|
||||
bool success = sema_analyse_statement(context, statement->for_stmt.cond);
|
||||
success = success && (!statement->for_stmt.incr || sema_analyse_statement(context, statement->for_stmt.incr));
|
||||
bool success = !statement->for_stmt.init || sema_analyse_statement(context, statement->for_stmt.init);
|
||||
|
||||
success = success && (!statement->for_stmt.cond || sema_analyse_expr(context, type_bool, statement->for_stmt.cond));
|
||||
success = success && (!statement->for_stmt.incr || sema_analyse_expr(context, NULL, statement->for_stmt.incr));
|
||||
context_pop_scope(context);
|
||||
if (!success) return false;
|
||||
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise)
|
||||
@@ -648,8 +643,7 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
|
||||
context_push_scope(context);
|
||||
Ast *cond = statement->if_stmt.cond;
|
||||
context_push_scope_with_flags(context, SCOPE_CONTROL);
|
||||
bool success = sema_analyse_statement(context, cond);
|
||||
success = success && sema_flatten_cond(context, cond, true);
|
||||
bool success = sema_analyse_cond(context, cond, true);
|
||||
context_push_scope(context);
|
||||
success = success && sema_analyse_statement(context, statement->if_stmt.then_body);
|
||||
context_pop_scope(context);
|
||||
@@ -864,14 +858,14 @@ static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *c
|
||||
|
||||
static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
Ast *cond = statement->switch_stmt.cond;
|
||||
context_push_scope_with_flags(context, SCOPE_CONTROL);
|
||||
bool success = sema_analyse_statement(context, cond);
|
||||
success = success && sema_flatten_cond(context, cond, false);
|
||||
bool success = sema_analyse_statement(context, statement->switch_stmt.cond);
|
||||
Ast *cond = statement->switch_stmt.cond;
|
||||
success = success && sema_analyse_cond(context, cond, false);
|
||||
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_NEXT); // NOLINT(hicpp-signed-bitwise)
|
||||
Ast *body = statement->switch_stmt.body;
|
||||
assert(body->ast_kind == AST_COMPOUND_STMT);
|
||||
Type *switch_type = cond->cond_stmt.expr->type->canonical;
|
||||
Type *switch_type = ast_cond_type(cond)->canonical;
|
||||
if (!type_is_integer(switch_type))
|
||||
{
|
||||
SEMA_ERROR(cond->token, "Expected an integer or enum type, was '%s'.", type_to_error_string(switch_type));
|
||||
@@ -945,7 +939,7 @@ static AstAnalysis AST_ANALYSIS[AST_WHILE_STMT + 1] =
|
||||
[AST_NEXT_STMT] = NULL, // Never reached
|
||||
[AST_VOLATILE_STMT] = &sema_analyse_volatile_stmt,
|
||||
[AST_WHILE_STMT] = &sema_analyse_while_stmt,
|
||||
[AST_STMT_LIST] = &sema_analyse_stmt_list
|
||||
[AST_DECL_EXPR_LIST] = &sema_analyse_decl_expr_list,
|
||||
};
|
||||
|
||||
bool sema_analyse_statement(Context *context, Ast *statement)
|
||||
|
||||
Reference in New Issue
Block a user