More work on packages
This commit is contained in:
2
ast.cpp
2
ast.cpp
@@ -111,6 +111,8 @@ struct Ast_Binary: Ast_Expr{
|
||||
Token_Kind op;
|
||||
Ast_Expr *left;
|
||||
Ast_Expr *right;
|
||||
|
||||
Ast_Resolved_Type *type;
|
||||
};
|
||||
|
||||
// Problem: We are parsing out of order, in the middle of parsing a function
|
||||
|
||||
63
ccodegen.cpp
63
ccodegen.cpp
@@ -4,6 +4,8 @@
|
||||
global S32 global_indent;
|
||||
global S32 is_inside_struct;
|
||||
|
||||
function void gen_ast(Ast *ast);
|
||||
|
||||
function void
|
||||
gen_indent(){
|
||||
for(S32 i = 0; i < global_indent; i++) gen(" ");
|
||||
@@ -172,57 +174,13 @@ gen_expr(Ast_Expr *ast){
|
||||
// BREAK();
|
||||
// }
|
||||
|
||||
CASE(VAR, Decl){
|
||||
gen_ast(node);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(CALL, Call){
|
||||
// @todo: Reach into map instead of direct lookup
|
||||
if(is_struct(node->type) || is_array(node->type)){
|
||||
if(is_array(node->type)){
|
||||
gen("(Slice){%d, ", node->exprs.len);
|
||||
}
|
||||
gen("(");
|
||||
gen_simple_decl(node->type, {});
|
||||
gen(")");
|
||||
|
||||
gen("{");
|
||||
For(node->exprs){
|
||||
auto comp = it;
|
||||
if(comp->name){
|
||||
gen(".");
|
||||
gen_expr(comp->name);
|
||||
gen(" = ");
|
||||
}
|
||||
if(comp->index){
|
||||
gen("[");
|
||||
gen_expr(comp->index);
|
||||
gen("] = ");
|
||||
}
|
||||
assert(comp->item);
|
||||
gen_expr(comp->item);
|
||||
|
||||
if(!node->exprs.is_last(&it)) gen(", ");
|
||||
}
|
||||
gen("}");
|
||||
if(is_array(node->type)){
|
||||
gen("}");
|
||||
}
|
||||
}
|
||||
else{
|
||||
gen_expr(node->name);
|
||||
gen("(");
|
||||
auto name_for_printf = (Ast_Atom *)node->name;
|
||||
For(node->exprs){
|
||||
// @special_case @todo in the future this should be replaced
|
||||
// with []Any
|
||||
if(intern_printf == name_for_printf->intern_val && &it == node->exprs.data){
|
||||
Ast_Atom *atom = (Ast_Atom *)it->item;
|
||||
assert(atom->kind == AST_VALUE);
|
||||
assert(atom->type == untyped_string);
|
||||
gen("\"%s\"", atom->intern_val.str);
|
||||
}
|
||||
else gen_expr(it->item);
|
||||
if(!node->exprs.is_last(&it)) gen(", ");
|
||||
}
|
||||
gen(")");
|
||||
}
|
||||
unused(node);
|
||||
|
||||
BREAK();
|
||||
}
|
||||
@@ -237,8 +195,6 @@ gen_line(Ast *node){
|
||||
genln("#line %d", node->pos->line+1);
|
||||
}
|
||||
|
||||
function void
|
||||
gen_ast(Ast *ast);
|
||||
function void
|
||||
gen_stmt_scope(Ast_Scope *scope){
|
||||
gen("{");
|
||||
@@ -368,8 +324,7 @@ gen_ast(Ast *ast){
|
||||
gen(")");
|
||||
|
||||
if(lambda->scope) {
|
||||
// gen_stmt_scope(lambda->scope);
|
||||
// @todo stmts
|
||||
gen_stmt_scope(lambda->scope);
|
||||
}
|
||||
else gen(";");
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ struct Parse_Ctx:Lexer{
|
||||
U64 unique_ids;
|
||||
Map type_map;
|
||||
|
||||
Ast_Scope *current_scope;
|
||||
Array<Ast_Scope *> scopes;
|
||||
Ast_Package *resolving_package;
|
||||
Array<Ast_Decl *> ordered_decls;
|
||||
|
||||
@@ -221,6 +221,7 @@ parse_init(Parse_Ctx *ctx, Allocator *perm_allocator, Allocator *heap_allocator)
|
||||
ctx->perm = perm_allocator;
|
||||
ctx->heap = heap_allocator;
|
||||
ctx->gen = {ctx->perm};
|
||||
ctx->scopes = {ctx->heap};
|
||||
ctx->ordered_decls = {ctx->heap};
|
||||
ctx->type_map = {ctx->heap};
|
||||
bigint_allocator = ctx->perm;
|
||||
|
||||
24
lambdas.kl
24
lambdas.kl
@@ -28,16 +28,16 @@ add_10 :: (size: S64): S64
|
||||
|
||||
constant :: 20; result := constant + 10
|
||||
|
||||
v3 := add(1,2)
|
||||
v2 := add(a = 1, b = 2)
|
||||
v1 := add(a = 1)
|
||||
// v_err := add([0] = 1)
|
||||
v4 := add(b = 1, a = 2)
|
||||
// v_err := add([0] = 1, [1] = 2)
|
||||
// v_err := add([0] = 1, 10) // illegal
|
||||
// v_err := add([1] = 1) // illegal
|
||||
// v_err := add() // illegal
|
||||
|
||||
// v3 := add(1,2)
|
||||
// v2 := add(a = 1, b = 2)
|
||||
// v1 := add(a = 1)
|
||||
// // v_err := add([0] = 1)
|
||||
// v4 := add(b = 1, a = 2)
|
||||
// // v_err := add([0] = 1, [1] = 2)
|
||||
// // v_err := add([0] = 1, 10) // illegal
|
||||
// // v_err := add([1] = 1) // illegal
|
||||
// // v_err := add() // illegal
|
||||
v4 := constant
|
||||
return v4
|
||||
|
||||
return_constant :: (): S64
|
||||
@@ -45,8 +45,8 @@ return_constant :: (): S64
|
||||
return constant
|
||||
|
||||
returning_void :: (insert: S64)
|
||||
val1: S64 = return_constant()
|
||||
val2: S64 = add_10(val1)
|
||||
// val1: S64 = return_constant()
|
||||
// val2: S64 = add_10(val1)
|
||||
return
|
||||
|
||||
|
||||
|
||||
@@ -542,9 +542,6 @@ lex_restream(Lexer *lexer, String istream, String file){
|
||||
lexer->stream.line_begin = istream.str;
|
||||
lexer->stream.file = lexer->intern(file);
|
||||
|
||||
|
||||
lexer->tokens.clear();
|
||||
lexer->token_iter = 0;
|
||||
Scratch scratch;
|
||||
lexer->stream.indent_stack.allocator = scratch;
|
||||
lexer->stream.indent_stack.add(&token_null);
|
||||
|
||||
@@ -15,4 +15,5 @@ val := CONSTANT_VAL
|
||||
DEPENDENCE :: CONSTANT_VAL
|
||||
CONSTANT_VAL :: 10
|
||||
|
||||
thing: a_type = 10
|
||||
|
||||
|
||||
@@ -122,8 +122,6 @@ parse_init_stmt(Ast_Expr *expr){
|
||||
if(token->kind == TK_ColonAssign && expr->kind != AST_IDENT)
|
||||
compiler_error(expr->pos, "Binding with [:=] to something that is not an identifier");
|
||||
|
||||
|
||||
|
||||
else if(token_is_assign(token)){
|
||||
token_next();
|
||||
Ast_Expr *value = parse_expr();
|
||||
@@ -131,10 +129,11 @@ parse_init_stmt(Ast_Expr *expr){
|
||||
if(token->kind == TK_ColonAssign){
|
||||
Ast_Atom *name = (Ast_Atom *)expr;
|
||||
result = (Ast_Expr *)ast_var(token, 0, name->intern_val, value);
|
||||
set_flag(result->flags, AST_EXPR);
|
||||
} else{
|
||||
result = ast_expr_binary((Ast_Atom *)expr, value, token);
|
||||
}
|
||||
result->flags = set_flag(result->flags, AST_STMT);
|
||||
set_flag(result->flags, AST_STMT);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
242
typechecking.cpp
242
typechecking.cpp
@@ -330,98 +330,6 @@ require_const_int(Ast_Expr *expr, B32 ast_can_be_null){
|
||||
return op;
|
||||
}
|
||||
|
||||
function Operand
|
||||
resolve_and_require_bool(const char *error, Ast_Expr *expr, B32 ast_can_be_null = AST_CANT_BE_NULL){
|
||||
if(!expr){
|
||||
if(ast_can_be_null)
|
||||
return {};
|
||||
else compiler_error(0, "Compiler error: Null expression");
|
||||
}
|
||||
|
||||
Operand op = resolve_expr(expr);
|
||||
if(!is_bool(op.type)){
|
||||
compiler_error(expr->pos, "Expected type [Bool] got instead type %s :: %s", docname(op.type), error);
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
// @note: Ret is return value of function passed down the stack
|
||||
// to check if type matches
|
||||
function void
|
||||
resolve_stmt(Ast *ast, Ast_Resolved_Type *ret){
|
||||
if(!ast) return;
|
||||
|
||||
switch(ast->kind){
|
||||
CASE(RETURN, Return){ // @todo: need to check if all paths return a value
|
||||
Operand op = resolve_expr(node->expr);
|
||||
if(!op.type && ret != type_void) compiler_error(node->pos, "Function expects a void return value but the returned value is %s", docname(op.type));
|
||||
op.value = convert_untyped_to_typed(node->pos, op.value, ret);
|
||||
if(op.type && op.type != ret) compiler_error(node->pos, "Return statement has different type then returned value, expecting: %s got instead %s", docname(ret), docname(op.type));
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(VAR, Var){
|
||||
Operand op = resolve_binding(node);
|
||||
sym_var(node->name, op, node, INSERT_INTO_SCOPE);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(CONST, Const){
|
||||
Operand op = resolve_binding(node);
|
||||
sym_const(node->name, op, node, INSERT_INTO_SCOPE);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(PASS, Pass){
|
||||
unused(node);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(FOR, For){
|
||||
if(node->init && node->cond == 0 && node->iter == 0){
|
||||
if(!is_flag_set(node->init->flags, AST_STMT)){
|
||||
node->cond = node->init;
|
||||
node->init = 0;
|
||||
}
|
||||
}
|
||||
|
||||
S64 scope = scope_open();
|
||||
{
|
||||
resolve_expr(node->init, ret);
|
||||
resolve_and_require_bool("Conditional in a for loop condition", node->cond, AST_CAN_BE_NULL);
|
||||
resolve_expr(node->iter, ret);
|
||||
For(node->block->stmts)
|
||||
resolve_stmt(it, ret);
|
||||
}
|
||||
scope_close(scope);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(IF, If){
|
||||
For(node->ifs){
|
||||
resolve_stmt(it->init, ret);
|
||||
S64 scope = scope_open();
|
||||
{
|
||||
// @todo: maybe add else kind ?? and then make sure other then else are AST_CANT_BE_NULL
|
||||
resolve_and_require_bool("Conditional in a if condition", it->expr, AST_CAN_BE_NULL);
|
||||
For_It(it->block->stmts, jt)
|
||||
resolve_stmt(jt, ret);
|
||||
}
|
||||
scope_close(scope);
|
||||
}
|
||||
BREAK();
|
||||
}
|
||||
|
||||
default:{
|
||||
if(is_flag_set(ast->flags, AST_EXPR)){
|
||||
assert(is_flag_set(ast->flags, AST_STMT));
|
||||
resolve_expr((Ast_Expr *)ast);
|
||||
}
|
||||
else invalid_codepath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Operand
|
||||
resolve_lambda(Ast_Lambda *lambda, Sym *sym = 0){
|
||||
@@ -924,18 +832,19 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
|
||||
|
||||
#define Enter_Scope(x) Enter_Scope_Defer package_scope(x)
|
||||
struct Enter_Scope_Defer{
|
||||
Ast_Scope *scope;
|
||||
Ast_Package *package;
|
||||
Ast_Scope *scope = 0;
|
||||
Ast_Package *package = 0;
|
||||
Enter_Scope_Defer(Ast_Scope *new_p){
|
||||
scope = pctx->current_scope;
|
||||
pctx->current_scope = new_p;
|
||||
pctx->scopes.add(new_p);
|
||||
scope = new_p;
|
||||
if(new_p->kind == AST_PACKAGE){
|
||||
package = pctx->resolving_package;
|
||||
pctx->resolving_package = (Ast_Package *)new_p;
|
||||
}
|
||||
}
|
||||
~Enter_Scope_Defer(){
|
||||
pctx->current_scope = scope;
|
||||
Ast_Scope *poped = pctx->scopes.pop();
|
||||
assert(poped == scope);
|
||||
if(package){
|
||||
pctx->resolving_package = package;
|
||||
}
|
||||
@@ -954,9 +863,15 @@ search_for_decl(Ast_Scope *scope, Intern_String name){
|
||||
|
||||
function Ast_Decl *
|
||||
search_for_decl_in_current_context(Intern_String name){
|
||||
Ast_Decl *result = search_for_decl(pctx->current_scope, name);
|
||||
Ast_Decl *result = 0;
|
||||
for(S64 i = pctx->scopes.len - 1; i >= 0; i--){
|
||||
result = search_for_decl(pctx->scopes[i], name);
|
||||
if(result) break;
|
||||
}
|
||||
|
||||
if(!result)
|
||||
result = search_for_decl(pctx->resolving_package, name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -967,7 +882,7 @@ insert_into_scope(Ast_Scope *scope, Ast_Decl *decl){
|
||||
|
||||
function void
|
||||
insert_into_current_scope(Ast_Decl *decl){
|
||||
insert_into_scope(pctx->current_scope, decl);
|
||||
insert_into_scope(*pctx->scopes.last(), decl);
|
||||
}
|
||||
|
||||
function void
|
||||
@@ -1006,6 +921,22 @@ resolve_typespec(Ast_Expr *ast, B32 flags){
|
||||
return resolved.type_val;
|
||||
}
|
||||
|
||||
function Operand
|
||||
resolve_and_require_bool(const char *error, Ast_Expr *expr, B32 flags){
|
||||
if(!expr){
|
||||
if(flags == AST_CAN_BE_NULL)
|
||||
return {};
|
||||
else compiler_error(0, "Compiler error: Null expression");
|
||||
}
|
||||
|
||||
Operand op = resolve_expr(expr, flags);
|
||||
if(!is_bool(op.type)){
|
||||
compiler_error(expr->pos, "Expected type [Bool] got instead type %s :: %s", docname(op.type), error);
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
function Operand
|
||||
require_const_int(Ast_Expr *expr, B32 flags){
|
||||
Operand op = resolve_expr(expr, flags);
|
||||
@@ -1023,6 +954,15 @@ require_const_int(Ast_Expr *expr, B32 flags){
|
||||
return op;
|
||||
}
|
||||
|
||||
function void
|
||||
resolve_const(Ast_Decl *node){
|
||||
Operand op = resolve_expr(node->expr, AST_CANT_BE_NULL);
|
||||
if(!op.is_const){
|
||||
compiler_error(node->pos, "Assigning a value that is not constant to a constant declaration");
|
||||
}
|
||||
node->value = op.value;
|
||||
}
|
||||
|
||||
function void
|
||||
resolve_var(Ast_Decl *node){
|
||||
Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL);
|
||||
@@ -1033,6 +973,83 @@ resolve_var(Ast_Decl *node){
|
||||
node->value = op.value;
|
||||
}
|
||||
|
||||
// @note: Ret is return value of function passed down the stack
|
||||
// to check if type matches
|
||||
function void
|
||||
resolve_stmt(Ast *ast, Ast_Resolved_Type *ret){
|
||||
if(!ast) return;
|
||||
|
||||
switch(ast->kind){
|
||||
CASE(RETURN, Return){ // @todo: need to check if all paths return a value
|
||||
Operand op = resolve_expr(node->expr, AST_CAN_BE_NULL);
|
||||
if(!op.type && ret != type_void) compiler_error(node->pos, "Function expects a void return value but the returned value is %s", docname(op.type));
|
||||
op.value = convert_untyped_to_typed(node->pos, op.value, ret);
|
||||
if(op.type && op.type != ret) compiler_error(node->pos, "Return statement has different type then returned value, expecting: %s got instead %s", docname(ret), docname(op.type));
|
||||
BREAK();
|
||||
}
|
||||
|
||||
// CASE(VAR, Decl){
|
||||
// resolve_decl(node);
|
||||
// insert_into_current_scope(node);
|
||||
// BREAK();
|
||||
// }
|
||||
|
||||
case AST_LAMBDA:
|
||||
case AST_VAR:
|
||||
CASE(CONST, Decl){
|
||||
resolve_decl(node);
|
||||
insert_into_current_scope(node);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(PASS, Pass){
|
||||
unused(node);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(FOR, For){
|
||||
if(node->init && node->cond == 0 && node->iter == 0){
|
||||
if(!is_flag_set(node->init->flags, AST_STMT)){
|
||||
node->cond = node->init;
|
||||
node->init = 0;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Enter_Scope(node->scope);
|
||||
resolve_expr(node->init, AST_CAN_BE_NULL);
|
||||
resolve_and_require_bool("Conditional in a for loop condition", node->cond, AST_CAN_BE_NULL);
|
||||
resolve_expr(node->iter, AST_CAN_BE_NULL);
|
||||
For(node->scope->stmts)
|
||||
resolve_stmt(it, ret);
|
||||
}
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(IF, If){
|
||||
For(node->ifs){
|
||||
resolve_stmt(it->init, ret);
|
||||
{
|
||||
Enter_Scope(it->scope);
|
||||
// @todo: maybe add else kind ?? and then make sure other then else are AST_CANT_BE_NULL
|
||||
resolve_and_require_bool("Conditional in a if condition", it->expr, AST_CAN_BE_NULL);
|
||||
For_It(it->scope->stmts, jt)
|
||||
resolve_stmt(jt, ret);
|
||||
}
|
||||
}
|
||||
BREAK();
|
||||
}
|
||||
|
||||
default:{
|
||||
if(is_flag_set(ast->flags, AST_EXPR)){
|
||||
assert(is_flag_set(ast->flags, AST_STMT));
|
||||
resolve_expr((Ast_Expr *)ast, AST_CANT_BE_NULL);
|
||||
}
|
||||
else invalid_codepath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Operand
|
||||
resolve_expr(Ast_Expr *ast, B32 flags){
|
||||
if(!ast && flags == AST_CAN_BE_NULL) return {};
|
||||
@@ -1046,6 +1063,12 @@ resolve_expr(Ast_Expr *ast, B32 flags){
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(CALL, Call){
|
||||
unused(node);
|
||||
// return {};
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(IDENT, Atom){
|
||||
Ast_Decl *decl = resolve_name(node->pos, node->intern_val);
|
||||
|
||||
@@ -1065,12 +1088,6 @@ resolve_expr(Ast_Expr *ast, B32 flags){
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(VAR, Decl){
|
||||
resolve_var(node);
|
||||
insert_into_current_scope(node);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(BINARY, Binary){
|
||||
if(token_is_assign(node->op)){
|
||||
assert(is_flag_set(node->flags, AST_STMT));
|
||||
@@ -1097,6 +1114,12 @@ resolve_expr(Ast_Expr *ast, B32 flags){
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(VAR, Decl){
|
||||
resolve_stmt(node, 0);
|
||||
return {};
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(UNARY, Unary){
|
||||
Operand value = resolve_expr(node->expr, AST_CANT_BE_NULL);
|
||||
if(node->op == TK_Pointer){
|
||||
@@ -1177,8 +1200,7 @@ resolve_decl(Ast_Decl *ast){
|
||||
insert_into_current_scope(it);
|
||||
}
|
||||
For(lambda->scope->stmts){
|
||||
unused(it);
|
||||
// resolve_stmt(it, ret_type);
|
||||
resolve_stmt(it, ret_type);
|
||||
}
|
||||
|
||||
result = operand_lambda(lambda_type);
|
||||
@@ -1190,11 +1212,7 @@ resolve_decl(Ast_Decl *ast){
|
||||
}
|
||||
|
||||
CASE(CONST, Decl){
|
||||
Operand op = resolve_expr(node->expr, AST_CANT_BE_NULL);
|
||||
if(!op.is_const){
|
||||
compiler_error(node->pos, "Assigning a value that is not constant to a constant declaration");
|
||||
}
|
||||
node->value = op.value;
|
||||
resolve_const(node);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user