Improved defer functionality, handling goto, conditional defers, next, break, continue, fixed bugs with module path detection. Improved switch parsing. Better errors on unknown module.

This commit is contained in:
Christoffer Lerno
2020-01-28 23:41:10 +01:00
parent 7b4ed09517
commit b437cb545f
17 changed files with 699 additions and 326 deletions

38
.clang-tidy Normal file
View File

@@ -0,0 +1,38 @@
---
# Configure clang-tidy for this project.
# Disabled:
# -google-readability-namespace-comments the *_CLIENT_NS is a macro, and
# clang-tidy fails to match it against the initial value.
Checks: >
-*,
bugprone-*,
google-*,
misc-*,
modernize-*,
performance-*,
portability-*,
readability-*,
-google-readability-namespace-comments,
-google-runtime-int,
-google-runtime-references,
-misc-non-private-member-variables-in-classes,
-readability-named-parameter,
-readability-braces-around-statements,
-readability-magic-numbers
# Turn all the warnings from the checks above into errors.
WarningsAsErrors: "*"
CheckOptions:
- { key: readability-identifier-naming.StructCase, value: CamelCase }
- { key: readability-identifier-naming.FunctionCase, value: lower_case }
- { key: readability-identifier-naming.VariableCase, value: lower_case }
- { key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE }
- { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE }
- { key: readability-identifier-naming.ConstexprVariableCase, value: CamelCase }
- { key: readability-identifier-naming.ConstexprVariablePrefix, value: k }
- { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase }
- { key: readability-identifier-naming.GlobalConstantPrefix, value: k }
- { key: readability-identifier-naming.StaticConstantCase, value: CamelCase }
- { key: readability-identifier-naming.StaticConstantPrefix, value: k }

View File

@@ -27,11 +27,12 @@ There are some small work being done on the parser here, but most of the structu
- `asm` sections.
- Macro parameter lists to imports.
- auxiliary data for enums.
- Docs not correctly linked to statements/functions/declarations.
- Docs not linked to statements/functions/declarations.
#### What's missing in the semantic analyser
- No handling imports.
- Incomplete handling of imports.
- `next` not correct
- Function signatures incomplete.
- Function typedef not done.
- `asm` not done.
@@ -51,10 +52,6 @@ There are some small work being done on the parser here, but most of the structu
#### What's missing overall
- Exactly how the module system should work together with the import is still
under discussion.
- Exactly how the library imports should work is not 100% decided.
- The compiler currently only works in single file mode.
- Integration with C.
#### What's working?

View File

@@ -120,20 +120,113 @@ func void bob()
long deee = (eok ? a : b) + c;
}
func int if_test(int x)
{
switch (x)
{
case 1:
x += 1;
if (x < 10)
{
defer x += 5;
if (x < 7)
{
defer x += 100;
next;
}
x += 99;
}
next;
default:
x += 2;
break;
}
return 1;
}
func int yyyy(int x)
{
defer printf("A");
if (x > 0) return 2;
defer printf("B");
printf("C");
return 1;
}
func void zzzz()
{
int x = 0;
defer
{
x += 1;
printf("A");
}
defer
{
x += 2;
printf("B");
}
printf("C");
x += 3;
}
func int jumpback(int x)
{
{
defer x += 1;
{
defer x += 2;
LABELX:
x += 3;
}
}
if (x < 100) goto LABELX;
return x + 1;
}
func int xxxx(int x)
{
{
x += 10;
defer printf("XXX");
if (x < 100) goto LABELD;
defer printf("EODfe");
}
{
defer printf("Defer says hello!\n");
LABEL:
LABELD:
x--;
}
if (x > 0) goto LABEL;
if (x > 0) goto LABELD;
return 1;
}
func int main(int x)
{
int efd = 9;
int okfe = 1;
switch (int bobe = okfe > 0 ? 1 : 0)
{
case 0:
defer printf("case0-\n");
case 1:
printf("case 1\n");
defer printf("case1-\n");
if (efd < 10)
{
{
defer printf("ef < 10\n");
if (efd < 7)
{
defer printf("ef < 7\n");
next;
}
}
}
next;
default:
printf("default\n");
break;
}
return 1;
int aa = x++;
int bb = x--;
int cc = ++x;

View File

@@ -6,6 +6,9 @@ import testbaz;
public func void test()
{
Foo x;
baz::foo::test();
foo::test();
baz::foo::Foo y;
foo::Foo d;
Zab z;
}

View File

@@ -893,6 +893,10 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent)
fprint_ast_recursive(file, ast->while_stmt.cond, indent + 1);
fprint_ast_recursive(file, ast->while_stmt.body, indent + 1);
break;
case AST_SCOPED_STMT:
fprintf(file, "(scoped\n");
fprint_ast_recursive(file, ast->scoped_stmt.stmt, indent + 1);
break;
case AST_CT_FOR_STMT:
if (ast->ct_for_stmt.index.string)
{
@@ -946,7 +950,7 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent)
}
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
{
@@ -967,7 +971,7 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent)
case AST_SWITCH_STMT:
fprintf(file, "(switchstmt\n");
fprint_ast_recursive(file, ast->switch_stmt.cond, indent + 1);
fprint_ast_recursive(file, ast->switch_stmt.body, indent + 1);
fprint_asts_recursive(file, ast->switch_stmt.cases, indent + 1);
break;
case AST_CASE_STMT:
fprintf(file, "(case\n");

View File

@@ -26,7 +26,6 @@ typedef struct _TypeInfo TypeInfo;
typedef struct _Expr Expr;
typedef struct _Module Module;
typedef struct _Type Type;
typedef uint16_t DeferId;
typedef bool(*CastFunc)(Expr *, Type *, Type *, Type *, CastType cast_type);
@@ -38,8 +37,8 @@ typedef struct
typedef struct
{
DeferId start;
DeferId end;
Ast *start;
Ast *end;
} DeferList;
typedef struct
@@ -458,6 +457,11 @@ typedef struct
};
} ExprCast;
typedef struct
{
Expr *expr;
DeferList defers;
} ExprScope;
struct _Expr
{
@@ -482,6 +486,7 @@ struct _Expr
ExprType type_expr;
Expr** initializer_expr;
Expr** expression_list;
ExprScope expr_scope;
};
};
@@ -549,15 +554,15 @@ typedef struct
bool has_next;
};
};
Ast *block;
Ast *body;
void *backend_value;
} AstCaseStmt;
typedef struct
{
Ast *decl;
Ast *cond;
Ast *body;
Ast **cases;
} AstSwitchStmt;
@@ -565,32 +570,29 @@ typedef struct
{
Ast *init;
Expr *cond;
Ast *incr;
Expr *incr;
Ast *body;
DeferList cond_defer;
} AstForStmt;
typedef struct
{
GotoType type : 2;
const char *label_name;
Ast *label;
Ast *defer;
DeferList defer;
union
{
struct _Ast *in_defer;
struct _Ast *defer_end;
};
} AstGotoStmt;
typedef struct _AstDeferStmt
{
bool emit_boolean : 1;
struct _Ast *body; // Compound statement
struct _Ast *prev_defer;
DeferId id;
Ast *body; // Compound statement
Ast *prev_defer;
void *bool_var;
} AstDeferStmt;
typedef struct _AstCatchStmt
@@ -613,6 +615,12 @@ typedef struct _AstGenericCaseStmt
struct _Ast *body;
} AstGenericCaseStmt;
typedef struct
{
Ast *stmt;
DeferList defers;
} AstScopedStmt;
typedef struct
{
Expr *cond;
@@ -635,8 +643,14 @@ typedef struct
typedef struct
{
Ast **defers;
} AstContinueStmt;
DeferList defers;
} AstContinueBreakStmt;
typedef struct
{
Ast *prev;
DeferList defers;
} AstNextStmt;
typedef struct _Ast
{
@@ -663,9 +677,10 @@ typedef struct _Ast
AstCaseStmt case_stmt;
AstCtSwitchStmt ct_switch_stmt;
AstCtCaseStmt ct_case_stmt;
AstContinueStmt continue_stmt;
AstContinueBreakStmt continue_stmt;
AstContinueBreakStmt break_stmt;
Ast* ct_default_stmt;
Ast* next_stmt;
AstNextStmt next_stmt;
AstCatchStmt catch_stmt;
AstGotoStmt goto_stmt;
AstForStmt for_stmt;
@@ -676,6 +691,7 @@ typedef struct _Ast
AstGenericCaseStmt generic_case_stmt;
Ast *generic_default_stmt;
Ast** decl_expr_stmt;
AstScopedStmt scoped_stmt;
};
} Ast;
@@ -704,8 +720,7 @@ typedef struct _DynamicScope
ScopeFlags flags_created;
unsigned errors;
Decl **local_decl_start;
DeferId defer_top;
DeferId defer_last;
DeferList defers;
ExitType exit;
} DynamicScope;
@@ -766,10 +781,15 @@ typedef struct _Context
Token next_tok;
struct
{
bool has_stored;
const char *current;
const char *start;
Token tok;
Token next_tok;
Token *lead_comment;
Token *trailing_comment;
Token *next_lead_comment;
unsigned comments;
} stored;
} Context;

