authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-09 23:43:07-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-09 23:43:07-04:00
log6928badd850f9fcebdcc0b13287db2c81d2293c0
tree241e9cbce7646b6ca7a0b0287a9a76dd14a4f38e
parentac4d55dec1e32ddef945bfa246eb78f20f31ec44
parentbf21747a426887ed2ac866c9a9d317f64b22da79

Merge branch 'master' into pointer-reform


52 files changed, 6437 insertions(+), 390 deletions(-)

CMakeLists.txt+30-28
...@@ -416,8 +416,8 @@ set(ZIG_CPP_SOURCES...@@ -416,8 +416,8 @@ set(ZIG_CPP_SOURCES
416set(ZIG_STD_FILES416set(ZIG_STD_FILES
417 "array_list.zig"417 "array_list.zig"
418 "atomic/index.zig"418 "atomic/index.zig"
419 "atomic/stack.zig"
420 "atomic/queue.zig"419 "atomic/queue.zig"
420 "atomic/stack.zig"
421 "base64.zig"421 "base64.zig"
422 "buf_map.zig"422 "buf_map.zig"
423 "buf_set.zig"423 "buf_set.zig"
...@@ -427,13 +427,13 @@ set(ZIG_STD_FILES...@@ -427,13 +427,13 @@ set(ZIG_STD_FILES
427 "c/index.zig"427 "c/index.zig"
428 "c/linux.zig"428 "c/linux.zig"
429 "c/windows.zig"429 "c/windows.zig"
430 "crypto/blake2.zig"
431 "crypto/hmac.zig"
430 "crypto/index.zig"432 "crypto/index.zig"
431 "crypto/md5.zig"433 "crypto/md5.zig"
432 "crypto/sha1.zig"434 "crypto/sha1.zig"
433 "crypto/sha2.zig"435 "crypto/sha2.zig"
434 "crypto/sha3.zig"436 "crypto/sha3.zig"
435 "crypto/blake2.zig"
436 "crypto/hmac.zig"
437 "cstr.zig"437 "cstr.zig"
438 "debug/failing_allocator.zig"438 "debug/failing_allocator.zig"
439 "debug/index.zig"439 "debug/index.zig"
...@@ -445,15 +445,16 @@ set(ZIG_STD_FILES...@@ -445,15 +445,16 @@ set(ZIG_STD_FILES
445 "fmt/errol/index.zig"445 "fmt/errol/index.zig"
446 "fmt/errol/lookup.zig"446 "fmt/errol/lookup.zig"
447 "fmt/index.zig"447 "fmt/index.zig"
448 "hash_map.zig"
449 "hash/index.zig"
450 "hash/adler.zig"448 "hash/adler.zig"
451 "hash/crc.zig"449 "hash/crc.zig"
452 "hash/fnv.zig"450 "hash/fnv.zig"
451 "hash/index.zig"
453 "hash/siphash.zig"452 "hash/siphash.zig"
453 "hash_map.zig"
454 "heap.zig"454 "heap.zig"
455 "index.zig"455 "index.zig"
456 "io.zig"456 "io.zig"
457 "json.zig"
457 "linked_list.zig"458 "linked_list.zig"
458 "macho.zig"459 "macho.zig"
459 "math/acos.zig"460 "math/acos.zig"
...@@ -465,6 +466,28 @@ set(ZIG_STD_FILES...@@ -465,6 +466,28 @@ set(ZIG_STD_FILES
465 "math/atanh.zig"466 "math/atanh.zig"
466 "math/cbrt.zig"467 "math/cbrt.zig"
467 "math/ceil.zig"468 "math/ceil.zig"
469 "math/complex/abs.zig"
470 "math/complex/acos.zig"
471 "math/complex/acosh.zig"
472 "math/complex/arg.zig"
473 "math/complex/asin.zig"
474 "math/complex/asinh.zig"
475 "math/complex/atan.zig"
476 "math/complex/atanh.zig"
477 "math/complex/conj.zig"
478 "math/complex/cos.zig"
479 "math/complex/cosh.zig"
480 "math/complex/exp.zig"
481 "math/complex/index.zig"
482 "math/complex/ldexp.zig"
483 "math/complex/log.zig"
484 "math/complex/pow.zig"
485 "math/complex/proj.zig"
486 "math/complex/sin.zig"
487 "math/complex/sinh.zig"
488 "math/complex/sqrt.zig"
489 "math/complex/tan.zig"
490 "math/complex/tanh.zig"
468 "math/copysign.zig"491 "math/copysign.zig"
469 "math/cos.zig"492 "math/cos.zig"
470 "math/cosh.zig"493 "math/cosh.zig"
...@@ -501,33 +524,12 @@ set(ZIG_STD_FILES...@@ -501,33 +524,12 @@ set(ZIG_STD_FILES
501 "math/tan.zig"524 "math/tan.zig"
502 "math/tanh.zig"525 "math/tanh.zig"
503 "math/trunc.zig"526 "math/trunc.zig"
504 "math/complex/abs.zig"
505 "math/complex/acosh.zig"
506 "math/complex/acos.zig"
507 "math/complex/arg.zig"
508 "math/complex/asinh.zig"
509 "math/complex/asin.zig"
510 "math/complex/atanh.zig"
511 "math/complex/atan.zig"
512 "math/complex/conj.zig"
513 "math/complex/cosh.zig"
514 "math/complex/cos.zig"
515 "math/complex/exp.zig"
516 "math/complex/index.zig"
517 "math/complex/ldexp.zig"
518 "math/complex/log.zig"
519 "math/complex/pow.zig"
520 "math/complex/proj.zig"
521 "math/complex/sinh.zig"
522 "math/complex/sin.zig"
523 "math/complex/sqrt.zig"
524 "math/complex/tanh.zig"
525 "math/complex/tan.zig"
526 "mem.zig"527 "mem.zig"
527 "net.zig"528 "net.zig"
528 "os/child_process.zig"529 "os/child_process.zig"
529 "os/darwin.zig"530 "os/darwin.zig"
530 "os/darwin_errno.zig"531 "os/darwin_errno.zig"
532 "os/epoch.zig"
531 "os/file.zig"533 "os/file.zig"
532 "os/get_user_id.zig"534 "os/get_user_id.zig"
533 "os/index.zig"535 "os/index.zig"
...@@ -537,13 +539,13 @@ set(ZIG_STD_FILES...@@ -537,13 +539,13 @@ set(ZIG_STD_FILES
537 "os/linux/x86_64.zig"539 "os/linux/x86_64.zig"
538 "os/path.zig"540 "os/path.zig"
539 "os/time.zig"541 "os/time.zig"
540 "os/epoch.zig"
541 "os/windows/error.zig"542 "os/windows/error.zig"
542 "os/windows/index.zig"543 "os/windows/index.zig"
543 "os/windows/util.zig"544 "os/windows/util.zig"
544 "os/zen.zig"545 "os/zen.zig"
545 "rand/index.zig"546 "rand/index.zig"
546 "rand/ziggurat.zig"547 "rand/ziggurat.zig"
548 "segmented_list.zig"
547 "sort.zig"549 "sort.zig"
548 "special/bootstrap.zig"550 "special/bootstrap.zig"
549 "special/bootstrap_lib.zig"551 "special/bootstrap_lib.zig"
doc/langref.html.in+388-5
...@@ -4809,6 +4809,182 @@ pub const TypeId = enum {...@@ -4809,6 +4809,182 @@ pub const TypeId = enum {
4809 BoundFn,4809 BoundFn,
4810 ArgTuple,4810 ArgTuple,
4811 Opaque,4811 Opaque,
4812};
4813 {#code_end#}
4814 {#header_close#}
4815 {#header_open|@typeInfo#}
4816 <pre><code class="zig">@typeInfo(comptime T: type) -&gt; @import("builtin").TypeInfo</code></pre>
4817 <p>
4818 Returns information on the type. Returns a value of the following union:
4819 </p>
4820 {#code_begin|syntax#}
4821pub const TypeInfo = union(TypeId) {
4822 Type: void,
4823 Void: void,
4824 Bool: void,
4825 NoReturn: void,
4826 Int: Int,
4827 Float: Float,
4828 Pointer: Pointer,
4829 Array: Array,
4830 Struct: Struct,
4831 FloatLiteral: void,
4832 IntLiteral: void,
4833 UndefinedLiteral: void,
4834 NullLiteral: void,
4835 Nullable: Nullable,
4836 ErrorUnion: ErrorUnion,
4837 ErrorSet: ErrorSet,
4838 Enum: Enum,
4839 Union: Union,
4840 Fn: Fn,
4841 Namespace: void,
4842 Block: void,
4843 BoundFn: Fn,
4844 ArgTuple: void,
4845 Opaque: void,
4846 Promise: Promise,
4847
4848
4849 pub const Int = struct {
4850 is_signed: bool,
4851 bits: u8,
4852 };
4853
4854 pub const Float = struct {
4855 bits: u8,
4856 };
4857
4858 pub const Pointer = struct {
4859 is_const: bool,
4860 is_volatile: bool,
4861 alignment: u32,
4862 child: type,
4863 };
4864
4865 pub const Array = struct {
4866 len: usize,
4867 child: type,
4868 };
4869
4870 pub const ContainerLayout = enum {
4871 Auto,
4872 Extern,
4873 Packed,
4874 };
4875
4876 pub const StructField = struct {
4877 name: []const u8,
4878 offset: ?usize,
4879 field_type: type,
4880 };
4881
4882 pub const Struct = struct {
4883 layout: ContainerLayout,
4884 fields: []StructField,
4885 defs: []Definition,
4886 };
4887
4888 pub const Nullable = struct {
4889 child: type,
4890 };
4891
4892 pub const ErrorUnion = struct {
4893 error_set: type,
4894 payload: type,
4895 };
4896
4897 pub const Error = struct {
4898 name: []const u8,
4899 value: usize,
4900 };
4901
4902 pub const ErrorSet = struct {
4903 errors: []Error,
4904 };
4905
4906 pub const EnumField = struct {
4907 name: []const u8,
4908 value: usize,
4909 };
4910
4911 pub const Enum = struct {
4912 layout: ContainerLayout,
4913 tag_type: type,
4914 fields: []EnumField,
4915 defs: []Definition,
4916 };
4917
4918 pub const UnionField = struct {
4919 name: []const u8,
4920 enum_field: ?EnumField,
4921 field_type: type,
4922 };
4923
4924 pub const Union = struct {
4925 layout: ContainerLayout,
4926 tag_type: type,
4927 fields: []UnionField,
4928 defs: []Definition,
4929 };
4930
4931 pub const CallingConvention = enum {
4932 Unspecified,
4933 C,
4934 Cold,
4935 Naked,
4936 Stdcall,
4937 Async,
4938 };
4939
4940 pub const FnArg = struct {
4941 is_generic: bool,
4942 is_noalias: bool,
4943 arg_type: type,
4944 };
4945
4946 pub const Fn = struct {
4947 calling_convention: CallingConvention,
4948 is_generic: bool,
4949 is_var_args: bool,
4950 return_type: type,
4951 async_allocator_type: type,
4952 args: []FnArg,
4953 };
4954
4955 pub const Promise = struct {
4956 child: type,
4957 };
4958
4959 pub const Definition = struct {
4960 name: []const u8,
4961 is_pub: bool,
4962 data: Data,
4963
4964 pub const Data = union(enum) {
4965 Type: type,
4966 Var: type,
4967 Fn: FnDef,
4968
4969 pub const FnDef = struct {
4970 fn_type: type,
4971 inline_type: Inline,
4972 calling_convention: CallingConvention,
4973 is_var_args: bool,
4974 is_extern: bool,
4975 is_export: bool,
4976 lib_name: ?[]const u8,
4977 return_type: type,
4978 arg_names: [][] const u8,
4979
4980 pub const Inline = enum {
4981 Auto,
4982 Always,
4983 Never,
4984 };
4985 };
4986 };
4987 };
4812};4988};
4813 {#code_end#}4989 {#code_end#}
4814 {#header_close#}4990 {#header_close#}
...@@ -5226,7 +5402,6 @@ pub const Os = enum {...@@ -5226,7 +5402,6 @@ pub const Os = enum {
5226 rtems,5402 rtems,
5227 nacl,5403 nacl,
5228 cnk,5404 cnk,
5229 bitrig,
5230 aix,5405 aix,
5231 cuda,5406 cuda,
5232 nvcl,5407 nvcl,
...@@ -5237,10 +5412,12 @@ pub const Os = enum {...@@ -5237,10 +5412,12 @@ pub const Os = enum {
5237 watchos,5412 watchos,
5238 mesa3d,5413 mesa3d,
5239 contiki,5414 contiki,
5415 amdpal,
5240 zen,5416 zen,
5241};5417};
52425418
5243pub const Arch = enum {5419pub const Arch = enum {
5420 armv8_3a,
5244 armv8_2a,5421 armv8_2a,
5245 armv8_1a,5422 armv8_1a,
5246 armv8,5423 armv8,
...@@ -5260,9 +5437,29 @@ pub const Arch = enum {...@@ -5260,9 +5437,29 @@ pub const Arch = enum {
5260 armv5,5437 armv5,
5261 armv5te,5438 armv5te,
5262 armv4t,5439 armv4t,
5263 armeb,5440 armebv8_3a,
5441 armebv8_2a,
5442 armebv8_1a,
5443 armebv8,
5444 armebv8r,
5445 armebv8m_baseline,
5446 armebv8m_mainline,
5447 armebv7,
5448 armebv7em,
5449 armebv7m,
5450 armebv7s,
5451 armebv7k,
5452 armebv7ve,
5453 armebv6,
5454 armebv6m,
5455 armebv6k,
5456 armebv6t2,
5457 armebv5,
5458 armebv5te,
5459 armebv4t,
5264 aarch64,5460 aarch64,
5265 aarch64_be,5461 aarch64_be,
5462 arc,
5266 avr,5463 avr,
5267 bpfel,5464 bpfel,
5268 bpfeb,5465 bpfeb,
...@@ -5315,6 +5512,7 @@ pub const Arch = enum {...@@ -5315,6 +5512,7 @@ pub const Arch = enum {
5315pub const Environ = enum {5512pub const Environ = enum {
5316 unknown,5513 unknown,
5317 gnu,5514 gnu,
5515 gnuabin32,
5318 gnuabi64,5516 gnuabi64,
5319 gnueabi,5517 gnueabi,
5320 gnueabihf,5518 gnueabihf,
...@@ -5332,6 +5530,7 @@ pub const Environ = enum {...@@ -5332,6 +5530,7 @@ pub const Environ = enum {
5332 amdopencl,5530 amdopencl,
5333 coreclr,5531 coreclr,
5334 opencl,5532 opencl,
5533 simulator,
5335};5534};
53365535
5337pub const ObjectFormat = enum {5536pub const ObjectFormat = enum {
...@@ -5358,10 +5557,23 @@ pub const AtomicOrder = enum {...@@ -5358,10 +5557,23 @@ pub const AtomicOrder = enum {
5358 SeqCst,5557 SeqCst,
5359};5558};
53605559
5560pub const AtomicRmwOp = enum {
5561 Xchg,
5562 Add,
5563 Sub,
5564 And,
5565 Nand,
5566 Or,
5567 Xor,
5568 Max,
5569 Min,
5570};
5571
5361pub const Mode = enum {5572pub const Mode = enum {
5362 Debug,5573 Debug,
5363 ReleaseSafe,5574 ReleaseSafe,
5364 ReleaseFast,5575 ReleaseFast,
5576 ReleaseSmall,
5365};5577};
53665578
5367pub const TypeId = enum {5579pub const TypeId = enum {
...@@ -5380,7 +5592,7 @@ pub const TypeId = enum {...@@ -5380,7 +5592,7 @@ pub const TypeId = enum {
5380 NullLiteral,5592 NullLiteral,
5381 Nullable,5593 Nullable,
5382 ErrorUnion,5594 ErrorUnion,
5383 Error,5595 ErrorSet,
5384 Enum,5596 Enum,
5385 Union,5597 Union,
5386 Fn,5598 Fn,
...@@ -5389,6 +5601,176 @@ pub const TypeId = enum {...@@ -5389,6 +5601,176 @@ pub const TypeId = enum {
5389 BoundFn,5601 BoundFn,
5390 ArgTuple,5602 ArgTuple,
5391 Opaque,5603 Opaque,
5604 Promise,
5605};
5606
5607pub const TypeInfo = union(TypeId) {
5608 Type: void,
5609 Void: void,
5610 Bool: void,
5611 NoReturn: void,
5612 Int: Int,
5613 Float: Float,
5614 Pointer: Pointer,
5615 Array: Array,
5616 Struct: Struct,
5617 FloatLiteral: void,
5618 IntLiteral: void,
5619 UndefinedLiteral: void,
5620 NullLiteral: void,
5621 Nullable: Nullable,
5622 ErrorUnion: ErrorUnion,
5623 ErrorSet: ErrorSet,
5624 Enum: Enum,
5625 Union: Union,
5626 Fn: Fn,
5627 Namespace: void,
5628 Block: void,
5629 BoundFn: Fn,
5630 ArgTuple: void,
5631 Opaque: void,
5632 Promise: Promise,
5633
5634
5635 pub const Int = struct {
5636 is_signed: bool,
5637 bits: u8,
5638 };
5639
5640 pub const Float = struct {
5641 bits: u8,
5642 };
5643
5644 pub const Pointer = struct {
5645 is_const: bool,
5646 is_volatile: bool,
5647 alignment: u32,
5648 child: type,
5649 };
5650
5651 pub const Array = struct {
5652 len: usize,
5653 child: type,
5654 };
5655
5656 pub const ContainerLayout = enum {
5657 Auto,
5658 Extern,
5659 Packed,
5660 };
5661
5662 pub const StructField = struct {
5663 name: []const u8,
5664 offset: ?usize,
5665 field_type: type,
5666 };
5667
5668 pub const Struct = struct {
5669 layout: ContainerLayout,
5670 fields: []StructField,
5671 defs: []Definition,
5672 };
5673
5674 pub const Nullable = struct {
5675 child: type,
5676 };
5677
5678 pub const ErrorUnion = struct {
5679 error_set: type,
5680 payload: type,
5681 };
5682
5683 pub const Error = struct {
5684 name: []const u8,
5685 value: usize,
5686 };
5687
5688 pub const ErrorSet = struct {
5689 errors: []Error,
5690 };
5691
5692 pub const EnumField = struct {
5693 name: []const u8,
5694 value: usize,
5695 };
5696
5697 pub const Enum = struct {
5698 layout: ContainerLayout,
5699 tag_type: type,
5700 fields: []EnumField,
5701 defs: []Definition,
5702 };
5703
5704 pub const UnionField = struct {
5705 name: []const u8,
5706 enum_field: ?EnumField,
5707 field_type: type,
5708 };
5709
5710 pub const Union = struct {
5711 layout: ContainerLayout,
5712 tag_type: type,
5713 fields: []UnionField,
5714 defs: []Definition,
5715 };
5716
5717 pub const CallingConvention = enum {
5718 Unspecified,
5719 C,
5720 Cold,
5721 Naked,
5722 Stdcall,
5723 Async,
5724 };
5725
5726 pub const FnArg = struct {
5727 is_generic: bool,
5728 is_noalias: bool,
5729 arg_type: type,
5730 };
5731
5732 pub const Fn = struct {
5733 calling_convention: CallingConvention,
5734 is_generic: bool,
5735 is_var_args: bool,
5736 return_type: type,
5737 async_allocator_type: type,
5738 args: []FnArg,
5739 };
5740
5741 pub const Promise = struct {
5742 child: type,
5743 };
5744
5745 pub const Definition = struct {
5746 name: []const u8,
5747 is_pub: bool,
5748 data: Data,
5749
5750 pub const Data = union(enum) {
5751 Type: type,
5752 Var: type,
5753 Fn: FnDef,
5754
5755 pub const FnDef = struct {
5756 fn_type: type,
5757 inline_type: Inline,
5758 calling_convention: CallingConvention,
5759 is_var_args: bool,
5760 is_extern: bool,
5761 is_export: bool,
5762 lib_name: ?[]const u8,
5763 return_type: type,
5764 arg_names: [][] const u8,
5765
5766 pub const Inline = enum {
5767 Auto,
5768 Always,
5769 Never,
5770 };
5771 };
5772 };
5773 };
5392};5774};
53935775
5394pub const FloatMode = enum {5776pub const FloatMode = enum {
...@@ -5402,7 +5784,7 @@ pub const Endian = enum {...@@ -5402,7 +5784,7 @@ pub const Endian = enum {
5402};5784};
54035785
5404pub const endian = Endian.Little;5786pub const endian = Endian.Little;
5405pub const is_test = false;5787pub const is_test = true;
5406pub const os = Os.linux;5788pub const os = Os.linux;
5407pub const arch = Arch.x86_64;5789pub const arch = Arch.x86_64;
5408pub const environ = Environ.gnu;5790pub const environ = Environ.gnu;
...@@ -5410,6 +5792,7 @@ pub const object_format = ObjectFormat.elf;...@@ -5410,6 +5792,7 @@ pub const object_format = ObjectFormat.elf;
5410pub const mode = Mode.Debug;5792pub const mode = Mode.Debug;
5411pub const link_libc = false;5793pub const link_libc = false;
5412pub const have_error_return_tracing = true;5794pub const have_error_return_tracing = true;
5795pub const __zig_test_fn_slice = {}; // overwritten later
5413 {#code_end#}5796 {#code_end#}
5414 {#see_also|Build Mode#}5797 {#see_also|Build Mode#}
5415 {#header_close#}5798 {#header_close#}
...@@ -6070,7 +6453,7 @@ hljs.registerLanguage("zig", function(t) {...@@ -6070,7 +6453,7 @@ hljs.registerLanguage("zig", function(t) {
6070 a = t.IR + "\\s*\\(",6453 a = t.IR + "\\s*\\(",
6071 c = {6454 c = {
6072 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",6455 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
6073 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field",6456 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo",
6074 literal: "true false null undefined"6457 literal: "true false null undefined"
6075 },6458 },
6076 n = [e, t.CLCM, t.CBCM, s, r];6459 n = [e, t.CLCM, t.CBCM, s, r];
src/all_types.hpp+9
...@@ -1298,6 +1298,7 @@ enum BuiltinFnId {...@@ -1298,6 +1298,7 @@ enum BuiltinFnId {
1298 BuiltinFnIdMemberType,1298 BuiltinFnIdMemberType,
1299 BuiltinFnIdMemberName,1299 BuiltinFnIdMemberName,
1300 BuiltinFnIdField,1300 BuiltinFnIdField,
1301 BuiltinFnIdTypeInfo,
1301 BuiltinFnIdTypeof,1302 BuiltinFnIdTypeof,
1302 BuiltinFnIdAddWithOverflow,1303 BuiltinFnIdAddWithOverflow,
1303 BuiltinFnIdSubWithOverflow,1304 BuiltinFnIdSubWithOverflow,
...@@ -1511,6 +1512,7 @@ struct CodeGen {...@@ -1511,6 +1512,7 @@ struct CodeGen {
1511 HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names;1512 HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names;
1512 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;1513 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
1513 HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;1514 HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
1515 HashMap<const TypeTableEntry *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
15141516
15151517
1516 ZigList<ImportTableEntry *> import_queue;1518 ZigList<ImportTableEntry *> import_queue;
...@@ -2042,6 +2044,7 @@ enum IrInstructionId {...@@ -2042,6 +2044,7 @@ enum IrInstructionId {
2042 IrInstructionIdTagType,2044 IrInstructionIdTagType,
2043 IrInstructionIdFieldParentPtr,2045 IrInstructionIdFieldParentPtr,
2044 IrInstructionIdOffsetOf,2046 IrInstructionIdOffsetOf,
2047 IrInstructionIdTypeInfo,
2045 IrInstructionIdTypeId,2048 IrInstructionIdTypeId,
2046 IrInstructionIdSetEvalBranchQuota,2049 IrInstructionIdSetEvalBranchQuota,
2047 IrInstructionIdPtrTypeOf,2050 IrInstructionIdPtrTypeOf,
...@@ -2863,6 +2866,12 @@ struct IrInstructionOffsetOf {...@@ -2863,6 +2866,12 @@ struct IrInstructionOffsetOf {
2863 IrInstruction *field_name;2866 IrInstruction *field_name;
2864};2867};
28652868
2869struct IrInstructionTypeInfo {
2870 IrInstruction base;
2871
2872 IrInstruction *type_value;
2873};
2874
2866struct IrInstructionTypeId {2875struct IrInstructionTypeId {
2867 IrInstruction base;2876 IrInstruction base;
28682877
src/analyze.cpp+11-3
...@@ -2325,8 +2325,14 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {...@@ -2325,8 +2325,14 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
2325 HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};2325 HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
2326 occupied_tag_values.init(field_count);2326 occupied_tag_values.init(field_count);
23272327
2328 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);2328 TypeTableEntry *tag_int_type;
2329 if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
2330 tag_int_type = get_c_int_type(g, CIntTypeInt);
2331 } else {
2332 tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
2333 }
23292334
2335 // TODO: Are extern enums allowed to have an init_arg_expr?
2330 if (decl_node->data.container_decl.init_arg_expr != nullptr) {2336 if (decl_node->data.container_decl.init_arg_expr != nullptr) {
2331 TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);2337 TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
2332 if (type_is_invalid(wanted_tag_int_type)) {2338 if (type_is_invalid(wanted_tag_int_type)) {
...@@ -5926,8 +5932,8 @@ size_t type_id_len() {...@@ -5926,8 +5932,8 @@ size_t type_id_len() {
5926 return array_length(all_type_ids);5932 return array_length(all_type_ids);
5927}5933}
59285934
5929size_t type_id_index(TypeTableEntryId id) {5935size_t type_id_index(TypeTableEntry *entry) {
5930 switch (id) {5936 switch (entry->id) {
5931 case TypeTableEntryIdInvalid:5937 case TypeTableEntryIdInvalid:
5932 zig_unreachable();5938 zig_unreachable();
5933 case TypeTableEntryIdMetaType:5939 case TypeTableEntryIdMetaType:
...@@ -5947,6 +5953,8 @@ size_t type_id_index(TypeTableEntryId id) {...@@ -5947,6 +5953,8 @@ size_t type_id_index(TypeTableEntryId id) {
5947 case TypeTableEntryIdArray:5953 case TypeTableEntryIdArray:
5948 return 7;5954 return 7;
5949 case TypeTableEntryIdStruct:5955 case TypeTableEntryIdStruct:
5956 if (entry->data.structure.is_slice)
5957 return 25;
5950 return 8;5958 return 8;
5951 case TypeTableEntryIdNumLitFloat:5959 case TypeTableEntryIdNumLitFloat:
5952 return 9;5960 return 9;
src/analyze.hpp+1-1
...@@ -174,7 +174,7 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);...@@ -174,7 +174,7 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);
174const char *type_id_name(TypeTableEntryId id);174const char *type_id_name(TypeTableEntryId id);
175TypeTableEntryId type_id_at_index(size_t index);175TypeTableEntryId type_id_at_index(size_t index);
176size_t type_id_len();176size_t type_id_len();
177size_t type_id_index(TypeTableEntryId id);177size_t type_id_index(TypeTableEntry *entry);
178TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);178TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);
179bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);179bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);
180LinkLib *create_link_lib(Buf *name);180LinkLib *create_link_lib(Buf *name);
src/ast_render.cpp+1-1
...@@ -736,7 +736,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -736,7 +736,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
736 render_node_grouped(ar, field_node->data.struct_field.type);736 render_node_grouped(ar, field_node->data.struct_field.type);
737 }737 }
738 if (field_node->data.struct_field.value != nullptr) {738 if (field_node->data.struct_field.value != nullptr) {
739 fprintf(ar->f, "= ");739 fprintf(ar->f, " = ");
740 render_node_grouped(ar, field_node->data.struct_field.value);740 render_node_grouped(ar, field_node->data.struct_field.value);
741 }741 }
742 fprintf(ar->f, ",\n");742 fprintf(ar->f, ",\n");
src/bigint.cpp+4-6
...@@ -1259,12 +1259,11 @@ void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2) {...@@ -1259,12 +1259,11 @@ void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2) {
1259 bigint_normalize(dest);1259 bigint_normalize(dest);
1260 return;1260 return;
1261 }1261 }
1262 // TODO this code path is untested1262
1263 uint64_t first_digit = dest->data.digit;
1264 dest->digit_count = max(op1->digit_count, op2->digit_count);1263 dest->digit_count = max(op1->digit_count, op2->digit_count);
1265 dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count);1264 dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count);
1266 dest->data.digits[0] = first_digit;1265
1267 size_t i = 1;1266 size_t i = 0;
1268 for (; i < op1->digit_count && i < op2->digit_count; i += 1) {1267 for (; i < op1->digit_count && i < op2->digit_count; i += 1) {
1269 dest->data.digits[i] = op1_digits[i] & op2_digits[i];1268 dest->data.digits[i] = op1_digits[i] & op2_digits[i];
1270 }1269 }
...@@ -1412,7 +1411,6 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) {...@@ -1412,7 +1411,6 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) {
1412 return;1411 return;
1413 }1412 }
14141413
1415 // TODO this code path is untested
1416 size_t digit_shift_count = shift_amt / 64;1414 size_t digit_shift_count = shift_amt / 64;
1417 size_t leftover_shift_count = shift_amt % 64;1415 size_t leftover_shift_count = shift_amt % 64;
14181416
...@@ -1427,7 +1425,7 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) {...@@ -1427,7 +1425,7 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) {
1427 uint64_t digit = op1_digits[op_digit_index];1425 uint64_t digit = op1_digits[op_digit_index];
1428 size_t dest_digit_index = op_digit_index - digit_shift_count;1426 size_t dest_digit_index = op_digit_index - digit_shift_count;
1429 dest->data.digits[dest_digit_index] = carry | (digit >> leftover_shift_count);1427 dest->data.digits[dest_digit_index] = carry | (digit >> leftover_shift_count);
1430 carry = (0xffffffffffffffffULL << leftover_shift_count) & digit;1428 carry = digit << leftover_shift_count;
14311429
1432 if (dest_digit_index == 0) { break; }1430 if (dest_digit_index == 0) { break; }
1433 op_digit_index -= 1;1431 op_digit_index -= 1;
src/codegen.cpp+191
...@@ -88,6 +88,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out...@@ -88,6 +88,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
88 g->exported_symbol_names.init(8);88 g->exported_symbol_names.init(8);
89 g->external_prototypes.init(8);89 g->external_prototypes.init(8);
90 g->string_literals_table.init(16);90 g->string_literals_table.init(16);
91 g->type_info_cache.init(32);
91 g->is_test_build = false;92 g->is_test_build = false;
92 g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);93 g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
93 buf_resize(&g->global_asm, 0);94 buf_resize(&g->global_asm, 0);
...@@ -4502,6 +4503,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4502,6 +4503,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4502 case IrInstructionIdDeclRef:4503 case IrInstructionIdDeclRef:
4503 case IrInstructionIdSwitchVar:4504 case IrInstructionIdSwitchVar:
4504 case IrInstructionIdOffsetOf:4505 case IrInstructionIdOffsetOf:
4506 case IrInstructionIdTypeInfo:
4505 case IrInstructionIdTypeId:4507 case IrInstructionIdTypeId:
4506 case IrInstructionIdSetEvalBranchQuota:4508 case IrInstructionIdSetEvalBranchQuota:
4507 case IrInstructionIdPtrTypeOf:4509 case IrInstructionIdPtrTypeOf:
...@@ -6125,6 +6127,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -6125,6 +6127,7 @@ static void define_builtin_fns(CodeGen *g) {
6125 create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);6127 create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
6126 create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);6128 create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);
6127 create_builtin_fn(g, BuiltinFnIdField, "field", 2);6129 create_builtin_fn(g, BuiltinFnIdField, "field", 2);
6130 create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1);
6128 create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf6131 create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
6129 create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);6132 create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
6130 create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);6133 create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
...@@ -6342,8 +6345,196 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -6342,8 +6345,196 @@ static void define_builtin_compile_vars(CodeGen *g) {
6342 const TypeTableEntryId id = type_id_at_index(i);6345 const TypeTableEntryId id = type_id_at_index(i);
6343 buf_appendf(contents, " %s,\n", type_id_name(id));6346 buf_appendf(contents, " %s,\n", type_id_name(id));
6344 }6347 }
6348 buf_appendf(contents, " Slice,\n");
6345 buf_appendf(contents, "};\n\n");6349 buf_appendf(contents, "};\n\n");
6346 }6350 }
6351 {
6352 buf_appendf(contents,
6353 "pub const TypeInfo = union(TypeId) {\n"
6354 " Type: void,\n"
6355 " Void: void,\n"
6356 " Bool: void,\n"
6357 " NoReturn: void,\n"
6358 " Int: Int,\n"
6359 " Float: Float,\n"
6360 " Pointer: Pointer,\n"
6361 " Slice: Slice,\n"
6362 " Array: Array,\n"
6363 " Struct: Struct,\n"
6364 " FloatLiteral: void,\n"
6365 " IntLiteral: void,\n"
6366 " UndefinedLiteral: void,\n"
6367 " NullLiteral: void,\n"
6368 " Nullable: Nullable,\n"
6369 " ErrorUnion: ErrorUnion,\n"
6370 " ErrorSet: ErrorSet,\n"
6371 " Enum: Enum,\n"
6372 " Union: Union,\n"
6373 " Fn: Fn,\n"
6374 " Namespace: void,\n"
6375 " Block: void,\n"
6376 " BoundFn: Fn,\n"
6377 " ArgTuple: void,\n"
6378 " Opaque: void,\n"
6379 " Promise: Promise,\n"
6380 "\n\n"
6381 " pub const Int = struct {\n"
6382 " is_signed: bool,\n"
6383 " bits: u8,\n"
6384 " };\n"
6385 "\n"
6386 " pub const Float = struct {\n"
6387 " bits: u8,\n"
6388 " };\n"
6389 "\n"
6390 " pub const Pointer = struct {\n"
6391 " is_const: bool,\n"
6392 " is_volatile: bool,\n"
6393 " alignment: u32,\n"
6394 " child: type,\n"
6395 " };\n"
6396 "\n"
6397 " pub const Slice = Pointer;\n"
6398 "\n"
6399 " pub const Array = struct {\n"
6400 " len: usize,\n"
6401 " child: type,\n"
6402 " };\n"
6403 "\n"
6404 " pub const ContainerLayout = enum {\n"
6405 " Auto,\n"
6406 " Extern,\n"
6407 " Packed,\n"
6408 " };\n"
6409 "\n"
6410 " pub const StructField = struct {\n"
6411 " name: []const u8,\n"
6412 " offset: ?usize,\n"
6413 " field_type: type,\n"
6414 " };\n"
6415 "\n"
6416 " pub const Struct = struct {\n"
6417 " layout: ContainerLayout,\n"
6418 " fields: []StructField,\n"
6419 " defs: []Definition,\n"
6420 " };\n"
6421 "\n"
6422 " pub const Nullable = struct {\n"
6423 " child: type,\n"
6424 " };\n"
6425 "\n"
6426 " pub const ErrorUnion = struct {\n"
6427 " error_set: type,\n"
6428 " payload: type,\n"
6429 " };\n"
6430 "\n"
6431 " pub const Error = struct {\n"
6432 " name: []const u8,\n"
6433 " value: usize,\n"
6434 " };\n"
6435 "\n"
6436 " pub const ErrorSet = struct {\n"
6437 " errors: []Error,\n"
6438 " };\n"
6439 "\n"
6440 " pub const EnumField = struct {\n"
6441 " name: []const u8,\n"
6442 " value: usize,\n"
6443 " };\n"
6444 "\n"
6445 " pub const Enum = struct {\n"
6446 " layout: ContainerLayout,\n"
6447 " tag_type: type,\n"
6448 " fields: []EnumField,\n"
6449 " defs: []Definition,\n"
6450 " };\n"
6451 "\n"
6452 " pub const UnionField = struct {\n"
6453 " name: []const u8,\n"
6454 " enum_field: ?EnumField,\n"
6455 " field_type: type,\n"
6456 " };\n"
6457 "\n"
6458 " pub const Union = struct {\n"
6459 " layout: ContainerLayout,\n"
6460 " tag_type: type,\n"
6461 " fields: []UnionField,\n"
6462 " defs: []Definition,\n"
6463 " };\n"
6464 "\n"
6465 " pub const CallingConvention = enum {\n"
6466 " Unspecified,\n"
6467 " C,\n"
6468 " Cold,\n"
6469 " Naked,\n"
6470 " Stdcall,\n"
6471 " Async,\n"
6472 " };\n"
6473 "\n"
6474 " pub const FnArg = struct {\n"
6475 " is_generic: bool,\n"
6476 " is_noalias: bool,\n"
6477 " arg_type: type,\n"
6478 " };\n"
6479 "\n"
6480 " pub const Fn = struct {\n"
6481 " calling_convention: CallingConvention,\n"
6482 " is_generic: bool,\n"
6483 " is_var_args: bool,\n"
6484 " return_type: type,\n"
6485 " async_allocator_type: type,\n"
6486 " args: []FnArg,\n"
6487 " };\n"
6488 "\n"
6489 " pub const Promise = struct {\n"
6490 " child: type,\n"
6491 " };\n"
6492 "\n"
6493 " pub const Definition = struct {\n"
6494 " name: []const u8,\n"
6495 " is_pub: bool,\n"
6496 " data: Data,\n"
6497 "\n"
6498 " pub const Data = union(enum) {\n"
6499 " Type: type,\n"
6500 " Var: type,\n"
6501 " Fn: FnDef,\n"
6502 "\n"
6503 " pub const FnDef = struct {\n"
6504 " fn_type: type,\n"
6505 " inline_type: Inline,\n"
6506 " calling_convention: CallingConvention,\n"
6507 " is_var_args: bool,\n"
6508 " is_extern: bool,\n"
6509 " is_export: bool,\n"
6510 " lib_name: ?[]const u8,\n"
6511 " return_type: type,\n"
6512 " arg_names: [][] const u8,\n"
6513 "\n"
6514 " pub const Inline = enum {\n"
6515 " Auto,\n"
6516 " Always,\n"
6517 " Never,\n"
6518 " };\n"
6519 " };\n"
6520 " };\n"
6521 " };\n"
6522 "};\n\n");
6523 assert(ContainerLayoutAuto == 0);
6524 assert(ContainerLayoutExtern == 1);
6525 assert(ContainerLayoutPacked == 2);
6526
6527 assert(CallingConventionUnspecified == 0);
6528 assert(CallingConventionC == 1);
6529 assert(CallingConventionCold == 2);
6530 assert(CallingConventionNaked == 3);
6531 assert(CallingConventionStdcall == 4);
6532 assert(CallingConventionAsync == 5);
6533
6534 assert(FnInlineAuto == 0);
6535 assert(FnInlineAlways == 1);
6536 assert(FnInlineNever == 2);
6537 }
6347 {6538 {
6348 buf_appendf(contents,6539 buf_appendf(contents,
6349 "pub const FloatMode = enum {\n"6540 "pub const FloatMode = enum {\n"
src/ir.cpp+989-11
...@@ -145,6 +145,8 @@ static bool ir_should_inline(IrExecutable *exec, Scope *scope) {...@@ -145,6 +145,8 @@ static bool ir_should_inline(IrExecutable *exec, Scope *scope) {
145 while (scope != nullptr) {145 while (scope != nullptr) {
146 if (scope->id == ScopeIdCompTime)146 if (scope->id == ScopeIdCompTime)
147 return true;147 return true;
148 if (scope->id == ScopeIdFnDef)
149 break;
148 scope = scope->parent;150 scope = scope->parent;
149 }151 }
150 return false;152 return false;
...@@ -615,6 +617,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) {...@@ -615,6 +617,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) {
615 return IrInstructionIdOffsetOf;617 return IrInstructionIdOffsetOf;
616}618}
617619
620static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) {
621 return IrInstructionIdTypeInfo;
622}
623
618static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeId *) {624static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeId *) {
619 return IrInstructionIdTypeId;625 return IrInstructionIdTypeId;
620}626}
...@@ -2440,6 +2446,16 @@ static IrInstruction *ir_build_offset_of(IrBuilder *irb, Scope *scope, AstNode *...@@ -2440,6 +2446,16 @@ static IrInstruction *ir_build_offset_of(IrBuilder *irb, Scope *scope, AstNode *
2440 return &instruction->base;2446 return &instruction->base;
2441}2447}
24422448
2449static IrInstruction *ir_build_type_info(IrBuilder *irb, Scope *scope, AstNode *source_node,
2450 IrInstruction *type_value) {
2451 IrInstructionTypeInfo *instruction = ir_build_instruction<IrInstructionTypeInfo>(irb, scope, source_node);
2452 instruction->type_value = type_value;
2453
2454 ir_ref_instruction(type_value, irb->current_basic_block);
2455
2456 return &instruction->base;
2457}
2458
2443static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node,2459static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node,
2444 IrInstruction *type_value)2460 IrInstruction *type_value)
2445{2461{
...@@ -4083,6 +4099,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4083,6 +4099,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40834099
4084 return ir_build_load_ptr(irb, scope, node, ptr_instruction);4100 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
4085 }4101 }
4102 case BuiltinFnIdTypeInfo:
4103 {
4104 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4105 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4106 if (arg0_value == irb->codegen->invalid_instruction)
4107 return arg0_value;
4108
4109 IrInstruction *type_info = ir_build_type_info(irb, scope, node, arg0_value);
4110 return ir_lval_wrap(irb, scope, type_info, lval);
4111 }
4086 case BuiltinFnIdBreakpoint:4112 case BuiltinFnIdBreakpoint:
4087 return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval);4113 return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval);
4088 case BuiltinFnIdReturnAddress:4114 case BuiltinFnIdReturnAddress:
...@@ -13392,7 +13418,6 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,...@@ -13392,7 +13418,6 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
13392 return ira->codegen->invalid_instruction;13418 return ira->codegen->invalid_instruction;
13393}13419}
1339413420
13395
13396static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,13421static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
13397 IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type)13422 IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type)
13398{13423{
...@@ -13454,6 +13479,51 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_...@@ -13454,6 +13479,51 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
13454 } else if (bare_type->id == TypeTableEntryIdUnion) {13479 } else if (bare_type->id == TypeTableEntryIdUnion) {
13455 TypeUnionField *field = find_union_type_field(bare_type, field_name);13480 TypeUnionField *field = find_union_type_field(bare_type, field_name);
13456 if (field) {13481 if (field) {
13482 if (instr_is_comptime(container_ptr)) {
13483 ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
13484 if (!ptr_val)
13485 return ira->codegen->invalid_instruction;
13486
13487 if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
13488 ConstExprValue *union_val = const_ptr_pointee(ira->codegen, ptr_val);
13489 if (type_is_invalid(union_val->type))
13490 return ira->codegen->invalid_instruction;
13491
13492 TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag);
13493 if (actual_field == nullptr)
13494 zig_unreachable();
13495
13496 if (field != actual_field) {
13497 ir_add_error_node(ira, source_instr->source_node,
13498 buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name),
13499 buf_ptr(actual_field->name)));
13500 return ira->codegen->invalid_instruction;
13501 }
13502
13503 ConstExprValue *payload_val = union_val->data.x_union.payload;
13504
13505 TypeTableEntry *field_type = field->type_entry;
13506 if (field_type->id == TypeTableEntryIdVoid)
13507 {
13508 assert(payload_val == nullptr);
13509 payload_val = create_const_vals(1);
13510 payload_val->special = ConstValSpecialStatic;
13511 payload_val->type = field_type;
13512 }
13513
13514 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, is_const, is_volatile,
13515 get_abi_alignment(ira->codegen, field_type), 0, 0);
13516
13517 IrInstruction *result = ir_get_const(ira, source_instr);
13518 ConstExprValue *const_val = &result->value;
13519 const_val->data.x_ptr.special = ConstPtrSpecialRef;
13520 const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut;
13521 const_val->data.x_ptr.data.ref.pointee = payload_val;
13522 const_val->type = ptr_type;
13523 return result;
13524 }
13525 }
13526
13457 IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field);13527 IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field);
13458 result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,13528 result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
13459 get_abi_alignment(ira->codegen, field->type_entry), 0, 0);13529 get_abi_alignment(ira->codegen, field->type_entry), 0, 0);
...@@ -13672,7 +13742,16 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru...@@ -13672,7 +13742,16 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
13672 create_const_enum(child_type, &field->value), child_type,13742 create_const_enum(child_type, &field->value), child_type,
13673 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);13743 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
13674 }13744 }
13675 } else if (child_type->id == TypeTableEntryIdUnion &&13745 }
13746 ScopeDecls *container_scope = get_container_scope(child_type);
13747 if (container_scope != nullptr) {
13748 auto entry = container_scope->decl_table.maybe_get(field_name);
13749 Tld *tld = entry ? entry->value : nullptr;
13750 if (tld) {
13751 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
13752 }
13753 }
13754 if (child_type->id == TypeTableEntryIdUnion &&
13676 (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr ||13755 (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr ||
13677 child_type->data.unionation.decl_node->data.container_decl.auto_enum))13756 child_type->data.unionation.decl_node->data.container_decl.auto_enum))
13678 {13757 {
...@@ -13689,14 +13768,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru...@@ -13689,14 +13768,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
13689 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);13768 ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
13690 }13769 }
13691 }13770 }
13692 ScopeDecls *container_scope = get_container_scope(child_type);
13693 if (container_scope != nullptr) {
13694 auto entry = container_scope->decl_table.maybe_get(field_name);
13695 Tld *tld = entry ? entry->value : nullptr;
13696 if (tld) {
13697 return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
13698 }
13699 }
13700 ir_add_error(ira, &field_ptr_instruction->base,13771 ir_add_error(ira, &field_ptr_instruction->base,
13701 buf_sprintf("container '%s' has no member called '%s'",13772 buf_sprintf("container '%s' has no member called '%s'",
13702 buf_ptr(&child_type->name), buf_ptr(field_name)));13773 buf_ptr(&child_type->name), buf_ptr(field_name)));
...@@ -15683,6 +15754,910 @@ static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira,...@@ -15683,6 +15754,910 @@ static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira,
15683 return ira->codegen->builtin_types.entry_num_lit_int;15754 return ira->codegen->builtin_types.entry_num_lit_int;
15684}15755}
1568515756
15757static void ensure_field_index(TypeTableEntry *type, const char *field_name, size_t index)
15758{
15759 Buf *field_name_buf;
15760
15761 assert(type != nullptr && !type_is_invalid(type));
15762 // Check for our field by creating a buffer in place then using the comma operator to free it so that we don't
15763 // leak memory in debug mode.
15764 assert(find_struct_type_field(type, field_name_buf = buf_create_from_str(field_name))->src_index == index &&
15765 (buf_deinit(field_name_buf), true));
15766}
15767
15768static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, TypeTableEntry *root = nullptr)
15769{
15770 static ConstExprValue *type_info_var = nullptr;
15771 static TypeTableEntry *type_info_type = nullptr;
15772 if (type_info_var == nullptr)
15773 {
15774 type_info_var = get_builtin_value(ira->codegen, "TypeInfo");
15775 assert(type_info_var->type->id == TypeTableEntryIdMetaType);
15776
15777 ensure_complete_type(ira->codegen, type_info_var->data.x_type);
15778 type_info_type = type_info_var->data.x_type;
15779 assert(type_info_type->id == TypeTableEntryIdUnion);
15780 }
15781
15782 if (type_name == nullptr && root == nullptr)
15783 return type_info_type;
15784 else if (type_name == nullptr)
15785 return root;
15786
15787 TypeTableEntry *root_type = (root == nullptr) ? type_info_type : root;
15788
15789 ScopeDecls *type_info_scope = get_container_scope(root_type);
15790 assert(type_info_scope != nullptr);
15791
15792 Buf field_name = BUF_INIT;
15793 buf_init_from_str(&field_name, type_name);
15794 auto entry = type_info_scope->decl_table.get(&field_name);
15795 buf_deinit(&field_name);
15796
15797 TldVar *tld = (TldVar *)entry;
15798 assert(tld->base.id == TldIdVar);
15799
15800 VariableTableEntry *var = tld->var;
15801
15802 ensure_complete_type(ira->codegen, var->value->type);
15803 assert(var->value->type->id == TypeTableEntryIdMetaType);
15804 return var->value->data.x_type;
15805}
15806
15807static void ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope)
15808{
15809 TypeTableEntry *type_info_definition_type = ir_type_info_get_type(ira, "Definition");
15810 ensure_complete_type(ira->codegen, type_info_definition_type);
15811 ensure_field_index(type_info_definition_type, "name", 0);
15812 ensure_field_index(type_info_definition_type, "is_pub", 1);
15813 ensure_field_index(type_info_definition_type, "data", 2);
15814
15815 TypeTableEntry *type_info_definition_data_type = ir_type_info_get_type(ira, "Data", type_info_definition_type);
15816 ensure_complete_type(ira->codegen, type_info_definition_data_type);
15817
15818 TypeTableEntry *type_info_fn_def_type = ir_type_info_get_type(ira, "FnDef", type_info_definition_data_type);
15819 ensure_complete_type(ira->codegen, type_info_fn_def_type);
15820
15821 TypeTableEntry *type_info_fn_def_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_def_type);
15822 ensure_complete_type(ira->codegen, type_info_fn_def_inline_type);
15823
15824 // Loop through our definitions once to figure out how many definitions we will generate info for.
15825 auto decl_it = decls_scope->decl_table.entry_iterator();
15826 decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr;
15827 int definition_count = 0;
15828
15829 while ((curr_entry = decl_it.next()) != nullptr)
15830 {
15831 // If the definition is unresolved, force it to be resolved again.
15832 if (curr_entry->value->resolution == TldResolutionUnresolved)
15833 {
15834 resolve_top_level_decl(ira->codegen, curr_entry->value, false, curr_entry->value->source_node);
15835 if (curr_entry->value->resolution != TldResolutionOk)
15836 {
15837 return;
15838 }
15839 }
15840
15841 // Skip comptime blocks and test functions.
15842 if (curr_entry->value->id != TldIdCompTime)
15843 {
15844 if (curr_entry->value->id == TldIdFn)
15845 {
15846 FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
15847 if (fn_entry->is_test)
15848 continue;
15849 }
15850
15851 definition_count += 1;
15852 }
15853 }
15854
15855 ConstExprValue *definition_array = create_const_vals(1);
15856 definition_array->special = ConstValSpecialStatic;
15857 definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count);
15858 definition_array->data.x_array.special = ConstArraySpecialNone;
15859 definition_array->data.x_array.s_none.parent.id = ConstParentIdNone;
15860 definition_array->data.x_array.s_none.elements = create_const_vals(definition_count);
15861 init_const_slice(ira->codegen, out_val, definition_array, 0, definition_count, false);
15862
15863 // Loop through the definitions and generate info.
15864 decl_it = decls_scope->decl_table.entry_iterator();
15865 curr_entry = nullptr;
15866 int definition_index = 0;
15867 while ((curr_entry = decl_it.next()) != nullptr)
15868 {
15869 // Skip comptime blocks and test functions.
15870 if (curr_entry->value->id == TldIdCompTime)
15871 continue;
15872 else if (curr_entry->value->id == TldIdFn)
15873 {
15874 FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
15875 if (fn_entry->is_test)
15876 continue;
15877 }
15878
15879 ConstExprValue *definition_val = &definition_array->data.x_array.s_none.elements[definition_index];
15880
15881 definition_val->special = ConstValSpecialStatic;
15882 definition_val->type = type_info_definition_type;
15883
15884 ConstExprValue *inner_fields = create_const_vals(3);
15885 ConstExprValue *name = create_const_str_lit(ira->codegen, curr_entry->key);
15886 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(curr_entry->key), true);
15887 inner_fields[1].special = ConstValSpecialStatic;
15888 inner_fields[1].type = ira->codegen->builtin_types.entry_bool;
15889 inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub;
15890 inner_fields[2].special = ConstValSpecialStatic;
15891 inner_fields[2].type = type_info_definition_data_type;
15892 inner_fields[2].data.x_union.parent.id = ConstParentIdStruct;
15893 inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val;
15894 inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1;
15895
15896 switch (curr_entry->value->id)
15897 {
15898 case TldIdVar:
15899 {
15900 VariableTableEntry *var = ((TldVar *)curr_entry->value)->var;
15901 ensure_complete_type(ira->codegen, var->value->type);
15902 if (var->value->type->id == TypeTableEntryIdMetaType)
15903 {
15904 // We have a variable of type 'type', so it's actually a type definition.
15905 // 0: Data.Type: type
15906 bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0);
15907 inner_fields[2].data.x_union.payload = var->value;
15908 }
15909 else
15910 {
15911 // We have a variable of another type, so we store the type of the variable.
15912 // 1: Data.Var: type
15913 bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 1);
15914
15915 ConstExprValue *payload = create_const_vals(1);
15916 payload->type = ira->codegen->builtin_types.entry_type;
15917 payload->data.x_type = var->value->type;
15918
15919 inner_fields[2].data.x_union.payload = payload;
15920 }
15921
15922 break;
15923 }
15924 case TldIdFn:
15925 {
15926 // 2: Data.Fn: Data.FnDef
15927 bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 2);
15928
15929 FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
15930 assert(!fn_entry->is_test);
15931
15932 analyze_fn_body(ira->codegen, fn_entry);
15933 if (fn_entry->anal_state == FnAnalStateInvalid)
15934 return;
15935
15936 AstNodeFnProto *fn_node = (AstNodeFnProto *)(fn_entry->proto_node);
15937
15938 ConstExprValue *fn_def_val = create_const_vals(1);
15939 fn_def_val->special = ConstValSpecialStatic;
15940 fn_def_val->type = type_info_fn_def_type;
15941 fn_def_val->data.x_struct.parent.id = ConstParentIdUnion;
15942 fn_def_val->data.x_struct.parent.data.p_union.union_val = &inner_fields[2];
15943
15944 ConstExprValue *fn_def_fields = create_const_vals(9);
15945 fn_def_val->data.x_struct.fields = fn_def_fields;
15946
15947 // fn_type: type
15948 ensure_field_index(fn_def_val->type, "fn_type", 0);
15949 fn_def_fields[0].special = ConstValSpecialStatic;
15950 fn_def_fields[0].type = ira->codegen->builtin_types.entry_type;
15951 fn_def_fields[0].data.x_type = fn_entry->type_entry;
15952 // inline_type: Data.FnDef.Inline
15953 ensure_field_index(fn_def_val->type, "inline_type", 1);
15954 fn_def_fields[1].special = ConstValSpecialStatic;
15955 fn_def_fields[1].type = type_info_fn_def_inline_type;
15956 bigint_init_unsigned(&fn_def_fields[1].data.x_enum_tag, fn_entry->fn_inline);
15957 // calling_convention: TypeInfo.CallingConvention
15958 ensure_field_index(fn_def_val->type, "calling_convention", 2);
15959 fn_def_fields[2].special = ConstValSpecialStatic;
15960 fn_def_fields[2].type = ir_type_info_get_type(ira, "CallingConvention");
15961 bigint_init_unsigned(&fn_def_fields[2].data.x_enum_tag, fn_node->cc);
15962 // is_var_args: bool
15963 ensure_field_index(fn_def_val->type, "is_var_args", 3);
15964 bool is_varargs = fn_node->is_var_args;
15965 fn_def_fields[3].special = ConstValSpecialStatic;
15966 fn_def_fields[3].type = ira->codegen->builtin_types.entry_bool;
15967 fn_def_fields[3].data.x_bool = is_varargs;
15968 // is_extern: bool
15969 ensure_field_index(fn_def_val->type, "is_extern", 4);
15970 fn_def_fields[4].special = ConstValSpecialStatic;
15971 fn_def_fields[4].type = ira->codegen->builtin_types.entry_bool;
15972 fn_def_fields[4].data.x_bool = fn_node->is_extern;
15973 // is_export: bool
15974 ensure_field_index(fn_def_val->type, "is_export", 5);
15975 fn_def_fields[5].special = ConstValSpecialStatic;
15976 fn_def_fields[5].type = ira->codegen->builtin_types.entry_bool;
15977 fn_def_fields[5].data.x_bool = fn_node->is_export;
15978 // lib_name: ?[]const u8
15979 ensure_field_index(fn_def_val->type, "lib_name", 6);
15980 fn_def_fields[6].special = ConstValSpecialStatic;
15981 fn_def_fields[6].type = get_maybe_type(ira->codegen,
15982 get_slice_type(ira->codegen, get_pointer_to_type(ira->codegen,
15983 ira->codegen->builtin_types.entry_u8, true)));
15984 if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0)
15985 {
15986 fn_def_fields[6].data.x_maybe = create_const_vals(1);
15987 ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name);
15988 init_const_slice(ira->codegen, fn_def_fields[6].data.x_maybe, lib_name, 0, buf_len(fn_node->lib_name), true);
15989 }
15990 else
15991 fn_def_fields[6].data.x_maybe = nullptr;
15992 // return_type: type
15993 ensure_field_index(fn_def_val->type, "return_type", 7);
15994 fn_def_fields[7].special = ConstValSpecialStatic;
15995 fn_def_fields[7].type = ira->codegen->builtin_types.entry_type;
15996 if (fn_entry->src_implicit_return_type != nullptr)
15997 fn_def_fields[7].data.x_type = fn_entry->src_implicit_return_type;
15998 else if (fn_entry->type_entry->data.fn.gen_return_type != nullptr)
15999 fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.gen_return_type;
16000 else
16001 fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
16002 // arg_names: [][] const u8
16003 ensure_field_index(fn_def_val->type, "arg_names", 8);
16004 size_t fn_arg_count = fn_entry->variable_list.length;
16005 ConstExprValue *fn_arg_name_array = create_const_vals(1);
16006 fn_arg_name_array->special = ConstValSpecialStatic;
16007 fn_arg_name_array->type = get_array_type(ira->codegen, get_slice_type(ira->codegen,
16008 get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true)), fn_arg_count);
16009 fn_arg_name_array->data.x_array.special = ConstArraySpecialNone;
16010 fn_arg_name_array->data.x_array.s_none.parent.id = ConstParentIdNone;
16011 fn_arg_name_array->data.x_array.s_none.elements = create_const_vals(fn_arg_count);
16012
16013 init_const_slice(ira->codegen, &fn_def_fields[8], fn_arg_name_array, 0, fn_arg_count, false);
16014
16015 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++)
16016 {
16017 VariableTableEntry *arg_var = fn_entry->variable_list.at(fn_arg_index);
16018 ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.s_none.elements[fn_arg_index];
16019 ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name);
16020 init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, buf_len(&arg_var->name), true);
16021 fn_arg_name_val->data.x_struct.parent.id = ConstParentIdArray;
16022 fn_arg_name_val->data.x_struct.parent.data.p_array.array_val = fn_arg_name_array;
16023 fn_arg_name_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index;
16024 }
16025
16026 inner_fields[2].data.x_union.payload = fn_def_val;
16027 break;
16028 }
16029 case TldIdContainer:
16030 {
16031 TypeTableEntry *type_entry = ((TldContainer *)curr_entry->value)->type_entry;
16032 ensure_complete_type(ira->codegen, type_entry);
16033 // This is a type.
16034 bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0);
16035
16036 ConstExprValue *payload = create_const_vals(1);
16037 payload->type = ira->codegen->builtin_types.entry_type;
16038 payload->data.x_type = type_entry;
16039
16040 inner_fields[2].data.x_union.payload = payload;
16041
16042 break;
16043 }
16044 default:
16045 zig_unreachable();
16046 }
16047
16048 definition_val->data.x_struct.fields = inner_fields;
16049 definition_index++;
16050 }
16051
16052 assert(definition_index == definition_count);
16053}
16054
16055static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *type_entry)
16056{
16057 assert(type_entry != nullptr);
16058 assert(!type_is_invalid(type_entry));
16059
16060 ensure_complete_type(ira->codegen, type_entry);
16061
16062 const auto make_enum_field_val = [ira](ConstExprValue *enum_field_val, TypeEnumField *enum_field,
16063 TypeTableEntry *type_info_enum_field_type) {
16064 enum_field_val->special = ConstValSpecialStatic;
16065 enum_field_val->type = type_info_enum_field_type;
16066
16067 ConstExprValue *inner_fields = create_const_vals(2);
16068 inner_fields[1].special = ConstValSpecialStatic;
16069 inner_fields[1].type = ira->codegen->builtin_types.entry_usize;
16070
16071 ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name);
16072 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(enum_field->name), true);
16073
16074 bigint_init_bigint(&inner_fields[1].data.x_bigint, &enum_field->value);
16075
16076 enum_field_val->data.x_struct.fields = inner_fields;
16077 };
16078
16079 const auto create_ptr_like_type_info = [ira](const char *name, TypeTableEntry *ptr_type_entry) {
16080 ConstExprValue *result = create_const_vals(1);
16081 result->special = ConstValSpecialStatic;
16082 result->type = ir_type_info_get_type(ira, name);
16083
16084 ConstExprValue *fields = create_const_vals(4);
16085 result->data.x_struct.fields = fields;
16086
16087 // is_const: bool
16088 ensure_field_index(result->type, "is_const", 0);
16089 fields[0].special = ConstValSpecialStatic;
16090 fields[0].type = ira->codegen->builtin_types.entry_bool;
16091 fields[0].data.x_bool = ptr_type_entry->data.pointer.is_const;
16092 // is_volatile: bool
16093 ensure_field_index(result->type, "is_volatile", 1);
16094 fields[1].special = ConstValSpecialStatic;
16095 fields[1].type = ira->codegen->builtin_types.entry_bool;
16096 fields[1].data.x_bool = ptr_type_entry->data.pointer.is_volatile;
16097 // alignment: u32
16098 ensure_field_index(result->type, "alignment", 2);
16099 fields[2].special = ConstValSpecialStatic;
16100 fields[2].type = ira->codegen->builtin_types.entry_u32;
16101 bigint_init_unsigned(&fields[2].data.x_bigint, ptr_type_entry->data.pointer.alignment);
16102 // child: type
16103 ensure_field_index(result->type, "child", 3);
16104 fields[3].special = ConstValSpecialStatic;
16105 fields[3].type = ira->codegen->builtin_types.entry_type;
16106 fields[3].data.x_type = ptr_type_entry->data.pointer.child_type;
16107
16108 return result;
16109 };
16110
16111 ConstExprValue *result = nullptr;
16112 switch (type_entry->id)
16113 {
16114 case TypeTableEntryIdInvalid:
16115 zig_unreachable();
16116 case TypeTableEntryIdMetaType:
16117 case TypeTableEntryIdVoid:
16118 case TypeTableEntryIdBool:
16119 case TypeTableEntryIdUnreachable:
16120 case TypeTableEntryIdNumLitFloat:
16121 case TypeTableEntryIdNumLitInt:
16122 case TypeTableEntryIdUndefLit:
16123 case TypeTableEntryIdNullLit:
16124 case TypeTableEntryIdNamespace:
16125 case TypeTableEntryIdBlock:
16126 case TypeTableEntryIdArgTuple:
16127 case TypeTableEntryIdOpaque:
16128 return nullptr;
16129 default:
16130 {
16131 // Lookup an available value in our cache.
16132 auto entry = ira->codegen->type_info_cache.maybe_get(type_entry);
16133 if (entry != nullptr)
16134 return entry->value;
16135
16136 // Fallthrough if we don't find one.
16137 }
16138 case TypeTableEntryIdInt:
16139 {
16140 result = create_const_vals(1);
16141 result->special = ConstValSpecialStatic;
16142 result->type = ir_type_info_get_type(ira, "Int");
16143
16144 ConstExprValue *fields = create_const_vals(2);
16145 result->data.x_struct.fields = fields;
16146
16147 // is_signed: bool
16148 ensure_field_index(result->type, "is_signed", 0);
16149 fields[0].special = ConstValSpecialStatic;
16150 fields[0].type = ira->codegen->builtin_types.entry_bool;
16151 fields[0].data.x_bool = type_entry->data.integral.is_signed;
16152 // bits: u8
16153 ensure_field_index(result->type, "bits", 1);
16154 fields[1].special = ConstValSpecialStatic;
16155 fields[1].type = ira->codegen->builtin_types.entry_u8;
16156 bigint_init_unsigned(&fields[1].data.x_bigint, type_entry->data.integral.bit_count);
16157
16158 break;
16159 }
16160 case TypeTableEntryIdFloat:
16161 {
16162 result = create_const_vals(1);
16163 result->special = ConstValSpecialStatic;
16164 result->type = ir_type_info_get_type(ira, "Float");
16165
16166 ConstExprValue *fields = create_const_vals(1);
16167 result->data.x_struct.fields = fields;
16168
16169 // bits: u8
16170 ensure_field_index(result->type, "bits", 0);
16171 fields[0].special = ConstValSpecialStatic;
16172 fields[0].type = ira->codegen->builtin_types.entry_u8;
16173 bigint_init_unsigned(&fields->data.x_bigint, type_entry->data.floating.bit_count);
16174
16175 break;
16176 }
16177 case TypeTableEntryIdPointer:
16178 {
16179 result = create_ptr_like_type_info("Pointer", type_entry);
16180 break;
16181 }
16182 case TypeTableEntryIdArray:
16183 {
16184 result = create_const_vals(1);
16185 result->special = ConstValSpecialStatic;
16186 result->type = ir_type_info_get_type(ira, "Array");
16187
16188 ConstExprValue *fields = create_const_vals(2);
16189 result->data.x_struct.fields = fields;
16190
16191 // len: usize
16192 ensure_field_index(result->type, "len", 0);
16193 fields[0].special = ConstValSpecialStatic;
16194 fields[0].type = ira->codegen->builtin_types.entry_usize;
16195 bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.array.len);
16196 // child: type
16197 ensure_field_index(result->type, "child", 1);
16198 fields[1].special = ConstValSpecialStatic;
16199 fields[1].type = ira->codegen->builtin_types.entry_type;
16200 fields[1].data.x_type = type_entry->data.array.child_type;
16201
16202 break;
16203 }
16204 case TypeTableEntryIdMaybe:
16205 {
16206 result = create_const_vals(1);
16207 result->special = ConstValSpecialStatic;
16208 result->type = ir_type_info_get_type(ira, "Nullable");
16209
16210 ConstExprValue *fields = create_const_vals(1);
16211 result->data.x_struct.fields = fields;
16212
16213 // child: type
16214 ensure_field_index(result->type, "child", 0);
16215 fields[0].special = ConstValSpecialStatic;
16216 fields[0].type = ira->codegen->builtin_types.entry_type;
16217 fields[0].data.x_type = type_entry->data.maybe.child_type;
16218
16219 break;
16220 }
16221 case TypeTableEntryIdPromise:
16222 {
16223 result = create_const_vals(1);
16224 result->special = ConstValSpecialStatic;
16225 result->type = ir_type_info_get_type(ira, "Promise");
16226
16227 ConstExprValue *fields = create_const_vals(1);
16228 result->data.x_struct.fields = fields;
16229
16230 // @TODO ?type instead of using @typeOf(undefined) when we have no type.
16231 // child: type
16232 ensure_field_index(result->type, "child", 0);
16233 fields[0].special = ConstValSpecialStatic;
16234 fields[0].type = ira->codegen->builtin_types.entry_type;
16235
16236 if (type_entry->data.promise.result_type == nullptr)
16237 fields[0].data.x_type = ira->codegen->builtin_types.entry_undef;
16238 else
16239 fields[0].data.x_type = type_entry->data.promise.result_type;
16240
16241 break;
16242 }
16243 case TypeTableEntryIdEnum:
16244 {
16245 result = create_const_vals(1);
16246 result->special = ConstValSpecialStatic;
16247 result->type = ir_type_info_get_type(ira, "Enum");
16248
16249 ConstExprValue *fields = create_const_vals(4);
16250 result->data.x_struct.fields = fields;
16251
16252 // layout: ContainerLayout
16253 ensure_field_index(result->type, "layout", 0);
16254 fields[0].special = ConstValSpecialStatic;
16255 fields[0].type = ir_type_info_get_type(ira, "ContainerLayout");
16256 bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.enumeration.layout);
16257 // tag_type: type
16258 ensure_field_index(result->type, "tag_type", 1);
16259 fields[1].special = ConstValSpecialStatic;
16260 fields[1].type = ira->codegen->builtin_types.entry_type;
16261 fields[1].data.x_type = type_entry->data.enumeration.tag_int_type;
16262 // fields: []TypeInfo.EnumField
16263 ensure_field_index(result->type, "fields", 2);
16264
16265 TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField");
16266 uint32_t enum_field_count = type_entry->data.enumeration.src_field_count;
16267
16268 ConstExprValue *enum_field_array = create_const_vals(1);
16269 enum_field_array->special = ConstValSpecialStatic;
16270 enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count);
16271 enum_field_array->data.x_array.special = ConstArraySpecialNone;
16272 enum_field_array->data.x_array.s_none.parent.id = ConstParentIdNone;
16273 enum_field_array->data.x_array.s_none.elements = create_const_vals(enum_field_count);
16274
16275 init_const_slice(ira->codegen, &fields[2], enum_field_array, 0, enum_field_count, false);
16276
16277 for (uint32_t enum_field_index = 0; enum_field_index < enum_field_count; enum_field_index++)
16278 {
16279 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index];
16280 ConstExprValue *enum_field_val = &enum_field_array->data.x_array.s_none.elements[enum_field_index];
16281 make_enum_field_val(enum_field_val, enum_field, type_info_enum_field_type);
16282 enum_field_val->data.x_struct.parent.id = ConstParentIdArray;
16283 enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array;
16284 enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index;
16285 }
16286 // defs: []TypeInfo.Definition
16287 ensure_field_index(result->type, "defs", 3);
16288 ir_make_type_info_defs(ira, &fields[3], type_entry->data.enumeration.decls_scope);
16289
16290 break;
16291 }
16292 case TypeTableEntryIdErrorSet:
16293 {
16294 result = create_const_vals(1);
16295 result->special = ConstValSpecialStatic;
16296 result->type = ir_type_info_get_type(ira, "ErrorSet");
16297
16298 ConstExprValue *fields = create_const_vals(1);
16299 result->data.x_struct.fields = fields;
16300
16301 // errors: []TypeInfo.Error
16302 ensure_field_index(result->type, "errors", 0);
16303
16304 TypeTableEntry *type_info_error_type = ir_type_info_get_type(ira, "Error");
16305 uint32_t error_count = type_entry->data.error_set.err_count;
16306 ConstExprValue *error_array = create_const_vals(1);
16307 error_array->special = ConstValSpecialStatic;
16308 error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count);
16309 error_array->data.x_array.special = ConstArraySpecialNone;
16310 error_array->data.x_array.s_none.parent.id = ConstParentIdNone;
16311 error_array->data.x_array.s_none.elements = create_const_vals(error_count);
16312
16313 init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false);
16314 for (uint32_t error_index = 0; error_index < error_count; error_index++)
16315 {
16316 ErrorTableEntry *error = type_entry->data.error_set.errors[error_index];
16317 ConstExprValue *error_val = &error_array->data.x_array.s_none.elements[error_index];
16318
16319 error_val->special = ConstValSpecialStatic;
16320 error_val->type = type_info_error_type;
16321
16322 ConstExprValue *inner_fields = create_const_vals(2);
16323 inner_fields[1].special = ConstValSpecialStatic;
16324 inner_fields[1].type = ira->codegen->builtin_types.entry_usize;
16325
16326 ConstExprValue *name = nullptr;
16327 if (error->cached_error_name_val != nullptr)
16328 name = error->cached_error_name_val;
16329 if (name == nullptr)
16330 name = create_const_str_lit(ira->codegen, &error->name);
16331 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(&error->name), true);
16332 bigint_init_unsigned(&inner_fields[1].data.x_bigint, error->value);
16333
16334 error_val->data.x_struct.fields = inner_fields;
16335 error_val->data.x_struct.parent.id = ConstParentIdArray;
16336 error_val->data.x_struct.parent.data.p_array.array_val = error_array;
16337 error_val->data.x_struct.parent.data.p_array.elem_index = error_index;
16338 }
16339
16340 break;
16341 }
16342 case TypeTableEntryIdErrorUnion:
16343 {
16344 result = create_const_vals(1);
16345 result->special = ConstValSpecialStatic;
16346 result->type = ir_type_info_get_type(ira, "ErrorUnion");
16347
16348 ConstExprValue *fields = create_const_vals(2);
16349 result->data.x_struct.fields = fields;
16350
16351 // error_set: type
16352 ensure_field_index(result->type, "error_set", 0);
16353 fields[0].special = ConstValSpecialStatic;
16354 fields[0].type = ira->codegen->builtin_types.entry_type;
16355 fields[0].data.x_type = type_entry->data.error_union.err_set_type;
16356
16357 // payload: type
16358 ensure_field_index(result->type, "payload", 1);
16359 fields[1].special = ConstValSpecialStatic;
16360 fields[1].type = ira->codegen->builtin_types.entry_type;
16361 fields[1].data.x_type = type_entry->data.error_union.payload_type;
16362
16363 break;
16364 }
16365 case TypeTableEntryIdUnion:
16366 {
16367 result = create_const_vals(1);
16368 result->special = ConstValSpecialStatic;
16369 result->type = ir_type_info_get_type(ira, "Union");
16370
16371 ConstExprValue *fields = create_const_vals(4);
16372 result->data.x_struct.fields = fields;
16373
16374 // layout: ContainerLayout
16375 ensure_field_index(result->type, "layout", 0);
16376 fields[0].special = ConstValSpecialStatic;
16377 fields[0].type = ir_type_info_get_type(ira, "ContainerLayout");
16378 bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.unionation.layout);
16379 // tag_type: type
16380 ensure_field_index(result->type, "tag_type", 1);
16381 fields[1].special = ConstValSpecialStatic;
16382 fields[1].type = ira->codegen->builtin_types.entry_type;
16383 // @TODO ?type instead of using @typeOf(undefined) when we have no type.
16384 AstNode *union_decl_node = type_entry->data.unionation.decl_node;
16385 if (union_decl_node->data.container_decl.auto_enum ||
16386 union_decl_node->data.container_decl.init_arg_expr != nullptr)
16387 {
16388 fields[1].data.x_type = type_entry->data.unionation.tag_type;
16389 }
16390 else
16391 fields[1].data.x_type = ira->codegen->builtin_types.entry_undef;
16392 // fields: []TypeInfo.UnionField
16393 ensure_field_index(result->type, "fields", 2);
16394
16395 TypeTableEntry *type_info_union_field_type = ir_type_info_get_type(ira, "UnionField");
16396 uint32_t union_field_count = type_entry->data.unionation.src_field_count;
16397
16398 ConstExprValue *union_field_array = create_const_vals(1);
16399 union_field_array->special = ConstValSpecialStatic;
16400 union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count);
16401 union_field_array->data.x_array.special = ConstArraySpecialNone;
16402 union_field_array->data.x_array.s_none.parent.id = ConstParentIdNone;
16403 union_field_array->data.x_array.s_none.elements = create_const_vals(union_field_count);
16404
16405 init_const_slice(ira->codegen, &fields[2], union_field_array, 0, union_field_count, false);
16406
16407 TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField");
16408
16409 for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++)
16410 {
16411 TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index];
16412 ConstExprValue *union_field_val = &union_field_array->data.x_array.s_none.elements[union_field_index];
16413
16414 union_field_val->special = ConstValSpecialStatic;
16415 union_field_val->type = type_info_union_field_type;
16416
16417 ConstExprValue *inner_fields = create_const_vals(3);
16418 inner_fields[1].special = ConstValSpecialStatic;
16419 inner_fields[1].type = get_maybe_type(ira->codegen, type_info_enum_field_type);
16420
16421 if (fields[1].data.x_type == ira->codegen->builtin_types.entry_undef)
16422 inner_fields[1].data.x_maybe = nullptr;
16423 else
16424 {
16425 inner_fields[1].data.x_maybe = create_const_vals(1);
16426 make_enum_field_val(inner_fields[1].data.x_maybe, union_field->enum_field, type_info_enum_field_type);
16427 }
16428
16429 inner_fields[2].special = ConstValSpecialStatic;
16430 inner_fields[2].type = ira->codegen->builtin_types.entry_type;
16431 inner_fields[2].data.x_type = union_field->type_entry;
16432
16433 ConstExprValue *name = create_const_str_lit(ira->codegen, union_field->name);
16434 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(union_field->name), true);
16435
16436 union_field_val->data.x_struct.fields = inner_fields;
16437 union_field_val->data.x_struct.parent.id = ConstParentIdArray;
16438 union_field_val->data.x_struct.parent.data.p_array.array_val = union_field_array;
16439 union_field_val->data.x_struct.parent.data.p_array.elem_index = union_field_index;
16440 }
16441 // defs: []TypeInfo.Definition
16442 ensure_field_index(result->type, "defs", 3);
16443 ir_make_type_info_defs(ira, &fields[3], type_entry->data.unionation.decls_scope);
16444
16445 break;
16446 }
16447 case TypeTableEntryIdStruct:
16448 {
16449 if (type_entry->data.structure.is_slice) {
16450 Buf ptr_field_name = BUF_INIT;
16451 buf_init_from_str(&ptr_field_name, "ptr");
16452 TypeTableEntry *ptr_type = type_entry->data.structure.fields_by_name.get(&ptr_field_name)->type_entry;
16453 ensure_complete_type(ira->codegen, ptr_type);
16454 buf_deinit(&ptr_field_name);
16455
16456 result = create_ptr_like_type_info("Slice", ptr_type);
16457 break;
16458 }
16459
16460 result = create_const_vals(1);
16461 result->special = ConstValSpecialStatic;
16462 result->type = ir_type_info_get_type(ira, "Struct");
16463
16464 ConstExprValue *fields = create_const_vals(3);
16465 result->data.x_struct.fields = fields;
16466
16467 // layout: ContainerLayout
16468 ensure_field_index(result->type, "layout", 0);
16469 fields[0].special = ConstValSpecialStatic;
16470 fields[0].type = ir_type_info_get_type(ira, "ContainerLayout");
16471 bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.structure.layout);
16472 // fields: []TypeInfo.StructField
16473 ensure_field_index(result->type, "fields", 1);
16474
16475 TypeTableEntry *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField");
16476 uint32_t struct_field_count = type_entry->data.structure.src_field_count;
16477
16478 ConstExprValue *struct_field_array = create_const_vals(1);
16479 struct_field_array->special = ConstValSpecialStatic;
16480 struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count);
16481 struct_field_array->data.x_array.special = ConstArraySpecialNone;
16482 struct_field_array->data.x_array.s_none.parent.id = ConstParentIdNone;
16483 struct_field_array->data.x_array.s_none.elements = create_const_vals(struct_field_count);
16484
16485 init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false);
16486
16487 for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++)
16488 {
16489 TypeStructField *struct_field = &type_entry->data.structure.fields[struct_field_index];
16490 ConstExprValue *struct_field_val = &struct_field_array->data.x_array.s_none.elements[struct_field_index];
16491
16492 struct_field_val->special = ConstValSpecialStatic;
16493 struct_field_val->type = type_info_struct_field_type;
16494
16495 ConstExprValue *inner_fields = create_const_vals(3);
16496 inner_fields[1].special = ConstValSpecialStatic;
16497 inner_fields[1].type = get_maybe_type(ira->codegen, ira->codegen->builtin_types.entry_usize);
16498
16499 if (!type_has_bits(struct_field->type_entry))
16500 inner_fields[1].data.x_maybe = nullptr;
16501 else
16502 {
16503 size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index);
16504 inner_fields[1].data.x_maybe = create_const_vals(1);
16505 inner_fields[1].data.x_maybe->type = ira->codegen->builtin_types.entry_usize;
16506 bigint_init_unsigned(&inner_fields[1].data.x_maybe->data.x_bigint, byte_offset);
16507 }
16508
16509 inner_fields[2].special = ConstValSpecialStatic;
16510 inner_fields[2].type = ira->codegen->builtin_types.entry_type;
16511 inner_fields[2].data.x_type = struct_field->type_entry;
16512
16513 ConstExprValue *name = create_const_str_lit(ira->codegen, struct_field->name);
16514 init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(struct_field->name), true);
16515
16516 struct_field_val->data.x_struct.fields = inner_fields;
16517 struct_field_val->data.x_struct.parent.id = ConstParentIdArray;
16518 struct_field_val->data.x_struct.parent.data.p_array.array_val = struct_field_array;
16519 struct_field_val->data.x_struct.parent.data.p_array.elem_index = struct_field_index;
16520 }
16521 // defs: []TypeInfo.Definition
16522 ensure_field_index(result->type, "defs", 2);
16523 ir_make_type_info_defs(ira, &fields[2], type_entry->data.structure.decls_scope);
16524
16525 break;
16526 }
16527 case TypeTableEntryIdFn:
16528 {
16529 result = create_const_vals(1);
16530 result->special = ConstValSpecialStatic;
16531 result->type = ir_type_info_get_type(ira, "Fn");
16532
16533 ConstExprValue *fields = create_const_vals(6);
16534 result->data.x_struct.fields = fields;
16535
16536 // @TODO Fix type = undefined with ?type
16537
16538 // calling_convention: TypeInfo.CallingConvention
16539 ensure_field_index(result->type, "calling_convention", 0);
16540 fields[0].special = ConstValSpecialStatic;
16541 fields[0].type = ir_type_info_get_type(ira, "CallingConvention");
16542 bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.fn.fn_type_id.cc);
16543 // is_generic: bool
16544 ensure_field_index(result->type, "is_generic", 1);
16545 bool is_generic = type_entry->data.fn.is_generic;
16546 fields[1].special = ConstValSpecialStatic;
16547 fields[1].type = ira->codegen->builtin_types.entry_bool;
16548 fields[1].data.x_bool = is_generic;
16549 // is_varargs: bool
16550 ensure_field_index(result->type, "is_var_args", 2);
16551 bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args;
16552 fields[2].special = ConstValSpecialStatic;
16553 fields[2].type = ira->codegen->builtin_types.entry_bool;
16554 fields[2].data.x_bool = type_entry->data.fn.fn_type_id.is_var_args;
16555 // return_type: type
16556 ensure_field_index(result->type, "return_type", 3);
16557 fields[3].special = ConstValSpecialStatic;
16558 fields[3].type = ira->codegen->builtin_types.entry_type;
16559 if (type_entry->data.fn.fn_type_id.return_type == nullptr)
16560 fields[3].data.x_type = ira->codegen->builtin_types.entry_undef;
16561 else
16562 fields[3].data.x_type = type_entry->data.fn.fn_type_id.return_type;
16563 // async_allocator_type: type
16564 ensure_field_index(result->type, "async_allocator_type", 4);
16565 fields[4].special = ConstValSpecialStatic;
16566 fields[4].type = ira->codegen->builtin_types.entry_type;
16567 if (type_entry->data.fn.fn_type_id.async_allocator_type == nullptr)
16568 fields[4].data.x_type = ira->codegen->builtin_types.entry_undef;
16569 else
16570 fields[4].data.x_type = type_entry->data.fn.fn_type_id.async_allocator_type;
16571 // args: []TypeInfo.FnArg
16572 TypeTableEntry *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg");
16573 size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count -
16574 (is_varargs && type_entry->data.fn.fn_type_id.cc != CallingConventionC);
16575
16576 ConstExprValue *fn_arg_array = create_const_vals(1);
16577 fn_arg_array->special = ConstValSpecialStatic;
16578 fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count);
16579 fn_arg_array->data.x_array.special = ConstArraySpecialNone;
16580 fn_arg_array->data.x_array.s_none.parent.id = ConstParentIdNone;
16581 fn_arg_array->data.x_array.s_none.elements = create_const_vals(fn_arg_count);
16582
16583 init_const_slice(ira->codegen, &fields[5], fn_arg_array, 0, fn_arg_count, false);
16584
16585 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++)
16586 {
16587 FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index];
16588 ConstExprValue *fn_arg_val = &fn_arg_array->data.x_array.s_none.elements[fn_arg_index];
16589
16590 fn_arg_val->special = ConstValSpecialStatic;
16591 fn_arg_val->type = type_info_fn_arg_type;
16592
16593 bool arg_is_generic = fn_param_info->type == nullptr;
16594 if (arg_is_generic) assert(is_generic);
16595
16596 ConstExprValue *inner_fields = create_const_vals(3);
16597 inner_fields[0].special = ConstValSpecialStatic;
16598 inner_fields[0].type = ira->codegen->builtin_types.entry_bool;
16599 inner_fields[0].data.x_bool = arg_is_generic;
16600 inner_fields[1].special = ConstValSpecialStatic;
16601 inner_fields[1].type = ira->codegen->builtin_types.entry_bool;
16602 inner_fields[1].data.x_bool = fn_param_info->is_noalias;
16603 inner_fields[2].special = ConstValSpecialStatic;
16604 inner_fields[2].type = ira->codegen->builtin_types.entry_type;
16605
16606 if (arg_is_generic)
16607 inner_fields[2].data.x_type = ira->codegen->builtin_types.entry_undef;
16608 else
16609 inner_fields[2].data.x_type = fn_param_info->type;
16610
16611 fn_arg_val->data.x_struct.fields = inner_fields;
16612 fn_arg_val->data.x_struct.parent.id = ConstParentIdArray;
16613 fn_arg_val->data.x_struct.parent.data.p_array.array_val = fn_arg_array;
16614 fn_arg_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index;
16615 }
16616
16617 break;
16618 }
16619 case TypeTableEntryIdBoundFn:
16620 {
16621 TypeTableEntry *fn_type = type_entry->data.bound_fn.fn_type;
16622 assert(fn_type->id == TypeTableEntryIdFn);
16623 result = ir_make_type_info_value(ira, fn_type);
16624
16625 break;
16626 }
16627 }
16628
16629 assert(result != nullptr);
16630 ira->codegen->type_info_cache.put(type_entry, result);
16631 return result;
16632}
16633
16634static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira,
16635 IrInstructionTypeInfo *instruction)
16636{
16637 IrInstruction *type_value = instruction->type_value->other;
16638 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
16639 if (type_is_invalid(type_entry))
16640 return ira->codegen->builtin_types.entry_invalid;
16641
16642 TypeTableEntry *result_type = ir_type_info_get_type(ira, nullptr);
16643
16644 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
16645 out_val->type = result_type;
16646 bigint_init_unsigned(&out_val->data.x_union.tag, type_id_index(type_entry));
16647
16648 ConstExprValue *payload = ir_make_type_info_value(ira, type_entry);
16649 out_val->data.x_union.payload = payload;
16650
16651 if (payload != nullptr)
16652 {
16653 assert(payload->type->id == TypeTableEntryIdStruct);
16654 payload->data.x_struct.parent.id = ConstParentIdUnion;
16655 payload->data.x_struct.parent.data.p_union.union_val = out_val;
16656 }
16657
16658 return result_type;
16659}
16660
15686static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,16661static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,
15687 IrInstructionTypeId *instruction)16662 IrInstructionTypeId *instruction)
15688{16663{
...@@ -15696,7 +16671,7 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,...@@ -15696,7 +16671,7 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,
15696 TypeTableEntry *result_type = var_value->data.x_type;16671 TypeTableEntry *result_type = var_value->data.x_type;
1569716672
15698 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);16673 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15699 bigint_init_unsigned(&out_val->data.x_enum_tag, type_id_index(type_entry->id));16674 bigint_init_unsigned(&out_val->data.x_enum_tag, type_id_index(type_entry));
15700 return result_type;16675 return result_type;
15701}16676}
1570216677
...@@ -18584,6 +19559,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -18584,6 +19559,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
18584 return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction);19559 return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction);
18585 case IrInstructionIdOffsetOf:19560 case IrInstructionIdOffsetOf:
18586 return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction);19561 return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction);
19562 case IrInstructionIdTypeInfo:
19563 return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction);
18587 case IrInstructionIdTypeId:19564 case IrInstructionIdTypeId:
18588 return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction);19565 return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction);
18589 case IrInstructionIdSetEvalBranchQuota:19566 case IrInstructionIdSetEvalBranchQuota:
...@@ -18850,6 +19827,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -18850,6 +19827,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
18850 case IrInstructionIdTagName:19827 case IrInstructionIdTagName:
18851 case IrInstructionIdFieldParentPtr:19828 case IrInstructionIdFieldParentPtr:
18852 case IrInstructionIdOffsetOf:19829 case IrInstructionIdOffsetOf:
19830 case IrInstructionIdTypeInfo:
18853 case IrInstructionIdTypeId:19831 case IrInstructionIdTypeId:
18854 case IrInstructionIdAlignCast:19832 case IrInstructionIdAlignCast:
18855 case IrInstructionIdOpaqueType:19833 case IrInstructionIdOpaqueType:
src/ir_print.cpp+9
...@@ -966,6 +966,12 @@ static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction)...@@ -966,6 +966,12 @@ static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction)
966 fprintf(irp->f, ")");966 fprintf(irp->f, ")");
967}967}
968968
969static void ir_print_type_info(IrPrint *irp, IrInstructionTypeInfo *instruction) {
970 fprintf(irp->f, "@typeInfo(");
971 ir_print_other_instruction(irp, instruction->type_value);
972 fprintf(irp->f, ")");
973}
974
969static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) {975static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) {
970 fprintf(irp->f, "@typeId(");976 fprintf(irp->f, "@typeId(");
971 ir_print_other_instruction(irp, instruction->type_value);977 ir_print_other_instruction(irp, instruction->type_value);
...@@ -1536,6 +1542,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1536,6 +1542,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1536 case IrInstructionIdOffsetOf:1542 case IrInstructionIdOffsetOf:
1537 ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction);1543 ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction);
1538 break;1544 break;
1545 case IrInstructionIdTypeInfo:
1546 ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction);
1547 break;
1539 case IrInstructionIdTypeId:1548 case IrInstructionIdTypeId:
1540 ir_print_type_id(irp, (IrInstructionTypeId *)instruction);1549 ir_print_type_id(irp, (IrInstructionTypeId *)instruction);
1541 break;1550 break;
src/translate_c.cpp+45-71
...@@ -3672,6 +3672,7 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_...@@ -3672,6 +3672,7 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_
3672 if (existing_entry) {3672 if (existing_entry) {
3673 return existing_entry->value;3673 return existing_entry->value;
3674 }3674 }
3675
3675 QualType child_qt = typedef_decl->getUnderlyingType();3676 QualType child_qt = typedef_decl->getUnderlyingType();
3676 Buf *type_name = buf_create_from_str(decl_name(typedef_decl));3677 Buf *type_name = buf_create_from_str(decl_name(typedef_decl));
36773678
...@@ -3705,16 +3706,19 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_...@@ -3705,16 +3706,19 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_
3705 // use the name of this typedef3706 // use the name of this typedef
3706 // TODO3707 // TODO
37073708
3709 // trans_qual_type here might cause us to look at this typedef again so we put the item in the map first
3710 AstNode *symbol_node = trans_create_node_symbol(c, type_name);
3711 c->decl_table.put(typedef_decl->getCanonicalDecl(), symbol_node);
3712
3708 AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation());3713 AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation());
3709 if (type_node == nullptr) {3714 if (type_node == nullptr) {
3710 emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name));3715 emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name));
3711 c->decl_table.put(typedef_decl, nullptr);3716 c->decl_table.put(typedef_decl, nullptr);
3717 // TODO add global var with type_name equal to @compileError("unable to resolve C type")
3712 return nullptr;3718 return nullptr;
3713 }3719 }
3714 add_global_var(c, type_name, type_node);3720 add_global_var(c, type_name, type_node);
37153721
3716 AstNode *symbol_node = trans_create_node_symbol(c, type_name);
3717 c->decl_table.put(typedef_decl->getCanonicalDecl(), symbol_node);
3718 return symbol_node;3722 return symbol_node;
3719}3723}
37203724
...@@ -3749,6 +3753,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {...@@ -3749,6 +3753,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
3749 return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name);3753 return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name);
3750 }3754 }
37513755
3756
3752 bool pure_enum = true;3757 bool pure_enum = true;
3753 uint32_t field_count = 0;3758 uint32_t field_count = 0;
3754 for (auto it = enum_def->enumerator_begin(),3759 for (auto it = enum_def->enumerator_begin(),
...@@ -3760,84 +3765,53 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {...@@ -3760,84 +3765,53 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
3760 pure_enum = false;3765 pure_enum = false;
3761 }3766 }
3762 }3767 }
3763
3764 AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation());3768 AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation());
3765 assert(tag_int_type);3769 assert(tag_int_type);
37663770
3767 if (pure_enum) {3771 AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl);
3768 AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl);3772 enum_node->data.container_decl.kind = ContainerKindEnum;
3769 enum_node->data.container_decl.kind = ContainerKindEnum;3773 enum_node->data.container_decl.layout = ContainerLayoutExtern;
3770 enum_node->data.container_decl.layout = ContainerLayoutExtern;3774 // TODO only emit this tag type if the enum tag type is not the default.
3771 // TODO only emit this tag type if the enum tag type is not the default.3775 // I don't know what the default is, need to figure out how clang is deciding.
3772 // I don't know what the default is, need to figure out how clang is deciding.3776 // it appears to at least be different across gcc/msvc
3773 // it appears to at least be different across gcc/msvc3777 if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) &&
3774 if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) &&3778 !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int))
3775 !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int))3779 {
3776 {3780 enum_node->data.container_decl.init_arg_expr = tag_int_type;
3777 enum_node->data.container_decl.init_arg_expr = tag_int_type;
3778 }
3779
3780 enum_node->data.container_decl.fields.resize(field_count);
3781 uint32_t i = 0;
3782 for (auto it = enum_def->enumerator_begin(),
3783 it_end = enum_def->enumerator_end();
3784 it != it_end; ++it, i += 1)
3785 {
3786 const EnumConstantDecl *enum_const = *it;
3787
3788 Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
3789 Buf *field_name;
3790 if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) {
3791 field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name));
3792 } else {
3793 field_name = enum_val_name;
3794 }
3795
3796 AstNode *field_node = trans_create_node(c, NodeTypeStructField);
3797 field_node->data.struct_field.name = field_name;
3798 field_node->data.struct_field.type = nullptr;
3799 enum_node->data.container_decl.fields.items[i] = field_node;
3800
3801 // in C each enum value is in the global namespace. so we put them there too.
3802 // at this point we can rely on the enum emitting successfully
3803 if (is_anonymous) {
3804 AstNode *lit_node = trans_create_node_unsigned(c, i);
3805 add_global_var(c, enum_val_name, lit_node);
3806 } else {
3807 AstNode *field_access_node = trans_create_node_field_access(c,
3808 trans_create_node_symbol(c, full_type_name), field_name);
3809 add_global_var(c, enum_val_name, field_access_node);
3810 }
3811 }
3812
3813 if (is_anonymous) {
3814 c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node);
3815 return enum_node;
3816 } else {
3817 AstNode *symbol_node = trans_create_node_symbol(c, full_type_name);
3818 add_global_weak_alias(c, bare_name, full_type_name);
3819 add_global_var(c, full_type_name, enum_node);
3820 c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node);
3821 return enum_node;
3822 }
3823 }3781 }
38243782 enum_node->data.container_decl.fields.resize(field_count);
3825 // TODO after issue #305 is solved, make this be an enum with tag_int_type3783 uint32_t i = 0;
3826 // as the integer type and set the custom enum values
3827 AstNode *enum_node = tag_int_type;
3828
3829
3830 // add variables for all the values with enum_node
3831 for (auto it = enum_def->enumerator_begin(),3784 for (auto it = enum_def->enumerator_begin(),
3832 it_end = enum_def->enumerator_end();3785 it_end = enum_def->enumerator_end();
3833 it != it_end; ++it)3786 it != it_end; ++it, i += 1)
3834 {3787 {
3835 const EnumConstantDecl *enum_const = *it;3788 const EnumConstantDecl *enum_const = *it;
38363789
3837 Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));3790 Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
3838 AstNode *int_node = trans_create_node_apint(c, enum_const->getInitVal());3791 Buf *field_name;
3839 AstNode *var_node = add_global_var(c, enum_val_name, int_node);3792 if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) {
3840 var_node->data.variable_declaration.type = tag_int_type;3793 field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name));
3794 } else {
3795 field_name = enum_val_name;
3796 }
3797
3798 AstNode *int_node = pure_enum && !is_anonymous ? nullptr : trans_create_node_apint(c, enum_const->getInitVal());
3799 AstNode *field_node = trans_create_node(c, NodeTypeStructField);
3800 field_node->data.struct_field.name = field_name;
3801 field_node->data.struct_field.type = nullptr;
3802 field_node->data.struct_field.value = int_node;
3803 enum_node->data.container_decl.fields.items[i] = field_node;
3804
3805 // in C each enum value is in the global namespace. so we put them there too.
3806 // at this point we can rely on the enum emitting successfully
3807 if (is_anonymous) {
3808 Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
3809 add_global_var(c, enum_val_name, int_node);
3810 } else {
3811 AstNode *field_access_node = trans_create_node_field_access(c,
3812 trans_create_node_symbol(c, full_type_name), field_name);
3813 add_global_var(c, enum_val_name, field_access_node);
3814 }
3841 }3815 }
38423816
3843 if (is_anonymous) {3817 if (is_anonymous) {
...@@ -3848,7 +3822,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {...@@ -3848,7 +3822,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
3848 add_global_weak_alias(c, bare_name, full_type_name);3822 add_global_weak_alias(c, bare_name, full_type_name);
3849 add_global_var(c, full_type_name, enum_node);3823 add_global_var(c, full_type_name, enum_node);
3850 c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node);3824 c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node);
3851 return symbol_node;3825 return enum_node;
3852 }3826 }
3853}3827}
38543828
std/array_list.zig+64-2
...@@ -28,11 +28,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {...@@ -28,11 +28,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
28 };28 };
29 }29 }
3030
31 pub fn deinit(l: &Self) void {31 pub fn deinit(l: &const Self) void {
32 l.allocator.free(l.items);32 l.allocator.free(l.items);
33 }33 }
3434
35 pub fn toSlice(l: &Self) []align(A) T {35 pub fn toSlice(l: &const Self) []align(A) T {
36 return l.items[0..l.len];36 return l.items[0..l.len];
37 }37 }
3838
...@@ -44,6 +44,10 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {...@@ -44,6 +44,10 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
44 return l.toSliceConst()[n];44 return l.toSliceConst()[n];
45 }45 }
4646
47 pub fn count(self: &const Self) usize {
48 return self.len;
49 }
50
47 /// ArrayList takes ownership of the passed in slice. The slice must have been51 /// ArrayList takes ownership of the passed in slice. The slice must have been
48 /// allocated with `allocator`.52 /// allocated with `allocator`.
49 /// Deinitialize with `deinit` or use `toOwnedSlice`.53 /// Deinitialize with `deinit` or use `toOwnedSlice`.
...@@ -127,6 +131,27 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {...@@ -127,6 +131,27 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
127 if (self.len == 0) return null;131 if (self.len == 0) return null;
128 return self.pop();132 return self.pop();
129 }133 }
134
135 pub const Iterator = struct {
136 list: &const Self,
137 // how many items have we returned
138 count: usize,
139
140 pub fn next(it: &Iterator) ?T {
141 if (it.count >= it.list.len) return null;
142 const val = it.list.at(it.count);
143 it.count += 1;
144 return val;
145 }
146
147 pub fn reset(it: &Iterator) void {
148 it.count = 0;
149 }
150 };
151
152 pub fn iterator(self: &const Self) Iterator {
153 return Iterator { .list = self, .count = 0 };
154 }
130 };155 };
131}156}
132157
...@@ -148,6 +173,14 @@ test "basic ArrayList test" {...@@ -148,6 +173,14 @@ test "basic ArrayList test" {
148 }173 }
149 }174 }
150175
176 for (list.toSlice()) |v, i| {
177 assert(v == i32(i + 1));
178 }
179
180 for (list.toSliceConst()) |v, i| {
181 assert(v == i32(i + 1));
182 }
183
151 assert(list.pop() == 10);184 assert(list.pop() == 10);
152 assert(list.len == 9);185 assert(list.len == 9);
153186
...@@ -166,6 +199,35 @@ test "basic ArrayList test" {...@@ -166,6 +199,35 @@ test "basic ArrayList test" {
166 assert(list.len == 9);199 assert(list.len == 9);
167}200}
168201
202test "iterator ArrayList test" {
203 var list = ArrayList(i32).init(debug.global_allocator);
204 defer list.deinit();
205
206 try list.append(1);
207 try list.append(2);
208 try list.append(3);
209
210 var count : i32 = 0;
211 var it = list.iterator();
212 while (it.next()) |next| {
213 assert(next == count + 1);
214 count += 1;
215 }
216
217 assert(count == 3);
218 assert(it.next() == null);
219 it.reset();
220 count = 0;
221 while (it.next()) |next| {
222 assert(next == count + 1);
223 count += 1;
224 if (count == 2) break;
225 }
226
227 it.reset();
228 assert(?? it.next() == 1);
229}
230
169test "insert ArrayList test" {231test "insert ArrayList test" {
170 var list = ArrayList(i32).init(debug.global_allocator);232 var list = ArrayList(i32).init(debug.global_allocator);
171 defer list.deinit();233 defer list.deinit();
std/atomic/queue.zig+10-4
...@@ -31,10 +31,10 @@ pub fn Queue(comptime T: type) type {...@@ -31,10 +31,10 @@ pub fn Queue(comptime T: type) type {
31 }31 }
3232
33 pub fn get(self: &Self) ?&Node {33 pub fn get(self: &Self) ?&Node {
34 var head = @atomicLoad(&Node, &self.head, AtomicOrder.Acquire);34 var head = @atomicLoad(&Node, &self.head, AtomicOrder.SeqCst);
35 while (true) {35 while (true) {
36 const node = head.next ?? return null;36 const node = head.next ?? return null;
37 head = @cmpxchgWeak(&Node, &self.head, head, node, AtomicOrder.Release, AtomicOrder.Acquire) ?? return node;37 head = @cmpxchgWeak(&Node, &self.head, head, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return node;
38 }38 }
39 }39 }
40 };40 };
...@@ -49,14 +49,20 @@ const Context = struct {...@@ -49,14 +49,20 @@ const Context = struct {
49 get_count: usize,49 get_count: usize,
50 puts_done: u8, // TODO make this a bool50 puts_done: u8, // TODO make this a bool
51};51};
52const puts_per_thread = 10000;52
53// TODO add lazy evaluated build options and then put puts_per_thread behind
54// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
55// CI we would use a less aggressive setting since at 1 core, while we still
56// want this test to pass, we need a smaller value since there is so much thrashing
57// we would also use a less aggressive setting when running in valgrind
58const puts_per_thread = 500;
53const put_thread_count = 3;59const put_thread_count = 3;
5460
55test "std.atomic.queue" {61test "std.atomic.queue" {
56 var direct_allocator = std.heap.DirectAllocator.init();62 var direct_allocator = std.heap.DirectAllocator.init();
57 defer direct_allocator.deinit();63 defer direct_allocator.deinit();
5864
59 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 64 * 1024 * 1024);65 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
60 defer direct_allocator.allocator.free(plenty_of_memory);66 defer direct_allocator.allocator.free(plenty_of_memory);
6167
62 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);68 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
std/atomic/stack.zig+8-3
...@@ -35,7 +35,7 @@ pub fn Stack(comptime T: type) type {...@@ -35,7 +35,7 @@ pub fn Stack(comptime T: type) type {
35 }35 }
3636
37 pub fn pop(self: &Self) ?&Node {37 pub fn pop(self: &Self) ?&Node {
38 var root = @atomicLoad(?&Node, &self.root, AtomicOrder.Acquire);38 var root = @atomicLoad(?&Node, &self.root, AtomicOrder.SeqCst);
39 while (true) {39 while (true) {
40 root = @cmpxchgWeak(?&Node, &self.root, root, (root ?? return null).next, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return root;40 root = @cmpxchgWeak(?&Node, &self.root, root, (root ?? return null).next, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return root;
41 }41 }
...@@ -56,14 +56,19 @@ const Context = struct {...@@ -56,14 +56,19 @@ const Context = struct {
56 get_count: usize,56 get_count: usize,
57 puts_done: u8, // TODO make this a bool57 puts_done: u8, // TODO make this a bool
58};58};
59const puts_per_thread = 1000;59// TODO add lazy evaluated build options and then put puts_per_thread behind
60// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
61// CI we would use a less aggressive setting since at 1 core, while we still
62// want this test to pass, we need a smaller value since there is so much thrashing
63// we would also use a less aggressive setting when running in valgrind
64const puts_per_thread = 500;
60const put_thread_count = 3;65const put_thread_count = 3;
6166
62test "std.atomic.stack" {67test "std.atomic.stack" {
63 var direct_allocator = std.heap.DirectAllocator.init();68 var direct_allocator = std.heap.DirectAllocator.init();
64 defer direct_allocator.deinit();69 defer direct_allocator.deinit();
6570
66 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 64 * 1024 * 1024);71 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
67 defer direct_allocator.allocator.free(plenty_of_memory);72 defer direct_allocator.allocator.free(plenty_of_memory);
6873
69 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);74 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
std/buf_map.zig+6-6
...@@ -18,10 +18,10 @@ pub const BufMap = struct {...@@ -18,10 +18,10 @@ pub const BufMap = struct {
18 return self;18 return self;
19 }19 }
2020
21 pub fn deinit(self: &BufMap) void {21 pub fn deinit(self: &const BufMap) void {
22 var it = self.hash_map.iterator();22 var it = self.hash_map.iterator();
23 while (true) {23 while (true) {
24 const entry = it.next() ?? break; 24 const entry = it.next() ?? break;
25 self.free(entry.key);25 self.free(entry.key);
26 self.free(entry.value);26 self.free(entry.value);
27 }27 }
...@@ -38,7 +38,7 @@ pub const BufMap = struct {...@@ -38,7 +38,7 @@ pub const BufMap = struct {
38 _ = try self.hash_map.put(key_copy, value_copy);38 _ = try self.hash_map.put(key_copy, value_copy);
39 }39 }
4040
41 pub fn get(self: &BufMap, key: []const u8) ?[]const u8 {41 pub fn get(self: &const BufMap, key: []const u8) ?[]const u8 {
42 const entry = self.hash_map.get(key) ?? return null;42 const entry = self.hash_map.get(key) ?? return null;
43 return entry.value;43 return entry.value;
44 }44 }
...@@ -50,18 +50,18 @@ pub const BufMap = struct {...@@ -50,18 +50,18 @@ pub const BufMap = struct {
50 }50 }
5151
52 pub fn count(self: &const BufMap) usize {52 pub fn count(self: &const BufMap) usize {
53 return self.hash_map.size;53 return self.hash_map.count();
54 }54 }
5555
56 pub fn iterator(self: &const BufMap) BufMapHashMap.Iterator {56 pub fn iterator(self: &const BufMap) BufMapHashMap.Iterator {
57 return self.hash_map.iterator();57 return self.hash_map.iterator();
58 }58 }
5959
60 fn free(self: &BufMap, value: []const u8) void {60 fn free(self: &const BufMap, value: []const u8) void {
61 self.hash_map.allocator.free(value);61 self.hash_map.allocator.free(value);
62 }62 }
6363
64 fn copy(self: &BufMap, value: []const u8) ![]const u8 {64 fn copy(self: &const BufMap, value: []const u8) ![]const u8 {
65 return mem.dupe(self.hash_map.allocator, u8, value);65 return mem.dupe(self.hash_map.allocator, u8, value);
66 }66 }
67};67};
std/buf_set.zig+23-5
...@@ -1,6 +1,8 @@...@@ -1,6 +1,8 @@
1const std = @import("index.zig");
1const HashMap = @import("hash_map.zig").HashMap;2const HashMap = @import("hash_map.zig").HashMap;
2const mem = @import("mem.zig");3const mem = @import("mem.zig");
3const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
5const assert = std.debug.assert;
46
5pub const BufSet = struct {7pub const BufSet = struct {
6 hash_map: BufSetHashMap,8 hash_map: BufSetHashMap,
...@@ -14,10 +16,10 @@ pub const BufSet = struct {...@@ -14,10 +16,10 @@ pub const BufSet = struct {
14 return self;16 return self;
15 }17 }
1618
17 pub fn deinit(self: &BufSet) void {19 pub fn deinit(self: &const BufSet) void {
18 var it = self.hash_map.iterator();20 var it = self.hash_map.iterator();
19 while (true) {21 while (true) {
20 const entry = it.next() ?? break; 22 const entry = it.next() ?? break;
21 self.free(entry.key);23 self.free(entry.key);
22 }24 }
2325
...@@ -38,7 +40,7 @@ pub const BufSet = struct {...@@ -38,7 +40,7 @@ pub const BufSet = struct {
38 }40 }
3941
40 pub fn count(self: &const BufSet) usize {42 pub fn count(self: &const BufSet) usize {
41 return self.hash_map.size;43 return self.hash_map.count();
42 }44 }
4345
44 pub fn iterator(self: &const BufSet) BufSetHashMap.Iterator {46 pub fn iterator(self: &const BufSet) BufSetHashMap.Iterator {
...@@ -49,14 +51,30 @@ pub const BufSet = struct {...@@ -49,14 +51,30 @@ pub const BufSet = struct {
49 return self.hash_map.allocator;51 return self.hash_map.allocator;
50 }52 }
5153
52 fn free(self: &BufSet, value: []const u8) void {54 fn free(self: &const BufSet, value: []const u8) void {
53 self.hash_map.allocator.free(value);55 self.hash_map.allocator.free(value);
54 }56 }
5557
56 fn copy(self: &BufSet, value: []const u8) ![]const u8 {58 fn copy(self: &const BufSet, value: []const u8) ![]const u8 {
57 const result = try self.hash_map.allocator.alloc(u8, value.len);59 const result = try self.hash_map.allocator.alloc(u8, value.len);
58 mem.copy(u8, result, value);60 mem.copy(u8, result, value);
59 return result;61 return result;
60 }62 }
61};63};
6264
65test "BufSet" {
66 var direct_allocator = std.heap.DirectAllocator.init();
67 defer direct_allocator.deinit();
68
69 var bufset = BufSet.init(&direct_allocator.allocator);
70 defer bufset.deinit();
71
72 try bufset.put("x");
73 assert(bufset.count() == 1);
74 bufset.delete("x");
75 assert(bufset.count() == 0);
76
77 try bufset.put("x");
78 try bufset.put("y");
79 try bufset.put("z");
80}
std/buffer.zig+2-2
...@@ -66,7 +66,7 @@ pub const Buffer = struct {...@@ -66,7 +66,7 @@ pub const Buffer = struct {
66 self.list.deinit();66 self.list.deinit();
67 }67 }
6868
69 pub fn toSlice(self: &Buffer) []u8 {69 pub fn toSlice(self: &const Buffer) []u8 {
70 return self.list.toSlice()[0..self.len()];70 return self.list.toSlice()[0..self.len()];
71 }71 }
7272
...@@ -166,5 +166,5 @@ test "simple Buffer" {...@@ -166,5 +166,5 @@ test "simple Buffer" {
166 assert(buf.endsWith("orld"));166 assert(buf.endsWith("orld"));
167167
168 try buf2.resize(4);168 try buf2.resize(4);
169 assert(buf.startsWith(buf2.toSliceConst()));169 assert(buf.startsWith(buf2.toSlice()));
170}170}
std/hash_map.zig+57-5
...@@ -54,6 +54,14 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -54,6 +54,14 @@ pub fn HashMap(comptime K: type, comptime V: type,
54 }54 }
55 unreachable; // no next item55 unreachable; // no next item
56 }56 }
57
58 // Reset the iterator to the initial index
59 pub fn reset(it: &Iterator) void {
60 it.count = 0;
61 it.index = 0;
62 // Resetting the modification count too
63 it.initial_modification_count = it.hm.modification_count;
64 }
57 };65 };
5866
59 pub fn init(allocator: &Allocator) Self {67 pub fn init(allocator: &Allocator) Self {
...@@ -66,7 +74,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -66,7 +74,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
66 };74 };
67 }75 }
6876
69 pub fn deinit(hm: &Self) void {77 pub fn deinit(hm: &const Self) void {
70 hm.allocator.free(hm.entries);78 hm.allocator.free(hm.entries);
71 }79 }
7280
...@@ -79,6 +87,10 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -79,6 +87,10 @@ pub fn HashMap(comptime K: type, comptime V: type,
79 hm.incrementModificationCount();87 hm.incrementModificationCount();
80 }88 }
8189
90 pub fn count(hm: &const Self) usize {
91 return hm.size;
92 }
93
82 /// Returns the value that was already there.94 /// Returns the value that was already there.
83 pub fn put(hm: &Self, key: K, value: &const V) !?V {95 pub fn put(hm: &Self, key: K, value: &const V) !?V {
84 if (hm.entries.len == 0) {96 if (hm.entries.len == 0) {
...@@ -102,14 +114,14 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -102,14 +114,14 @@ pub fn HashMap(comptime K: type, comptime V: type,
102 return hm.internalPut(key, value);114 return hm.internalPut(key, value);
103 }115 }
104116
105 pub fn get(hm: &Self, key: K) ?&Entry {117 pub fn get(hm: &const Self, key: K) ?&Entry {
106 if (hm.entries.len == 0) {118 if (hm.entries.len == 0) {
107 return null;119 return null;
108 }120 }
109 return hm.internalGet(key);121 return hm.internalGet(key);
110 }122 }
111123
112 pub fn contains(hm: &Self, key: K) bool {124 pub fn contains(hm: &const Self, key: K) bool {
113 return hm.get(key) != null;125 return hm.get(key) != null;
114 }126 }
115127
...@@ -218,7 +230,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -218,7 +230,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
218 unreachable; // put into a full map230 unreachable; // put into a full map
219 }231 }
220232
221 fn internalGet(hm: &Self, key: K) ?&Entry {233 fn internalGet(hm: &const Self, key: K) ?&Entry {
222 const start_index = hm.keyToIndex(key);234 const start_index = hm.keyToIndex(key);
223 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {235 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
224 const index = (start_index + roll_over) % hm.entries.len;236 const index = (start_index + roll_over) % hm.entries.len;
...@@ -230,7 +242,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -230,7 +242,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
230 return null;242 return null;
231 }243 }
232244
233 fn keyToIndex(hm: &Self, key: K) usize {245 fn keyToIndex(hm: &const Self, key: K) usize {
234 return usize(hash(key)) % hm.entries.len;246 return usize(hash(key)) % hm.entries.len;
235 }247 }
236 };248 };
...@@ -252,12 +264,52 @@ test "basic hash map usage" {...@@ -252,12 +264,52 @@ test "basic hash map usage" {
252 assert(??(map.put(5, 66) catch unreachable) == 55);264 assert(??(map.put(5, 66) catch unreachable) == 55);
253 assert(??(map.put(5, 55) catch unreachable) == 66);265 assert(??(map.put(5, 55) catch unreachable) == 66);
254266
267 assert(map.contains(2));
255 assert((??map.get(2)).value == 22);268 assert((??map.get(2)).value == 22);
256 _ = map.remove(2);269 _ = map.remove(2);
257 assert(map.remove(2) == null);270 assert(map.remove(2) == null);
258 assert(map.get(2) == null);271 assert(map.get(2) == null);
259}272}
260273
274test "iterator hash map" {
275 var direct_allocator = std.heap.DirectAllocator.init();
276 defer direct_allocator.deinit();
277
278 var reset_map = HashMap(i32, i32, hash_i32, eql_i32).init(&direct_allocator.allocator);
279 defer reset_map.deinit();
280
281 assert((reset_map.put(1, 11) catch unreachable) == null);
282 assert((reset_map.put(2, 22) catch unreachable) == null);
283 assert((reset_map.put(3, 33) catch unreachable) == null);
284
285 var keys = []i32 { 1, 2, 3 };
286 var values = []i32 { 11, 22, 33 };
287
288 var it = reset_map.iterator();
289 var count : usize = 0;
290 while (it.next()) |next| {
291 assert(next.key == keys[count]);
292 assert(next.value == values[count]);
293 count += 1;
294 }
295
296 assert(count == 3);
297 assert(it.next() == null);
298 it.reset();
299 count = 0;
300 while (it.next()) |next| {
301 assert(next.key == keys[count]);
302 assert(next.value == values[count]);
303 count += 1;
304 if (count == 2) break;
305 }
306
307 it.reset();
308 var entry = ?? it.next();
309 assert(entry.key == keys[0]);
310 assert(entry.value == values[0]);
311}
312
261fn hash_i32(x: i32) u32 {313fn hash_i32(x: i32) u32 {
262 return @bitCast(u32, x);314 return @bitCast(u32, x);
263}315}
std/index.zig+4
...@@ -7,6 +7,7 @@ pub const BufferOutStream = @import("buffer.zig").BufferOutStream;...@@ -7,6 +7,7 @@ pub const BufferOutStream = @import("buffer.zig").BufferOutStream;
7pub const HashMap = @import("hash_map.zig").HashMap;7pub const HashMap = @import("hash_map.zig").HashMap;
8pub const LinkedList = @import("linked_list.zig").LinkedList;8pub const LinkedList = @import("linked_list.zig").LinkedList;
9pub const IntrusiveLinkedList = @import("linked_list.zig").IntrusiveLinkedList;9pub const IntrusiveLinkedList = @import("linked_list.zig").IntrusiveLinkedList;
10pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
1011
11pub const atomic = @import("atomic/index.zig");12pub const atomic = @import("atomic/index.zig");
12pub const base64 = @import("base64.zig");13pub const base64 = @import("base64.zig");
...@@ -23,6 +24,7 @@ pub const fmt = @import("fmt/index.zig");...@@ -23,6 +24,7 @@ pub const fmt = @import("fmt/index.zig");
23pub const hash = @import("hash/index.zig");24pub const hash = @import("hash/index.zig");
24pub const heap = @import("heap.zig");25pub const heap = @import("heap.zig");
25pub const io = @import("io.zig");26pub const io = @import("io.zig");
27pub const json = @import("json.zig");
26pub const macho = @import("macho.zig");28pub const macho = @import("macho.zig");
27pub const math = @import("math/index.zig");29pub const math = @import("math/index.zig");
28pub const mem = @import("mem.zig");30pub const mem = @import("mem.zig");
...@@ -42,6 +44,7 @@ test "std" {...@@ -42,6 +44,7 @@ test "std" {
42 _ = @import("buffer.zig");44 _ = @import("buffer.zig");
43 _ = @import("hash_map.zig");45 _ = @import("hash_map.zig");
44 _ = @import("linked_list.zig");46 _ = @import("linked_list.zig");
47 _ = @import("segmented_list.zig");
4548
46 _ = @import("base64.zig");49 _ = @import("base64.zig");
47 _ = @import("build.zig");50 _ = @import("build.zig");
...@@ -56,6 +59,7 @@ test "std" {...@@ -56,6 +59,7 @@ test "std" {
56 _ = @import("fmt/index.zig");59 _ = @import("fmt/index.zig");
57 _ = @import("hash/index.zig");60 _ = @import("hash/index.zig");
58 _ = @import("io.zig");61 _ = @import("io.zig");
62 _ = @import("json.zig");
59 _ = @import("macho.zig");63 _ = @import("macho.zig");
60 _ = @import("math/index.zig");64 _ = @import("math/index.zig");
61 _ = @import("mem.zig");65 _ = @import("mem.zig");
std/json.zig created+1304
...@@ -0,0 +1,1304 @@
1// JSON parser conforming to RFC8259.
2//
3// https://tools.ietf.org/html/rfc8259
4
5const std = @import("index.zig");
6const mem = std.mem;
7
8const u1 = @IntType(false, 1);
9const u256 = @IntType(false, 256);
10
11// A single token slice into the parent string.
12//
13// Use `token.slice()` on the inptu at the current position to get the current slice.
14pub const Token = struct {
15 id: Id,
16 // How many bytes do we skip before counting
17 offset: u1,
18 // Whether string contains a \uXXXX sequence and cannot be zero-copied
19 string_has_escape: bool,
20 // Whether number is simple and can be represented by an integer (i.e. no `.` or `e`)
21 number_is_integer: bool,
22 // How many bytes from the current position behind the start of this token is.
23 count: usize,
24
25 pub const Id = enum {
26 ObjectBegin,
27 ObjectEnd,
28 ArrayBegin,
29 ArrayEnd,
30 String,
31 Number,
32 True,
33 False,
34 Null,
35 };
36
37 pub fn init(id: Id, count: usize, offset: u1) Token {
38 return Token {
39 .id = id,
40 .offset = offset,
41 .string_has_escape = false,
42 .number_is_integer = true,
43 .count = count,
44 };
45 }
46
47 pub fn initString(count: usize, has_unicode_escape: bool) Token {
48 return Token {
49 .id = Id.String,
50 .offset = 0,
51 .string_has_escape = has_unicode_escape,
52 .number_is_integer = true,
53 .count = count,
54 };
55 }
56
57 pub fn initNumber(count: usize, number_is_integer: bool) Token {
58 return Token {
59 .id = Id.Number,
60 .offset = 0,
61 .string_has_escape = false,
62 .number_is_integer = number_is_integer,
63 .count = count,
64 };
65 }
66
67 // A marker token is a zero-length
68 pub fn initMarker(id: Id) Token {
69 return Token {
70 .id = id,
71 .offset = 0,
72 .string_has_escape = false,
73 .number_is_integer = true,
74 .count = 0,
75 };
76 }
77
78 // Slice into the underlying input string.
79 pub fn slice(self: &const Token, input: []const u8, i: usize) []const u8 {
80 return input[i + self.offset - self.count .. i + self.offset];
81 }
82};
83
84// A small streaming JSON parser. This accepts input one byte at a time and returns tokens as
85// they are encountered. No copies or allocations are performed during parsing and the entire
86// parsing state requires ~40-50 bytes of stack space.
87//
88// Conforms strictly to RFC8529.
89const StreamingJsonParser = struct {
90 // Current state
91 state: State,
92 // How many bytes we have counted for the current token
93 count: usize,
94 // What state to follow after parsing a string (either property or value string)
95 after_string_state: State,
96 // What state to follow after parsing a value (either top-level or value end)
97 after_value_state: State,
98 // If we stopped now, would the complete parsed string to now be a valid json string
99 complete: bool,
100 // Current token flags to pass through to the next generated, see Token.
101 string_has_escape: bool,
102 number_is_integer: bool,
103
104 // Bit-stack for nested object/map literals (max 255 nestings).
105 stack: u256,
106 stack_used: u8,
107
108 const object_bit = 0;
109 const array_bit = 1;
110 const max_stack_size = @maxValue(u8);
111
112 pub fn init() StreamingJsonParser {
113 var p: StreamingJsonParser = undefined;
114 p.reset();
115 return p;
116 }
117
118 pub fn reset(p: &StreamingJsonParser) void {
119 p.state = State.TopLevelBegin;
120 p.count = 0;
121 // Set before ever read in main transition function
122 p.after_string_state = undefined;
123 p.after_value_state = State.ValueEnd; // handle end of values normally
124 p.stack = 0;
125 p.stack_used = 0;
126 p.complete = false;
127 p.string_has_escape = false;
128 p.number_is_integer = true;
129 }
130
131 pub const State = enum {
132 // These must be first with these explicit values as we rely on them for indexing the
133 // bit-stack directly and avoiding a branch.
134 ObjectSeparator = 0,
135 ValueEnd = 1,
136
137 TopLevelBegin,
138 TopLevelEnd,
139
140 ValueBegin,
141 ValueBeginNoClosing,
142
143 String,
144 StringUtf8Byte3,
145 StringUtf8Byte2,
146 StringUtf8Byte1,
147 StringEscapeCharacter,
148 StringEscapeHexUnicode4,
149 StringEscapeHexUnicode3,
150 StringEscapeHexUnicode2,
151 StringEscapeHexUnicode1,
152
153 Number,
154 NumberMaybeDotOrExponent,
155 NumberMaybeDigitOrDotOrExponent,
156 NumberFractionalRequired,
157 NumberFractional,
158 NumberMaybeExponent,
159 NumberExponent,
160 NumberExponentDigitsRequired,
161 NumberExponentDigits,
162
163 TrueLiteral1,
164 TrueLiteral2,
165 TrueLiteral3,
166
167 FalseLiteral1,
168 FalseLiteral2,
169 FalseLiteral3,
170 FalseLiteral4,
171
172 NullLiteral1,
173 NullLiteral2,
174 NullLiteral3,
175
176 // Only call this function to generate array/object final state.
177 pub fn fromInt(x: var) State {
178 std.debug.assert(x == 0 or x == 1);
179 const T = @TagType(State);
180 return State(T(x));
181 }
182 };
183
184 pub const Error = error {
185 InvalidTopLevel,
186 TooManyNestedItems,
187 TooManyClosingItems,
188 InvalidValueBegin,
189 InvalidValueEnd,
190 UnbalancedBrackets,
191 UnbalancedBraces,
192 UnexpectedClosingBracket,
193 UnexpectedClosingBrace,
194 InvalidNumber,
195 InvalidSeparator,
196 InvalidLiteral,
197 InvalidEscapeCharacter,
198 InvalidUnicodeHexSymbol,
199 InvalidUtf8Byte,
200 InvalidTopLevelTrailing,
201 InvalidControlCharacter,
202 };
203
204 // Give another byte to the parser and obtain any new tokens. This may (rarely) return two
205 // tokens. token2 is always null if token1 is null.
206 //
207 // There is currently no error recovery on a bad stream.
208 pub fn feed(p: &StreamingJsonParser, c: u8, token1: &?Token, token2: &?Token) Error!void {
209 *token1 = null;
210 *token2 = null;
211 p.count += 1;
212
213 // unlikely
214 if (try p.transition(c, token1)) {
215 _ = try p.transition(c, token2);
216 }
217 }
218
219 // Perform a single transition on the state machine and return any possible token.
220 fn transition(p: &StreamingJsonParser, c: u8, token: &?Token) Error!bool {
221 switch (p.state) {
222 State.TopLevelBegin => switch (c) {
223 '{' => {
224 p.stack <<= 1;
225 p.stack |= object_bit;
226 p.stack_used += 1;
227
228 p.state = State.ValueBegin;
229 p.after_string_state = State.ObjectSeparator;
230
231 *token = Token.initMarker(Token.Id.ObjectBegin);
232 },
233 '[' => {
234 p.stack <<= 1;
235 p.stack |= array_bit;
236 p.stack_used += 1;
237
238 p.state = State.ValueBegin;
239 p.after_string_state = State.ValueEnd;
240
241 *token = Token.initMarker(Token.Id.ArrayBegin);
242 },
243 '-' => {
244 p.number_is_integer = true;
245 p.state = State.Number;
246 p.after_value_state = State.TopLevelEnd;
247 p.count = 0;
248 },
249 '0' => {
250 p.number_is_integer = true;
251 p.state = State.NumberMaybeDotOrExponent;
252 p.after_value_state = State.TopLevelEnd;
253 p.count = 0;
254 },
255 '1' ... '9' => {
256 p.number_is_integer = true;
257 p.state = State.NumberMaybeDigitOrDotOrExponent;
258 p.after_value_state = State.TopLevelEnd;
259 p.count = 0;
260 },
261 '"' => {
262 p.state = State.String;
263 p.after_value_state = State.TopLevelEnd;
264 // We don't actually need the following since after_value_state should override.
265 p.after_string_state = State.ValueEnd;
266 p.string_has_escape = false;
267 p.count = 0;
268 },
269 't' => {
270 p.state = State.TrueLiteral1;
271 p.after_value_state = State.TopLevelEnd;
272 p.count = 0;
273 },
274 'f' => {
275 p.state = State.FalseLiteral1;
276 p.after_value_state = State.TopLevelEnd;
277 p.count = 0;
278 },
279 'n' => {
280 p.state = State.NullLiteral1;
281 p.after_value_state = State.TopLevelEnd;
282 p.count = 0;
283 },
284 0x09, 0x0A, 0x0D, 0x20 => {
285 // whitespace
286 },
287 else => {
288 return error.InvalidTopLevel;
289 },
290 },
291
292 State.TopLevelEnd => switch (c) {
293 0x09, 0x0A, 0x0D, 0x20 => {
294 // whitespace
295 },
296 else => {
297 return error.InvalidTopLevelTrailing;
298 },
299 },
300
301 State.ValueBegin => switch (c) {
302 // NOTE: These are shared in ValueEnd as well, think we can reorder states to
303 // be a bit clearer and avoid this duplication.
304 '}' => {
305 // unlikely
306 if (p.stack & 1 != object_bit) {
307 return error.UnexpectedClosingBracket;
308 }
309 if (p.stack_used == 0) {
310 return error.TooManyClosingItems;
311 }
312
313 p.state = State.ValueBegin;
314 p.after_string_state = State.fromInt(p.stack & 1);
315
316 p.stack >>= 1;
317 p.stack_used -= 1;
318
319 switch (p.stack_used) {
320 0 => {
321 p.complete = true;
322 p.state = State.TopLevelEnd;
323 },
324 else => {},
325 }
326
327 *token = Token.initMarker(Token.Id.ObjectEnd);
328 },
329 ']' => {
330 if (p.stack & 1 != array_bit) {
331 return error.UnexpectedClosingBrace;
332 }
333 if (p.stack_used == 0) {
334 return error.TooManyClosingItems;
335 }
336
337 p.state = State.ValueBegin;
338 p.after_string_state = State.fromInt(p.stack & 1);
339
340 p.stack >>= 1;
341 p.stack_used -= 1;
342
343 switch (p.stack_used) {
344 0 => {
345 p.complete = true;
346 p.state = State.TopLevelEnd;
347 },
348 else => {},
349 }
350
351 *token = Token.initMarker(Token.Id.ArrayEnd);
352 },
353 '{' => {
354 if (p.stack_used == max_stack_size) {
355 return error.TooManyNestedItems;
356 }
357
358 p.stack <<= 1;
359 p.stack |= object_bit;
360 p.stack_used += 1;
361
362 p.state = State.ValueBegin;
363 p.after_string_state = State.ObjectSeparator;
364
365 *token = Token.initMarker(Token.Id.ObjectBegin);
366 },
367 '[' => {
368 if (p.stack_used == max_stack_size) {
369 return error.TooManyNestedItems;
370 }
371
372 p.stack <<= 1;
373 p.stack |= array_bit;
374 p.stack_used += 1;
375
376 p.state = State.ValueBegin;
377 p.after_string_state = State.ValueEnd;
378
379 *token = Token.initMarker(Token.Id.ArrayBegin);
380 },
381 '-' => {
382 p.state = State.Number;
383 p.count = 0;
384 },
385 '0' => {
386 p.state = State.NumberMaybeDotOrExponent;
387 p.count = 0;
388 },
389 '1' ... '9' => {
390 p.state = State.NumberMaybeDigitOrDotOrExponent;
391 p.count = 0;
392 },
393 '"' => {
394 p.state = State.String;
395 p.count = 0;
396 },
397 't' => {
398 p.state = State.TrueLiteral1;
399 p.count = 0;
400 },
401 'f' => {
402 p.state = State.FalseLiteral1;
403 p.count = 0;
404 },
405 'n' => {
406 p.state = State.NullLiteral1;
407 p.count = 0;
408 },
409 0x09, 0x0A, 0x0D, 0x20 => {
410 // whitespace
411 },
412 else => {
413 return error.InvalidValueBegin;
414 },
415 },
416
417 // TODO: A bit of duplication here and in the following state, redo.
418 State.ValueBeginNoClosing => switch (c) {
419 '{' => {
420 if (p.stack_used == max_stack_size) {
421 return error.TooManyNestedItems;
422 }
423
424 p.stack <<= 1;
425 p.stack |= object_bit;
426 p.stack_used += 1;
427
428 p.state = State.ValueBegin;
429 p.after_string_state = State.ObjectSeparator;
430
431 *token = Token.initMarker(Token.Id.ObjectBegin);
432 },
433 '[' => {
434 if (p.stack_used == max_stack_size) {
435 return error.TooManyNestedItems;
436 }
437
438 p.stack <<= 1;
439 p.stack |= array_bit;
440 p.stack_used += 1;
441
442 p.state = State.ValueBegin;
443 p.after_string_state = State.ValueEnd;
444
445 *token = Token.initMarker(Token.Id.ArrayBegin);
446 },
447 '-' => {
448 p.state = State.Number;
449 p.count = 0;
450 },
451 '0' => {
452 p.state = State.NumberMaybeDotOrExponent;
453 p.count = 0;
454 },
455 '1' ... '9' => {
456 p.state = State.NumberMaybeDigitOrDotOrExponent;
457 p.count = 0;
458 },
459 '"' => {
460 p.state = State.String;
461 p.count = 0;
462 },
463 't' => {
464 p.state = State.TrueLiteral1;
465 p.count = 0;
466 },
467 'f' => {
468 p.state = State.FalseLiteral1;
469 p.count = 0;
470 },
471 'n' => {
472 p.state = State.NullLiteral1;
473 p.count = 0;
474 },
475 0x09, 0x0A, 0x0D, 0x20 => {
476 // whitespace
477 },
478 else => {
479 return error.InvalidValueBegin;
480 },
481 },
482
483 State.ValueEnd => switch (c) {
484 ',' => {
485 p.after_string_state = State.fromInt(p.stack & 1);
486 p.state = State.ValueBeginNoClosing;
487 },
488 ']' => {
489 if (p.stack_used == 0) {
490 return error.UnbalancedBrackets;
491 }
492
493 p.state = State.ValueEnd;
494 p.after_string_state = State.fromInt(p.stack & 1);
495
496 p.stack >>= 1;
497 p.stack_used -= 1;
498
499 if (p.stack_used == 0) {
500 p.complete = true;
501 p.state = State.TopLevelEnd;
502 }
503
504 *token = Token.initMarker(Token.Id.ArrayEnd);
505 },
506 '}' => {
507 if (p.stack_used == 0) {
508 return error.UnbalancedBraces;
509 }
510
511 p.state = State.ValueEnd;
512 p.after_string_state = State.fromInt(p.stack & 1);
513
514 p.stack >>= 1;
515 p.stack_used -= 1;
516
517 if (p.stack_used == 0) {
518 p.complete = true;
519 p.state = State.TopLevelEnd;
520 }
521
522 *token = Token.initMarker(Token.Id.ObjectEnd);
523 },
524 0x09, 0x0A, 0x0D, 0x20 => {
525 // whitespace
526 },
527 else => {
528 return error.InvalidValueEnd;
529 },
530 },
531
532 State.ObjectSeparator => switch (c) {
533 ':' => {
534 p.state = State.ValueBegin;
535 p.after_string_state = State.ValueEnd;
536 },
537 0x09, 0x0A, 0x0D, 0x20 => {
538 // whitespace
539 },
540 else => {
541 return error.InvalidSeparator;
542 },
543 },
544
545 State.String => switch (c) {
546 0x00 ... 0x1F => {
547 return error.InvalidControlCharacter;
548 },
549 '"' => {
550 p.state = p.after_string_state;
551 if (p.after_value_state == State.TopLevelEnd) {
552 p.state = State.TopLevelEnd;
553 p.complete = true;
554 }
555
556 *token = Token.initString(p.count - 1, p.string_has_escape);
557 },
558 '\\' => {
559 p.state = State.StringEscapeCharacter;
560 },
561 0x20, 0x21, 0x23 ... 0x5B, 0x5D ... 0x7F => {
562 // non-control ascii
563 },
564 0xC0 ... 0xDF => {
565 p.state = State.StringUtf8Byte1;
566 },
567 0xE0 ... 0xEF => {
568 p.state = State.StringUtf8Byte2;
569 },
570 0xF0 ... 0xFF => {
571 p.state = State.StringUtf8Byte3;
572 },
573 else => {
574 return error.InvalidUtf8Byte;
575 },
576 },
577
578 State.StringUtf8Byte3 => switch (c >> 6) {
579 0b10 => p.state = State.StringUtf8Byte2,
580 else => return error.InvalidUtf8Byte,
581 },
582
583 State.StringUtf8Byte2 => switch (c >> 6) {
584 0b10 => p.state = State.StringUtf8Byte1,
585 else => return error.InvalidUtf8Byte,
586 },
587
588 State.StringUtf8Byte1 => switch (c >> 6) {
589 0b10 => p.state = State.String,
590 else => return error.InvalidUtf8Byte,
591 },
592
593 State.StringEscapeCharacter => switch (c) {
594 // NOTE: '/' is allowed as an escaped character but it also is allowed
595 // as unescaped according to the RFC. There is a reported errata which suggests
596 // removing the non-escaped variant but it makes more sense to simply disallow
597 // it as an escape code here.
598 //
599 // The current JSONTestSuite tests rely on both of this behaviour being present
600 // however, so we default to the status quo where both are accepted until this
601 // is further clarified.
602 '"', '\\', '/', 'b', 'f', 'n', 'r', 't' => {
603 p.string_has_escape = true;
604 p.state = State.String;
605 },
606 'u' => {
607 p.string_has_escape = true;
608 p.state = State.StringEscapeHexUnicode4;
609 },
610 else => {
611 return error.InvalidEscapeCharacter;
612 },
613 },
614
615 State.StringEscapeHexUnicode4 => switch (c) {
616 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
617 p.state = State.StringEscapeHexUnicode3;
618 },
619 else => return error.InvalidUnicodeHexSymbol,
620 },
621
622 State.StringEscapeHexUnicode3 => switch (c) {
623 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
624 p.state = State.StringEscapeHexUnicode2;
625 },
626 else => return error.InvalidUnicodeHexSymbol,
627 },
628
629 State.StringEscapeHexUnicode2 => switch (c) {
630 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
631 p.state = State.StringEscapeHexUnicode1;
632 },
633 else => return error.InvalidUnicodeHexSymbol,
634 },
635
636 State.StringEscapeHexUnicode1 => switch (c) {
637 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
638 p.state = State.String;
639 },
640 else => return error.InvalidUnicodeHexSymbol,
641 },
642
643 State.Number => {
644 p.complete = p.after_value_state == State.TopLevelEnd;
645 switch (c) {
646 '0' => {
647 p.state = State.NumberMaybeDotOrExponent;
648 },
649 '1' ... '9' => {
650 p.state = State.NumberMaybeDigitOrDotOrExponent;
651 },
652 else => {
653 return error.InvalidNumber;
654 },
655 }
656 },
657
658 State.NumberMaybeDotOrExponent => {
659 p.complete = p.after_value_state == State.TopLevelEnd;
660 switch (c) {
661 '.' => {
662 p.number_is_integer = false;
663 p.state = State.NumberFractionalRequired;
664 },
665 'e', 'E' => {
666 p.number_is_integer = false;
667 p.state = State.NumberExponent;
668 },
669 else => {
670 p.state = p.after_value_state;
671 *token = Token.initNumber(p.count, p.number_is_integer);
672 return true;
673 },
674 }
675 },
676
677 State.NumberMaybeDigitOrDotOrExponent => {
678 p.complete = p.after_value_state == State.TopLevelEnd;
679 switch (c) {
680 '.' => {
681 p.number_is_integer = false;
682 p.state = State.NumberFractionalRequired;
683 },
684 'e', 'E' => {
685 p.number_is_integer = false;
686 p.state = State.NumberExponent;
687 },
688 '0' ... '9' => {
689 // another digit
690 },
691 else => {
692 p.state = p.after_value_state;
693 *token = Token.initNumber(p.count, p.number_is_integer);
694 return true;
695 },
696 }
697 },
698
699 State.NumberFractionalRequired => {
700 p.complete = p.after_value_state == State.TopLevelEnd;
701 switch (c) {
702 '0' ... '9' => {
703 p.state = State.NumberFractional;
704 },
705 else => {
706 return error.InvalidNumber;
707 },
708 }
709 },
710
711 State.NumberFractional => {
712 p.complete = p.after_value_state == State.TopLevelEnd;
713 switch (c) {
714 '0' ... '9' => {
715 // another digit
716 },
717 'e', 'E' => {
718 p.number_is_integer = false;
719 p.state = State.NumberExponent;
720 },
721 else => {
722 p.state = p.after_value_state;
723 *token = Token.initNumber(p.count, p.number_is_integer);
724 return true;
725 },
726 }
727 },
728
729 State.NumberMaybeExponent => {
730 p.complete = p.after_value_state == State.TopLevelEnd;
731 switch (c) {
732 'e', 'E' => {
733 p.number_is_integer = false;
734 p.state = State.NumberExponent;
735 },
736 else => {
737 p.state = p.after_value_state;
738 *token = Token.initNumber(p.count, p.number_is_integer);
739 return true;
740 },
741 }
742 },
743
744 State.NumberExponent => switch (c) {
745 '-', '+', => {
746 p.complete = false;
747 p.state = State.NumberExponentDigitsRequired;
748 },
749 '0' ... '9' => {
750 p.complete = p.after_value_state == State.TopLevelEnd;
751 p.state = State.NumberExponentDigits;
752 },
753 else => {
754 return error.InvalidNumber;
755 },
756 },
757
758 State.NumberExponentDigitsRequired => switch (c) {
759 '0' ... '9' => {
760 p.complete = p.after_value_state == State.TopLevelEnd;
761 p.state = State.NumberExponentDigits;
762 },
763 else => {
764 return error.InvalidNumber;
765 },
766 },
767
768 State.NumberExponentDigits => {
769 p.complete = p.after_value_state == State.TopLevelEnd;
770 switch (c) {
771 '0' ... '9' => {
772 // another digit
773 },
774 else => {
775 p.state = p.after_value_state;
776 *token = Token.initNumber(p.count, p.number_is_integer);
777 return true;
778 },
779 }
780 },
781
782 State.TrueLiteral1 => switch (c) {
783 'r' => p.state = State.TrueLiteral2,
784 else => return error.InvalidLiteral,
785 },
786
787 State.TrueLiteral2 => switch (c) {
788 'u' => p.state = State.TrueLiteral3,
789 else => return error.InvalidLiteral,
790 },
791
792 State.TrueLiteral3 => switch (c) {
793 'e' => {
794 p.state = p.after_value_state;
795 p.complete = p.state == State.TopLevelEnd;
796 *token = Token.init(Token.Id.True, p.count + 1, 1);
797 },
798 else => {
799 return error.InvalidLiteral;
800 },
801 },
802
803 State.FalseLiteral1 => switch (c) {
804 'a' => p.state = State.FalseLiteral2,
805 else => return error.InvalidLiteral,
806 },
807
808 State.FalseLiteral2 => switch (c) {
809 'l' => p.state = State.FalseLiteral3,
810 else => return error.InvalidLiteral,
811 },
812
813 State.FalseLiteral3 => switch (c) {
814 's' => p.state = State.FalseLiteral4,
815 else => return error.InvalidLiteral,
816 },
817
818 State.FalseLiteral4 => switch (c) {
819 'e' => {
820 p.state = p.after_value_state;
821 p.complete = p.state == State.TopLevelEnd;
822 *token = Token.init(Token.Id.False, p.count + 1, 1);
823 },
824 else => {
825 return error.InvalidLiteral;
826 },
827 },
828
829 State.NullLiteral1 => switch (c) {
830 'u' => p.state = State.NullLiteral2,
831 else => return error.InvalidLiteral,
832 },
833
834 State.NullLiteral2 => switch (c) {
835 'l' => p.state = State.NullLiteral3,
836 else => return error.InvalidLiteral,
837 },
838
839 State.NullLiteral3 => switch (c) {
840 'l' => {
841 p.state = p.after_value_state;
842 p.complete = p.state == State.TopLevelEnd;
843 *token = Token.init(Token.Id.Null, p.count + 1, 1);
844 },
845 else => {
846 return error.InvalidLiteral;
847 },
848 },
849 }
850
851 return false;
852 }
853};
854
855// Validate a JSON string. This does not limit number precision so a decoder may not necessarily
856// be able to decode the string even if this returns true.
857pub fn validate(s: []const u8) bool {
858 var p = StreamingJsonParser.init();
859
860 for (s) |c, i| {
861 var token1: ?Token = undefined;
862 var token2: ?Token = undefined;
863
864 p.feed(c, &token1, &token2) catch |err| {
865 return false;
866 };
867 }
868
869 return p.complete;
870}
871
872const Allocator = std.mem.Allocator;
873const ArenaAllocator = std.heap.ArenaAllocator;
874const ArrayList = std.ArrayList;
875const HashMap = std.HashMap;
876
877pub const ValueTree = struct {
878 arena: ArenaAllocator,
879 root: Value,
880
881 pub fn deinit(self: &ValueTree) void {
882 self.arena.deinit();
883 }
884};
885
886pub const ObjectMap = HashMap([]const u8, Value, mem.hash_slice_u8, mem.eql_slice_u8);
887
888pub const Value = union(enum) {
889 Null,
890 Bool: bool,
891 Integer: i64,
892 Float: f64,
893 String: []const u8,
894 Array: ArrayList(Value),
895 Object: ObjectMap,
896
897 pub fn dump(self: &const Value) void {
898 switch (*self) {
899 Value.Null => {
900 std.debug.warn("null");
901 },
902 Value.Bool => |inner| {
903 std.debug.warn("{}", inner);
904 },
905 Value.Integer => |inner| {
906 std.debug.warn("{}", inner);
907 },
908 Value.Float => |inner| {
909 std.debug.warn("{.5}", inner);
910 },
911 Value.String => |inner| {
912 std.debug.warn("\"{}\"", inner);
913 },
914 Value.Array => |inner| {
915 var not_first = false;
916 std.debug.warn("[");
917 for (inner.toSliceConst()) |value| {
918 if (not_first) {
919 std.debug.warn(",");
920 }
921 not_first = true;
922 value.dump();
923 }
924 std.debug.warn("]");
925 },
926 Value.Object => |inner| {
927 var not_first = false;
928 std.debug.warn("{{");
929 var it = inner.iterator();
930
931 while (it.next()) |entry| {
932 if (not_first) {
933 std.debug.warn(",");
934 }
935 not_first = true;
936 std.debug.warn("\"{}\":", entry.key);
937 entry.value.dump();
938 }
939 std.debug.warn("}}");
940 },
941 }
942 }
943
944 pub fn dumpIndent(self: &const Value, indent: usize) void {
945 if (indent == 0) {
946 self.dump();
947 } else {
948 self.dumpIndentLevel(indent, 0);
949 }
950 }
951
952 fn dumpIndentLevel(self: &const Value, indent: usize, level: usize) void {
953 switch (*self) {
954 Value.Null => {
955 std.debug.warn("null");
956 },
957 Value.Bool => |inner| {
958 std.debug.warn("{}", inner);
959 },
960 Value.Integer => |inner| {
961 std.debug.warn("{}", inner);
962 },
963 Value.Float => |inner| {
964 std.debug.warn("{.5}", inner);
965 },
966 Value.String => |inner| {
967 std.debug.warn("\"{}\"", inner);
968 },
969 Value.Array => |inner| {
970 var not_first = false;
971 std.debug.warn("[\n");
972
973 for (inner.toSliceConst()) |value| {
974 if (not_first) {
975 std.debug.warn(",\n");
976 }
977 not_first = true;
978 padSpace(level + indent);
979 value.dumpIndentLevel(indent, level + indent);
980 }
981 std.debug.warn("\n");
982 padSpace(level);
983 std.debug.warn("]");
984 },
985 Value.Object => |inner| {
986 var not_first = false;
987 std.debug.warn("{{\n");
988 var it = inner.iterator();
989
990 while (it.next()) |entry| {
991 if (not_first) {
992 std.debug.warn(",\n");
993 }
994 not_first = true;
995 padSpace(level + indent);
996 std.debug.warn("\"{}\": ", entry.key);
997 entry.value.dumpIndentLevel(indent, level + indent);
998 }
999 std.debug.warn("\n");
1000 padSpace(level);
1001 std.debug.warn("}}");
1002 },
1003 }
1004 }
1005
1006 fn padSpace(indent: usize) void {
1007 var i: usize = 0;
1008 while (i < indent) : (i += 1) {
1009 std.debug.warn(" ");
1010 }
1011 }
1012};
1013
1014// A non-stream JSON parser which constructs a tree of Value's.
1015const JsonParser = struct {
1016 allocator: &Allocator,
1017 state: State,
1018 copy_strings: bool,
1019 // Stores parent nodes and un-combined Values.
1020 stack: ArrayList(Value),
1021
1022 const State = enum {
1023 ObjectKey,
1024 ObjectValue,
1025 ArrayValue,
1026 Simple,
1027 };
1028
1029 pub fn init(allocator: &Allocator, copy_strings: bool) JsonParser {
1030 return JsonParser {
1031 .allocator = allocator,
1032 .state = State.Simple,
1033 .copy_strings = copy_strings,
1034 .stack = ArrayList(Value).init(allocator),
1035 };
1036 }
1037
1038 pub fn deinit(p: &JsonParser) void {
1039 p.stack.deinit();
1040 }
1041
1042 pub fn reset(p: &JsonParser) void {
1043 p.state = State.Simple;
1044 p.stack.shrink(0);
1045 }
1046
1047 pub fn parse(p: &JsonParser, input: []const u8) !ValueTree {
1048 var mp = StreamingJsonParser.init();
1049
1050 var arena = ArenaAllocator.init(p.allocator);
1051 errdefer arena.deinit();
1052
1053 for (input) |c, i| {
1054 var mt1: ?Token = undefined;
1055 var mt2: ?Token = undefined;
1056
1057 try mp.feed(c, &mt1, &mt2);
1058 if (mt1) |t1| {
1059 try p.transition(&arena.allocator, input, i, t1);
1060
1061 if (mt2) |t2| {
1062 try p.transition(&arena.allocator, input, i, t2);
1063 }
1064 }
1065 }
1066
1067 // Handle top-level lonely number values.
1068 {
1069 const i = input.len;
1070 var mt1: ?Token = undefined;
1071 var mt2: ?Token = undefined;
1072
1073 try mp.feed(' ', &mt1, &mt2);
1074 if (mt1) |t1| {
1075 try p.transition(&arena.allocator, input, i, t1);
1076 }
1077 }
1078
1079 if (!mp.complete) {
1080 return error.IncompleteJsonInput;
1081 }
1082
1083 std.debug.assert(p.stack.len == 1);
1084
1085 return ValueTree {
1086 .arena = arena,
1087 .root = p.stack.at(0),
1088 };
1089 }
1090
1091 // Even though p.allocator exists, we take an explicit allocator so that allocation state
1092 // can be cleaned up on error correctly during a `parse` on call.
1093 fn transition(p: &JsonParser, allocator: &Allocator, input: []const u8, i: usize, token: &const Token) !void {
1094 switch (p.state) {
1095 State.ObjectKey => switch (token.id) {
1096 Token.Id.ObjectEnd => {
1097 if (p.stack.len == 1) {
1098 return;
1099 }
1100
1101 var value = p.stack.pop();
1102 try p.pushToParent(value);
1103 },
1104 Token.Id.String => {
1105 try p.stack.append(try p.parseString(allocator, token, input, i));
1106 p.state = State.ObjectValue;
1107 },
1108 else => {
1109 unreachable;
1110 },
1111 },
1112 State.ObjectValue => {
1113 var object = &p.stack.items[p.stack.len - 2].Object;
1114 var key = p.stack.items[p.stack.len - 1].String;
1115
1116 switch (token.id) {
1117 Token.Id.ObjectBegin => {
1118 try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
1119 p.state = State.ObjectKey;
1120 },
1121 Token.Id.ArrayBegin => {
1122 try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
1123 p.state = State.ArrayValue;
1124 },
1125 Token.Id.String => {
1126 _ = try object.put(key, try p.parseString(allocator, token, input, i));
1127 _ = p.stack.pop();
1128 p.state = State.ObjectKey;
1129 },
1130 Token.Id.Number => {
1131 _ = try object.put(key, try p.parseNumber(token, input, i));
1132 _ = p.stack.pop();
1133 p.state = State.ObjectKey;
1134 },
1135 Token.Id.True => {
1136 _ = try object.put(key, Value { .Bool = true });
1137 _ = p.stack.pop();
1138 p.state = State.ObjectKey;
1139 },
1140 Token.Id.False => {
1141 _ = try object.put(key, Value { .Bool = false });
1142 _ = p.stack.pop();
1143 p.state = State.ObjectKey;
1144 },
1145 Token.Id.Null => {
1146 _ = try object.put(key, Value.Null);
1147 _ = p.stack.pop();
1148 p.state = State.ObjectKey;
1149 },
1150 else => {
1151 unreachable;
1152 },
1153 }
1154 },
1155 State.ArrayValue => {
1156 var array = &p.stack.items[p.stack.len - 1].Array;
1157
1158 switch (token.id) {
1159 Token.Id.ArrayEnd => {
1160 if (p.stack.len == 1) {
1161 return;
1162 }
1163
1164 var value = p.stack.pop();
1165 try p.pushToParent(value);
1166 },
1167 Token.Id.ObjectBegin => {
1168 try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
1169 p.state = State.ObjectKey;
1170 },
1171 Token.Id.ArrayBegin => {
1172 try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
1173 p.state = State.ArrayValue;
1174 },
1175 Token.Id.String => {
1176 try array.append(try p.parseString(allocator, token, input, i));
1177 },
1178 Token.Id.Number => {
1179 try array.append(try p.parseNumber(token, input, i));
1180 },
1181 Token.Id.True => {
1182 try array.append(Value { .Bool = true });
1183 },
1184 Token.Id.False => {
1185 try array.append(Value { .Bool = false });
1186 },
1187 Token.Id.Null => {
1188 try array.append(Value.Null);
1189 },
1190 else => {
1191 unreachable;
1192 },
1193 }
1194 },
1195 State.Simple => switch (token.id) {
1196 Token.Id.ObjectBegin => {
1197 try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
1198 p.state = State.ObjectKey;
1199 },
1200 Token.Id.ArrayBegin => {
1201 try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
1202 p.state = State.ArrayValue;
1203 },
1204 Token.Id.String => {
1205 try p.stack.append(try p.parseString(allocator, token, input, i));
1206 },
1207 Token.Id.Number => {
1208 try p.stack.append(try p.parseNumber(token, input, i));
1209 },
1210 Token.Id.True => {
1211 try p.stack.append(Value { .Bool = true });
1212 },
1213 Token.Id.False => {
1214 try p.stack.append(Value { .Bool = false });
1215 },
1216 Token.Id.Null => {
1217 try p.stack.append(Value.Null);
1218 },
1219 Token.Id.ObjectEnd, Token.Id.ArrayEnd => {
1220 unreachable;
1221 },
1222 },
1223 }
1224 }
1225
1226 fn pushToParent(p: &JsonParser, value: &const Value) !void {
1227 switch (p.stack.at(p.stack.len - 1)) {
1228 // Object Parent -> [ ..., object, <key>, value ]
1229 Value.String => |key| {
1230 _ = p.stack.pop();
1231
1232 var object = &p.stack.items[p.stack.len - 1].Object;
1233 _ = try object.put(key, value);
1234 p.state = State.ObjectKey;
1235 },
1236 // Array Parent -> [ ..., <array>, value ]
1237 Value.Array => |*array| {
1238 try array.append(value);
1239 p.state = State.ArrayValue;
1240 },
1241 else => {
1242 unreachable;
1243 },
1244 }
1245 }
1246
1247 fn parseString(p: &JsonParser, allocator: &Allocator, token: &const Token, input: []const u8, i: usize) !Value {
1248 // TODO: We don't strictly have to copy values which do not contain any escape
1249 // characters if flagged with the option.
1250 const slice = token.slice(input, i);
1251 return Value { .String = try mem.dupe(p.allocator, u8, slice) };
1252 }
1253
1254 fn parseNumber(p: &JsonParser, token: &const Token, input: []const u8, i: usize) !Value {
1255 return if (token.number_is_integer)
1256 Value { .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
1257 else
1258 @panic("TODO: fmt.parseFloat not yet implemented")
1259 ;
1260 }
1261};
1262
1263const debug = std.debug;
1264
1265test "json parser dynamic" {
1266 var p = JsonParser.init(std.debug.global_allocator, false);
1267 defer p.deinit();
1268
1269 const s =
1270 \\{
1271 \\ "Image": {
1272 \\ "Width": 800,
1273 \\ "Height": 600,
1274 \\ "Title": "View from 15th Floor",
1275 \\ "Thumbnail": {
1276 \\ "Url": "http://www.example.com/image/481989943",
1277 \\ "Height": 125,
1278 \\ "Width": 100
1279 \\ },
1280 \\ "Animated" : false,
1281 \\ "IDs": [116, 943, 234, 38793]
1282 \\ }
1283 \\}
1284 ;
1285
1286 var tree = try p.parse(s);
1287 defer tree.deinit();
1288
1289 var root = tree.root;
1290
1291 var image = (??root.Object.get("Image")).value;
1292
1293 const width = (??image.Object.get("Width")).value;
1294 debug.assert(width.Integer == 800);
1295
1296 const height = (??image.Object.get("Height")).value;
1297 debug.assert(height.Integer == 600);
1298
1299 const title = (??image.Object.get("Title")).value;
1300 debug.assert(mem.eql(u8, title.String, "View from 15th Floor"));
1301
1302 const animated = (??image.Object.get("Animated")).value;
1303 debug.assert(animated.Bool == false);
1304}
std/json_test.zig created+1942
...@@ -0,0 +1,1942 @@
1// RFC 8529 conformance tests.
2//
3// Tests are taken from https://github.com/nst/JSONTestSuite
4// Read also http://seriot.ch/parsing_json.php for a good overview.
5
6const std = @import("index.zig");
7
8fn ok(comptime s: []const u8) void {
9 std.debug.assert(std.json.validate(s));
10}
11
12fn err(comptime s: []const u8) void {
13 std.debug.assert(!std.json.validate(s));
14}
15
16fn any(comptime s: []const u8) void {
17 std.debug.assert(true);
18}
19
20////////////////////////////////////////////////////////////////////////////////////////////////////
21
22test "y_array_arraysWithSpaces" {
23 ok(
24 \\[[] ]
25 );
26}
27
28test "y_array_empty" {
29 ok(
30 \\[]
31 );
32}
33
34test "y_array_empty-string" {
35 ok(
36 \\[""]
37 );
38}
39
40test "y_array_ending_with_newline" {
41 ok(
42 \\["a"]
43 );
44}
45
46test "y_array_false" {
47 ok(
48 \\[false]
49 );
50}
51
52test "y_array_heterogeneous" {
53 ok(
54 \\[null, 1, "1", {}]
55 );
56}
57
58test "y_array_null" {
59 ok(
60 \\[null]
61 );
62}
63
64test "y_array_with_1_and_newline" {
65 ok(
66 \\[1
67 \\]
68 );
69}
70
71test "y_array_with_leading_space" {
72 ok(
73 \\ [1]
74 );
75}
76
77test "y_array_with_several_null" {
78 ok(
79 \\[1,null,null,null,2]
80 );
81}
82
83test "y_array_with_trailing_space" {
84 ok(
85 "[2] "
86 );
87}
88
89test "y_number_0e+1" {
90 ok(
91 \\[0e+1]
92 );
93}
94
95test "y_number_0e1" {
96 ok(
97 \\[0e1]
98 );
99}
100
101test "y_number_after_space" {
102 ok(
103 \\[ 4]
104 );
105}
106
107test "y_number_double_close_to_zero" {
108 ok(
109 \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001]
110 );
111}
112
113test "y_number_int_with_exp" {
114 ok(
115 \\[20e1]
116 );
117}
118
119test "y_number" {
120 ok(
121 \\[123e65]
122 );
123}
124
125test "y_number_minus_zero" {
126 ok(
127 \\[-0]
128 );
129}
130
131test "y_number_negative_int" {
132 ok(
133 \\[-123]
134 );
135}
136
137test "y_number_negative_one" {
138 ok(
139 \\[-1]
140 );
141}
142
143test "y_number_negative_zero" {
144 ok(
145 \\[-0]
146 );
147}
148
149test "y_number_real_capital_e" {
150 ok(
151 \\[1E22]
152 );
153}
154
155test "y_number_real_capital_e_neg_exp" {
156 ok(
157 \\[1E-2]
158 );
159}
160
161test "y_number_real_capital_e_pos_exp" {
162 ok(
163 \\[1E+2]
164 );
165}
166
167test "y_number_real_exponent" {
168 ok(
169 \\[123e45]
170 );
171}
172
173test "y_number_real_fraction_exponent" {
174 ok(
175 \\[123.456e78]
176 );
177}
178
179test "y_number_real_neg_exp" {
180 ok(
181 \\[1e-2]
182 );
183}
184
185test "y_number_real_pos_exponent" {
186 ok(
187 \\[1e+2]
188 );
189}
190
191test "y_number_simple_int" {
192 ok(
193 \\[123]
194 );
195}
196
197test "y_number_simple_real" {
198 ok(
199 \\[123.456789]
200 );
201}
202
203test "y_object_basic" {
204 ok(
205 \\{"asd":"sdf"}
206 );
207}
208
209test "y_object_duplicated_key_and_value" {
210 ok(
211 \\{"a":"b","a":"b"}
212 );
213}
214
215test "y_object_duplicated_key" {
216 ok(
217 \\{"a":"b","a":"c"}
218 );
219}
220
221test "y_object_empty" {
222 ok(
223 \\{}
224 );
225}
226
227test "y_object_empty_key" {
228 ok(
229 \\{"":0}
230 );
231}
232
233test "y_object_escaped_null_in_key" {
234 ok(
235 \\{"foo\u0000bar": 42}
236 );
237}
238
239test "y_object_extreme_numbers" {
240 ok(
241 \\{ "min": -1.0e+28, "max": 1.0e+28 }
242 );
243}
244
245test "y_object" {
246 ok(
247 \\{"asd":"sdf", "dfg":"fgh"}
248 );
249}
250
251test "y_object_long_strings" {
252 ok(
253 \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
254 );
255}
256
257test "y_object_simple" {
258 ok(
259 \\{"a":[]}
260 );
261}
262
263test "y_object_string_unicode" {
264 ok(
265 \\{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" }
266 );
267}
268
269test "y_object_with_newlines" {
270 ok(
271 \\{
272 \\"a": "b"
273 \\}
274 );
275}
276
277test "y_string_1_2_3_bytes_UTF-8_sequences" {
278 ok(
279 \\["\u0060\u012a\u12AB"]
280 );
281}
282
283test "y_string_accepted_surrogate_pair" {
284 ok(
285 \\["\uD801\udc37"]
286 );
287}
288
289test "y_string_accepted_surrogate_pairs" {
290 ok(
291 \\["\ud83d\ude39\ud83d\udc8d"]
292 );
293}
294
295test "y_string_allowed_escapes" {
296 ok(
297 \\["\"\\\/\b\f\n\r\t"]
298 );
299}
300
301test "y_string_backslash_and_u_escaped_zero" {
302 ok(
303 \\["\\u0000"]
304 );
305}
306
307test "y_string_backslash_doublequotes" {
308 ok(
309 \\["\""]
310 );
311}
312
313test "y_string_comments" {
314 ok(
315 \\["a/*b*/c/*d//e"]
316 );
317}
318
319test "y_string_double_escape_a" {
320 ok(
321 \\["\\a"]
322 );
323}
324
325test "y_string_double_escape_n" {
326 ok(
327 \\["\\n"]
328 );
329}
330
331test "y_string_escaped_control_character" {
332 ok(
333 \\["\u0012"]
334 );
335}
336
337test "y_string_escaped_noncharacter" {
338 ok(
339 \\["\uFFFF"]
340 );
341}
342
343test "y_string_in_array" {
344 ok(
345 \\["asd"]
346 );
347}
348
349test "y_string_in_array_with_leading_space" {
350 ok(
351 \\[ "asd"]
352 );
353}
354
355test "y_string_last_surrogates_1_and_2" {
356 ok(
357 \\["\uDBFF\uDFFF"]
358 );
359}
360
361test "y_string_nbsp_uescaped" {
362 ok(
363 \\["new\u00A0line"]
364 );
365}
366
367test "y_string_nonCharacterInUTF-8_U+10FFFF" {
368 ok(
369 \\["􏿿"]
370 );
371}
372
373test "y_string_nonCharacterInUTF-8_U+FFFF" {
374 ok(
375 \\["￿"]
376 );
377}
378
379test "y_string_null_escape" {
380 ok(
381 \\["\u0000"]
382 );
383}
384
385test "y_string_one-byte-utf-8" {
386 ok(
387 \\["\u002c"]
388 );
389}
390
391test "y_string_pi" {
392 ok(
393 \\["π"]
394 );
395}
396
397test "y_string_reservedCharacterInUTF-8_U+1BFFF" {
398 ok(
399 \\["𛿿"]
400 );
401}
402
403test "y_string_simple_ascii" {
404 ok(
405 \\["asd "]
406 );
407}
408
409test "y_string_space" {
410 ok(
411 \\" "
412 );
413}
414
415test "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" {
416 ok(
417 \\["\uD834\uDd1e"]
418 );
419}
420
421test "y_string_three-byte-utf-8" {
422 ok(
423 \\["\u0821"]
424 );
425}
426
427test "y_string_two-byte-utf-8" {
428 ok(
429 \\["\u0123"]
430 );
431}
432
433test "y_string_u+2028_line_sep" {
434 ok(
435 \\["
"]
436 );
437}
438
439test "y_string_u+2029_par_sep" {
440 ok(
441 \\["
"]
442 );
443}
444
445test "y_string_uescaped_newline" {
446 ok(
447 \\["new\u000Aline"]
448 );
449}
450
451test "y_string_uEscape" {
452 ok(
453 \\["\u0061\u30af\u30EA\u30b9"]
454 );
455}
456
457test "y_string_unescaped_char_delete" {
458 ok(
459 \\[""]
460 );
461}
462
463test "y_string_unicode_2" {
464 ok(
465 \\["⍂㈴⍂"]
466 );
467}
468
469test "y_string_unicodeEscapedBackslash" {
470 ok(
471 \\["\u005C"]
472 );
473}
474
475test "y_string_unicode_escaped_double_quote" {
476 ok(
477 \\["\u0022"]
478 );
479}
480
481test "y_string_unicode" {
482 ok(
483 \\["\uA66D"]
484 );
485}
486
487test "y_string_unicode_U+10FFFE_nonchar" {
488 ok(
489 \\["\uDBFF\uDFFE"]
490 );
491}
492
493test "y_string_unicode_U+1FFFE_nonchar" {
494 ok(
495 \\["\uD83F\uDFFE"]
496 );
497}
498
499test "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" {
500 ok(
501 \\["\u200B"]
502 );
503}
504
505test "y_string_unicode_U+2064_invisible_plus" {
506 ok(
507 \\["\u2064"]
508 );
509}
510
511test "y_string_unicode_U+FDD0_nonchar" {
512 ok(
513 \\["\uFDD0"]
514 );
515}
516
517test "y_string_unicode_U+FFFE_nonchar" {
518 ok(
519 \\["\uFFFE"]
520 );
521}
522
523test "y_string_utf8" {
524 ok(
525 \\["€𝄞"]
526 );
527}
528
529test "y_string_with_del_character" {
530 ok(
531 \\["aa"]
532 );
533}
534
535test "y_structure_lonely_false" {
536 ok(
537 \\false
538 );
539}
540
541test "y_structure_lonely_int" {
542 ok(
543 \\42
544 );
545}
546
547test "y_structure_lonely_negative_real" {
548 ok(
549 \\-0.1
550 );
551}
552
553test "y_structure_lonely_null" {
554 ok(
555 \\null
556 );
557}
558
559test "y_structure_lonely_string" {
560 ok(
561 \\"asd"
562 );
563}
564
565test "y_structure_lonely_true" {
566 ok(
567 \\true
568 );
569}
570
571test "y_structure_string_empty" {
572 ok(
573 \\""
574 );
575}
576
577test "y_structure_trailing_newline" {
578 ok(
579 \\["a"]
580 );
581}
582
583test "y_structure_true_in_array" {
584 ok(
585 \\[true]
586 );
587}
588
589test "y_structure_whitespace_array" {
590 ok(
591 " [] "
592 );
593}
594
595////////////////////////////////////////////////////////////////////////////////////////////////////
596
597test "n_array_1_true_without_comma" {
598 err(
599 \\[1 true]
600 );
601}
602
603test "n_array_a_invalid_utf8" {
604 err(
605 \\[aå]
606 );
607}
608
609test "n_array_colon_instead_of_comma" {
610 err(
611 \\["": 1]
612 );
613}
614
615test "n_array_comma_after_close" {
616 //err(
617 // \\[""],
618 //);
619}
620
621test "n_array_comma_and_number" {
622 err(
623 \\[,1]
624 );
625}
626
627test "n_array_double_comma" {
628 err(
629 \\[1,,2]
630 );
631}
632
633test "n_array_double_extra_comma" {
634 err(
635 \\["x",,]
636 );
637}
638
639test "n_array_extra_close" {
640 err(
641 \\["x"]]
642 );
643}
644
645test "n_array_extra_comma" {
646 //err(
647 // \\["",]
648 //);
649}
650
651test "n_array_incomplete_invalid_value" {
652 err(
653 \\[x
654 );
655}
656
657test "n_array_incomplete" {
658 err(
659 \\["x"
660 );
661}
662
663test "n_array_inner_array_no_comma" {
664 err(
665 \\[3[4]]
666 );
667}
668
669test "n_array_invalid_utf8" {
670 err(
671 \\[ÿ]
672 );
673}
674
675test "n_array_items_separated_by_semicolon" {
676 err(
677 \\[1:2]
678 );
679}
680
681test "n_array_just_comma" {
682 err(
683 \\[,]
684 );
685}
686
687test "n_array_just_minus" {
688 err(
689 \\[-]
690 );
691}
692
693test "n_array_missing_value" {
694 err(
695 \\[ , ""]
696 );
697}
698
699test "n_array_newlines_unclosed" {
700 err(
701 \\["a",
702 \\4
703 \\,1,
704 );
705}
706
707
708test "n_array_number_and_comma" {
709 err(
710 \\[1,]
711 );
712}
713
714test "n_array_number_and_several_commas" {
715 err(
716 \\[1,,]
717 );
718}
719
720test "n_array_spaces_vertical_tab_formfeed" {
721 err(
722 \\[" a"\f]
723 );
724}
725
726test "n_array_star_inside" {
727 err(
728 \\[*]
729 );
730}
731
732test "n_array_unclosed" {
733 err(
734 \\[""
735 );
736}
737
738test "n_array_unclosed_trailing_comma" {
739 err(
740 \\[1,
741 );
742}
743
744test "n_array_unclosed_with_new_lines" {
745 err(
746 \\[1,
747 \\1
748 \\,1
749 );
750}
751
752test "n_array_unclosed_with_object_inside" {
753 err(
754 \\[{}
755 );
756}
757
758test "n_incomplete_false" {
759 err(
760 \\[fals]
761 );
762}
763
764test "n_incomplete_null" {
765 err(
766 \\[nul]
767 );
768}
769
770test "n_incomplete_true" {
771 err(
772 \\[tru]
773 );
774}
775
776test "n_multidigit_number_then_00" {
777 err(
778 \\123
779 );
780}
781
782test "n_number_0.1.2" {
783 err(
784 \\[0.1.2]
785 );
786}
787
788test "n_number_-01" {
789 err(
790 \\[-01]
791 );
792}
793
794test "n_number_0.3e" {
795 err(
796 \\[0.3e]
797 );
798}
799
800test "n_number_0.3e+" {
801 err(
802 \\[0.3e+]
803 );
804}
805
806test "n_number_0_capital_E" {
807 err(
808 \\[0E]
809 );
810}
811
812test "n_number_0_capital_E+" {
813 err(
814 \\[0E+]
815 );
816}
817
818test "n_number_0.e1" {
819 err(
820 \\[0.e1]
821 );
822}
823
824test "n_number_0e" {
825 err(
826 \\[0e]
827 );
828}
829
830test "n_number_0e+" {
831 err(
832 \\[0e+]
833 );
834}
835
836test "n_number_1_000" {
837 err(
838 \\[1 000.0]
839 );
840}
841
842test "n_number_1.0e-" {
843 err(
844 \\[1.0e-]
845 );
846}
847
848test "n_number_1.0e" {
849 err(
850 \\[1.0e]
851 );
852}
853
854test "n_number_1.0e+" {
855 err(
856 \\[1.0e+]
857 );
858}
859
860test "n_number_-1.0." {
861 err(
862 \\[-1.0.]
863 );
864}
865
866test "n_number_1eE2" {
867 err(
868 \\[1eE2]
869 );
870}
871
872test "n_number_.-1" {
873 err(
874 \\[.-1]
875 );
876}
877
878test "n_number_+1" {
879 err(
880 \\[+1]
881 );
882}
883
884test "n_number_.2e-3" {
885 err(
886 \\[.2e-3]
887 );
888}
889
890test "n_number_2.e-3" {
891 err(
892 \\[2.e-3]
893 );
894}
895
896test "n_number_2.e+3" {
897 err(
898 \\[2.e+3]
899 );
900}
901
902test "n_number_2.e3" {
903 err(
904 \\[2.e3]
905 );
906}
907
908test "n_number_-2." {
909 err(
910 \\[-2.]
911 );
912}
913
914test "n_number_9.e+" {
915 err(
916 \\[9.e+]
917 );
918}
919
920test "n_number_expression" {
921 err(
922 \\[1+2]
923 );
924}
925
926test "n_number_hex_1_digit" {
927 err(
928 \\[0x1]
929 );
930}
931
932test "n_number_hex_2_digits" {
933 err(
934 \\[0x42]
935 );
936}
937
938test "n_number_infinity" {
939 err(
940 \\[Infinity]
941 );
942}
943
944test "n_number_+Inf" {
945 err(
946 \\[+Inf]
947 );
948}
949
950test "n_number_Inf" {
951 err(
952 \\[Inf]
953 );
954}
955
956test "n_number_invalid+-" {
957 err(
958 \\[0e+-1]
959 );
960}
961
962test "n_number_invalid-negative-real" {
963 err(
964 \\[-123.123foo]
965 );
966}
967
968test "n_number_invalid-utf-8-in-bigger-int" {
969 err(
970 \\[123å]
971 );
972}
973
974test "n_number_invalid-utf-8-in-exponent" {
975 err(
976 \\[1e1å]
977 );
978}
979
980test "n_number_invalid-utf-8-in-int" {
981 err(
982 \\[0å]
983 );
984}
985
986
987test "n_number_++" {
988 err(
989 \\[++1234]
990 );
991}
992
993test "n_number_minus_infinity" {
994 err(
995 \\[-Infinity]
996 );
997}
998
999test "n_number_minus_sign_with_trailing_garbage" {
1000 err(
1001 \\[-foo]
1002 );
1003}
1004
1005test "n_number_minus_space_1" {
1006 err(
1007 \\[- 1]
1008 );
1009}
1010
1011test "n_number_-NaN" {
1012 err(
1013 \\[-NaN]
1014 );
1015}
1016
1017test "n_number_NaN" {
1018 err(
1019 \\[NaN]
1020 );
1021}
1022
1023test "n_number_neg_int_starting_with_zero" {
1024 err(
1025 \\[-012]
1026 );
1027}
1028
1029test "n_number_neg_real_without_int_part" {
1030 err(
1031 \\[-.123]
1032 );
1033}
1034
1035test "n_number_neg_with_garbage_at_end" {
1036 err(
1037 \\[-1x]
1038 );
1039}
1040
1041test "n_number_real_garbage_after_e" {
1042 err(
1043 \\[1ea]
1044 );
1045}
1046
1047test "n_number_real_with_invalid_utf8_after_e" {
1048 err(
1049 \\[1eå]
1050 );
1051}
1052
1053test "n_number_real_without_fractional_part" {
1054 err(
1055 \\[1.]
1056 );
1057}
1058
1059test "n_number_starting_with_dot" {
1060 err(
1061 \\[.123]
1062 );
1063}
1064
1065test "n_number_U+FF11_fullwidth_digit_one" {
1066 err(
1067 \\[1]
1068 );
1069}
1070
1071test "n_number_with_alpha_char" {
1072 err(
1073 \\[1.8011670033376514H-308]
1074 );
1075}
1076
1077test "n_number_with_alpha" {
1078 err(
1079 \\[1.2a-3]
1080 );
1081}
1082
1083test "n_number_with_leading_zero" {
1084 err(
1085 \\[012]
1086 );
1087}
1088
1089test "n_object_bad_value" {
1090 err(
1091 \\["x", truth]
1092 );
1093}
1094
1095test "n_object_bracket_key" {
1096 err(
1097 \\{[: "x"}
1098 );
1099}
1100
1101test "n_object_comma_instead_of_colon" {
1102 err(
1103 \\{"x", null}
1104 );
1105}
1106
1107test "n_object_double_colon" {
1108 err(
1109 \\{"x"::"b"}
1110 );
1111}
1112
1113test "n_object_emoji" {
1114 err(
1115 \\{🇨🇭}
1116 );
1117}
1118
1119test "n_object_garbage_at_end" {
1120 err(
1121 \\{"a":"a" 123}
1122 );
1123}
1124
1125test "n_object_key_with_single_quotes" {
1126 err(
1127 \\{key: 'value'}
1128 );
1129}
1130
1131test "n_object_lone_continuation_byte_in_key_and_trailing_comma" {
1132 err(
1133 \\{"¹":"0",}
1134 );
1135}
1136
1137test "n_object_missing_colon" {
1138 err(
1139 \\{"a" b}
1140 );
1141}
1142
1143test "n_object_missing_key" {
1144 err(
1145 \\{:"b"}
1146 );
1147}
1148
1149test "n_object_missing_semicolon" {
1150 err(
1151 \\{"a" "b"}
1152 );
1153}
1154
1155test "n_object_missing_value" {
1156 err(
1157 \\{"a":
1158 );
1159}
1160
1161test "n_object_no-colon" {
1162 err(
1163 \\{"a"
1164 );
1165}
1166
1167test "n_object_non_string_key_but_huge_number_instead" {
1168 err(
1169 \\{9999E9999:1}
1170 );
1171}
1172
1173test "n_object_non_string_key" {
1174 err(
1175 \\{1:1}
1176 );
1177}
1178
1179test "n_object_repeated_null_null" {
1180 err(
1181 \\{null:null,null:null}
1182 );
1183}
1184
1185test "n_object_several_trailing_commas" {
1186 err(
1187 \\{"id":0,,,,,}
1188 );
1189}
1190
1191test "n_object_single_quote" {
1192 err(
1193 \\{'a':0}
1194 );
1195}
1196
1197test "n_object_trailing_comma" {
1198 err(
1199 \\{"id":0,}
1200 );
1201}
1202
1203test "n_object_trailing_comment" {
1204 err(
1205 \\{"a":"b"}/**/
1206 );
1207}
1208
1209test "n_object_trailing_comment_open" {
1210 err(
1211 \\{"a":"b"}/**//
1212 );
1213}
1214
1215test "n_object_trailing_comment_slash_open_incomplete" {
1216 err(
1217 \\{"a":"b"}/
1218 );
1219}
1220
1221test "n_object_trailing_comment_slash_open" {
1222 err(
1223 \\{"a":"b"}//
1224 );
1225}
1226
1227test "n_object_two_commas_in_a_row" {
1228 err(
1229 \\{"a":"b",,"c":"d"}
1230 );
1231}
1232
1233test "n_object_unquoted_key" {
1234 err(
1235 \\{a: "b"}
1236 );
1237}
1238
1239test "n_object_unterminated-value" {
1240 err(
1241 \\{"a":"a
1242 );
1243 }
1244
1245test "n_object_with_single_string" {
1246 err(
1247 \\{ "foo" : "bar", "a" }
1248 );
1249}
1250
1251test "n_object_with_trailing_garbage" {
1252 err(
1253 \\{"a":"b"}#
1254 );
1255}
1256
1257test "n_single_space" {
1258 err(
1259 " "
1260 );
1261}
1262
1263test "n_string_1_surrogate_then_escape" {
1264 err(
1265 \\["\uD800\"]
1266 );
1267}
1268
1269test "n_string_1_surrogate_then_escape_u1" {
1270 err(
1271 \\["\uD800\u1"]
1272 );
1273}
1274
1275test "n_string_1_surrogate_then_escape_u1x" {
1276 err(
1277 \\["\uD800\u1x"]
1278 );
1279}
1280
1281test "n_string_1_surrogate_then_escape_u" {
1282 err(
1283 \\["\uD800\u"]
1284 );
1285}
1286
1287test "n_string_accentuated_char_no_quotes" {
1288 err(
1289 \\[é]
1290 );
1291}
1292
1293test "n_string_backslash_00" {
1294 err(
1295 \\["\"]
1296 );
1297}
1298
1299test "n_string_escaped_backslash_bad" {
1300 err(
1301 \\["\\\"]
1302 );
1303}
1304
1305test "n_string_escaped_ctrl_char_tab" {
1306 err(
1307 \\["\ "]
1308 );
1309}
1310
1311test "n_string_escaped_emoji" {
1312 err(
1313 \\["\🌀"]
1314 );
1315}
1316
1317test "n_string_escape_x" {
1318 err(
1319 \\["\x00"]
1320 );
1321}
1322
1323test "n_string_incomplete_escaped_character" {
1324 err(
1325 \\["\u00A"]
1326 );
1327}
1328
1329test "n_string_incomplete_escape" {
1330 err(
1331 \\["\"]
1332 );
1333}
1334
1335test "n_string_incomplete_surrogate_escape_invalid" {
1336 err(
1337 \\["\uD800\uD800\x"]
1338 );
1339}
1340
1341test "n_string_incomplete_surrogate" {
1342 err(
1343 \\["\uD834\uDd"]
1344 );
1345}
1346
1347test "n_string_invalid_backslash_esc" {
1348 err(
1349 \\["\a"]
1350 );
1351}
1352
1353test "n_string_invalid_unicode_escape" {
1354 err(
1355 \\["\uqqqq"]
1356 );
1357}
1358
1359test "n_string_invalid_utf8_after_escape" {
1360 err(
1361 \\["\å"]
1362 );
1363}
1364
1365test "n_string_invalid-utf-8-in-escape" {
1366 err(
1367 \\["\uå"]
1368 );
1369}
1370
1371test "n_string_leading_uescaped_thinspace" {
1372 err(
1373 \\[\u0020"asd"]
1374 );
1375}
1376
1377test "n_string_no_quotes_with_bad_escape" {
1378 err(
1379 \\[\n]
1380 );
1381}
1382
1383test "n_string_single_doublequote" {
1384 err(
1385 \\"
1386 );
1387}
1388
1389test "n_string_single_quote" {
1390 err(
1391 \\['single quote']
1392 );
1393}
1394
1395test "n_string_single_string_no_double_quotes" {
1396 err(
1397 \\abc
1398 );
1399}
1400
1401test "n_string_start_escape_unclosed" {
1402 err(
1403 \\["\
1404 );
1405}
1406
1407test "n_string_unescaped_crtl_char" {
1408 err(
1409 \\["aa"]
1410 );
1411}
1412
1413test "n_string_unescaped_newline" {
1414 err(
1415 \\["new
1416 \\line"]
1417 );
1418}
1419
1420test "n_string_unescaped_tab" {
1421 err(
1422 \\[" "]
1423 );
1424}
1425
1426test "n_string_unicode_CapitalU" {
1427 err(
1428 \\"\UA66D"
1429 );
1430}
1431
1432test "n_string_with_trailing_garbage" {
1433 err(
1434 \\""x
1435 );
1436}
1437
1438test "n_structure_100000_opening_arrays" {
1439 err(
1440 "[" ** 100000
1441 );
1442}
1443
1444test "n_structure_angle_bracket_." {
1445 err(
1446 \\<.>
1447 );
1448}
1449
1450test "n_structure_angle_bracket_null" {
1451 err(
1452 \\[<null>]
1453 );
1454}
1455
1456test "n_structure_array_trailing_garbage" {
1457 err(
1458 \\[1]x
1459 );
1460}
1461
1462test "n_structure_array_with_extra_array_close" {
1463 err(
1464 \\[1]]
1465 );
1466}
1467
1468test "n_structure_array_with_unclosed_string" {
1469 err(
1470 \\["asd]
1471 );
1472}
1473
1474test "n_structure_ascii-unicode-identifier" {
1475 err(
1476 \\aå
1477 );
1478}
1479
1480test "n_structure_capitalized_True" {
1481 err(
1482 \\[True]
1483 );
1484}
1485
1486test "n_structure_close_unopened_array" {
1487 err(
1488 \\1]
1489 );
1490}
1491
1492test "n_structure_comma_instead_of_closing_brace" {
1493 err(
1494 \\{"x": true,
1495 );
1496}
1497
1498test "n_structure_double_array" {
1499 err(
1500 \\[][]
1501 );
1502}
1503
1504test "n_structure_end_array" {
1505 err(
1506 \\]
1507 );
1508}
1509
1510test "n_structure_incomplete_UTF8_BOM" {
1511 err(
1512 \\ï»{}
1513 );
1514}
1515
1516test "n_structure_lone-invalid-utf-8" {
1517 err(
1518 \\å
1519 );
1520}
1521
1522test "n_structure_lone-open-bracket" {
1523 err(
1524 \\[
1525 );
1526}
1527
1528test "n_structure_no_data" {
1529 err(
1530 \\
1531 );
1532}
1533
1534test "n_structure_null-byte-outside-string" {
1535 err(
1536 \\[]
1537 );
1538}
1539
1540test "n_structure_number_with_trailing_garbage" {
1541 err(
1542 \\2@
1543 );
1544}
1545
1546test "n_structure_object_followed_by_closing_object" {
1547 err(
1548 \\{}}
1549 );
1550}
1551
1552test "n_structure_object_unclosed_no_value" {
1553 err(
1554 \\{"":
1555 );
1556}
1557
1558test "n_structure_object_with_comment" {
1559 err(
1560 \\{"a":/*comment*/"b"}
1561 );
1562}
1563
1564test "n_structure_object_with_trailing_garbage" {
1565 err(
1566 \\{"a": true} "x"
1567 );
1568}
1569
1570test "n_structure_open_array_apostrophe" {
1571 err(
1572 \\['
1573 );
1574}
1575
1576test "n_structure_open_array_comma" {
1577 err(
1578 \\[,
1579 );
1580}
1581
1582test "n_structure_open_array_object" {
1583 err(
1584 "[{\"\":" ** 50000
1585 );
1586}
1587
1588test "n_structure_open_array_open_object" {
1589 err(
1590 \\[{
1591 );
1592}
1593
1594test "n_structure_open_array_open_string" {
1595 err(
1596 \\["a
1597 );
1598}
1599
1600test "n_structure_open_array_string" {
1601 err(
1602 \\["a"
1603 );
1604}
1605
1606test "n_structure_open_object_close_array" {
1607 err(
1608 \\{]
1609 );
1610}
1611
1612test "n_structure_open_object_comma" {
1613 err(
1614 \\{,
1615 );
1616}
1617
1618test "n_structure_open_object" {
1619 err(
1620 \\{
1621 );
1622}
1623
1624test "n_structure_open_object_open_array" {
1625 err(
1626 \\{[
1627 );
1628}
1629
1630test "n_structure_open_object_open_string" {
1631 err(
1632 \\{"a
1633 );
1634}
1635
1636test "n_structure_open_object_string_with_apostrophes" {
1637 err(
1638 \\{'a'
1639 );
1640}
1641
1642test "n_structure_open_open" {
1643 err(
1644 \\["\{["\{["\{["\{
1645 );
1646}
1647
1648test "n_structure_single_eacute" {
1649 err(
1650 \\é
1651 );
1652}
1653
1654test "n_structure_single_star" {
1655 err(
1656 \\*
1657 );
1658}
1659
1660test "n_structure_trailing_#" {
1661 err(
1662 \\{"a":"b"}#{}
1663 );
1664}
1665
1666test "n_structure_U+2060_word_joined" {
1667 err(
1668 \\[⁠]
1669 );
1670}
1671
1672test "n_structure_uescaped_LF_before_string" {
1673 err(
1674 \\[\u000A""]
1675 );
1676}
1677
1678test "n_structure_unclosed_array" {
1679 err(
1680 \\[1
1681 );
1682}
1683
1684test "n_structure_unclosed_array_partial_null" {
1685 err(
1686 \\[ false, nul
1687 );
1688}
1689
1690test "n_structure_unclosed_array_unfinished_false" {
1691 err(
1692 \\[ true, fals
1693 );
1694}
1695
1696test "n_structure_unclosed_array_unfinished_true" {
1697 err(
1698 \\[ false, tru
1699 );
1700}
1701
1702test "n_structure_unclosed_object" {
1703 err(
1704 \\{"asd":"asd"
1705 );
1706}
1707
1708test "n_structure_unicode-identifier" {
1709 err(
1710 \\Ã¥
1711 );
1712}
1713
1714test "n_structure_UTF8_BOM_no_data" {
1715 err(
1716 \\
1717 );
1718}
1719
1720test "n_structure_whitespace_formfeed" {
1721 err(
1722 \\[ ]
1723 );
1724}
1725
1726test "n_structure_whitespace_U+2060_word_joiner" {
1727 err(
1728 \\[⁠]
1729 );
1730}
1731
1732////////////////////////////////////////////////////////////////////////////////////////////////////
1733
1734test "i_number_double_huge_neg_exp" {
1735 any(
1736 \\[123.456e-789]
1737 );
1738}
1739
1740test "i_number_huge_exp" {
1741 any(
1742 \\[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006]
1743 );
1744}
1745
1746test "i_number_neg_int_huge_exp" {
1747 any(
1748 \\[-1e+9999]
1749 );
1750}
1751
1752test "i_number_pos_double_huge_exp" {
1753 any(
1754 \\[1.5e+9999]
1755 );
1756}
1757
1758test "i_number_real_neg_overflow" {
1759 any(
1760 \\[-123123e100000]
1761 );
1762}
1763
1764test "i_number_real_pos_overflow" {
1765 any(
1766 \\[123123e100000]
1767 );
1768}
1769
1770test "i_number_real_underflow" {
1771 any(
1772 \\[123e-10000000]
1773 );
1774}
1775
1776test "i_number_too_big_neg_int" {
1777 any(
1778 \\[-123123123123123123123123123123]
1779 );
1780}
1781
1782test "i_number_too_big_pos_int" {
1783 any(
1784 \\[100000000000000000000]
1785 );
1786}
1787
1788test "i_number_very_big_negative_int" {
1789 any(
1790 \\[-237462374673276894279832749832423479823246327846]
1791 );
1792}
1793
1794test "i_object_key_lone_2nd_surrogate" {
1795 any(
1796 \\{"\uDFAA":0}
1797 );
1798}
1799
1800test "i_string_1st_surrogate_but_2nd_missing" {
1801 any(
1802 \\["\uDADA"]
1803 );
1804}
1805
1806test "i_string_1st_valid_surrogate_2nd_invalid" {
1807 any(
1808 \\["\uD888\u1234"]
1809 );
1810}
1811
1812test "i_string_incomplete_surrogate_and_escape_valid" {
1813 any(
1814 \\["\uD800\n"]
1815 );
1816}
1817
1818test "i_string_incomplete_surrogate_pair" {
1819 any(
1820 \\["\uDd1ea"]
1821 );
1822}
1823
1824test "i_string_incomplete_surrogates_escape_valid" {
1825 any(
1826 \\["\uD800\uD800\n"]
1827 );
1828}
1829
1830test "i_string_invalid_lonely_surrogate" {
1831 any(
1832 \\["\ud800"]
1833 );
1834}
1835
1836test "i_string_invalid_surrogate" {
1837 any(
1838 \\["\ud800abc"]
1839 );
1840}
1841
1842test "i_string_invalid_utf-8" {
1843 any(
1844 \\["ÿ"]
1845 );
1846}
1847
1848test "i_string_inverted_surrogates_U+1D11E" {
1849 any(
1850 \\["\uDd1e\uD834"]
1851 );
1852}
1853
1854test "i_string_iso_latin_1" {
1855 any(
1856 \\["é"]
1857 );
1858}
1859
1860test "i_string_lone_second_surrogate" {
1861 any(
1862 \\["\uDFAA"]
1863 );
1864}
1865
1866test "i_string_lone_utf8_continuation_byte" {
1867 any(
1868 \\[""]
1869 );
1870}
1871
1872test "i_string_not_in_unicode_range" {
1873 any(
1874 \\["ô¿¿¿"]
1875 );
1876}
1877
1878test "i_string_overlong_sequence_2_bytes" {
1879 any(
1880 \\["À¯"]
1881 );
1882}
1883
1884test "i_string_overlong_sequence_6_bytes" {
1885 any(
1886 \\["üƒ¿¿¿¿"]
1887 );
1888}
1889
1890test "i_string_overlong_sequence_6_bytes_null" {
1891 any(
1892 \\["ü€€€€€"]
1893 );
1894}
1895
1896test "i_string_truncated-utf-8" {
1897 any(
1898 \\["àÿ"]
1899 );
1900}
1901
1902test "i_string_utf16BE_no_BOM" {
1903 any(
1904 \\["é"]
1905 );
1906}
1907
1908test "i_string_utf16LE_no_BOM" {
1909 any(
1910 \\["é"]
1911 );
1912}
1913
1914test "i_string_UTF-16LE_with_BOM" {
1915 any(
1916 \\ÿþ["é"]
1917 );
1918}
1919
1920test "i_string_UTF-8_invalid_sequence" {
1921 any(
1922 \\["日шú"]
1923 );
1924}
1925
1926test "i_string_UTF8_surrogate_U+D800" {
1927 any(
1928 \\["í €"]
1929 );
1930}
1931
1932test "i_structure_500_nested_arrays" {
1933 any(
1934 ("[" ** 500) ++ ("]" ** 500)
1935 );
1936}
1937
1938test "i_structure_UTF-8_BOM_empty_object" {
1939 any(
1940 \\{}
1941 );
1942}
std/math/index.zig+26
...@@ -541,6 +541,32 @@ test "math.floorPowerOfTwo" {...@@ -541,6 +541,32 @@ test "math.floorPowerOfTwo" {
541 comptime testFloorPowerOfTwo();541 comptime testFloorPowerOfTwo();
542}542}
543543
544pub fn log2_int(comptime T: type, x: T) Log2Int(T) {
545 assert(x != 0);
546 return Log2Int(T)(T.bit_count - 1 - @clz(x));
547}
548
549pub fn log2_int_ceil(comptime T: type, x: T) Log2Int(T) {
550 assert(x != 0);
551 const log2_val = log2_int(T, x);
552 if (T(1) << log2_val == x)
553 return log2_val;
554 return log2_val + 1;
555}
556
557test "std.math.log2_int_ceil" {
558 assert(log2_int_ceil(u32, 1) == 0);
559 assert(log2_int_ceil(u32, 2) == 1);
560 assert(log2_int_ceil(u32, 3) == 2);
561 assert(log2_int_ceil(u32, 4) == 2);
562 assert(log2_int_ceil(u32, 5) == 3);
563 assert(log2_int_ceil(u32, 6) == 3);
564 assert(log2_int_ceil(u32, 7) == 3);
565 assert(log2_int_ceil(u32, 8) == 3);
566 assert(log2_int_ceil(u32, 9) == 4);
567 assert(log2_int_ceil(u32, 10) == 4);
568}
569
544fn testFloorPowerOfTwo() void {570fn testFloorPowerOfTwo() void {
545 assert(floorPowerOfTwo(u32, 63) == 32);571 assert(floorPowerOfTwo(u32, 63) == 32);
546 assert(floorPowerOfTwo(u32, 64) == 64);572 assert(floorPowerOfTwo(u32, 64) == 64);
std/math/log2.zig+1-6
...@@ -31,17 +31,12 @@ pub fn log2(x: var) @typeOf(x) {...@@ -31,17 +31,12 @@ pub fn log2(x: var) @typeOf(x) {
31 return result;31 return result;
32 },32 },
33 TypeId.Int => {33 TypeId.Int => {
34 return log2_int(T, x);34 return math.log2_int(T, x);
35 },35 },
36 else => @compileError("log2 not implemented for " ++ @typeName(T)),36 else => @compileError("log2 not implemented for " ++ @typeName(T)),
37 }37 }
38}38}
3939
40pub fn log2_int(comptime T: type, x: T) T {
41 assert(x != 0);
42 return T.bit_count - 1 - T(@clz(x));
43}
44
45pub fn log2_32(x_: f32) f32 {40pub fn log2_32(x_: f32) f32 {
46 const ivln2hi: f32 = 1.4428710938e+00;41 const ivln2hi: f32 = 1.4428710938e+00;
47 const ivln2lo: f32 = -1.7605285393e-04;42 const ivln2lo: f32 = -1.7605285393e-04;
std/os/index.zig+1
...@@ -2473,6 +2473,7 @@ pub const Thread = struct {...@@ -2473,6 +2473,7 @@ pub const Thread = struct {
2473 },2473 },
2474 builtin.Os.windows => {2474 builtin.Os.windows => {
2475 assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);2475 assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
2476 assert(windows.CloseHandle(self.data.handle) != 0);
2476 assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);2477 assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);
2477 },2478 },
2478 else => @compileError("Unsupported OS"),2479 else => @compileError("Unsupported OS"),
std/segmented_list.zig created+368
...@@ -0,0 +1,368 @@
1const std = @import("index.zig");
2const assert = std.debug.assert;
3const Allocator = std.mem.Allocator;
4
5// Imagine that `fn at(self: &Self, index: usize) &T` is a customer asking for a box
6// from a warehouse, based on a flat array, boxes ordered from 0 to N - 1.
7// But the warehouse actually stores boxes in shelves of increasing powers of 2 sizes.
8// So when the customer requests a box index, we have to translate it to shelf index
9// and box index within that shelf. Illustration:
10//
11// customer indexes:
12// shelf 0: 0
13// shelf 1: 1 2
14// shelf 2: 3 4 5 6
15// shelf 3: 7 8 9 10 11 12 13 14
16// shelf 4: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
17// shelf 5: 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
18// ...
19//
20// warehouse indexes:
21// shelf 0: 0
22// shelf 1: 0 1
23// shelf 2: 0 1 2 3
24// shelf 3: 0 1 2 3 4 5 6 7
25// shelf 4: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
26// shelf 5: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
27// ...
28//
29// With this arrangement, here are the equations to get the shelf index and
30// box index based on customer box index:
31//
32// shelf_index = floor(log2(customer_index + 1))
33// shelf_count = ceil(log2(box_count + 1))
34// box_index = customer_index + 1 - 2 ** shelf
35// shelf_size = 2 ** shelf_index
36//
37// Now we complicate it a little bit further by adding a preallocated shelf, which must be
38// a power of 2:
39// prealloc=4
40//
41// customer indexes:
42// prealloc: 0 1 2 3
43// shelf 0: 4 5 6 7 8 9 10 11
44// shelf 1: 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
45// shelf 2: 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
46// ...
47//
48// warehouse indexes:
49// prealloc: 0 1 2 3
50// shelf 0: 0 1 2 3 4 5 6 7
51// shelf 1: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
52// shelf 2: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
53// ...
54//
55// Now the equations are:
56//
57// shelf_index = floor(log2(customer_index + prealloc)) - log2(prealloc) - 1
58// shelf_count = ceil(log2(box_count + prealloc)) - log2(prealloc) - 1
59// box_index = customer_index + prealloc - 2 ** (log2(prealloc) + 1 + shelf)
60// shelf_size = prealloc * 2 ** (shelf_index + 1)
61
62/// This is a stack data structure where pointers to indexes have the same lifetime as the data structure
63/// itself, unlike ArrayList where push() invalidates all existing element pointers.
64/// The tradeoff is that elements are not guaranteed to be contiguous. For that, use ArrayList.
65/// Note however that most elements are contiguous, making this data structure cache-friendly.
66///
67/// Because it never has to copy elements from an old location to a new location, it does not require
68/// its elements to be copyable, and it avoids wasting memory when backed by an ArenaAllocator.
69/// Note that the push() and pop() convenience methods perform a copy, but you can instead use
70/// addOne(), at(), setCapacity(), and shrinkCapacity() to avoid copying items.
71///
72/// This data structure has O(1) push and O(1) pop.
73///
74/// It supports preallocated elements, making it especially well suited when the expected maximum
75/// size is small. `prealloc_item_count` must be 0, or a power of 2.
76pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type {
77 return struct {
78 const Self = this;
79 const prealloc_exp = blk: {
80 // we don't use the prealloc_exp constant when prealloc_item_count is 0.
81 assert(prealloc_item_count != 0);
82
83 const value = std.math.log2_int(usize, prealloc_item_count);
84 assert((1 << value) == prealloc_item_count); // prealloc_item_count must be a power of 2
85 break :blk @typeOf(1)(value);
86 };
87 const ShelfIndex = std.math.Log2Int(usize);
88
89 prealloc_segment: [prealloc_item_count]T,
90 dynamic_segments: []&T,
91 allocator: &Allocator,
92 len: usize,
93
94 /// Deinitialize with `deinit`
95 pub fn init(allocator: &Allocator) Self {
96 return Self {
97 .allocator = allocator,
98 .len = 0,
99 .prealloc_segment = undefined,
100 .dynamic_segments = []&T{},
101 };
102 }
103
104 pub fn deinit(self: &Self) void {
105 self.freeShelves(ShelfIndex(self.dynamic_segments.len), 0);
106 self.allocator.free(self.dynamic_segments);
107 *self = undefined;
108 }
109
110 pub fn at(self: &Self, i: usize) &T {
111 assert(i < self.len);
112 return self.uncheckedAt(i);
113 }
114
115 pub fn count(self: &const Self) usize {
116 return self.len;
117 }
118
119 pub fn push(self: &Self, item: &const T) !void {
120 const new_item_ptr = try self.addOne();
121 *new_item_ptr = *item;
122 }
123
124 pub fn pushMany(self: &Self, items: []const T) !void {
125 for (items) |item| {
126 try self.push(item);
127 }
128 }
129
130 pub fn pop(self: &Self) ?T {
131 if (self.len == 0)
132 return null;
133
134 const index = self.len - 1;
135 const result = *self.uncheckedAt(index);
136 self.len = index;
137 return result;
138 }
139
140 pub fn addOne(self: &Self) !&T {
141 const new_length = self.len + 1;
142 try self.growCapacity(new_length);
143 const result = self.uncheckedAt(self.len);
144 self.len = new_length;
145 return result;
146 }
147
148 /// Grows or shrinks capacity to match usage.
149 pub fn setCapacity(self: &Self, new_capacity: usize) !void {
150 if (new_capacity <= usize(1) << (prealloc_exp + self.dynamic_segments.len)) {
151 return self.shrinkCapacity(new_capacity);
152 } else {
153 return self.growCapacity(new_capacity);
154 }
155 }
156
157 /// Only grows capacity, or retains current capacity
158 pub fn growCapacity(self: &Self, new_capacity: usize) !void {
159 const new_cap_shelf_count = shelfCount(new_capacity);
160 const old_shelf_count = ShelfIndex(self.dynamic_segments.len);
161 if (new_cap_shelf_count > old_shelf_count) {
162 self.dynamic_segments = try self.allocator.realloc(&T, self.dynamic_segments, new_cap_shelf_count);
163 var i = old_shelf_count;
164 errdefer {
165 self.freeShelves(i, old_shelf_count);
166 self.dynamic_segments = self.allocator.shrink(&T, self.dynamic_segments, old_shelf_count);
167 }
168 while (i < new_cap_shelf_count) : (i += 1) {
169 self.dynamic_segments[i] = (try self.allocator.alloc(T, shelfSize(i))).ptr;
170 }
171 }
172 }
173
174 /// Only shrinks capacity or retains current capacity
175 pub fn shrinkCapacity(self: &Self, new_capacity: usize) void {
176 if (new_capacity <= prealloc_item_count) {
177 const len = ShelfIndex(self.dynamic_segments.len);
178 self.freeShelves(len, 0);
179 self.allocator.free(self.dynamic_segments);
180 self.dynamic_segments = []&T{};
181 return;
182 }
183
184 const new_cap_shelf_count = shelfCount(new_capacity);
185 const old_shelf_count = ShelfIndex(self.dynamic_segments.len);
186 assert(new_cap_shelf_count <= old_shelf_count);
187 if (new_cap_shelf_count == old_shelf_count) {
188 return;
189 }
190
191 self.freeShelves(old_shelf_count, new_cap_shelf_count);
192 self.dynamic_segments = self.allocator.shrink(&T, self.dynamic_segments, new_cap_shelf_count);
193 }
194
195 pub fn uncheckedAt(self: &Self, index: usize) &T {
196 if (index < prealloc_item_count) {
197 return &self.prealloc_segment[index];
198 }
199 const shelf_index = shelfIndex(index);
200 const box_index = boxIndex(index, shelf_index);
201 return &self.dynamic_segments[shelf_index][box_index];
202 }
203
204 fn shelfCount(box_count: usize) ShelfIndex {
205 if (prealloc_item_count == 0) {
206 return std.math.log2_int_ceil(usize, box_count + 1);
207 }
208 return std.math.log2_int_ceil(usize, box_count + prealloc_item_count) - prealloc_exp - 1;
209 }
210
211 fn shelfSize(shelf_index: ShelfIndex) usize {
212 if (prealloc_item_count == 0) {
213 return usize(1) << shelf_index;
214 }
215 return usize(1) << (shelf_index + (prealloc_exp + 1));
216 }
217
218 fn shelfIndex(list_index: usize) ShelfIndex {
219 if (prealloc_item_count == 0) {
220 return std.math.log2_int(usize, list_index + 1);
221 }
222 return std.math.log2_int(usize, list_index + prealloc_item_count) - prealloc_exp - 1;
223 }
224
225 fn boxIndex(list_index: usize, shelf_index: ShelfIndex) usize {
226 if (prealloc_item_count == 0) {
227 return (list_index + 1) - (usize(1) << shelf_index);
228 }
229 return list_index + prealloc_item_count - (usize(1) << ((prealloc_exp + 1) + shelf_index));
230 }
231
232 fn freeShelves(self: &Self, from_count: ShelfIndex, to_count: ShelfIndex) void {
233 var i = from_count;
234 while (i != to_count) {
235 i -= 1;
236 self.allocator.free(self.dynamic_segments[i][0..shelfSize(i)]);
237 }
238 }
239
240 pub const Iterator = struct {
241 list: &Self,
242 index: usize,
243 box_index: usize,
244 shelf_index: ShelfIndex,
245 shelf_size: usize,
246
247 pub fn next(it: &Iterator) ?&T {
248 if (it.index >= it.list.len)
249 return null;
250 if (it.index < prealloc_item_count) {
251 const ptr = &it.list.prealloc_segment[it.index];
252 it.index += 1;
253 if (it.index == prealloc_item_count) {
254 it.box_index = 0;
255 it.shelf_index = 0;
256 it.shelf_size = prealloc_item_count * 2;
257 }
258 return ptr;
259 }
260
261 const ptr = &it.list.dynamic_segments[it.shelf_index][it.box_index];
262 it.index += 1;
263 it.box_index += 1;
264 if (it.box_index == it.shelf_size) {
265 it.shelf_index += 1;
266 it.box_index = 0;
267 it.shelf_size *= 2;
268 }
269 return ptr;
270 }
271
272 pub fn prev(it: &Iterator) ?&T {
273 if (it.index == 0)
274 return null;
275
276 it.index -= 1;
277 if (it.index < prealloc_item_count)
278 return &it.list.prealloc_segment[it.index];
279
280 if (it.box_index == 0) {
281 it.shelf_index -= 1;
282 it.shelf_size /= 2;
283 it.box_index = it.shelf_size - 1;
284 } else {
285 it.box_index -= 1;
286 }
287
288 return &it.list.dynamic_segments[it.shelf_index][it.box_index];
289 }
290 };
291
292 pub fn iterator(self: &Self, start_index: usize) Iterator {
293 var it = Iterator {
294 .list = self,
295 .index = start_index,
296 .shelf_index = undefined,
297 .box_index = undefined,
298 .shelf_size = undefined,
299 };
300 if (start_index >= prealloc_item_count) {
301 it.shelf_index = shelfIndex(start_index);
302 it.box_index = boxIndex(start_index, it.shelf_index);
303 it.shelf_size = shelfSize(it.shelf_index);
304 }
305 return it;
306 }
307 };
308}
309
310test "std.SegmentedList" {
311 var da = std.heap.DirectAllocator.init();
312 defer da.deinit();
313 var a = &da.allocator;
314
315 try testSegmentedList(0, a);
316 try testSegmentedList(1, a);
317 try testSegmentedList(2, a);
318 try testSegmentedList(4, a);
319 try testSegmentedList(8, a);
320 try testSegmentedList(16, a);
321}
322
323fn testSegmentedList(comptime prealloc: usize, allocator: &Allocator) !void {
324 var list = SegmentedList(i32, prealloc).init(allocator);
325 defer list.deinit();
326
327 {var i: usize = 0; while (i < 100) : (i += 1) {
328 try list.push(i32(i + 1));
329 assert(list.len == i + 1);
330 }}
331
332 {var i: usize = 0; while (i < 100) : (i += 1) {
333 assert(*list.at(i) == i32(i + 1));
334 }}
335
336 {
337 var it = list.iterator(0);
338 var x: i32 = 0;
339 while (it.next()) |item| {
340 x += 1;
341 assert(*item == x);
342 }
343 assert(x == 100);
344 while (it.prev()) |item| : (x -= 1) {
345 assert(*item == x);
346 }
347 assert(x == 0);
348 }
349
350 assert(??list.pop() == 100);
351 assert(list.len == 99);
352
353 try list.pushMany([]i32 { 1, 2, 3 });
354 assert(list.len == 102);
355 assert(??list.pop() == 3);
356 assert(??list.pop() == 2);
357 assert(??list.pop() == 1);
358 assert(list.len == 99);
359
360 try list.pushMany([]const i32 {});
361 assert(list.len == 99);
362
363 var i: i32 = 99;
364 while (list.pop()) |item| : (i -= 1) {
365 assert(item == i);
366 list.shrinkCapacity(list.len);
367 }
368}
std/special/compiler_rt/fixuint.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const is_test = @import("builtin").is_test;1const is_test = @import("builtin").is_test;
2const Log2Int = @import("../../math/index.zig").Log2Int;2const Log2Int = @import("std").math.Log2Int;
33
4pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t {4pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t {
5 @setRuntimeSafety(is_test);5 @setRuntimeSafety(is_test);
std/special/compiler_rt/fixunsdfdi_test.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;1const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;
2const assert = @import("../../index.zig").debug.assert;2const assert = @import("std").debug.assert;
33
4fn test__fixunsdfdi(a: f64, expected: u64) void {4fn test__fixunsdfdi(a: f64, expected: u64) void {
5 const x = __fixunsdfdi(a);5 const x = __fixunsdfdi(a);
std/special/compiler_rt/fixunsdfsi_test.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;1const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;
2const assert = @import("../../index.zig").debug.assert;2const assert = @import("std").debug.assert;
33
4fn test__fixunsdfsi(a: f64, expected: u32) void {4fn test__fixunsdfsi(a: f64, expected: u32) void {
5 const x = __fixunsdfsi(a);5 const x = __fixunsdfsi(a);
std/special/compiler_rt/fixunsdfti_test.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;1const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;
2const assert = @import("../../index.zig").debug.assert;2const assert = @import("std").debug.assert;
33
4fn test__fixunsdfti(a: f64, expected: u128) void {4fn test__fixunsdfti(a: f64, expected: u128) void {
5 const x = __fixunsdfti(a);5 const x = __fixunsdfti(a);
std/special/compiler_rt/fixunssfdi_test.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;1const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;
2const assert = @import("../../index.zig").debug.assert;2const assert = @import("std").debug.assert;
33
4fn test__fixunssfdi(a: f32, expected: u64) void {4fn test__fixunssfdi(a: f32, expected: u64) void {
5 const x = __fixunssfdi(a);5 const x = __fixunssfdi(a);
std/special/compiler_rt/fixunssfsi_test.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;1const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;
2const assert = @import("../../index.zig").debug.assert;2const assert = @import("std").debug.assert;
33
4fn test__fixunssfsi(a: f32, expected: u32) void {4fn test__fixunssfsi(a: f32, expected: u32) void {
5 const x = __fixunssfsi(a);5 const x = __fixunssfsi(a);
std/special/compiler_rt/fixunssfti_test.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;1const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;
2const assert = @import("../../index.zig").debug.assert;2const assert = @import("std").debug.assert;
33
4fn test__fixunssfti(a: f32, expected: u128) void {4fn test__fixunssfti(a: f32, expected: u128) void {
5 const x = __fixunssfti(a);5 const x = __fixunssfti(a);
std/special/compiler_rt/fixunstfdi_test.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;1const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;
2const assert = @import("../../index.zig").debug.assert;2const assert = @import("std").debug.assert;
33
4fn test__fixunstfdi(a: f128, expected: u64) void {4fn test__fixunstfdi(a: f128, expected: u64) void {
5 const x = __fixunstfdi(a);5 const x = __fixunstfdi(a);
std/special/compiler_rt/fixunstfsi_test.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;1const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;
2const assert = @import("../../index.zig").debug.assert;2const assert = @import("std").debug.assert;
33
4fn test__fixunstfsi(a: f128, expected: u32) void {4fn test__fixunstfsi(a: f128, expected: u32) void {
5 const x = __fixunstfsi(a);5 const x = __fixunstfsi(a);
std/special/compiler_rt/fixunstfti_test.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;1const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;
2const assert = @import("../../index.zig").debug.assert;2const assert = @import("std").debug.assert;
33
4fn test__fixunstfti(a: f128, expected: u128) void {4fn test__fixunstfti(a: f128, expected: u128) void {
5 const x = __fixunstfti(a);5 const x = __fixunstfti(a);
std/special/compiler_rt/index.zig+3-2
...@@ -71,7 +71,8 @@ comptime {...@@ -71,7 +71,8 @@ comptime {
71 }71 }
72}72}
7373
74const assert = @import("../../index.zig").debug.assert;74const std = @import("std");
75const assert = std.debug.assert;
7576
76const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;77const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
7778
...@@ -80,7 +81,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;...@@ -80,7 +81,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
80pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn {81pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn {
81 @setCold(true);82 @setCold(true);
82 if (is_test) {83 if (is_test) {
83 @import("std").debug.panic("{}", msg);84 std.debug.panic("{}", msg);
84 } else {85 } else {
85 unreachable;86 unreachable;
86 }87 }
std/special/compiler_rt/udivmod.zig+1-1
...@@ -12,7 +12,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -12,7 +12,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
1212
13 const SingleInt = @IntType(false, @divExact(DoubleInt.bit_count, 2));13 const SingleInt = @IntType(false, @divExact(DoubleInt.bit_count, 2));
14 const SignedDoubleInt = @IntType(true, DoubleInt.bit_count);14 const SignedDoubleInt = @IntType(true, DoubleInt.bit_count);
15 const Log2SingleInt = @import("../../math/index.zig").Log2Int(SingleInt);15 const Log2SingleInt = @import("std").math.Log2Int(SingleInt);
1616
17 const n = @ptrCast(&const [2]SingleInt, &a).*; // TODO issue #42117 const n = @ptrCast(&const [2]SingleInt, &a).*; // TODO issue #421
18 const d = @ptrCast(&const [2]SingleInt, &b).*; // TODO issue #42118 const d = @ptrCast(&const [2]SingleInt, &b).*; // TODO issue #421
std/zig/ast.zig+88-4
...@@ -6,7 +6,6 @@ const mem = std.mem;...@@ -6,7 +6,6 @@ const mem = std.mem;
66
7pub const Node = struct {7pub const Node = struct {
8 id: Id,8 id: Id,
9 doc_comments: ?&DocComment,
10 same_line_comment: ?&Token,9 same_line_comment: ?&Token,
1110
12 pub const Id = enum {11 pub const Id = enum {
...@@ -36,6 +35,7 @@ pub const Node = struct {...@@ -36,6 +35,7 @@ pub const Node = struct {
36 VarType,35 VarType,
37 ErrorType,36 ErrorType,
38 FnProto,37 FnProto,
38 PromiseType,
3939
40 // Primary expressions40 // Primary expressions
41 IntegerLiteral,41 IntegerLiteral,
...@@ -69,6 +69,7 @@ pub const Node = struct {...@@ -69,6 +69,7 @@ pub const Node = struct {
69 StructField,69 StructField,
70 UnionTag,70 UnionTag,
71 EnumTag,71 EnumTag,
72 ErrorTag,
72 AsmInput,73 AsmInput,
73 AsmOutput,74 AsmOutput,
74 AsyncAttribute,75 AsyncAttribute,
...@@ -76,6 +77,13 @@ pub const Node = struct {...@@ -76,6 +77,13 @@ pub const Node = struct {
76 FieldInitializer,77 FieldInitializer,
77 };78 };
7879
80 pub fn cast(base: &Node, comptime T: type) ?&T {
81 if (base.id == comptime typeToId(T)) {
82 return @fieldParentPtr(T, "base", base);
83 }
84 return null;
85 }
86
79 pub fn iterate(base: &Node, index: usize) ?&Node {87 pub fn iterate(base: &Node, index: usize) ?&Node {
80 comptime var i = 0;88 comptime var i = 0;
81 inline while (i < @memberCount(Id)) : (i += 1) {89 inline while (i < @memberCount(Id)) : (i += 1) {
...@@ -121,6 +129,7 @@ pub const Node = struct {...@@ -121,6 +129,7 @@ pub const Node = struct {
121129
122 pub const Root = struct {130 pub const Root = struct {
123 base: Node,131 base: Node,
132 doc_comments: ?&DocComment,
124 decls: ArrayList(&Node),133 decls: ArrayList(&Node),
125 eof_token: Token,134 eof_token: Token,
126135
...@@ -142,6 +151,7 @@ pub const Node = struct {...@@ -142,6 +151,7 @@ pub const Node = struct {
142151
143 pub const VarDecl = struct {152 pub const VarDecl = struct {
144 base: Node,153 base: Node,
154 doc_comments: ?&DocComment,
145 visib_token: ?Token,155 visib_token: ?Token,
146 name_token: Token,156 name_token: Token,
147 eq_token: Token,157 eq_token: Token,
...@@ -190,6 +200,7 @@ pub const Node = struct {...@@ -190,6 +200,7 @@ pub const Node = struct {
190200
191 pub const Use = struct {201 pub const Use = struct {
192 base: Node,202 base: Node,
203 doc_comments: ?&DocComment,
193 visib_token: ?Token,204 visib_token: ?Token,
194 expr: &Node,205 expr: &Node,
195 semicolon_token: Token,206 semicolon_token: Token,
...@@ -260,7 +271,7 @@ pub const Node = struct {...@@ -260,7 +271,7 @@ pub const Node = struct {
260271
261 const InitArg = union(enum) {272 const InitArg = union(enum) {
262 None,273 None,
263 Enum,274 Enum: ?&Node,
264 Type: &Node,275 Type: &Node,
265 };276 };
266277
...@@ -293,6 +304,7 @@ pub const Node = struct {...@@ -293,6 +304,7 @@ pub const Node = struct {
293304
294 pub const StructField = struct {305 pub const StructField = struct {
295 base: Node,306 base: Node,
307 doc_comments: ?&DocComment,
296 visib_token: ?Token,308 visib_token: ?Token,
297 name_token: Token,309 name_token: Token,
298 type_expr: &Node,310 type_expr: &Node,
...@@ -318,8 +330,10 @@ pub const Node = struct {...@@ -318,8 +330,10 @@ pub const Node = struct {
318330
319 pub const UnionTag = struct {331 pub const UnionTag = struct {
320 base: Node,332 base: Node,
333 doc_comments: ?&DocComment,
321 name_token: Token,334 name_token: Token,
322 type_expr: ?&Node,335 type_expr: ?&Node,
336 value_expr: ?&Node,
323337
324 pub fn iterate(self: &UnionTag, index: usize) ?&Node {338 pub fn iterate(self: &UnionTag, index: usize) ?&Node {
325 var i = index;339 var i = index;
...@@ -329,6 +343,11 @@ pub const Node = struct {...@@ -329,6 +343,11 @@ pub const Node = struct {
329 i -= 1;343 i -= 1;
330 }344 }
331345
346 if (self.value_expr) |value_expr| {
347 if (i < 1) return value_expr;
348 i -= 1;
349 }
350
332 return null;351 return null;
333 }352 }
334353
...@@ -337,6 +356,9 @@ pub const Node = struct {...@@ -337,6 +356,9 @@ pub const Node = struct {
337 }356 }
338357
339 pub fn lastToken(self: &UnionTag) Token {358 pub fn lastToken(self: &UnionTag) Token {
359 if (self.value_expr) |value_expr| {
360 return value_expr.lastToken();
361 }
340 if (self.type_expr) |type_expr| {362 if (self.type_expr) |type_expr| {
341 return type_expr.lastToken();363 return type_expr.lastToken();
342 }364 }
...@@ -347,6 +369,7 @@ pub const Node = struct {...@@ -347,6 +369,7 @@ pub const Node = struct {
347369
348 pub const EnumTag = struct {370 pub const EnumTag = struct {
349 base: Node,371 base: Node,
372 doc_comments: ?&DocComment,
350 name_token: Token,373 name_token: Token,
351 value: ?&Node,374 value: ?&Node,
352375
...@@ -374,6 +397,31 @@ pub const Node = struct {...@@ -374,6 +397,31 @@ pub const Node = struct {
374 }397 }
375 };398 };
376399
400 pub const ErrorTag = struct {
401 base: Node,
402 doc_comments: ?&DocComment,
403 name_token: Token,
404
405 pub fn iterate(self: &ErrorTag, index: usize) ?&Node {
406 var i = index;
407
408 if (self.doc_comments) |comments| {
409 if (i < 1) return &comments.base;
410 i -= 1;
411 }
412
413 return null;
414 }
415
416 pub fn firstToken(self: &ErrorTag) Token {
417 return self.name_token;
418 }
419
420 pub fn lastToken(self: &ErrorTag) Token {
421 return self.name_token;
422 }
423 };
424
377 pub const Identifier = struct {425 pub const Identifier = struct {
378 base: Node,426 base: Node,
379 token: Token,427 token: Token,
...@@ -423,6 +471,7 @@ pub const Node = struct {...@@ -423,6 +471,7 @@ pub const Node = struct {
423471
424 pub const FnProto = struct {472 pub const FnProto = struct {
425 base: Node,473 base: Node,
474 doc_comments: ?&DocComment,
426 visib_token: ?Token,475 visib_token: ?Token,
427 fn_token: Token,476 fn_token: Token,
428 name_token: ?Token,477 name_token: ?Token,
...@@ -495,6 +544,37 @@ pub const Node = struct {...@@ -495,6 +544,37 @@ pub const Node = struct {
495 }544 }
496 };545 };
497546
547 pub const PromiseType = struct {
548 base: Node,
549 promise_token: Token,
550 result: ?Result,
551
552 pub const Result = struct {
553 arrow_token: Token,
554 return_type: &Node,
555 };
556
557 pub fn iterate(self: &PromiseType, index: usize) ?&Node {
558 var i = index;
559
560 if (self.result) |result| {
561 if (i < 1) return result.return_type;
562 i -= 1;
563 }
564
565 return null;
566 }
567
568 pub fn firstToken(self: &PromiseType) Token {
569 return self.promise_token;
570 }
571
572 pub fn lastToken(self: &PromiseType) Token {
573 if (self.result) |result| return result.return_type.lastToken();
574 return self.promise_token;
575 }
576 };
577
498 pub const ParamDecl = struct {578 pub const ParamDecl = struct {
499 base: Node,579 base: Node,
500 comptime_token: ?Token,580 comptime_token: ?Token,
...@@ -585,6 +665,7 @@ pub const Node = struct {...@@ -585,6 +665,7 @@ pub const Node = struct {
585665
586 pub const Comptime = struct {666 pub const Comptime = struct {
587 base: Node,667 base: Node,
668 doc_comments: ?&DocComment,
588 comptime_token: Token,669 comptime_token: Token,
589 expr: &Node,670 expr: &Node,
590671
...@@ -1188,7 +1269,7 @@ pub const Node = struct {...@@ -1188,7 +1269,7 @@ pub const Node = struct {
1188 ArrayAccess: &Node,1269 ArrayAccess: &Node,
1189 Slice: SliceRange,1270 Slice: SliceRange,
1190 ArrayInitializer: ArrayList(&Node),1271 ArrayInitializer: ArrayList(&Node),
1191 StructInitializer: ArrayList(&FieldInitializer),1272 StructInitializer: ArrayList(&Node),
1192 };1273 };
11931274
1194 const CallInfo = struct {1275 const CallInfo = struct {
...@@ -1230,7 +1311,7 @@ pub const Node = struct {...@@ -1230,7 +1311,7 @@ pub const Node = struct {
1230 i -= exprs.len;1311 i -= exprs.len;
1231 },1312 },
1232 Op.StructInitializer => |fields| {1313 Op.StructInitializer => |fields| {
1233 if (i < fields.len) return &fields.at(i).base;1314 if (i < fields.len) return fields.at(i);
1234 i -= fields.len;1315 i -= fields.len;
1235 },1316 },
1236 }1317 }
...@@ -1339,6 +1420,7 @@ pub const Node = struct {...@@ -1339,6 +1420,7 @@ pub const Node = struct {
13391420
1340 pub const Suspend = struct {1421 pub const Suspend = struct {
1341 base: Node,1422 base: Node,
1423 label: ?Token,
1342 suspend_token: Token,1424 suspend_token: Token,
1343 payload: ?&Node,1425 payload: ?&Node,
1344 body: ?&Node,1426 body: ?&Node,
...@@ -1360,6 +1442,7 @@ pub const Node = struct {...@@ -1360,6 +1442,7 @@ pub const Node = struct {
1360 }1442 }
13611443
1362 pub fn firstToken(self: &Suspend) Token {1444 pub fn firstToken(self: &Suspend) Token {
1445 if (self.label) |label| return label;
1363 return self.suspend_token;1446 return self.suspend_token;
1364 }1447 }
13651448
...@@ -1751,6 +1834,7 @@ pub const Node = struct {...@@ -1751,6 +1834,7 @@ pub const Node = struct {
17511834
1752 pub const TestDecl = struct {1835 pub const TestDecl = struct {
1753 base: Node,1836 base: Node,
1837 doc_comments: ?&DocComment,
1754 test_token: Token,1838 test_token: Token,
1755 name: &Node,1839 name: &Node,
1756 body_node: &Node,1840 body_node: &Node,
std/zig/bench.zig created+38
...@@ -0,0 +1,38 @@
1const std = @import("std");
2const mem = std.mem;
3const warn = std.debug.warn;
4const Tokenizer = std.zig.Tokenizer;
5const Parser = std.zig.Parser;
6const io = std.io;
7
8const source = @embedFile("../os/index.zig");
9var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
10
11pub fn main() !void {
12 var i: usize = 0;
13 var timer = try std.os.time.Timer.start();
14 const start = timer.lap();
15 const iterations = 100;
16 var memory_used: usize = 0;
17 while (i < iterations) : (i += 1) {
18 memory_used += testOnce();
19 }
20 const end = timer.read();
21 memory_used /= iterations;
22 const elapsed_s = f64(end - start) / std.os.time.ns_per_s;
23 const bytes_per_sec = f64(source.len * iterations) / elapsed_s;
24 const mb_per_sec = bytes_per_sec / (1024 * 1024);
25
26 var stdout_file = try std.io.getStdOut();
27 const stdout = &std.io.FileOutStream.init(&stdout_file).stream;
28 try stdout.print("{.3} MB/s, {} KB used \n", mb_per_sec, memory_used / 1024);
29}
30
31fn testOnce() usize {
32 var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
33 var allocator = &fixed_buf_alloc.allocator;
34 var tokenizer = Tokenizer.init(source);
35 var parser = Parser.init(&tokenizer, allocator, "(memory buffer)");
36 _ = parser.parse() catch @panic("parse failure");
37 return fixed_buf_alloc.end_index;
38}
std/zig/parser.zig+257-94
...@@ -228,7 +228,6 @@ pub const Parser = struct {...@@ -228,7 +228,6 @@ pub const Parser = struct {
228 Statement: &ast.Node.Block,228 Statement: &ast.Node.Block,
229 ComptimeStatement: ComptimeStatementCtx,229 ComptimeStatement: ComptimeStatementCtx,
230 Semicolon: &&ast.Node,230 Semicolon: &&ast.Node,
231 AddComments: AddCommentsCtx,
232 LookForSameLineComment: &&ast.Node,231 LookForSameLineComment: &&ast.Node,
233 LookForSameLineCommentDirect: &ast.Node,232 LookForSameLineCommentDirect: &ast.Node,
234233
...@@ -239,11 +238,12 @@ pub const Parser = struct {...@@ -239,11 +238,12 @@ pub const Parser = struct {
239238
240 ExprListItemOrEnd: ExprListCtx,239 ExprListItemOrEnd: ExprListCtx,
241 ExprListCommaOrEnd: ExprListCtx,240 ExprListCommaOrEnd: ExprListCtx,
242 FieldInitListItemOrEnd: ListSave(&ast.Node.FieldInitializer),241 FieldInitListItemOrEnd: ListSave(&ast.Node),
243 FieldInitListCommaOrEnd: ListSave(&ast.Node.FieldInitializer),242 FieldInitListCommaOrEnd: ListSave(&ast.Node),
244 FieldListCommaOrEnd: &ast.Node.ContainerDecl,243 FieldListCommaOrEnd: &ast.Node.ContainerDecl,
245 IdentifierListItemOrEnd: ListSave(&ast.Node),244 FieldInitValue: OptionalCtx,
246 IdentifierListCommaOrEnd: ListSave(&ast.Node),245 ErrorTagListItemOrEnd: ListSave(&ast.Node),
246 ErrorTagListCommaOrEnd: ListSave(&ast.Node),
247 SwitchCaseOrEnd: ListSave(&ast.Node),247 SwitchCaseOrEnd: ListSave(&ast.Node),
248 SwitchCaseCommaOrEnd: ListSave(&ast.Node),248 SwitchCaseCommaOrEnd: ListSave(&ast.Node),
249 SwitchCaseFirstItem: &ArrayList(&ast.Node),249 SwitchCaseFirstItem: &ArrayList(&ast.Node),
...@@ -300,6 +300,7 @@ pub const Parser = struct {...@@ -300,6 +300,7 @@ pub const Parser = struct {
300 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,300 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
301 StringLiteral: OptionalCtx,301 StringLiteral: OptionalCtx,
302 Identifier: OptionalCtx,302 Identifier: OptionalCtx,
303 ErrorTag: &&ast.Node,
303304
304305
305 IfToken: @TagType(Token.Id),306 IfToken: @TagType(Token.Id),
...@@ -324,6 +325,7 @@ pub const Parser = struct {...@@ -324,6 +325,7 @@ pub const Parser = struct {
324 ast.Node.Root {325 ast.Node.Root {
325 .base = undefined,326 .base = undefined,
326 .decls = ArrayList(&ast.Node).init(arena),327 .decls = ArrayList(&ast.Node).init(arena),
328 .doc_comments = null,
327 // initialized when we get the eof token329 // initialized when we get the eof token
328 .eof_token = undefined,330 .eof_token = undefined,
329 }331 }
...@@ -353,7 +355,7 @@ pub const Parser = struct {...@@ -353,7 +355,7 @@ pub const Parser = struct {
353 try root_node.decls.append(&line_comment.base);355 try root_node.decls.append(&line_comment.base);
354 }356 }
355357
356 const comments = try self.eatComments(arena);358 const comments = try self.eatDocComments(arena);
357 const token = self.getNextToken();359 const token = self.getNextToken();
358 switch (token.id) {360 switch (token.id) {
359 Token.Id.Keyword_test => {361 Token.Id.Keyword_test => {
...@@ -362,7 +364,6 @@ pub const Parser = struct {...@@ -362,7 +364,6 @@ pub const Parser = struct {
362 const block = try arena.construct(ast.Node.Block {364 const block = try arena.construct(ast.Node.Block {
363 .base = ast.Node {365 .base = ast.Node {
364 .id = ast.Node.Id.Block,366 .id = ast.Node.Id.Block,
365 .doc_comments = null,
366 .same_line_comment = null,367 .same_line_comment = null,
367 },368 },
368 .label = null,369 .label = null,
...@@ -373,9 +374,9 @@ pub const Parser = struct {...@@ -373,9 +374,9 @@ pub const Parser = struct {
373 const test_node = try arena.construct(ast.Node.TestDecl {374 const test_node = try arena.construct(ast.Node.TestDecl {
374 .base = ast.Node {375 .base = ast.Node {
375 .id = ast.Node.Id.TestDecl,376 .id = ast.Node.Id.TestDecl,
376 .doc_comments = comments,
377 .same_line_comment = null,377 .same_line_comment = null,
378 },378 },
379 .doc_comments = comments,
379 .test_token = token,380 .test_token = token,
380 .name = undefined,381 .name = undefined,
381 .body_node = &block.base,382 .body_node = &block.base,
...@@ -393,7 +394,11 @@ pub const Parser = struct {...@@ -393,7 +394,11 @@ pub const Parser = struct {
393 },394 },
394 Token.Id.Eof => {395 Token.Id.Eof => {
395 root_node.eof_token = token;396 root_node.eof_token = token;
396 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};397 root_node.doc_comments = comments;
398 return Tree {
399 .root_node = root_node,
400 .arena_allocator = arena_allocator,
401 };
397 },402 },
398 Token.Id.Keyword_pub => {403 Token.Id.Keyword_pub => {
399 stack.append(State.TopLevel) catch unreachable;404 stack.append(State.TopLevel) catch unreachable;
...@@ -423,6 +428,7 @@ pub const Parser = struct {...@@ -423,6 +428,7 @@ pub const Parser = struct {
423 .base = undefined,428 .base = undefined,
424 .comptime_token = token,429 .comptime_token = token,
425 .expr = &block.base,430 .expr = &block.base,
431 .doc_comments = comments,
426 }432 }
427 );433 );
428 stack.append(State.TopLevel) catch unreachable;434 stack.append(State.TopLevel) catch unreachable;
...@@ -519,6 +525,7 @@ pub const Parser = struct {...@@ -519,6 +525,7 @@ pub const Parser = struct {
519 .visib_token = ctx.visib_token,525 .visib_token = ctx.visib_token,
520 .expr = undefined,526 .expr = undefined,
521 .semicolon_token = undefined,527 .semicolon_token = undefined,
528 .doc_comments = ctx.comments,
522 }529 }
523 );530 );
524 stack.append(State {531 stack.append(State {
...@@ -555,9 +562,9 @@ pub const Parser = struct {...@@ -555,9 +562,9 @@ pub const Parser = struct {
555 const fn_proto = try arena.construct(ast.Node.FnProto {562 const fn_proto = try arena.construct(ast.Node.FnProto {
556 .base = ast.Node {563 .base = ast.Node {
557 .id = ast.Node.Id.FnProto,564 .id = ast.Node.Id.FnProto,
558 .doc_comments = ctx.comments,
559 .same_line_comment = null,565 .same_line_comment = null,
560 },566 },
567 .doc_comments = ctx.comments,
561 .visib_token = ctx.visib_token,568 .visib_token = ctx.visib_token,
562 .name_token = null,569 .name_token = null,
563 .fn_token = undefined,570 .fn_token = undefined,
...@@ -624,9 +631,9 @@ pub const Parser = struct {...@@ -624,9 +631,9 @@ pub const Parser = struct {
624 const node = try arena.construct(ast.Node.StructField {631 const node = try arena.construct(ast.Node.StructField {
625 .base = ast.Node {632 .base = ast.Node {
626 .id = ast.Node.Id.StructField,633 .id = ast.Node.Id.StructField,
627 .doc_comments = null,
628 .same_line_comment = null,634 .same_line_comment = null,
629 },635 },
636 .doc_comments = ctx.comments,
630 .visib_token = ctx.visib_token,637 .visib_token = ctx.visib_token,
631 .name_token = identifier,638 .name_token = identifier,
632 .type_expr = undefined,639 .type_expr = undefined,
...@@ -653,6 +660,15 @@ pub const Parser = struct {...@@ -653,6 +660,15 @@ pub const Parser = struct {
653 continue;660 continue;
654 },661 },
655662
663 State.FieldInitValue => |ctx| {
664 const eq_tok = self.getNextToken();
665 if (eq_tok.id != Token.Id.Equal) {
666 self.putBackToken(eq_tok);
667 continue;
668 }
669 stack.append(State { .Expression = ctx }) catch unreachable;
670 continue;
671 },
656672
657 State.ContainerKind => |ctx| {673 State.ContainerKind => |ctx| {
658 const token = self.getNextToken();674 const token = self.getNextToken();
...@@ -699,7 +715,16 @@ pub const Parser = struct {...@@ -699,7 +715,16 @@ pub const Parser = struct {
699 const init_arg_token = self.getNextToken();715 const init_arg_token = self.getNextToken();
700 switch (init_arg_token.id) {716 switch (init_arg_token.id) {
701 Token.Id.Keyword_enum => {717 Token.Id.Keyword_enum => {
702 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg.Enum;718 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg {.Enum = null};
719 const lparen_tok = self.getNextToken();
720 if (lparen_tok.id == Token.Id.LParen) {
721 try stack.append(State { .ExpectToken = Token.Id.RParen } );
722 try stack.append(State { .Expression = OptionalCtx {
723 .RequiredNull = &container_decl.init_arg_expr.Enum,
724 } });
725 } else {
726 self.putBackToken(lparen_tok);
727 }
703 },728 },
704 else => {729 else => {
705 self.putBackToken(init_arg_token);730 self.putBackToken(init_arg_token);
...@@ -709,12 +734,13 @@ pub const Parser = struct {...@@ -709,12 +734,13 @@ pub const Parser = struct {
709 }734 }
710 continue;735 continue;
711 },736 },
737
712 State.ContainerDecl => |container_decl| {738 State.ContainerDecl => |container_decl| {
713 while (try self.eatLineComment(arena)) |line_comment| {739 while (try self.eatLineComment(arena)) |line_comment| {
714 try container_decl.fields_and_decls.append(&line_comment.base);740 try container_decl.fields_and_decls.append(&line_comment.base);
715 }741 }
716742
717 const comments = try self.eatComments(arena);743 const comments = try self.eatDocComments(arena);
718 const token = self.getNextToken();744 const token = self.getNextToken();
719 switch (token.id) {745 switch (token.id) {
720 Token.Id.Identifier => {746 Token.Id.Identifier => {
...@@ -723,9 +749,9 @@ pub const Parser = struct {...@@ -723,9 +749,9 @@ pub const Parser = struct {
723 const node = try arena.construct(ast.Node.StructField {749 const node = try arena.construct(ast.Node.StructField {
724 .base = ast.Node {750 .base = ast.Node {
725 .id = ast.Node.Id.StructField,751 .id = ast.Node.Id.StructField,
726 .doc_comments = comments,
727 .same_line_comment = null,752 .same_line_comment = null,
728 },753 },
754 .doc_comments = comments,
729 .visib_token = null,755 .visib_token = null,
730 .name_token = token,756 .name_token = token,
731 .type_expr = undefined,757 .type_expr = undefined,
...@@ -744,10 +770,13 @@ pub const Parser = struct {...@@ -744,10 +770,13 @@ pub const Parser = struct {
744 .base = undefined,770 .base = undefined,
745 .name_token = token,771 .name_token = token,
746 .type_expr = null,772 .type_expr = null,
773 .value_expr = null,
774 .doc_comments = comments,
747 }775 }
748 );776 );
749777
750 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;778 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
779 try stack.append(State { .FieldInitValue = OptionalCtx { .RequiredNull = &node.value_expr } });
751 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });780 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
752 try stack.append(State { .IfToken = Token.Id.Colon });781 try stack.append(State { .IfToken = Token.Id.Colon });
753 continue;782 continue;
...@@ -758,6 +787,7 @@ pub const Parser = struct {...@@ -758,6 +787,7 @@ pub const Parser = struct {
758 .base = undefined,787 .base = undefined,
759 .name_token = token,788 .name_token = token,
760 .value = null,789 .value = null,
790 .doc_comments = comments,
761 }791 }
762 );792 );
763793
...@@ -809,6 +839,9 @@ pub const Parser = struct {...@@ -809,6 +839,9 @@ pub const Parser = struct {
809 continue;839 continue;
810 },840 },
811 Token.Id.RBrace => {841 Token.Id.RBrace => {
842 if (comments != null) {
843 return self.parseError(token, "doc comments must be attached to a node");
844 }
812 container_decl.rbrace_token = token;845 container_decl.rbrace_token = token;
813 continue;846 continue;
814 },847 },
...@@ -834,9 +867,9 @@ pub const Parser = struct {...@@ -834,9 +867,9 @@ pub const Parser = struct {
834 const var_decl = try arena.construct(ast.Node.VarDecl {867 const var_decl = try arena.construct(ast.Node.VarDecl {
835 .base = ast.Node {868 .base = ast.Node {
836 .id = ast.Node.Id.VarDecl,869 .id = ast.Node.Id.VarDecl,
837 .doc_comments = ctx.comments,
838 .same_line_comment = null,870 .same_line_comment = null,
839 },871 },
872 .doc_comments = ctx.comments,
840 .visib_token = ctx.visib_token,873 .visib_token = ctx.visib_token,
841 .mut_token = ctx.mut_token,874 .mut_token = ctx.mut_token,
842 .comptime_token = ctx.comptime_token,875 .comptime_token = ctx.comptime_token,
...@@ -1093,6 +1126,22 @@ pub const Parser = struct {...@@ -1093,6 +1126,22 @@ pub const Parser = struct {
1093 }) catch unreachable;1126 }) catch unreachable;
1094 continue;1127 continue;
1095 },1128 },
1129 Token.Id.Keyword_suspend => {
1130 const node = try arena.construct(ast.Node.Suspend {
1131 .base = ast.Node {
1132 .id = ast.Node.Id.Suspend,
1133 .same_line_comment = null,
1134 },
1135 .label = ctx.label,
1136 .suspend_token = token,
1137 .payload = null,
1138 .body = null,
1139 });
1140 ctx.opt_ctx.store(&node.base);
1141 stack.append(State { .SuspendBody = node }) catch unreachable;
1142 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
1143 continue;
1144 },
1096 Token.Id.Keyword_inline => {1145 Token.Id.Keyword_inline => {
1097 stack.append(State {1146 stack.append(State {
1098 .Inline = InlineCtx {1147 .Inline = InlineCtx {
...@@ -1244,7 +1293,6 @@ pub const Parser = struct {...@@ -1244,7 +1293,6 @@ pub const Parser = struct {
1244 }1293 }
1245 },1294 },
1246 State.Statement => |block| {1295 State.Statement => |block| {
1247 const comments = try self.eatComments(arena);
1248 const token = self.getNextToken();1296 const token = self.getNextToken();
1249 switch (token.id) {1297 switch (token.id) {
1250 Token.Id.Keyword_comptime => {1298 Token.Id.Keyword_comptime => {
...@@ -1259,7 +1307,7 @@ pub const Parser = struct {...@@ -1259,7 +1307,7 @@ pub const Parser = struct {
1259 Token.Id.Keyword_var, Token.Id.Keyword_const => {1307 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1260 stack.append(State {1308 stack.append(State {
1261 .VarDecl = VarDeclCtx {1309 .VarDecl = VarDeclCtx {
1262 .comments = comments,1310 .comments = null,
1263 .visib_token = null,1311 .visib_token = null,
1264 .comptime_token = null,1312 .comptime_token = null,
1265 .extern_export_token = null,1313 .extern_export_token = null,
...@@ -1274,7 +1322,6 @@ pub const Parser = struct {...@@ -1274,7 +1322,6 @@ pub const Parser = struct {
1274 const node = try arena.construct(ast.Node.Defer {1322 const node = try arena.construct(ast.Node.Defer {
1275 .base = ast.Node {1323 .base = ast.Node {
1276 .id = ast.Node.Id.Defer,1324 .id = ast.Node.Id.Defer,
1277 .doc_comments = comments,
1278 .same_line_comment = null,1325 .same_line_comment = null,
1279 },1326 },
1280 .defer_token = token,1327 .defer_token = token,
...@@ -1310,23 +1357,18 @@ pub const Parser = struct {...@@ -1310,23 +1357,18 @@ pub const Parser = struct {
1310 const statement = try block.statements.addOne();1357 const statement = try block.statements.addOne();
1311 stack.append(State { .LookForSameLineComment = statement }) catch unreachable;1358 stack.append(State { .LookForSameLineComment = statement }) catch unreachable;
1312 try stack.append(State { .Semicolon = statement });1359 try stack.append(State { .Semicolon = statement });
1313 try stack.append(State { .AddComments = AddCommentsCtx {
1314 .node_ptr = statement,
1315 .comments = comments,
1316 }});
1317 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });1360 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
1318 continue;1361 continue;
1319 }1362 }
1320 }1363 }
1321 },1364 },
1322 State.ComptimeStatement => |ctx| {1365 State.ComptimeStatement => |ctx| {
1323 const comments = try self.eatComments(arena);
1324 const token = self.getNextToken();1366 const token = self.getNextToken();
1325 switch (token.id) {1367 switch (token.id) {
1326 Token.Id.Keyword_var, Token.Id.Keyword_const => {1368 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1327 stack.append(State {1369 stack.append(State {
1328 .VarDecl = VarDeclCtx {1370 .VarDecl = VarDeclCtx {
1329 .comments = comments,1371 .comments = null,
1330 .visib_token = null,1372 .visib_token = null,
1331 .comptime_token = ctx.comptime_token,1373 .comptime_token = ctx.comptime_token,
1332 .extern_export_token = null,1374 .extern_export_token = null,
...@@ -1340,9 +1382,10 @@ pub const Parser = struct {...@@ -1340,9 +1382,10 @@ pub const Parser = struct {
1340 else => {1382 else => {
1341 self.putBackToken(token);1383 self.putBackToken(token);
1342 self.putBackToken(ctx.comptime_token);1384 self.putBackToken(ctx.comptime_token);
1343 const statememt = try ctx.block.statements.addOne();1385 const statement = try ctx.block.statements.addOne();
1344 stack.append(State { .Semicolon = statememt }) catch unreachable;1386 stack.append(State { .LookForSameLineComment = statement }) catch unreachable;
1345 try stack.append(State { .Expression = OptionalCtx { .Required = statememt } });1387 try stack.append(State { .Semicolon = statement });
1388 try stack.append(State { .Expression = OptionalCtx { .Required = statement } });
1346 continue;1389 continue;
1347 }1390 }
1348 }1391 }
...@@ -1356,12 +1399,6 @@ pub const Parser = struct {...@@ -1356,12 +1399,6 @@ pub const Parser = struct {
1356 continue;1399 continue;
1357 },1400 },
13581401
1359 State.AddComments => |add_comments_ctx| {
1360 const node = *add_comments_ctx.node_ptr;
1361 node.doc_comments = add_comments_ctx.comments;
1362 continue;
1363 },
1364
1365 State.LookForSameLineComment => |node_ptr| {1402 State.LookForSameLineComment => |node_ptr| {
1366 try self.lookForSameLineComment(arena, *node_ptr);1403 try self.lookForSameLineComment(arena, *node_ptr);
1367 continue;1404 continue;
...@@ -1474,6 +1511,10 @@ pub const Parser = struct {...@@ -1474,6 +1511,10 @@ pub const Parser = struct {
1474 }1511 }
1475 },1512 },
1476 State.FieldInitListItemOrEnd => |list_state| {1513 State.FieldInitListItemOrEnd => |list_state| {
1514 while (try self.eatLineComment(arena)) |line_comment| {
1515 try list_state.list.append(&line_comment.base);
1516 }
1517
1477 if (self.eatToken(Token.Id.RBrace)) |rbrace| {1518 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1478 *list_state.ptr = rbrace;1519 *list_state.ptr = rbrace;
1479 continue;1520 continue;
...@@ -1482,14 +1523,13 @@ pub const Parser = struct {...@@ -1482,14 +1523,13 @@ pub const Parser = struct {
1482 const node = try arena.construct(ast.Node.FieldInitializer {1523 const node = try arena.construct(ast.Node.FieldInitializer {
1483 .base = ast.Node {1524 .base = ast.Node {
1484 .id = ast.Node.Id.FieldInitializer,1525 .id = ast.Node.Id.FieldInitializer,
1485 .doc_comments = null,
1486 .same_line_comment = null,1526 .same_line_comment = null,
1487 },1527 },
1488 .period_token = undefined,1528 .period_token = undefined,
1489 .name_token = undefined,1529 .name_token = undefined,
1490 .expr = undefined,1530 .expr = undefined,
1491 });1531 });
1492 try list_state.list.append(node);1532 try list_state.list.append(&node.base);
14931533
1494 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;1534 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1495 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });1535 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
...@@ -1527,7 +1567,7 @@ pub const Parser = struct {...@@ -1527,7 +1567,7 @@ pub const Parser = struct {
1527 try stack.append(State { .ContainerDecl = container_decl });1567 try stack.append(State { .ContainerDecl = container_decl });
1528 continue;1568 continue;
1529 },1569 },
1530 State.IdentifierListItemOrEnd => |list_state| {1570 State.ErrorTagListItemOrEnd => |list_state| {
1531 while (try self.eatLineComment(arena)) |line_comment| {1571 while (try self.eatLineComment(arena)) |line_comment| {
1532 try list_state.list.append(&line_comment.base);1572 try list_state.list.append(&line_comment.base);
1533 }1573 }
...@@ -1537,23 +1577,18 @@ pub const Parser = struct {...@@ -1537,23 +1577,18 @@ pub const Parser = struct {
1537 continue;1577 continue;
1538 }1578 }
15391579
1540 const comments = try self.eatComments(arena);
1541 const node_ptr = try list_state.list.addOne();1580 const node_ptr = try list_state.list.addOne();
15421581
1543 try stack.append(State { .AddComments = AddCommentsCtx {1582 try stack.append(State { .ErrorTagListCommaOrEnd = list_state });
1544 .node_ptr = node_ptr,1583 try stack.append(State { .ErrorTag = node_ptr });
1545 .comments = comments,
1546 }});
1547 try stack.append(State { .IdentifierListCommaOrEnd = list_state });
1548 try stack.append(State { .Identifier = OptionalCtx { .Required = node_ptr } });
1549 continue;1584 continue;
1550 },1585 },
1551 State.IdentifierListCommaOrEnd => |list_state| {1586 State.ErrorTagListCommaOrEnd => |list_state| {
1552 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {1587 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1553 *list_state.ptr = end;1588 *list_state.ptr = end;
1554 continue;1589 continue;
1555 } else {1590 } else {
1556 stack.append(State { .IdentifierListItemOrEnd = list_state }) catch unreachable;1591 stack.append(State { .ErrorTagListItemOrEnd = list_state }) catch unreachable;
1557 continue;1592 continue;
1558 }1593 }
1559 },1594 },
...@@ -1567,11 +1602,10 @@ pub const Parser = struct {...@@ -1567,11 +1602,10 @@ pub const Parser = struct {
1567 continue;1602 continue;
1568 }1603 }
15691604
1570 const comments = try self.eatComments(arena);1605 const comments = try self.eatDocComments(arena);
1571 const node = try arena.construct(ast.Node.SwitchCase {1606 const node = try arena.construct(ast.Node.SwitchCase {
1572 .base = ast.Node {1607 .base = ast.Node {
1573 .id = ast.Node.Id.SwitchCase,1608 .id = ast.Node.Id.SwitchCase,
1574 .doc_comments = comments,
1575 .same_line_comment = null,1609 .same_line_comment = null,
1576 },1610 },
1577 .items = ArrayList(&ast.Node).init(arena),1611 .items = ArrayList(&ast.Node).init(arena),
...@@ -1684,9 +1718,9 @@ pub const Parser = struct {...@@ -1684,9 +1718,9 @@ pub const Parser = struct {
1684 const fn_proto = try arena.construct(ast.Node.FnProto {1718 const fn_proto = try arena.construct(ast.Node.FnProto {
1685 .base = ast.Node {1719 .base = ast.Node {
1686 .id = ast.Node.Id.FnProto,1720 .id = ast.Node.Id.FnProto,
1687 .doc_comments = ctx.comments,
1688 .same_line_comment = null,1721 .same_line_comment = null,
1689 },1722 },
1723 .doc_comments = ctx.comments,
1690 .visib_token = null,1724 .visib_token = null,
1691 .name_token = null,1725 .name_token = null,
1692 .fn_token = fn_token,1726 .fn_token = fn_token,
...@@ -1857,12 +1891,13 @@ pub const Parser = struct {...@@ -1857,12 +1891,13 @@ pub const Parser = struct {
1857 }1891 }
1858 );1892 );
18591893
1860 stack.append(State {1894 stack.append(State {.LookForSameLineCommentDirect = &node.base }) catch unreachable;
1895 try stack.append(State {
1861 .ExpectTokenSave = ExpectTokenSave {1896 .ExpectTokenSave = ExpectTokenSave {
1862 .id = Token.Id.Pipe,1897 .id = Token.Id.Pipe,
1863 .ptr = &node.rpipe,1898 .ptr = &node.rpipe,
1864 }1899 }
1865 }) catch unreachable;1900 });
1866 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });1901 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1867 try stack.append(State {1902 try stack.append(State {
1868 .OptionalTokenSave = OptionalTokenSave {1903 .OptionalTokenSave = OptionalTokenSave {
...@@ -2317,7 +2352,7 @@ pub const Parser = struct {...@@ -2317,7 +2352,7 @@ pub const Parser = struct {
2317 .base = undefined,2352 .base = undefined,
2318 .lhs = lhs,2353 .lhs = lhs,
2319 .op = ast.Node.SuffixOp.Op {2354 .op = ast.Node.SuffixOp.Op {
2320 .StructInitializer = ArrayList(&ast.Node.FieldInitializer).init(arena),2355 .StructInitializer = ArrayList(&ast.Node).init(arena),
2321 },2356 },
2322 .rtoken = undefined,2357 .rtoken = undefined,
2323 }2358 }
...@@ -2325,7 +2360,7 @@ pub const Parser = struct {...@@ -2325,7 +2360,7 @@ pub const Parser = struct {
2325 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;2360 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2326 try stack.append(State { .IfToken = Token.Id.LBrace });2361 try stack.append(State { .IfToken = Token.Id.LBrace });
2327 try stack.append(State {2362 try stack.append(State {
2328 .FieldInitListItemOrEnd = ListSave(&ast.Node.FieldInitializer) {2363 .FieldInitListItemOrEnd = ListSave(&ast.Node) {
2329 .list = &node.op.StructInitializer,2364 .list = &node.op.StructInitializer,
2330 .ptr = &node.rtoken,2365 .ptr = &node.rtoken,
2331 }2366 }
...@@ -2550,6 +2585,29 @@ pub const Parser = struct {...@@ -2550,6 +2585,29 @@ pub const Parser = struct {
2550 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token);2585 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token);
2551 continue;2586 continue;
2552 },2587 },
2588 Token.Id.Keyword_promise => {
2589 const node = try arena.construct(ast.Node.PromiseType {
2590 .base = ast.Node {
2591 .id = ast.Node.Id.PromiseType,
2592 .same_line_comment = null,
2593 },
2594 .promise_token = token,
2595 .result = null,
2596 });
2597 opt_ctx.store(&node.base);
2598 const next_token = self.getNextToken();
2599 if (next_token.id != Token.Id.Arrow) {
2600 self.putBackToken(next_token);
2601 continue;
2602 }
2603 node.result = ast.Node.PromiseType.Result {
2604 .arrow_token = next_token,
2605 .return_type = undefined,
2606 };
2607 const return_type_ptr = &((??node.result).return_type);
2608 try stack.append(State { .Expression = OptionalCtx { .Required = return_type_ptr, } });
2609 continue;
2610 },
2553 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {2611 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2554 opt_ctx.store((try self.parseStringLiteral(arena, token)) ?? unreachable);2612 opt_ctx.store((try self.parseStringLiteral(arena, token)) ?? unreachable);
2555 continue;2613 continue;
...@@ -2656,9 +2714,9 @@ pub const Parser = struct {...@@ -2656,9 +2714,9 @@ pub const Parser = struct {
2656 const fn_proto = try arena.construct(ast.Node.FnProto {2714 const fn_proto = try arena.construct(ast.Node.FnProto {
2657 .base = ast.Node {2715 .base = ast.Node {
2658 .id = ast.Node.Id.FnProto,2716 .id = ast.Node.Id.FnProto,
2659 .doc_comments = null,
2660 .same_line_comment = null,2717 .same_line_comment = null,
2661 },2718 },
2719 .doc_comments = null,
2662 .visib_token = null,2720 .visib_token = null,
2663 .name_token = null,2721 .name_token = null,
2664 .fn_token = token,2722 .fn_token = token,
...@@ -2680,9 +2738,9 @@ pub const Parser = struct {...@@ -2680,9 +2738,9 @@ pub const Parser = struct {
2680 const fn_proto = try arena.construct(ast.Node.FnProto {2738 const fn_proto = try arena.construct(ast.Node.FnProto {
2681 .base = ast.Node {2739 .base = ast.Node {
2682 .id = ast.Node.Id.FnProto,2740 .id = ast.Node.Id.FnProto,
2683 .doc_comments = null,
2684 .same_line_comment = null,2741 .same_line_comment = null,
2685 },2742 },
2743 .doc_comments = null,
2686 .visib_token = null,2744 .visib_token = null,
2687 .name_token = null,2745 .name_token = null,
2688 .fn_token = undefined,2746 .fn_token = undefined,
...@@ -2773,7 +2831,6 @@ pub const Parser = struct {...@@ -2773,7 +2831,6 @@ pub const Parser = struct {
2773 const node = try arena.construct(ast.Node.ErrorSetDecl {2831 const node = try arena.construct(ast.Node.ErrorSetDecl {
2774 .base = ast.Node {2832 .base = ast.Node {
2775 .id = ast.Node.Id.ErrorSetDecl,2833 .id = ast.Node.Id.ErrorSetDecl,
2776 .doc_comments = null,
2777 .same_line_comment = null,2834 .same_line_comment = null,
2778 },2835 },
2779 .error_token = ctx.error_token,2836 .error_token = ctx.error_token,
...@@ -2783,7 +2840,7 @@ pub const Parser = struct {...@@ -2783,7 +2840,7 @@ pub const Parser = struct {
2783 ctx.opt_ctx.store(&node.base);2840 ctx.opt_ctx.store(&node.base);
27842841
2785 stack.append(State {2842 stack.append(State {
2786 .IdentifierListItemOrEnd = ListSave(&ast.Node) {2843 .ErrorTagListItemOrEnd = ListSave(&ast.Node) {
2787 .list = &node.decls,2844 .list = &node.decls,
2788 .ptr = &node.rbrace_token,2845 .ptr = &node.rbrace_token,
2789 }2846 }
...@@ -2803,6 +2860,7 @@ pub const Parser = struct {...@@ -2803,6 +2860,7 @@ pub const Parser = struct {
2803 }2860 }
2804 );2861 );
2805 },2862 },
2863
2806 State.Identifier => |opt_ctx| {2864 State.Identifier => |opt_ctx| {
2807 if (self.eatToken(Token.Id.Identifier)) |ident_token| {2865 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
2808 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);2866 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
...@@ -2815,6 +2873,25 @@ pub const Parser = struct {...@@ -2815,6 +2873,25 @@ pub const Parser = struct {
2815 }2873 }
2816 },2874 },
28172875
2876 State.ErrorTag => |node_ptr| {
2877 const comments = try self.eatDocComments(arena);
2878 const ident_token = self.getNextToken();
2879 if (ident_token.id != Token.Id.Identifier) {
2880 return self.parseError(ident_token, "expected {}, found {}",
2881 @tagName(Token.Id.Identifier), @tagName(ident_token.id));
2882 }
2883
2884 const node = try arena.construct(ast.Node.ErrorTag {
2885 .base = ast.Node {
2886 .id = ast.Node.Id.ErrorTag,
2887 .same_line_comment = null,
2888 },
2889 .doc_comments = comments,
2890 .name_token = ident_token,
2891 });
2892 *node_ptr = &node.base;
2893 continue;
2894 },
28182895
2819 State.ExpectToken => |token_id| {2896 State.ExpectToken => |token_id| {
2820 _ = try self.expectToken(token_id);2897 _ = try self.expectToken(token_id);
...@@ -2853,7 +2930,7 @@ pub const Parser = struct {...@@ -2853,7 +2930,7 @@ pub const Parser = struct {
2853 }2930 }
2854 }2931 }
28552932
2856 fn eatComments(self: &Parser, arena: &mem.Allocator) !?&ast.Node.DocComment {2933 fn eatDocComments(self: &Parser, arena: &mem.Allocator) !?&ast.Node.DocComment {
2857 var result: ?&ast.Node.DocComment = null;2934 var result: ?&ast.Node.DocComment = null;
2858 while (true) {2935 while (true) {
2859 if (self.eatToken(Token.Id.DocComment)) |line_comment| {2936 if (self.eatToken(Token.Id.DocComment)) |line_comment| {
...@@ -2864,7 +2941,6 @@ pub const Parser = struct {...@@ -2864,7 +2941,6 @@ pub const Parser = struct {
2864 const comment_node = try arena.construct(ast.Node.DocComment {2941 const comment_node = try arena.construct(ast.Node.DocComment {
2865 .base = ast.Node {2942 .base = ast.Node {
2866 .id = ast.Node.Id.DocComment,2943 .id = ast.Node.Id.DocComment,
2867 .doc_comments = null,
2868 .same_line_comment = null,2944 .same_line_comment = null,
2869 },2945 },
2870 .lines = ArrayList(Token).init(arena),2946 .lines = ArrayList(Token).init(arena),
...@@ -2886,7 +2962,6 @@ pub const Parser = struct {...@@ -2886,7 +2962,6 @@ pub const Parser = struct {
2886 return try arena.construct(ast.Node.LineComment {2962 return try arena.construct(ast.Node.LineComment {
2887 .base = ast.Node {2963 .base = ast.Node {
2888 .id = ast.Node.Id.LineComment,2964 .id = ast.Node.Id.LineComment,
2889 .doc_comments = null,
2890 .same_line_comment = null,2965 .same_line_comment = null,
2891 },2966 },
2892 .token = token,2967 .token = token,
...@@ -3022,6 +3097,7 @@ pub const Parser = struct {...@@ -3022,6 +3097,7 @@ pub const Parser = struct {
3022 const node = try self.createToCtxNode(arena, ctx, ast.Node.Suspend,3097 const node = try self.createToCtxNode(arena, ctx, ast.Node.Suspend,
3023 ast.Node.Suspend {3098 ast.Node.Suspend {
3024 .base = undefined,3099 .base = undefined,
3100 .label = null,
3025 .suspend_token = *token,3101 .suspend_token = *token,
3026 .payload = null,3102 .payload = null,
3027 .body = null,3103 .body = null,
...@@ -3047,6 +3123,7 @@ pub const Parser = struct {...@@ -3047,6 +3123,7 @@ pub const Parser = struct {
3047 stack.append(State { .Else = &node.@"else" }) catch unreachable;3123 stack.append(State { .Else = &node.@"else" }) catch unreachable;
3048 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });3124 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
3049 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });3125 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
3126 try stack.append(State { .LookForSameLineComment = &node.condition });
3050 try stack.append(State { .ExpectToken = Token.Id.RParen });3127 try stack.append(State { .ExpectToken = Token.Id.RParen });
3051 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });3128 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
3052 try stack.append(State { .ExpectToken = Token.Id.LParen });3129 try stack.append(State { .ExpectToken = Token.Id.LParen });
...@@ -3078,7 +3155,6 @@ pub const Parser = struct {...@@ -3078,7 +3155,6 @@ pub const Parser = struct {
3078 const node = try arena.construct(ast.Node.Switch {3155 const node = try arena.construct(ast.Node.Switch {
3079 .base = ast.Node {3156 .base = ast.Node {
3080 .id = ast.Node.Id.Switch,3157 .id = ast.Node.Id.Switch,
3081 .doc_comments = null,
3082 .same_line_comment = null,3158 .same_line_comment = null,
3083 },3159 },
3084 .switch_token = *token,3160 .switch_token = *token,
...@@ -3106,6 +3182,7 @@ pub const Parser = struct {...@@ -3106,6 +3182,7 @@ pub const Parser = struct {
3106 .base = undefined,3182 .base = undefined,
3107 .comptime_token = *token,3183 .comptime_token = *token,
3108 .expr = undefined,3184 .expr = undefined,
3185 .doc_comments = null,
3109 }3186 }
3110 );3187 );
3111 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });3188 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
...@@ -3248,7 +3325,6 @@ pub const Parser = struct {...@@ -3248,7 +3325,6 @@ pub const Parser = struct {
3248 const id = ast.Node.typeToId(T);3325 const id = ast.Node.typeToId(T);
3249 break :blk ast.Node {3326 break :blk ast.Node {
3250 .id = id,3327 .id = id,
3251 .doc_comments = null,
3252 .same_line_comment = null,3328 .same_line_comment = null,
3253 };3329 };
3254 };3330 };
...@@ -3383,11 +3459,10 @@ pub const Parser = struct {...@@ -3383,11 +3459,10 @@ pub const Parser = struct {
3383 Expression: &ast.Node,3459 Expression: &ast.Node,
3384 VarDecl: &ast.Node.VarDecl,3460 VarDecl: &ast.Node.VarDecl,
3385 Statement: &ast.Node,3461 Statement: &ast.Node,
3386 FieldInitializer: &ast.Node.FieldInitializer,
3387 PrintIndent,3462 PrintIndent,
3388 Indent: usize,3463 Indent: usize,
3389 PrintSameLineComment: ?&Token,3464 PrintSameLineComment: ?&Token,
3390 PrintComments: &ast.Node,3465 PrintLineComment: &Token,
3391 };3466 };
33923467
3393 pub fn renderSource(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {3468 pub fn renderSource(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {
...@@ -3426,7 +3501,7 @@ pub const Parser = struct {...@@ -3426,7 +3501,7 @@ pub const Parser = struct {
3426 switch (decl.id) {3501 switch (decl.id) {
3427 ast.Node.Id.FnProto => {3502 ast.Node.Id.FnProto => {
3428 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);3503 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
3429 try self.renderComments(stream, &fn_proto.base, indent);3504 try self.renderComments(stream, fn_proto, indent);
34303505
3431 if (fn_proto.body_node) |body_node| {3506 if (fn_proto.body_node) |body_node| {
3432 stack.append(RenderState { .Expression = body_node}) catch unreachable;3507 stack.append(RenderState { .Expression = body_node}) catch unreachable;
...@@ -3448,12 +3523,12 @@ pub const Parser = struct {...@@ -3448,12 +3523,12 @@ pub const Parser = struct {
3448 },3523 },
3449 ast.Node.Id.VarDecl => {3524 ast.Node.Id.VarDecl => {
3450 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);3525 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
3451 try self.renderComments(stream, &var_decl.base, indent);3526 try self.renderComments(stream, var_decl, indent);
3452 try stack.append(RenderState { .VarDecl = var_decl});3527 try stack.append(RenderState { .VarDecl = var_decl});
3453 },3528 },
3454 ast.Node.Id.TestDecl => {3529 ast.Node.Id.TestDecl => {
3455 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);3530 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
3456 try self.renderComments(stream, &test_decl.base, indent);3531 try self.renderComments(stream, test_decl, indent);
3457 try stream.print("test ");3532 try stream.print("test ");
3458 try stack.append(RenderState { .Expression = test_decl.body_node });3533 try stack.append(RenderState { .Expression = test_decl.body_node });
3459 try stack.append(RenderState { .Text = " " });3534 try stack.append(RenderState { .Text = " " });
...@@ -3461,6 +3536,7 @@ pub const Parser = struct {...@@ -3461,6 +3536,7 @@ pub const Parser = struct {
3461 },3536 },
3462 ast.Node.Id.StructField => {3537 ast.Node.Id.StructField => {
3463 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);3538 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
3539 try self.renderComments(stream, field, indent);
3464 if (field.visib_token) |visib_token| {3540 if (field.visib_token) |visib_token| {
3465 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));3541 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3466 }3542 }
...@@ -3470,9 +3546,16 @@ pub const Parser = struct {...@@ -3470,9 +3546,16 @@ pub const Parser = struct {
3470 },3546 },
3471 ast.Node.Id.UnionTag => {3547 ast.Node.Id.UnionTag => {
3472 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);3548 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
3549 try self.renderComments(stream, tag, indent);
3473 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));3550 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
34743551
3475 try stack.append(RenderState { .Text = "," });3552 try stack.append(RenderState { .Text = "," });
3553
3554 if (tag.value_expr) |value_expr| {
3555 try stack.append(RenderState { .Expression = value_expr });
3556 try stack.append(RenderState { .Text = " = " });
3557 }
3558
3476 if (tag.type_expr) |type_expr| {3559 if (tag.type_expr) |type_expr| {
3477 try stream.print(": ");3560 try stream.print(": ");
3478 try stack.append(RenderState { .Expression = type_expr});3561 try stack.append(RenderState { .Expression = type_expr});
...@@ -3480,6 +3563,7 @@ pub const Parser = struct {...@@ -3480,6 +3563,7 @@ pub const Parser = struct {
3480 },3563 },
3481 ast.Node.Id.EnumTag => {3564 ast.Node.Id.EnumTag => {
3482 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);3565 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
3566 try self.renderComments(stream, tag, indent);
3483 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));3567 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
34843568
3485 try stack.append(RenderState { .Text = "," });3569 try stack.append(RenderState { .Text = "," });
...@@ -3488,6 +3572,11 @@ pub const Parser = struct {...@@ -3488,6 +3572,11 @@ pub const Parser = struct {
3488 try stack.append(RenderState { .Expression = value});3572 try stack.append(RenderState { .Expression = value});
3489 }3573 }
3490 },3574 },
3575 ast.Node.Id.ErrorTag => {
3576 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
3577 try self.renderComments(stream, tag, indent);
3578 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3579 },
3491 ast.Node.Id.Comptime => {3580 ast.Node.Id.Comptime => {
3492 if (requireSemiColon(decl)) {3581 if (requireSemiColon(decl)) {
3493 try stack.append(RenderState { .Text = ";" });3582 try stack.append(RenderState { .Text = ";" });
...@@ -3502,17 +3591,12 @@ pub const Parser = struct {...@@ -3502,17 +3591,12 @@ pub const Parser = struct {
3502 }3591 }
3503 },3592 },
35043593
3505 RenderState.FieldInitializer => |field_init| {
3506 try stream.print(".{}", self.tokenizer.getTokenSlice(field_init.name_token));
3507 try stream.print(" = ");
3508 try stack.append(RenderState { .Expression = field_init.expr });
3509 },
3510
3511 RenderState.VarDecl => |var_decl| {3594 RenderState.VarDecl => |var_decl| {
3512 try stack.append(RenderState { .Text = ";" });3595 try stack.append(RenderState { .Text = ";" });
3513 if (var_decl.init_node) |init_node| {3596 if (var_decl.init_node) |init_node| {
3514 try stack.append(RenderState { .Expression = init_node });3597 try stack.append(RenderState { .Expression = init_node });
3515 try stack.append(RenderState { .Text = " = " });3598 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
3599 try stack.append(RenderState { .Text = text });
3516 }3600 }
3517 if (var_decl.align_node) |align_node| {3601 if (var_decl.align_node) |align_node| {
3518 try stack.append(RenderState { .Text = ")" });3602 try stack.append(RenderState { .Text = ")" });
...@@ -3630,6 +3714,9 @@ pub const Parser = struct {...@@ -3630,6 +3714,9 @@ pub const Parser = struct {
3630 },3714 },
3631 ast.Node.Id.Suspend => {3715 ast.Node.Id.Suspend => {
3632 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);3716 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
3717 if (suspend_node.label) |label| {
3718 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3719 }
3633 try stream.print("{}", self.tokenizer.getTokenSlice(suspend_node.suspend_token));3720 try stream.print("{}", self.tokenizer.getTokenSlice(suspend_node.suspend_token));
36343721
3635 if (suspend_node.body) |body| {3722 if (suspend_node.body) |body| {
...@@ -3803,19 +3890,41 @@ pub const Parser = struct {...@@ -3803,19 +3890,41 @@ pub const Parser = struct {
3803 try stack.append(RenderState { .Expression = suffix_op.lhs });3890 try stack.append(RenderState { .Expression = suffix_op.lhs });
3804 continue;3891 continue;
3805 }3892 }
3893 if (field_inits.len == 1) {
3894 const field_init = field_inits.at(0);
3895
3896 try stack.append(RenderState { .Text = " }" });
3897 try stack.append(RenderState { .Expression = field_init });
3898 try stack.append(RenderState { .Text = "{ " });
3899 try stack.append(RenderState { .Expression = suffix_op.lhs });
3900 continue;
3901 }
3806 try stack.append(RenderState { .Text = "}"});3902 try stack.append(RenderState { .Text = "}"});
3807 try stack.append(RenderState.PrintIndent);3903 try stack.append(RenderState.PrintIndent);
3808 try stack.append(RenderState { .Indent = indent });3904 try stack.append(RenderState { .Indent = indent });
3905 try stack.append(RenderState { .Text = "\n" });
3809 var i = field_inits.len;3906 var i = field_inits.len;
3810 while (i != 0) {3907 while (i != 0) {
3811 i -= 1;3908 i -= 1;
3812 const field_init = field_inits.at(i);3909 const field_init = field_inits.at(i);
3813 try stack.append(RenderState { .Text = ",\n" });3910 if (field_init.id != ast.Node.Id.LineComment) {
3814 try stack.append(RenderState { .FieldInitializer = field_init });3911 try stack.append(RenderState { .Text = "," });
3912 }
3913 try stack.append(RenderState { .Expression = field_init });
3815 try stack.append(RenderState.PrintIndent);3914 try stack.append(RenderState.PrintIndent);
3915 if (i != 0) {
3916 try stack.append(RenderState { .Text = blk: {
3917 const prev_node = field_inits.at(i - 1);
3918 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, field_init.firstToken());
3919 if (loc.line >= 2) {
3920 break :blk "\n\n";
3921 }
3922 break :blk "\n";
3923 }});
3924 }
3816 }3925 }
3817 try stack.append(RenderState { .Indent = indent + indent_delta });3926 try stack.append(RenderState { .Indent = indent + indent_delta });
3818 try stack.append(RenderState { .Text = " {\n"});3927 try stack.append(RenderState { .Text = "{\n"});
3819 try stack.append(RenderState { .Expression = suffix_op.lhs });3928 try stack.append(RenderState { .Expression = suffix_op.lhs });
3820 },3929 },
3821 ast.Node.SuffixOp.Op.ArrayInitializer => |exprs| {3930 ast.Node.SuffixOp.Op.ArrayInitializer => |exprs| {
...@@ -3829,7 +3938,7 @@ pub const Parser = struct {...@@ -3829,7 +3938,7 @@ pub const Parser = struct {
38293938
3830 try stack.append(RenderState { .Text = "}" });3939 try stack.append(RenderState { .Text = "}" });
3831 try stack.append(RenderState { .Expression = expr });3940 try stack.append(RenderState { .Expression = expr });
3832 try stack.append(RenderState { .Text = " {" });3941 try stack.append(RenderState { .Text = "{" });
3833 try stack.append(RenderState { .Expression = suffix_op.lhs });3942 try stack.append(RenderState { .Expression = suffix_op.lhs });
3834 continue;3943 continue;
3835 }3944 }
...@@ -3846,7 +3955,7 @@ pub const Parser = struct {...@@ -3846,7 +3955,7 @@ pub const Parser = struct {
3846 try stack.append(RenderState.PrintIndent);3955 try stack.append(RenderState.PrintIndent);
3847 }3956 }
3848 try stack.append(RenderState { .Indent = indent + indent_delta });3957 try stack.append(RenderState { .Indent = indent + indent_delta });
3849 try stack.append(RenderState { .Text = " {\n"});3958 try stack.append(RenderState { .Text = "{\n"});
3850 try stack.append(RenderState { .Expression = suffix_op.lhs });3959 try stack.append(RenderState { .Expression = suffix_op.lhs });
3851 },3960 },
3852 }3961 }
...@@ -4014,7 +4123,15 @@ pub const Parser = struct {...@@ -4014,7 +4123,15 @@ pub const Parser = struct {
40144123
4015 switch (container_decl.init_arg_expr) {4124 switch (container_decl.init_arg_expr) {
4016 ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),4125 ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
4017 ast.Node.ContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}),4126 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
4127 if (enum_tag_type) |expr| {
4128 try stack.append(RenderState { .Text = ")) "});
4129 try stack.append(RenderState { .Expression = expr});
4130 try stack.append(RenderState { .Text = "(enum("});
4131 } else {
4132 try stack.append(RenderState { .Text = "(enum) "});
4133 }
4134 },
4018 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {4135 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
4019 try stack.append(RenderState { .Text = ") "});4136 try stack.append(RenderState { .Text = ") "});
4020 try stack.append(RenderState { .Expression = type_expr});4137 try stack.append(RenderState { .Expression = type_expr});
...@@ -4024,14 +4141,39 @@ pub const Parser = struct {...@@ -4024,14 +4141,39 @@ pub const Parser = struct {
4024 },4141 },
4025 ast.Node.Id.ErrorSetDecl => {4142 ast.Node.Id.ErrorSetDecl => {
4026 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);4143 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
4027 try stream.print("error ");4144
4145 const decls = err_set_decl.decls.toSliceConst();
4146 if (decls.len == 0) {
4147 try stream.write("error{}");
4148 continue;
4149 }
4150
4151 if (decls.len == 1) blk: {
4152 const node = decls[0];
4153
4154 // if there are any doc comments or same line comments
4155 // don't try to put it all on one line
4156 if (node.same_line_comment != null) break :blk;
4157 if (node.cast(ast.Node.ErrorTag)) |tag| {
4158 if (tag.doc_comments != null) break :blk;
4159 } else {
4160 break :blk;
4161 }
4162
4163
4164 try stream.write("error{");
4165 try stack.append(RenderState { .Text = "}" });
4166 try stack.append(RenderState { .TopLevelDecl = node });
4167 continue;
4168 }
4169
4170 try stream.write("error{");
40284171
4029 try stack.append(RenderState { .Text = "}"});4172 try stack.append(RenderState { .Text = "}"});
4030 try stack.append(RenderState.PrintIndent);4173 try stack.append(RenderState.PrintIndent);
4031 try stack.append(RenderState { .Indent = indent });4174 try stack.append(RenderState { .Indent = indent });
4032 try stack.append(RenderState { .Text = "\n"});4175 try stack.append(RenderState { .Text = "\n"});
40334176
4034 const decls = err_set_decl.decls.toSliceConst();
4035 var i = decls.len;4177 var i = decls.len;
4036 while (i != 0) {4178 while (i != 0) {
4037 i -= 1;4179 i -= 1;
...@@ -4039,8 +4181,7 @@ pub const Parser = struct {...@@ -4039,8 +4181,7 @@ pub const Parser = struct {
4039 if (node.id != ast.Node.Id.LineComment) {4181 if (node.id != ast.Node.Id.LineComment) {
4040 try stack.append(RenderState { .Text = "," });4182 try stack.append(RenderState { .Text = "," });
4041 }4183 }
4042 try stack.append(RenderState { .Expression = node });4184 try stack.append(RenderState { .TopLevelDecl = node });
4043 try stack.append(RenderState { .PrintComments = node });
4044 try stack.append(RenderState.PrintIndent);4185 try stack.append(RenderState.PrintIndent);
4045 try stack.append(RenderState {4186 try stack.append(RenderState {
4046 .Text = blk: {4187 .Text = blk: {
...@@ -4056,7 +4197,6 @@ pub const Parser = struct {...@@ -4056,7 +4197,6 @@ pub const Parser = struct {
4056 });4197 });
4057 }4198 }
4058 try stack.append(RenderState { .Indent = indent + indent_delta});4199 try stack.append(RenderState { .Indent = indent + indent_delta});
4059 try stack.append(RenderState { .Text = "{"});
4060 },4200 },
4061 ast.Node.Id.MultilineStringLiteral => {4201 ast.Node.Id.MultilineStringLiteral => {
4062 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);4202 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
...@@ -4068,7 +4208,7 @@ pub const Parser = struct {...@@ -4068,7 +4208,7 @@ pub const Parser = struct {
4068 try stream.writeByteNTimes(' ', indent + indent_delta);4208 try stream.writeByteNTimes(' ', indent + indent_delta);
4069 try stream.print("{}", self.tokenizer.getTokenSlice(t));4209 try stream.print("{}", self.tokenizer.getTokenSlice(t));
4070 }4210 }
4071 try stream.writeByteNTimes(' ', indent + indent_delta);4211 try stream.writeByteNTimes(' ', indent);
4072 },4212 },
4073 ast.Node.Id.UndefinedLiteral => {4213 ast.Node.Id.UndefinedLiteral => {
4074 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);4214 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
...@@ -4151,6 +4291,14 @@ pub const Parser = struct {...@@ -4151,6 +4291,14 @@ pub const Parser = struct {
4151 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });4291 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
4152 }4292 }
4153 },4293 },
4294 ast.Node.Id.PromiseType => {
4295 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
4296 try stream.write(self.tokenizer.getTokenSlice(promise_type.promise_token));
4297 if (promise_type.result) |result| {
4298 try stream.write(self.tokenizer.getTokenSlice(result.arrow_token));
4299 try stack.append(RenderState { .Expression = result.return_type});
4300 }
4301 },
4154 ast.Node.Id.LineComment => {4302 ast.Node.Id.LineComment => {
4155 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);4303 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
4156 try stream.write(self.tokenizer.getTokenSlice(line_comment_node.token));4304 try stream.write(self.tokenizer.getTokenSlice(line_comment_node.token));
...@@ -4158,14 +4306,21 @@ pub const Parser = struct {...@@ -4158,14 +4306,21 @@ pub const Parser = struct {
4158 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes4306 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
4159 ast.Node.Id.Switch => {4307 ast.Node.Id.Switch => {
4160 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);4308 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
4309 const cases = switch_node.cases.toSliceConst();
4310
4161 try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token));4311 try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token));
41624312
4313 if (cases.len == 0) {
4314 try stack.append(RenderState { .Text = ") {}"});
4315 try stack.append(RenderState { .Expression = switch_node.expr });
4316 continue;
4317 }
4318
4163 try stack.append(RenderState { .Text = "}"});4319 try stack.append(RenderState { .Text = "}"});
4164 try stack.append(RenderState.PrintIndent);4320 try stack.append(RenderState.PrintIndent);
4165 try stack.append(RenderState { .Indent = indent });4321 try stack.append(RenderState { .Indent = indent });
4166 try stack.append(RenderState { .Text = "\n"});4322 try stack.append(RenderState { .Text = "\n"});
41674323
4168 const cases = switch_node.cases.toSliceConst();
4169 var i = cases.len;4324 var i = cases.len;
4170 while (i != 0) {4325 while (i != 0) {
4171 i -= 1;4326 i -= 1;
...@@ -4192,8 +4347,6 @@ pub const Parser = struct {...@@ -4192,8 +4347,6 @@ pub const Parser = struct {
4192 ast.Node.Id.SwitchCase => {4347 ast.Node.Id.SwitchCase => {
4193 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);4348 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
41944349
4195 try self.renderComments(stream, base, indent);
4196
4197 try stack.append(RenderState { .PrintSameLineComment = base.same_line_comment });4350 try stack.append(RenderState { .PrintSameLineComment = base.same_line_comment });
4198 try stack.append(RenderState { .Text = "," });4351 try stack.append(RenderState { .Text = "," });
4199 try stack.append(RenderState { .Expression = switch_case.expr });4352 try stack.append(RenderState { .Expression = switch_case.expr });
...@@ -4372,7 +4525,18 @@ pub const Parser = struct {...@@ -4372,7 +4525,18 @@ pub const Parser = struct {
4372 }4525 }
4373 }4526 }
43744527
4375 try stack.append(RenderState { .Expression = if_node.body });4528 if (if_node.condition.same_line_comment) |comment| {
4529 try stack.append(RenderState { .Indent = indent });
4530 try stack.append(RenderState { .Expression = if_node.body });
4531 try stack.append(RenderState.PrintIndent);
4532 try stack.append(RenderState { .Indent = indent + indent_delta });
4533 try stack.append(RenderState { .Text = "\n" });
4534 try stack.append(RenderState { .PrintLineComment = comment });
4535 } else {
4536 try stack.append(RenderState { .Expression = if_node.body });
4537 }
4538
4539
4376 try stack.append(RenderState { .Text = " " });4540 try stack.append(RenderState { .Text = " " });
43774541
4378 if (if_node.payload) |payload| {4542 if (if_node.payload) |payload| {
...@@ -4505,6 +4669,7 @@ pub const Parser = struct {...@@ -4505,6 +4669,7 @@ pub const Parser = struct {
4505 ast.Node.Id.StructField,4669 ast.Node.Id.StructField,
4506 ast.Node.Id.UnionTag,4670 ast.Node.Id.UnionTag,
4507 ast.Node.Id.EnumTag,4671 ast.Node.Id.EnumTag,
4672 ast.Node.Id.ErrorTag,
4508 ast.Node.Id.Root,4673 ast.Node.Id.Root,
4509 ast.Node.Id.VarDecl,4674 ast.Node.Id.VarDecl,
4510 ast.Node.Id.Use,4675 ast.Node.Id.Use,
...@@ -4512,7 +4677,6 @@ pub const Parser = struct {...@@ -4512,7 +4677,6 @@ pub const Parser = struct {
4512 ast.Node.Id.ParamDecl => unreachable,4677 ast.Node.Id.ParamDecl => unreachable,
4513 },4678 },
4514 RenderState.Statement => |base| {4679 RenderState.Statement => |base| {
4515 try self.renderComments(stream, base, indent);
4516 try stack.append(RenderState { .PrintSameLineComment = base.same_line_comment } );4680 try stack.append(RenderState { .PrintSameLineComment = base.same_line_comment } );
4517 switch (base.id) {4681 switch (base.id) {
4518 ast.Node.Id.VarDecl => {4682 ast.Node.Id.VarDecl => {
...@@ -4533,15 +4697,14 @@ pub const Parser = struct {...@@ -4533,15 +4697,14 @@ pub const Parser = struct {
4533 const comment_token = maybe_comment ?? break :blk;4697 const comment_token = maybe_comment ?? break :blk;
4534 try stream.print(" {}", self.tokenizer.getTokenSlice(comment_token));4698 try stream.print(" {}", self.tokenizer.getTokenSlice(comment_token));
4535 },4699 },
45364700 RenderState.PrintLineComment => |comment_token| {
4537 RenderState.PrintComments => |node| blk: {4701 try stream.write(self.tokenizer.getTokenSlice(comment_token));
4538 try self.renderComments(stream, node, indent);
4539 },4702 },
4540 }4703 }
4541 }4704 }
4542 }4705 }
45434706
4544 fn renderComments(self: &Parser, stream: var, node: &ast.Node, indent: usize) !void {4707 fn renderComments(self: &Parser, stream: var, node: var, indent: usize) !void {
4545 const comment = node.doc_comments ?? return;4708 const comment = node.doc_comments ?? return;
4546 for (comment.lines.toSliceConst()) |line_token| {4709 for (comment.lines.toSliceConst()) |line_token| {
4547 try stream.print("{}\n", self.tokenizer.getTokenSlice(line_token));4710 try stream.print("{}\n", self.tokenizer.getTokenSlice(line_token));
std/zig/parser_test.zig+154-62
...@@ -1,6 +1,129 @@...@@ -1,6 +1,129 @@
1test "zig fmt: same-line comment after non-block if expression" {
2 try testCanonical(
3 \\comptime {
4 \\ if (sr > n_uword_bits - 1) {
5 \\ // d > r
6 \\ return 0;
7 \\ }
8 \\}
9 \\
10 );
11}
12
13test "zig fmt: switch with empty body" {
14 try testCanonical(
15 \\test "" {
16 \\ foo() catch |err| switch (err) {};
17 \\}
18 \\
19 );
20}
21
22test "zig fmt: same-line comment on comptime expression" {
23 try testCanonical(
24 \\test "" {
25 \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
26 \\}
27 \\
28 );
29}
30
31test "zig fmt: float literal with exponent" {
32 try testCanonical(
33 \\pub const f64_true_min = 4.94065645841246544177e-324;
34 \\
35 );
36}
37
38test "zig fmt: line comments in struct initializer" {
39 try testCanonical(
40 \\fn foo() void {
41 \\ return Self{
42 \\ .a = b,
43 \\
44 \\ // Initialize these two fields to buffer_size so that
45 \\ // in `readFn` we treat the state as being able to read
46 \\ .start_index = buffer_size,
47 \\ .end_index = buffer_size,
48 \\
49 \\ // middle
50 \\
51 \\ .a = b,
52 \\
53 \\ // end
54 \\ };
55 \\}
56 \\
57 );
58}
59
60test "zig fmt: doc comments before struct field" {
61 try testCanonical(
62 \\pub const Allocator = struct {
63 \\ /// Allocate byte_count bytes and return them in a slice, with the
64 \\ /// slice's pointer aligned at least to alignment bytes.
65 \\ allocFn: fn() void,
66 \\};
67 \\
68 );
69}
70
71test "zig fmt: error set declaration" {
72 try testCanonical(
73 \\const E = error{
74 \\ A,
75 \\ B,
76 \\
77 \\ C,
78 \\};
79 \\
80 \\const Error = error{
81 \\ /// no more memory
82 \\ OutOfMemory,
83 \\};
84 \\
85 \\const Error = error{
86 \\ /// no more memory
87 \\ OutOfMemory,
88 \\
89 \\ /// another
90 \\ Another,
91 \\
92 \\ // end
93 \\};
94 \\
95 \\const Error = error{OutOfMemory};
96 \\const Error = error{};
97 \\
98 );
99}
100
101test "zig fmt: union(enum(u32)) with assigned enum values" {
102 try testCanonical(
103 \\const MultipleChoice = union(enum(u32)) {
104 \\ A = 20,
105 \\ B = 40,
106 \\ C = 60,
107 \\ D = 1000,
108 \\};
109 \\
110 );
111}
112
113test "zig fmt: labeled suspend" {
114 try testCanonical(
115 \\fn foo() void {
116 \\ s: suspend |p| {
117 \\ break :s;
118 \\ }
119 \\}
120 \\
121 );
122}
123
1test "zig fmt: comments before error set decl" {124test "zig fmt: comments before error set decl" {
2 try testCanonical(125 try testCanonical(
3 \\const UnexpectedError = error {126 \\const UnexpectedError = error{
4 \\ /// The Operating System returned an undocumented error code.127 \\ /// The Operating System returned an undocumented error code.
5 \\ Unexpected,128 \\ Unexpected,
6 \\ // another129 \\ // another
...@@ -92,7 +215,7 @@ test "zig fmt: same-line comment after field decl" {...@@ -92,7 +215,7 @@ test "zig fmt: same-line comment after field decl" {
92215
93test "zig fmt: array literal with 1 item on 1 line" {216test "zig fmt: array literal with 1 item on 1 line" {
94 try testCanonical(217 try testCanonical(
95 \\var s = []const u64 {0} ** 25;218 \\var s = []const u64{0} ** 25;
96 \\219 \\
97 );220 );
98}221}
...@@ -117,7 +240,7 @@ test "zig fmt: comments before global variables" {...@@ -117,7 +240,7 @@ test "zig fmt: comments before global variables" {
117 );240 );
118}241}
119242
120test "zig fmt: comments before statements" {243test "zig fmt: comments in statements" {
121 try testCanonical(244 try testCanonical(
122 \\test "std" {245 \\test "std" {
123 \\ // statement comment246 \\ // statement comment
...@@ -147,22 +270,6 @@ test "zig fmt: comments before test decl" {...@@ -147,22 +270,6 @@ test "zig fmt: comments before test decl" {
147 );270 );
148}271}
149272
150test "zig fmt: comments before variable declarations" {
151 try testCanonical(
152 \\const std = @import("std");
153 \\
154 \\pub fn main() !void {
155 \\ /// If this program is run without stdout attached, exit with an error.
156 \\ /// another comment
157 \\ var stdout_file = try std.io.getStdOut;
158 \\ // If this program is run without stdout attached, exit with an error.
159 \\ // another comment
160 \\ var stdout_file = try std.io.getStdOut;
161 \\}
162 \\
163 );
164}
165
166test "zig fmt: preserve spacing" {273test "zig fmt: preserve spacing" {
167 try testCanonical(274 try testCanonical(
168 \\const std = @import("std");275 \\const std = @import("std");
...@@ -423,10 +530,18 @@ test "zig fmt: functions" {...@@ -423,10 +530,18 @@ test "zig fmt: functions" {
423530
424test "zig fmt: multiline string" {531test "zig fmt: multiline string" {
425 try testCanonical(532 try testCanonical(
426 \\const s = 533 \\test "" {
427 \\ \\ something534 \\ const s1 =
428 \\ \\ something else535 \\ \\one
536 \\ \\two)
537 \\ \\three
429 \\ ;538 \\ ;
539 \\ const s2 =
540 \\ c\\one
541 \\ c\\two)
542 \\ c\\three
543 \\ ;
544 \\}
430 \\545 \\
431 );546 );
432}547}
...@@ -570,26 +685,14 @@ test "zig fmt: union declaration" {...@@ -570,26 +685,14 @@ test "zig fmt: union declaration" {
570 );685 );
571}686}
572687
573test "zig fmt: error set declaration" {
574 try testCanonical(
575 \\const E = error {
576 \\ A,
577 \\ B,
578 \\
579 \\ C,
580 \\};
581 \\
582 );
583}
584
585test "zig fmt: arrays" {688test "zig fmt: arrays" {
586 try testCanonical(689 try testCanonical(
587 \\test "test array" {690 \\test "test array" {
588 \\ const a: [2]u8 = [2]u8 {691 \\ const a: [2]u8 = [2]u8{
589 \\ 1,692 \\ 1,
590 \\ 2,693 \\ 2,
591 \\ };694 \\ };
592 \\ const a: [2]u8 = []u8 {695 \\ const a: [2]u8 = []u8{
593 \\ 1,696 \\ 1,
594 \\ 2,697 \\ 2,
595 \\ };698 \\ };
...@@ -601,15 +704,17 @@ test "zig fmt: arrays" {...@@ -601,15 +704,17 @@ test "zig fmt: arrays" {
601704
602test "zig fmt: container initializers" {705test "zig fmt: container initializers" {
603 try testCanonical(706 try testCanonical(
604 \\const a1 = []u8{};707 \\const a0 = []u8{};
605 \\const a2 = []u8 {708 \\const a1 = []u8{1};
709 \\const a2 = []u8{
606 \\ 1,710 \\ 1,
607 \\ 2,711 \\ 2,
608 \\ 3,712 \\ 3,
609 \\ 4,713 \\ 4,
610 \\};714 \\};
611 \\const s1 = S{};715 \\const s0 = S{};
612 \\const s2 = S {716 \\const s1 = S{ .a = 1 };
717 \\const s2 = S{
613 \\ .a = 1,718 \\ .a = 1,
614 \\ .b = 2,719 \\ .b = 2,
615 \\};720 \\};
...@@ -678,9 +783,6 @@ test "zig fmt: switch" {...@@ -678,9 +783,6 @@ test "zig fmt: switch" {
678 \\ Float: f64,783 \\ Float: f64,
679 \\ };784 \\ };
680 \\785 \\
681 \\ const u = Union {
682 \\ .Int = 0,
683 \\ };
684 \\ switch (u) {786 \\ switch (u) {
685 \\ Union.Int => |int| {},787 \\ Union.Int => |int| {},
686 \\ Union.Float => |*float| unreachable,788 \\ Union.Float => |*float| unreachable,
...@@ -759,11 +861,6 @@ test "zig fmt: while" {...@@ -759,11 +861,6 @@ test "zig fmt: while" {
759test "zig fmt: for" {861test "zig fmt: for" {
760 try testCanonical(862 try testCanonical(
761 \\test "for" {863 \\test "for" {
762 \\ const a = []u8 {
763 \\ 1,
764 \\ 2,
765 \\ 3,
766 \\ };
767 \\ for (a) |v| {864 \\ for (a) |v| {
768 \\ continue;865 \\ continue;
769 \\ }866 \\ }
...@@ -940,12 +1037,12 @@ test "zig fmt: coroutines" {...@@ -940,12 +1037,12 @@ test "zig fmt: coroutines" {
940 \\ suspend;1037 \\ suspend;
941 \\ x += 1;1038 \\ x += 1;
942 \\ suspend |p| {}1039 \\ suspend |p| {}
943 \\ const p = async simpleAsyncFn() catch unreachable;1040 \\ const p: promise->void = async simpleAsyncFn() catch unreachable;
944 \\ await p;1041 \\ await p;
945 \\}1042 \\}
946 \\1043 \\
947 \\test "coroutine suspend, resume, cancel" {1044 \\test "coroutine suspend, resume, cancel" {
948 \\ const p = try async<std.debug.global_allocator> testAsyncSeq();1045 \\ const p: promise = try async<std.debug.global_allocator> testAsyncSeq();
949 \\ resume p;1046 \\ resume p;
950 \\ cancel p;1047 \\ cancel p;
951 \\}1048 \\}
...@@ -994,15 +1091,6 @@ test "zig fmt: error return" {...@@ -994,15 +1091,6 @@ test "zig fmt: error return" {
994 );1091 );
995}1092}
9961093
997test "zig fmt: struct literals with fields on each line" {
998 try testCanonical(
999 \\var self = BufSet {
1000 \\ .hash_map = BufSetHashMap.init(a),
1001 \\};
1002 \\
1003 );
1004}
1005
1006const std = @import("std");1094const std = @import("std");
1007const mem = std.mem;1095const mem = std.mem;
1008const warn = std.debug.warn;1096const warn = std.debug.warn;
...@@ -1028,15 +1116,15 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {...@@ -1028,15 +1116,15 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) ![]u8 {
1028 return buffer.toOwnedSlice();1116 return buffer.toOwnedSlice();
1029}1117}
10301118
1031fn testCanonical(source: []const u8) !void {1119fn testTransform(source: []const u8, expected_source: []const u8) !void {
1032 const needed_alloc_count = x: {1120 const needed_alloc_count = x: {
1033 // Try it once with unlimited memory, make sure it works1121 // Try it once with unlimited memory, make sure it works
1034 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1122 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1035 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));1123 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));
1036 const result_source = try testParse(source, &failing_allocator.allocator);1124 const result_source = try testParse(source, &failing_allocator.allocator);
1037 if (!mem.eql(u8, result_source, source)) {1125 if (!mem.eql(u8, result_source, expected_source)) {
1038 warn("\n====== expected this output: =========\n");1126 warn("\n====== expected this output: =========\n");
1039 warn("{}", source);1127 warn("{}", expected_source);
1040 warn("\n======== instead found this: =========\n");1128 warn("\n======== instead found this: =========\n");
1041 warn("{}", result_source);1129 warn("{}", result_source);
1042 warn("\n======================================\n");1130 warn("\n======================================\n");
...@@ -1067,3 +1155,7 @@ fn testCanonical(source: []const u8) !void {...@@ -1067,3 +1155,7 @@ fn testCanonical(source: []const u8) !void {
1067 }1155 }
1068}1156}
10691157
1158fn testCanonical(source: []const u8) !void {
1159 return testTransform(source, source);
1160}
1161
std/zig/tokenizer.zig+62-51
...@@ -6,59 +6,60 @@ pub const Token = struct {...@@ -6,59 +6,60 @@ pub const Token = struct {
6 start: usize,6 start: usize,
7 end: usize,7 end: usize,
88
9 const KeywordId = struct {9 const Keyword = struct {
10 bytes: []const u8,10 bytes: []const u8,
11 id: Id,11 id: Id,
12 };12 };
1313
14 const keywords = []KeywordId {14 const keywords = []Keyword {
15 KeywordId{.bytes="align", .id = Id.Keyword_align},15 Keyword{.bytes="align", .id = Id.Keyword_align},
16 KeywordId{.bytes="and", .id = Id.Keyword_and},16 Keyword{.bytes="and", .id = Id.Keyword_and},
17 KeywordId{.bytes="asm", .id = Id.Keyword_asm},17 Keyword{.bytes="asm", .id = Id.Keyword_asm},
18 KeywordId{.bytes="async", .id = Id.Keyword_async},18 Keyword{.bytes="async", .id = Id.Keyword_async},
19 KeywordId{.bytes="await", .id = Id.Keyword_await},19 Keyword{.bytes="await", .id = Id.Keyword_await},
20 KeywordId{.bytes="break", .id = Id.Keyword_break},20 Keyword{.bytes="break", .id = Id.Keyword_break},
21 KeywordId{.bytes="catch", .id = Id.Keyword_catch},21 Keyword{.bytes="catch", .id = Id.Keyword_catch},
22 KeywordId{.bytes="cancel", .id = Id.Keyword_cancel},22 Keyword{.bytes="cancel", .id = Id.Keyword_cancel},
23 KeywordId{.bytes="comptime", .id = Id.Keyword_comptime},23 Keyword{.bytes="comptime", .id = Id.Keyword_comptime},
24 KeywordId{.bytes="const", .id = Id.Keyword_const},24 Keyword{.bytes="const", .id = Id.Keyword_const},
25 KeywordId{.bytes="continue", .id = Id.Keyword_continue},25 Keyword{.bytes="continue", .id = Id.Keyword_continue},
26 KeywordId{.bytes="defer", .id = Id.Keyword_defer},26 Keyword{.bytes="defer", .id = Id.Keyword_defer},
27 KeywordId{.bytes="else", .id = Id.Keyword_else},27 Keyword{.bytes="else", .id = Id.Keyword_else},
28 KeywordId{.bytes="enum", .id = Id.Keyword_enum},28 Keyword{.bytes="enum", .id = Id.Keyword_enum},
29 KeywordId{.bytes="errdefer", .id = Id.Keyword_errdefer},29 Keyword{.bytes="errdefer", .id = Id.Keyword_errdefer},
30 KeywordId{.bytes="error", .id = Id.Keyword_error},30 Keyword{.bytes="error", .id = Id.Keyword_error},
31 KeywordId{.bytes="export", .id = Id.Keyword_export},31 Keyword{.bytes="export", .id = Id.Keyword_export},
32 KeywordId{.bytes="extern", .id = Id.Keyword_extern},32 Keyword{.bytes="extern", .id = Id.Keyword_extern},
33 KeywordId{.bytes="false", .id = Id.Keyword_false},33 Keyword{.bytes="false", .id = Id.Keyword_false},
34 KeywordId{.bytes="fn", .id = Id.Keyword_fn},34 Keyword{.bytes="fn", .id = Id.Keyword_fn},
35 KeywordId{.bytes="for", .id = Id.Keyword_for},35 Keyword{.bytes="for", .id = Id.Keyword_for},
36 KeywordId{.bytes="if", .id = Id.Keyword_if},36 Keyword{.bytes="if", .id = Id.Keyword_if},
37 KeywordId{.bytes="inline", .id = Id.Keyword_inline},37 Keyword{.bytes="inline", .id = Id.Keyword_inline},
38 KeywordId{.bytes="nakedcc", .id = Id.Keyword_nakedcc},38 Keyword{.bytes="nakedcc", .id = Id.Keyword_nakedcc},
39 KeywordId{.bytes="noalias", .id = Id.Keyword_noalias},39 Keyword{.bytes="noalias", .id = Id.Keyword_noalias},
40 KeywordId{.bytes="null", .id = Id.Keyword_null},40 Keyword{.bytes="null", .id = Id.Keyword_null},
41 KeywordId{.bytes="or", .id = Id.Keyword_or},41 Keyword{.bytes="or", .id = Id.Keyword_or},
42 KeywordId{.bytes="packed", .id = Id.Keyword_packed},42 Keyword{.bytes="packed", .id = Id.Keyword_packed},
43 KeywordId{.bytes="pub", .id = Id.Keyword_pub},43 Keyword{.bytes="promise", .id = Id.Keyword_promise},
44 KeywordId{.bytes="resume", .id = Id.Keyword_resume},44 Keyword{.bytes="pub", .id = Id.Keyword_pub},
45 KeywordId{.bytes="return", .id = Id.Keyword_return},45 Keyword{.bytes="resume", .id = Id.Keyword_resume},
46 KeywordId{.bytes="section", .id = Id.Keyword_section},46 Keyword{.bytes="return", .id = Id.Keyword_return},
47 KeywordId{.bytes="stdcallcc", .id = Id.Keyword_stdcallcc},47 Keyword{.bytes="section", .id = Id.Keyword_section},
48 KeywordId{.bytes="struct", .id = Id.Keyword_struct},48 Keyword{.bytes="stdcallcc", .id = Id.Keyword_stdcallcc},
49 KeywordId{.bytes="suspend", .id = Id.Keyword_suspend},49 Keyword{.bytes="struct", .id = Id.Keyword_struct},
50 KeywordId{.bytes="switch", .id = Id.Keyword_switch},50 Keyword{.bytes="suspend", .id = Id.Keyword_suspend},
51 KeywordId{.bytes="test", .id = Id.Keyword_test},51 Keyword{.bytes="switch", .id = Id.Keyword_switch},
52 KeywordId{.bytes="this", .id = Id.Keyword_this},52 Keyword{.bytes="test", .id = Id.Keyword_test},
53 KeywordId{.bytes="true", .id = Id.Keyword_true},53 Keyword{.bytes="this", .id = Id.Keyword_this},
54 KeywordId{.bytes="try", .id = Id.Keyword_try},54 Keyword{.bytes="true", .id = Id.Keyword_true},
55 KeywordId{.bytes="undefined", .id = Id.Keyword_undefined},55 Keyword{.bytes="try", .id = Id.Keyword_try},
56 KeywordId{.bytes="union", .id = Id.Keyword_union},56 Keyword{.bytes="undefined", .id = Id.Keyword_undefined},
57 KeywordId{.bytes="unreachable", .id = Id.Keyword_unreachable},57 Keyword{.bytes="union", .id = Id.Keyword_union},
58 KeywordId{.bytes="use", .id = Id.Keyword_use},58 Keyword{.bytes="unreachable", .id = Id.Keyword_unreachable},
59 KeywordId{.bytes="var", .id = Id.Keyword_var},59 Keyword{.bytes="use", .id = Id.Keyword_use},
60 KeywordId{.bytes="volatile", .id = Id.Keyword_volatile},60 Keyword{.bytes="var", .id = Id.Keyword_var},
61 KeywordId{.bytes="while", .id = Id.Keyword_while},61 Keyword{.bytes="volatile", .id = Id.Keyword_volatile},
62 Keyword{.bytes="while", .id = Id.Keyword_while},
62 };63 };
6364
64 fn getKeyword(bytes: []const u8) ?Id {65 fn getKeyword(bytes: []const u8) ?Id {
...@@ -166,6 +167,7 @@ pub const Token = struct {...@@ -166,6 +167,7 @@ pub const Token = struct {
166 Keyword_null,167 Keyword_null,
167 Keyword_or,168 Keyword_or,
168 Keyword_packed,169 Keyword_packed,
170 Keyword_promise,
169 Keyword_pub,171 Keyword_pub,
170 Keyword_resume,172 Keyword_resume,
171 Keyword_return,173 Keyword_return,
...@@ -910,10 +912,10 @@ pub const Tokenizer = struct {...@@ -910,10 +912,10 @@ pub const Tokenizer = struct {
910 },912 },
911 },913 },
912 State.FloatFraction => switch (c) {914 State.FloatFraction => switch (c) {
913 'p', 'P' => {915 'p', 'P', 'e', 'E' => {
914 state = State.FloatExponentUnsigned;916 state = State.FloatExponentUnsigned;
915 },917 },
916 '0'...'9', 'a'...'f', 'A'...'F' => {},918 '0'...'9' => {},
917 else => break,919 else => break,
918 },920 },
919 State.FloatExponentUnsigned => switch (c) {921 State.FloatExponentUnsigned => switch (c) {
...@@ -1106,6 +1108,15 @@ test "tokenizer" {...@@ -1106,6 +1108,15 @@ test "tokenizer" {
1106 });1108 });
1107}1109}
11081110
1111test "tokenizer - float literal" {
1112 testTokenize("a = 4.94065645841246544177e-324;\n", []Token.Id {
1113 Token.Id.Identifier,
1114 Token.Id.Equal,
1115 Token.Id.FloatLiteral,
1116 Token.Id.Semicolon,
1117 });
1118}
1119
1109test "tokenizer - chars" {1120test "tokenizer - chars" {
1110 testTokenize("'c'", []Token.Id {Token.Id.CharLiteral});1121 testTokenize("'c'", []Token.Id {Token.Id.CharLiteral});
1111}1122}
test/behavior.zig+2
...@@ -37,6 +37,7 @@ comptime {...@@ -37,6 +37,7 @@ comptime {
37 _ = @import("cases/pub_enum/index.zig");37 _ = @import("cases/pub_enum/index.zig");
38 _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");38 _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
39 _ = @import("cases/reflection.zig");39 _ = @import("cases/reflection.zig");
40 _ = @import("cases/type_info.zig");
40 _ = @import("cases/sizeof_and_typeof.zig");41 _ = @import("cases/sizeof_and_typeof.zig");
41 _ = @import("cases/slice.zig");42 _ = @import("cases/slice.zig");
42 _ = @import("cases/struct.zig");43 _ = @import("cases/struct.zig");
...@@ -53,4 +54,5 @@ comptime {...@@ -53,4 +54,5 @@ comptime {
53 _ = @import("cases/var_args.zig");54 _ = @import("cases/var_args.zig");
54 _ = @import("cases/void.zig");55 _ = @import("cases/void.zig");
55 _ = @import("cases/while.zig");56 _ = @import("cases/while.zig");
57 _ = @import("cases/fn_in_struct_in_comptime.zig");
56}58}
test/cases/coroutines.zig+3-2
...@@ -219,8 +219,9 @@ async fn printTrace(p: promise->error!void) void {...@@ -219,8 +219,9 @@ async fn printTrace(p: promise->error!void) void {
219 std.debug.assert(e == error.Fail);219 std.debug.assert(e == error.Fail);
220 if (@errorReturnTrace()) |trace| {220 if (@errorReturnTrace()) |trace| {
221 assert(trace.index == 1);221 assert(trace.index == 1);
222 } else if (builtin.mode != builtin.Mode.ReleaseFast) {222 } else switch (builtin.mode) {
223 @panic("expected return trace");223 builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"),
224 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {},
224 }225 }
225 };226 };
226}227}
test/cases/enum.zig+9
...@@ -882,3 +882,12 @@ test "enum with 1 field but explicit tag type should still have the tag type" {...@@ -882,3 +882,12 @@ test "enum with 1 field but explicit tag type should still have the tag type" {
882 };882 };
883 comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));883 comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
884}884}
885
886test "empty extern enum with members" {
887 const E = extern enum {
888 A,
889 B,
890 C,
891 };
892 assert(@sizeOf(E) == @sizeOf(c_int));
893}
test/cases/fn_in_struct_in_comptime.zig created+17
...@@ -0,0 +1,17 @@
1const assert = @import("std").debug.assert;
2
3fn get_foo() fn(&u8)usize {
4 comptime {
5 return struct {
6 fn func(ptr: &u8) usize {
7 var u = @ptrToInt(ptr);
8 return u;
9 }
10 }.func;
11 }
12}
13
14test "define a function in an anonymous struct in comptime" {
15 const foo = get_foo();
16 assert(foo(@intToPtr(&u8, 12345)) == 12345);
17}
test/cases/math.zig+17
...@@ -335,6 +335,23 @@ test "big number shifting" {...@@ -335,6 +335,23 @@ test "big number shifting" {
335 }335 }
336}336}
337337
338test "big number multi-limb shift and mask" {
339 comptime {
340 var a = 0xefffffffa0000001eeeeeeefaaaaaaab;
341
342 assert(u32(a & 0xffffffff) == 0xaaaaaaab);
343 a >>= 32;
344 assert(u32(a & 0xffffffff) == 0xeeeeeeef);
345 a >>= 32;
346 assert(u32(a & 0xffffffff) == 0xa0000001);
347 a >>= 32;
348 assert(u32(a & 0xffffffff) == 0xefffffff);
349 a >>= 32;
350
351 assert(a == 0);
352 }
353}
354
338test "xor" {355test "xor" {
339 test_xor();356 test_xor();
340 comptime test_xor();357 comptime test_xor();
test/cases/type_info.zig created+200
...@@ -0,0 +1,200 @@
1const assert = @import("std").debug.assert;
2const mem = @import("std").mem;
3const TypeInfo = @import("builtin").TypeInfo;
4const TypeId = @import("builtin").TypeId;
5
6test "type info: tag type, void info" {
7 comptime {
8 assert(@TagType(TypeInfo) == TypeId);
9 const void_info = @typeInfo(void);
10 assert(TypeId(void_info) == TypeId.Void);
11 assert(void_info.Void == {});
12 }
13}
14
15test "type info: integer, floating point type info" {
16 comptime {
17 const u8_info = @typeInfo(u8);
18 assert(TypeId(u8_info) == TypeId.Int);
19 assert(!u8_info.Int.is_signed);
20 assert(u8_info.Int.bits == 8);
21
22 const f64_info = @typeInfo(f64);
23 assert(TypeId(f64_info) == TypeId.Float);
24 assert(f64_info.Float.bits == 64);
25 }
26}
27
28test "type info: pointer type info" {
29 comptime {
30 const u32_ptr_info = @typeInfo(&u32);
31 assert(TypeId(u32_ptr_info) == TypeId.Pointer);
32 assert(u32_ptr_info.Pointer.is_const == false);
33 assert(u32_ptr_info.Pointer.is_volatile == false);
34 assert(u32_ptr_info.Pointer.alignment == 4);
35 assert(u32_ptr_info.Pointer.child == u32);
36 }
37}
38
39test "type info: slice type info" {
40 comptime {
41 const u32_slice_info = @typeInfo([]u32);
42 assert(TypeId(u32_slice_info) == TypeId.Slice);
43 assert(u32_slice_info.Slice.is_const == false);
44 assert(u32_slice_info.Slice.is_volatile == false);
45 assert(u32_slice_info.Slice.alignment == 4);
46 assert(u32_slice_info.Slice.child == u32);
47 }
48}
49
50test "type info: array type info" {
51 comptime {
52 const arr_info = @typeInfo([42]bool);
53 assert(TypeId(arr_info) == TypeId.Array);
54 assert(arr_info.Array.len == 42);
55 assert(arr_info.Array.child == bool);
56 }
57}
58
59test "type info: nullable type info" {
60 comptime {
61 const null_info = @typeInfo(?void);
62 assert(TypeId(null_info) == TypeId.Nullable);
63 assert(null_info.Nullable.child == void);
64 }
65}
66
67test "type info: promise info" {
68 comptime {
69 const null_promise_info = @typeInfo(promise);
70 assert(TypeId(null_promise_info) == TypeId.Promise);
71 assert(null_promise_info.Promise.child == @typeOf(undefined));
72
73 const promise_info = @typeInfo(promise->usize);
74 assert(TypeId(promise_info) == TypeId.Promise);
75 assert(promise_info.Promise.child == usize);
76 }
77
78}
79
80test "type info: error set, error union info" {
81 comptime {
82 const TestErrorSet = error {
83 First,
84 Second,
85 Third,
86 };
87
88 const error_set_info = @typeInfo(TestErrorSet);
89 assert(TypeId(error_set_info) == TypeId.ErrorSet);
90 assert(error_set_info.ErrorSet.errors.len == 3);
91 assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
92 assert(error_set_info.ErrorSet.errors[2].value == usize(TestErrorSet.Third));
93
94 const error_union_info = @typeInfo(TestErrorSet!usize);
95 assert(TypeId(error_union_info) == TypeId.ErrorUnion);
96 assert(error_union_info.ErrorUnion.error_set == TestErrorSet);
97 assert(error_union_info.ErrorUnion.payload == usize);
98 }
99}
100
101test "type info: enum info" {
102 comptime {
103 const Os = @import("builtin").Os;
104
105 const os_info = @typeInfo(Os);
106 assert(TypeId(os_info) == TypeId.Enum);
107 assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
108 assert(os_info.Enum.fields.len == 32);
109 assert(mem.eql(u8, os_info.Enum.fields[1].name, "ananas"));
110 assert(os_info.Enum.fields[10].value == 10);
111 assert(os_info.Enum.tag_type == u5);
112 assert(os_info.Enum.defs.len == 0);
113 }
114}
115
116test "type info: union info" {
117 comptime {
118 const typeinfo_info = @typeInfo(TypeInfo);
119 assert(TypeId(typeinfo_info) == TypeId.Union);
120 assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
121 assert(typeinfo_info.Union.tag_type == TypeId);
122 assert(typeinfo_info.Union.fields.len == 26);
123 assert(typeinfo_info.Union.fields[4].enum_field != null);
124 assert((??typeinfo_info.Union.fields[4].enum_field).value == 4);
125 assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
126 assert(typeinfo_info.Union.defs.len == 21);
127
128 const TestNoTagUnion = union {
129 Foo: void,
130 Bar: u32,
131 };
132
133 const notag_union_info = @typeInfo(TestNoTagUnion);
134 assert(TypeId(notag_union_info) == TypeId.Union);
135 assert(notag_union_info.Union.tag_type == @typeOf(undefined));
136 assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
137 assert(notag_union_info.Union.fields.len == 2);
138 assert(notag_union_info.Union.fields[0].enum_field == null);
139 assert(notag_union_info.Union.fields[1].field_type == u32);
140
141 const TestExternUnion = extern union {
142 foo: &c_void,
143 };
144
145 const extern_union_info = @typeInfo(TestExternUnion);
146 assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
147 assert(extern_union_info.Union.tag_type == @typeOf(undefined));
148 assert(extern_union_info.Union.fields[0].enum_field == null);
149 assert(extern_union_info.Union.fields[0].field_type == &c_void);
150 }
151}
152
153test "type info: struct info" {
154 comptime {
155 const struct_info = @typeInfo(TestStruct);
156 assert(TypeId(struct_info) == TypeId.Struct);
157 assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
158 assert(struct_info.Struct.fields.len == 3);
159 assert(struct_info.Struct.fields[1].offset == null);
160 assert(struct_info.Struct.fields[2].field_type == &TestStruct);
161 assert(struct_info.Struct.defs.len == 2);
162 assert(struct_info.Struct.defs[0].is_pub);
163 assert(!struct_info.Struct.defs[0].data.Fn.is_extern);
164 assert(struct_info.Struct.defs[0].data.Fn.lib_name == null);
165 assert(struct_info.Struct.defs[0].data.Fn.return_type == void);
166 assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn(&const TestStruct)void);
167 }
168}
169
170const TestStruct = packed struct {
171 const Self = this;
172
173 fieldA: usize,
174 fieldB: void,
175 fieldC: &Self,
176
177 pub fn foo(self: &const Self) void {}
178};
179
180test "type info: function type info" {
181 comptime {
182 const fn_info = @typeInfo(@typeOf(foo));
183 assert(TypeId(fn_info) == TypeId.Fn);
184 assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
185 assert(fn_info.Fn.is_generic);
186 assert(fn_info.Fn.args.len == 2);
187 assert(fn_info.Fn.is_var_args);
188 assert(fn_info.Fn.return_type == @typeOf(undefined));
189 assert(fn_info.Fn.async_allocator_type == @typeOf(undefined));
190
191 const test_instance: TestStruct = undefined;
192 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
193 assert(TypeId(bound_fn_info) == TypeId.BoundFn);
194 assert(bound_fn_info.BoundFn.args[0].arg_type == &const TestStruct);
195 }
196}
197
198fn foo(comptime a: usize, b: bool, args: ...) usize {
199 return 0;
200}
test/cases/union.zig+23
...@@ -48,6 +48,16 @@ test "basic unions" {...@@ -48,6 +48,16 @@ test "basic unions" {
48 assert(foo.float == 12.34);48 assert(foo.float == 12.34);
49}49}
5050
51test "comptime union field access" {
52 comptime {
53 var foo = Foo { .int = 0 };
54 assert(foo.int == 0);
55
56 foo = Foo { .float = 42.42 };
57 assert(foo.float == 42.42);
58 }
59}
60
51test "init union with runtime value" {61test "init union with runtime value" {
52 var foo: Foo = undefined;62 var foo: Foo = undefined;
5363
...@@ -275,3 +285,16 @@ const PartialInst = union(enum) {...@@ -275,3 +285,16 @@ const PartialInst = union(enum) {
275const PartialInstWithPayload = union(enum) {285const PartialInstWithPayload = union(enum) {
276 Compiled: i32,286 Compiled: i32,
277};287};
288
289
290test "access a member of tagged union with conflicting enum tag name" {
291 const Bar = union(enum) {
292 A: A,
293 B: B,
294
295 const A = u8;
296 const B = void;
297 };
298
299 comptime assert(Bar.A == u8);
300}
test/compile_errors.zig+12-1
...@@ -3210,6 +3210,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -3210,6 +3210,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
3210 ,3210 ,
3211 ".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset");3211 ".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset");
32123212
3213 cases.add("invalid union field access in comptime",
3214 \\const Foo = union {
3215 \\ Bar: u8,
3216 \\ Baz: void,
3217 \\};
3218 \\comptime {
3219 \\ var foo = Foo {.Baz = {}};
3220 \\ const bar_val = foo.Bar;
3221 \\}
3222 ,
3223 ".tmp_source.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set");
3224
3213 cases.add("getting return type of generic function",3225 cases.add("getting return type of generic function",
3214 \\fn generic(a: var) void {}3226 \\fn generic(a: var) void {}
3215 \\comptime {3227 \\comptime {
...@@ -3225,5 +3237,4 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -3225,5 +3237,4 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
3225 \\}3237 \\}
3226 ,3238 ,
3227 ".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic");3239 ".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic");
3228
3229}3240}
test/tests.zig+4-4
...@@ -152,7 +152,7 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons...@@ -152,7 +152,7 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons
152 const step = b.step(b.fmt("test-{}", name), desc);152 const step = b.step(b.fmt("test-{}", name), desc);
153 for (test_targets) |test_target| {153 for (test_targets) |test_target| {
154 const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch);154 const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch);
155 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {155 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {
156 for ([]bool{false, true}) |link_libc| {156 for ([]bool{false, true}) |link_libc| {
157 if (link_libc and !is_native) {157 if (link_libc and !is_native) {
158 // don't assume we have a cross-compiling libc set up158 // don't assume we have a cross-compiling libc set up
...@@ -451,7 +451,7 @@ pub const CompareOutputContext = struct {...@@ -451,7 +451,7 @@ pub const CompareOutputContext = struct {
451 self.step.dependOn(&run_and_cmp_output.step);451 self.step.dependOn(&run_and_cmp_output.step);
452 },452 },
453 Special.None => {453 Special.None => {
454 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {454 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {
455 const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})",455 const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})",
456 "compare-output", case.name, @tagName(mode)) catch unreachable;456 "compare-output", case.name, @tagName(mode)) catch unreachable;
457 if (self.test_filter) |filter| {457 if (self.test_filter) |filter| {
...@@ -705,7 +705,7 @@ pub const CompileErrorContext = struct {...@@ -705,7 +705,7 @@ pub const CompileErrorContext = struct {
705 pub fn addCase(self: &CompileErrorContext, case: &const TestCase) void {705 pub fn addCase(self: &CompileErrorContext, case: &const TestCase) void {
706 const b = self.b;706 const b = self.b;
707707
708 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {708 for ([]Mode{Mode.Debug, Mode.ReleaseFast}) |mode| {
709 const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {} ({})",709 const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {} ({})",
710 case.name, @tagName(mode)) catch unreachable;710 case.name, @tagName(mode)) catch unreachable;
711 if (self.test_filter) |filter| {711 if (self.test_filter) |filter| {
...@@ -773,7 +773,7 @@ pub const BuildExamplesContext = struct {...@@ -773,7 +773,7 @@ pub const BuildExamplesContext = struct {
773 pub fn addAllArgs(self: &BuildExamplesContext, root_src: []const u8, link_libc: bool) void {773 pub fn addAllArgs(self: &BuildExamplesContext, root_src: []const u8, link_libc: bool) void {
774 const b = self.b;774 const b = self.b;
775775
776 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {776 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {
777 const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {} ({})",777 const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {} ({})",
778 root_src, @tagName(mode)) catch unreachable;778 root_src, @tagName(mode)) catch unreachable;
779 if (self.test_filter) |filter| {779 if (self.test_filter) |filter| {
test/translate_c.zig+43
...@@ -1,6 +1,27 @@...@@ -1,6 +1,27 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.TranslateCContext) void {3pub fn addCases(cases: &tests.TranslateCContext) void {
4 cases.add("double define struct",
5 \\typedef struct Bar Bar;
6 \\typedef struct Foo Foo;
7 \\
8 \\struct Foo {
9 \\ Foo *a;
10 \\};
11 \\
12 \\struct Bar {
13 \\ Foo *a;
14 \\};
15 ,
16 \\pub const struct_Foo = extern struct {
17 \\ a: ?&Foo,
18 \\};
19 \\pub const Foo = struct_Foo;
20 \\pub const struct_Bar = extern struct {
21 \\ a: ?&Foo,
22 \\};
23 );
24
4 cases.addAllowWarnings("simple data types",25 cases.addAllowWarnings("simple data types",
5 \\#include <stdint.h>26 \\#include <stdint.h>
6 \\int foo(char a, unsigned char b, signed char c);27 \\int foo(char a, unsigned char b, signed char c);
...@@ -53,6 +74,28 @@ pub fn addCases(cases: &tests.TranslateCContext) void {...@@ -53,6 +74,28 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
53 \\pub const Foo = enum_Foo;74 \\pub const Foo = enum_Foo;
54 );75 );
5576
77 cases.add("enums",
78 \\enum Foo {
79 \\ FooA = 2,
80 \\ FooB = 5,
81 \\ Foo1,
82 \\};
83 ,
84 \\pub const enum_Foo = extern enum {
85 \\ A = 2,
86 \\ B = 5,
87 \\ @"1" = 6,
88 \\};
89 ,
90 \\pub const FooA = enum_Foo.A;
91 ,
92 \\pub const FooB = enum_Foo.B;
93 ,
94 \\pub const Foo1 = enum_Foo.@"1";
95 ,
96 \\pub const Foo = enum_Foo;
97 );
98
56 cases.add("restrict -> noalias",99 cases.add("restrict -> noalias",
57 \\void foo(void *restrict bar, void *restrict);100 \\void foo(void *restrict bar, void *restrict);
58 ,101 ,