Restructure
This commit is contained in:
@@ -13,6 +13,10 @@ if_stmt :: (cond: int): type
|
|||||||
return CONSTANT
|
return CONSTANT
|
||||||
|
|
||||||
|
|
||||||
|
for_stmt :: ()
|
||||||
|
for i := 0, i + 10, i
|
||||||
|
pass
|
||||||
|
|
||||||
add_10 :: (size: int): int
|
add_10 :: (size: int): int
|
||||||
add_20 :: (new_size: int): int
|
add_20 :: (new_size: int): int
|
||||||
return 20
|
return 20
|
||||||
|
|||||||
18
main.cpp
18
main.cpp
@@ -1,11 +1,3 @@
|
|||||||
#include "base.cpp"
|
|
||||||
#include "base_unicode.cpp"
|
|
||||||
#include "new_lex.cpp"
|
|
||||||
#include "new_ast.cpp"
|
|
||||||
#include "new_parse.cpp"
|
|
||||||
#include "typechecking.cpp"
|
|
||||||
#include "ccodegen.cpp"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -41,6 +33,7 @@ For now I don't thing it should be overloadable.
|
|||||||
|
|
||||||
@todo
|
@todo
|
||||||
[ ] - For loop
|
[ ] - For loop
|
||||||
|
[ ] - More operators
|
||||||
[ ] - Init statements
|
[ ] - Init statements
|
||||||
[ ] - Fixing access to constants, in C we cant have constants inside of structs / functions so we need to rewrite the tree
|
[ ] - Fixing access to constants, in C we cant have constants inside of structs / functions so we need to rewrite the tree
|
||||||
[ ] - Default values in structs??? Should compound stmts bring values from default values?? Maybe not? Whats the alternative
|
[ ] - Default values in structs??? Should compound stmts bring values from default values?? Maybe not? Whats the alternative
|
||||||
@@ -73,7 +66,14 @@ For now I don't thing it should be overloadable.
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "base.cpp"
|
||||||
|
#include "base_unicode.cpp"
|
||||||
|
#include "new_lex.cpp"
|
||||||
|
#include "new_ast.cpp"
|
||||||
|
#include "new_parse.cpp"
|
||||||
|
#include "typecheck.h"
|
||||||
|
#include "typecheck.cpp"
|
||||||
|
#include "ccodegen.cpp"
|
||||||
int main(){
|
int main(){
|
||||||
|
|
||||||
test_os_memory();
|
test_os_memory();
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Intern_String keyword_return;
|
|||||||
Intern_String keyword_if;
|
Intern_String keyword_if;
|
||||||
Intern_String keyword_else;
|
Intern_String keyword_else;
|
||||||
Intern_String keyword_for;
|
Intern_String keyword_for;
|
||||||
|
Intern_String keyword_pass;
|
||||||
Intern_String keyword_cast;
|
Intern_String keyword_cast;
|
||||||
Intern_String keyword_enum;
|
Intern_String keyword_enum;
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ struct Parse_Ctx:Lexer{
|
|||||||
keyword_cast = intern("cast"_s);
|
keyword_cast = intern("cast"_s);
|
||||||
keyword_return = intern("return"_s);
|
keyword_return = intern("return"_s);
|
||||||
keyword_if = intern("if"_s);
|
keyword_if = intern("if"_s);
|
||||||
|
keyword_pass = intern("pass"_s);
|
||||||
keyword_else = intern("else"_s);
|
keyword_else = intern("else"_s);
|
||||||
keyword_for = intern("for"_s);
|
keyword_for = intern("for"_s);
|
||||||
keyword_enum = intern_string(&interns, "enum"_s);
|
keyword_enum = intern_string(&interns, "enum"_s);
|
||||||
@@ -98,6 +100,7 @@ enum Ast_Kind: U32{
|
|||||||
AST_IF_NODE,
|
AST_IF_NODE,
|
||||||
AST_RETURN,
|
AST_RETURN,
|
||||||
AST_BLOCK,
|
AST_BLOCK,
|
||||||
|
AST_PASS,
|
||||||
AST_LAMBDA,
|
AST_LAMBDA,
|
||||||
AST_LAMBDA_ARG,
|
AST_LAMBDA_ARG,
|
||||||
AST_ENUM,
|
AST_ENUM,
|
||||||
@@ -410,6 +413,12 @@ ast_for(Token *pos, Ast_Expr *init, Ast_Expr *cond, Ast_Expr *iter, Ast_Block *b
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Ast_Pass *
|
||||||
|
ast_pass(Token *pos){
|
||||||
|
AST_NEW(Pass, PASS, pos, AST_STMT);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
function Ast_Return *
|
function Ast_Return *
|
||||||
ast_return(Token *pos, Ast_Expr *expr){
|
ast_return(Token *pos, Ast_Expr *expr){
|
||||||
AST_NEW(Return, RETURN, pos, AST_STMT);
|
AST_NEW(Return, RETURN, pos, AST_STMT);
|
||||||
|
|||||||
@@ -207,8 +207,11 @@ parse_block(){
|
|||||||
if(token_match_keyword(keyword_return)){
|
if(token_match_keyword(keyword_return)){
|
||||||
Ast_Expr *expr = 0;
|
Ast_Expr *expr = 0;
|
||||||
if(!token_is_scope()) expr = parse_expr();
|
if(!token_is_scope()) expr = parse_expr();
|
||||||
Ast_Return *return_stmt = ast_return(token, expr);
|
stmts.add(ast_return(token, expr));
|
||||||
stmts.add(return_stmt);
|
}
|
||||||
|
|
||||||
|
else if(token_match_keyword(keyword_pass)){
|
||||||
|
stmts.add(ast_pass(token));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(token_match_keyword(keyword_for)){
|
else if(token_match_keyword(keyword_for)){
|
||||||
@@ -225,7 +228,8 @@ parse_block(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stmts.add(ast_for(token, actual_init, cond, iter, parse_block()));
|
Ast_Block *for_block = parse_block();
|
||||||
|
stmts.add(ast_for(token, actual_init, cond, iter, for_block));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(token_match_keyword(keyword_if)){
|
else if(token_match_keyword(keyword_if)){
|
||||||
|
|||||||
267
new_type.cpp
267
new_type.cpp
@@ -1,268 +1 @@
|
|||||||
enum Ast_Resolved_Type_Kind{
|
|
||||||
TYPE_NONE,
|
|
||||||
TYPE_NULL,
|
|
||||||
TYPE_COMPLETING,
|
|
||||||
TYPE_INCOMPLETE,
|
|
||||||
TYPE_INT,
|
|
||||||
TYPE_BOOL,
|
|
||||||
TYPE_UNSIGNED,
|
|
||||||
TYPE_STRING,
|
|
||||||
TYPE_VOID,
|
|
||||||
TYPE_POINTER,
|
|
||||||
TYPE_ARRAY,
|
|
||||||
TYPE_LAMBDA,
|
|
||||||
TYPE_STRUCT,
|
|
||||||
TYPE_UNION,
|
|
||||||
TYPE_ENUM,
|
|
||||||
TYPE_TYPE,
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *type_names[] = {
|
|
||||||
"[Invalid Ast_Resolved_Type]",
|
|
||||||
"[Null]",
|
|
||||||
"[Completing]",
|
|
||||||
"[Incomplete]",
|
|
||||||
"[Int]",
|
|
||||||
"[Bool]",
|
|
||||||
"[Unsigned]",
|
|
||||||
"[String]",
|
|
||||||
"[Void]",
|
|
||||||
"[Pointer]",
|
|
||||||
"[Array]",
|
|
||||||
"[Lambda]",
|
|
||||||
"[Struct]",
|
|
||||||
"[Union]",
|
|
||||||
"[Enum]",
|
|
||||||
"[Type]",
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Ast_Resolved_Member{
|
|
||||||
Ast_Resolved_Type *type;
|
|
||||||
Intern_String name;
|
|
||||||
U64 offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Ast_Resolved_Type{
|
|
||||||
Ast_Resolved_Type_Kind kind;
|
|
||||||
SizeU size;
|
|
||||||
SizeU align;
|
|
||||||
|
|
||||||
Ast *ast;
|
|
||||||
union{
|
|
||||||
Ast_Resolved_Type *base;
|
|
||||||
struct{
|
|
||||||
Ast_Resolved_Type *base;
|
|
||||||
SizeU size;
|
|
||||||
}arr;
|
|
||||||
struct{
|
|
||||||
Array<Ast_Resolved_Member> members;
|
|
||||||
}agg;
|
|
||||||
struct{
|
|
||||||
Ast_Resolved_Type *ret;
|
|
||||||
Array<Ast_Resolved_Type *> args;
|
|
||||||
}func;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const SizeU pointer_size = sizeof(SizeU);
|
|
||||||
const SizeU pointer_align = __alignof(SizeU);
|
|
||||||
|
|
||||||
global Ast_Resolved_Type type__null = {TYPE_NULL};
|
|
||||||
global Ast_Resolved_Type type__void = {TYPE_VOID};
|
|
||||||
global Ast_Resolved_Type type__int = {TYPE_INT, sizeof(int), __alignof(int)};
|
|
||||||
global Ast_Resolved_Type type__unsigned = {TYPE_INT, sizeof(unsigned), __alignof(unsigned)};
|
|
||||||
global Ast_Resolved_Type type__string = {TYPE_STRING, sizeof(String), __alignof(String)};
|
|
||||||
global Ast_Resolved_Type type__bool = {TYPE_BOOL, sizeof(bool), __alignof(bool)};
|
|
||||||
global Ast_Resolved_Type type__type = {TYPE_TYPE};
|
|
||||||
|
|
||||||
global Ast_Resolved_Type *type_type = &type__type;
|
|
||||||
global Ast_Resolved_Type *type_void = &type__void;
|
|
||||||
global Ast_Resolved_Type *type_int = &type__int;
|
|
||||||
global Ast_Resolved_Type *type_unsigned = &type__unsigned;
|
|
||||||
global Ast_Resolved_Type *type_string = &type__string;
|
|
||||||
global Ast_Resolved_Type *type_bool = &type__bool;
|
|
||||||
global Ast_Resolved_Type *type_null = &type__null;
|
|
||||||
|
|
||||||
force_inline B32 is_string(Ast_Resolved_Type *type){return type->kind == TYPE_STRING;}
|
|
||||||
force_inline B32 is_int(Ast_Resolved_Type *type){return type->kind == TYPE_INT;}
|
|
||||||
force_inline B32 is_struct(Ast_Resolved_Type *type){return type->kind == TYPE_STRUCT;}
|
|
||||||
force_inline B32 is_array(Ast_Resolved_Type *type){return type->kind == TYPE_ARRAY;}
|
|
||||||
force_inline B32 is_enum(Ast_Resolved_Type *type){return type->kind == TYPE_ENUM;}
|
|
||||||
force_inline B32 is_pointer(Ast_Resolved_Type *type){return type->kind == TYPE_POINTER;}
|
|
||||||
|
|
||||||
function Ast_Resolved_Type *
|
|
||||||
type_new(Allocator *allocator, Ast_Resolved_Type_Kind kind, SizeU size, SizeU align){
|
|
||||||
Ast_Resolved_Type *result = exp_alloc_type(allocator, Ast_Resolved_Type, AF_ZeroMemory);
|
|
||||||
result->kind = kind;
|
|
||||||
result->size = size;
|
|
||||||
result->align = align;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Ast_Resolved_Type *
|
|
||||||
type_copy(Allocator *a, Ast_Resolved_Type *type){
|
|
||||||
Ast_Resolved_Type *result = exp_alloc_type(a, Ast_Resolved_Type);
|
|
||||||
memory_copy(result, type, sizeof(Ast_Resolved_Type));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Ast_Resolved_Type *
|
|
||||||
type_pointer(Ast_Resolved_Type *base){
|
|
||||||
Ast_Resolved_Type *result = (Ast_Resolved_Type *)map_get(&pctx->type_map, (void *)base);
|
|
||||||
if(!result){
|
|
||||||
result = type_new(pctx->perm, TYPE_POINTER, pointer_size, pointer_align);
|
|
||||||
result->base = base;
|
|
||||||
map_insert(&pctx->type_map, base, result);
|
|
||||||
}
|
|
||||||
assert(result->kind == TYPE_POINTER);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Ast_Resolved_Type *
|
|
||||||
type_array(Ast_Resolved_Type *base, SizeU size){
|
|
||||||
U64 hash = hash_mix(hash_ptr(base), hash_u64(size));
|
|
||||||
Ast_Resolved_Type *result = (Ast_Resolved_Type *)map_get(&pctx->type_map, hash);
|
|
||||||
if(result){
|
|
||||||
assert(result->kind == TYPE_ARRAY);
|
|
||||||
assert(result->arr.size == size);
|
|
||||||
assert(result->arr.base == base);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = type_new(pctx->perm, TYPE_ARRAY, pointer_size, pointer_align);
|
|
||||||
result->arr.base = base;
|
|
||||||
result->arr.size = size;
|
|
||||||
map_insert(&pctx->type_map, hash, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Ast_Resolved_Type *
|
|
||||||
type_lambda(Ast *ast, Ast_Resolved_Type *ret, Array<Ast_Resolved_Type *> args){
|
|
||||||
U64 hash = hash_ptr(ret);
|
|
||||||
For(args) hash = hash_mix(hash, hash_ptr(it));
|
|
||||||
Ast_Resolved_Type *result = (Ast_Resolved_Type *)map_get(&pctx->type_map, hash);
|
|
||||||
|
|
||||||
if(result){
|
|
||||||
assert(result->kind == TYPE_LAMBDA);
|
|
||||||
assert(result->func.ret == ret);
|
|
||||||
assert(result->func.args.len == args.len);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = type_new(pctx->perm, TYPE_LAMBDA, pointer_size, pointer_align);
|
|
||||||
result->ast = ast;
|
|
||||||
result->func.ret = ret;
|
|
||||||
result->func.args = args.tight_copy(pctx->perm);
|
|
||||||
map_insert(&pctx->type_map, hash, result);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Ast_Resolved_Type *
|
|
||||||
type_enum(Ast_Enum *ast){
|
|
||||||
Ast_Resolved_Type *type = resolve_typespec(ast->typespec, AST_CAN_BE_NULL);
|
|
||||||
if(!type) {
|
|
||||||
type = type_int;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ast_Resolved_Type *result = type_new(pctx->perm, TYPE_ENUM, type->size, type->align);
|
|
||||||
result->base = type;
|
|
||||||
result->ast = ast;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Ast_Resolved_Type *
|
|
||||||
type_incomplete(Ast *ast){
|
|
||||||
Ast_Resolved_Type *result = type_new(pctx->perm, TYPE_INCOMPLETE, 0, 0);
|
|
||||||
result->ast = ast;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function void
|
|
||||||
type_struct_complete(Ast_Resolved_Type *type, Ast_Struct *node){
|
|
||||||
// @todo: compute size, alignement, offset !!!
|
|
||||||
// @note: resolve all the struct members first
|
|
||||||
type->kind = TYPE_COMPLETING;
|
|
||||||
Scratch scratch;
|
|
||||||
Array<Ast_Resolved_Member> members = {scratch};
|
|
||||||
For(node->members){
|
|
||||||
Operand op = resolve_binding(it);
|
|
||||||
Intern_String name = ast_get_name(it);
|
|
||||||
sym_new_resolved(SYM_VAR, name, op.type, {}, it);
|
|
||||||
members.add({op.type, name});
|
|
||||||
}
|
|
||||||
type->agg.members = members.tight_copy(pctx->perm);
|
|
||||||
type->kind = TYPE_STRUCT;
|
|
||||||
|
|
||||||
// @note: resolve constant members after the struct got resolved
|
|
||||||
// this way we avoid a problem where we start resolving the function
|
|
||||||
// and this function has parameter of type parent struct
|
|
||||||
// which is being resolved right now, cyclic dependency happens.
|
|
||||||
// constants arent required to make struct work
|
|
||||||
For(node->const_members){
|
|
||||||
Operand op = resolve_binding(it);
|
|
||||||
Intern_String name = ast_get_name(it);
|
|
||||||
sym_new_resolved(SYM_CONST, name, op.type, op.value, it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Ast_Resolved_Type *
|
|
||||||
type_struct(Ast_Struct *agg){
|
|
||||||
Ast_Resolved_Type *result = type_new(pctx->perm, TYPE_STRUCT, 0, 0);
|
|
||||||
result->ast = agg;
|
|
||||||
type_struct_complete(result, agg);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function void
|
|
||||||
type_complete(Ast_Resolved_Type *type){
|
|
||||||
if(type->kind == TYPE_COMPLETING){
|
|
||||||
parsing_error(type->ast->pos, "Cyclic type dependency");
|
|
||||||
}
|
|
||||||
else if(type->kind != TYPE_INCOMPLETE){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ast_Struct *node = (Ast_Struct *)type->ast;
|
|
||||||
type_struct_complete(type, node);
|
|
||||||
pctx->resolving_package->ordered.add((Ast_Named *)node->parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
function void
|
|
||||||
test_types(){
|
|
||||||
Scratch scratch;
|
|
||||||
Parse_Ctx ctx = {};
|
|
||||||
ctx.init(scratch, scratch);
|
|
||||||
pctx = &ctx;
|
|
||||||
|
|
||||||
Ast_Resolved_Type *array_type1 = type_array(type_int, 32);
|
|
||||||
Ast_Resolved_Type *array_type2 = type_array(type_int, 32);
|
|
||||||
Ast_Resolved_Type *array_type3 = type_array(type_int, 48);
|
|
||||||
assert(array_type1 == array_type2);
|
|
||||||
assert(array_type2 != array_type3);
|
|
||||||
Ast_Resolved_Type *pointer_type1 = type_pointer(type_int);
|
|
||||||
Ast_Resolved_Type *pointer_type2 = type_pointer(type_int);
|
|
||||||
assert(pointer_type2 == pointer_type1);
|
|
||||||
Ast_Resolved_Type *pointer_type3 = type_pointer(pointer_type1);
|
|
||||||
Ast_Resolved_Type *pointer_type4 = type_pointer(pointer_type2);
|
|
||||||
assert(pointer_type3 != pointer_type1);
|
|
||||||
assert(pointer_type3 == pointer_type4);
|
|
||||||
|
|
||||||
Array<Ast_Resolved_Type*> types = {scratch};
|
|
||||||
types.add(type_array(type_int, 32));
|
|
||||||
Ast_Resolved_Type *func_type1 = type_lambda(0, types[0], types);
|
|
||||||
Ast_Resolved_Type *func_type2 = type_lambda(0, types[0], types);
|
|
||||||
assert(func_type1 == func_type2);
|
|
||||||
|
|
||||||
Array<Ast_Resolved_Type*> types2 = {scratch};
|
|
||||||
{
|
|
||||||
types2.add(type_array(type_int, 32));
|
|
||||||
types2.add(type_int);
|
|
||||||
}
|
|
||||||
types.add(type_int);
|
|
||||||
Ast_Resolved_Type *func_type3 = type_lambda(0, types[0], types);
|
|
||||||
Ast_Resolved_Type *func_type4 = type_lambda(0, types[0], types2);
|
|
||||||
assert(func_type1 != func_type3);
|
|
||||||
assert(func_type3 == func_type4);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,187 +1,6 @@
|
|||||||
#define CASE(kind,type) case AST_##kind: { Ast_##type *node = (Ast_##type *)ast;
|
#define CASE(kind,type) case AST_##kind: { Ast_##type *node = (Ast_##type *)ast;
|
||||||
#define BREAK() } break
|
#define BREAK() } break
|
||||||
|
|
||||||
enum Sym_Kind{
|
|
||||||
SYM_NONE,
|
|
||||||
SYM_CONST,
|
|
||||||
SYM_VAR,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Sym_State{
|
|
||||||
SYM_NOT_RESOLVED,
|
|
||||||
SYM_RESOLVING,
|
|
||||||
SYM_RESOLVED,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define VALUE_FIELDS \
|
|
||||||
S64 int_val; \
|
|
||||||
Intern_String intern_val; \
|
|
||||||
Ast_Resolved_Type *type_val;
|
|
||||||
#define INLINE_VALUE_FIELDS union{Value value; union{VALUE_FIELDS};}
|
|
||||||
|
|
||||||
union Value{VALUE_FIELDS};
|
|
||||||
|
|
||||||
struct Sym{
|
|
||||||
Intern_String name;
|
|
||||||
Sym_Kind kind;
|
|
||||||
Sym_State state;
|
|
||||||
Ast *ast;
|
|
||||||
|
|
||||||
Ast_Resolved_Type *type;
|
|
||||||
INLINE_VALUE_FIELDS;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Operand{
|
|
||||||
Ast_Resolved_Type *type;
|
|
||||||
bool is_const;
|
|
||||||
INLINE_VALUE_FIELDS;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Typecheck_Ctx{ // @todo
|
|
||||||
Ast_Resolved_Type *required_type;
|
|
||||||
Sym *const_sym;
|
|
||||||
B32 expr_can_be_null;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum{AST_CANT_BE_NULL = 0, AST_CAN_BE_NULL = 1};
|
|
||||||
function Ast_Resolved_Type *resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null = AST_CANT_BE_NULL);
|
|
||||||
function Sym *resolve_name(Token *pos, Intern_String name);
|
|
||||||
function Operand resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *compound_required_type = 0, Sym *const_sym = 0);
|
|
||||||
function Operand resolve_binding(Ast *ast, Sym *sym = 0);
|
|
||||||
global Ast_Named empty_decl = {};
|
|
||||||
|
|
||||||
function void
|
|
||||||
sym_insert(Sym *sym){
|
|
||||||
U64 hash = hash_string(sym->name.s);
|
|
||||||
Sym *is_sym = (Sym *)map_get(&pctx->syms, hash);
|
|
||||||
if(is_sym){
|
|
||||||
parsing_error(sym->ast->pos, "Symbol with name: [%s] defined multiple times", sym->name.s.str);
|
|
||||||
}
|
|
||||||
if(pctx->scope > 0){
|
|
||||||
pctx->local_syms.add(sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
map_insert(&pctx->syms, hash, sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Sym *
|
|
||||||
sym_get(Intern_String name){
|
|
||||||
Sym *result = (Sym *)map_get(&pctx->syms, hash_string(name.s));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function S64
|
|
||||||
scope_open(){
|
|
||||||
S64 local_sym_count = pctx->local_syms.len;
|
|
||||||
pctx->scope++;
|
|
||||||
return local_sym_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
function void
|
|
||||||
scope_close(S64 local_sym_count){
|
|
||||||
pctx->scope--;
|
|
||||||
assert(pctx->scope >= 0);
|
|
||||||
for(S64 i = local_sym_count; i < pctx->local_syms.len; i++){
|
|
||||||
Sym *it = pctx->local_syms.data[i];
|
|
||||||
void *removed = map_remove(&pctx->syms, hash_string(it->name.s));
|
|
||||||
assert(removed);
|
|
||||||
}
|
|
||||||
pctx->local_syms.len = local_sym_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
function void
|
|
||||||
sym_associate(Ast *ast, Sym *sym){
|
|
||||||
assert(ast);
|
|
||||||
assert(sym);
|
|
||||||
map_insert(&pctx->resolved, ast, sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Sym *
|
|
||||||
sym_new(Sym_Kind kind, Intern_String name, Ast *ast, B32 associate = true){
|
|
||||||
Sym *result = exp_alloc_type(pctx->perm, Sym, AF_ZeroMemory);
|
|
||||||
result->name = name;
|
|
||||||
result->kind = kind;
|
|
||||||
result->ast = ast;
|
|
||||||
if(associate) sym_associate(ast, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Sym *
|
|
||||||
sym_new_resolved(Sym_Kind kind, Intern_String name, Ast_Resolved_Type *type, Value value, Ast *ast, B32 associate = true){
|
|
||||||
Sym *result = sym_new(kind, name, ast, associate);
|
|
||||||
result->type = type;
|
|
||||||
result->state = SYM_RESOLVED;
|
|
||||||
result->value = value;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Sym *
|
|
||||||
resolved_get(Ast *ast){
|
|
||||||
Sym *result = (Sym *)map_get(&pctx->resolved, ast);
|
|
||||||
assert(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#include "new_type.cpp"
|
|
||||||
|
|
||||||
function Ast_Resolved_Type *
|
|
||||||
resolved_type_get(Ast_Expr *ast){
|
|
||||||
Sym *result = resolved_get(ast);
|
|
||||||
assert(result->type == type_type);
|
|
||||||
assert(result->type);
|
|
||||||
return result->type_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Sym *
|
|
||||||
sym_type(Ast *ast, Ast_Resolved_Type *type, Intern_String name = {}, B32 associate = true){
|
|
||||||
Value value; value.type_val = type;
|
|
||||||
Sym *result = sym_new_resolved(SYM_CONST, name, type_type, value, ast, associate);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Sym *
|
|
||||||
sym_insert(Sym_Kind kind, Intern_String name, Ast_Resolved_Type *type, Value value, Ast *ast){
|
|
||||||
Sym *sym = sym_new_resolved(kind, name, type, value, ast);
|
|
||||||
sym_insert(sym);
|
|
||||||
return sym;
|
|
||||||
}
|
|
||||||
|
|
||||||
function void
|
|
||||||
sym_insert_builtin_type(String name, Ast_Resolved_Type *type){
|
|
||||||
Intern_String string = intern_string(&pctx->interns, name);
|
|
||||||
Sym *sym = sym_type(&empty_decl, type, string, false);
|
|
||||||
sym_insert(sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
function void
|
|
||||||
sym_insert_builtins(){
|
|
||||||
sym_insert_builtin_type("void"_s, type_void);
|
|
||||||
sym_insert_builtin_type("bool"_s, type_bool);
|
|
||||||
sym_insert_builtin_type("int"_s, type_int);
|
|
||||||
sym_insert_builtin_type("String"_s, type_string);
|
|
||||||
|
|
||||||
{
|
|
||||||
Intern_String string = intern_string(&pctx->interns, "true"_s);
|
|
||||||
Value val; val.int_val = 1;
|
|
||||||
Sym *sym = sym_new_resolved(SYM_CONST, string, type_bool, val, &empty_decl, false);
|
|
||||||
sym_insert(sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Intern_String string = intern_string(&pctx->interns, "false"_s);
|
|
||||||
Value val; val.int_val = 0;
|
|
||||||
Sym *sym = sym_new_resolved(SYM_CONST, string, type_bool, val, &empty_decl, false);
|
|
||||||
sym_insert(sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Intern_String string = intern_string(&pctx->interns, "null"_s);
|
|
||||||
Value val; val.int_val = 0;
|
|
||||||
Sym *sym = sym_new_resolved(SYM_CONST, string, type_null, val, &empty_decl, false);
|
|
||||||
sym_insert(sym);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Ast_Resolved_Type *
|
function Ast_Resolved_Type *
|
||||||
resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null){
|
resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null){
|
||||||
if(ast_can_be_null && ast == 0) return 0;
|
if(ast_can_be_null && ast == 0) return 0;
|
||||||
@@ -236,9 +55,8 @@ resolve_stmt(Ast *ast, Ast_Resolved_Type *ret){
|
|||||||
|
|
||||||
CASE(BINARY, Binary){
|
CASE(BINARY, Binary){
|
||||||
switch(node->op){
|
switch(node->op){
|
||||||
case TK_Comma:{
|
case TK_Colon:{
|
||||||
Operand left = resolve_expr(node->left); // needs to be lvalue
|
// Operand left = resolve_expr(node->left); // needs to be lvalue
|
||||||
unused(left);
|
|
||||||
Operand right = resolve_expr(node->right);
|
Operand right = resolve_expr(node->right);
|
||||||
assert(node->left->kind == AST_IDENT);
|
assert(node->left->kind == AST_IDENT);
|
||||||
Ast_Atom *atom = (Ast_Atom *)node->left; // @todo use left operand
|
Ast_Atom *atom = (Ast_Atom *)node->left; // @todo use left operand
|
||||||
@@ -265,22 +83,6 @@ resolve_stmt(Ast *ast, Ast_Resolved_Type *ret){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Operand
|
|
||||||
operand(Sym *sym){
|
|
||||||
Operand result = {};
|
|
||||||
result.type = sym->type;
|
|
||||||
result.is_const = sym->kind == SYM_CONST ? true : false;
|
|
||||||
result.value = sym->value;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Operand
|
|
||||||
operand_type(Ast_Resolved_Type *type){
|
|
||||||
Operand result = {type_type, true};
|
|
||||||
result.type_val = type;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Operand
|
function Operand
|
||||||
require_const_int(Ast_Expr *expr, B32 ast_can_be_null){
|
require_const_int(Ast_Expr *expr, B32 ast_can_be_null){
|
||||||
Operand op = resolve_expr(expr);
|
Operand op = resolve_expr(expr);
|
||||||
@@ -839,3 +641,40 @@ parse_file(){
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
test_types(){
|
||||||
|
Scratch scratch;
|
||||||
|
Parse_Ctx ctx = {};
|
||||||
|
ctx.init(scratch, scratch);
|
||||||
|
pctx = &ctx;
|
||||||
|
|
||||||
|
Ast_Resolved_Type *array_type1 = type_array(type_int, 32);
|
||||||
|
Ast_Resolved_Type *array_type2 = type_array(type_int, 32);
|
||||||
|
Ast_Resolved_Type *array_type3 = type_array(type_int, 48);
|
||||||
|
assert(array_type1 == array_type2);
|
||||||
|
assert(array_type2 != array_type3);
|
||||||
|
Ast_Resolved_Type *pointer_type1 = type_pointer(type_int);
|
||||||
|
Ast_Resolved_Type *pointer_type2 = type_pointer(type_int);
|
||||||
|
assert(pointer_type2 == pointer_type1);
|
||||||
|
Ast_Resolved_Type *pointer_type3 = type_pointer(pointer_type1);
|
||||||
|
Ast_Resolved_Type *pointer_type4 = type_pointer(pointer_type2);
|
||||||
|
assert(pointer_type3 != pointer_type1);
|
||||||
|
assert(pointer_type3 == pointer_type4);
|
||||||
|
|
||||||
|
Array<Ast_Resolved_Type*> types = {scratch};
|
||||||
|
types.add(type_array(type_int, 32));
|
||||||
|
Ast_Resolved_Type *func_type1 = type_lambda(0, types[0], types);
|
||||||
|
Ast_Resolved_Type *func_type2 = type_lambda(0, types[0], types);
|
||||||
|
assert(func_type1 == func_type2);
|
||||||
|
|
||||||
|
Array<Ast_Resolved_Type*> types2 = {scratch};
|
||||||
|
{
|
||||||
|
types2.add(type_array(type_int, 32));
|
||||||
|
types2.add(type_int);
|
||||||
|
}
|
||||||
|
types.add(type_int);
|
||||||
|
Ast_Resolved_Type *func_type3 = type_lambda(0, types[0], types);
|
||||||
|
Ast_Resolved_Type *func_type4 = type_lambda(0, types[0], types2);
|
||||||
|
assert(func_type1 != func_type3);
|
||||||
|
assert(func_type3 == func_type4);
|
||||||
|
}
|
||||||
448
typecheck.h
Normal file
448
typecheck.h
Normal file
@@ -0,0 +1,448 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Resolved Types
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
enum Ast_Resolved_Type_Kind{
|
||||||
|
TYPE_NONE,
|
||||||
|
TYPE_NULL,
|
||||||
|
TYPE_COMPLETING,
|
||||||
|
TYPE_INCOMPLETE,
|
||||||
|
TYPE_INT,
|
||||||
|
TYPE_BOOL,
|
||||||
|
TYPE_UNSIGNED,
|
||||||
|
TYPE_STRING,
|
||||||
|
TYPE_VOID,
|
||||||
|
TYPE_POINTER,
|
||||||
|
TYPE_ARRAY,
|
||||||
|
TYPE_LAMBDA,
|
||||||
|
TYPE_STRUCT,
|
||||||
|
TYPE_UNION,
|
||||||
|
TYPE_ENUM,
|
||||||
|
TYPE_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *type_names[] = {
|
||||||
|
"[Invalid Ast_Resolved_Type]",
|
||||||
|
"[Null]",
|
||||||
|
"[Completing]",
|
||||||
|
"[Incomplete]",
|
||||||
|
"[Int]",
|
||||||
|
"[Bool]",
|
||||||
|
"[Unsigned]",
|
||||||
|
"[String]",
|
||||||
|
"[Void]",
|
||||||
|
"[Pointer]",
|
||||||
|
"[Array]",
|
||||||
|
"[Lambda]",
|
||||||
|
"[Struct]",
|
||||||
|
"[Union]",
|
||||||
|
"[Enum]",
|
||||||
|
"[Type]",
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Ast_Resolved_Member{
|
||||||
|
Ast_Resolved_Type *type;
|
||||||
|
Intern_String name;
|
||||||
|
U64 offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Ast_Resolved_Type{
|
||||||
|
Ast_Resolved_Type_Kind kind;
|
||||||
|
SizeU size;
|
||||||
|
SizeU align;
|
||||||
|
|
||||||
|
Ast *ast;
|
||||||
|
union{
|
||||||
|
Ast_Resolved_Type *base;
|
||||||
|
struct{
|
||||||
|
Ast_Resolved_Type *base;
|
||||||
|
SizeU size;
|
||||||
|
}arr;
|
||||||
|
struct{
|
||||||
|
Array<Ast_Resolved_Member> members;
|
||||||
|
}agg;
|
||||||
|
struct{
|
||||||
|
Ast_Resolved_Type *ret;
|
||||||
|
Array<Ast_Resolved_Type *> args;
|
||||||
|
}func;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Type globals
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
const SizeU pointer_size = sizeof(SizeU);
|
||||||
|
const SizeU pointer_align = __alignof(SizeU);
|
||||||
|
global Ast_Resolved_Type type__null = {TYPE_NULL};
|
||||||
|
global Ast_Resolved_Type type__void = {TYPE_VOID};
|
||||||
|
global Ast_Resolved_Type type__int = {TYPE_INT, sizeof(int), __alignof(int)};
|
||||||
|
global Ast_Resolved_Type type__unsigned = {TYPE_INT, sizeof(unsigned), __alignof(unsigned)};
|
||||||
|
global Ast_Resolved_Type type__string = {TYPE_STRING, sizeof(String), __alignof(String)};
|
||||||
|
global Ast_Resolved_Type type__bool = {TYPE_BOOL, sizeof(bool), __alignof(bool)};
|
||||||
|
global Ast_Resolved_Type type__type = {TYPE_TYPE};
|
||||||
|
|
||||||
|
global Ast_Resolved_Type *type_type = &type__type;
|
||||||
|
global Ast_Resolved_Type *type_void = &type__void;
|
||||||
|
global Ast_Resolved_Type *type_int = &type__int;
|
||||||
|
global Ast_Resolved_Type *type_unsigned = &type__unsigned;
|
||||||
|
global Ast_Resolved_Type *type_string = &type__string;
|
||||||
|
global Ast_Resolved_Type *type_bool = &type__bool;
|
||||||
|
global Ast_Resolved_Type *type_null = &type__null;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Symbols
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
enum Sym_Kind{
|
||||||
|
SYM_NONE,
|
||||||
|
SYM_CONST,
|
||||||
|
SYM_VAR,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Sym_State{
|
||||||
|
SYM_NOT_RESOLVED,
|
||||||
|
SYM_RESOLVING,
|
||||||
|
SYM_RESOLVED,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VALUE_FIELDS \
|
||||||
|
S64 int_val; \
|
||||||
|
Intern_String intern_val; \
|
||||||
|
Ast_Resolved_Type *type_val;
|
||||||
|
#define INLINE_VALUE_FIELDS union{Value value; union{VALUE_FIELDS};}
|
||||||
|
union Value{VALUE_FIELDS};
|
||||||
|
|
||||||
|
struct Sym{
|
||||||
|
Intern_String name;
|
||||||
|
Sym_Kind kind;
|
||||||
|
Sym_State state;
|
||||||
|
Ast *ast;
|
||||||
|
|
||||||
|
Ast_Resolved_Type *type;
|
||||||
|
INLINE_VALUE_FIELDS;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Operand{
|
||||||
|
Ast_Resolved_Type *type;
|
||||||
|
bool is_const;
|
||||||
|
INLINE_VALUE_FIELDS;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Typecheck_Ctx{ // @todo
|
||||||
|
Ast_Resolved_Type *required_type;
|
||||||
|
Sym *const_sym;
|
||||||
|
B32 expr_can_be_null;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum{AST_CANT_BE_NULL = 0, AST_CAN_BE_NULL = 1};
|
||||||
|
function Ast_Resolved_Type *resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null = AST_CANT_BE_NULL);
|
||||||
|
function Sym *resolve_name(Token *pos, Intern_String name);
|
||||||
|
function Operand resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *compound_required_type = 0, Sym *const_sym = 0);
|
||||||
|
function Operand resolve_binding(Ast *ast, Sym *sym = 0);
|
||||||
|
global Ast_Named empty_decl = {};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Symbol constructors and utils
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
function void
|
||||||
|
sym_insert(Sym *sym){
|
||||||
|
U64 hash = hash_string(sym->name.s);
|
||||||
|
Sym *is_sym = (Sym *)map_get(&pctx->syms, hash);
|
||||||
|
if(is_sym) parsing_error(sym->ast->pos, "Symbol with name: [%s] defined multiple times", sym->name.s.str);
|
||||||
|
if(pctx->scope > 0) pctx->local_syms.add(sym);
|
||||||
|
map_insert(&pctx->syms, hash, sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Sym *
|
||||||
|
sym_get(Intern_String name){
|
||||||
|
Sym *result = (Sym *)map_get(&pctx->syms, hash_string(name.s));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function S64
|
||||||
|
scope_open(){
|
||||||
|
S64 local_sym_count = pctx->local_syms.len;
|
||||||
|
pctx->scope++;
|
||||||
|
return local_sym_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
scope_close(S64 local_sym_count){
|
||||||
|
pctx->scope--;
|
||||||
|
assert(pctx->scope >= 0);
|
||||||
|
for(S64 i = local_sym_count; i < pctx->local_syms.len; i++){
|
||||||
|
Sym *it = pctx->local_syms.data[i];
|
||||||
|
void *removed = map_remove(&pctx->syms, hash_string(it->name.s));
|
||||||
|
assert(removed);
|
||||||
|
}
|
||||||
|
pctx->local_syms.len = local_sym_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
sym_associate(Ast *ast, Sym *sym){
|
||||||
|
assert(ast);
|
||||||
|
assert(sym);
|
||||||
|
map_insert(&pctx->resolved, ast, sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Sym *
|
||||||
|
sym_new(Sym_Kind kind, Intern_String name, Ast *ast, B32 associate = true){
|
||||||
|
Sym *result = exp_alloc_type(pctx->perm, Sym, AF_ZeroMemory);
|
||||||
|
result->name = name;
|
||||||
|
result->kind = kind;
|
||||||
|
result->ast = ast;
|
||||||
|
if(associate) sym_associate(ast, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Sym *
|
||||||
|
sym_new_resolved(Sym_Kind kind, Intern_String name, Ast_Resolved_Type *type, Value value, Ast *ast, B32 associate = true){
|
||||||
|
Sym *result = sym_new(kind, name, ast, associate);
|
||||||
|
result->type = type;
|
||||||
|
result->state = SYM_RESOLVED;
|
||||||
|
result->value = value;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Sym *
|
||||||
|
resolved_get(Ast *ast){
|
||||||
|
Sym *result = (Sym *)map_get(&pctx->resolved, ast);
|
||||||
|
assert(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ast_Resolved_Type *
|
||||||
|
resolved_type_get(Ast_Expr *ast){
|
||||||
|
Sym *result = resolved_get(ast);
|
||||||
|
assert(result->type == type_type);
|
||||||
|
assert(result->type);
|
||||||
|
return result->type_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Sym *
|
||||||
|
sym_type(Ast *ast, Ast_Resolved_Type *type, Intern_String name = {}, B32 associate = true){
|
||||||
|
Value value; value.type_val = type;
|
||||||
|
Sym *result = sym_new_resolved(SYM_CONST, name, type_type, value, ast, associate);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Sym *
|
||||||
|
sym_insert(Sym_Kind kind, Intern_String name, Ast_Resolved_Type *type, Value value, Ast *ast){
|
||||||
|
Sym *sym = sym_new_resolved(kind, name, type, value, ast);
|
||||||
|
sym_insert(sym);
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
sym_insert_builtin_type(String name, Ast_Resolved_Type *type){
|
||||||
|
Intern_String string = intern_string(&pctx->interns, name);
|
||||||
|
Sym *sym = sym_type(&empty_decl, type, string, false);
|
||||||
|
sym_insert(sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
sym_insert_builtins(){
|
||||||
|
sym_insert_builtin_type("void"_s, type_void);
|
||||||
|
sym_insert_builtin_type("bool"_s, type_bool);
|
||||||
|
sym_insert_builtin_type("int"_s, type_int);
|
||||||
|
sym_insert_builtin_type("String"_s, type_string);
|
||||||
|
|
||||||
|
{
|
||||||
|
Intern_String string = intern_string(&pctx->interns, "true"_s);
|
||||||
|
Value val; val.int_val = 1;
|
||||||
|
Sym *sym = sym_new_resolved(SYM_CONST, string, type_bool, val, &empty_decl, false);
|
||||||
|
sym_insert(sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Intern_String string = intern_string(&pctx->interns, "false"_s);
|
||||||
|
Value val; val.int_val = 0;
|
||||||
|
Sym *sym = sym_new_resolved(SYM_CONST, string, type_bool, val, &empty_decl, false);
|
||||||
|
sym_insert(sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Intern_String string = intern_string(&pctx->interns, "null"_s);
|
||||||
|
Value val; val.int_val = 0;
|
||||||
|
Sym *sym = sym_new_resolved(SYM_CONST, string, type_null, val, &empty_decl, false);
|
||||||
|
sym_insert(sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Operands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
function Operand
|
||||||
|
operand(Sym *sym){
|
||||||
|
Operand result = {};
|
||||||
|
result.type = sym->type;
|
||||||
|
result.is_const = sym->kind == SYM_CONST ? true : false;
|
||||||
|
result.value = sym->value;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Operand
|
||||||
|
operand_type(Ast_Resolved_Type *type){
|
||||||
|
Operand result = {type_type, true};
|
||||||
|
result.type_val = type;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Type constructors and utillities
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
force_inline B32 is_string(Ast_Resolved_Type *type){return type->kind == TYPE_STRING;}
|
||||||
|
force_inline B32 is_int(Ast_Resolved_Type *type){return type->kind == TYPE_INT;}
|
||||||
|
force_inline B32 is_struct(Ast_Resolved_Type *type){return type->kind == TYPE_STRUCT;}
|
||||||
|
force_inline B32 is_array(Ast_Resolved_Type *type){return type->kind == TYPE_ARRAY;}
|
||||||
|
force_inline B32 is_enum(Ast_Resolved_Type *type){return type->kind == TYPE_ENUM;}
|
||||||
|
force_inline B32 is_pointer(Ast_Resolved_Type *type){return type->kind == TYPE_POINTER;}
|
||||||
|
|
||||||
|
function Ast_Resolved_Type *
|
||||||
|
type_new(Allocator *allocator, Ast_Resolved_Type_Kind kind, SizeU size, SizeU align){
|
||||||
|
Ast_Resolved_Type *result = exp_alloc_type(allocator, Ast_Resolved_Type, AF_ZeroMemory);
|
||||||
|
result->kind = kind;
|
||||||
|
result->size = size;
|
||||||
|
result->align = align;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ast_Resolved_Type *
|
||||||
|
type_copy(Allocator *a, Ast_Resolved_Type *type){
|
||||||
|
Ast_Resolved_Type *result = exp_alloc_type(a, Ast_Resolved_Type);
|
||||||
|
memory_copy(result, type, sizeof(Ast_Resolved_Type));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ast_Resolved_Type *
|
||||||
|
type_pointer(Ast_Resolved_Type *base){
|
||||||
|
Ast_Resolved_Type *result = (Ast_Resolved_Type *)map_get(&pctx->type_map, (void *)base);
|
||||||
|
if(!result){
|
||||||
|
result = type_new(pctx->perm, TYPE_POINTER, pointer_size, pointer_align);
|
||||||
|
result->base = base;
|
||||||
|
map_insert(&pctx->type_map, base, result);
|
||||||
|
}
|
||||||
|
assert(result->kind == TYPE_POINTER);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ast_Resolved_Type *
|
||||||
|
type_array(Ast_Resolved_Type *base, SizeU size){
|
||||||
|
U64 hash = hash_mix(hash_ptr(base), hash_u64(size));
|
||||||
|
Ast_Resolved_Type *result = (Ast_Resolved_Type *)map_get(&pctx->type_map, hash);
|
||||||
|
if(result){
|
||||||
|
assert(result->kind == TYPE_ARRAY);
|
||||||
|
assert(result->arr.size == size);
|
||||||
|
assert(result->arr.base == base);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = type_new(pctx->perm, TYPE_ARRAY, pointer_size, pointer_align);
|
||||||
|
result->arr.base = base;
|
||||||
|
result->arr.size = size;
|
||||||
|
map_insert(&pctx->type_map, hash, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ast_Resolved_Type *
|
||||||
|
type_lambda(Ast *ast, Ast_Resolved_Type *ret, Array<Ast_Resolved_Type *> args){
|
||||||
|
U64 hash = hash_ptr(ret);
|
||||||
|
For(args) hash = hash_mix(hash, hash_ptr(it));
|
||||||
|
Ast_Resolved_Type *result = (Ast_Resolved_Type *)map_get(&pctx->type_map, hash);
|
||||||
|
|
||||||
|
if(result){
|
||||||
|
assert(result->kind == TYPE_LAMBDA);
|
||||||
|
assert(result->func.ret == ret);
|
||||||
|
assert(result->func.args.len == args.len);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = type_new(pctx->perm, TYPE_LAMBDA, pointer_size, pointer_align);
|
||||||
|
result->ast = ast;
|
||||||
|
result->func.ret = ret;
|
||||||
|
result->func.args = args.tight_copy(pctx->perm);
|
||||||
|
map_insert(&pctx->type_map, hash, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ast_Resolved_Type *
|
||||||
|
type_enum(Ast_Enum *ast){
|
||||||
|
Ast_Resolved_Type *type = resolve_typespec(ast->typespec, AST_CAN_BE_NULL);
|
||||||
|
if(!type) {
|
||||||
|
type = type_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ast_Resolved_Type *result = type_new(pctx->perm, TYPE_ENUM, type->size, type->align);
|
||||||
|
result->base = type;
|
||||||
|
result->ast = ast;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
2022.05.31 - Global scope structs vs nested structs
|
||||||
|
Structs exist in 2 variants, the global scope structs are a bit different
|
||||||
|
then scoped structs. They startout incomplete and when some operation
|
||||||
|
requires the actual struct size, alignment, field access etc. then it
|
||||||
|
should call complete_type. It resolves all the children, calculates the
|
||||||
|
size and makes sure there are no cyclic dependencies. This is require for
|
||||||
|
correct behaviour of order independent structs. If someone just wants a pointer
|
||||||
|
to that struct we don't need to complete the type, we know how large a pointer is.
|
||||||
|
This allows us to have cyclic dependency that is a pointer. Cause we know how large pointer is.
|
||||||
|
*/
|
||||||
|
function Ast_Resolved_Type *
|
||||||
|
type_incomplete(Ast *ast){
|
||||||
|
Ast_Resolved_Type *result = type_new(pctx->perm, TYPE_INCOMPLETE, 0, 0);
|
||||||
|
result->ast = ast;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
type_struct_complete(Ast_Resolved_Type *type, Ast_Struct *node){
|
||||||
|
// @todo: compute size, alignement, offset !!!
|
||||||
|
// @note: resolve all the struct members first
|
||||||
|
type->kind = TYPE_COMPLETING;
|
||||||
|
Scratch scratch;
|
||||||
|
Array<Ast_Resolved_Member> members = {scratch};
|
||||||
|
For(node->members){
|
||||||
|
Operand op = resolve_binding(it);
|
||||||
|
Intern_String name = ast_get_name(it);
|
||||||
|
sym_new_resolved(SYM_VAR, name, op.type, {}, it);
|
||||||
|
members.add({op.type, name});
|
||||||
|
}
|
||||||
|
type->agg.members = members.tight_copy(pctx->perm);
|
||||||
|
type->kind = TYPE_STRUCT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@note: resolve constant members after the struct got resolved
|
||||||
|
this way we avoid a problem where we start resolving the function
|
||||||
|
and this function has parameter of type parent struct
|
||||||
|
which is being resolved right now, cyclic dependency happens.
|
||||||
|
constants arent required to make struct work
|
||||||
|
*/
|
||||||
|
For(node->const_members){
|
||||||
|
Operand op = resolve_binding(it);
|
||||||
|
Intern_String name = ast_get_name(it);
|
||||||
|
sym_new_resolved(SYM_CONST, name, op.type, op.value, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ast_Resolved_Type *
|
||||||
|
type_struct(Ast_Struct *agg){
|
||||||
|
Ast_Resolved_Type *result = type_new(pctx->perm, TYPE_STRUCT, 0, 0);
|
||||||
|
result->ast = agg;
|
||||||
|
type_struct_complete(result, agg);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
type_complete(Ast_Resolved_Type *type){
|
||||||
|
if(type->kind == TYPE_COMPLETING){
|
||||||
|
parsing_error(type->ast->pos, "Cyclic type dependency");
|
||||||
|
}
|
||||||
|
else if(type->kind != TYPE_INCOMPLETE){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ast_Struct *node = (Ast_Struct *)type->ast;
|
||||||
|
type_struct_complete(type, node);
|
||||||
|
pctx->resolving_package->ordered.add((Ast_Named *)node->parent);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user