| author | |
| committer | |
| log | 09f68c7c339075183c67c56149620c6970b6842a |
| tree | 55afa659954e143035792d44bf4edf992d26fd18 |
| parent | afac1a0123cb574e92fbc37e99e6778c51b46683 |
now you can depend on libc in zig language instead of it being
hardcoded in the compiler.7 files changed, 120 insertions(+), 7 deletions(-)
README.md+6-3| ... | @@ -40,12 +40,13 @@ readable, safe, optimal, and concise code to solve any computing problem. | ... | @@ -40,12 +40,13 @@ readable, safe, optimal, and concise code to solve any computing problem. |
| 40 | 40 | ||
| 41 | ## Roadmap | 41 | ## Roadmap |
| 42 | 42 | ||
| 43 | * don't hardcode the link against libc | ||
| 44 | * C style comments. | 43 | * C style comments. |
| 45 | * Unit tests. | 44 | * Unit tests. |
| 46 | * Simple .so library | 45 | * Simple .so library |
| 47 | * Multiple files | 46 | * Multiple files |
| 48 | * figure out integers | 47 | * figure out integers |
| 48 | * inline assembly and syscalls | ||
| 49 | * running code at compile time | ||
| 49 | * implement a simple game using SDL2 | 50 | * implement a simple game using SDL2 |
| 50 | * How should the Widget use case be solved? In Genesis I'm using C++ and inheritance. | 51 | * How should the Widget use case be solved? In Genesis I'm using C++ and inheritance. |
| 51 | 52 | ||
| ... | @@ -74,13 +75,13 @@ Root : many(TopLevelDecl) token(EOF) | ... | @@ -74,13 +75,13 @@ Root : many(TopLevelDecl) token(EOF) |
| 74 | 75 | ||
| 75 | TopLevelDecl : FnDef | ExternBlock | 76 | TopLevelDecl : FnDef | ExternBlock |
| 76 | 77 | ||
| 77 | ExternBlock : token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace) | 78 | ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace) |
| 78 | 79 | ||
| 79 | FnProto : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) | 80 | FnProto : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) |
| 80 | 81 | ||
| 81 | FnDecl : FnProto token(Semicolon) | 82 | FnDecl : FnProto token(Semicolon) |
| 82 | 83 | ||
| 83 | FnDef : FnProto Block | 84 | FnDef : many(Directive) FnProto Block |
| 84 | 85 | ||
| 85 | ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen) | 86 | ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen) |
| 86 | 87 | ||
| ... | @@ -101,4 +102,6 @@ ReturnStatement : token(Return) Expression token(Semicolon) | ... | @@ -101,4 +102,6 @@ ReturnStatement : token(Return) Expression token(Semicolon) |
| 101 | Expression : token(Number) | token(String) | token(Unreachable) | FnCall | 102 | Expression : token(Number) | token(String) | token(Unreachable) | FnCall |
| 102 | 103 | ||
| 103 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) | 104 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) |
| 105 | |||
| 106 | Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen) | ||
| 104 | ``` | 107 | ``` |
src/codegen.cpp+27-1| ... | @@ -56,6 +56,7 @@ struct CodeGen { | ... | @@ -56,6 +56,7 @@ struct CodeGen { |
| 56 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | 56 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; |
| 57 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; | 57 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; |
| 58 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; | 58 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; |
| 59 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; | ||
| 59 | TypeTableEntry *invalid_type_entry; | 60 | TypeTableEntry *invalid_type_entry; |
| 60 | LLVMTargetDataRef target_data_ref; | 61 | LLVMTargetDataRef target_data_ref; |
| 61 | unsigned pointer_size_bytes; | 62 | unsigned pointer_size_bytes; |
| ... | @@ -86,6 +87,7 @@ CodeGen *create_codegen(AstNode *root, Buf *in_full_path) { | ... | @@ -86,6 +87,7 @@ CodeGen *create_codegen(AstNode *root, Buf *in_full_path) { |
| 86 | g->fn_table.init(32); | 87 | g->fn_table.init(32); |
| 87 | g->str_table.init(32); | 88 | g->str_table.init(32); |
| 88 | g->type_table.init(32); | 89 | g->type_table.init(32); |
| 90 | g->link_table.init(32); | ||
| 89 | g->is_static = false; | 91 | g->is_static = false; |
| 90 | g->build_type = CodeGenBuildTypeDebug; | 92 | g->build_type = CodeGenBuildTypeDebug; |
| 91 | g->strip_debug_symbols = false; | 93 | g->strip_debug_symbols = false; |
| ... | @@ -198,6 +200,18 @@ static void analyze_node(CodeGen *g, AstNode *node) { | ... | @@ -198,6 +200,18 @@ static void analyze_node(CodeGen *g, AstNode *node) { |
| 198 | } | 200 | } |
| 199 | break; | 201 | break; |
| 200 | case NodeTypeExternBlock: | 202 | case NodeTypeExternBlock: |
| 203 | for (int i = 0; i < node->data.extern_block.directives->length; i += 1) { | ||
| 204 | AstNode *directive_node = node->data.extern_block.directives->at(i); | ||
| 205 | Buf *name = &directive_node->data.directive.name; | ||
| 206 | Buf *param = &directive_node->data.directive.param; | ||
| 207 | if (buf_eql_str(name, "link")) { | ||
| 208 | g->link_table.put(param, true); | ||
| 209 | } else { | ||
| 210 | add_node_error(g, node, | ||
| 211 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 201 | for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) { | 215 | for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) { |
| 202 | AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i); | 216 | AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i); |
| 203 | analyze_node(g, fn_decl); | 217 | analyze_node(g, fn_decl); |
| ... | @@ -306,6 +320,8 @@ static void analyze_node(CodeGen *g, AstNode *node) { | ... | @@ -306,6 +320,8 @@ static void analyze_node(CodeGen *g, AstNode *node) { |
| 306 | analyze_node(g, child); | 320 | analyze_node(g, child); |
| 307 | } | 321 | } |
| 308 | break; | 322 | break; |
| 323 | case NodeTypeDirective: | ||
| 324 | break; | ||
| 309 | } | 325 | } |
| 310 | } | 326 | } |
| 311 | 327 | ||
| ... | @@ -639,6 +655,16 @@ void code_gen_link(CodeGen *g, const char *out_file) { | ... | @@ -639,6 +655,16 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 639 | args.append("-o"); | 655 | args.append("-o"); |
| 640 | args.append(out_file); | 656 | args.append(out_file); |
| 641 | args.append((const char *)buf_ptr(&out_file_o)); | 657 | args.append((const char *)buf_ptr(&out_file_o)); |
| 642 | args.append("-lc"); | 658 | |
| 659 | auto it = g->link_table.entry_iterator(); | ||
| 660 | for (;;) { | ||
| 661 | auto *entry = it.next(); | ||
| 662 | if (!entry) | ||
| 663 | break; | ||
| 664 | |||
| 665 | Buf *arg = buf_sprintf("-l%s", buf_ptr(entry->key)); | ||
| 666 | args.append(buf_ptr(arg)); | ||
| 667 | } | ||
| 668 | |||
| 643 | os_spawn_process("ld", args, false); | 669 | os_spawn_process("ld", args, false); |
| 644 | } | 670 | } |
src/parser.cpp+72-3| ... | @@ -48,6 +48,8 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -48,6 +48,8 @@ const char *node_type_str(NodeType node_type) { |
| 48 | return "FnCall"; | 48 | return "FnCall"; |
| 49 | case NodeTypeExternBlock: | 49 | case NodeTypeExternBlock: |
| 50 | return "ExternBlock"; | 50 | return "ExternBlock"; |
| 51 | case NodeTypeDirective: | ||
| 52 | return "Directive"; | ||
| 51 | } | 53 | } |
| 52 | zig_unreachable(); | 54 | zig_unreachable(); |
| 53 | } | 55 | } |
| ... | @@ -158,13 +160,23 @@ struct ParseContext { | ... | @@ -158,13 +160,23 @@ struct ParseContext { |
| 158 | Buf *buf; | 160 | Buf *buf; |
| 159 | AstNode *root; | 161 | AstNode *root; |
| 160 | ZigList<Token> *tokens; | 162 | ZigList<Token> *tokens; |
| 163 | ZigList<AstNode *> *directive_list; | ||
| 161 | }; | 164 | }; |
| 162 | 165 | ||
| 163 | static AstNode *ast_create_node(NodeType type, Token *first_token) { | 166 | static AstNode *ast_create_node_no_line_info(NodeType type) { |
| 164 | AstNode *node = allocate<AstNode>(1); | 167 | AstNode *node = allocate<AstNode>(1); |
| 165 | node->type = type; | 168 | node->type = type; |
| 169 | return node; | ||
| 170 | } | ||
| 171 | |||
| 172 | static void ast_update_node_line_info(AstNode *node, Token *first_token) { | ||
| 166 | node->line = first_token->start_line; | 173 | node->line = first_token->start_line; |
| 167 | node->column = first_token->start_column; | 174 | node->column = first_token->start_column; |
| 175 | } | ||
| 176 | |||
| 177 | static AstNode *ast_create_node(NodeType type, Token *first_token) { | ||
| 178 | AstNode *node = ast_create_node_no_line_info(type); | ||
| 179 | ast_update_node_line_info(node, first_token); | ||
| 168 | return node; | 180 | return node; |
| 169 | } | 181 | } |
| 170 | 182 | ||
| ... | @@ -536,7 +548,57 @@ static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_to | ... | @@ -536,7 +548,57 @@ static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_to |
| 536 | } | 548 | } |
| 537 | 549 | ||
| 538 | /* | 550 | /* |
| 539 | ExternBlock : token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace) | 551 | Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen) |
| 552 | */ | ||
| 553 | static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_token_index) { | ||
| 554 | Token *number_sign = &pc->tokens->at(token_index); | ||
| 555 | token_index += 1; | ||
| 556 | ast_expect_token(pc, number_sign, TokenIdNumberSign); | ||
| 557 | |||
| 558 | AstNode *node = ast_create_node(NodeTypeDirective, number_sign); | ||
| 559 | |||
| 560 | Token *name_symbol = &pc->tokens->at(token_index); | ||
| 561 | token_index += 1; | ||
| 562 | ast_expect_token(pc, name_symbol, TokenIdSymbol); | ||
| 563 | |||
| 564 | ast_buf_from_token(pc, name_symbol, &node->data.directive.name); | ||
| 565 | |||
| 566 | Token *l_paren = &pc->tokens->at(token_index); | ||
| 567 | token_index += 1; | ||
| 568 | ast_expect_token(pc, l_paren, TokenIdLParen); | ||
| 569 | |||
| 570 | Token *param_str = &pc->tokens->at(token_index); | ||
| 571 | token_index += 1; | ||
| 572 | ast_expect_token(pc, param_str, TokenIdStringLiteral); | ||
| 573 | |||
| 574 | parse_string_literal(pc, param_str, &node->data.directive.param); | ||
| 575 | |||
| 576 | Token *r_paren = &pc->tokens->at(token_index); | ||
| 577 | token_index += 1; | ||
| 578 | ast_expect_token(pc, r_paren, TokenIdRParen); | ||
| 579 | |||
| 580 | *new_token_index = token_index; | ||
| 581 | return node; | ||
| 582 | } | ||
| 583 | |||
| 584 | static void ast_parse_directives(ParseContext *pc, int token_index, int *new_token_index, | ||
| 585 | ZigList<AstNode *> *directives) | ||
| 586 | { | ||
| 587 | for (;;) { | ||
| 588 | Token *token = &pc->tokens->at(token_index); | ||
| 589 | if (token->id == TokenIdNumberSign) { | ||
| 590 | AstNode *directive_node = ast_parse_directive(pc, token_index, &token_index); | ||
| 591 | directives->append(directive_node); | ||
| 592 | } else { | ||
| 593 | *new_token_index = token_index; | ||
| 594 | return; | ||
| 595 | } | ||
| 596 | } | ||
| 597 | zig_unreachable(); | ||
| 598 | } | ||
| 599 | |||
| 600 | /* | ||
| 601 | ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace) | ||
| 540 | */ | 602 | */ |
| 541 | static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *new_token_index) { | 603 | static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *new_token_index) { |
| 542 | Token *extern_kw = &pc->tokens->at(token_index); | 604 | Token *extern_kw = &pc->tokens->at(token_index); |
| ... | @@ -545,6 +607,9 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *n | ... | @@ -545,6 +607,9 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *n |
| 545 | 607 | ||
| 546 | AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw); | 608 | AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw); |
| 547 | 609 | ||
| 610 | node->data.extern_block.directives = pc->directive_list; | ||
| 611 | pc->directive_list = nullptr; | ||
| 612 | |||
| 548 | Token *l_brace = &pc->tokens->at(token_index); | 613 | Token *l_brace = &pc->tokens->at(token_index); |
| 549 | token_index += 1; | 614 | token_index += 1; |
| 550 | ast_expect_token(pc, l_brace, TokenIdLBrace); | 615 | ast_expect_token(pc, l_brace, TokenIdLBrace); |
| ... | @@ -570,7 +635,11 @@ static void ast_parse_top_level_decls(ParseContext *pc, int token_index, int *ne | ... | @@ -570,7 +635,11 @@ static void ast_parse_top_level_decls(ParseContext *pc, int token_index, int *ne |
| 570 | { | 635 | { |
| 571 | for (;;) { | 636 | for (;;) { |
| 572 | Token *token = &pc->tokens->at(token_index); | 637 | Token *token = &pc->tokens->at(token_index); |
| 573 | if (token->id == TokenIdKeywordFn) { | 638 | if (token->id == TokenIdNumberSign) { |
| 639 | assert(!pc->directive_list); | ||
| 640 | pc->directive_list = allocate<ZigList<AstNode*>>(1); | ||
| 641 | ast_parse_directives(pc, token_index, &token_index, pc->directive_list); | ||
| 642 | } else if (token->id == TokenIdKeywordFn) { | ||
| 574 | AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, &token_index); | 643 | AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, &token_index); |
| 575 | top_level_decls->append(fn_decl_node); | 644 | top_level_decls->append(fn_decl_node); |
| 576 | } else if (token->id == TokenIdKeywordExtern) { | 645 | } else if (token->id == TokenIdKeywordExtern) { |
src/parser.hpp+8| ... | @@ -27,6 +27,7 @@ enum NodeType { | ... | @@ -27,6 +27,7 @@ enum NodeType { |
| 27 | NodeTypeExpression, | 27 | NodeTypeExpression, |
| 28 | NodeTypeFnCall, | 28 | NodeTypeFnCall, |
| 29 | NodeTypeExternBlock, | 29 | NodeTypeExternBlock, |
| 30 | NodeTypeDirective, | ||
| 30 | }; | 31 | }; |
| 31 | 32 | ||
| 32 | struct AstNodeRoot { | 33 | struct AstNodeRoot { |
| ... | @@ -112,9 +113,15 @@ struct AstNodeFnCall { | ... | @@ -112,9 +113,15 @@ struct AstNodeFnCall { |
| 112 | }; | 113 | }; |
| 113 | 114 | ||
| 114 | struct AstNodeExternBlock { | 115 | struct AstNodeExternBlock { |
| 116 | ZigList<AstNode *> *directives; | ||
| 115 | ZigList<AstNode *> fn_decls; | 117 | ZigList<AstNode *> fn_decls; |
| 116 | }; | 118 | }; |
| 117 | 119 | ||
| 120 | struct AstNodeDirective { | ||
| 121 | Buf name; | ||
| 122 | Buf param; | ||
| 123 | }; | ||
| 124 | |||
| 118 | struct AstNode { | 125 | struct AstNode { |
| 119 | enum NodeType type; | 126 | enum NodeType type; |
| 120 | AstNode *parent; | 127 | AstNode *parent; |
| ... | @@ -133,6 +140,7 @@ struct AstNode { | ... | @@ -133,6 +140,7 @@ struct AstNode { |
| 133 | AstNodeExpression expression; | 140 | AstNodeExpression expression; |
| 134 | AstNodeFnCall fn_call; | 141 | AstNodeFnCall fn_call; |
| 135 | AstNodeExternBlock extern_block; | 142 | AstNodeExternBlock extern_block; |
| 143 | AstNodeDirective directive; | ||
| 136 | } data; | 144 | } data; |
| 137 | }; | 145 | }; |
| 138 | 146 |
src/tokenizer.cpp+5| ... | @@ -218,6 +218,10 @@ ZigList<Token> *tokenize(Buf *buf) { | ... | @@ -218,6 +218,10 @@ ZigList<Token> *tokenize(Buf *buf) { |
| 218 | begin_token(&t, TokenIdDash); | 218 | begin_token(&t, TokenIdDash); |
| 219 | t.state = TokenizeStateSawDash; | 219 | t.state = TokenizeStateSawDash; |
| 220 | break; | 220 | break; |
| 221 | case '#': | ||
| 222 | begin_token(&t, TokenIdNumberSign); | ||
| 223 | end_token(&t); | ||
| 224 | break; | ||
| 221 | default: | 225 | default: |
| 222 | tokenize_error(&t, "invalid character: '%c'", c); | 226 | tokenize_error(&t, "invalid character: '%c'", c); |
| 223 | } | 227 | } |
| ... | @@ -321,6 +325,7 @@ static const char * token_name(Token *token) { | ... | @@ -321,6 +325,7 @@ static const char * token_name(Token *token) { |
| 321 | case TokenIdColon: return "Colon"; | 325 | case TokenIdColon: return "Colon"; |
| 322 | case TokenIdArrow: return "Arrow"; | 326 | case TokenIdArrow: return "Arrow"; |
| 323 | case TokenIdDash: return "Dash"; | 327 | case TokenIdDash: return "Dash"; |
| 328 | case TokenIdNumberSign: return "NumberSign"; | ||
| 324 | } | 329 | } |
| 325 | return "(invalid token)"; | 330 | return "(invalid token)"; |
| 326 | } | 331 | } |
src/tokenizer.hpp+1| ... | @@ -32,6 +32,7 @@ enum TokenId { | ... | @@ -32,6 +32,7 @@ enum TokenId { |
| 32 | TokenIdColon, | 32 | TokenIdColon, |
| 33 | TokenIdArrow, | 33 | TokenIdArrow, |
| 34 | TokenIdDash, | 34 | TokenIdDash, |
| 35 | TokenIdNumberSign, | ||
| 35 | }; | 36 | }; |
| 36 | 37 | ||
| 37 | struct Token { | 38 | struct Token { |
test/hello.zig+1| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | #link("c") | ||
| 1 | extern { | 2 | extern { |
| 2 | fn puts(s: *mut u8) -> i32; | 3 | fn puts(s: *mut u8) -> i32; |
| 3 | fn exit(code: i32) -> unreachable; | 4 | fn exit(code: i32) -> unreachable; |