From 980a3b68b9739142c5754a1d7c6985c6d9805a41 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Mon, 30 May 2022 18:27:06 +0200 Subject: [PATCH] Struct field access. Damn, I coded for like 30 minutes and then it just worked on the first try --- ccodegen.cpp | 19 ++++++++--- new_ast.cpp | 65 +++++++++++++++++++++++++++++------ new_parse.cpp | 21 +++++++++--- new_type.cpp | 12 +++++++ order2.kl | 22 +++++++----- typechecking.cpp | 88 ++++++++++++++++++++++++++++++++++++++++-------- 6 files changed, 186 insertions(+), 41 deletions(-) diff --git a/ccodegen.cpp b/ccodegen.cpp index c5df184..4c29102 100644 --- a/ccodegen.cpp +++ b/ccodegen.cpp @@ -100,11 +100,20 @@ gen_expr(Ast_Expr *ast){ } CASE(BINARY, Binary){ - gen("("); - gen_expr(node->left); - gen("%s", token_kind_string(node->op).str); - gen_expr(node->right); - gen(")"); + if(node->op == TK_Dot){ + Sym *sym = resolved_get(node->left); + gen_expr(node->left); + if(sym->type->kind == TYPE_POINTER) gen("->"); + else gen("."); + gen_expr(node->right); + } + else{ + gen("("); + gen_expr(node->left); + gen("%s", token_kind_string(node->op).str); + gen_expr(node->right); + gen(")"); + } BREAK(); } diff --git a/new_ast.cpp b/new_ast.cpp index 24fe91c..7dd5f1a 100644 --- a/new_ast.cpp +++ b/new_ast.cpp @@ -217,18 +217,20 @@ struct Ast_Named:Ast{ Intern_String name; }; -struct Ast_Resolved_Type; -struct Ast_Struct: Ast_Expr{ - // Required to be Ast_Struct or Ast_Var or Ast_Const - Array members; - Ast_Resolved_Type *type; -}; - struct Ast_Var: Ast_Named{ Ast_Expr *typespec; Ast_Expr *expr; }; +struct Ast_Const; +struct Ast_Resolved_Type; +struct Ast_Struct: Ast_Expr{ + // Required to be Ast_Struct or Ast_Var or Ast_Const + Array members; + Array const_members; + Ast_Resolved_Type *type; +}; + struct Ast_Const: Ast_Named{ union{ Ast *ast; @@ -281,7 +283,7 @@ ast_expr_binary(Ast_Expr *left, Ast_Expr *right, Token *op){ result->left = left; result->right = right; result->left->parent = result; - result->right->parent = result; + if(result->right) result->right->parent = result; return result; } @@ -426,12 +428,18 @@ ast_array(Token *pos, Ast_Expr *expr){ } function Ast_Struct * -ast_struct(Token *pos, Array members){ +ast_struct(Token *pos, Array members, Array const_members){ AST_NEW(Struct, STRUCT, pos, AST_AGGREGATE); result->members = members.tight_copy(pctx->perm); + result->const_members = const_members.tight_copy(pctx->perm); For(result->members) { assert(is_flag_set(it->flags, AST_BINDING)); - assert(it->kind == AST_VAR || it->kind == AST_CONST); + assert(it->kind == AST_VAR); + it->parent = result; + } + For(result->const_members) { + assert(is_flag_set(it->flags, AST_BINDING)); + assert(it->kind == AST_CONST); it->parent = result; } return result; @@ -525,3 +533,40 @@ ast_is_struct(Ast *ast){ } return false; } + +function B32 +is_ident(Ast *ast){ + B32 result = ast->kind == AST_IDENT; + return result; +} + +function B32 +is_binary(Ast *ast){ + B32 result = ast->kind == AST_BINARY; + return result; +} + +function B32 +is_atom(Ast *ast){ + B32 result = is_flag_set(ast->flags, AST_ATOM); + return result; +} + +function Ast * +query_struct(Ast_Struct *agg, Intern_String string){ + + For(agg->members){ + if(it->name == string){ + return it; + } + } + + For(agg->const_members){ + if(it->name == string){ + return it; + } + } + + return 0; +} + diff --git a/new_parse.cpp b/new_parse.cpp index d0a0c77..b71d60a 100644 --- a/new_parse.cpp +++ b/new_parse.cpp @@ -353,7 +353,7 @@ left_denotation(Token *op, Ast_Expr *left){ function S64 postfix_binding_power(Token_Kind kind){ switch(kind){ - case TK_Decrement: case TK_Increment: case TK_OpenBracket: case TK_OpenParen: return 1; + case TK_Dot: case TK_Decrement: case TK_Increment: case TK_OpenBracket: case TK_OpenParen: return 1; default: return 0; } } @@ -369,6 +369,12 @@ parse_expr(S64 rbp){ if(postfix_binding_power(token->kind) > rbp){ token_next(); switch(token->kind){ + case TK_Dot: { + // @note: making sure that we always get a configuration where + // Identifier is in left node + Ast_Expr *right = parse_expr(); + left = ast_expr_binary(left, right, token); + }break; case TK_OpenBracket:{ Ast_Expr *index = parse_expr(); left = ast_expr_index(token, left, index); @@ -406,18 +412,25 @@ parse_assign_expr(){ function Ast_Struct * parse_struct(Token *pos){ Scratch scratch; - Array members = {scratch}; + Array members = {scratch}; + Array members_const = {scratch}; token_match(OPEN_SCOPE); do{ Token *token = token_get(); Ast_Named *named = parse_named(false); if(!named) parsing_error(token, "Failed to parse struct member"); - members.add(named); + if(named->kind == AST_CONST){ + members_const.add((Ast_Const *)named); + } else { + assert(named->kind == AST_VAR); + members.add((Ast_Var *)named); + } + }while(token_match(SAME_SCOPE)); token_expect(CLOSE_SCOPE); - Ast_Struct *result = ast_struct(pos, members); + Ast_Struct *result = ast_struct(pos, members, members_const); return result; } diff --git a/new_type.cpp b/new_type.cpp index 7e550dc..9e53f44 100644 --- a/new_type.cpp +++ b/new_type.cpp @@ -83,6 +83,18 @@ global Ast_Resolved_Type *type_string = &type__string; global Ast_Resolved_Type *type_bool = &type__bool; global Ast_Resolved_Type *type_null = &type__null; +function B32 +is_struct(Ast_Resolved_Type *type){ + B32 result = type->kind == TYPE_STRUCT; + return result; +} + +function B32 +is_pointer(Ast_Resolved_Type *type){ + B32 result = type->kind == TYPE_POINTER; + return result; +} + 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); diff --git a/order2.kl b/order2.kl index c337e22..477a92f 100644 --- a/order2.kl +++ b/order2.kl @@ -4,6 +4,14 @@ arena_pointer: *Arena = null thing: Arena no_type := thing +arena := Arena( + next = null, + data = null, + len = 1000, + cap = 1000, + // constant_inside = 10, +) + Arena :: struct // arena: Arena next: *Arena @@ -11,8 +19,12 @@ Arena :: struct len : int cap : int - get_len :: (s: *Arena): int - return s.len + constant_inside :: 10000 +constant_outside :: 10000 + +get_len :: (s: *Arena): int + return s.next.len + string16: Str16 @@ -24,10 +36,4 @@ with_type: Arena = thing pointer := &with_type deref := *pointer -arena := Arena( - next = null, - data = null, - len = 1000, - cap = 1000, -) diff --git a/typechecking.cpp b/typechecking.cpp index de0c3c9..41f16d2 100644 --- a/typechecking.cpp +++ b/typechecking.cpp @@ -363,6 +363,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *const_sym){ CASE(CALL, Call){ Operand name = resolve_expr(node->name); Ast_Resolved_Type *type = name.type; + type_complete(type); if(name.type == type_type){ type = name.type_val; if(expected_type && expected_type != type) parsing_error(node->pos, "Variable type different from explicit compound type"); @@ -530,6 +531,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *const_sym){ else if(value.type->kind == TYPE_TYPE){ Operand result = {type_type, true}; result.type_val = type_pointer(value.type_val); + sym_new_resolved(SYM_CONST, {}, type_type, result.value, node); return result; } else{ parsing_error(node->pos, "Dereferencing expression %s that is not a [Pointer] or [Type]", type_names[value.type->kind]); return {}; } @@ -545,23 +547,81 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *const_sym){ } CASE(BINARY, Binary){ - Operand left = resolve_expr(node->left); - Operand right = resolve_expr(node->right); Operand result = {}; - result.type = resolve_type_pair(node->pos, left.type, right.type); - if(left.is_const && right.is_const){ - result.is_const = true; - if(result.type == type_int){ - switch(node->op){ - case TK_Add: result.int_val = left.int_val + right.int_val; break; - case TK_Sub: result.int_val = left.int_val - right.int_val; break; - case TK_Mul: result.int_val = left.int_val * right.int_val; break; - case TK_Div: result.int_val = left.int_val / right.int_val; break; - invalid_default_case; - } + if(node->op == TK_Dot){ + // @note: resolve first chunk which involves querying global map + // second part requires searching through a struct + // resolve.x.y + Operand resolved_ident = resolve_expr(node->left); + // @copy_paste + Ast_Resolved_Type *type = resolved_ident.type; + if(is_pointer(type)){ + type = type->base; } - else parsing_error(node->pos, "Arithmetic on type [%s] is not supported", type_names[result.type->kind]); + type_complete(type); + if(!is_struct(type)){ + parsing_error(node->pos, "Trying to access inside a value that is not a struct"); + } + sym_new_resolved(SYM_VAR, {}, resolved_ident.type, {}, node->left); + + // This happens only on binary nodes which further chain with dots and require lookups + // x.resolve.y + Ast_Binary *binary = (Ast_Binary *)node->right; + for(; !is_ident(binary); binary=(Ast_Binary *)binary->right){ + assert(is_ident(binary->left)); + Ast_Atom *ident = (Ast_Atom *)binary->left; + assert(is_binary(binary)); + + Ast_Struct *agg = (Ast_Struct *)type->ast; + Ast *query = query_struct(agg, ident->intern_val); + // @copy_paste + if(query){ + Sym *sym = resolved_get(query); + type = sym->type; + if(is_pointer(type)){ + type = type->base; + } + type_complete(type); + if(!is_struct(type)){ + parsing_error(node->pos, "Trying to access inside a value that is not a struct"); + } + sym_new_resolved(SYM_VAR, {}, sym->type, {}, ident); + + } else parsing_error(ident->pos, "No such member in struct"); + } + + // Here we can resolve the last part, this doesnt need to be a struct + // x.y.resolve + // @copy_paste + Ast_Atom *ident = (Ast_Atom *)binary; + Ast_Struct *agg = (Ast_Struct *)type->ast; + Ast *query = query_struct(agg, ident->intern_val); + if(query){ + Sym *sym = resolved_get(query); + result.type = sym->type; + sym_new_resolved(SYM_VAR, {}, sym->type, {}, ident); + } else parsing_error(ident->pos, "No such member in struct"); + } + else{ + Operand left = resolve_expr(node->left); + Operand right = resolve_expr(node->right); + result.type = resolve_type_pair(node->pos, left.type, right.type); + if(left.is_const && right.is_const){ + result.is_const = true; + if(result.type == type_int){ + switch(node->op){ + case TK_Add: result.int_val = left.int_val + right.int_val; break; + case TK_Sub: result.int_val = left.int_val - right.int_val; break; + case TK_Mul: result.int_val = left.int_val * right.int_val; break; + case TK_Div: result.int_val = left.int_val / right.int_val; break; + invalid_default_case; + } + } + else parsing_error(node->pos, "Arithmetic on type [%s] is not supported", type_names[result.type->kind]); + } + } + return result; BREAK();