View File

@@ -103,6 +103,7 @@ typedef enum
AST_NEXT_STMT,
AST_VOLATILE_STMT,
AST_WHILE_STMT,
AST_SCOPED_STMT,
} AstKind;
typedef enum
@@ -241,14 +242,9 @@ typedef enum
EXPR_INITIALIZER_LIST,
EXPR_EXPRESSION_LIST,
EXPR_CAST,
EXPR_SCOPED_EXPR,
} ExprKind;
typedef enum
{
GOTO_NOT_ANALYSED,
GOTO_JUMP_FORWARD,
GOTO_JUMP_BACK
} GotoType;
typedef enum
@@ -263,7 +259,7 @@ typedef enum
{
PREC_NONE,
PREC_ASSIGNMENT, // =, *=, /=, %=, ...
PREC_TERNARY, // ?:
PREC_TERNARY, // ?:
PREC_LOGICAL, // && ||
PREC_RELATIONAL, // < > <= >= == !=
PREC_ADDITIVE, // + -

View File

@@ -87,7 +87,6 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e
}
expr->type = left->type;
return true;
}
@@ -103,6 +102,9 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr
return false;
}
// Already handled
if (!decl_ok(decl)) return false;
if (ambiguous_decl)
{
SEMA_ERROR(expr,
@@ -1472,6 +1474,8 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
{
case EXPR_POISONED:
return false;
case EXPR_SCOPED_EXPR:
UNREACHABLE
case EXPR_TRY:
return sema_expr_analyse_try(context, to, expr);
case EXPR_CONST:

View File

@@ -59,6 +59,20 @@ static inline LLVMValueRef gencontext_emit_access_addr(GenContext *context, Expr
return LLVMBuildStructGEP2(context->builder, BACKEND_TYPE(expr->access_expr.parent->type), value, (unsigned)expr->access_expr.index, "");
}
LLVMValueRef gencontext_emit_scoped_expr(GenContext *context, Expr *expr)
{
LLVMValueRef value = gencontext_emit_expr(context, expr->expr_scope.expr);
gencontext_emit_defer(context, expr->expr_scope.defers.start, expr->expr_scope.defers.end);
return value;
}
LLVMValueRef gencontext_emit_scoped_expr_address(GenContext *context, Expr *expr)
{
LLVMValueRef value = gencontext_emit_address(context, expr->expr_scope.expr);
gencontext_emit_defer(context, expr->expr_scope.defers.start, expr->expr_scope.defers.end);
return value;
}
LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
{
switch (expr->expr_kind)
@@ -72,6 +86,8 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
return gencontext_emit_access_addr(context, expr);
case EXPR_SUBSCRIPT:
return gencontext_emit_subscript_addr(context, expr);
case EXPR_SCOPED_EXPR:
return gencontext_emit_scoped_expr_address(context, expr);
case EXPR_CONST:
case EXPR_TYPE:
case EXPR_POISONED:
@@ -614,20 +630,14 @@ static inline LLVMValueRef gencontext_emit_struct_init_values_expr(GenContext *c
TODO
}
LLVMValueRef gencontext_emit_ast_expr(GenContext *context, Ast *expr)
{
assert(expr->ast_kind == AST_EXPR_STMT);
LLVMValueRef value = gencontext_emit_expr(context, expr->expr_stmt);
// gencontext_emit_defer(context, expr);
return value;
}
LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
{
switch (expr->expr_kind)
{
case EXPR_POISONED:
UNREACHABLE
case EXPR_SCOPED_EXPR:
return gencontext_emit_scoped_expr(context, expr);
case EXPR_UNARY:
return gencontext_emit_unary_expr(context, expr);
case EXPR_CONST:

View File

@@ -112,8 +112,10 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl)
label->label_stmt.backend_value = gencontext_create_free_block(context, label->label_stmt.name);
}
gencontext_emit_compound_stmt(context, decl->func.body);
VECEACH(decl->func.body->compound_stmt.stmts, i)
{
gencontext_emit_stmt(context, decl->func.body->compound_stmt.stmts[i]);
}
if (!LLVMGetFirstInstruction(context->current_block) && !LLVMGetFirstUse(LLVMBasicBlockAsValue(context->current_block)))
{
@@ -122,10 +124,12 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl)
context->current_block = prev_block;
LLVMPositionBuilderAtEnd(context->builder, context->current_block);
}
// Insert a return if needed.
// Insert a return (and defer) if needed.
if (!LLVMGetBasicBlockTerminator(context->current_block))
{
assert(decl->func.function_signature.rtype->type->type_kind == TYPE_VOID);
assert(decl->func.body->compound_stmt.defer_list.end == NULL);
gencontext_emit_defer(context, decl->func.body->compound_stmt.defer_list.start, NULL);
LLVMBuildRetVoid(context->builder);
}

View File

@@ -72,7 +72,7 @@ typedef struct
void gencontext_begin_module(GenContext *context);
void gencontext_end_module(GenContext *context);
void gencontext_emit_stmt(GenContext *context, Ast *ast);
void gencontext_emit_defer(GenContext *context, DeferList defer_list);
void gencontext_emit_defer(GenContext *context, Ast *defer_start, Ast *defer_end);
LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr);
LLVMValueRef gencontext_emit_ast_expr(GenContext *context, Ast *expr);
LLVMMetadataRef gencontext_get_debug_type(GenContext *context, Type *type);

View File

@@ -15,6 +15,7 @@ void gencontext_emit_compound_stmt(GenContext *context, Ast *ast)
{
gencontext_emit_stmt(context, ast->compound_stmt.stmts[i]);
}
gencontext_emit_defer(context, ast->compound_stmt.defer_list.start, ast->compound_stmt.defer_list.end);
}
@@ -43,7 +44,7 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
{
LLVMValueRef value = gencontext_emit_expr(context, decl->var.init_expr);
LLVMBuildStore(context->builder, value, decl->var.backend_ref);
return value;
return decl->var.backend_ref;
}
return decl->var.backend_ref;
}
@@ -99,20 +100,14 @@ 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;
Ast *defer = ast->return_stmt.defer;
while (defer)
{
gencontext_emit_stmt(context, defer->defer_stmt.body);
// TODO boolean
defer = defer->defer_stmt.prev_defer;
}
if (!ast->return_stmt.expr)
LLVMValueRef ret_value = ast->return_stmt.expr ? gencontext_emit_expr(context, ast->return_stmt.expr) : NULL;
gencontext_emit_defer(context, ast->return_stmt.defer, NULL);
if (!ret_value)
{
LLVMBuildRetVoid(context->builder);
return;
}
LLVMValueRef returnValue = gencontext_emit_expr(context, ast->return_stmt.expr);
LLVMBuildRet(context->builder, returnValue);
LLVMBuildRet(context->builder, ret_value);
context->current_block = NULL;
LLVMBasicBlockRef post_ret_block = gencontext_create_free_block(context, "ret");
gencontext_emit_block(context, post_ret_block);
@@ -225,7 +220,6 @@ void gencontext_emit_for_stmt(GenContext *context, Ast *ast)
gencontext_emit_br(context, cond_block);
gencontext_emit_block(context, cond_block);
value = gencontext_emit_expr(context, ast->for_stmt.cond);
gencontext_emit_defer(context, ast->for_stmt.cond_defer);
// If we have a body, conditionally jump to it.
if (body_block)
{
@@ -258,7 +252,7 @@ void gencontext_emit_for_stmt(GenContext *context, Ast *ast)
{
// Emit the block
gencontext_emit_block(context, inc_block);
gencontext_emit_expr(context, ast->for_stmt.incr->expr_stmt);
gencontext_emit_expr(context, ast->for_stmt.incr);
}
// Loop back.
@@ -285,7 +279,14 @@ void gencontext_emit_while_stmt(GenContext *context, Ast *ast)
// 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);
DeferList defers = { NULL, NULL };
Ast *cond = ast->while_stmt.cond;
if (cond->ast_kind == AST_SCOPED_STMT)
{
defers = cond->scoped_stmt.defers;
cond = cond->scoped_stmt.stmt;
}
LLVMValueRef value = gencontext_emit_decl_expr_list(context, cond, true);
// If we have a body, conditionally jump to it.
if (body_block)
{
@@ -293,6 +294,9 @@ void gencontext_emit_while_stmt(GenContext *context, Ast *ast)
}
else
{
// Emit defers
gencontext_emit_defer(context, defers.start, defers.end);
// Otherwise jump to inc or cond depending on what's available.
gencontext_emit_cond_br(context, value, begin_block, exit_block);
}
@@ -301,6 +305,9 @@ void gencontext_emit_while_stmt(GenContext *context, Ast *ast)
{
gencontext_emit_block(context, body_block);
gencontext_emit_stmt(context, ast->while_stmt.body);
// Emit defers
gencontext_emit_defer(context, defers.start, defers.end);
}
// Loop back.
@@ -308,6 +315,9 @@ void gencontext_emit_while_stmt(GenContext *context, Ast *ast)
// And insert exit block
gencontext_emit_block(context, exit_block);
// Emit defers
gencontext_emit_defer(context, defers.start, defers.end);
gencontext_pop_break_continue(context);
}
@@ -369,6 +379,7 @@ void gencontext_emit_label(GenContext *context, Ast *ast)
void gencontext_emit_switch(GenContext *context, Ast *ast)
{
// TODO check defer correctness
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);
@@ -385,13 +396,13 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
Ast *case_stmt = ast->switch_stmt.cases[i];
if (case_stmt->case_stmt.value_type == CASE_VALUE_DEFAULT)
{
if (case_stmt->case_stmt.block)
if (case_stmt->case_stmt.body)
{
case_stmt->case_stmt.backend_value = gencontext_create_free_block(context, "switch.default");
}
default_case = case_stmt;
}
else if (case_stmt->case_stmt.block)
else if (case_stmt->case_stmt.body)
{
case_stmt->case_stmt.backend_value = gencontext_create_free_block(context, "switch.case");
}
@@ -444,13 +455,13 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
}
// Skip fallthroughs.
if (!case_stmt->case_stmt.block) continue;
if (!case_stmt->case_stmt.body) continue;
gencontext_emit_block(context, block);
// IMPORTANT!
context->current_block_is_target = true;
gencontext_push_break_continue(context, NULL, NULL, i < cases - 1 ? ast->switch_stmt.cases[i + 1]->case_stmt.backend_value : exit_block);
gencontext_emit_stmt(context, case_stmt->case_stmt.block);
gencontext_emit_stmt(context, case_stmt->case_stmt.body);
gencontext_pop_break_continue(context);
gencontext_emit_br(context, exit_block);
}
@@ -458,15 +469,92 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
gencontext_emit_block(context, exit_block);
}
void gencontext_emit_defer(GenContext *context, DeferList defer_list)
LLVMValueRef gencontext_get_defer_bool(GenContext *context, Ast *defer)
{
if (defer_list.start == defer_list.end) return;
Ast *defer = context->ast_context->defers[defer_list.start - 1];
while (defer && defer->defer_stmt.id != defer_list.end)
assert(defer->ast_kind == AST_DEFER_STMT && defer->defer_stmt.emit_boolean);
if (!defer->defer_stmt.bool_var)
{
gencontext_emit_stmt(context, defer->defer_stmt.body);
// TODO boolean
defer->defer_stmt.bool_var = gencontext_emit_alloca(context, BACKEND_TYPE(type_bool), "defer");
}
return defer->defer_stmt.bool_var;
}
void gencontext_emit_defer(GenContext *context, Ast *defer_start, Ast *defer_end)
{
if (defer_start == defer_end) return;
Ast *defer = defer_start;
while (defer && defer != defer_end)
{
if (defer->defer_stmt.emit_boolean)
{
// We need at least the exit block and the "then" block.
LLVMBasicBlockRef exit_block = LLVMCreateBasicBlockInContext(context->context, "skip.defer");
LLVMBasicBlockRef defer_block = LLVMCreateBasicBlockInContext(context->context, "do.defer");
LLVMValueRef value = LLVMBuildLoad2(context->builder, BACKEND_TYPE(type_bool), gencontext_get_defer_bool(context, defer), "will.defer");
gencontext_emit_cond_br(context, value, defer_block, exit_block);
// Emit the defer.
gencontext_emit_block(context, defer_block);
gencontext_emit_stmt(context, defer->defer_stmt.body);
// Jump to exit.
gencontext_emit_br(context, exit_block);
// And now we just emit the exit block.
gencontext_emit_block(context, exit_block);
}
else
{
gencontext_emit_stmt(context, defer->defer_stmt.body);
}
defer = defer->defer_stmt.prev_defer;
}
}
void gencontext_emit_goto(GenContext *context, Ast *ast)
{
gencontext_emit_defer(context, ast->goto_stmt.defer.start, ast->goto_stmt.defer.end);
Ast *defer = ast->goto_stmt.label->label_stmt.defer;
while (defer != ast->goto_stmt.defer.end)
{
LLVMBuildStore(context->builder, LLVMConstInt(BACKEND_TYPE(type_bool), 0, false),
gencontext_get_defer_bool(context, defer));
defer = defer->defer_stmt.prev_defer;
}
gencontext_emit_jmp(context, ast->goto_stmt.label->label_stmt.backend_value);
}
void gencontext_emit_break(GenContext *context, Ast *ast)
{
gencontext_emit_defer(context, ast->break_stmt.defers.start, ast->break_stmt.defers.end);
assert(context->break_continue_stack_index);
gencontext_emit_jmp(context, context->break_continue_stack[context->break_continue_stack_index - 1].break_block);
}
void gencontext_emit_continue(GenContext *context, Ast *ast)
{
gencontext_emit_defer(context, ast->continue_stmt.defers.start, ast->continue_stmt.defers.end);
assert(context->break_continue_stack_index);
gencontext_emit_jmp(context, context->break_continue_stack[context->break_continue_stack_index - 1].continue_block);
}
void gencontext_emit_next_stmt(GenContext *context, Ast *ast)
{
gencontext_emit_defer(context, ast->next_stmt.defers.start, ast->next_stmt.defers.end);
assert(context->break_continue_stack_index);
gencontext_emit_jmp(context, context->break_continue_stack[context->break_continue_stack_index - 1].next_block);
}
void gencontext_emit_scoped_stmt(GenContext *context, Ast *ast)
{
gencontext_emit_stmt(context, ast->scoped_stmt.stmt);
gencontext_emit_defer(context, ast->scoped_stmt.defers.start, ast->scoped_stmt.defers.end);
}
void gencontext_emit_stmt(GenContext *context, Ast *ast)
@@ -477,6 +565,9 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
TODO
case AST_POISONED:
UNREACHABLE
case AST_SCOPED_STMT:
gencontext_emit_scoped_stmt(context, ast);
break;
case AST_EXPR_STMT:
gencontext_emit_expr(context, ast->expr_stmt);
break;
@@ -484,12 +575,10 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
gencontext_emit_decl(context, ast);
break;
case AST_BREAK_STMT:
assert(context->break_continue_stack_index);
gencontext_emit_jmp(context, context->break_continue_stack[context->break_continue_stack_index - 1].break_block);
gencontext_emit_break(context, ast);
break;
case AST_CONTINUE_STMT:
assert(context->break_continue_stack_index);
gencontext_emit_jmp(context, context->break_continue_stack[context->break_continue_stack_index - 1].continue_block);
gencontext_emit_continue(context, ast);
break;
case AST_IF_STMT:
gencontext_emit_if(context, ast);
@@ -510,11 +599,16 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
gencontext_emit_do_stmt(context, ast);
break;
case AST_NEXT_STMT:
assert(context->break_continue_stack_index);
gencontext_emit_jmp(context, context->break_continue_stack[context->break_continue_stack_index - 1].next_block);
gencontext_emit_next_stmt(context, ast);
break;
case AST_DEFER_STMT:
if (ast->defer_stmt.emit_boolean)
{
LLVMBuildStore(context->builder, LLVMConstInt(BACKEND_TYPE(type_bool), 1, false),
gencontext_get_defer_bool(context, ast));
}
break;
case AST_NOP_STMT:
case AST_DEFER_STMT:
break;
case AST_CATCH_STMT:
case AST_TRY_STMT:
@@ -539,7 +633,7 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
gencontext_emit_label(context, ast);
break;
case AST_GOTO_STMT:
gencontext_emit_jmp(context, ast->goto_stmt.label->label_stmt.backend_value);
gencontext_emit_goto(context, ast);
break;
case AST_SWITCH_STMT:
gencontext_emit_switch(context, ast);

