Fixed a lot of while/if/for. ?: now works.

This commit is contained in:
Christoffer Lerno
2019-12-13 00:08:07 +01:00
parent 0492683ca0
commit df4f88dfcc
13 changed files with 525 additions and 403 deletions

View File

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

View File

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

View File

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

View File

@@ -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, // + -

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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