From f885abe3f533f2d92bbc05b59bc202a27af9a405 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Tue, 14 Jun 2022 13:50:59 +0200 Subject: [PATCH] -> Operator has very low precedence, size_of, align_of, length_of expressions --- ast.cpp | 34 ++++++++++++++++++++---- ccodegen.cpp | 26 +++++++----------- compiler.h | 8 ++++-- main.kl | 14 +++------- parsing.cpp | 26 +++++++++++++++--- typechecking.cpp | 69 +++++++++++++++++++++++++++++++++--------------- typechecking.h | 2 +- 7 files changed, 121 insertions(+), 58 deletions(-) diff --git a/ast.cpp b/ast.cpp index 651e34b..f510586 100644 --- a/ast.cpp +++ b/ast.cpp @@ -20,6 +20,10 @@ enum Ast_Kind: U32{ AST_CALL_ITEM, AST_CALL, + AST_SIZE_OF, + AST_LENGTH_OF, + AST_ALIGN_OF, + AST_COMPOUND, AST_TYPE, AST_VAR, @@ -56,7 +60,7 @@ enum{ }; struct Ast{ - U64 id; + U64 di; // Debug id, shouldn't ever be used in the program Token *pos; Ast_Kind kind; @@ -119,13 +123,12 @@ struct Ast_Binary: Ast_Expr{ Token_Kind op; Ast_Expr *left; Ast_Expr *right; - - // Ast_Type *type; // For casts after_type Ast_Type *before_type; }; -struct Ast_Len: Ast_Expr{ +struct Ast_Builtin: Ast_Expr{ Ast_Expr *expr; + U64 padding[3]; // For folding constants into atoms }; // Problem: We are parsing out of order, in the middle of parsing a function @@ -236,7 +239,7 @@ struct Ast_Decl: Ast{ result->kind = AST_##ikind; \ result->parent_scope = pctx->currently_parsed_scope; \ result->pos = ipos; \ - result->id = ++pctx->unique_ids + result->di = ++pctx->unique_ids function Ast_Atom * ast_str(Token *pos, Intern_String string){ @@ -513,6 +516,27 @@ ast_module(Intern_String filename){ return result; } +function Ast_Builtin * +ast_sizeof(Token *pos, Ast_Expr *expr){ + AST_NEW(Builtin, SIZE_OF, pos, AST_EXPR); + result->expr = expr; + return result; +} + +function Ast_Builtin * +ast_len(Token *pos, Ast_Expr *expr){ + AST_NEW(Builtin, LENGTH_OF, pos, AST_EXPR); + result->expr = expr; + return result; +} + +function Ast_Builtin * +ast_alignof(Token *pos, Ast_Expr *expr){ + AST_NEW(Builtin, ALIGN_OF, pos, AST_EXPR); + result->expr = expr; + return result; +} + //----------------------------------------------------------------------------- // Value //----------------------------------------------------------------------------- diff --git a/ccodegen.cpp b/ccodegen.cpp index c113822..d7f0208 100644 --- a/ccodegen.cpp +++ b/ccodegen.cpp @@ -256,6 +256,7 @@ gen_expr(Ast_Expr *ast, Ast_Type *type_of_var){ CASE(INDEX, Index){ gen("("); gen_expr(node->expr); + if(node->expr->resolved_type == type_string) gen(".str"); gen("["); gen_expr(node->index); gen("]"); @@ -310,19 +311,15 @@ gen_expr(Ast_Expr *ast, Ast_Type *type_of_var){ BREAK(); } - CASE(CALL, Call){ - if(node->name->kind == AST_IDENT){ - auto ident = (Ast_Atom *)node->name; - if(ident->intern_val == pctx->intern("len"_s)){ - if(is_slice(ident->type)){ - Ast_Call_Item *arg = node->exprs[0]; - gen_expr(arg->item); - gen(".len"); - return true; - } else invalid_codepath; - } - } + CASE(LENGTH_OF, Builtin){ + gen_expr(node->expr); + if(is_pointer(node->expr->resolved_type)) + gen("->len"); + else gen(".len"); + BREAK(); + } + CASE(CALL, Call){ gen_expr(node->name); gen("("); For(node->exprs){ @@ -680,10 +677,7 @@ typedef struct String{ #endif For(pctx->ordered_decls){ if(it->kind == AST_STRUCT){ - genln("typedef struct struct %s;", it->name.str); - } else if(it->kind == AST_LAMBDA){ - genln(""); - gen_lambda(it->name, it->lambda, false); + genln("typedef struct %s %s;", it->name.str, it->name.str); } } diff --git a/compiler.h b/compiler.h index df0d02b..c3f6731 100644 --- a/compiler.h +++ b/compiler.h @@ -163,7 +163,9 @@ Intern_String keyword_true; Intern_String keyword_false; Intern_String keyword_for; Intern_String keyword_pass; -Intern_String keyword_cast; +Intern_String keyword_sizeof; +Intern_String keyword_alignof; +Intern_String keyword_lengthof; Intern_String keyword_enum; Intern_String intern_void; @@ -202,7 +204,9 @@ lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){ keyword_struct= l->intern("struct"_s); keyword_union = l->intern("union"_s); - keyword_cast = l->intern("cast"_s); + keyword_sizeof = l->intern("size_of"_s); + keyword_lengthof = l->intern("length_of"_s); + keyword_alignof = l->intern("align_of"_s); keyword_true = l->intern("true"_s); keyword_false = l->intern("false"_s); keyword_return = l->intern("return"_s); diff --git a/main.kl b/main.kl index 1822c5f..ec754fe 100644 --- a/main.kl +++ b/main.kl @@ -1,16 +1,10 @@ #import "base.kl" -test_arrays :: () - array := [4]int{1,2,3,4} - item := array[0] - length := len(array) - slice: []int = array - slice_length := len(slice) +print :: (string: String) + handle := Windows.GetStdHandle(Windows.STD_OUTPUT_HANDLE) + Windows.WriteConsoleA(handle, &string[0]->*void, length_of(string)->Windows.DWORD, 0, 0) main :: (argc: int, argv: **char): int memory := reserve(size = 10000) - handle := Windows.GetStdHandle(Windows.STD_OUTPUT_HANDLE) + print("Hello world") - - string: *char = "hello world" - Windows.WriteConsoleA(handle, string->*void, 11, 0, 0) diff --git a/parsing.cpp b/parsing.cpp index df0f588..89da684 100644 --- a/parsing.cpp +++ b/parsing.cpp @@ -404,7 +404,7 @@ binding_power(Binding binding, Token_Kind kind){ case TK_Dot: return {31,30}; case TK_Arrow: - return {29,28}; + return {2,1}; default: return {}; } Postfix: switch(kind){ @@ -457,8 +457,28 @@ parse_expr(S64 min_bp){ }break; case TK_Keyword: { - if(token->intern_val == keyword_true) left = ast_bool(token, 1); - else if(token->intern_val == keyword_false) left = ast_bool(token, 0); + if(token->intern_val == keyword_true) + left = ast_bool(token, 1); + else if(token->intern_val == keyword_false) + left = ast_bool(token, 0); + else if(token->intern_val == keyword_sizeof){ + token_expect(TK_OpenParen); + Ast_Expr *expr = parse_expr(); + token_expect(TK_CloseParen); + left = ast_sizeof(token, expr); + } + else if(token->intern_val == keyword_alignof){ + token_expect(TK_OpenParen); + Ast_Expr *expr = parse_expr(); + token_expect(TK_CloseParen); + left = ast_alignof(token, expr); + } + else if(token->intern_val == keyword_lengthof){ + token_expect(TK_OpenParen); + Ast_Expr *expr = parse_expr(); + token_expect(TK_CloseParen); + left = ast_len(token, expr); + } else compiler_error(token, "Unexpected keyword: [%s], expected keyword [cast]", token->intern_val.str); }break; diff --git a/typechecking.cpp b/typechecking.cpp index f995a1d..e6c3527 100644 --- a/typechecking.cpp +++ b/typechecking.cpp @@ -311,6 +311,7 @@ _rewrite_into_const(Ast *node, U64 ast_size, Value value){ set_flag(ast->flags, AST_ATOM); ast->kind = AST_VALUE; ast->value = value; + ast->resolved_type = value.type; } function Ast_Decl * @@ -682,6 +683,7 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ CASE(IDENT, Atom){ node->resolved_decl = resolve_name(node->parent_scope, node->pos, node->intern_val); + node->resolved_type = node->resolved_decl->type; Operand result = operand(node->resolved_decl); if(result.is_const){ @@ -749,11 +751,15 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ 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)){ + + node->index_original_type = left.type; + if(is_string(left.type)){ + return operand_lvalue(type_u8); + } + else 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->index_original_type = left.type; return operand_lvalue(left.type->arr.base); BREAK(); } @@ -858,28 +864,49 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ BREAK(); } - CASE(CALL, Call){ - // Handle builtin calls - if(node->name->kind == AST_IDENT){ - auto ident = (Ast_Atom *)node->name; - if(ident->intern_val == pctx->intern("len"_s)){ - if(node->exprs.len > 1) compiler_error(node->pos, "Expected 1 argument"); - Ast_Call_Item *arg = node->exprs[0]; - if(arg->name || arg->index) compiler_error(node->pos, "No named or indexed arguments expected"); - Operand op = resolve_expr(arg->item, AST_CANT_BE_NULL); - ident->type = op.type; + CASE(ALIGN_OF, Builtin){ + Operand name = resolve_expr(node->expr, AST_CANT_BE_NULL); + if(!name.is_const) compiler_error(node->pos, "align_of requires a constant value"); + Ast_Type *type = name.type == type_type ? name.type_val : name.type; + Value v = value_int(type->align); + rewrite_into_const(node, Ast_Builtin, v); + return operand_const_rvalue(v); + BREAK(); + } - if(is_array(op.type)){ - Value val = value_int(op.type->arr.size); - rewrite_into_const(node, Ast_Call, val); - return operand_const_rvalue(val); - } else if(is_slice(op.type)){ - return operand_rvalue(type_s64); - } else compiler_error(node->pos, "Invalid argument"); + CASE(SIZE_OF, Builtin){ + Operand name = resolve_expr(node->expr, AST_CANT_BE_NULL); + if(!name.is_const) compiler_error(node->pos, "size_of requires a constant value"); + Ast_Type *type = name.type == type_type ? name.type_val : name.type; + Value v = value_int(type->size); + rewrite_into_const(node, Ast_Builtin, v); + return operand_const_rvalue(v); + BREAK(); + } + + CASE(LENGTH_OF, Builtin){ + Operand name = resolve_expr(node->expr, AST_CANT_BE_NULL); + if(name.type == type_type){ + if(is_array(name.type_val)){ + Value value = value_int(name.type_val->arr.size); + rewrite_into_const(node, Ast_Builtin, value); + return operand_const_rvalue(value); } + else compiler_error(node->pos, "Can't get length of type %s", docname(name.type_val)); } + else if(name.type->kind == TYPE_UNTYPED_STRING){ + Value value = value_int(name.intern_val.len); + rewrite_into_const(node, Ast_Builtin, value); + return operand_const_rvalue(value); + } + else if(is_array(name.type) || is_slice(name.type) || is_string(name.type)){ + return operand_rvalue(type_s64); + } + else compiler_error(node->pos, "Can't get length of type %s", docname(name.type)); + BREAK(); + } - // Handle calls + 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)); @@ -918,7 +945,7 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ if(item){ set_flag(item->flags, AST_ITEM_INCLUDED); Operand expr = resolve_expr(item->item, AST_CANT_BE_NULL, lambda_arg->type); - make_sure_value_is_compatible_with_type(node->pos, &expr, lambda_arg->type, TYPE_AND_EXPR_REQUIRED); + make_sure_value_is_compatible_with_type(item->pos, &expr, lambda_arg->type, TYPE_AND_EXPR_REQUIRED); items.add(item); } else{ diff --git a/typechecking.h b/typechecking.h index a190732..9424952 100644 --- a/typechecking.h +++ b/typechecking.h @@ -164,7 +164,7 @@ type_array(Ast_Type *base, S64 size){ return result; } - result = type_new(pctx->perm, TYPE_ARRAY, pointer_size, pointer_align); + result = type_new(pctx->perm, TYPE_ARRAY, size*base->size, pointer_align); result->arr.base = base; result->arr.size = size; result->arr.slice_hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE));