| author | |
| committer | |
| log | f6eecfe5f486b250de33a8129b1c85198be43280 |
| tree | 2cef7045ade894407c6b6d99e6daa5c86a9a496b |
| parent | 94e61287e708f61d2a9d814bfe7910d13e067ada |
11 files changed, 116 insertions(+), 21 deletions(-)
README.md+4-2| ... | ... | @@ -144,9 +144,11 @@ ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen) |
| 144 | 144 | |
| 145 | 145 | ParamDecl : token(Symbol) token(Colon) Type |
| 146 | 146 | |
| 147 | Type : token(Symbol) | PointerType | token(Unreachable) | |
| 147 | Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | |
| 148 | 148 | |
| 149 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type | |
| 149 | PointerType : token(Star) (token(Const) | token(Mut)) Type | |
| 150 | ||
| 151 | ArrayType : token(LBracket) Type token(Semicolon) Expression token(RBracket) | |
| 150 | 152 | |
| 151 | 153 | Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace) |
| 152 | 154 |
src/analyze.cpp+52-3| ... | ... | @@ -48,18 +48,23 @@ static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) |
| 48 | 48 | } |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | TypeTableEntry *new_type_table_entry() { | |
| 52 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | |
| 53 | entry->arrays_by_size.init(2); | |
| 54 | return entry; | |
| 55 | } | |
| 56 | ||
| 51 | 57 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { |
| 52 | 58 | TypeTableEntry **parent_pointer = is_const ? |
| 53 | 59 | &child_type->pointer_const_parent : |
| 54 | 60 | &child_type->pointer_mut_parent; |
| 55 | const char *const_or_mut_str = is_const ? "const" : "mut"; | |
| 56 | 61 | if (*parent_pointer) { |
| 57 | 62 | return *parent_pointer; |
| 58 | 63 | } else { |
| 59 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | |
| 64 | TypeTableEntry *entry = new_type_table_entry(); | |
| 60 | 65 | entry->type_ref = LLVMPointerType(child_type->type_ref, 0); |
| 61 | 66 | buf_resize(&entry->name, 0); |
| 62 | buf_appendf(&entry->name, "*%s %s", const_or_mut_str, buf_ptr(&child_type->name)); | |
| 67 | buf_appendf(&entry->name, "*%s %s", is_const ? "const" : "mut", buf_ptr(&child_type->name)); | |
| 63 | 68 | entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type, |
| 64 | 69 | g->pointer_size_bytes * 8, g->pointer_size_bytes * 8, buf_ptr(&entry->name)); |
| 65 | 70 | g->type_table.put(&entry->name, entry); |
| ... | ... | @@ -68,6 +73,28 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool |
| 68 | 73 | } |
| 69 | 74 | } |
| 70 | 75 | |
| 76 | static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, int array_size) { | |
| 77 | auto existing_entry = child_type->arrays_by_size.maybe_get(array_size); | |
| 78 | if (existing_entry) { | |
| 79 | return existing_entry->value; | |
| 80 | } else { | |
| 81 | TypeTableEntry *entry = new_type_table_entry(); | |
| 82 | entry->type_ref = LLVMArrayType(child_type->type_ref, array_size); | |
| 83 | buf_resize(&entry->name, 0); | |
| 84 | buf_appendf(&entry->name, "[%s; %ud]", buf_ptr(&child_type->name), array_size); | |
| 85 | //entry->di_type = LLVMZigCreateDebugArrayType(g->dbuilder, ..., buf_ptr(&entry->name)); // TODO | |
| 86 | ||
| 87 | g->type_table.put(&entry->name, entry); | |
| 88 | child_type->arrays_by_size.put(array_size, entry); | |
| 89 | return entry; | |
| 90 | } | |
| 91 | } | |
| 92 | ||
| 93 | static int parse_int(Buf *number) { | |
| 94 | // TODO: think about integer size of array sizes | |
| 95 | return atoi(buf_ptr(number)); | |
| 96 | } | |
| 97 | ||
| 71 | 98 | static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { |
| 72 | 99 | assert(node->type == NodeTypeType); |
| 73 | 100 | assert(!node->codegen_node); |
| ... | ... | @@ -98,6 +125,28 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { |
| 98 | 125 | type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const); |
| 99 | 126 | return type_node->entry; |
| 100 | 127 | } |
| 128 | case AstNodeTypeTypeArray: | |
| 129 | { | |
| 130 | resolve_type(g, node->data.type.child_type); | |
| 131 | TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; | |
| 132 | if (child_type == g->builtin_types.entry_unreachable) { | |
| 133 | add_node_error(g, node, | |
| 134 | buf_create_from_str("array of unreachable not allowed")); | |
| 135 | } | |
| 136 | ||
| 137 | AstNode *size_node = node->data.type.array_size; | |
| 138 | int size; // TODO: think about integer size of array sizes | |
| 139 | if (size_node->type != NodeTypeNumberLiteral) { | |
| 140 | add_node_error(g, size_node, | |
| 141 | buf_create_from_str("array size must be literal number")); | |
| 142 | size = -1; | |
| 143 | } else { | |
| 144 | size = parse_int(&size_node->data.number); | |
| 145 | } | |
| 146 | ||
| 147 | type_node->entry = get_array_type(g, child_type, size); // TODO | |
| 148 | return type_node->entry; | |
| 149 | } | |
| 101 | 150 | } |
| 102 | 151 | zig_unreachable(); |
| 103 | 152 | } |
src/analyze.hpp+1| ... | ... | @@ -18,6 +18,7 @@ struct BlockContext; |
| 18 | 18 | |
| 19 | 19 | void semantic_analyze(CodeGen *g); |
| 20 | 20 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg); |
| 21 | TypeTableEntry *new_type_table_entry(); | |
| 21 | 22 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); |
| 22 | 23 | LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name); |
| 23 | 24 |
src/codegen.cpp+6-6| ... | ... | @@ -781,12 +781,12 @@ static void do_code_gen(CodeGen *g) { |
| 781 | 781 | static void define_primitive_types(CodeGen *g) { |
| 782 | 782 | { |
| 783 | 783 | // if this type is anywhere in the AST, we should never hit codegen. |
| 784 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | |
| 784 | TypeTableEntry *entry = new_type_table_entry(); | |
| 785 | 785 | buf_init_from_str(&entry->name, "(invalid)"); |
| 786 | 786 | g->builtin_types.entry_invalid = entry; |
| 787 | 787 | } |
| 788 | 788 | { |
| 789 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | |
| 789 | TypeTableEntry *entry = new_type_table_entry(); | |
| 790 | 790 | entry->type_ref = LLVMInt1Type(); |
| 791 | 791 | buf_init_from_str(&entry->name, "bool"); |
| 792 | 792 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 1, 8, |
| ... | ... | @@ -795,7 +795,7 @@ static void define_primitive_types(CodeGen *g) { |
| 795 | 795 | g->builtin_types.entry_bool = entry; |
| 796 | 796 | } |
| 797 | 797 | { |
| 798 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | |
| 798 | TypeTableEntry *entry = new_type_table_entry(); | |
| 799 | 799 | entry->type_ref = LLVMInt8Type(); |
| 800 | 800 | buf_init_from_str(&entry->name, "u8"); |
| 801 | 801 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8, |
| ... | ... | @@ -805,7 +805,7 @@ static void define_primitive_types(CodeGen *g) { |
| 805 | 805 | } |
| 806 | 806 | g->builtin_types.entry_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true); |
| 807 | 807 | { |
| 808 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | |
| 808 | TypeTableEntry *entry = new_type_table_entry(); | |
| 809 | 809 | entry->type_ref = LLVMInt32Type(); |
| 810 | 810 | buf_init_from_str(&entry->name, "i32"); |
| 811 | 811 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32, |
| ... | ... | @@ -814,7 +814,7 @@ static void define_primitive_types(CodeGen *g) { |
| 814 | 814 | g->builtin_types.entry_i32 = entry; |
| 815 | 815 | } |
| 816 | 816 | { |
| 817 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | |
| 817 | TypeTableEntry *entry = new_type_table_entry(); | |
| 818 | 818 | entry->type_ref = LLVMVoidType(); |
| 819 | 819 | buf_init_from_str(&entry->name, "void"); |
| 820 | 820 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0, |
| ... | ... | @@ -823,7 +823,7 @@ static void define_primitive_types(CodeGen *g) { |
| 823 | 823 | g->builtin_types.entry_void = entry; |
| 824 | 824 | } |
| 825 | 825 | { |
| 826 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | |
| 826 | TypeTableEntry *entry = new_type_table_entry(); | |
| 827 | 827 | entry->type_ref = LLVMVoidType(); |
| 828 | 828 | buf_init_from_str(&entry->name, "unreachable"); |
| 829 | 829 | entry->di_type = g->builtin_types.entry_void->di_type; |
src/parser.cpp+25-10| ... | ... | @@ -180,6 +180,13 @@ void ast_print(AstNode *node, int indent) { |
| 180 | 180 | ast_print(node->data.type.child_type, indent + 2); |
| 181 | 181 | break; |
| 182 | 182 | } |
| 183 | case AstNodeTypeTypeArray: | |
| 184 | { | |
| 185 | fprintf(stderr, "ArrayType\n"); | |
| 186 | ast_print(node->data.type.child_type, indent + 2); | |
| 187 | ast_print(node->data.type.array_size, indent + 2); | |
| 188 | break; | |
| 189 | } | |
| 183 | 190 | } |
| 184 | 191 | break; |
| 185 | 192 | case NodeTypeReturnExpr: |
| ... | ... | @@ -448,8 +455,9 @@ static void ast_parse_directives(ParseContext *pc, int *token_index, |
| 448 | 455 | |
| 449 | 456 | |
| 450 | 457 | /* |
| 451 | Type : token(Symbol) | PointerType | token(Unreachable) | |
| 452 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type; | |
| 458 | Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | |
| 459 | PointerType : token(Star) (token(Const) | token(Mut)) Type | |
| 460 | ArrayType : token(LBracket) Type token(Semicolon) token(Number) token(RBracket) | |
| 453 | 461 | */ |
| 454 | 462 | static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token_index) { |
| 455 | 463 | Token *token = &pc->tokens->at(token_index); |
| ... | ... | @@ -463,12 +471,6 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token |
| 463 | 471 | } else if (token->id == TokenIdKeywordVoid) { |
| 464 | 472 | node->data.type.type = AstNodeTypeTypePrimitive; |
| 465 | 473 | buf_init_from_str(&node->data.type.primitive_name, "void"); |
| 466 | } else if (token->id == TokenIdKeywordTrue) { | |
| 467 | node->data.type.type = AstNodeTypeTypePrimitive; | |
| 468 | buf_init_from_str(&node->data.type.primitive_name, "true"); | |
| 469 | } else if (token->id == TokenIdKeywordFalse) { | |
| 470 | node->data.type.type = AstNodeTypeTypePrimitive; | |
| 471 | buf_init_from_str(&node->data.type.primitive_name, "false"); | |
| 472 | 474 | } else if (token->id == TokenIdSymbol) { |
| 473 | 475 | node->data.type.type = AstNodeTypeTypePrimitive; |
| 474 | 476 | ast_buf_from_token(pc, token, &node->data.type.primitive_name); |
| ... | ... | @@ -485,6 +487,20 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token |
| 485 | 487 | } |
| 486 | 488 | |
| 487 | 489 | node->data.type.child_type = ast_parse_type(pc, token_index, &token_index); |
| 490 | } else if (token->id == TokenIdLBracket) { | |
| 491 | node->data.type.type = AstNodeTypeTypeArray; | |
| 492 | ||
| 493 | node->data.type.child_type = ast_parse_type(pc, token_index, &token_index); | |
| 494 | ||
| 495 | Token *semicolon_token = &pc->tokens->at(token_index); | |
| 496 | token_index += 1; | |
| 497 | ast_expect_token(pc, semicolon_token, TokenIdSemicolon); | |
| 498 | ||
| 499 | node->data.type.array_size = ast_parse_expression(pc, &token_index, true); | |
| 500 | ||
| 501 | Token *rbracket_token = &pc->tokens->at(token_index); | |
| 502 | token_index += 1; | |
| 503 | ast_expect_token(pc, rbracket_token, TokenIdRBracket); | |
| 488 | 504 | } else { |
| 489 | 505 | ast_invalid_token_error(pc, token); |
| 490 | 506 | } |
| ... | ... | @@ -494,8 +510,7 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token |
| 494 | 510 | } |
| 495 | 511 | |
| 496 | 512 | /* |
| 497 | ParamDecl<node> : token(Symbol) token(Colon) Type { | |
| 498 | }; | |
| 513 | ParamDecl : token(Symbol) token(Colon) Type | |
| 499 | 514 | */ |
| 500 | 515 | static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new_token_index) { |
| 501 | 516 | Token *param_name = &pc->tokens->at(token_index); |
src/parser.hpp+2| ... | ... | @@ -81,12 +81,14 @@ struct AstNodeParamDecl { |
| 81 | 81 | enum AstNodeTypeType { |
| 82 | 82 | AstNodeTypeTypePrimitive, |
| 83 | 83 | AstNodeTypeTypePointer, |
| 84 | AstNodeTypeTypeArray, | |
| 84 | 85 | }; |
| 85 | 86 | |
| 86 | 87 | struct AstNodeType { |
| 87 | 88 | AstNodeTypeType type; |
| 88 | 89 | Buf primitive_name; |
| 89 | 90 | AstNode *child_type; |
| 91 | AstNode *array_size; | |
| 90 | 92 | bool is_const; |
| 91 | 93 | }; |
| 92 | 94 |
src/semantic_info.hpp+3| ... | ... | @@ -23,8 +23,11 @@ struct TypeTableEntry { |
| 23 | 23 | bool pointer_is_const; |
| 24 | 24 | int user_defined_id; |
| 25 | 25 | Buf name; |
| 26 | ||
| 27 | // use these fields to make sure we don't duplicate type table entries for the same type | |
| 26 | 28 | TypeTableEntry *pointer_const_parent; |
| 27 | 29 | TypeTableEntry *pointer_mut_parent; |
| 30 | HashMap<int, TypeTableEntry *, int_hash, int_eq> arrays_by_size; | |
| 28 | 31 | }; |
| 29 | 32 | |
| 30 | 33 | struct ImportTableEntry { |
src/tokenizer.cpp+10| ... | ... | @@ -259,6 +259,14 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 259 | 259 | begin_token(&t, TokenIdRBrace); |
| 260 | 260 | end_token(&t); |
| 261 | 261 | break; |
| 262 | case '[': | |
| 263 | begin_token(&t, TokenIdLBracket); | |
| 264 | end_token(&t); | |
| 265 | break; | |
| 266 | case ']': | |
| 267 | begin_token(&t, TokenIdRBracket); | |
| 268 | end_token(&t); | |
| 269 | break; | |
| 262 | 270 | case ';': |
| 263 | 271 | begin_token(&t, TokenIdSemicolon); |
| 264 | 272 | end_token(&t); |
| ... | ... | @@ -601,6 +609,8 @@ static const char * token_name(Token *token) { |
| 601 | 609 | case TokenIdStar: return "Star"; |
| 602 | 610 | case TokenIdLBrace: return "LBrace"; |
| 603 | 611 | case TokenIdRBrace: return "RBrace"; |
| 612 | case TokenIdLBracket: return "LBracket"; | |
| 613 | case TokenIdRBracket: return "RBracket"; | |
| 604 | 614 | case TokenIdStringLiteral: return "StringLiteral"; |
| 605 | 615 | case TokenIdSemicolon: return "Semicolon"; |
| 606 | 616 | case TokenIdNumberLiteral: return "NumberLiteral"; |
src/tokenizer.hpp+2| ... | ... | @@ -36,6 +36,8 @@ enum TokenId { |
| 36 | 36 | TokenIdStar, |
| 37 | 37 | TokenIdLBrace, |
| 38 | 38 | TokenIdRBrace, |
| 39 | TokenIdLBracket, | |
| 40 | TokenIdRBracket, | |
| 39 | 41 | TokenIdStringLiteral, |
| 40 | 42 | TokenIdSemicolon, |
| 41 | 43 | TokenIdNumberLiteral, |
src/util.cpp+7| ... | ... | @@ -19,3 +19,10 @@ void zig_panic(const char *format, ...) { |
| 19 | 19 | va_end(ap); |
| 20 | 20 | abort(); |
| 21 | 21 | } |
| 22 | ||
| 23 | uint32_t int_hash(int i) { | |
| 24 | return *reinterpret_cast<uint32_t*>(&i); | |
| 25 | } | |
| 26 | bool int_eq(int a, int b) { | |
| 27 | return a == b; | |
| 28 | } |
src/util.hpp+4| ... | ... | @@ -9,6 +9,7 @@ |
| 9 | 9 | #define ZIG_UTIL_HPP |
| 10 | 10 | |
| 11 | 11 | #include <stdlib.h> |
| 12 | #include <stdint.h> | |
| 12 | 13 | #include <string.h> |
| 13 | 14 | #include <assert.h> |
| 14 | 15 | |
| ... | ... | @@ -78,4 +79,7 @@ static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) |
| 78 | 79 | return memcmp(mem, str, mem_len) == 0; |
| 79 | 80 | } |
| 80 | 81 | |
| 82 | uint32_t int_hash(int i); | |
| 83 | bool int_eq(int a, int b); | |
| 84 | ||
| 81 | 85 | #endif |