From 93bd0fb337272989b06344778152fd5d9a6144b0 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 5 May 2020 11:28:49 +0200 Subject: [PATCH] Jumping on else added. --- README.md | 2 +- resources/testfragments/super_simple.c3 | 3 + src/build/build_options.c | 2 +- src/build/build_options.h | 9 +- src/compiler/dwarf.h | 2 +- src/compiler/llvm_codegen.c | 2 +- src/compiler/llvm_codegen_expr.c | 12 ++- src/compiler/llvm_codegen_function.c | 8 +- src/compiler/llvm_codegen_module.c | 23 +----- src/compiler/parse_expr.c | 17 +++- src/compiler/parse_stmt.c | 105 ++++++++++++++++-------- src/compiler/parser_internal.h | 1 + src/compiler/sema_expr.c | 11 ++- 13 files changed, 128 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index f5c48ff9d..26dcbf6ba 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ C3 tries to be an alternative in the the C/C++ niche: fast and close to the meta ### Design Principles - Procedural "get things done"-type of language. - Try to stay close to C - only change where truly needed. -- Flawless C integration. +- C ABI compatibility and C C integration. - Learning C3 should be easy for a C programmer. - Dare violating the "close to metal" principle if the value is great. - Data is inert. diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index 523c5f3f8..7c39472d2 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -663,6 +663,9 @@ func int testThrowAny(int x) throws func int oekt() throws { + int z = try testThrow(-1) else goto NEXT; + printf("Skipped.\n"); + NEXT: int x = try testThrow(-3); return x; } diff --git a/src/build/build_options.c b/src/build/build_options.c index d8ac764ea..e4eee10ce 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -315,7 +315,7 @@ void parse_arguments(int argc, const char *argv[]) build_options.emit_bitcode = true; build_options.optimization_level = OPTIMIZATION_NOT_SET; build_options.size_optimization_level = SIZE_OPTIMIZATION_NOT_SET; - build_options.debug_info = false; + build_options.debug_info = DEBUG_INFO_NONE; build_options.debug_mode = false; build_options.command = COMMAND_MISSING; build_options.symtab_size = DEFAULT_SYMTAB_SIZE; diff --git a/src/build/build_options.h b/src/build/build_options.h index 14a716b2b..4c1400b73 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -86,6 +86,13 @@ typedef enum SIZE_OPTIMIZATION_TINY = 2, // -Oz } SizeOptimizationLevel; +typedef enum +{ + DEBUG_INFO_NONE, + DEBUG_INFO_LINE_TABLES, + DEBUG_INFO_FULL +} DebugInfo; + typedef struct { const char* lib_dir[MAX_LIB_DIRS]; @@ -102,7 +109,7 @@ typedef struct DiagnosticsSeverity severity[DIAG_END_SENTINEL]; OptimizationLevel optimization_level; SizeOptimizationLevel size_optimization_level; - bool debug_info; + DebugInfo debug_info; bool debug_mode; bool emit_llvm; bool emit_bitcode; diff --git a/src/compiler/dwarf.h b/src/compiler/dwarf.h index ffd6dde90..89677362a 100644 --- a/src/compiler/dwarf.h +++ b/src/compiler/dwarf.h @@ -281,4 +281,4 @@ #define DW_CFA_lo_user 0x1c #define DW_CFA_hi_user 0x3f -#define DWARF_PRODUCER_NAME "C3 Compiler" \ No newline at end of file +#define DWARF_PRODUCER_NAME "c3c" \ No newline at end of file diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index db8dcdcb2..607249aa3 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -112,7 +112,7 @@ static void gencontext_emit_global_variable_definition(GenContext *context, Decl int alignment = 64; // TODO // Should we set linkage here? - if (context->debug.builder) + if (context->debug.builder && false) { decl->var.backend_debug_ref = LLVMDIBuilderCreateGlobalVariableExpression(context->debug.builder, NULL /*scope*/, diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 8de865b30..9be1bac67 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -811,7 +811,7 @@ LLVMValueRef gencontext_emit_typeid(GenContext *context, Expr *expr) LLVMValueRef gencontext_emit_try_expr(GenContext *context, Expr *expr) { - if (expr->try_expr.else_expr) + if (expr->try_expr.type == TRY_EXPR_ELSE_EXPR) { LLVMBasicBlockRef else_block = gencontext_get_try_target(context, expr); LLVMBasicBlockRef after_catch = gencontext_create_free_block(context, "aftercatch"); @@ -826,6 +826,16 @@ LLVMValueRef gencontext_emit_try_expr(GenContext *context, Expr *expr) gencontext_emit_block(context, after_catch); return gencontext_emit_load(context, expr->try_expr.else_expr->type, res); } + if (expr->try_expr.type == TRY_EXPR_ELSE_JUMP) + { + LLVMBasicBlockRef else_block = gencontext_get_try_target(context, expr); + LLVMBasicBlockRef after_catch = gencontext_create_free_block(context, "aftercatch"); + gencontext_emit_br(context, after_catch); + gencontext_emit_block(context, else_block); + gencontext_emit_stmt(context, expr->try_expr.else_stmt); + gencontext_emit_br(context, after_catch); + gencontext_emit_block(context, after_catch); + } return gencontext_emit_expr(context, expr->try_expr.expr); } diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 7ea406e66..561d3aee5 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -216,19 +216,19 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl) break; } SourcePosition decl_position = source_file_find_position(decl->name_span.loc); - context->debug.function = LLVMDIBuilderCreateFunction(context->debug.builder, + /* context->debug.function = LLVMDIBuilderCreateFunction(context->debug.builder, context->debug.compile_unit, decl->name, source_range_len(decl->name_span), decl->name, source_range_len(decl->name_span), context->debug.file, decl_position.line, - decl->type->backend_debug_type, + decl->type->backend_type, decl->visibility == VISIBLE_LOCAL, 1, decl_position.line, flags, - 0); - LLVMSetSubprogram(decl->func.backend_value, context->debug.function); + build_options.optimization_level != OPTIMIZATION_NONE); + LLVMSetSubprogram(decl->func.backend_value, context->debug.function);*/ } } diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index 66428d6b8..22965f584 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -47,17 +47,17 @@ void gencontext_begin_module(GenContext *context) LLVMSetSourceFileName(context->module, full_path, strlen(context->ast_context->file->full_path)); LLVMSetTarget(context->module, build_options.target); - if (build_options.debug_info) + if (build_options.debug_info != DEBUG_INFO_NONE) { const char *filename = context->ast_context->file->name; const char *dir_path = context->ast_context->file->dir_path; context->debug.builder = LLVMCreateDIBuilder(context->module); context->debug.file = LLVMDIBuilderCreateFile(context->debug.builder, filename, strlen(filename), dir_path, strlen(dir_path)); - bool is_optimized = false; + bool is_optimized = build_options.optimization_level != OPTIMIZATION_NONE; const char *dwarf_flags = ""; unsigned runtime_version = 1; - LLVMDWARFEmissionKind emission_kind = LLVMDWARFEmissionFull; + LLVMDWARFEmissionKind emission_kind = build_options.debug_info == DEBUG_INFO_FULL ? LLVMDWARFEmissionFull : LLVMDWARFEmissionLineTablesOnly; context->debug.compile_unit = LLVMDIBuilderCreateCompileUnit(context->debug.builder, LLVMDWARFSourceLanguageC, context->debug.file, DWARF_PRODUCER_NAME, strlen(DWARF_PRODUCER_NAME), is_optimized, @@ -70,8 +70,6 @@ void gencontext_begin_module(GenContext *context) // We need to remove the context from the cache after this. // This would seem to indicate that we should change Type / actual type. - context->pointer_alignment = LLVMPointerSizeForAS(target_data_layout(), 0); - context->block_global_unique_count = 0; context->ast_alloca_addr_space = target_alloca_addr_space(); @@ -79,21 +77,6 @@ void gencontext_begin_module(GenContext *context) { compiler.type[i]->backend_type = NULL; } -/* - SizeSizeInBytes = - C.toCharUnitsFromBits(C.getTargetInfo().getMaxPointerWidth()).getQuantity(); - IntAlignInBytes = - C.toCharUnitsFromBits(C.getTargetInfo().getIntAlign()).getQuantity(); - IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth()); - IntPtrTy = llvm::IntegerType::get(LLVMContext, - C.getTargetInfo().getMaxPointerWidth()); - Int8PtrTy = Int8Ty->getPointerTo(0); - Int8PtrPtrTy = Int8PtrTy->getPointerTo(0); - AllocaInt8PtrTy = Int8Ty->getPointerTo( - M.getDataLayout().getAllocaAddrSpace()); - ASTAllocaAddressSpace = getTargetCodeGenInfo().getASTAllocaAddressSpace(); -*/ - } diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index d13f17cc6..49224abf0 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -400,21 +400,32 @@ static Expr *parse_try_expr(Context *context, Expr *left) Expr *try_expr = EXPR_NEW_TOKEN(EXPR_TRY, context->tok); advance_and_verify(context, TOKEN_TRY); try_expr->try_expr.expr = TRY_EXPR_OR(parse_precedence(context, PREC_TRY + 1), poisoned_expr); - try_expr->try_expr.type = TRY_EXPR_ELSE_EXPR; + try_expr->try_expr.type = TRY_STMT; if (try_consume(context, TOKEN_ELSE)) { switch (context->tok.type) { + case TOKEN_GOTO: case TOKEN_RETURN: case TOKEN_BREAK: case TOKEN_CONTINUE: case TOKEN_THROW: + { + Ast *ast = TRY_AST_OR(parse_jump_stmt_no_eos(context), poisoned_expr); try_expr->try_expr.type = TRY_EXPR_ELSE_JUMP; - TODO + try_expr->try_expr.else_stmt = ast; + if (context->tok.type != TOKEN_EOS) + { + SEMA_ERROR(ast, "try-else jump statement must end with a ';'"); + return poisoned_expr; + } + break; + } default: + try_expr->try_expr.type = TRY_EXPR_ELSE_EXPR; + try_expr->try_expr.else_expr = TRY_EXPR_OR(parse_precedence(context, PREC_ASSIGNMENT), poisoned_expr); break; } - try_expr->try_expr.else_expr = TRY_EXPR_OR(parse_precedence(context, PREC_ASSIGNMENT), poisoned_expr); } return try_expr; } diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index adf2d41aa..a08967940 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -302,50 +302,51 @@ static inline Ast* parse_for_stmt(Context *context) } /** - * goto_stmt - * : GOTO ct_ident EOS + * goto + * : GOTO ct_ident * ; */ -static inline Ast* parse_goto_stmt(Context *context) +static inline Ast* parse_goto(Context *context) { Ast *ast = AST_NEW_TOKEN(AST_GOTO_STMT, context->tok); advance_and_verify(context, TOKEN_GOTO); ast->goto_stmt.label_name = context->tok.string; if (!consume_const_name(context, "label")) return poisoned_ast; - RETURN_AFTER_EOS(ast); + return ast; } /** * continue_stmt - * : CONTINUE EOS + * : CONTINUE */ -static inline Ast* parse_continue_stmt(Context *context) +static inline Ast* parse_continue(Context *context) { Ast *ast = AST_NEW_TOKEN(AST_CONTINUE_STMT, context->tok); advance_and_verify(context, TOKEN_CONTINUE); - RETURN_AFTER_EOS(ast); + return ast; } + /** - * next_stmt - * : NEXT EOS + * next + * : NEXT */ -static inline Ast* parse_next_stmt(Context *context) +static inline Ast* parse_next(Context *context) { Ast *ast = AST_NEW_TOKEN(AST_NEXT_STMT, context->tok); advance_and_verify(context, TOKEN_NEXT); - RETURN_AFTER_EOS(ast); + return ast; } /** - * break_stmt - * : BREAK EOS + * break + * : BREAK */ -static inline Ast* parse_break_stmt(Context *context) +static inline Ast* parse_break(Context *context) { Ast *ast = AST_NEW_TOKEN(AST_BREAK_STMT, context->tok); advance_and_verify(context, TOKEN_BREAK); - RETURN_AFTER_EOS(ast); + return ast; } /** @@ -434,35 +435,34 @@ static inline Ast *parse_label_stmt(Context *context) /** - * return_stmt - * : RETURN expression EOS - * | RETURN EOS + * return + * : RETURN expression + * | RETURN * ; */ -static inline Ast *parse_return_stmt(Context *context) +static inline Ast *parse_return(Context *context) { advance_and_verify(context, TOKEN_RETURN); Ast *ast = AST_NEW_TOKEN(AST_RETURN_STMT, context->tok); ast->return_stmt.defer = NULL; - if (try_consume(context, TOKEN_EOS)) + if (context->tok.type != TOKEN_EOS) { - ast->return_stmt.expr = NULL; - return ast; + ast->return_stmt.expr = TRY_EXPR_OR(parse_expr(context), poisoned_ast); } - ast->return_stmt.expr = TRY_EXPR_OR(parse_expr(context), poisoned_ast); - RETURN_AFTER_EOS(ast); + return ast; } /** - * throw_stmt - * : THROW expr EOS + * throw + * : THROW expr */ -static inline Ast *parse_throw_stmt(Context *context) +static inline Ast *parse_throw(Context *context) { Ast *ast = AST_NEW_TOKEN(AST_THROW_STMT, context->tok); advance_and_verify(context, TOKEN_THROW); ast->throw_stmt.throw_value = TRY_EXPR_OR(parse_expr(context), poisoned_ast); - RETURN_AFTER_EOS(ast); + RANGE_EXTEND_PREV(ast); + return ast; } /** @@ -486,6 +486,7 @@ static inline bool is_valid_try_statement(TokenType type) case TOKEN_WHILE: case TOKEN_DO: case TOKEN_RETURN: + case TOKEN_LBRACE: return true; default: return false; @@ -667,7 +668,10 @@ Ast *parse_stmt(Context *context) } return parse_expr_stmt(context); case TOKEN_RETURN: - return parse_return_stmt(context); + { + Ast *ast = TRY_AST(parse_return(context)); + RETURN_AFTER_EOS(ast); + } case TOKEN_IF: return parse_if_stmt(context); case TOKEN_WHILE: @@ -677,7 +681,10 @@ Ast *parse_stmt(Context *context) case TOKEN_SWITCH: return parse_switch_stmt(context); case TOKEN_GOTO: - return parse_goto_stmt(context); + { + Ast *ast = TRY_AST(parse_goto(context)); + RETURN_AFTER_EOS(ast); + } case TOKEN_DO: return parse_do_stmt(context); case TOKEN_FOR: @@ -699,15 +706,24 @@ Ast *parse_stmt(Context *context) } return parse_expr_stmt(context); case TOKEN_CONTINUE: - return parse_continue_stmt(context); + { + Ast *ast = TRY_AST(parse_continue(context)); + RETURN_AFTER_EOS(ast); + } case TOKEN_CASE: SEMA_TOKEN_ERROR(context->tok, "'case' was found outside of 'switch', did you mismatch a '{ }' pair?"); advance(context); return poisoned_ast; case TOKEN_BREAK: - return parse_break_stmt(context); + { + Ast *ast = TRY_AST(parse_break(context)); + RETURN_AFTER_EOS(ast); + } case TOKEN_NEXT: - return parse_next_stmt(context); + { + Ast *ast = TRY_AST(parse_next(context)); + RETURN_AFTER_EOS(ast); + } case TOKEN_ASM: return parse_asm_stmt(context); case TOKEN_DEFAULT: @@ -721,7 +737,10 @@ Ast *parse_stmt(Context *context) case TOKEN_CT_FOR: return parse_ct_for_stmt(context); case TOKEN_THROW: - return parse_throw_stmt(context); + { + Ast *ast = TRY_AST(parse_throw(context)); + RETURN_AFTER_EOS(ast); + } case TOKEN_VOLATILE: return parse_volatile_stmt(context); case TOKEN_STAR: @@ -841,6 +860,24 @@ Ast *parse_stmt(Context *context) UNREACHABLE } +Ast *parse_jump_stmt_no_eos(Context *context) +{ + switch (context->tok.type) + { + case TOKEN_GOTO: + return parse_goto(context); + case TOKEN_RETURN: + return parse_return(context); + case TOKEN_BREAK: + return parse_break(context); + case TOKEN_CONTINUE: + return parse_continue(context); + case TOKEN_THROW: + return parse_throw(context); + default: + UNREACHABLE + } +} /** diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index 13fe74ddc..cd253a6e8 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -40,6 +40,7 @@ Expr *parse_initializer(Context *context); Decl *parse_decl(Context *context); Ast *parse_decl_expr_list(Context *context); Ast* parse_compound_stmt(Context *context); +Ast *parse_jump_stmt_no_eos(Context *context); Expr *parse_expression_list(Context *context); bool parse_type_or_expr(Context *context, Expr **expr_ptr, TypeInfo **type_ptr); Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index e38aa94f5..a03e0e409 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2259,7 +2259,7 @@ static inline bool sema_expr_analyse_try(Context *context, Type *to, Expr *expr) break; } } - if (expr->try_expr.else_expr) + if (expr->try_expr.type != TRY_STMT) { CatchInfo info = { .kind = CATCH_TRY_ELSE, .try_else = expr, .defer = context->current_scope->defers.start }; // Absorb all errors. @@ -2273,7 +2273,14 @@ static inline bool sema_expr_analyse_try(Context *context, Type *to, Expr *expr) } // Resize to remove the throws from consideration. vec_resize(context->error_calls, prev_throws); - if (!sema_analyse_expr(context, to, expr->try_expr.else_expr)) return false; + if (expr->try_expr.type == TRY_EXPR_ELSE_JUMP) + { + if (!sema_analyse_statement(context, expr->try_expr.else_stmt)) return false; + } + else + { + if (!sema_analyse_expr(context, to, expr->try_expr.else_expr)) return false; + } } if (!found) {