-> Operator has very low precedence, size_of, align_of, length_of expressions
This commit is contained in:
34
ast.cpp
34
ast.cpp
@@ -20,6 +20,10 @@ enum Ast_Kind: U32{
|
|||||||
AST_CALL_ITEM,
|
AST_CALL_ITEM,
|
||||||
AST_CALL,
|
AST_CALL,
|
||||||
|
|
||||||
|
AST_SIZE_OF,
|
||||||
|
AST_LENGTH_OF,
|
||||||
|
AST_ALIGN_OF,
|
||||||
|
|
||||||
AST_COMPOUND,
|
AST_COMPOUND,
|
||||||
AST_TYPE,
|
AST_TYPE,
|
||||||
AST_VAR,
|
AST_VAR,
|
||||||
@@ -56,7 +60,7 @@ enum{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Ast{
|
struct Ast{
|
||||||
U64 id;
|
U64 di; // Debug id, shouldn't ever be used in the program
|
||||||
Token *pos;
|
Token *pos;
|
||||||
|
|
||||||
Ast_Kind kind;
|
Ast_Kind kind;
|
||||||
@@ -119,13 +123,12 @@ struct Ast_Binary: Ast_Expr{
|
|||||||
Token_Kind op;
|
Token_Kind op;
|
||||||
Ast_Expr *left;
|
Ast_Expr *left;
|
||||||
Ast_Expr *right;
|
Ast_Expr *right;
|
||||||
|
|
||||||
// Ast_Type *type; // For casts after_type
|
|
||||||
Ast_Type *before_type;
|
Ast_Type *before_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Ast_Len: Ast_Expr{
|
struct Ast_Builtin: Ast_Expr{
|
||||||
Ast_Expr *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
|
// 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->kind = AST_##ikind; \
|
||||||
result->parent_scope = pctx->currently_parsed_scope; \
|
result->parent_scope = pctx->currently_parsed_scope; \
|
||||||
result->pos = ipos; \
|
result->pos = ipos; \
|
||||||
result->id = ++pctx->unique_ids
|
result->di = ++pctx->unique_ids
|
||||||
|
|
||||||
function Ast_Atom *
|
function Ast_Atom *
|
||||||
ast_str(Token *pos, Intern_String string){
|
ast_str(Token *pos, Intern_String string){
|
||||||
@@ -513,6 +516,27 @@ ast_module(Intern_String filename){
|
|||||||
return result;
|
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
|
// Value
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|||||||
24
ccodegen.cpp
24
ccodegen.cpp
@@ -256,6 +256,7 @@ gen_expr(Ast_Expr *ast, Ast_Type *type_of_var){
|
|||||||
CASE(INDEX, Index){
|
CASE(INDEX, Index){
|
||||||
gen("(");
|
gen("(");
|
||||||
gen_expr(node->expr);
|
gen_expr(node->expr);
|
||||||
|
if(node->expr->resolved_type == type_string) gen(".str");
|
||||||
gen("[");
|
gen("[");
|
||||||
gen_expr(node->index);
|
gen_expr(node->index);
|
||||||
gen("]");
|
gen("]");
|
||||||
@@ -310,19 +311,15 @@ gen_expr(Ast_Expr *ast, Ast_Type *type_of_var){
|
|||||||
BREAK();
|
BREAK();
|
||||||
}
|
}
|
||||||
|
|
||||||
CASE(CALL, Call){
|
CASE(LENGTH_OF, Builtin){
|
||||||
if(node->name->kind == AST_IDENT){
|
gen_expr(node->expr);
|
||||||
auto ident = (Ast_Atom *)node->name;
|
if(is_pointer(node->expr->resolved_type))
|
||||||
if(ident->intern_val == pctx->intern("len"_s)){
|
gen("->len");
|
||||||
if(is_slice(ident->type)){
|
else gen(".len");
|
||||||
Ast_Call_Item *arg = node->exprs[0];
|
BREAK();
|
||||||
gen_expr(arg->item);
|
|
||||||
gen(".len");
|
|
||||||
return true;
|
|
||||||
} else invalid_codepath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CASE(CALL, Call){
|
||||||
gen_expr(node->name);
|
gen_expr(node->name);
|
||||||
gen("(");
|
gen("(");
|
||||||
For(node->exprs){
|
For(node->exprs){
|
||||||
@@ -680,10 +677,7 @@ typedef struct String{
|
|||||||
#endif
|
#endif
|
||||||
For(pctx->ordered_decls){
|
For(pctx->ordered_decls){
|
||||||
if(it->kind == AST_STRUCT){
|
if(it->kind == AST_STRUCT){
|
||||||
genln("typedef struct struct %s;", it->name.str);
|
genln("typedef struct %s %s;", it->name.str, it->name.str);
|
||||||
} else if(it->kind == AST_LAMBDA){
|
|
||||||
genln("");
|
|
||||||
gen_lambda(it->name, it->lambda, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -163,7 +163,9 @@ Intern_String keyword_true;
|
|||||||
Intern_String keyword_false;
|
Intern_String keyword_false;
|
||||||
Intern_String keyword_for;
|
Intern_String keyword_for;
|
||||||
Intern_String keyword_pass;
|
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 keyword_enum;
|
||||||
|
|
||||||
Intern_String intern_void;
|
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_struct= l->intern("struct"_s);
|
||||||
keyword_union = l->intern("union"_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_true = l->intern("true"_s);
|
||||||
keyword_false = l->intern("false"_s);
|
keyword_false = l->intern("false"_s);
|
||||||
keyword_return = l->intern("return"_s);
|
keyword_return = l->intern("return"_s);
|
||||||
|
|||||||
14
main.kl
14
main.kl
@@ -1,16 +1,10 @@
|
|||||||
#import "base.kl"
|
#import "base.kl"
|
||||||
|
|
||||||
test_arrays :: ()
|
print :: (string: String)
|
||||||
array := [4]int{1,2,3,4}
|
handle := Windows.GetStdHandle(Windows.STD_OUTPUT_HANDLE)
|
||||||
item := array[0]
|
Windows.WriteConsoleA(handle, &string[0]->*void, length_of(string)->Windows.DWORD, 0, 0)
|
||||||
length := len(array)
|
|
||||||
slice: []int = array
|
|
||||||
slice_length := len(slice)
|
|
||||||
|
|
||||||
main :: (argc: int, argv: **char): int
|
main :: (argc: int, argv: **char): int
|
||||||
memory := reserve(size = 10000)
|
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)
|
|
||||||
|
|||||||
26
parsing.cpp
26
parsing.cpp
@@ -404,7 +404,7 @@ binding_power(Binding binding, Token_Kind kind){
|
|||||||
case TK_Dot:
|
case TK_Dot:
|
||||||
return {31,30};
|
return {31,30};
|
||||||
case TK_Arrow:
|
case TK_Arrow:
|
||||||
return {29,28};
|
return {2,1};
|
||||||
default: return {};
|
default: return {};
|
||||||
}
|
}
|
||||||
Postfix: switch(kind){
|
Postfix: switch(kind){
|
||||||
@@ -457,8 +457,28 @@ parse_expr(S64 min_bp){
|
|||||||
}break;
|
}break;
|
||||||
|
|
||||||
case TK_Keyword: {
|
case TK_Keyword: {
|
||||||
if(token->intern_val == keyword_true) left = ast_bool(token, 1);
|
if(token->intern_val == keyword_true)
|
||||||
else if(token->intern_val == keyword_false) left = ast_bool(token, 0);
|
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);
|
else compiler_error(token, "Unexpected keyword: [%s], expected keyword [cast]", token->intern_val.str);
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
|
|||||||
@@ -311,6 +311,7 @@ _rewrite_into_const(Ast *node, U64 ast_size, Value value){
|
|||||||
set_flag(ast->flags, AST_ATOM);
|
set_flag(ast->flags, AST_ATOM);
|
||||||
ast->kind = AST_VALUE;
|
ast->kind = AST_VALUE;
|
||||||
ast->value = value;
|
ast->value = value;
|
||||||
|
ast->resolved_type = value.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Ast_Decl *
|
function Ast_Decl *
|
||||||
@@ -682,6 +683,7 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){
|
|||||||
|
|
||||||
CASE(IDENT, Atom){
|
CASE(IDENT, Atom){
|
||||||
node->resolved_decl = resolve_name(node->parent_scope, node->pos, node->intern_val);
|
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);
|
Operand result = operand(node->resolved_decl);
|
||||||
if(result.is_const){
|
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)){
|
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));
|
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));
|
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);
|
return operand_lvalue(left.type->arr.base);
|
||||||
BREAK();
|
BREAK();
|
||||||
}
|
}
|
||||||
@@ -858,28 +864,49 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){
|
|||||||
BREAK();
|
BREAK();
|
||||||
}
|
}
|
||||||
|
|
||||||
CASE(CALL, Call){
|
CASE(ALIGN_OF, Builtin){
|
||||||
// Handle builtin calls
|
Operand name = resolve_expr(node->expr, AST_CANT_BE_NULL);
|
||||||
if(node->name->kind == AST_IDENT){
|
if(!name.is_const) compiler_error(node->pos, "align_of requires a constant value");
|
||||||
auto ident = (Ast_Atom *)node->name;
|
Ast_Type *type = name.type == type_type ? name.type_val : name.type;
|
||||||
if(ident->intern_val == pctx->intern("len"_s)){
|
Value v = value_int(type->align);
|
||||||
if(node->exprs.len > 1) compiler_error(node->pos, "Expected 1 argument");
|
rewrite_into_const(node, Ast_Builtin, v);
|
||||||
Ast_Call_Item *arg = node->exprs[0];
|
return operand_const_rvalue(v);
|
||||||
if(arg->name || arg->index) compiler_error(node->pos, "No named or indexed arguments expected");
|
BREAK();
|
||||||
Operand op = resolve_expr(arg->item, AST_CANT_BE_NULL);
|
}
|
||||||
ident->type = op.type;
|
|
||||||
|
|
||||||
if(is_array(op.type)){
|
CASE(SIZE_OF, Builtin){
|
||||||
Value val = value_int(op.type->arr.size);
|
Operand name = resolve_expr(node->expr, AST_CANT_BE_NULL);
|
||||||
rewrite_into_const(node, Ast_Call, val);
|
if(!name.is_const) compiler_error(node->pos, "size_of requires a constant value");
|
||||||
return operand_const_rvalue(val);
|
Ast_Type *type = name.type == type_type ? name.type_val : name.type;
|
||||||
} else if(is_slice(op.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);
|
return operand_rvalue(type_s64);
|
||||||
} else compiler_error(node->pos, "Invalid argument");
|
|
||||||
}
|
}
|
||||||
|
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);
|
Operand name = resolve_expr(node->name, AST_CANT_BE_NULL);
|
||||||
if(name.type->kind != TYPE_LAMBDA)
|
if(name.type->kind != TYPE_LAMBDA)
|
||||||
compiler_error(node->pos, "Calling %s which is not a [Lambda]", docname(name.type));
|
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){
|
if(item){
|
||||||
set_flag(item->flags, AST_ITEM_INCLUDED);
|
set_flag(item->flags, AST_ITEM_INCLUDED);
|
||||||
Operand expr = resolve_expr(item->item, AST_CANT_BE_NULL, lambda_arg->type);
|
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);
|
items.add(item);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ type_array(Ast_Type *base, S64 size){
|
|||||||
return result;
|
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.base = base;
|
||||||
result->arr.size = size;
|
result->arr.size = size;
|
||||||
result->arr.slice_hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE));
|
result->arr.slice_hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE));
|
||||||
|
|||||||
Reference in New Issue
Block a user