authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-02 03:39:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-02 03:39:36-07:00
log303823b6b8b250580d644bacce5285efda76b731
tree9ba13c51bf8e0bcbe00b7309076f3e9283006e51
parent34f8d80eac87a5e3bdf495163d8bc0fbd80ae83f

building part of the hello world AST


4 files changed, 414 insertions(+), 25 deletions(-)

README.md+5
......@@ -29,4 +29,9 @@ readable, safe, optimal, and concise code to solve any computing problem.
2929## Roadmap
3030
3131 * Hello, world.
32 - Build AST
33 - Code Gen
34 * C style comments.
35 * Unit tests.
36 * Simple .so library
3237 * How should the Widget use case be solved? In Genesis I'm using C++ and inheritance.
src/buffer.hpp+8-4
......@@ -49,16 +49,20 @@ static inline void buf_deinit(Buf *buf) {
4949 buf->list.deinit();
5050}
5151
52static inline Buf *buf_from_mem(char *ptr, int len) {
53 Buf *buf = allocate<Buf>(1);
52static inline void buf_init_from_mem(Buf *buf, char *ptr, int len) {
5453 buf->list.resize(len + 1);
5554 memcpy(buf_ptr(buf), ptr, len);
5655 buf->list.at(buf_len(buf)) = 0;
56}
57
58static inline Buf *buf_create_from_mem(char *ptr, int len) {
59 Buf *buf = allocate<Buf>(1);
60 buf_init_from_mem(buf, ptr, len);
5761 return buf;
5862}
5963
60static inline Buf *buf_from_str(char *str) {
61 return buf_from_mem(str, strlen(str));
64static inline Buf *buf_create_from_str(char *str) {
65 return buf_create_from_mem(str, strlen(str));
6266}
6367
6468static inline Buf *buf_slice(Buf *in_buf, int start, int end) {
src/main.cpp+400-20
......@@ -48,6 +48,14 @@ static Buf *fetch_file(FILE *f) {
4848 return buf;
4949}
5050
51static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) {
52 size_t str_len = strlen(str);
53 if (str_len != mem_len)
54 return false;
55 return memcmp(mem, str, mem_len) == 0;
56}
57
58
5159#define WHITESPACE \
5260 ' ': \
5361 case '\t': \
......@@ -130,6 +138,10 @@ static Buf *fetch_file(FILE *f) {
130138
131139enum TokenId {
132140 TokenIdSymbol,
141 TokenIdKeywordFn,
142 TokenIdKeywordReturn,
143 TokenIdKeywordMut,
144 TokenIdKeywordConst,
133145 TokenIdLParen,
134146 TokenIdRParen,
135147 TokenIdComma,
......@@ -208,6 +220,20 @@ static void begin_token(Tokenize *t, TokenId id) {
208220static void end_token(Tokenize *t) {
209221 assert(t->cur_tok);
210222 t->cur_tok->end_pos = t->pos + 1;
223
224 char *token_mem = buf_ptr(t->buf) + t->cur_tok->start_pos;
225 int token_len = t->cur_tok->end_pos - t->cur_tok->start_pos;
226
227 if (mem_eql_str(token_mem, token_len, "fn")) {
228 t->cur_tok->id = TokenIdKeywordFn;
229 } else if (mem_eql_str(token_mem, token_len, "return")) {
230 t->cur_tok->id = TokenIdKeywordReturn;
231 } else if (mem_eql_str(token_mem, token_len, "mut")) {
232 t->cur_tok->id = TokenIdKeywordMut;
233 } else if (mem_eql_str(token_mem, token_len, "const")) {
234 t->cur_tok->id = TokenIdKeywordConst;
235 }
236
211237 t->cur_tok = nullptr;
212238}
213239
......@@ -357,6 +383,10 @@ static ZigList<Token> *tokenize(Buf *buf, ZigList<char *> *include_paths, Buf *c
357383static const char * token_name(Token *token) {
358384 switch (token->id) {
359385 case TokenIdSymbol: return "Symbol";
386 case TokenIdKeywordFn: return "Fn";
387 case TokenIdKeywordConst: return "Const";
388 case TokenIdKeywordMut: return "Mut";
389 case TokenIdKeywordReturn: return "Return";
360390 case TokenIdLParen: return "LParen";
361391 case TokenIdRParen: return "RParen";
362392 case TokenIdComma: return "Comma";
......@@ -383,17 +413,86 @@ static void print_tokens(Buf *buf, ZigList<Token> *tokens) {
383413 }
384414}
385415
416struct AstNode;
417
386418enum NodeType {
387419 NodeTypeRoot,
420 NodeTypeFnDecl,
421 NodeTypeParam,
422 NodeTypeType,
423 NodeTypeBlock,
388424};
389425
390struct AstNode {
391 enum NodeType type;
392 ZigList<AstNode *> children;
426struct AstNodeFnDecl {
427 Buf name;
428 ZigList<AstNode *> params;
429 AstNode *return_type;
430 AstNode *body;
431};
432
433struct AstNodeRoot {
434 ZigList<AstNode *> fn_decls;
435};
436
437enum AstNodeTypeType {
438 AstNodeTypeTypePrimitive,
439 AstNodeTypeTypePointer,
440};
441
442enum AstPrimitiveType {
443 AstPrimitiveTypeVoid,
444 AstPrimitiveTypeU8,
445 AstPrimitiveTypeI8,
446 AstPrimitiveTypeU16,
447 AstPrimitiveTypeI16,
448 AstPrimitiveTypeU32,
449 AstPrimitiveTypeI32,
450 AstPrimitiveTypeU64,
451 AstPrimitiveTypeI64,
452 AstPrimitiveTypeUSize,
453 AstPrimitiveTypeISize,
454 AstPrimitiveTypeF32,
455 AstPrimitiveTypeF64,
456};
457
458
459struct AstNodeType {
460 AstNodeTypeType type;
461 AstPrimitiveType primitive_type;
462 AstNode *pointer_type;
463 bool is_const;
464};
465
466struct AstNodeParam {
467 Buf name;
468 AstNode *type;
393469};
394470
395471enum AstState {
396472 AstStateStart,
473 AstStateFn,
474 AstStateFnLParen,
475 AstStateFnParamName,
476 AstStateParamColon,
477 AstStateType,
478 AstStateTypeEnd,
479 AstStateFnParamComma,
480 AstStateFnDeclArrow,
481 AstStateFnDeclBlock,
482 AstStatePointerType,
483 AstStateBlock,
484};
485
486struct AstNode {
487 enum NodeType type;
488 AstNode *parent;
489 AstState prev_state;
490 union {
491 AstNodeRoot root;
492 AstNodeFnDecl fn_decl;
493 AstNodeType type;
494 AstNodeParam param;
495 } data;
397496};
398497
399498struct BuildAst {
......@@ -402,6 +501,7 @@ struct BuildAst {
402501 AstState state;
403502 int line;
404503 int column;
504 AstNode *cur_node;
405505};
406506
407507__attribute__ ((format (printf, 2, 3)))
......@@ -418,36 +518,320 @@ static void ast_error(BuildAst *b, const char *format, ...) {
418518 exit(EXIT_FAILURE);
419519}
420520
421static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) {
422 size_t str_len = strlen(str);
423 if (str_len != mem_len)
424 return false;
425 return memcmp(mem, str, mem_len) == 0;
521static AstNode *ast_create_node(BuildAst *b, NodeType type) {
522 AstNode *child = allocate<AstNode>(1);
523 child->prev_state = b->state;
524 child->parent = b->cur_node;
525 child->type = type;
526 return child;
527}
528
529static void ast_make_node_current(BuildAst *b, AstNode *node) {
530 b->cur_node = node;
531}
532
533static void ast_up_stack(BuildAst *b) {
534 assert(b->cur_node->parent);
535 b->state = b->cur_node->prev_state;
536 b->cur_node = b->cur_node->parent;
537}
538
539
540static const char *node_type_str(NodeType node_type) {
541 switch (node_type) {
542 case NodeTypeRoot: return "Root";
543 case NodeTypeFnDecl: return "FnDecl";
544 case NodeTypeParam: return "Param";
545 case NodeTypeType: return "Type";
546 case NodeTypeBlock: return "Block";
547 }
548 zig_panic("unreachable");
549}
550
551static void print_ast(AstNode *node, int indent) {
552 for (int i = 0; i < indent; i += 1) {
553 fprintf(stderr, " ");
554 }
555
556 switch (node->type) {
557 case NodeTypeRoot:
558 fprintf(stderr, "%s\n", node_type_str(node->type));
559 for (int i = 0; i < node->data.root.fn_decls.length; i += 1) {
560 AstNode *child = node->data.root.fn_decls.at(i);
561 print_ast(child, indent + 2);
562 }
563 break;
564 case NodeTypeFnDecl:
565 {
566 Buf *name_buf = &node->data.fn_decl.name;
567 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf));
568
569 for (int i = 0; i < node->data.fn_decl.params.length; i += 1) {
570 AstNode *child = node->data.fn_decl.params.at(i);
571 print_ast(child, indent + 2);
572 }
573
574 print_ast(node->data.fn_decl.return_type, indent + 2);
575
576 print_ast(node->data.fn_decl.body, indent + 2);
577
578 break;
579 }
580 case NodeTypeParam:
581 {
582 Buf *name_buf = &node->data.param.name;
583 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf));
584
585 print_ast(node->data.param.type, indent + 2);
586 break;
587 }
588 case NodeTypeType:
589 fprintf(stderr, "%s\n", node_type_str(node->type));
590 break;
591 case NodeTypeBlock:
592 fprintf(stderr, "%s\n", node_type_str(node->type));
593 break;
594 }
426595}
427596
597static void ast_end_fn_param_list(BuildAst *b) {
598 b->state = AstStateFnDeclArrow;
599}
428600
429601static AstNode *build_ast(Buf *buf, ZigList<Token> *tokens) {
430602 BuildAst b = {0};
603 b.state = AstStateStart;
431604 b.buf = buf;
432605 b.root = allocate<AstNode>(1);
433606 b.root->type = NodeTypeRoot;
607 b.cur_node = b.root;
434608
435609 for (int i = 0; i < tokens->length; i += 1) {
436610 Token *token = &tokens->at(i);
437 const char *token_str = buf_ptr(buf) + token->start_pos;
611 char *token_mem = buf_ptr(buf) + token->start_pos;
438612 int token_len = token->end_pos - token->start_pos;
439613 b.line = token->start_line;
440614 b.column = token->start_column;
441615 switch (b.state) {
442616 case AstStateStart:
443 if (mem_eql_str(token_str, token_len, "fn")) {
444 zig_panic("TODO fn");
617 assert(b.cur_node->type == NodeTypeRoot);
618 if (token->id == TokenIdKeywordFn) {
619 AstNode *child = ast_create_node(&b, NodeTypeFnDecl);
620 b.cur_node->data.root.fn_decls.append(child);
621 ast_make_node_current(&b, child);
622 b.state = AstStateFn;
445623 } else {
446624 Buf msg = {0};
447 buf_append_str(&msg, "unexpected symbol: '");
448 buf_append_mem(&msg, token_str, token_len);
625 buf_appendf(&msg, "unexpected %s: '", token_name(token));
626 buf_append_mem(&msg, token_mem, token_len);
449627 buf_append_str(&msg, "'");
450628 ast_error(&b, "%s", buf_ptr(&msg));
629 break;
630 }
631 break;
632 case AstStateFn:
633 if (token->id != TokenIdSymbol)
634 ast_error(&b, "expected symbol");
635 buf_init_from_mem(&b.cur_node->data.fn_decl.name, token_mem, token_len);
636 b.state = AstStateFnLParen;
637 break;
638 case AstStateFnLParen:
639 if (token->id != TokenIdLParen)
640 ast_error(&b, "expected '('");
641 b.state = AstStateFnParamName;
642 break;
643 case AstStateFnParamName:
644 switch (token->id) {
645 case TokenIdSymbol:
646 {
647 b.state = AstStateFnParamComma;
648 AstNode *child = ast_create_node(&b, NodeTypeParam);
649 buf_init_from_mem(&child->data.param.name, token_mem, token_len);
650 b.cur_node->data.fn_decl.params.append(child);
651 ast_make_node_current(&b, child);
652 b.state = AstStateParamColon;
653 break;
654 }
655 case TokenIdRParen:
656 ast_end_fn_param_list(&b);
657 break;
658 default:
659 ast_error(&b, "expected parameter name");
660 break;
661 }
662 break;
663 case AstStateParamColon:
664 {
665 if (token->id != TokenIdColon)
666 ast_error(&b, "expected ':'");
667 assert(b.cur_node->type == NodeTypeParam);
668 b.state = AstStateTypeEnd;
669 AstNode *child = ast_create_node(&b, NodeTypeType);
670 b.cur_node->data.param.type = child;
671 ast_make_node_current(&b, child);
672 b.state = AstStateType;
673 break;
674 }
675 case AstStateType:
676 switch (token->id) {
677 case TokenIdSymbol:
678 assert(b.cur_node->type == NodeTypeType);
679 if (mem_eql_str(token_mem, token_len, "u8")) {
680 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
681 b.cur_node->data.type.primitive_type = AstPrimitiveTypeU8;
682 ast_up_stack(&b);
683 } else if (mem_eql_str(token_mem, token_len, "i8")) {
684 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
685 b.cur_node->data.type.primitive_type = AstPrimitiveTypeI8;
686 ast_up_stack(&b);
687 } else if (mem_eql_str(token_mem, token_len, "u16")) {
688 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
689 b.cur_node->data.type.primitive_type = AstPrimitiveTypeU16;
690 ast_up_stack(&b);
691 } else if (mem_eql_str(token_mem, token_len, "i16")) {
692 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
693 b.cur_node->data.type.primitive_type = AstPrimitiveTypeI16;
694 ast_up_stack(&b);
695 } else if (mem_eql_str(token_mem, token_len, "u32")) {
696 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
697 b.cur_node->data.type.primitive_type = AstPrimitiveTypeU32;
698 ast_up_stack(&b);
699 } else if (mem_eql_str(token_mem, token_len, "i32")) {
700 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
701 b.cur_node->data.type.primitive_type = AstPrimitiveTypeI32;
702 ast_up_stack(&b);
703 } else if (mem_eql_str(token_mem, token_len, "u64")) {
704 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
705 b.cur_node->data.type.primitive_type = AstPrimitiveTypeU64;
706 ast_up_stack(&b);
707 } else if (mem_eql_str(token_mem, token_len, "i64")) {
708 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
709 b.cur_node->data.type.primitive_type = AstPrimitiveTypeI64;
710 ast_up_stack(&b);
711 } else if (mem_eql_str(token_mem, token_len, "usize")) {
712 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
713 b.cur_node->data.type.primitive_type = AstPrimitiveTypeUSize;
714 ast_up_stack(&b);
715 } else if (mem_eql_str(token_mem, token_len, "isize")) {
716 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
717 b.cur_node->data.type.primitive_type = AstPrimitiveTypeISize;
718 ast_up_stack(&b);
719 } else if (mem_eql_str(token_mem, token_len, "f32")) {
720 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
721 b.cur_node->data.type.primitive_type = AstPrimitiveTypeF32;
722 ast_up_stack(&b);
723 } else if (mem_eql_str(token_mem, token_len, "f64")) {
724 b.cur_node->data.type.type = AstNodeTypeTypePrimitive;
725 b.cur_node->data.type.primitive_type = AstPrimitiveTypeF64;
726 ast_up_stack(&b);
727 } else {
728 Buf msg = {0};
729 buf_append_str(&msg, "invalid primitive type: '");
730 buf_append_mem(&msg, token_mem, token_len);
731 buf_append_str(&msg, "'");
732 ast_error(&b, "%s", buf_ptr(&msg));
733 }
734 break;
735 case TokenIdStar:
736 b.cur_node->data.type.type = AstNodeTypeTypePointer;
737 b.state = AstStatePointerType;
738 break;
739 default:
740 ast_error(&b, "expected type name");
741 break;
742 }
743 break;
744 case AstStatePointerType:
745 {
746 if (token->id == TokenIdKeywordMut) {
747 b.cur_node->data.type.is_const = false;
748 } else if (token->id == TokenIdKeywordConst) {
749 b.cur_node->data.type.is_const = true;
750 } else {
751 ast_error(&b, "expected 'mut' or 'const'");
752 }
753 b.state = AstStateTypeEnd;
754 AstNode *child = ast_create_node(&b, NodeTypeType);
755 b.cur_node->data.type.pointer_type = child;
756 ast_make_node_current(&b, child);
757 b.state = AstStateType;
758 break;
759 }
760 case AstStateTypeEnd:
761 ast_up_stack(&b);
762 i -= 1;
763 continue;
764 case AstStateFnParamComma:
765 switch (token->id) {
766 case TokenIdComma:
767 b.state = AstStateFnParamName;
768 break;
769 case TokenIdRParen:
770 ast_end_fn_param_list(&b);
771 break;
772 default:
773 ast_error(&b, "expected ',' or ')'");
774 break;
775
776 }
777 break;
778 case AstStateFnDeclArrow:
779 switch (token->id) {
780 case TokenIdArrow:
781 {
782 assert(b.cur_node->type == NodeTypeFnDecl);
783 b.state = AstStateFnDeclBlock;
784 AstNode *child = ast_create_node(&b, NodeTypeType);
785 b.cur_node->data.fn_decl.return_type = child;
786 ast_make_node_current(&b, child);
787 b.state = AstStateType;
788 break;
789 }
790 case TokenIdLBrace:
791 {
792 AstNode *node = ast_create_node(&b, NodeTypeType);
793 node->data.type.type = AstNodeTypeTypePrimitive;
794 node->data.type.primitive_type = AstPrimitiveTypeVoid;
795 b.cur_node->data.fn_decl.return_type = node;
796
797 b.state = AstStateTypeEnd;
798 AstNode *child = ast_create_node(&b, NodeTypeBlock);
799 b.cur_node->data.fn_decl.body = child;
800 ast_make_node_current(&b, child);
801 b.state = AstStateBlock;
802 break;
803 }
804 default:
805 ast_error(&b, "expected '->' or '}'");
806 break;
807 }
808 break;
809 case AstStateFnDeclBlock:
810 {
811 if (token->id != TokenIdLBrace)
812 ast_error(&b, "expected '{'");
813
814 b.state = AstStateTypeEnd;
815 AstNode *child = ast_create_node(&b, NodeTypeBlock);
816 b.cur_node->data.fn_decl.body = child;
817 ast_make_node_current(&b, child);
818 b.state = AstStateBlock;
819 break;
820 }
821 case AstStateBlock:
822 switch (token->id) {
823 case TokenIdSymbol:
824 zig_panic("TODO symbol");
825 break;
826 default:
827 {
828 Buf msg = {0};
829 buf_appendf(&msg, "unexpected %s: '", token_name(token));
830 buf_append_mem(&msg, token_mem, token_len);
831 buf_append_str(&msg, "'");
832 ast_error(&b, "%s", buf_ptr(&msg));
833 break;
834 }
451835 }
452836 break;
453837 }
......@@ -456,10 +840,6 @@ static AstNode *build_ast(Buf *buf, ZigList<Token> *tokens) {
456840 return b.root;
457841}
458842
459static void print_ast(AstNode *node) {
460 zig_panic("TODO");
461}
462
463843char cur_dir[1024];
464844
465845int main(int argc, char **argv) {
......@@ -502,12 +882,12 @@ int main(int argc, char **argv) {
502882 char *result = getcwd(cur_dir, sizeof(cur_dir));
503883 if (!result)
504884 zig_panic("unable to get current working directory: %s", strerror(errno));
505 cur_dir_path = buf_from_str(result);
885 cur_dir_path = buf_create_from_str(result);
506886 } else {
507887 in_f = fopen(in_file, "rb");
508888 if (!in_f)
509889 zig_panic("unable to open %s for reading: %s\n", in_file, strerror(errno));
510 cur_dir_path = buf_dirname(buf_from_str(in_file));
890 cur_dir_path = buf_dirname(buf_create_from_str(in_file));
511891 }
512892
513893 Buf *in_data = fetch_file(in_f);
......@@ -523,7 +903,7 @@ int main(int argc, char **argv) {
523903 print_tokens(in_data, tokens);
524904
525905 AstNode *root = build_ast(in_data, tokens);
526 print_ast(root);
906 print_ast(root, 0);
527907
528908
529909 return EXIT_SUCCESS;
test/hello.zig+1-1
......@@ -1,6 +1,6 @@
11
22
3fn main(argc: int, argv: *mut char) -> int {
3fn main(argc: isize, argv: *mut u8) -> isize {
44 puts("Hello, world!\n");
55 return 0;
66}