diff --git a/main.cpp b/main.cpp index b65d45e..14fe87e 100644 --- a/main.cpp +++ b/main.cpp @@ -32,6 +32,7 @@ For now I don't thing it should be overloadable. ------------------------------------------------------------------------------- @todo +[ ] - Test new operators, add constant eval for them [ ] - Compiling and running a program [ ] - Passing down program to compile through command line [ ] - More operators @@ -39,15 +40,21 @@ For now I don't thing it should be overloadable. [ ] - 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 [ ] - Write up on order independent declarations -[ ] - Order independent declarations in structs [ ] - Switch [ ] - More basic types [ ] - Array of inferred size [ ] - Add single line lambda expressions +[ ] - Ternary operator +[ ] - Constants embeded in structs should be able to refer to other constants in that namespace without prefix +[ ] - Order independent constants in structs +[ ] - Can you even have recursive lambdas in structs, other recursive stuff +[ ] - Casting to basic types by call S64(x) +[ ] - Type aliases :: should probably be strictly typed, but assigning constant values should work @ideas [ ] - [Using] keyword that brings in the struct enviroment into current scope etc. [ ] - Constant arrays that evaluate fully at compile time +[ ] - Rust like enum where you associate values(other structs) with keys @donzo [x] - lvalue, rvalue concept so we cant assign value to some arbitrary weird expression @@ -78,10 +85,6 @@ For now I don't thing it should be overloadable. #include "typecheck.h" #include "typecheck.cpp" #include "ccodegen.cpp" - - - - int main(){ test_os_memory(); @@ -102,17 +105,17 @@ int main(){ printf("%s", result.str); result = compile_file("order1.kl"_s); printf("%s", result.str); - result = compile_file("order2.kl"_s); - printf("%s", result.str); result = compile_file("lambdas.kl"_s); printf("%s", result.str); + result = compile_file("order2.kl"_s); + printf("%s", result.str); #endif - result = compile_file("lexer.kl"_s); - FILE *f = fopen("program.c", "w"); - assert(f); - fprintf(f, "%.*s", (int)result.len, result.str); - fclose(f); + // result = compile_file("lexer.kl"_s); + // FILE *f = fopen("program.c", "w"); + // assert(f); + // fprintf(f, "%.*s", (int)result.len, result.str); + // fclose(f); - // __debugbreak(); + __debugbreak(); } diff --git a/new_lex.cpp b/new_lex.cpp index c9ac720..ed1f095 100644 --- a/new_lex.cpp +++ b/new_lex.cpp @@ -134,6 +134,10 @@ struct Lexer{ force_inline B32 token_is_assign(Token_Kind token){return token >= TK_FirstAssign && token <= TK_LastAssign;} force_inline B32 token_is_assign(Token *token){return token_is_assign(token->kind);} +force_inline B32 token_is_compare(Token_Kind token){return token >= TK_FirstCompare && token <= TK_LastCompare;} +force_inline B32 token_is_compare(Token *token){return token_is_compare(token->kind);} + + function U8 lexc(Lex_Stream *s){ diff --git a/new_parse.cpp b/new_parse.cpp index fa6a268..2f8db87 100644 --- a/new_parse.cpp +++ b/new_parse.cpp @@ -110,41 +110,7 @@ token_expect(Token_Kind kind){ return 0; } -//----------------------------------------------------------------------------- -// Expression parsing -//----------------------------------------------------------------------------- -/* -add = [+-] -mul = [/%*] -compare = == | != | >= | > | <= | < -logical = [&|^] | && | || -unary = [&*-!~+] | ++ | -- - -atom_expr = Int -| Float -| String -| Identifier -| 'cast' '(' typespec ',' expr ')' -| 'size_type' '(' typespec ')' -| 'size_expr' '(' expr ')' -| '{' call_expr '}' -| '(' expr ')' -| '(' ':' typespec ')' '{' call_expr '}' -postfix_expr = atom_expr ('[' expr ']' | '.' Identifier | ++ | -- | '(' expr_list ')')* -unary_expr = unary ? unary_expr : atom_expr -mul_expr = atom_expr (mul atom_expr)* -add_expr = mul_expr (add mul_expr)* -logical_expr = add_expr (logical add_expr)* -compare_expr = logical_expr (compare logical_expr)* -ternary_expr = compare_expr ('?' ternary_expr ':' ternary_expr)? -expr = logical_expr - -Compound literals -- (:[23]*Type){} - - Type{} -- { } -*/ -function Ast_Expr *parse_expr(S64 rbp = 0); +function Ast_Expr *parse_expr(S64 minbp = 0); function Ast_Expr * parse_init_stmt(Ast_Expr *expr){ diff --git a/order2.kl b/order2.kl index 43cb604..5c5738f 100644 --- a/order2.kl +++ b/order2.kl @@ -56,6 +56,9 @@ test_assignments :: () i >>= 2 i <<= 2 + i = i > 2 + CONST :: 23 == 23 + j: *int *j = 1 /* invalid diff --git a/typecheck.cpp b/typecheck.cpp index 2fa0d27..6caa121 100644 --- a/typecheck.cpp +++ b/typecheck.cpp @@ -23,7 +23,14 @@ resolve_type_pair(Token *pos, Ast_Resolved_Type *a, Ast_Resolved_Type *b){ } if(result->kind == TYPE_NULL) parsing_error(pos, "Couldn't infer type of null value"); + return result; +} +function Operand +resolve_operand_pair(Token *pos, Operand a, Operand b){ + Operand result = {}; + result.is_const = a.is_const && b.is_const; + result.type = resolve_type_pair(pos, a.type, b.type); return result; } @@ -400,112 +407,142 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res CASE(BINARY, Binary){ Operand result = {}; - switch(node->op){ - case TK_ColonAssign:{ - // @note: This is actually a statement so it doesn't need to return Operand - assert(is_flag_set(node->flags, AST_STMT)); - assert(node->left->kind == AST_IDENT); + if(node->op == TK_ColonAssign){ + // @note: This is actually a statement so it doesn't need to return Operand + assert(is_flag_set(node->flags, AST_STMT)); + assert(node->left->kind == AST_IDENT); - Operand right = resolve_expr(node->right); - Ast_Atom *atom = (Ast_Atom *)node->left; - sym_insert(SYM_VAR, atom->intern_val, right.type, right.value, node); - }break; - case TK_Dot: { - B32 required_to_be_const = false; - // @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); - Ast_Resolved_Type *type = resolved_ident.type; - if(type == type_type){ - type = resolved_ident.type_val; - required_to_be_const = true; - } + Operand right = resolve_expr(node->right); + Ast_Atom *atom = (Ast_Atom *)node->left; + sym_insert(SYM_VAR, atom->intern_val, right.type, right.value, node); + } + + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + else if(node->op == TK_Dot){ + B32 required_to_be_const = false; + // @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); + Ast_Resolved_Type *type = resolved_ident.type; + if(type == type_type){ + type = resolved_ident.type_val; + required_to_be_const = true; + } + // @copy_paste + if(is_pointer(type)) type = type->base; + type_complete(type); + if(!(is_struct(type) || is_enum(type))) parsing_error(node->pos, "Trying to access inside a value that is not a struct or enum"); + sym_new_resolved(SYM_VAR, {}, resolved_ident.type, {}, node->left); + + // This happens only on binary nodes which further chain with dots and require lookups + // This part cant happen on enums + // 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); + if(query){ + Sym *sym = resolved_get(query); + if(required_to_be_const && sym->kind != SYM_CONST) parsing_error(ident->pos, "Required to be constant"); + type = sym->type; // @copy_paste - if(is_pointer(type)) type = type->base; - type_complete(type); - if(!(is_struct(type) || is_enum(type))) parsing_error(node->pos, "Trying to access inside a value that is not a struct or enum"); - sym_new_resolved(SYM_VAR, {}, resolved_ident.type, {}, node->left); - - // This happens only on binary nodes which further chain with dots and require lookups - // This part cant happen on enums - // 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); - if(query){ - Sym *sym = resolved_get(query); - if(required_to_be_const && sym->kind != SYM_CONST) parsing_error(ident->pos, "Required to be constant"); - type = sym->type; - // @copy_paste - if(type == type_type){ - required_to_be_const = true; - type = sym->type_val; - } - if(is_pointer(type)) type = type->base; - type_complete(type); - if(!(is_struct(type) || is_enum(type))) parsing_error(node->pos, "Trying to access inside a value that is not a struct or enum"); - sym_associate(ident, sym); - - } 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; - if(is_enum(type)){ - Ast_Enum *enu = (Ast_Enum *)type->ast; - Ast_Enum_Member *query = query_enum(enu, ident->intern_val); - if(query){ - Sym *resolved = resolved_get(query); - assert(resolved); - rewrite_into_const(node, Ast_Binary, resolved); - result = operand(resolved); + if(type == type_type){ + required_to_be_const = true; + type = sym->type_val; } - } - else if(is_struct(type)){ - Ast_Struct *agg = (Ast_Struct *)type->ast; - Ast *query = query_struct(agg, ident->intern_val); - if(query){ - Sym *sym = resolved_get(query); - result = operand(sym); - assert(sym); - if(sym->kind == SYM_CONST) rewrite_into_const(node, Ast_Binary, sym); - else sym_associate(ident, sym); + if(is_pointer(type)) type = type->base; + type_complete(type); + if(!(is_struct(type) || is_enum(type))) parsing_error(node->pos, "Trying to access inside a value that is not a struct or enum"); + sym_associate(ident, sym); - } else parsing_error(ident->pos, "No such member in struct"); - } - else parsing_error(ident->pos, "Trying to [.] access a value that is not [Enum] or [Struct]"); + } else parsing_error(ident->pos, "No such member in struct"); + } - if(result.is_const == false && required_to_be_const){ - invalid_codepath; + // 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; + if(is_enum(type)){ + Ast_Enum *enu = (Ast_Enum *)type->ast; + Ast_Enum_Member *query = query_enum(enu, ident->intern_val); + if(query){ + Sym *resolved = resolved_get(query); + assert(resolved); + rewrite_into_const(node, Ast_Binary, resolved); + result = operand(resolved); } - } break; - default: { - 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]); - }break; + } + else if(is_struct(type)){ + Ast_Struct *agg = (Ast_Struct *)type->ast; + Ast *query = query_struct(agg, ident->intern_val); + if(query){ + Sym *sym = resolved_get(query); + result = operand(sym); + assert(sym); + if(sym->kind == SYM_CONST) rewrite_into_const(node, Ast_Binary, sym); + else sym_associate(ident, sym); + + } else parsing_error(ident->pos, "No such member in struct"); + } + else parsing_error(ident->pos, "Trying to [.] access a value that is not [Enum] or [Struct]"); + + if(result.is_const == false && required_to_be_const){ + invalid_codepath; } } + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + else if(token_is_compare(node->op)){ + Operand left = resolve_expr(node->left); + Operand right = resolve_expr(node->right); + result = resolve_operand_pair(node->pos, left, right); + if(result.is_const){ + if(result.type == type_int){ + switch(node->op){ + case TK_GreaterThen : result.bool_val = left.int_val > right.int_val; break; + case TK_GreaterThenOrEqual: result.bool_val = left.int_val >= right.int_val; break; + case TK_LesserThen : result.bool_val = left.int_val < right.int_val; break; + case TK_LesserThenOrEqual : result.bool_val = left.int_val <= right.int_val; break; + case TK_Equals : result.bool_val = left.int_val == right.int_val; break; + case TK_NotEquals : result.bool_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]); + } + + } + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + else{ + Operand left = resolve_expr(node->left); + Operand right = resolve_expr(node->right); + result = resolve_operand_pair(node->pos, left, right); + if(result.is_const){ + 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(); @@ -514,7 +551,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res invalid_default_case; } - return {}; + invalid_return; } function Operand diff --git a/typecheck.h b/typecheck.h index 76388f1..1e91482 100644 --- a/typecheck.h +++ b/typecheck.h @@ -6,6 +6,9 @@ enum Ast_Resolved_Type_Kind{ TYPE_NULL, TYPE_COMPLETING, TYPE_INCOMPLETE, + TYPE_UNTYPED_BOOL, + TYPE_UNTYPED_INT, + TYPE_UNTYPED_STRING, TYPE_INT, TYPE_BOOL, TYPE_UNSIGNED, @@ -25,6 +28,9 @@ const char *type_names[] = { "[Null]", "[Completing]", "[Incomplete]", + "[Untyped_Bool]", + "[Untyped_Int]", + "[Untyped_String]", "[Int]", "[Bool]", "[Unsigned]", @@ -75,7 +81,6 @@ 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}; @@ -83,11 +88,18 @@ 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; +global Ast_Resolved_Type type__untyped_bool = {TYPE_UNTYPED_BOOL, sizeof(bool), __alignof(bool)}; +global Ast_Resolved_Type type__untyped_int = {TYPE_UNTYPED_INT, sizeof(S64), __alignof(S64)}; +global Ast_Resolved_Type type__untyped_string = {TYPE_UNTYPED_STRING, sizeof(String), __alignof(String)}; + +global Ast_Resolved_Type *type_untyped_string = &type__untyped_string; +global Ast_Resolved_Type *type_untyped_bool = &type__untyped_bool; +global Ast_Resolved_Type *type_untyped_int = &type__untyped_int; + //----------------------------------------------------------------------------- // Symbols //----------------------------------------------------------------------------- @@ -103,9 +115,10 @@ enum Sym_State{ SYM_RESOLVED, }; -#define VALUE_FIELDS \ - S64 int_val; \ - Intern_String intern_val; \ +#define VALUE_FIELDS \ + bool bool_val; \ + 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};