authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-10 19:40:46-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-10 19:40:46-05:00
logdc2e3465c78411c67eb6d1efd4944b19b0b279f2
tree95b220593b870509420344e064a5658b850836ba
parent62ead3a2ee3670e2eba8a8e8fe5b2cb32630d787

rendering source code without recursion


5 files changed, 326 insertions(+), 115 deletions(-)

src-self-hosted/main.zig+297-86
...@@ -1,11 +1,14 @@...@@ -1,11 +1,14 @@
1const std = @import("std");
1const builtin = @import("builtin");2const builtin = @import("builtin");
2const io = @import("std").io;3const io = std.io;
3const os = @import("std").os;4const os = std.os;
4const heap = @import("std").heap;5const heap = std.heap;
5const warn = @import("std").debug.warn;6const warn = std.debug.warn;
6const assert = @import("std").debug.assert;7const assert = std.debug.assert;
7const mem = @import("std").mem;8const mem = std.mem;
8const ArrayList = @import("std").ArrayList;9const ArrayList = std.ArrayList;
10const AlignedArrayList = std.AlignedArrayList;
11const math = std.math;
912
1013
11const Token = struct {14const Token = struct {
...@@ -474,6 +477,10 @@ const Tokenizer = struct {...@@ -474,6 +477,10 @@ const Tokenizer = struct {
474 // TODO check state when returning EOF477 // TODO check state when returning EOF
475 return result;478 return result;
476 }479 }
480
481 pub fn getTokenSlice(self: &const Tokenizer, token: &const Token) -> []const u8 {
482 return self.buffer[token.start..token.end];
483 }
477};484};
478485
479const Comptime = enum { No, Yes };486const Comptime = enum { No, Yes };
...@@ -525,6 +532,17 @@ const AstNode = struct {...@@ -525,6 +532,17 @@ const AstNode = struct {
525 Id.AddrOfExpr => @fieldParentPtr(AstNodeAddrOfExpr, "base", base).iterate(index),532 Id.AddrOfExpr => @fieldParentPtr(AstNodeAddrOfExpr, "base", base).iterate(index),
526 };533 };
527 }534 }
535
536 fn destroy(base: &AstNode, allocator: &mem.Allocator) {
537 return switch (base.id) {
538 Id.Root => allocator.destroy(@fieldParentPtr(AstNodeRoot, "base", base)),
539 Id.VarDecl => allocator.destroy(@fieldParentPtr(AstNodeVarDecl, "base", base)),
540 Id.Identifier => allocator.destroy(@fieldParentPtr(AstNodeIdentifier, "base", base)),
541 Id.FnProto => allocator.destroy(@fieldParentPtr(AstNodeFnProto, "base", base)),
542 Id.ParamDecl => allocator.destroy(@fieldParentPtr(AstNodeParamDecl, "base", base)),
543 Id.AddrOfExpr => allocator.destroy(@fieldParentPtr(AstNodeAddrOfExpr, "base", base)),
544 };
545 }
528};546};
529547
530const AstNodeRoot = struct {548const AstNodeRoot = struct {
...@@ -541,7 +559,7 @@ const AstNodeRoot = struct {...@@ -541,7 +559,7 @@ const AstNodeRoot = struct {
541559
542const AstNodeVarDecl = struct {560const AstNodeVarDecl = struct {
543 base: AstNode,561 base: AstNode,
544 visib: Visibility,562 visib_token: ?Token,
545 name_token: Token,563 name_token: Token,
546 eq_token: Token,564 eq_token: Token,
547 mut: Mutability,565 mut: Mutability,
...@@ -585,7 +603,7 @@ const AstNodeIdentifier = struct {...@@ -585,7 +603,7 @@ const AstNodeIdentifier = struct {
585603
586const AstNodeFnProto = struct {604const AstNodeFnProto = struct {
587 base: AstNode,605 base: AstNode,
588 visib: Visibility,606 visib_token: ?Token,
589 fn_token: Token,607 fn_token: Token,
590 name_token: ?Token,608 name_token: ?Token,
591 params: ArrayList(&AstNode),609 params: ArrayList(&AstNode),
...@@ -648,8 +666,8 @@ const AstNodeParamDecl = struct {...@@ -648,8 +666,8 @@ const AstNodeParamDecl = struct {
648666
649const AstNodeAddrOfExpr = struct {667const AstNodeAddrOfExpr = struct {
650 base: AstNode,668 base: AstNode,
651 align_expr: ?&AstNode,
652 op_token: Token,669 op_token: Token,
670 align_expr: ?&AstNode,
653 bit_offset_start_token: ?Token,671 bit_offset_start_token: ?Token,
654 bit_offset_end_token: ?Token,672 bit_offset_end_token: ?Token,
655 const_token: ?Token,673 const_token: ?Token,
...@@ -674,26 +692,47 @@ const AstNodeAddrOfExpr = struct {...@@ -674,26 +692,47 @@ const AstNodeAddrOfExpr = struct {
674error ParseError;692error ParseError;
675693
676const Parser = struct {694const Parser = struct {
677 tokenizer: &Tokenizer,
678 allocator: &mem.Allocator,695 allocator: &mem.Allocator,
696 tokenizer: &Tokenizer,
679 put_back_tokens: [2]Token,697 put_back_tokens: [2]Token,
680 put_back_count: usize,698 put_back_count: usize,
681 source_file_name: []const u8,699 source_file_name: []const u8,
682700
683 fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator, source_file_name: []const u8) -> Parser {701 // This memory contents are used only during a function call. It's used to repurpose memory;
702 // specifically so that freeAst can be guaranteed to succeed.
703 const utility_bytes_align = @alignOf( union { a: RenderAstFrame, b: State, c: RenderState } );
704 utility_bytes: []align(utility_bytes_align) u8,
705
706 fn initUtilityArrayList(self: &Parser, comptime T: type) -> ArrayList(T) {
707 const new_byte_count = self.utility_bytes.len - self.utility_bytes.len % @sizeOf(T);
708 self.utility_bytes = self.allocator.alignedShrink(u8, utility_bytes_align, self.utility_bytes, new_byte_count);
709 const typed_slice = ([]T)(self.utility_bytes);
710 return ArrayList(T).fromOwnedSlice(self.allocator, typed_slice);
711 }
712
713 fn deinitUtilityArrayList(self: &Parser, list: var) {
714 self.utility_bytes = ([]align(utility_bytes_align) u8)(list.toOwnedSlice());
715 }
716
717 pub fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator, source_file_name: []const u8) -> Parser {
684 return Parser {718 return Parser {
685 .tokenizer = tokenizer,
686 .allocator = allocator,719 .allocator = allocator,
720 .tokenizer = tokenizer,
687 .put_back_tokens = undefined,721 .put_back_tokens = undefined,
688 .put_back_count = 0,722 .put_back_count = 0,
689 .source_file_name = source_file_name,723 .source_file_name = source_file_name,
724 .utility_bytes = []align(utility_bytes_align) u8{},
690 };725 };
691 }726 }
692727
728 pub fn deinit(self: &Parser) {
729 self.allocator.free(self.utility_bytes);
730 }
731
693 const State = union(enum) {732 const State = union(enum) {
694 TopLevel, 733 TopLevel,
695 TopLevelModifier: Visibility, 734 TopLevelModifier: ?Token,
696 TopLevelExtern: Visibility, 735 TopLevelExtern: ?Token,
697 Expression: &&AstNode,736 Expression: &&AstNode,
698 GroupedExpression: &&AstNode,737 GroupedExpression: &&AstNode,
699 UnwrapExpression: &&AstNode,738 UnwrapExpression: &&AstNode,
...@@ -721,14 +760,36 @@ const Parser = struct {...@@ -721,14 +760,36 @@ const Parser = struct {
721 ParamDeclComma,760 ParamDeclComma,
722 };761 };
723762
724 pub fn parse(self: &Parser) -> %&AstNode {763 pub fn freeAst(self: &Parser, root_node: &AstNodeRoot) {
725 var stack = ArrayList(State).init(self.allocator);764 // utility_bytes is big enough to do this iteration since we were able to do
726 defer stack.deinit();765 // the parsing in the first place
766 comptime assert(@sizeOf(State) >= @sizeOf(&AstNode));
727767
728 %return stack.append(State.TopLevel);768 var stack = self.initUtilityArrayList(&AstNode);
769 defer self.deinitUtilityArrayList(stack);
770
771 stack.append(&root_node.base) %% unreachable;
772 while (stack.popOrNull()) |node| {
773 var i: usize = 0;
774 while (node.iterate(i)) |child| : (i += 1) {
775 if (child.iterate(0) != null) {
776 stack.append(child) %% unreachable;
777 } else {
778 child.destroy(self.allocator);
779 }
780 }
781 node.destroy(self.allocator);
782 }
783 }
784
785 pub fn parse(self: &Parser) -> %&AstNodeRoot {
786 var stack = self.initUtilityArrayList(State);
787 defer self.deinitUtilityArrayList(stack);
729788
730 const root_node = %return self.createRoot();789 const root_node = %return self.createRoot();
731 // TODO %defer self.freeAst();790 %defer self.allocator.destroy(root_node);
791 %return stack.append(State.TopLevel);
792 %defer self.freeAst(root_node);
732793
733 while (true) {794 while (true) {
734 // This gives us 1 free append that can't fail795 // This gives us 1 free append that can't fail
...@@ -738,95 +799,74 @@ const Parser = struct {...@@ -738,95 +799,74 @@ const Parser = struct {
738 State.TopLevel => {799 State.TopLevel => {
739 const token = self.getNextToken();800 const token = self.getNextToken();
740 switch (token.id) {801 switch (token.id) {
741 Token.Id.Keyword_pub => {802 Token.Id.Keyword_pub, Token.Id.Keyword_export => {
742 stack.append(State {.TopLevelModifier = Visibility.Pub }) %% unreachable;803 stack.append(State { .TopLevelModifier = token }) %% unreachable;
743 continue;
744 },
745 Token.Id.Keyword_export => {
746 stack.append(State {.TopLevelModifier = Visibility.Export }) %% unreachable;
747 continue;804 continue;
748 },805 },
749 Token.Id.Keyword_const => {806 Token.Id.Keyword_const => {
750 stack.append(State.TopLevel) %% unreachable;807 stack.append(State.TopLevel) %% unreachable;
751 const var_decl_node = {808 // TODO shouldn't need this cast
752 const var_decl_node = %return self.createVarDecl(Visibility.Private, Mutability.Const, Comptime.No, Extern.No);809 const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, (?Token)(null),
753 %defer self.allocator.destroy(var_decl_node);810 Mutability.Const, Comptime.No, Extern.No);
754 %return root_node.decls.append(&var_decl_node.base);
755 var_decl_node
756 };
757 %return stack.append(State { .VarDecl = var_decl_node });811 %return stack.append(State { .VarDecl = var_decl_node });
758 continue;812 continue;
759 },813 },
760 Token.Id.Keyword_var => {814 Token.Id.Keyword_var => {
761 stack.append(State.TopLevel) %% unreachable;815 stack.append(State.TopLevel) %% unreachable;
762 const var_decl_node = {816 // TODO shouldn't need this cast
763 const var_decl_node = %return self.createVarDecl(Visibility.Private, Mutability.Var, Comptime.No, Extern.No);817 const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, (?Token)(null),
764 %defer self.allocator.destroy(var_decl_node);818 Mutability.Var, Comptime.No, Extern.No);
765 %return root_node.decls.append(&var_decl_node.base);
766 var_decl_node
767 };
768 %return stack.append(State { .VarDecl = var_decl_node });819 %return stack.append(State { .VarDecl = var_decl_node });
769 continue;820 continue;
770 },821 },
771 Token.Id.Eof => return &root_node.base,822 Token.Id.Eof => return root_node,
772 Token.Id.Keyword_extern => {823 Token.Id.Keyword_extern => {
773 stack.append(State { .TopLevelExtern = Visibility.Private }) %% unreachable;824 stack.append(State { .TopLevelExtern = null }) %% unreachable;
774 continue;825 continue;
775 },826 },
776 else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)),827 else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)),
777 }828 }
778 },829 },
779 State.TopLevelModifier => |visib| {830 State.TopLevelModifier => |visib_token| {
780 const token = self.getNextToken();831 const token = self.getNextToken();
781 switch (token.id) {832 switch (token.id) {
782 Token.Id.Keyword_const => {833 Token.Id.Keyword_const => {
783 stack.append(State.TopLevel) %% unreachable;834 stack.append(State.TopLevel) %% unreachable;
784 const var_decl_node = {835 const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token,
785 const var_decl_node = %return self.createVarDecl(visib, Mutability.Const, Comptime.No, Extern.No);836 Mutability.Const, Comptime.No, Extern.No);
786 %defer self.allocator.destroy(var_decl_node);
787 %return root_node.decls.append(&var_decl_node.base);
788 var_decl_node
789 };
790 %return stack.append(State { .VarDecl = var_decl_node });837 %return stack.append(State { .VarDecl = var_decl_node });
791 continue;838 continue;
792 },839 },
793 Token.Id.Keyword_var => {840 Token.Id.Keyword_var => {
794 stack.append(State.TopLevel) %% unreachable;841 stack.append(State.TopLevel) %% unreachable;
795 const var_decl_node = {842 const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token,
796 const var_decl_node = %return self.createVarDecl(visib, Mutability.Var, Comptime.No, Extern.No);843 Mutability.Var, Comptime.No, Extern.No);
797 %defer self.allocator.destroy(var_decl_node);
798 %return root_node.decls.append(&var_decl_node.base);
799 var_decl_node
800 };
801 %return stack.append(State { .VarDecl = var_decl_node });844 %return stack.append(State { .VarDecl = var_decl_node });
802 continue;845 continue;
803 },846 },
804 Token.Id.Keyword_extern => {847 Token.Id.Keyword_extern => {
805 stack.append(State { .TopLevelExtern = visib }) %% unreachable;848 stack.append(State { .TopLevelExtern = visib_token }) %% unreachable;
806 continue;849 continue;
807 },850 },
808 else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)),851 else => return self.parseError(token, "expected top level declaration, found {}", @tagName(token.id)),
809 }852 }
810 },853 },
811 State.TopLevelExtern => |visib| {854 State.TopLevelExtern => |visib_token| {
812 const token = self.getNextToken();855 const token = self.getNextToken();
813 switch (token.id) {856 switch (token.id) {
814 Token.Id.Keyword_var => {857 Token.Id.Keyword_var => {
815 stack.append(State.TopLevel) %% unreachable;858 stack.append(State.TopLevel) %% unreachable;
816 const var_decl_node = {859 const var_decl_node = %return self.createAttachVarDecl(&root_node.decls, visib_token,
817 const var_decl_node = %return self.createVarDecl(visib, Mutability.Var, Comptime.No, Extern.Yes);860 Mutability.Var, Comptime.No, Extern.Yes);
818 %defer self.allocator.destroy(var_decl_node);
819 %return root_node.decls.append(&var_decl_node.base);
820 var_decl_node
821 };
822 %return stack.append(State { .VarDecl = var_decl_node });861 %return stack.append(State { .VarDecl = var_decl_node });
823 continue;862 continue;
824 },863 },
825 Token.Id.Keyword_fn => {864 Token.Id.Keyword_fn => {
826 stack.append(State.TopLevel) %% unreachable;865 stack.append(State.TopLevel) %% unreachable;
827 %return stack.append(State { .ExpectToken = Token.Id.Semicolon });866 %return stack.append(State { .ExpectToken = Token.Id.Semicolon });
867 // TODO shouldn't need this cast
828 const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, token,868 const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, token,
829 Extern.Yes, CallingConvention.Auto, visib, Inline.Auto);869 Extern.Yes, CallingConvention.Auto, (?Token)(null), Inline.Auto);
830 %return stack.append(State { .FnProto = fn_proto_node });870 %return stack.append(State { .FnProto = fn_proto_node });
831 continue;871 continue;
832 },872 },
...@@ -843,8 +883,9 @@ const Parser = struct {...@@ -843,8 +883,9 @@ const Parser = struct {
843 else => unreachable,883 else => unreachable,
844 };884 };
845 const fn_token = %return self.eatToken(Token.Id.Keyword_fn);885 const fn_token = %return self.eatToken(Token.Id.Keyword_fn);
886 // TODO shouldn't need this cast
846 const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, fn_token,887 const fn_proto_node = %return self.createAttachFnProto(&root_node.decls, fn_token,
847 Extern.Yes, cc, visib, Inline.Auto);888 Extern.Yes, cc, (?Token)(null), Inline.Auto);
848 %return stack.append(State { .FnProto = fn_proto_node });889 %return stack.append(State { .FnProto = fn_proto_node });
849 continue;890 continue;
850 },891 },
...@@ -1054,6 +1095,8 @@ const Parser = struct {...@@ -1054,6 +1095,8 @@ const Parser = struct {
1054 }1095 }
1055 if (token.id == Token.Id.Ellipsis3) {1096 if (token.id == Token.Id.Ellipsis3) {
1056 param_decl.var_args_token = token;1097 param_decl.var_args_token = token;
1098 stack.append(State { .ExpectToken = Token.Id.RParen }) %% unreachable;
1099 continue;
1057 } else {1100 } else {
1058 self.putBackToken(token);1101 self.putBackToken(token);
1059 }1102 }
...@@ -1094,7 +1137,7 @@ const Parser = struct {...@@ -1094,7 +1137,7 @@ const Parser = struct {
1094 return node;1137 return node;
1095 }1138 }
10961139
1097 fn createVarDecl(self: &Parser, visib: Visibility, mut: Mutability, is_comptime: Comptime,1140 fn createVarDecl(self: &Parser, visib_token: &const ?Token, mut: Mutability, is_comptime: Comptime,
1098 is_extern: Extern) -> %&AstNodeVarDecl1141 is_extern: Extern) -> %&AstNodeVarDecl
1099 {1142 {
1100 const node = %return self.allocator.create(AstNodeVarDecl);1143 const node = %return self.allocator.create(AstNodeVarDecl);
...@@ -1102,7 +1145,7 @@ const Parser = struct {...@@ -1102,7 +1145,7 @@ const Parser = struct {
11021145
1103 *node = AstNodeVarDecl {1146 *node = AstNodeVarDecl {
1104 .base = AstNode {.id = AstNode.Id.VarDecl},1147 .base = AstNode {.id = AstNode.Id.VarDecl},
1105 .visib = visib,1148 .visib_token = *visib_token,
1106 .mut = mut,1149 .mut = mut,
1107 .is_comptime = is_comptime,1150 .is_comptime = is_comptime,
1108 .is_extern = is_extern,1151 .is_extern = is_extern,
...@@ -1129,14 +1172,14 @@ const Parser = struct {...@@ -1129,14 +1172,14 @@ const Parser = struct {
1129 }1172 }
11301173
1131 fn createFnProto(self: &Parser, fn_token: &const Token, is_extern: Extern,1174 fn createFnProto(self: &Parser, fn_token: &const Token, is_extern: Extern,
1132 cc: CallingConvention, visib: Visibility, is_inline: Inline) -> %&AstNodeFnProto1175 cc: CallingConvention, visib_token: &const ?Token, is_inline: Inline) -> %&AstNodeFnProto
1133 {1176 {
1134 const node = %return self.allocator.create(AstNodeFnProto);1177 const node = %return self.allocator.create(AstNodeFnProto);
1135 %defer self.allocator.destroy(node);1178 %defer self.allocator.destroy(node);
11361179
1137 *node = AstNodeFnProto {1180 *node = AstNodeFnProto {
1138 .base = AstNode {.id = AstNode.Id.FnProto},1181 .base = AstNode {.id = AstNode.Id.FnProto},
1139 .visib = visib,1182 .visib_token = *visib_token,
1140 .name_token = null,1183 .name_token = null,
1141 .fn_token = *fn_token,1184 .fn_token = *fn_token,
1142 .params = ArrayList(&AstNode).init(self.allocator),1185 .params = ArrayList(&AstNode).init(self.allocator),
...@@ -1199,9 +1242,18 @@ const Parser = struct {...@@ -1199,9 +1242,18 @@ const Parser = struct {
1199 }1242 }
12001243
1201 fn createAttachFnProto(self: &Parser, list: &ArrayList(&AstNode), fn_token: &const Token,1244 fn createAttachFnProto(self: &Parser, list: &ArrayList(&AstNode), fn_token: &const Token,
1202 is_extern: Extern, cc: CallingConvention, visib: Visibility, is_inline: Inline) -> %&AstNodeFnProto1245 is_extern: Extern, cc: CallingConvention, visib_token: &const ?Token, is_inline: Inline) -> %&AstNodeFnProto
1203 {1246 {
1204 const node = %return self.createFnProto(fn_token, is_extern, cc, visib, is_inline);1247 const node = %return self.createFnProto(fn_token, is_extern, cc, visib_token, is_inline);
1248 %defer self.allocator.destroy(node);
1249 %return list.append(&node.base);
1250 return node;
1251 }
1252
1253 fn createAttachVarDecl(self: &Parser, list: &ArrayList(&AstNode), visib_token: &const ?Token, mut: Mutability,
1254 is_comptime: Comptime, is_extern: Extern) -> %&AstNodeVarDecl
1255 {
1256 const node = %return self.createVarDecl(visib_token, mut, is_comptime, is_extern);
1205 %defer self.allocator.destroy(node);1257 %defer self.allocator.destroy(node);
1206 %return list.append(&node.base);1258 %return list.append(&node.base);
1207 return node;1259 return node;
...@@ -1255,8 +1307,171 @@ const Parser = struct {...@@ -1255,8 +1307,171 @@ const Parser = struct {
1255 self.tokenizer.next()1307 self.tokenizer.next()
1256 };1308 };
1257 }1309 }
1258};
12591310
1311 const RenderAstFrame = struct {
1312 node: &AstNode,
1313 indent: usize,
1314 };
1315
1316 pub fn renderAst(self: &Parser, stream: &std.io.OutStream, root_node: &AstNodeRoot) -> %void {
1317 var stack = self.initUtilityArrayList(RenderAstFrame);
1318 defer self.deinitUtilityArrayList(stack);
1319
1320 %return stack.append(RenderAstFrame {
1321 .node = &root_node.base,
1322 .indent = 0,
1323 });
1324
1325 while (stack.popOrNull()) |frame| {
1326 {
1327 var i: usize = 0;
1328 while (i < frame.indent) : (i += 1) {
1329 %return stream.print(" ");
1330 }
1331 }
1332 %return stream.print("{}\n", @tagName(frame.node.id));
1333 var child_i: usize = 0;
1334 while (frame.node.iterate(child_i)) |child| : (child_i += 1) {
1335 %return stack.append(RenderAstFrame {
1336 .node = child,
1337 .indent = frame.indent + 2,
1338 });
1339 }
1340 }
1341 }
1342
1343
1344 pub const RenderState = union(enum) {
1345 TopLevelDecl: &AstNode,
1346 FnProtoRParen: &AstNodeFnProto,
1347 ParamDecl: &AstNode,
1348 Text: []const u8,
1349 Expression: &AstNode,
1350 AddrOfExprBit: &AstNodeAddrOfExpr,
1351 };
1352
1353 pub fn renderSource(self: &Parser, stream: &std.io.OutStream, root_node: &AstNodeRoot) -> %void {
1354 var stack = self.initUtilityArrayList(RenderState);
1355 defer self.deinitUtilityArrayList(stack);
1356
1357 {
1358 var i = root_node.decls.len;
1359 while (i != 0) {
1360 i -= 1;
1361 const decl = root_node.decls.items[i];
1362 %return stack.append(RenderState {.TopLevelDecl = decl});
1363 }
1364 }
1365
1366 while (stack.popOrNull()) |state| {
1367 switch (state) {
1368 RenderState.TopLevelDecl => |decl| {
1369 switch (decl.id) {
1370 AstNode.Id.FnProto => {
1371 const fn_proto = @fieldParentPtr(AstNodeFnProto, "base", decl);
1372 if (fn_proto.visib_token) |visib_token| {
1373 switch (visib_token.id) {
1374 Token.Id.Keyword_pub => %return stream.print("pub "),
1375 Token.Id.Keyword_export => %return stream.print("export "),
1376 else => unreachable,
1377 };
1378 }
1379 if (fn_proto.is_extern == Extern.Yes) {
1380 %return stream.print("extern ");
1381 }
1382 %return stream.print("fn");
1383
1384 if (fn_proto.name_token) |name_token| {
1385 %return stream.print(" {}", self.tokenizer.getTokenSlice(name_token));
1386 }
1387
1388 %return stream.print("(");
1389
1390 if (fn_proto.fn_def_node == null) {
1391 %return stack.append(RenderState { .Text = ";" });
1392 }
1393
1394 %return stack.append(RenderState { .FnProtoRParen = fn_proto});
1395 var i = fn_proto.params.len;
1396 while (i != 0) {
1397 i -= 1;
1398 const param_decl_node = fn_proto.params.items[i];
1399 %return stack.append(RenderState { .ParamDecl = param_decl_node});
1400 if (i != 0) {
1401 %return stack.append(RenderState { .Text = ", " });
1402 }
1403 }
1404 },
1405 else => unreachable,
1406 }
1407 },
1408 RenderState.ParamDecl => |base| {
1409 const param_decl = @fieldParentPtr(AstNodeParamDecl, "base", base);
1410 if (param_decl.comptime_token) |comptime_token| {
1411 %return stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token));
1412 }
1413 if (param_decl.noalias_token) |noalias_token| {
1414 %return stream.print("{} ", self.tokenizer.getTokenSlice(noalias_token));
1415 }
1416 if (param_decl.name_token) |name_token| {
1417 %return stream.print("{}: ", self.tokenizer.getTokenSlice(name_token));
1418 }
1419 if (param_decl.var_args_token) |var_args_token| {
1420 %return stream.print("{}", self.tokenizer.getTokenSlice(var_args_token));
1421 } else {
1422 %return stack.append(RenderState { .Expression = param_decl.type_node});
1423 }
1424 },
1425 RenderState.Text => |bytes| {
1426 %return stream.write(bytes);
1427 },
1428 RenderState.Expression => |base| switch (base.id) {
1429 AstNode.Id.Identifier => {
1430 const identifier = @fieldParentPtr(AstNodeIdentifier, "base", base);
1431 %return stream.print("{}", self.tokenizer.getTokenSlice(identifier.name_token));
1432 },
1433 AstNode.Id.AddrOfExpr => {
1434 const addr_of_expr = @fieldParentPtr(AstNodeAddrOfExpr, "base", base);
1435 %return stream.print("{}", self.tokenizer.getTokenSlice(addr_of_expr.op_token));
1436 %return stack.append(RenderState { .AddrOfExprBit = addr_of_expr});
1437
1438 if (addr_of_expr.align_expr) |align_expr| {
1439 %return stream.print("align(");
1440 %return stack.append(RenderState { .Text = ")"});
1441 %return stack.append(RenderState { .Expression = align_expr});
1442 }
1443 },
1444 else => unreachable,
1445 },
1446 RenderState.AddrOfExprBit => |addr_of_expr| {
1447 if (addr_of_expr.bit_offset_start_token) |bit_offset_start_token| {
1448 %return stream.print("{} ", self.tokenizer.getTokenSlice(bit_offset_start_token));
1449 }
1450 if (addr_of_expr.bit_offset_end_token) |bit_offset_end_token| {
1451 %return stream.print("{} ", self.tokenizer.getTokenSlice(bit_offset_end_token));
1452 }
1453 if (addr_of_expr.const_token) |const_token| {
1454 %return stream.print("{} ", self.tokenizer.getTokenSlice(const_token));
1455 }
1456 if (addr_of_expr.volatile_token) |volatile_token| {
1457 %return stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token));
1458 }
1459 %return stack.append(RenderState { .Expression = addr_of_expr.op_expr});
1460 },
1461 RenderState.FnProtoRParen => |fn_proto| {
1462 %return stream.print(")");
1463 if (fn_proto.align_expr != null) {
1464 @panic("TODO");
1465 }
1466 if (fn_proto.return_type) |return_type| {
1467 %return stream.print(" -> ");
1468 %return stack.append(RenderState { .Expression = return_type});
1469 }
1470 },
1471 }
1472 }
1473 }
1474};
12601475
1261pub fn main() -> %void {1476pub fn main() -> %void {
1262 main2() %% |err| {1477 main2() %% |err| {
...@@ -1277,6 +1492,11 @@ pub fn main2() -> %void {...@@ -1277,6 +1492,11 @@ pub fn main2() -> %void {
1277 const target_file = args[1];1492 const target_file = args[1];
12781493
1279 const target_file_buf = %return io.readFileAlloc(target_file, allocator);1494 const target_file_buf = %return io.readFileAlloc(target_file, allocator);
1495 defer allocator.free(target_file_buf);
1496
1497 var stderr_file = %return std.io.getStdErr();
1498 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
1499 const out_stream = &stderr_file_out_stream.stream;
12801500
1281 warn("====input:====\n");1501 warn("====input:====\n");
12821502
...@@ -1298,24 +1518,15 @@ pub fn main2() -> %void {...@@ -1298,24 +1518,15 @@ pub fn main2() -> %void {
12981518
1299 var tokenizer = Tokenizer.init(target_file_buf);1519 var tokenizer = Tokenizer.init(target_file_buf);
1300 var parser = Parser.init(&tokenizer, allocator, target_file);1520 var parser = Parser.init(&tokenizer, allocator, target_file);
1301 const node = %return parser.parse();1521 defer parser.deinit();
13021522
1523 const root_node = %return parser.parse();
1524 defer parser.freeAst(root_node);
13031525
1304 render(node, 0);1526 %return parser.renderAst(out_stream, root_node);
1305}
13061527
1307fn render(node: &AstNode, indent: usize) {1528 warn("====fmt:====\n");
1308 {1529 %return parser.renderSource(out_stream, root_node);
1309 var i: usize = 0;
1310 while (i < indent) : (i += 1) {
1311 warn(" ");
1312 }
1313 }
1314 warn("{}\n", @tagName(node.id));
1315 var i: usize = 0;
1316 while (node.iterate(i)) |child| : (i += 1) {
1317 render(child, indent + 2);
1318 }
1319}1530}
13201531
1321fn removeNullCast(x: var) -> {const InnerPtr = @typeOf(x).Child.Child; &InnerPtr} {1532fn removeNullCast(x: var) -> {const InnerPtr = @typeOf(x).Child.Child; &InnerPtr} {
src/analyze.cpp+1-1
...@@ -2227,7 +2227,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {...@@ -2227,7 +2227,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
22272227
2228 tag_type = new_type_table_entry(TypeTableEntryIdEnum);2228 tag_type = new_type_table_entry(TypeTableEntryIdEnum);
2229 buf_resize(&tag_type->name, 0);2229 buf_resize(&tag_type->name, 0);
2230 buf_appendf(&tag_type->name, "@TagType(%s)", buf_ptr(&union_type->name));2230 buf_appendf(&tag_type->name, "@EnumTagType(%s)", buf_ptr(&union_type->name));
2231 tag_type->is_copyable = true;2231 tag_type->is_copyable = true;
2232 tag_type->type_ref = tag_int_type->type_ref;2232 tag_type->type_ref = tag_int_type->type_ref;
2233 tag_type->zero_bits = tag_int_type->zero_bits;2233 tag_type->zero_bits = tag_int_type->zero_bits;
std/array_list.zig+20-10
...@@ -3,21 +3,25 @@ const assert = debug.assert;...@@ -3,21 +3,25 @@ const assert = debug.assert;
3const mem = @import("mem.zig");3const mem = @import("mem.zig");
4const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
55
6pub fn ArrayList(comptime T: type) -> type{6pub fn ArrayList(comptime T: type) -> type {
7 return AlignedArrayList(T, @alignOf(T));
8}
9
10pub fn AlignedArrayList(comptime T: type, comptime A: u29) -> type{
7 struct {11 struct {
8 const Self = this;12 const Self = this;
913
10 /// Use toSlice instead of slicing this directly, because if you don't14 /// Use toSlice instead of slicing this directly, because if you don't
11 /// specify the end position of the slice, this will potentially give15 /// specify the end position of the slice, this will potentially give
12 /// you uninitialized memory.16 /// you uninitialized memory.
13 items: []T,17 items: []align(A) T,
14 len: usize,18 len: usize,
15 allocator: &Allocator,19 allocator: &Allocator,
1620
17 /// Deinitialize with `deinit` or use `toOwnedSlice`.21 /// Deinitialize with `deinit` or use `toOwnedSlice`.
18 pub fn init(allocator: &Allocator) -> Self {22 pub fn init(allocator: &Allocator) -> Self {
19 Self {23 Self {
20 .items = []T{},24 .items = []align(A) T{},
21 .len = 0,25 .len = 0,
22 .allocator = allocator,26 .allocator = allocator,
23 }27 }
...@@ -27,18 +31,18 @@ pub fn ArrayList(comptime T: type) -> type{...@@ -27,18 +31,18 @@ pub fn ArrayList(comptime T: type) -> type{
27 l.allocator.free(l.items);31 l.allocator.free(l.items);
28 }32 }
2933
30 pub fn toSlice(l: &Self) -> []T {34 pub fn toSlice(l: &Self) -> []align(A) T {
31 return l.items[0..l.len];35 return l.items[0..l.len];
32 }36 }
3337
34 pub fn toSliceConst(l: &const Self) -> []const T {38 pub fn toSliceConst(l: &const Self) -> []align(A) const T {
35 return l.items[0..l.len];39 return l.items[0..l.len];
36 }40 }
3741
38 /// ArrayList takes ownership of the passed in slice. The slice must have been42 /// ArrayList takes ownership of the passed in slice. The slice must have been
39 /// allocated with `allocator`.43 /// allocated with `allocator`.
40 /// Deinitialize with `deinit` or use `toOwnedSlice`.44 /// Deinitialize with `deinit` or use `toOwnedSlice`.
41 pub fn fromOwnedSlice(allocator: &Allocator, slice: []T) -> Self {45 pub fn fromOwnedSlice(allocator: &Allocator, slice: []align(A) T) -> Self {
42 return Self {46 return Self {
43 .items = slice,47 .items = slice,
44 .len = slice.len,48 .len = slice.len,
...@@ -47,9 +51,9 @@ pub fn ArrayList(comptime T: type) -> type{...@@ -47,9 +51,9 @@ pub fn ArrayList(comptime T: type) -> type{
47 }51 }
4852
49 /// The caller owns the returned memory. ArrayList becomes empty.53 /// The caller owns the returned memory. ArrayList becomes empty.
50 pub fn toOwnedSlice(self: &Self) -> []T {54 pub fn toOwnedSlice(self: &Self) -> []align(A) T {
51 const allocator = self.allocator;55 const allocator = self.allocator;
52 const result = allocator.shrink(T, self.items, self.len);56 const result = allocator.alignedShrink(T, A, self.items, self.len);
53 *self = init(allocator);57 *self = init(allocator);
54 return result;58 return result;
55 }59 }
...@@ -59,7 +63,7 @@ pub fn ArrayList(comptime T: type) -> type{...@@ -59,7 +63,7 @@ pub fn ArrayList(comptime T: type) -> type{
59 *new_item_ptr = *item;63 *new_item_ptr = *item;
60 }64 }
6165
62 pub fn appendSlice(l: &Self, items: []const T) -> %void {66 pub fn appendSlice(l: &Self, items: []align(A) const T) -> %void {
63 %return l.ensureCapacity(l.len + items.len);67 %return l.ensureCapacity(l.len + items.len);
64 mem.copy(T, l.items[l.len..], items);68 mem.copy(T, l.items[l.len..], items);
65 l.len += items.len;69 l.len += items.len;
...@@ -82,7 +86,7 @@ pub fn ArrayList(comptime T: type) -> type{...@@ -82,7 +86,7 @@ pub fn ArrayList(comptime T: type) -> type{
82 better_capacity += better_capacity / 2 + 8;86 better_capacity += better_capacity / 2 + 8;
83 if (better_capacity >= new_capacity) break;87 if (better_capacity >= new_capacity) break;
84 }88 }
85 l.items = %return l.allocator.realloc(T, l.items, better_capacity);89 l.items = %return l.allocator.alignedRealloc(T, A, l.items, better_capacity);
86 }90 }
8791
88 pub fn addOne(l: &Self) -> %&T {92 pub fn addOne(l: &Self) -> %&T {
...@@ -97,6 +101,12 @@ pub fn ArrayList(comptime T: type) -> type{...@@ -97,6 +101,12 @@ pub fn ArrayList(comptime T: type) -> type{
97 self.len -= 1;101 self.len -= 1;
98 return self.items[self.len];102 return self.items[self.len];
99 }103 }
104
105 pub fn popOrNull(self: &Self) -> ?T {
106 if (self.len == 0)
107 return null;
108 return self.pop();
109 }
100 }110 }
101}111}
102112
std/index.zig+7-6
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1pub const ArrayList = @import("array_list.zig").ArrayList;1pub const ArrayList = @import("array_list.zig").ArrayList;
2pub const AlignedArrayList = @import("array_list.zig").AlignedArrayList;
2pub const BufMap = @import("buf_map.zig").BufMap;3pub const BufMap = @import("buf_map.zig").BufMap;
3pub const BufSet = @import("buf_set.zig").BufSet;4pub const BufSet = @import("buf_set.zig").BufSet;
4pub const Buffer = @import("buffer.zig").Buffer;5pub const Buffer = @import("buffer.zig").Buffer;
...@@ -26,12 +27,12 @@ pub const sort = @import("sort.zig");...@@ -26,12 +27,12 @@ pub const sort = @import("sort.zig");
2627
27test "std" {28test "std" {
28 // run tests from these29 // run tests from these
29 _ = @import("array_list.zig").ArrayList;30 _ = @import("array_list.zig");
30 _ = @import("buf_map.zig").BufMap;31 _ = @import("buf_map.zig");
31 _ = @import("buf_set.zig").BufSet;32 _ = @import("buf_set.zig");
32 _ = @import("buffer.zig").Buffer;33 _ = @import("buffer.zig");
33 _ = @import("hash_map.zig").HashMap;34 _ = @import("hash_map.zig");
34 _ = @import("linked_list.zig").LinkedList;35 _ = @import("linked_list.zig");
3536
36 _ = @import("base64.zig");37 _ = @import("base64.zig");
37 _ = @import("build.zig");38 _ = @import("build.zig");
std/mem.zig+1-12
...@@ -8,7 +8,6 @@ pub const Cmp = math.Cmp;...@@ -8,7 +8,6 @@ pub const Cmp = math.Cmp;
8pub const Allocator = struct {8pub const Allocator = struct {
9 /// Allocate byte_count bytes and return them in a slice, with the9 /// Allocate byte_count bytes and return them in a slice, with the
10 /// slice's pointer aligned at least to alignment bytes.10 /// slice's pointer aligned at least to alignment bytes.
11 /// The returned newly allocated memory is undefined.
12 allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) -> %[]u8,11 allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) -> %[]u8,
1312
14 /// If `new_byte_count > old_mem.len`:13 /// If `new_byte_count > old_mem.len`:
...@@ -18,8 +17,6 @@ pub const Allocator = struct {...@@ -18,8 +17,6 @@ pub const Allocator = struct {
18 /// If `new_byte_count <= old_mem.len`:17 /// If `new_byte_count <= old_mem.len`:
19 /// * this function must return successfully. 18 /// * this function must return successfully.
20 /// * alignment <= alignment of old_mem.ptr19 /// * alignment <= alignment of old_mem.ptr
21 ///
22 /// The returned newly allocated memory is undefined.
23 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) -> %[]u8,20 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) -> %[]u8,
2421
25 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`22 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
...@@ -43,10 +40,6 @@ pub const Allocator = struct {...@@ -43,10 +40,6 @@ pub const Allocator = struct {
43 {40 {
44 const byte_count = %return math.mul(usize, @sizeOf(T), n);41 const byte_count = %return math.mul(usize, @sizeOf(T), n);
45 const byte_slice = %return self.allocFn(self, byte_count, alignment);42 const byte_slice = %return self.allocFn(self, byte_count, alignment);
46 // This loop should get optimized out in ReleaseFast mode
47 for (byte_slice) |*byte| {
48 *byte = undefined;
49 }
50 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));43 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
51 }44 }
5245
...@@ -63,10 +56,6 @@ pub const Allocator = struct {...@@ -63,10 +56,6 @@ pub const Allocator = struct {
6356
64 const byte_count = %return math.mul(usize, @sizeOf(T), n);57 const byte_count = %return math.mul(usize, @sizeOf(T), n);
65 const byte_slice = %return self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment);58 const byte_slice = %return self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment);
66 // This loop should get optimized out in ReleaseFast mode
67 for (byte_slice[old_mem.len..]) |*byte| {
68 *byte = undefined;
69 }
70 return ([]T)(@alignCast(alignment, byte_slice));59 return ([]T)(@alignCast(alignment, byte_slice));
71 }60 }
7261
...@@ -92,7 +81,7 @@ pub const Allocator = struct {...@@ -92,7 +81,7 @@ pub const Allocator = struct {
92 const byte_count = @sizeOf(T) * n;81 const byte_count = @sizeOf(T) * n;
9382
94 const byte_slice = %%self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment);83 const byte_slice = %%self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment);
95 return ([]T)(@alignCast(alignment, byte_slice));84 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
96 }85 }
9786
98 fn free(self: &Allocator, memory: var) {87 fn free(self: &Allocator, memory: var) {