diff --git a/ccodegen.cpp b/ccodegen.cpp index 3ca799b..e3f1ad8 100644 --- a/ccodegen.cpp +++ b/ccodegen.cpp @@ -28,6 +28,7 @@ gen_simple_decl_prefix(Ast_Resolved_Type *ast){ case TYPE_POINTER:{gen_simple_decl_prefix(ast->base); gen("*");} break; case TYPE_ARRAY: gen_simple_decl_prefix(ast->base); break; case TYPE_LAMBDA:break; + case TYPE_ENUM: case TYPE_STRUCT: { auto constant = (Ast_Const *)ast->ast->parent; auto name = constant->name; @@ -48,7 +49,7 @@ gen_simple_decl_postfix(Ast_Resolved_Type *ast){ case TYPE_POINTER: gen_simple_decl_postfix(ast->base); break; case TYPE_ARRAY: gen("[%d]", (int)ast->arr.size); gen_simple_decl_postfix(ast->arr.base); break; case TYPE_LAMBDA:break; - case TYPE_STRUCT:break; + case TYPE_ENUM: case TYPE_STRUCT:break; invalid_default_case; } } @@ -323,7 +324,28 @@ gen_ast(Ast *ast){ genln("};"); } else{ - // type alias + // Type alias + } + } + else if(sym->type_val->kind == TYPE_ENUM){ + Ast_Enum *enu = (Ast_Enum *)sym->type_val->ast; + assert(enu->kind == AST_ENUM); + if(node->value->kind == AST_ENUM){ + gen("enum %s{", node->name.str); + // @todo add typespec + global_indent++; + For(enu->members){ + genln("%s", it->name.str); + gen(" = "); + Sym *value_sym = resolved_get(it); + gen("%d", value_sym->int_val); + gen(","); + } + global_indent--; + genln("};"); + } + else{ + // Type alias } } else{ diff --git a/enums.kl b/enums.kl new file mode 100644 index 0000000..8678ad0 --- /dev/null +++ b/enums.kl @@ -0,0 +1,5 @@ + +Allocator_Kind :: enum + Null + Arena + Heap = Arena diff --git a/main.cpp b/main.cpp index e1df43c..afdfee7 100644 --- a/main.cpp +++ b/main.cpp @@ -7,6 +7,8 @@ #include "ccodegen.cpp" /* +------------------------------------------------------------------------------- + 2022.05.28 - On lambda expressions I think it's not wise to add the multiline lambda expressions As is the case with python it would require new alternative syntax. @@ -18,12 +20,14 @@ in a language to solve something that is a minor inconvenience, second of all it turned out to be kind of bad, maybe if it would be more complicated then it would be ok but it implies that you have to semicolon end a lot of thing unintuitively. -// + Probably single line lambdas should be ok. Currently braces turn off indentation awareness. There might be something you can do by trying to turn that on problem is that complicates parsing a lot cause you have to account for multiple indent styles, which means error messages become bad. +------------------------------------------------------------------------------- + 2022.05.30 - On constructors and compound expressions I unified the compound expression syntax (Type){} with function call syntax Type(). It's differentiating on whether you used type. I think there is a benefit to the language @@ -33,6 +37,7 @@ and variants. having the idea of compounds doing one thing is reassuring I think You can always do a constructor by writing a function with lower case type if you want that. For now I don't thing it should be overloadable. +------------------------------------------------------------------------------- @todo [ ] - Enums @@ -40,11 +45,13 @@ 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 [ ] - Access through struct names to constants Arena.CONSTANT [ ] - Default values in structs??? Should compound stmts bring values from default values?? Maybe not? Whats the alternative +[ ] - Write up on order independent declarations [ ] - For loop [ ] - Switch [ ] - Lexer: Need to insert scope endings when hitting End of file [ ] - Add single line lambda expressions + @donzo [x] - Struct calls [x] - Default values in calls @@ -76,7 +83,8 @@ int main(){ String result = {}; // result = compile_file("order1.kl"_s); // result = compile_file("lambdas.kl"_s); - result = compile_file("order2.kl"_s); + // result = compile_file("order2.kl"_s); + result = compile_file("enums.kl"_s); // result = compile_file("globals.kl"_s); printf("%s", result.str); diff --git a/new_ast.cpp b/new_ast.cpp index 8e6754e..6b08660 100644 --- a/new_ast.cpp +++ b/new_ast.cpp @@ -100,6 +100,8 @@ enum Ast_Kind: U32{ AST_BLOCK, AST_LAMBDA, AST_LAMBDA_ARG, + AST_ENUM, + AST_ENUM_MEMBER, AST_STRUCT, AST_CONST, AST_VAR, @@ -112,7 +114,8 @@ enum{ AST_BINDING = 4, AST_AGGREGATE = 8, AST_ATOM = 16, - AST_ITEM_INCLUDED = 32, + AST_AGGREGATE_CHILD = 32, + AST_ITEM_INCLUDED = 64, }; struct Ast{ @@ -191,11 +194,6 @@ struct Ast_If: Ast{ Array ifs; }; -struct Ast_Enum : Ast{ - Ast_Expr *typespec; - Array children; -}; - struct Ast_Lambda_Arg: Ast_Expr{ Intern_String name; Ast_Expr *typespec; @@ -224,18 +222,29 @@ struct Ast_Var: Ast_Named{ struct Ast_Const; struct Ast_Resolved_Type; -struct Ast_Struct: Ast_Expr{ +struct Ast_Struct: Ast{ // Required to be Ast_Struct or Ast_Var or Ast_Const Array members; Array const_members; Ast_Resolved_Type *type; }; +struct Ast_Enum_Member: Ast{ + Intern_String name; + Ast_Expr *value; +}; + +struct Ast_Enum: Ast{ + Ast_Expr *typespec; + Array members; +}; + struct Ast_Const: Ast_Named{ union{ Ast *ast; Ast_Expr *value; Ast_Struct *agg; + Ast_Enum *enu; }; }; @@ -421,12 +430,32 @@ ast_init(Token *pos, Token_Kind op, Ast_Atom *ident, Ast_Expr *expr){ function Ast_Array * ast_array(Token *pos, Ast_Expr *expr){ AST_NEW(Array, ARRAY, pos, AST_EXPR); - result->flags = AST_EXPR; result->expr = expr; result->expr->parent = result; return result; } +function Ast_Enum_Member * +ast_enum_member(Token *pos, Intern_String name, Ast_Expr *default_value){ + AST_NEW(Enum_Member, ENUM_MEMBER, pos, AST_AGGREGATE_CHILD); + result->name = name; + result->value = default_value; + if(result->value) result->value->parent = result; + return result; +} + +function Ast_Enum * +ast_enum(Token *pos, Ast_Expr *typespec, Array members){ + AST_NEW(Enum, ENUM, pos, AST_AGGREGATE); + result->members = members.tight_copy(pctx->perm); + result->typespec = typespec; + if(result->typespec) result->typespec->parent = result; + For(result->members){ + it->parent = result; + } + return result; +} + function Ast_Struct * ast_struct(Token *pos, Array members, Array const_members){ AST_NEW(Struct, STRUCT, pos, AST_AGGREGATE); @@ -461,9 +490,8 @@ ast_var(Token *pos, Ast_Expr *typespec, Intern_String name, Ast_Expr *expr){ function Ast_Const * ast_const(Token *pos, Intern_String name, Ast_Expr *value){ + assert(is_flag_set(value->flags, AST_AGGREGATE) || is_flag_set(value->flags, AST_EXPR) ); AST_NEW(Const, CONST, pos, AST_BINDING); - - assert(value->kind == AST_STRUCT || is_flag_set(value->flags, AST_EXPR)); result->value = value; result->name = name; result->value->parent = result; diff --git a/new_parse.cpp b/new_parse.cpp index b71d60a..e94a389 100644 --- a/new_parse.cpp +++ b/new_parse.cpp @@ -419,6 +419,7 @@ parse_struct(Token *pos){ do{ Token *token = token_get(); Ast_Named *named = parse_named(false); + named->flags = set_flag(named->flags, AST_AGGREGATE_CHILD); if(!named) parsing_error(token, "Failed to parse struct member"); if(named->kind == AST_CONST){ members_const.add((Ast_Const *)named); @@ -434,6 +435,25 @@ parse_struct(Token *pos){ return result; } +function Ast_Enum * +parse_enum(Token *pos){ + Scratch scratch; + Array members = {scratch}; + Ast_Expr *typespec = parse_optional_type(); + + token_match(OPEN_SCOPE); + do{ + Token *name = token_expect(TK_Identifier); + Ast_Expr *value = parse_assign_expr(); + Ast_Enum_Member *member = ast_enum_member(name, name->intern_val, value); + members.add(member); + }while(token_match(SAME_SCOPE)); + token_expect(CLOSE_SCOPE); + + Ast_Enum *result = ast_enum(pos, typespec, members); + return result; +} + function Ast_Named * parse_named(B32 is_global){ Ast_Named *result = 0; @@ -448,7 +468,12 @@ parse_named(B32 is_global){ Token *struct_pos = token_get(); if(token_match_keyword(keyword_struct)){ Ast_Struct *struct_val = parse_struct(struct_pos); - result = ast_const(name, name->intern_val, struct_val); + result = ast_const(name, name->intern_val, (Ast_Expr *)struct_val); + } + + else if(token_match_keyword(keyword_enum)){ + Ast_Enum *enum_val = parse_enum(struct_pos); + result = ast_const(name, name->intern_val, (Ast_Expr *)enum_val); } // parse constant expression diff --git a/new_type.cpp b/new_type.cpp index 9eadbb9..3cf1404 100644 --- a/new_type.cpp +++ b/new_type.cpp @@ -163,6 +163,19 @@ type_lambda(Ast *ast, Ast_Resolved_Type *ret, Array args){ return result; } +function Ast_Resolved_Type * +type_enum(Ast_Enum *ast){ + Ast_Resolved_Type *type = resolve_typespec(ast->typespec, AST_CAN_BE_NULL); + if(!type) { + type = type_int; + } + + Ast_Resolved_Type *result = type_new(pctx->perm, TYPE_ENUM, type->size, type->align); + result->base = type; + result->ast = ast; + return result; +} + function Ast_Resolved_Type * type_incomplete(Ast *ast){ Ast_Resolved_Type *result = type_new(pctx->perm, TYPE_INCOMPLETE, 0, 0); diff --git a/order2.kl b/order2.kl index 9ff8c1b..a9778cb 100644 --- a/order2.kl +++ b/order2.kl @@ -11,6 +11,9 @@ arena := Arena( // constant_inside = 10, ) +// lambda_value := (val: int) // What to do with this??? + // return + Arena :: struct // arena: Arena next: *Arena diff --git a/typechecking.cpp b/typechecking.cpp index 8079a86..c0b678a 100644 --- a/typechecking.cpp +++ b/typechecking.cpp @@ -42,12 +42,13 @@ enum{ AST_CAN_BE_NULL = 1 }; -struct Typecheck_Ctx{ +struct Typecheck_Ctx{ // @todo Ast_Resolved_Type *required_type; Sym *const_sym; B32 expr_can_be_null; }; +function Ast_Resolved_Type *resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null = AST_CANT_BE_NULL); function Sym *resolve_name(Token *pos, Intern_String name); function Operand resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *compound_required_type = 0, Sym *const_sym = 0); function Operand resolve_binding(Ast *ast, Sym *sym = 0); @@ -166,7 +167,7 @@ sym_insert_builtins(){ } function Ast_Resolved_Type * -resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null = AST_CANT_BE_NULL){ +resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null){ if(ast_can_be_null && ast == 0) return 0; Operand resolved = resolve_expr(ast); if(resolved.type != type_type) parsing_error(ast->pos, "Expected [Type] got instead %s", resolved.type->kind); @@ -255,6 +256,27 @@ operand(Sym *sym){ return result; } +function Operand +operand_type(Ast_Resolved_Type *type){ + Operand result = {type_type, true}; + result.type_val = type; + return result; +} + +function Operand +require_const_int(Ast_Expr *expr, B32 ast_can_be_null){ + Operand op = resolve_expr(expr); + if(expr == 0 && ast_can_be_null){ + return op; + } + else if(expr == 0) parsing_error(expr->pos, "This field cannot be null"); + + if(!op.is_const) parsing_error(expr->pos, "Expected a const value"); + if(op.type != type_int) parsing_error(expr->pos, "Expected a constant integer"); + + return op; +} + function Operand resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *const_sym){ if(!ast) return {}; // @todo: add option for better error prevention @@ -308,6 +330,31 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *const_sym){ BREAK(); } + CASE(ENUM, Enum){ + Ast_Resolved_Type *type = type_enum(node); + + S64 scope_index = scope_open(); + S64 value = 0; + For(node->members){ + Operand op = require_const_int(it->value, AST_CAN_BE_NULL); + if(op.type){ + value = op.int_val + 1; + } + else{ + op.type = type_int; + op.int_val = value++; + } + + + Sym *arg_sym = sym_new_resolved(SYM_CONST, it->name, op.type, op.value, it); + sym_insert(arg_sym); + } + scope_close(scope_index); + + return operand_type(type); + BREAK(); + } + CASE(LAMBDA, Lambda){ // @note: first resolve type of lambda Scratch scratch;