mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Jumping on else added.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
@@ -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*/,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user