Jumping on else added.

This commit is contained in:
Christoffer Lerno
2020-05-05 11:28:49 +02:00
parent 982b663f2c
commit 93bd0fb337
13 changed files with 128 additions and 69 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -281,4 +281,4 @@
#define DW_CFA_lo_user 0x1c
#define DW_CFA_hi_user 0x3f
#define DWARF_PRODUCER_NAME "C3 Compiler"
#define DWARF_PRODUCER_NAME "c3c"

View File

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

View File

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

View File

@@ -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);*/
}
}

View File

@@ -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();
*/
}

View File

@@ -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
default:
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;
}
}
return try_expr;
}

View File

@@ -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);
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
}
}
/**

View File

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

View File

@@ -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,8 +2273,15 @@ 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 (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)
{
if (expr->try_expr.type == TRY_STMT)