View File

@@ -13,7 +13,7 @@ static Expr *parse_paren_expr(Context *context);
static Expr *parse_precedence(Context *context, Precedence precedence);
static Expr *parse_initializer_list(Context *context);
static Expr *parse_initializer(Context *context);
static bool parse_type_or_expr(Context *context, Expr **exprPtr, TypeInfo **typePtr);
static bool parse_type_or_expr(Context *context, Expr **expr_ptr, TypeInfo **type_ptr);
static Decl *parse_top_level(Context *context);
typedef Expr *(*ParseFn)(Context *context, Expr *);
@@ -29,18 +29,31 @@ extern ParseRule rules[TOKEN_EOF + 1];
void context_store_lexer_state(Context *context)
{
assert(!context->stored.has_stored && "Nested lexer store is forbidden");
context->stored.has_stored = true;
context->stored.current = context->lexer.current;
context->stored.start = context->lexer.lexing_start;
context->stored.tok = context->tok;
context->stored.next_tok = context->next_tok;
context->stored.lead_comment = context->lead_comment;
context->stored.trailing_comment = context->trailing_comment;
context->stored.next_lead_comment = context->next_lead_comment;
context->stored.comments = vec_size(context->comments);
}
void context_restore_lexer_state(Context *context)
{
assert(context->stored.has_stored && "Tried to restore missing stored state.");
context->stored.has_stored = false;
context->lexer.current = context->stored.current;
context->lexer.lexing_start = context->stored.start;
context->tok = context->stored.tok;
context->next_tok = context->stored.next_tok;
context->lead_comment = context->stored.lead_comment;
context->next_lead_comment = context->stored.next_lead_comment;
context->trailing_comment = context->stored.trailing_comment;
context->prev_tok_end = context->tok.span.end_loc;
vec_resize(context->comments, context->stored.comments);
}
inline void advance(Context *context)
@@ -347,13 +360,12 @@ static Path *parse_path_prefix(Context *context)
while (context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE)
{
last_range = context->tok.span;
advance(context);
advance(context);
scratch_ptr[offset++] = ':';
scratch_ptr[offset++] = ':';
len = context->tok.span.end_loc - context->tok.span.loc;
memcpy(scratch_ptr + offset, context->tok.start, len);
offset += len;
advance(context); advance(context);
}
TokenType type = TOKEN_IDENT;
@@ -768,7 +780,6 @@ static inline Ast* parse_if_stmt(Context *context)
{
return if_ast;
}
advance_and_verify(context, TOKEN_ELSE);
if_ast->if_stmt.else_body = TRY_AST(parse_stmt(context));
return if_ast;
}
@@ -857,22 +868,7 @@ static inline Ast* parse_do_stmt(Context *context)
return do_ast;
}
/**
* switch
* : SWITCH '(' control_expression ')' compound_statement
*
* @return
*/
static inline Ast* parse_switch_stmt(Context *context)
{
Ast *switch_ast = AST_NEW_TOKEN(AST_SWITCH_STMT, context->tok);
advance_and_verify(context, TOKEN_SWITCH);
CONSUME_OR(TOKEN_LPAREN, &poisoned_ast);
if (!parse_control_expression(context, &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(context));
return switch_ast;
}
/**
* for_statement
@@ -912,7 +908,7 @@ static inline Ast* parse_for_stmt(Context *context)
if (context->tok.type != TOKEN_RPAREN)
{
ast->for_stmt.incr = TRY_AST(ast_from_expr(parse_expression_list(context)));
ast->for_stmt.incr = parse_expression_list(context);
}
CONSUME_OR(TOKEN_RPAREN, &poisoned_ast);
@@ -926,21 +922,6 @@ static inline Expr* parse_constant_expr(Context *context)
{
return parse_precedence(context, PREC_TERNARY);
}
/**
* case_stmt
* : CASE constant_expression ':'
*
* @return Ast*
*/
static inline Ast* parse_case_stmt(Context *context)
{
Ast *ast = AST_NEW_TOKEN(AST_CASE_STMT, context->tok);
advance(context);
Expr *expr = TRY_EXPR_OR(parse_constant_expr(context), &poisoned_ast);
ast->case_stmt.expr = expr;
TRY_CONSUME(TOKEN_COLON, "Missing ':' after case");
return extend_ast_with_prev_token(context, ast);
}
static inline Ast* parse_goto_stmt(Context *context)
{
@@ -1136,7 +1117,7 @@ static Ast *parse_return_stmt(Context *context)
advance_and_verify(context, TOKEN_RETURN);
Ast *ast = AST_NEW_TOKEN(AST_RETURN_STMT, context->tok);
ast->exit = EXIT_RETURN;
ast->return_stmt.defer = 0;
ast->return_stmt.defer = NULL;
if (try_consume(context, TOKEN_EOS))
{
ast->return_stmt.expr = NULL;
@@ -1161,13 +1142,6 @@ static Ast *parse_volatile_stmt(Context *context)
return ast;
}
static Ast *parse_default_stmt(Context *context)
{
Ast *ast = AST_NEW_TOKEN(AST_DEFAULT_STMT, context->tok);
advance_and_verify(context, TOKEN_DEFAULT);
TRY_CONSUME_OR(TOKEN_COLON, "Expected ':' after 'default'.", &poisoned_ast);
return ast;
}
bool is_valid_try_statement(TokenType type)
@@ -1236,7 +1210,10 @@ static bool parse_type_or_expr(Context *context, Expr **exprPtr, TypeInfo **type
{
// We need a little lookahead to see if this is type or expression.
context_store_lexer_state(context);
advance(context); advance(context);
do
{
advance(context); advance(context);
} while (context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE);
if (context->tok.type == TOKEN_TYPE_IDENT && !is_expr_after_type_ident(context))
{
context_restore_lexer_state(context);
@@ -1282,21 +1259,106 @@ static inline Ast *parse_decl_or_expr_stmt(Context *context)
if (!parse_type_or_expr(context, &expr, &type)) return &poisoned_ast;
Ast *ast;
if (expr)
{
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
Ast *ast = AST_NEW(AST_EXPR_STMT, expr->span);
ast = AST_NEW(AST_EXPR_STMT, expr->span);
ast->expr_stmt = expr;
return ast;
}
else
{
Decl *decl = TRY_DECL_OR(parse_decl_after_type(context, false, type), &poisoned_ast);
Ast *ast = AST_NEW(AST_DECLARE_STMT, decl->span);
ast = AST_NEW(AST_DECLARE_STMT, decl->span);
ast->declare_stmt = decl;
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
return ast;
}
CONSUME_OR(TOKEN_EOS, &poisoned_ast);
return ast;
}
static inline bool token_type_ends_case(TokenType type)
{
return type == TOKEN_CASE || type == TOKEN_DEFAULT || type == TOKEN_RBRACE;
}
static inline Ast *parse_case_stmts(Context *context)
{
Ast *compound = AST_NEW_TOKEN(AST_COMPOUND_STMT, context->tok);
while (!token_type_ends_case(context->tok.type))
{
Ast *stmt = TRY_AST(parse_stmt(context));
vec_add(compound->compound_stmt.stmts, stmt);
}
return compound;
}
/**
* case_stmt
* : CASE constant_expression ':'
*
* @return Ast*
*/
static inline Ast* parse_case_stmt(Context *context)
{
Ast *ast = AST_NEW_TOKEN(AST_CASE_STMT, context->tok);
advance(context);
Expr *expr = TRY_EXPR_OR(parse_constant_expr(context), &poisoned_ast);
ast->case_stmt.expr = expr;
TRY_CONSUME(TOKEN_COLON, "Missing ':' after case");
extend_ast_with_prev_token(context, ast);
ast->case_stmt.body = TRY_AST(parse_case_stmts(context));
return ast;
}
static Ast *parse_default_stmt(Context *context)
{
Ast *ast = AST_NEW_TOKEN(AST_DEFAULT_STMT, context->tok);
advance_and_verify(context, TOKEN_DEFAULT);
TRY_CONSUME_OR(TOKEN_COLON, "Expected ':' after 'default'.", &poisoned_ast);
extend_ast_with_prev_token(context, ast);
ast->case_stmt.body = TRY_AST(parse_case_stmts(context));
ast->case_stmt.value_type = CASE_VALUE_DEFAULT;
return ast;
}
static inline bool parse_switch_body(Context *context, Ast *switch_ast)
{
Ast *result;
switch (context->tok.type)
{
case TOKEN_CASE:
result = TRY_AST_OR(parse_case_stmt(context), false);
break;
case TOKEN_DEFAULT:
result = TRY_AST_OR(parse_default_stmt(context), false);
break;
default:
SEMA_TOKEN_ERROR(context->tok, "A 'case' or 'default' would be needed here, '%.*s' is not allowed.", source_range_len(context->tok.span), context->tok.start);
return false;
}
vec_add(switch_ast->switch_stmt.cases, result);
return true;
}
/**
* switch
* : SWITCH '(' control_expression ')' compound_statement
*
* @return
*/
static inline Ast* parse_switch_stmt(Context *context)
{
Ast *switch_ast = AST_NEW_TOKEN(AST_SWITCH_STMT, context->tok);
advance_and_verify(context, TOKEN_SWITCH);
CONSUME_OR(TOKEN_LPAREN, &poisoned_ast);
if (!parse_control_expression(context, &switch_ast->switch_stmt.decl, &switch_ast->switch_stmt.cond)) return &poisoned_ast;
CONSUME_OR(TOKEN_RPAREN, &poisoned_ast);
CONSUME_OR(TOKEN_LBRACE, &poisoned_ast);
while (!try_consume(context, TOKEN_RBRACE))
{
if (!parse_switch_body(context, switch_ast)) return &poisoned_ast;
}
return switch_ast;
}
static Ast *parse_stmt(Context *context)
@@ -1389,7 +1451,9 @@ static Ast *parse_stmt(Context *context)
case TOKEN_CONTINUE:
return parse_continue_stmt(context);
case TOKEN_CASE:
return parse_case_stmt(context);
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);
case TOKEN_NEXT:
@@ -1397,7 +1461,9 @@ static Ast *parse_stmt(Context *context)
case TOKEN_ASM:
return parse_asm_stmt(context);
case TOKEN_DEFAULT:
return parse_default_stmt(context);
SEMA_TOKEN_ERROR(context->tok, "'default' was found outside of 'switch', did you mismatch a '{ }' pair?");
advance(context);
return &poisoned_ast;
case TOKEN_CT_IF:
return parse_ct_if_stmt(context);
case TOKEN_CT_SWITCH:

View File

@@ -31,6 +31,7 @@ static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path
assert(path && "Expected path.");
*ambiguous_other_decl = NULL;
Decl *decl = NULL;
bool path_found = false;
VECEACH(context->imports, i)
{
Decl *import = context->imports[i];
@@ -39,6 +40,7 @@ static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path
// Full import, first match the subpath.
if (path->len > import->import.path->len) continue;
if (!matches_subpath(import->import.path, path)) continue;
path_found = true;
Decl *found = module_find_symbol(import->module, symbol, MODULE_SYMBOL_SEARCH_EXTERNAL);
if (!found) continue;
if (decl)
@@ -48,6 +50,15 @@ static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path
}
decl = found;
}
if (!decl)
{
if (!path_found)
{
SEMA_ERROR(path, "Unknown module %.*s.", path->len, path->module);
return &poisoned_decl;
}
return NULL;
}
context_register_external_symbol(context, decl);
return decl;
}

View File

@@ -4,14 +4,6 @@
#include "compiler_internal.h"
typedef bool(*AstAnalysis)(Context *, Ast*);
static inline DeferId defer_id_from_ast(Ast *ast)
{
if (!ast) return 0;
assert(ast->ast_kind == AST_DEFER_STMT);
return ast->defer_stmt.id;
}
static inline Type *ast_cond_type(Ast *ast)
{
assert(ast->ast_kind == AST_DECL_EXPR_LIST);
@@ -42,12 +34,12 @@ static inline void context_push_scope_with_flags(Context *context, ScopeFlags fl
FATAL_ERROR("Too deeply nested scopes.");
}
ScopeFlags previous_flags = context->current_scope->flags;
DeferId parent_defer = context->current_scope->defer_last;
Ast *parent_defer = context->current_scope->defers.start;
context->current_scope++;
context->current_scope->exit = EXIT_NONE;
context->current_scope->local_decl_start = context->last_local;
context->current_scope->defer_top = parent_defer;
context->current_scope->defer_last = parent_defer;
context->current_scope->defers.start = parent_defer;
context->current_scope->defers.end = parent_defer;
context->current_scope->flags = previous_flags | flags;
context->current_scope->flags_created = flags;
}
@@ -57,15 +49,23 @@ static inline void context_push_scope(Context *context)
context_push_scope_with_flags(context, SCOPE_NONE);
}
static inline void context_pop_scope(Context *context, Ast **ast, Expr **expr)
static inline void context_pop_defers(Context *context)
{
context->current_scope->defers.start = context->current_scope->defers.end;
}
static inline void context_pop_defers_to(Context *context, DeferList *list)
{
*list = context->current_scope->defers;
context_pop_defers(context);
}
static inline void context_pop_scope(Context *context)
{
assert(context->current_scope != &context->scopes[0]);
context->last_local = context->current_scope->local_decl_start;
ExitType exit_type = context->current_scope->exit;
if (context->current_scope->defer_top != context->current_scope->defer_last)
{
TODO;
}
assert (context->current_scope->defers.end == context->current_scope->defers.start);
context->current_scope--;
if (context->current_scope->exit < exit_type)
{
@@ -73,6 +73,37 @@ static inline void context_pop_scope(Context *context, Ast **ast, Expr **expr)
}
}
static Expr *context_pop_defers_and_wrap_expr(Context *context, Expr *expr)
{
DeferList defers = { NULL, NULL };
context_pop_defers_to(context, &defers);
if (defers.end == defers.start) return expr;
Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span);
wrap->type = expr->type;
wrap->resolve_status = RESOLVE_DONE;
wrap->expr_scope.expr = expr;
wrap->expr_scope.defers = defers;
return expr;
}
static void context_pop_defers_and_replace_ast(Context *context, Ast *ast)
{
DeferList defers = { NULL, NULL };
context_pop_defers_to(context, &defers);
if (defers.end == defers.start) return;
if (ast->ast_kind == AST_DEFER_STMT)
{
assert(defers.start == ast);
*ast = *ast->defer_stmt.body;
return;
}
assert(ast->ast_kind != AST_COMPOUND_STMT);
Ast *replacement = malloc_arena(sizeof(Ast));
*replacement = *ast;
ast->ast_kind = AST_SCOPED_STMT;
ast->scoped_stmt.stmt = replacement;
ast->scoped_stmt.defers = defers;
}
static bool sema_resolve_ptr_type(Context *context, TypeInfo *type_info)
@@ -107,6 +138,7 @@ static bool sema_resolve_array_type(Context *context, TypeInfo *type)
type->resolve_status = RESOLVE_DONE;
return true;
}
static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
{
if (decl->decl_kind == DECL_STRUCT || decl->decl_kind == DECL_UNION)
@@ -174,7 +206,6 @@ static inline bool sema_analyse_struct_union(Context *context, Decl *decl)
}
static inline bool sema_analyse_function_param(Context *context, Decl *param, bool is_function)
{
assert(param->decl_kind == DECL_VAR);
@@ -294,6 +325,8 @@ static inline bool sema_analyse_compound_statement_no_scope(Context *context, As
all_ok = false;
}
}
context_pop_defers_to(context, &compound_statement->compound_stmt.defer_list);
/*
if (parent->exit < compound_statement->exit)
{
@@ -307,7 +340,7 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
context->current_scope->exit = EXIT_RETURN;
Type *expected_rtype = context->rtype;
Expr *return_expr = statement->return_stmt.expr;
statement->return_stmt.defer = VECLAST(context->defers);
statement->return_stmt.defer = context->current_scope->defers.start;
if (return_expr == NULL)
{
if (!expected_rtype)
@@ -359,50 +392,6 @@ static inline Ast *convert_expr_to_ast(Expr *expr)
ast->expr_stmt = expr;
return ast;
}
static inline Expr *convert_decl_to_expr(Context *context, Decl *decl)
{
assert(decl->decl_kind == DECL_VAR);
assert(decl->decl_kind == VARDECL_LOCAL);
if (!decl->var.init_expr) return NULL;
Expr *assign_expr = expr_new(EXPR_BINARY, decl->span);
assign_expr->resolve_status = RESOLVE_DONE;
Expr *identifier = expr_new(EXPR_IDENTIFIER, decl->span);
identifier->resolve_status = RESOLVE_DONE;
identifier->identifier_expr.identifier = decl->name;
identifier->identifier_expr.decl = decl;
assign_expr->binary_expr.left = identifier;
assign_expr->binary_expr.right = decl->var.init_expr;
assign_expr->binary_expr.operator = BINARYOP_ASSIGN;
// Possibly not right v TODO
identifier->type = decl->var.type_info->type;
assign_expr->type = decl->var.init_expr->type;
return assign_expr;
}
static inline bool convert_decl_for_cond(Context *context, Decl *decl, Ast*** stmt_list, Expr** last, bool is_last)
{
Expr *expr = convert_decl_to_expr(context, decl);
if (!expr)
{
if (is_last)
{
SEMA_ERROR(decl, "Expected an initializer for '%s'.", decl->name);
return false;
}
// Simply skip declarations if they don't have an initializer, since they're already registered anyway.
return true;
}
if (is_last)
{
*last = expr;
}
else
{
Ast *stmt = convert_expr_to_ast(expr);
*stmt_list = VECADD(*stmt_list, stmt);
}
return true;
}
static inline bool sema_analyse_function_block_stmt(Context *context, Ast *stmt)
@@ -453,7 +442,7 @@ static inline bool sema_analyse_cond(Context *context, Ast *stmt, bool cast_to_b
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)
cast_to_bool_kind(last->declare_stmt->var.type_info->type) == CAST_ERROR)
{
SEMA_ERROR(last->declare_stmt->var.init_expr, "The expression needs to be convertible to a boolean.");
return false;
@@ -473,12 +462,16 @@ static inline bool sema_analyse_while_stmt(Context *context, Ast *statement)
context_push_scope(context);
bool success = !decl || sema_analyse_statement(context, decl);
context_push_scope(context);
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, &body, NULL);
context_pop_scope(context, &cond, NULL);
context_pop_scope(context, &decl, NULL);
context_pop_defers_and_replace_ast(context, body);
context_pop_scope(context);
context_pop_defers_and_replace_ast(context, cond);
context_pop_scope(context);
context_pop_defers_and_replace_ast(context, statement);
context_pop_scope(context);
if (!success) return false;
return success;
}
@@ -490,16 +483,17 @@ static inline bool sema_analyse_do_stmt(Context *context, Ast *statement)
bool success;
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise)
success = sema_analyse_statement(context, body);
context_pop_scope(context, &body, NULL);
context_pop_defers_and_replace_ast(context, body);
context_pop_scope(context);
if (!success) return false;
context_push_scope(context);
success = sema_analyse_expr(context, type_bool, expr);
context_pop_scope(context, NULL, &expr);
statement->do_stmt.expr = context_pop_defers_and_wrap_expr(context, expr);
context_pop_scope(context);
return success;
}
static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement)
{
Decl *decl = statement->declare_stmt;
@@ -520,17 +514,16 @@ static inline bool sema_analyse_defer_stmt(Context *context, Ast *statement)
bool success = sema_analyse_statement(context, statement->defer_stmt.body);
context_pop_scope(context, &statement->defer_stmt.body, NULL);
context_pop_scope(context);
if (!success) return false;
statement->defer_stmt.prev_defer = VECLAST(context->defers);
vec_add(context->defers, statement);
statement->defer_stmt.id = vec_size(context->defers);
statement->defer_stmt.prev_defer = context->current_scope->defers.start;
context->current_scope->defers.start = statement;
return true;
}
static inline bool sema_analyse_default_stmt(Context *context, Ast *statement)
static inline bool sema_analyse_default_stmt(Context *context __unused, Ast *statement)
{
SEMA_ERROR(statement, "Unexpected 'default' outside of switch");
return false;
@@ -550,17 +543,21 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
{
// Conditional scope start
context_push_scope(context);
success = sema_analyse_expr(context, type_bool, statement->for_stmt.cond);
Expr *cond = statement->for_stmt.cond;
success = sema_analyse_expr(context, type_bool, cond);
statement->for_stmt.cond = context_pop_defers_and_wrap_expr(context, cond);
// Conditional scope end
context_pop_scope(context, NULL, &statement->for_stmt.cond);
context_pop_scope(context);
}
if (success && statement->for_stmt.incr)
{
// Incr scope start
context_push_scope(context);
success = sema_analyse_statement(context, statement->for_stmt.incr);
Expr *incr = statement->for_stmt.incr;
success = sema_analyse_expr(context, NULL, incr);
statement->for_stmt.incr = context_pop_defers_and_wrap_expr(context, incr);
// Incr scope end
context_pop_scope(context, &statement->for_stmt.incr, NULL);
context_pop_scope(context);
}
if (!success) return false;
@@ -568,20 +565,23 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise)
success = sema_analyse_statement(context, statement->for_stmt.body);
// End for body scope
context_pop_scope(context, &statement->for_stmt.body, NULL);
context_pop_defers_and_replace_ast(context, statement->for_stmt.body);
context_pop_scope(context);
context_pop_defers_and_replace_ast(context, statement);
// End for scope
context_pop_scope(context, &statement, NULL);
context_pop_scope(context);
return success;
}
static inline bool sema_analyse_goto_stmt(Context *context, Ast *statement)
{
statement->goto_stmt.defer = context->current_scope->defers;
VECEACH(context->labels, i)
{
Ast *label = context->labels[i];
if (statement->goto_stmt.label_name == label->label_stmt.name)
{
statement->goto_stmt.type = GOTO_JUMP_BACK;
label->label_stmt.is_used = true;
statement->goto_stmt.label = label;
}
@@ -604,7 +604,8 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
{
if (statement->if_stmt.then_body->ast_kind != AST_COMPOUND_STMT)
{
SEMA_ERROR(statement->if_stmt.then_body, "if-statements with an 'else' must use '{ }' even around a single statement.");
SEMA_ERROR(statement->if_stmt.then_body,
"if-statements with an 'else' must use '{ }' even around a single statement.");
success = false;
}
if (success && statement->if_stmt.else_body->ast_kind != AST_COMPOUND_STMT)
@@ -614,22 +615,19 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
success = false;
}
}
context_push_scope(context);
success = success && sema_analyse_statement(context, statement->if_stmt.then_body);
context_pop_scope(context, &statement->if_stmt.then_body, NULL);
// TODO null flowcheck
if (statement->if_stmt.else_body)
{
context_push_scope(context);
success = success && sema_analyse_statement(context, statement->if_stmt.else_body);
context_pop_scope(context, &statement->if_stmt.else_body, NULL);
}
context_pop_scope(context, &statement, NULL);
context_pop_defers_and_replace_ast(context, statement);
context_pop_scope(context);
return success;
}
static inline bool sema_analyse_label(Context *context, Ast *statement)
{
statement->label_stmt.defer = context->current_scope->defers.start;
VECEACH(context->labels, i)
{
Ast *label = context->labels[i];
@@ -648,7 +646,6 @@ static inline bool sema_analyse_label(Context *context, Ast *statement)
Ast *the_goto = context->gotos[i];
if (the_goto->goto_stmt.label_name == statement->label_stmt.name)
{
the_goto->goto_stmt.type = GOTO_JUMP_FORWARD;
the_goto->goto_stmt.label = statement;
statement->label_stmt.is_used = true;
break;
@@ -657,18 +654,13 @@ static inline bool sema_analyse_label(Context *context, Ast *statement)
return true;
}
static inline bool sema_analyse_nop_stmt(Context *context, Ast *statement)
{
return true;
}
static bool sema_analyse_catch_stmt(Context *context, Ast *statement)
static bool sema_analyse_catch_stmt(Context *context __unused, Ast *statement __unused)
{
TODO
}
static bool sema_analyse_asm_stmt(Context *context, Ast *statement)
static bool sema_analyse_asm_stmt(Context *context __unused, Ast *statement __unused)
{
TODO
}
@@ -681,6 +673,30 @@ static bool sema_analyse_break_stmt(Context *context, Ast *statement)
SEMA_ERROR(statement, "'break' is not allowed here.");
return false;
}
DynamicScope *scope = context->current_scope;
statement->break_stmt.defers.start = scope->defers.start;
while (!(scope->flags_created & SCOPE_BREAK)) // NOLINT(hicpp-signed-bitwise)
{
scope--;
}
statement->break_stmt.defers.end = scope->defers.end;
return true;
}
static bool sema_analyse_next_stmt(Context *context, Ast *statement)
{
if (!(context->current_scope->flags & SCOPE_NEXT)) // NOLINT(hicpp-signed-bitwise)
{
SEMA_ERROR(statement, "'next' is not allowed here.");
return false;
}
DynamicScope *scope = context->current_scope;
statement->next_stmt.defers.start = scope->defers.start;
while (!(scope->flags_created & SCOPE_NEXT)) // NOLINT(hicpp-signed-bitwise)
{
scope--;
}
statement->next_stmt.defers.end = scope->defers.end;
return true;
}
@@ -697,6 +713,13 @@ static bool sema_analyse_continue_stmt(Context *context, Ast *statement)
SEMA_ERROR(statement, "'continue' is not allowed here.");
return false;
}
DynamicScope *scope = context->current_scope;
statement->continue_stmt.defers.start = scope->defers.start;
while (!(scope->flags_created & SCOPE_CONTINUE)) // NOLINT(hicpp-signed-bitwise)
{
scope--;
}
statement->continue_stmt.defers.end = scope->defers.end;
return true;
}
@@ -754,112 +777,99 @@ static bool sema_analyse_ct_if_stmt(Context *context, Ast *statement)
}
}
static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *case_stmt, Type *switch_type, Ast **prev_case)
static bool sema_analyse_case_expr(Context *context, Ast *case_stmt)
{
if (case_stmt->ast_kind == AST_CASE_STMT)
Expr *case_expr = case_stmt->case_stmt.expr;
// TODO handle enums
if (!sema_analyse_expr(context, NULL, case_expr)) return false;
if (case_expr->expr_kind != EXPR_CONST)
{
if (*prev_case)
{
// sema_build_defer_chain(context, prev_cases);
context_pop_scope(context, prev_case, NULL);
*prev_case = NULL;
}
Expr *case_expr = case_stmt->case_stmt.expr;
if (!sema_analyse_expr(context, switch_type, case_expr)) return false;
if (case_expr->expr_kind != EXPR_CONST)
{
SEMA_ERROR(case_expr, "This must be a constant expression.");
return false;
}
assert(case_expr->const_expr.type == CONST_INT);
case_stmt->case_stmt.value_type = type_is_signed(case_expr->type->canonical) ? CASE_VALUE_INT : CASE_VALUE_UINT;
uint64_t val = case_expr->const_expr.i;
case_stmt->case_stmt.val = val;
*prev_case = case_stmt;
VECEACH(*prev_cases, i)
{
if ((*prev_cases)[i]->case_stmt.val == val)
{
SEMA_ERROR(case_stmt, "Duplicate case value.");
sema_prev_at_range((*prev_cases)[i]->span, "Previous use was here.");
return false;
}
}
context_push_scope_with_flags(context, SCOPE_BREAK);
vec_add(*prev_cases, case_stmt);
return true;
}
if (case_stmt->ast_kind == AST_DEFAULT_STMT)
{
case_stmt->ast_kind = AST_CASE_STMT;
case_stmt->case_stmt.value_type = CASE_VALUE_DEFAULT;
case_stmt->case_stmt.block = NULL;
if (*prev_case)
{
context_pop_scope(context, prev_case, NULL);
}
context_push_scope(context);
*prev_case = case_stmt;
vec_add(*prev_cases, case_stmt);
return true;
}
if (!*prev_case)
{
SEMA_ERROR(case_stmt, "Expected a 'case' or 'default' statement.");
SEMA_ERROR(case_expr, "This must be a constant expression.");
return false;
}
if (case_stmt->ast_kind == AST_NEXT_STMT)
if (case_expr->const_expr.type != CONST_INT)
{
case_stmt->next_stmt = *prev_case;
(*prev_case)->case_stmt.has_next = true;
SEMA_ERROR(case_expr, "The 'case' value must be an integer constant.");
return false;
}
else
{
if (!sema_analyse_statement(context, case_stmt)) return false;
}
if (!(*prev_case)->case_stmt.block)
{
(*prev_case)->case_stmt.block = AST_NEW(AST_COMPOUND_STMT, (*prev_case)->span);
}
vec_add((*prev_case)->case_stmt.block->compound_stmt.stmts, case_stmt);
assert(case_expr->const_expr.type == CONST_INT);
case_stmt->case_stmt.value_type = type_is_signed(case_expr->type->canonical) ? CASE_VALUE_INT : CASE_VALUE_UINT;
uint64_t val = case_expr->const_expr.i;
case_stmt->case_stmt.val = val;
return true;
}
static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
{
context_push_scope(context);
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);
bool success = sema_analyse_cond(context, cond, false);
Type *switch_type = ast_cond_type(cond)->canonical;
if (!type_is_integer(switch_type))
{
SEMA_ERROR(cond, "Expected an integer or enum type, was '%s'.", type_to_error_string(switch_type));
return false;
}
Ast *in_case = NULL;
VECEACH(body->compound_stmt.stmts, i)
Ast *default_case = NULL;
assert(context->current_scope->defers.start == context->current_scope->defers.end);
VECEACH(statement->switch_stmt.cases, i)
{
success = success && sema_analyse_switch_case(context, &statement->switch_stmt.cases, body->compound_stmt.stmts[i], switch_type, &in_case);
Ast *stmt = statement->switch_stmt.cases[i];
switch (stmt->ast_kind)
{
case AST_CASE_STMT:
if (!sema_analyse_case_expr(context, stmt))
{
success = false;
break;
}
for (unsigned j = 0; j < i; j++)
{
Ast *other = statement->switch_stmt.cases[j];
if (other->ast_kind == AST_CASE_STMT && other->case_stmt.val == stmt->case_stmt.val)
{
SEMA_ERROR(stmt, "The same case value appears more than once.");
SEMA_PREV(other, "Here is the previous use of that value.");
success = false;
}
}
break;
case AST_DEFAULT_STMT:
if (default_case)
{
SEMA_ERROR(stmt, "'default' may only appear once in a single 'switch', please remove one.");
SEMA_PREV(default_case, "Here is the previous use.");
success = false;
}
default_case = stmt;
break;
default:
UNREACHABLE;
}
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_NEXT);
success = success && sema_analyse_compound_statement_no_scope(context, stmt->case_stmt.body);
context_pop_scope(context);
}
if (in_case)
context_pop_defers_and_replace_ast(context, statement);
context_pop_scope(context);
if (!success) return false;
// Is this a typeless switch value?
if (switch_type->type_kind == TYPE_UXX || switch_type->type_kind == TYPE_IXX)
{
context_pop_scope(context, &in_case, NULL);
TODO
}
context_pop_scope(context, &cond, NULL);
context_pop_scope(context, &statement, NULL);
return success;
}
static bool sema_analyse_try_stmt(Context *context, Ast *statement)
static bool sema_analyse_try_stmt(Context *context __unused, Ast *statement __unused)
{
TODO
}
static bool sema_analyse_throw_stmt(Context *context, Ast *statement)
static bool sema_analyse_throw_stmt(Context *context __unused, Ast *statement __unused)
{
TODO
}
@@ -877,7 +887,7 @@ static bool sema_analyse_compound_stmt(Context *context, Ast *statement)
{
context_push_scope(context);
bool success = sema_analyse_compound_statement_no_scope(context, statement);
context_pop_scope(context, &statement, NULL);
context_pop_scope(context);
return success;
}
@@ -888,6 +898,7 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
case AST_POISONED:
return false;
case AST_ATTRIBUTE:
case AST_SCOPED_STMT:
UNREACHABLE
case AST_ASM_STMT:
return sema_analyse_asm_stmt(context, statement);
@@ -922,7 +933,7 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
case AST_LABEL:
return sema_analyse_label(context, statement);
case AST_NOP_STMT:
return sema_analyse_nop_stmt(context, statement);
return true;
case AST_RETURN_STMT:
return sema_analyse_return_stmt(context, statement);
case AST_SWITCH_STMT:
@@ -932,7 +943,7 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
case AST_TRY_STMT:
return sema_analyse_try_stmt(context, statement);
case AST_NEXT_STMT:
UNREACHABLE
return sema_analyse_next_stmt(context, statement);
case AST_VOLATILE_STMT:
return sema_analyse_volatile_stmt(context, statement);
case AST_WHILE_STMT:
@@ -1007,6 +1018,7 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func)
return false;
}
}
VECEACH(context->gotos, i)
{
Ast *goto_stmt = context->gotos[i];
@@ -1018,14 +1030,15 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func)
}
// If there are no defers, then that's fine.
if (!goto_stmt->goto_stmt.defer && !label_target->label_stmt.defer) continue;
// First we need to search for the common depth.
int label_depth = defer_depth(label_target->label_stmt.defer);
int goto_depth = defer_depth(goto_stmt->goto_stmt.defer);
if (!goto_stmt->goto_stmt.defer.start && !label_target->label_stmt.defer) continue;
Ast *common_depth_label = label_target->label_stmt.defer;
Ast *common_depth_goto = goto_stmt->goto_stmt.defer;
Ast *common_depth_goto = goto_stmt->goto_stmt.defer.start;
// First we need to search for the common depth.
int label_depth = defer_depth(common_depth_label);
int goto_depth = defer_depth(common_depth_goto);
// Now walk up to the common depth.
defer_list_walk_to_common_depth(&common_depth_label, label_depth, goto_depth);
@@ -1040,17 +1053,18 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func)
}
// We now know the top defer (which we won't actually generate)
goto_stmt->goto_stmt.defer_end = common_depth_goto;
goto_stmt->goto_stmt.defer.end = common_depth_goto;
// Mark all defers that occur on the way "up" to the common depth conditional.
Ast *current = label_target->label_stmt.defer;
while (current != common_depth_goto)
{
current->defer_stmt.emit_boolean = true;
current = current->defer_stmt.prev_defer;
}
}
func->func.labels = context->labels;
context_pop_scope(context, &func->func.body, NULL);
context_pop_scope(context);
context->current_scope = NULL;
return true;
}
@@ -1062,7 +1076,9 @@ static inline bool sema_analyse_method_function(Context *context, Decl *decl)
if (!sema_resolve_type_info(context, parent_type)) return false;
if (!type_may_have_method_functions(parent_type->type))
{
SEMA_ERROR(decl, "Method functions can not be associated with '%s'", type_to_error_string(decl->func.type_parent->type));
SEMA_ERROR(decl,
"Method functions can not be associated with '%s'",
type_to_error_string(decl->func.type_parent->type));
return false;
}
Decl *parent = parent_type->type->decl;
@@ -1101,7 +1117,7 @@ static inline bool sema_analyse_func(Context *context, Decl *decl)
}
decl->visibility = VISIBLE_EXTERN;
}
DEBUG_LOG("Function analysis done.")
DEBUG_LOG("Function analysis done.");
return true;
}
@@ -1279,7 +1295,6 @@ bool sema_analyse_decl(Context *context, Decl *decl)
}
static void append_decls(Context *context, Decl **decls)
{
VECEACH(decls, i)
@@ -1287,6 +1302,7 @@ static void append_decls(Context *context, Decl **decls)
context_register_global_decl(context, decls[i]);
}
}
static inline bool sema_analyse_top_level_if(Context *context, Decl *ct_if)
{
int res = sema_check_comp_time_bool(context, ct_if->ct_if_decl.expr);
@@ -1387,7 +1403,16 @@ bool sema_resolve_type_info(Context *context, TypeInfo *type_info)
static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
{
Decl *ambiguous_decl;
Decl *decl = sema_resolve_symbol(context, type_info->unresolved.name_loc.string, type_info->unresolved.path, &ambiguous_decl);
Decl *decl = sema_resolve_symbol(context,
type_info->unresolved.name_loc.string,
type_info->unresolved.path,
&ambiguous_decl);
// Already handled
if (!decl_ok(decl))
{
return type_info_poison(type_info);
}
if (!decl)
{
@@ -1397,8 +1422,11 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
if (ambiguous_decl)
{
SEMA_TOKEN_ERROR(type_info->unresolved.name_loc, "Ambiguous type '%s' both defined in %s and %s, please add the module name to resolve the ambiguity", type_info->unresolved.name_loc.string,
decl->module->name->module, ambiguous_decl->module->name->module);
SEMA_TOKEN_ERROR(type_info->unresolved.name_loc,
"Ambiguous type '%s' both defined in %s and %s, please add the module name to resolve the ambiguity",
type_info->unresolved.name_loc.string,
decl->module->name->module,
ambiguous_decl->module->name->module);
return type_info_poison(type_info);
}
switch (decl->decl_kind)
@@ -1453,7 +1481,9 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info)
if (type_info->resolve_status == RESOLVE_RUNNING)
{
// TODO this is incorrect for unresolved expressions
SEMA_TOKEN_ERROR(type_info->unresolved.name_loc, "Circular dependency resolving type '%s'.", type_info->unresolved.name_loc.string);
SEMA_TOKEN_ERROR(type_info->unresolved.name_loc,
"Circular dependency resolving type '%s'.",
type_info->unresolved.name_loc.string);
return type_info_poison(type_info);
}

View File

@@ -15,4 +15,7 @@
#include <stdbool.h>
#define MAX_IDENTIFIER_LENGTH 31
#define PROJECT_TOML "project.toml"
#define PROJECT_TOML "project.toml"
#ifndef __unused
#define __unused
#endif

View File

@@ -27,7 +27,7 @@ void error_exit(const char *format, ...) __attribute__((noreturn));
#ifndef NDEBUG
#define DEBUG_LOG(_string, ...) eprintf("-- DEBUG: "); eprintf(_string, ##__VA_ARGS__); eprintf("\n");
#define DEBUG_LOG(_string, ...) eprintf("-- DEBUG: "); eprintf(_string, ##__VA_ARGS__); eprintf("\n")
#else
#define DEBUG_LOG(_string, ...)
#endif