Closer to old state
This commit is contained in:
7
ast.cpp
7
ast.cpp
@@ -29,6 +29,7 @@ enum Ast_Kind: U32{
|
||||
AST_BLOCK,
|
||||
AST_PASS,
|
||||
AST_LAMBDA,
|
||||
AST_LAMBDA_EXPR,
|
||||
AST_LAMBDA_ARG,
|
||||
AST_ENUM,
|
||||
AST_ENUM_MEMBER,
|
||||
@@ -100,11 +101,14 @@ struct Ast_Unary: Ast_Expr{
|
||||
struct Ast_Cast: Ast_Expr{
|
||||
Ast_Expr *expr;
|
||||
Ast_Expr *typespec;
|
||||
Ast_Resolved_Type *before_type;
|
||||
Ast_Resolved_Type *after_type;
|
||||
};
|
||||
|
||||
struct Ast_Index: Ast_Expr{
|
||||
Ast_Expr *expr;
|
||||
Ast_Expr *index;
|
||||
Ast_Resolved_Type *original_type;
|
||||
};
|
||||
|
||||
struct Ast_Binary: Ast_Expr{
|
||||
@@ -154,6 +158,7 @@ struct Ast_Lambda : Ast_Expr {
|
||||
struct Ast_Array: Ast_Expr{
|
||||
Ast_Expr *base;
|
||||
Ast_Expr *expr;
|
||||
Ast_Resolved_Type *type;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -335,7 +340,7 @@ ast_expr_index(Token *pos, Ast_Expr *expr, Ast_Expr *index){
|
||||
|
||||
function Ast_Lambda *
|
||||
ast_lambda(Token *pos, Array<Ast_Decl *> params, B32 has_var_args, Ast_Expr *ret, Ast_Scope *scope){
|
||||
AST_NEW(Lambda, LAMBDA, pos, AST_EXPR);
|
||||
AST_NEW(Lambda, LAMBDA_EXPR, pos, AST_EXPR);
|
||||
result->flags = AST_EXPR;
|
||||
result->args = params.tight_copy(pctx->perm);
|
||||
result->scope = scope;
|
||||
|
||||
51
ccodegen.cpp
51
ccodegen.cpp
@@ -164,15 +164,15 @@ gen_expr(Ast_Expr *ast){
|
||||
BREAK();
|
||||
}
|
||||
|
||||
// CASE(CAST, Cast){
|
||||
// gen("(");
|
||||
// gen("(");
|
||||
// gen_simple_decl(resolved_type_get(node->typespec), {});
|
||||
// gen(")");
|
||||
// gen_expr(node->expr);
|
||||
// gen(")");
|
||||
// BREAK();
|
||||
// }
|
||||
CASE(CAST, Cast){
|
||||
gen("(");
|
||||
gen("(");
|
||||
gen_simple_decl(node->after_type, {});
|
||||
gen(")");
|
||||
gen_expr(node->expr);
|
||||
gen(")");
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(VAR, Decl){
|
||||
gen_ast(node);
|
||||
@@ -180,8 +180,13 @@ gen_expr(Ast_Expr *ast){
|
||||
}
|
||||
|
||||
CASE(CALL, Call){
|
||||
unused(node);
|
||||
|
||||
gen_expr(node->name);
|
||||
gen("(");
|
||||
For(node->exprs){
|
||||
gen_expr(it->item);
|
||||
if(!node->exprs.is_last(&it)) gen(", ");
|
||||
}
|
||||
gen(")");
|
||||
BREAK();
|
||||
}
|
||||
|
||||
@@ -215,11 +220,7 @@ enum {
|
||||
|
||||
function void
|
||||
gen_var(Intern_String name, Ast_Resolved_Type *type, Ast_Expr *expr, B32 emit_value){
|
||||
if(is_array(type)){
|
||||
gen("Slice %s", name.str);
|
||||
} else{
|
||||
gen_simple_decl(type, name);
|
||||
}
|
||||
|
||||
if(emit_value == DONT_EMIT_VALUE){
|
||||
return;
|
||||
@@ -228,11 +229,6 @@ gen_var(Intern_String name, Ast_Resolved_Type *type, Ast_Expr *expr, B32 emit_va
|
||||
if(expr){
|
||||
gen(" = ");
|
||||
gen_expr(expr);
|
||||
} else if(is_array(type)){
|
||||
gen(" = (Slice){%d, (", type->arr.size);
|
||||
gen_simple_decl(type, {});
|
||||
gen("){}");
|
||||
gen("}");
|
||||
} else { // Default zero
|
||||
if(is_numeric(type)){
|
||||
gen(" = 0");
|
||||
@@ -337,6 +333,21 @@ gen_ast(Ast *ast){
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(STRUCT, Decl){
|
||||
gen("typedef struct %s{", node->name.str);
|
||||
global_indent++;
|
||||
is_inside_struct++;
|
||||
For(node->scope->decls){
|
||||
genln("");
|
||||
gen_ast(it);
|
||||
}
|
||||
|
||||
is_inside_struct--;
|
||||
global_indent--;
|
||||
genln("}%s;", node->name.str);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(CONST, Decl){
|
||||
switch(node->type->kind){
|
||||
CASE_FLOAT:{
|
||||
|
||||
@@ -28,7 +28,7 @@ add_10 :: (size: S64): S64
|
||||
|
||||
constant :: 20; result := constant + 10
|
||||
|
||||
// v3 := add(1,2)
|
||||
v3 := add(1,2)
|
||||
// v2 := add(a = 1, b = 2)
|
||||
// v1 := add(a = 1)
|
||||
// // v_err := add([0] = 1)
|
||||
|
||||
1
main.cpp
1
main.cpp
@@ -221,6 +221,7 @@ int main(int argument_count, char **arguments){
|
||||
Array<String> files = {scratch};
|
||||
files.add("lambdas.kl"_s);
|
||||
files.add("order1.kl"_s);
|
||||
files.add("order2.kl"_s);
|
||||
String result = compile_files(files);
|
||||
printf("%s", result.str);
|
||||
__debugbreak();
|
||||
|
||||
25
order2.kl
25
order2.kl
@@ -1,37 +1,14 @@
|
||||
Str16 :: String16
|
||||
// arena_pointer: *Arena = null
|
||||
arena_pointer: *Arena = 0
|
||||
thing: Arena
|
||||
no_type := thing
|
||||
constant_access := Arena.constant_inside
|
||||
|
||||
arena := Arena(
|
||||
// next = null,
|
||||
// data = null,
|
||||
len = 1000,
|
||||
cap = 1000,
|
||||
)
|
||||
|
||||
// lambda_value := (val: S64) // @todo
|
||||
// return
|
||||
|
||||
Arena :: struct
|
||||
// arena: Arena
|
||||
next: *Arena
|
||||
data: *S64
|
||||
len : S64
|
||||
cap : S64
|
||||
|
||||
Sub :: struct
|
||||
len: S64
|
||||
Sub_Sub :: struct
|
||||
len: S64
|
||||
|
||||
get_len :: (s: *Arena): S64 // @todo
|
||||
return s.next.len
|
||||
|
||||
constant_inside :: 10000
|
||||
|
||||
// subarena: Arena.Sub // @todo
|
||||
string16: Str16
|
||||
|
||||
String16 :: struct
|
||||
|
||||
@@ -581,7 +581,7 @@ parse_decl(B32 is_global){
|
||||
Ast_Expr *expr = parse_expr();
|
||||
result = ast_const(tname, tname->intern_val, expr);
|
||||
|
||||
if(expr->kind == AST_LAMBDA){
|
||||
if(expr->kind == AST_LAMBDA_EXPR){
|
||||
auto a = (Ast_Lambda *)expr;
|
||||
if(a->scope){
|
||||
result->kind = AST_LAMBDA;
|
||||
|
||||
541
typechecking.cpp
541
typechecking.cpp
@@ -295,8 +295,7 @@ make_sure_value_is_compatible_with_type(Token *pos, Operand *expr, Ast_Resolved_
|
||||
compiler_error(pos, "Assigning but incompatible types, expression: %s expected var type: %s", docname(expr->type), docname(type));
|
||||
}
|
||||
|
||||
// @todo
|
||||
// type_complete(expr->type);
|
||||
type_complete(expr->type);
|
||||
check_value_bounds(pos, &expr->value);
|
||||
assert(expr->type);
|
||||
}
|
||||
@@ -306,7 +305,7 @@ function void
|
||||
_rewrite_into_const(Ast *node, U64 ast_size, Value value){
|
||||
auto ast = (Ast_Atom *)node;
|
||||
assert(ast_size >= sizeof(Ast_Atom));
|
||||
ast->flags = set_flag(ast->flags, AST_ATOM);
|
||||
set_flag(ast->flags, AST_ATOM);
|
||||
ast->kind = AST_VALUE;
|
||||
ast->value = value;
|
||||
}
|
||||
@@ -331,82 +330,6 @@ require_const_int(Ast_Expr *expr, B32 ast_can_be_null){
|
||||
}
|
||||
|
||||
|
||||
function Operand
|
||||
resolve_lambda(Ast_Lambda *lambda, Sym *sym = 0){
|
||||
Scratch scratch;
|
||||
Ast_Resolved_Type *lambda_type = 0;
|
||||
Ast_Resolved_Type *ret_type = resolve_typespec(lambda->ret);
|
||||
Array<Ast_Resolved_Type *> args = {scratch};
|
||||
For(lambda->args){
|
||||
Ast_Resolved_Type *type =
|
||||
resolve_typespec(it->typespec, AST_CANT_BE_NULL);
|
||||
Operand default_value = resolve_expr(it->default_value, type);
|
||||
make_sure_value_is_compatible_with_type(it->pos, &default_value, type, EXPR_CAN_BE_NULL);
|
||||
args.add(type);
|
||||
}
|
||||
|
||||
lambda_type = type_lambda(lambda, ret_type, args);
|
||||
sym_type(lambda_type, lambda);
|
||||
Operand result = operand_type(lambda_type);
|
||||
|
||||
// @note: top level lambda needs to get marked as resolved
|
||||
// so that the cyclic dependency wont trigger
|
||||
if(sym){
|
||||
sym->type = lambda_type;
|
||||
sym->state = SYM_RESOLVED;
|
||||
}
|
||||
|
||||
// @todo: We also need to make sure there is a return value when ret type is not void
|
||||
// @note: then try resolving the block of lambda
|
||||
if(lambda->block){
|
||||
S64 scope_index = scope_open();
|
||||
For(lambda->args){
|
||||
S64 i = lambda->args.get_index(&it);
|
||||
Ast_Resolved_Type *type = args[i];
|
||||
sym_var(it->name, type, it, INSERT_INTO_SCOPE);
|
||||
}
|
||||
For(lambda->block->stmts){
|
||||
resolve_stmt(it, ret_type);
|
||||
}
|
||||
scope_close(scope_index);
|
||||
|
||||
result = operand_lambda(lambda_type);
|
||||
}
|
||||
else if(is_flag_set(lambda->parent->flags, AST_FOREIGN)){
|
||||
result = operand_lambda(lambda_type);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function Operand
|
||||
field_access_builtin_string(Ast_Expr *right){
|
||||
if(right->kind == AST_BINARY) invalid_codepath; // @todo entire field access needs a rework
|
||||
assert(right->kind == AST_IDENT);
|
||||
|
||||
auto a = (Ast_Atom *)right;
|
||||
if(a->intern_val == pctx->intern("len"_s)){
|
||||
return operand_lvalue(type_s64);
|
||||
}
|
||||
else if(a->intern_val == pctx->intern("str"_s)){
|
||||
return operand_lvalue(type_pointer(type_u8));
|
||||
}
|
||||
else invalid_return;
|
||||
}
|
||||
|
||||
function Operand
|
||||
field_access_builtin_array(Ast_Expr *right){
|
||||
if(right->kind == AST_BINARY) invalid_codepath; // @todo entire field access needs a rework
|
||||
assert(right->kind == AST_IDENT);
|
||||
|
||||
auto a = (Ast_Atom *)right;
|
||||
if(a->intern_val == pctx->intern("len"_s)){
|
||||
return operand_lvalue(type_s64);
|
||||
}
|
||||
else invalid_return;
|
||||
}
|
||||
|
||||
|
||||
function Operand
|
||||
resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_resolve){
|
||||
@@ -414,257 +337,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
|
||||
assert(is_flag_set(ast->flags, AST_EXPR));
|
||||
|
||||
switch(ast->kind){
|
||||
CASE(VALUE, Atom){
|
||||
return operand_const_rvalue(node->value);
|
||||
BREAK();
|
||||
}
|
||||
CASE(IDENT, Atom){
|
||||
Sym *sym = resolve_name(node->pos, node->intern_val);
|
||||
|
||||
if(sym->kind == SYM_CONST && sym->type != type_type && sym->type->kind != TYPE_LAMBDA){
|
||||
rewrite_into_const(node, Ast_Atom, sym);
|
||||
return operand(sym);
|
||||
}
|
||||
else if(sym->kind == SYM_VAR || sym->kind == SYM_CONST){
|
||||
sym_associate(node, sym);
|
||||
return operand(sym);
|
||||
}
|
||||
|
||||
invalid_return;
|
||||
BREAK();
|
||||
}
|
||||
|
||||
// Typespec array [32]int
|
||||
CASE(ARRAY, Array){
|
||||
// @todo: Arrays of inferred size []
|
||||
Operand type = resolve_expr(node->base);
|
||||
if(type.type != type_type) compiler_error(node->pos, "Prefix array operator is only allowed on types");
|
||||
Operand expr = require_const_int(node->expr, AST_CAN_BE_NULL);
|
||||
|
||||
Ast_Resolved_Type *resolved = type_array(type.type_val, node->expr ? 1 : 0, bigint_as_unsigned(&expr.big_int_val));
|
||||
sym_type(resolved, node);
|
||||
return operand_type(resolved);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(INDEX, Index){
|
||||
Operand left = resolve_expr(node->expr);
|
||||
Operand index = resolve_expr(node->index);
|
||||
if(!is_int(index.type)){
|
||||
|
||||
compiler_error(node->pos, "Trying to index the array with invalid type, expected [Int] got instead %s", docname(index.type));
|
||||
}
|
||||
if(!is_array(left.type) && !is_pointer(left.type)){
|
||||
compiler_error(node->pos, "Indexing variable that is not an [Array] or [Pointer], it's of type %s instead", docname(left.type));
|
||||
}
|
||||
|
||||
sym_new_resolved(SYM_VAR, {}, left.value, node);
|
||||
return operand_lvalue(left.type->arr.base);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(LAMBDA, Lambda){
|
||||
return resolve_lambda(node);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(CALL, Call){
|
||||
Operand name = resolve_expr(node->name);
|
||||
Ast_Resolved_Type *type = name.type;
|
||||
if(name.type == type_type){
|
||||
type = name.type_val;
|
||||
if(expected_type && expected_type != type)
|
||||
compiler_error(node->pos, "Variable type different from explicit compound type");
|
||||
if(type->kind == TYPE_LAMBDA)
|
||||
compiler_error(node->pos, "Calling a lambda type");
|
||||
}
|
||||
type_complete(type);
|
||||
node->type = type;
|
||||
|
||||
if(type->kind == TYPE_ARRAY){
|
||||
if(node->exprs.len > type->arr.size && type->arr.size != ARRAY_SIZE_INFERRED)
|
||||
compiler_error(node->pos, "compound statement has too many items for this type");
|
||||
Ast_Resolved_Type *item_type = type->arr.base;
|
||||
|
||||
For(node->exprs){
|
||||
Ast_Call_Item *i = (Ast_Call_Item *)it;
|
||||
assert(i->kind == AST_CALL_ITEM);
|
||||
if(i->name) compiler_error(i->pos, "Invalid indexing kind in a compound expression of type %s", type_names[type->kind]);
|
||||
if(i->index){
|
||||
Operand index_op = require_const_int(i->index, AST_CANT_BE_NULL);
|
||||
U64 index = bigint_as_unsigned(&index_op.big_int_val);
|
||||
if(index > (type->arr.size - 1)) compiler_error(i->pos, "Invalid index in compound expression, larger then type can store");
|
||||
}
|
||||
Operand expr = resolve_expr(i->item, item_type);
|
||||
expr.value = convert_untyped_to_typed(i->pos, expr.value, item_type);
|
||||
// @todo I don't think this detects when types are different
|
||||
}
|
||||
}
|
||||
|
||||
else if(type->kind == TYPE_STRUCT){
|
||||
auto agg = (Ast_Struct *)type->ast;
|
||||
|
||||
S64 default_iter = 0;
|
||||
For_It(node->exprs, expr){
|
||||
if(expr->index) compiler_error(expr->index->pos, "Function call indexing is illegal");
|
||||
Ast_Atom *name = expr->name;
|
||||
S64 expr_index = node->exprs.get_index(&expr);
|
||||
|
||||
Ast_Named *found = 0;
|
||||
Ast_Resolved_Member *found_type = 0;
|
||||
if(name){
|
||||
assert(name->kind == AST_IDENT);
|
||||
For_It(agg->members, member){
|
||||
if(member->name.str == name->intern_val.str){
|
||||
if(member->kind == AST_CONST) compiler_error(expr->pos, "Initializing a value that is a constant");
|
||||
found = member;
|
||||
found_type = &type->agg.members[agg->members.get_index(&member)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(expr_index == default_iter){
|
||||
S64 i = default_iter++;
|
||||
found = agg->members[i];
|
||||
found_type = &type->agg.members[i];
|
||||
if(i >= agg->members.len) compiler_error(expr->pos, "Too many arguments in compound constructor");
|
||||
}
|
||||
else compiler_error(expr->pos, "Positional argument after named or indexed argument");
|
||||
|
||||
if(!found) compiler_error(expr->pos, "Invalid argument in compound constructor");
|
||||
if(is_flag_set(found->flags, AST_ITEM_INCLUDED)) compiler_error(found->pos, "Item included multiple times in compound constructor");
|
||||
found->flags = set_flag(found->flags, AST_ITEM_INCLUDED);
|
||||
|
||||
Operand op = resolve_expr(expr->item, found_type->type);
|
||||
|
||||
op.value = convert_untyped_to_typed(node->pos, op.value, found_type->type);
|
||||
if(found_type->type != op.type) compiler_error(expr->pos, "Invalid type of compound constructor item, expected %s got instead %s", type_names[found_type->type->kind], type_names[op.type->kind]);
|
||||
}
|
||||
|
||||
// @note: cleanup, required?
|
||||
For(agg->members) it->flags = unset_flag(it->flags, AST_ITEM_INCLUDED);
|
||||
}
|
||||
else if(type->kind == TYPE_LAMBDA){
|
||||
Scratch scratch;
|
||||
Array<Ast_Call_Item *> items = {scratch};
|
||||
|
||||
S64 was_name_indexed = false;
|
||||
S64 default_iter = 0;
|
||||
auto lambda = (Ast_Lambda *)type->ast;
|
||||
For(lambda->args){
|
||||
S64 i = lambda->args.get_index(&it);
|
||||
Ast_Resolved_Type *resolved = type->func.args[i];
|
||||
Ast_Lambda_Arg *arg = it;
|
||||
|
||||
// @note: match any in list of call items, if none matched then we have a problem
|
||||
// there are three kinds of possible matches: indexed, named, default
|
||||
Ast_Call_Item *item = 0;
|
||||
For_It(node->exprs, expr){
|
||||
if(expr->index) compiler_error(expr->index->pos, "Function call indexing is illegal");
|
||||
Ast_Atom *name = expr->name;
|
||||
|
||||
if(name){
|
||||
assert(name->kind == AST_IDENT);
|
||||
was_name_indexed = true;
|
||||
if(name->intern_val.str == arg->name.str) item = expr;
|
||||
}
|
||||
else if(node->exprs.get_index(&expr) == default_iter){
|
||||
default_iter++;
|
||||
item = expr;
|
||||
}
|
||||
else if(node->exprs.get_index(&expr) > default_iter){
|
||||
compiler_error(expr->pos, "Positional argument after named argument");
|
||||
}
|
||||
|
||||
if(item)
|
||||
break;
|
||||
}
|
||||
|
||||
if(item){
|
||||
item->flags = set_flag(item->flags, AST_ITEM_INCLUDED);
|
||||
Operand expr = resolve_expr(item->item);
|
||||
make_sure_value_is_compatible_with_type(node->pos, &expr, resolved, TYPE_AND_EXPR_REQUIRED);
|
||||
items.add(item);
|
||||
}
|
||||
else{
|
||||
if(arg->default_value){
|
||||
Ast_Call_Item *item_default = ast_call_item(arg->default_value->pos, 0, 0, arg->default_value);
|
||||
items.add(item_default);
|
||||
}
|
||||
else compiler_error(arg->pos, "Required value in lambda call was not passed");
|
||||
}
|
||||
}
|
||||
|
||||
if(lambda->has_var_args){
|
||||
if(was_name_indexed)
|
||||
compiler_error(lambda->pos, "Cant name index a lambda with var args");
|
||||
for(S64 i = lambda->args.len; i < node->exprs.len; i++){
|
||||
Ast_Call_Item *item = node->exprs.data[i];
|
||||
resolve_expr(item->item);
|
||||
item->flags = set_flag(item->flags, AST_ITEM_INCLUDED);
|
||||
items.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
// @note: check if all arguments are included and cleanup
|
||||
For(node->exprs){
|
||||
if(!is_flag_set(it->flags, AST_ITEM_INCLUDED))
|
||||
compiler_error(it->pos, "Invalid argument to function call");
|
||||
else it->flags = unset_flag(it->flags, AST_ITEM_INCLUDED);
|
||||
}
|
||||
|
||||
node->exprs = items.tight_copy(pctx->perm);
|
||||
type = type->func.ret;
|
||||
}
|
||||
else compiler_error(node->pos, "Invalid function call type");
|
||||
|
||||
return operand_rvalue(type);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(CAST, Cast){
|
||||
Operand expr = resolve_expr(node->expr);
|
||||
Ast_Resolved_Type *type = resolve_typespec(node->typespec);
|
||||
Ast_Resolved_Type *original_type = expr.type;
|
||||
|
||||
// @todo: cleanup, probably just want one big if
|
||||
// @todo: factor this into a function for easier search
|
||||
|
||||
switch(expr.type->kind){
|
||||
case TYPE_POINTER:{
|
||||
if(is_pointer(type))
|
||||
expr = operand_rvalue(type);
|
||||
else goto failure;
|
||||
} break;
|
||||
CASE_UNTYPED: {
|
||||
expr.value = convert_untyped_to_typed(node->pos, expr.value, type);
|
||||
} break;
|
||||
CASE_UINT:
|
||||
CASE_SINT:{
|
||||
if(is_int(type))
|
||||
expr.type = type;
|
||||
else if(is_float(type)){
|
||||
expr.value.type = type;
|
||||
if(expr.is_const) expr.value.f64_val = bigint_as_float(&expr.big_int_val); // @leak
|
||||
} else goto failure;
|
||||
} break;
|
||||
case TYPE_F32: case TYPE_F64: {
|
||||
if(is_float(type)){
|
||||
expr.type = type;
|
||||
}
|
||||
else if(is_int(type)){
|
||||
if(expr.is_const) expr.value.big_int_val = bigint_s64((S64)expr.value.f64_val); // @todo: What to do here???
|
||||
expr.type = type;
|
||||
} else goto failure;
|
||||
} break;
|
||||
default: failure: compiler_error(node->pos, "Failed to cast from %s to %s", docname(expr.type), docname(type));;
|
||||
}
|
||||
|
||||
if(original_type != type) assert(expr.type == type);
|
||||
if(expr.is_const) check_value_bounds(node->pos, &expr.value);
|
||||
return expr;
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(UNARY, Unary){
|
||||
Operand value = resolve_expr(node->expr);
|
||||
@@ -912,10 +585,12 @@ insert_builtin_types_into_package(Ast_Package *p){
|
||||
|
||||
function Ast_Resolved_Type *
|
||||
resolve_typespec(Ast_Expr *ast, B32 flags){
|
||||
if(!ast && flags == AST_CAN_BE_NULL)
|
||||
if(!ast && is_flag_set(flags, AST_CAN_BE_NULL))
|
||||
return 0;
|
||||
|
||||
Operand resolved = resolve_expr(ast, flags);
|
||||
if(is_flag_set(flags, RESOLVE_TYPESPEC_COMPLETE))
|
||||
type_complete(resolved.type);
|
||||
if(resolved.type != type_type)
|
||||
compiler_error(ast->pos, "Expected [Type] got instead %s", type_names[resolved.type->kind]);
|
||||
return resolved.type_val;
|
||||
@@ -954,25 +629,6 @@ 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);
|
||||
Operand op = resolve_expr(node->expr, AST_CAN_BE_NULL);
|
||||
assert(op.type != 0 || type != 0);
|
||||
|
||||
make_sure_value_is_compatible_with_type(node->pos, &op, type, EXPR_CAN_BE_NULL|TYPE_CAN_BE_NULL);
|
||||
node->value = op.value;
|
||||
}
|
||||
|
||||
// @note: Ret is return value of function passed down the stack
|
||||
// to check if type matches
|
||||
function void
|
||||
@@ -988,16 +644,10 @@ resolve_stmt(Ast *ast, Ast_Resolved_Type *ret){
|
||||
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);
|
||||
resolve_decl(node, IS_NOT_PACKAGE_GLOBAL);
|
||||
insert_into_current_scope(node);
|
||||
BREAK();
|
||||
}
|
||||
@@ -1050,9 +700,54 @@ resolve_stmt(Ast *ast, Ast_Resolved_Type *ret){
|
||||
}
|
||||
}
|
||||
|
||||
function Operand
|
||||
resolve_cast(Ast_Cast *node){
|
||||
Operand expr = resolve_expr(node->expr, AST_CANT_BE_NULL);
|
||||
Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CANT_BE_NULL);
|
||||
Ast_Resolved_Type *original_type = expr.type;
|
||||
node->before_type = expr.type;
|
||||
|
||||
// @todo: cleanup, probably just want one big if
|
||||
switch(expr.type->kind){
|
||||
case TYPE_POINTER:{
|
||||
if(is_pointer(type))
|
||||
expr = operand_rvalue(type);
|
||||
else goto failure;
|
||||
} break;
|
||||
CASE_UNTYPED: {
|
||||
expr.value = convert_untyped_to_typed(node->pos, expr.value, type);
|
||||
} break;
|
||||
CASE_UINT:
|
||||
CASE_SINT:{
|
||||
if(is_int(type))
|
||||
expr.type = type;
|
||||
else if(is_float(type)){
|
||||
expr.value.type = type;
|
||||
if(expr.is_const) expr.value.f64_val = bigint_as_float(&expr.big_int_val); // @leak
|
||||
} else goto failure;
|
||||
} break;
|
||||
case TYPE_F32: case TYPE_F64: {
|
||||
if(is_float(type)){
|
||||
expr.type = type;
|
||||
}
|
||||
else if(is_int(type)){
|
||||
if(expr.is_const) expr.value.big_int_val = bigint_s64((S64)expr.value.f64_val); // @todo: What to do here???
|
||||
expr.type = type;
|
||||
} else goto failure;
|
||||
} break;
|
||||
default: failure: compiler_error(node->pos, "Failed to cast from %s to %s", docname(expr.type), docname(type));;
|
||||
}
|
||||
|
||||
assert(original_type != type ? expr.type == type : 1);
|
||||
if(expr.is_const) check_value_bounds(node->pos, &expr.value);
|
||||
|
||||
node->after_type = expr.type;
|
||||
return expr;
|
||||
}
|
||||
|
||||
function Operand
|
||||
resolve_expr(Ast_Expr *ast, B32 flags){
|
||||
if(!ast && flags == AST_CAN_BE_NULL) return {};
|
||||
if(!ast && is_flag_set(flags, AST_CAN_BE_NULL)) return {};
|
||||
assert(is_flag_set(ast->flags, AST_EXPR));
|
||||
|
||||
|
||||
@@ -1063,9 +758,30 @@ resolve_expr(Ast_Expr *ast, B32 flags){
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(CALL, Call){
|
||||
unused(node);
|
||||
// return {};
|
||||
// Typespec array [32]int
|
||||
CASE(ARRAY, Array){
|
||||
// @todo: Arrays of inferred size []
|
||||
Operand type = resolve_expr(node->base, AST_CANT_BE_NULL);
|
||||
Operand expr = require_const_int(node->expr, AST_CAN_BE_NULL);
|
||||
if(type.type != type_type) compiler_error(node->pos, "Prefix array operator is only allowed on types");
|
||||
|
||||
node->type = type_array(type.type_val, node->expr ? 1 : 0, bigint_as_unsigned(&expr.big_int_val));
|
||||
return operand_type(node->type);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(INDEX, Index){
|
||||
Operand left = resolve_expr(node->expr, AST_CANT_BE_NULL);
|
||||
Operand index = resolve_expr(node->index, AST_CANT_BE_NULL);
|
||||
if(!is_int(index.type)){
|
||||
compiler_error(node->pos, "Trying to index the array with invalid type, expected [Int] got instead %s", docname(index.type));
|
||||
}
|
||||
if(!is_array(left.type) && !is_pointer(left.type)){
|
||||
compiler_error(node->pos, "Indexing variable that is not an [Array] or [Pointer], it's of type %s instead", docname(left.type));
|
||||
}
|
||||
|
||||
node->original_type = left.type;
|
||||
return operand_lvalue(left.type->arr.base);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
@@ -1073,18 +789,21 @@ resolve_expr(Ast_Expr *ast, B32 flags){
|
||||
Ast_Decl *decl = resolve_name(node->pos, node->intern_val);
|
||||
|
||||
node->resolved_decl = decl;
|
||||
if(decl->kind == AST_CONST){
|
||||
Operand result = operand(decl);
|
||||
if(decl->kind != AST_VAR){
|
||||
// @note
|
||||
// There might be some problem with types getting rewritten
|
||||
// I would like decls to be resolved to be of AST_TYPE ??
|
||||
//
|
||||
// assert(decl->value.type != type_type);
|
||||
// assert(!is_lambda(decl->value.type));
|
||||
if(decl->kind == AST_CONST){
|
||||
rewrite_into_const(node, Ast_Atom, decl->value);
|
||||
}
|
||||
result.is_const = 1;
|
||||
}
|
||||
|
||||
|
||||
return operand(decl);
|
||||
return result;
|
||||
BREAK();
|
||||
}
|
||||
|
||||
@@ -1149,6 +868,77 @@ resolve_expr(Ast_Expr *ast, B32 flags){
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(CAST, Cast){
|
||||
return resolve_cast(node);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(CALL, Call){
|
||||
Operand name = resolve_expr(node->name, AST_CANT_BE_NULL);
|
||||
if(name.type->kind != TYPE_LAMBDA)
|
||||
compiler_error(node->pos, "Calling %s which is not a [Lambda]", docname(name.type));
|
||||
|
||||
Scratch scratch;
|
||||
Array<Ast_Call_Item *> items = {scratch};
|
||||
S64 was_name_indexed = false;
|
||||
S64 default_iter = 0;
|
||||
|
||||
Ast_Decl *decl = (Ast_Decl *)name.type->ast;
|
||||
Ast_Lambda *lambda = decl->lambda;
|
||||
for(S64 i = 0; i < lambda->args.len; i++){
|
||||
Ast_Decl *lambda_arg = lambda->args[i];
|
||||
assert(lambda_arg->type);
|
||||
|
||||
Ast_Call_Item *item = 0;
|
||||
For(node->exprs){
|
||||
if(it->index) compiler_error(it->index->pos, "Function call indexing is illegal");
|
||||
|
||||
if(it->name){
|
||||
Ast_Atom *name = it->name;
|
||||
assert(name->kind == AST_IDENT);
|
||||
was_name_indexed = true;
|
||||
if(name->intern_val.str == lambda_arg->name.str)
|
||||
item = it;
|
||||
}
|
||||
else if(node->exprs.get_index(&it) == default_iter){
|
||||
default_iter++;
|
||||
item = it;
|
||||
}
|
||||
else if(node->exprs.get_index(&it) > default_iter){
|
||||
compiler_error(it->pos, "Positional argument after named argument");
|
||||
}
|
||||
|
||||
if(item) break;
|
||||
}
|
||||
|
||||
if(item){
|
||||
set_flag(item->flags, AST_ITEM_INCLUDED);
|
||||
Operand expr = resolve_expr(item->item, AST_CANT_BE_NULL);
|
||||
make_sure_value_is_compatible_with_type(node->pos, &expr, lambda_arg->type, TYPE_AND_EXPR_REQUIRED);
|
||||
items.add(item);
|
||||
}
|
||||
else{
|
||||
// default values are typechecked when they get resolved
|
||||
if(lambda_arg->expr){
|
||||
Ast_Call_Item *item_default = ast_call_item(lambda_arg->expr->pos, 0, 0, lambda_arg->expr);
|
||||
items.add(item_default);
|
||||
}
|
||||
else compiler_error(lambda_arg->pos, "Required value in lambda call was not passed");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// @note: check if all arguments are included and cleanup
|
||||
For(node->exprs){
|
||||
if(!is_flag_set(it->flags, AST_ITEM_INCLUDED))
|
||||
compiler_error(it->pos, "Invalid argument to function call");
|
||||
else unset_flag(it->flags, AST_ITEM_INCLUDED);
|
||||
}
|
||||
|
||||
return operand_rvalue(name.type);
|
||||
BREAK();
|
||||
}
|
||||
|
||||
invalid_default_case;
|
||||
}
|
||||
|
||||
@@ -1156,7 +946,7 @@ resolve_expr(Ast_Expr *ast, B32 flags){
|
||||
}
|
||||
|
||||
function void
|
||||
resolve_decl(Ast_Decl *ast){
|
||||
resolve_decl(Ast_Decl *ast, B32 flags){
|
||||
if(ast->state == DECL_RESOLVED){
|
||||
return;
|
||||
}
|
||||
@@ -1208,21 +998,32 @@ resolve_decl(Ast_Decl *ast){
|
||||
else if(is_flag_set(lambda->parent->flags, AST_FOREIGN)){
|
||||
result = operand_lambda(lambda_type);
|
||||
}
|
||||
|
||||
node->value = result.value;
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(CONST, Decl){
|
||||
resolve_const(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;
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(VAR, Decl){
|
||||
resolve_var(node);
|
||||
Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL | RESOLVE_TYPESPEC_COMPLETE);
|
||||
Operand op = resolve_expr(node->expr, AST_CAN_BE_NULL);
|
||||
assert(op.type != 0 || type != 0);
|
||||
|
||||
make_sure_value_is_compatible_with_type(node->pos, &op, type, EXPR_CAN_BE_NULL|TYPE_CAN_BE_NULL);
|
||||
node->value = op.value;
|
||||
BREAK();
|
||||
}
|
||||
|
||||
CASE(ENUM, Decl){
|
||||
node->type = type_enum(node);
|
||||
node->type = type_type;
|
||||
node->type_val = type_enum(node);
|
||||
Enter_Scope(node->scope);
|
||||
S64 value = 0;
|
||||
For(node->scope->decls){
|
||||
@@ -1246,6 +1047,7 @@ resolve_decl(Ast_Decl *ast){
|
||||
}
|
||||
ast->state = DECL_RESOLVED;
|
||||
|
||||
if(!is_flag_set(flags, IS_NOT_PACKAGE_GLOBAL))
|
||||
pctx->ordered_decls.add(ast);
|
||||
}
|
||||
|
||||
@@ -1295,7 +1097,8 @@ parse_file(Ast_File *file){
|
||||
if(!decl) break;
|
||||
|
||||
if(decl->kind == AST_STRUCT){
|
||||
decl->type = type_incomplete(decl);
|
||||
decl->type = type_type;
|
||||
decl->type_val = type_incomplete(decl);
|
||||
decl->state = DECL_RESOLVED;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ struct Operand{
|
||||
U8 is_lvalue: 1;
|
||||
};
|
||||
|
||||
enum{AST_CANT_BE_NULL = 0, AST_CAN_BE_NULL = 1};
|
||||
enum{AST_CANT_BE_NULL = 0, AST_CAN_BE_NULL = 1, IS_NOT_PACKAGE_GLOBAL=2, RESOLVE_TYPESPEC_COMPLETE = bit_flag(3)};
|
||||
function Operand resolve_expr(Ast_Expr *ast, B32 flags);
|
||||
function void resolve_decl(Ast_Decl *ast);
|
||||
function void resolve_decl(Ast_Decl *ast, B32 flags = 0);
|
||||
function Ast_Decl *resolve_name(Token *pos, Intern_String name);
|
||||
function Ast_Resolved_Type *resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null);
|
||||
#if 0
|
||||
|
||||
Reference in New Issue
Block a user