Struct field access. Damn, I coded for like 30 minutes and then it just worked on the first try
This commit is contained in:
19
ccodegen.cpp
19
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();
|
||||
}
|
||||
|
||||
|
||||
65
new_ast.cpp
65
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<Ast_Named *> 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<Ast_Var *> members;
|
||||
Array<Ast_Const *> 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<Ast_Named *> members){
|
||||
ast_struct(Token *pos, Array<Ast_Var *> members, Array<Ast_Const *> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Ast_Named *> members = {scratch};
|
||||
Array<Ast_Var *> members = {scratch};
|
||||
Array<Ast_Const *> 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;
|
||||
}
|
||||
|
||||
|
||||
12
new_type.cpp
12
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);
|
||||
|
||||
22
order2.kl
22
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,
|
||||
)
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user