| author | |
| committer | |
| log | 7e37d268c86ccc823c4a381a42029722d36c3975 |
| tree | 1600a184f03fedd91131bcbaea2c5ee85dfa06a3 |
| parent | 6309121f70ff88cf64267f2bf1d9e452090ca277 |
| parent | ef3111be236fc389a696562d31bccd3a9b6d1c56 |
41 files changed, 5282 insertions(+), 129 deletions(-)
CMakeLists.txt+1| ... | @@ -454,6 +454,7 @@ set(ZIG_STD_FILES | ... | @@ -454,6 +454,7 @@ set(ZIG_STD_FILES |
| 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" |
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#} | ||
| 4821 | pub 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 | }; |
| 5242 | 5418 | ||
| 5243 | pub const Arch = enum { | 5419 | pub 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 { |
| 5315 | pub const Environ = enum { | 5512 | pub 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 | }; |
| 5336 | 5535 | ||
| 5337 | pub const ObjectFormat = enum { | 5536 | pub 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 | }; |
| 5360 | 5559 | ||
| 5560 | pub const AtomicRmwOp = enum { | ||
| 5561 | Xchg, | ||
| 5562 | Add, | ||
| 5563 | Sub, | ||
| 5564 | And, | ||
| 5565 | Nand, | ||
| 5566 | Or, | ||
| 5567 | Xor, | ||
| 5568 | Max, | ||
| 5569 | Min, | ||
| 5570 | }; | ||
| 5571 | |||
| 5361 | pub const Mode = enum { | 5572 | pub const Mode = enum { |
| 5362 | Debug, | 5573 | Debug, |
| 5363 | ReleaseSafe, | 5574 | ReleaseSafe, |
| 5364 | ReleaseFast, | 5575 | ReleaseFast, |
| 5576 | ReleaseSmall, | ||
| 5365 | }; | 5577 | }; |
| 5366 | 5578 | ||
| 5367 | pub const TypeId = enum { | 5579 | pub 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 | |||
| 5607 | pub 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 | }; |
| 5393 | 5775 | ||
| 5394 | pub const FloatMode = enum { | 5776 | pub const FloatMode = enum { |
| ... | @@ -5402,7 +5784,7 @@ pub const Endian = enum { | ... | @@ -5402,7 +5784,7 @@ pub const Endian = enum { |
| 5402 | }; | 5784 | }; |
| 5403 | 5785 | ||
| 5404 | pub const endian = Endian.Little; | 5786 | pub const endian = Endian.Little; |
| 5405 | pub const is_test = false; | 5787 | pub const is_test = true; |
| 5406 | pub const os = Os.linux; | 5788 | pub const os = Os.linux; |
| 5407 | pub const arch = Arch.x86_64; | 5789 | pub const arch = Arch.x86_64; |
| 5408 | pub const environ = Environ.gnu; | 5790 | pub const environ = Environ.gnu; |
| ... | @@ -5410,6 +5792,7 @@ pub const object_format = ObjectFormat.elf; | ... | @@ -5410,6 +5792,7 @@ pub const object_format = ObjectFormat.elf; |
| 5410 | pub const mode = Mode.Debug; | 5792 | pub const mode = Mode.Debug; |
| 5411 | pub const link_libc = false; | 5793 | pub const link_libc = false; |
| 5412 | pub const have_error_return_tracing = true; | 5794 | pub const have_error_return_tracing = true; |
| 5795 | pub 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#} |
| ... | @@ -6068,7 +6451,7 @@ hljs.registerLanguage("zig", function(t) { | ... | @@ -6068,7 +6451,7 @@ hljs.registerLanguage("zig", function(t) { |
| 6068 | a = t.IR + "\\s*\\(", | 6451 | a = t.IR + "\\s*\\(", |
| 6069 | c = { | 6452 | c = { |
| 6070 | 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", | 6453 | 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", |
| 6071 | 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", | 6454 | 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", |
| 6072 | literal: "true false null undefined" | 6455 | literal: "true false null undefined" |
| 6073 | }, | 6456 | }, |
| 6074 | n = [e, t.CLCM, t.CBCM, s, r]; | 6457 | n = [e, t.CLCM, t.CBCM, s, r]; |
src/all_types.hpp+9| ... | @@ -1293,6 +1293,7 @@ enum BuiltinFnId { | ... | @@ -1293,6 +1293,7 @@ enum BuiltinFnId { |
| 1293 | BuiltinFnIdMemberType, | 1293 | BuiltinFnIdMemberType, |
| 1294 | BuiltinFnIdMemberName, | 1294 | BuiltinFnIdMemberName, |
| 1295 | BuiltinFnIdField, | 1295 | BuiltinFnIdField, |
| 1296 | BuiltinFnIdTypeInfo, | ||
| 1296 | BuiltinFnIdTypeof, | 1297 | BuiltinFnIdTypeof, |
| 1297 | BuiltinFnIdAddWithOverflow, | 1298 | BuiltinFnIdAddWithOverflow, |
| 1298 | BuiltinFnIdSubWithOverflow, | 1299 | BuiltinFnIdSubWithOverflow, |
| ... | @@ -1506,6 +1507,7 @@ struct CodeGen { | ... | @@ -1506,6 +1507,7 @@ struct CodeGen { |
| 1506 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names; | 1507 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names; |
| 1507 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; | 1508 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; |
| 1508 | HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table; | 1509 | HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table; |
| 1510 | HashMap<const TypeTableEntry *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache; | ||
| 1509 | 1511 | ||
| 1510 | 1512 | ||
| 1511 | ZigList<ImportTableEntry *> import_queue; | 1513 | ZigList<ImportTableEntry *> import_queue; |
| ... | @@ -2035,6 +2037,7 @@ enum IrInstructionId { | ... | @@ -2035,6 +2037,7 @@ enum IrInstructionId { |
| 2035 | IrInstructionIdTagType, | 2037 | IrInstructionIdTagType, |
| 2036 | IrInstructionIdFieldParentPtr, | 2038 | IrInstructionIdFieldParentPtr, |
| 2037 | IrInstructionIdOffsetOf, | 2039 | IrInstructionIdOffsetOf, |
| 2040 | IrInstructionIdTypeInfo, | ||
| 2038 | IrInstructionIdTypeId, | 2041 | IrInstructionIdTypeId, |
| 2039 | IrInstructionIdSetEvalBranchQuota, | 2042 | IrInstructionIdSetEvalBranchQuota, |
| 2040 | IrInstructionIdPtrTypeOf, | 2043 | IrInstructionIdPtrTypeOf, |
| ... | @@ -2856,6 +2859,12 @@ struct IrInstructionOffsetOf { | ... | @@ -2856,6 +2859,12 @@ struct IrInstructionOffsetOf { |
| 2856 | IrInstruction *field_name; | 2859 | IrInstruction *field_name; |
| 2857 | }; | 2860 | }; |
| 2858 | 2861 | ||
| 2862 | struct IrInstructionTypeInfo { | ||
| 2863 | IrInstruction base; | ||
| 2864 | |||
| 2865 | IrInstruction *type_value; | ||
| 2866 | }; | ||
| 2867 | |||
| 2859 | struct IrInstructionTypeId { | 2868 | struct IrInstructionTypeId { |
| 2860 | IrInstruction base; | 2869 | IrInstruction base; |
| 2861 | 2870 |
src/analyze.cpp+7-1| ... | @@ -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); |
| 2327 | 2327 | ||
| 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 | } | ||
| 2329 | 2334 | ||
| 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)) { |
src/ast_render.cpp+1-1| ... | @@ -728,7 +728,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -728,7 +728,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 728 | render_node_grouped(ar, field_node->data.struct_field.type); | 728 | render_node_grouped(ar, field_node->data.struct_field.type); |
| 729 | } | 729 | } |
| 730 | if (field_node->data.struct_field.value != nullptr) { | 730 | if (field_node->data.struct_field.value != nullptr) { |
| 731 | fprintf(ar->f, "= "); | 731 | fprintf(ar->f, " = "); |
| 732 | render_node_grouped(ar, field_node->data.struct_field.value); | 732 | render_node_grouped(ar, field_node->data.struct_field.value); |
| 733 | } | 733 | } |
| 734 | fprintf(ar->f, ",\n"); | 734 | fprintf(ar->f, ",\n"); |
src/codegen.cpp+187| ... | @@ -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); |
| ... | @@ -4417,6 +4418,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -4417,6 +4418,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4417 | case IrInstructionIdDeclRef: | 4418 | case IrInstructionIdDeclRef: |
| 4418 | case IrInstructionIdSwitchVar: | 4419 | case IrInstructionIdSwitchVar: |
| 4419 | case IrInstructionIdOffsetOf: | 4420 | case IrInstructionIdOffsetOf: |
| 4421 | case IrInstructionIdTypeInfo: | ||
| 4420 | case IrInstructionIdTypeId: | 4422 | case IrInstructionIdTypeId: |
| 4421 | case IrInstructionIdSetEvalBranchQuota: | 4423 | case IrInstructionIdSetEvalBranchQuota: |
| 4422 | case IrInstructionIdPtrTypeOf: | 4424 | case IrInstructionIdPtrTypeOf: |
| ... | @@ -6040,6 +6042,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -6040,6 +6042,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 6040 | create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2); | 6042 | create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2); |
| 6041 | create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2); | 6043 | create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2); |
| 6042 | create_builtin_fn(g, BuiltinFnIdField, "field", 2); | 6044 | create_builtin_fn(g, BuiltinFnIdField, "field", 2); |
| 6045 | create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1); | ||
| 6043 | create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf | 6046 | create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf |
| 6044 | create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4); | 6047 | create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4); |
| 6045 | create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4); | 6048 | create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4); |
| ... | @@ -6259,6 +6262,190 @@ static void define_builtin_compile_vars(CodeGen *g) { | ... | @@ -6259,6 +6262,190 @@ static void define_builtin_compile_vars(CodeGen *g) { |
| 6259 | } | 6262 | } |
| 6260 | buf_appendf(contents, "};\n\n"); | 6263 | buf_appendf(contents, "};\n\n"); |
| 6261 | } | 6264 | } |
| 6265 | { | ||
| 6266 | buf_appendf(contents, | ||
| 6267 | "pub const TypeInfo = union(TypeId) {\n" | ||
| 6268 | " Type: void,\n" | ||
| 6269 | " Void: void,\n" | ||
| 6270 | " Bool: void,\n" | ||
| 6271 | " NoReturn: void,\n" | ||
| 6272 | " Int: Int,\n" | ||
| 6273 | " Float: Float,\n" | ||
| 6274 | " Pointer: Pointer,\n" | ||
| 6275 | " Array: Array,\n" | ||
| 6276 | " Struct: Struct,\n" | ||
| 6277 | " FloatLiteral: void,\n" | ||
| 6278 | " IntLiteral: void,\n" | ||
| 6279 | " UndefinedLiteral: void,\n" | ||
| 6280 | " NullLiteral: void,\n" | ||
| 6281 | " Nullable: Nullable,\n" | ||
| 6282 | " ErrorUnion: ErrorUnion,\n" | ||
| 6283 | " ErrorSet: ErrorSet,\n" | ||
| 6284 | " Enum: Enum,\n" | ||
| 6285 | " Union: Union,\n" | ||
| 6286 | " Fn: Fn,\n" | ||
| 6287 | " Namespace: void,\n" | ||
| 6288 | " Block: void,\n" | ||
| 6289 | " BoundFn: Fn,\n" | ||
| 6290 | " ArgTuple: void,\n" | ||
| 6291 | " Opaque: void,\n" | ||
| 6292 | " Promise: Promise,\n" | ||
| 6293 | "\n\n" | ||
| 6294 | " pub const Int = struct {\n" | ||
| 6295 | " is_signed: bool,\n" | ||
| 6296 | " bits: u8,\n" | ||
| 6297 | " };\n" | ||
| 6298 | "\n" | ||
| 6299 | " pub const Float = struct {\n" | ||
| 6300 | " bits: u8,\n" | ||
| 6301 | " };\n" | ||
| 6302 | "\n" | ||
| 6303 | " pub const Pointer = struct {\n" | ||
| 6304 | " is_const: bool,\n" | ||
| 6305 | " is_volatile: bool,\n" | ||
| 6306 | " alignment: u32,\n" | ||
| 6307 | " child: type,\n" | ||
| 6308 | " };\n" | ||
| 6309 | "\n" | ||
| 6310 | " pub const Array = struct {\n" | ||
| 6311 | " len: usize,\n" | ||
| 6312 | " child: type,\n" | ||
| 6313 | " };\n" | ||
| 6314 | "\n" | ||
| 6315 | " pub const ContainerLayout = enum {\n" | ||
| 6316 | " Auto,\n" | ||
| 6317 | " Extern,\n" | ||
| 6318 | " Packed,\n" | ||
| 6319 | " };\n" | ||
| 6320 | "\n" | ||
| 6321 | " pub const StructField = struct {\n" | ||
| 6322 | " name: []const u8,\n" | ||
| 6323 | " offset: ?usize,\n" | ||
| 6324 | " field_type: type,\n" | ||
| 6325 | " };\n" | ||
| 6326 | "\n" | ||
| 6327 | " pub const Struct = struct {\n" | ||
| 6328 | " layout: ContainerLayout,\n" | ||
| 6329 | " fields: []StructField,\n" | ||
| 6330 | " defs: []Definition,\n" | ||
| 6331 | " };\n" | ||
| 6332 | "\n" | ||
| 6333 | " pub const Nullable = struct {\n" | ||
| 6334 | " child: type,\n" | ||
| 6335 | " };\n" | ||
| 6336 | "\n" | ||
| 6337 | " pub const ErrorUnion = struct {\n" | ||
| 6338 | " error_set: type,\n" | ||
| 6339 | " payload: type,\n" | ||
| 6340 | " };\n" | ||
| 6341 | "\n" | ||
| 6342 | " pub const Error = struct {\n" | ||
| 6343 | " name: []const u8,\n" | ||
| 6344 | " value: usize,\n" | ||
| 6345 | " };\n" | ||
| 6346 | "\n" | ||
| 6347 | " pub const ErrorSet = struct {\n" | ||
| 6348 | " errors: []Error,\n" | ||
| 6349 | " };\n" | ||
| 6350 | "\n" | ||
| 6351 | " pub const EnumField = struct {\n" | ||
| 6352 | " name: []const u8,\n" | ||
| 6353 | " value: usize,\n" | ||
| 6354 | " };\n" | ||
| 6355 | "\n" | ||
| 6356 | " pub const Enum = struct {\n" | ||
| 6357 | " layout: ContainerLayout,\n" | ||
| 6358 | " tag_type: type,\n" | ||
| 6359 | " fields: []EnumField,\n" | ||
| 6360 | " defs: []Definition,\n" | ||
| 6361 | " };\n" | ||
| 6362 | "\n" | ||
| 6363 | " pub const UnionField = struct {\n" | ||
| 6364 | " name: []const u8,\n" | ||
| 6365 | " enum_field: ?EnumField,\n" | ||
| 6366 | " field_type: type,\n" | ||
| 6367 | " };\n" | ||
| 6368 | "\n" | ||
| 6369 | " pub const Union = struct {\n" | ||
| 6370 | " layout: ContainerLayout,\n" | ||
| 6371 | " tag_type: type,\n" | ||
| 6372 | " fields: []UnionField,\n" | ||
| 6373 | " defs: []Definition,\n" | ||
| 6374 | " };\n" | ||
| 6375 | "\n" | ||
| 6376 | " pub const CallingConvention = enum {\n" | ||
| 6377 | " Unspecified,\n" | ||
| 6378 | " C,\n" | ||
| 6379 | " Cold,\n" | ||
| 6380 | " Naked,\n" | ||
| 6381 | " Stdcall,\n" | ||
| 6382 | " Async,\n" | ||
| 6383 | " };\n" | ||
| 6384 | "\n" | ||
| 6385 | " pub const FnArg = struct {\n" | ||
| 6386 | " is_generic: bool,\n" | ||
| 6387 | " is_noalias: bool,\n" | ||
| 6388 | " arg_type: type,\n" | ||
| 6389 | " };\n" | ||
| 6390 | "\n" | ||
| 6391 | " pub const Fn = struct {\n" | ||
| 6392 | " calling_convention: CallingConvention,\n" | ||
| 6393 | " is_generic: bool,\n" | ||
| 6394 | " is_var_args: bool,\n" | ||
| 6395 | " return_type: type,\n" | ||
| 6396 | " async_allocator_type: type,\n" | ||
| 6397 | " args: []FnArg,\n" | ||
| 6398 | " };\n" | ||
| 6399 | "\n" | ||
| 6400 | " pub const Promise = struct {\n" | ||
| 6401 | " child: type,\n" | ||
| 6402 | " };\n" | ||
| 6403 | "\n" | ||
| 6404 | " pub const Definition = struct {\n" | ||
| 6405 | " name: []const u8,\n" | ||
| 6406 | " is_pub: bool,\n" | ||
| 6407 | " data: Data,\n" | ||
| 6408 | "\n" | ||
| 6409 | " pub const Data = union(enum) {\n" | ||
| 6410 | " Type: type,\n" | ||
| 6411 | " Var: type,\n" | ||
| 6412 | " Fn: FnDef,\n" | ||
| 6413 | "\n" | ||
| 6414 | " pub const FnDef = struct {\n" | ||
| 6415 | " fn_type: type,\n" | ||
| 6416 | " inline_type: Inline,\n" | ||
| 6417 | " calling_convention: CallingConvention,\n" | ||
| 6418 | " is_var_args: bool,\n" | ||
| 6419 | " is_extern: bool,\n" | ||
| 6420 | " is_export: bool,\n" | ||
| 6421 | " lib_name: ?[]const u8,\n" | ||
| 6422 | " return_type: type,\n" | ||
| 6423 | " arg_names: [][] const u8,\n" | ||
| 6424 | "\n" | ||
| 6425 | " pub const Inline = enum {\n" | ||
| 6426 | " Auto,\n" | ||
| 6427 | " Always,\n" | ||
| 6428 | " Never,\n" | ||
| 6429 | " };\n" | ||
| 6430 | " };\n" | ||
| 6431 | " };\n" | ||
| 6432 | " };\n" | ||
| 6433 | "};\n\n"); | ||
| 6434 | assert(ContainerLayoutAuto == 0); | ||
| 6435 | assert(ContainerLayoutExtern == 1); | ||
| 6436 | assert(ContainerLayoutPacked == 2); | ||
| 6437 | |||
| 6438 | assert(CallingConventionUnspecified == 0); | ||
| 6439 | assert(CallingConventionC == 1); | ||
| 6440 | assert(CallingConventionCold == 2); | ||
| 6441 | assert(CallingConventionNaked == 3); | ||
| 6442 | assert(CallingConventionStdcall == 4); | ||
| 6443 | assert(CallingConventionAsync == 5); | ||
| 6444 | |||
| 6445 | assert(FnInlineAuto == 0); | ||
| 6446 | assert(FnInlineAlways == 1); | ||
| 6447 | assert(FnInlineNever == 2); | ||
| 6448 | } | ||
| 6262 | { | 6449 | { |
| 6263 | buf_appendf(contents, | 6450 | buf_appendf(contents, |
| 6264 | "pub const FloatMode = enum {\n" | 6451 | "pub const FloatMode = enum {\n" |
src/ir.cpp+963-1| ... | @@ -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 | } |
| 617 | 619 | ||
| 620 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) { | ||
| 621 | return IrInstructionIdTypeInfo; | ||
| 622 | } | ||
| 623 | |||
| 618 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeId *) { | 624 | static 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 | } |
| 2442 | 2448 | ||
| 2449 | static 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 | |||
| 2443 | static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node, | 2459 | static 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 |
| 4083 | 4099 | ||
| 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: |
| ... | @@ -13386,7 +13412,6 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, | ... | @@ -13386,7 +13412,6 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 13386 | return ira->codegen->invalid_instruction; | 13412 | return ira->codegen->invalid_instruction; |
| 13387 | } | 13413 | } |
| 13388 | 13414 | ||
| 13389 | |||
| 13390 | static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, | 13415 | static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, |
| 13391 | IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type) | 13416 | IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type) |
| 13392 | { | 13417 | { |
| ... | @@ -13448,6 +13473,51 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ | ... | @@ -13448,6 +13473,51 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ |
| 13448 | } else if (bare_type->id == TypeTableEntryIdUnion) { | 13473 | } else if (bare_type->id == TypeTableEntryIdUnion) { |
| 13449 | TypeUnionField *field = find_union_type_field(bare_type, field_name); | 13474 | TypeUnionField *field = find_union_type_field(bare_type, field_name); |
| 13450 | if (field) { | 13475 | if (field) { |
| 13476 | if (instr_is_comptime(container_ptr)) { | ||
| 13477 | ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); | ||
| 13478 | if (!ptr_val) | ||
| 13479 | return ira->codegen->invalid_instruction; | ||
| 13480 | |||
| 13481 | if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { | ||
| 13482 | ConstExprValue *union_val = const_ptr_pointee(ira->codegen, ptr_val); | ||
| 13483 | if (type_is_invalid(union_val->type)) | ||
| 13484 | return ira->codegen->invalid_instruction; | ||
| 13485 | |||
| 13486 | TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag); | ||
| 13487 | if (actual_field == nullptr) | ||
| 13488 | zig_unreachable(); | ||
| 13489 | |||
| 13490 | if (field != actual_field) { | ||
| 13491 | ir_add_error_node(ira, source_instr->source_node, | ||
| 13492 | buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name), | ||
| 13493 | buf_ptr(actual_field->name))); | ||
| 13494 | return ira->codegen->invalid_instruction; | ||
| 13495 | } | ||
| 13496 | |||
| 13497 | ConstExprValue *payload_val = union_val->data.x_union.payload; | ||
| 13498 | |||
| 13499 | TypeTableEntry *field_type = field->type_entry; | ||
| 13500 | if (field_type->id == TypeTableEntryIdVoid) | ||
| 13501 | { | ||
| 13502 | assert(payload_val == nullptr); | ||
| 13503 | payload_val = create_const_vals(1); | ||
| 13504 | payload_val->special = ConstValSpecialStatic; | ||
| 13505 | payload_val->type = field_type; | ||
| 13506 | } | ||
| 13507 | |||
| 13508 | TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, is_const, is_volatile, | ||
| 13509 | get_abi_alignment(ira->codegen, field_type), 0, 0); | ||
| 13510 | |||
| 13511 | IrInstruction *result = ir_get_const(ira, source_instr); | ||
| 13512 | ConstExprValue *const_val = &result->value; | ||
| 13513 | const_val->data.x_ptr.special = ConstPtrSpecialRef; | ||
| 13514 | const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut; | ||
| 13515 | const_val->data.x_ptr.data.ref.pointee = payload_val; | ||
| 13516 | const_val->type = ptr_type; | ||
| 13517 | return result; | ||
| 13518 | } | ||
| 13519 | } | ||
| 13520 | |||
| 13451 | IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field); | 13521 | IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field); |
| 13452 | result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, | 13522 | result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, |
| 13453 | get_abi_alignment(ira->codegen, field->type_entry), 0, 0); | 13523 | get_abi_alignment(ira->codegen, field->type_entry), 0, 0); |
| ... | @@ -15677,6 +15747,895 @@ static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira, | ... | @@ -15677,6 +15747,895 @@ static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira, |
| 15677 | return ira->codegen->builtin_types.entry_num_lit_int; | 15747 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 15678 | } | 15748 | } |
| 15679 | 15749 | ||
| 15750 | static void ensure_field_index(TypeTableEntry *type, const char *field_name, size_t index) | ||
| 15751 | { | ||
| 15752 | Buf *field_name_buf; | ||
| 15753 | |||
| 15754 | assert(type != nullptr && !type_is_invalid(type)); | ||
| 15755 | // Check for our field by creating a buffer in place then using the comma operator to free it so that we don't | ||
| 15756 | // leak memory in debug mode. | ||
| 15757 | assert(find_struct_type_field(type, field_name_buf = buf_create_from_str(field_name))->src_index == index && | ||
| 15758 | (buf_deinit(field_name_buf), true)); | ||
| 15759 | } | ||
| 15760 | |||
| 15761 | static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, TypeTableEntry *root = nullptr) | ||
| 15762 | { | ||
| 15763 | static ConstExprValue *type_info_var = nullptr; | ||
| 15764 | static TypeTableEntry *type_info_type = nullptr; | ||
| 15765 | if (type_info_var == nullptr) | ||
| 15766 | { | ||
| 15767 | type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); | ||
| 15768 | assert(type_info_var->type->id == TypeTableEntryIdMetaType); | ||
| 15769 | |||
| 15770 | ensure_complete_type(ira->codegen, type_info_var->data.x_type); | ||
| 15771 | type_info_type = type_info_var->data.x_type; | ||
| 15772 | assert(type_info_type->id == TypeTableEntryIdUnion); | ||
| 15773 | } | ||
| 15774 | |||
| 15775 | if (type_name == nullptr && root == nullptr) | ||
| 15776 | return type_info_type; | ||
| 15777 | else if (type_name == nullptr) | ||
| 15778 | return root; | ||
| 15779 | |||
| 15780 | TypeTableEntry *root_type = (root == nullptr) ? type_info_type : root; | ||
| 15781 | |||
| 15782 | ScopeDecls *type_info_scope = get_container_scope(root_type); | ||
| 15783 | assert(type_info_scope != nullptr); | ||
| 15784 | |||
| 15785 | Buf field_name = BUF_INIT; | ||
| 15786 | buf_init_from_str(&field_name, type_name); | ||
| 15787 | auto entry = type_info_scope->decl_table.maybe_get(&field_name); | ||
| 15788 | buf_deinit(&field_name); | ||
| 15789 | assert(entry != nullptr); | ||
| 15790 | |||
| 15791 | TldVar *tld = (TldVar *)entry->value; | ||
| 15792 | assert(tld->base.id == TldIdVar); | ||
| 15793 | |||
| 15794 | VariableTableEntry *var = tld->var; | ||
| 15795 | |||
| 15796 | ensure_complete_type(ira->codegen, var->value->type); | ||
| 15797 | assert(var->value->type->id == TypeTableEntryIdMetaType); | ||
| 15798 | return var->value->data.x_type; | ||
| 15799 | } | ||
| 15800 | |||
| 15801 | static void ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) | ||
| 15802 | { | ||
| 15803 | TypeTableEntry *type_info_definition_type = ir_type_info_get_type(ira, "Definition"); | ||
| 15804 | ensure_complete_type(ira->codegen, type_info_definition_type); | ||
| 15805 | ensure_field_index(type_info_definition_type, "name", 0); | ||
| 15806 | ensure_field_index(type_info_definition_type, "is_pub", 1); | ||
| 15807 | ensure_field_index(type_info_definition_type, "data", 2); | ||
| 15808 | |||
| 15809 | TypeTableEntry *type_info_definition_data_type = ir_type_info_get_type(ira, "Data", type_info_definition_type); | ||
| 15810 | ensure_complete_type(ira->codegen, type_info_definition_data_type); | ||
| 15811 | |||
| 15812 | TypeTableEntry *type_info_fn_def_type = ir_type_info_get_type(ira, "FnDef", type_info_definition_data_type); | ||
| 15813 | ensure_complete_type(ira->codegen, type_info_fn_def_type); | ||
| 15814 | |||
| 15815 | TypeTableEntry *type_info_fn_def_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_def_type); | ||
| 15816 | ensure_complete_type(ira->codegen, type_info_fn_def_inline_type); | ||
| 15817 | |||
| 15818 | // Loop through our definitions once to figure out how many definitions we will generate info for. | ||
| 15819 | auto decl_it = decls_scope->decl_table.entry_iterator(); | ||
| 15820 | decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr; | ||
| 15821 | int definition_count = 0; | ||
| 15822 | |||
| 15823 | while ((curr_entry = decl_it.next()) != nullptr) | ||
| 15824 | { | ||
| 15825 | // If the definition is unresolved, force it to be resolved again. | ||
| 15826 | if (curr_entry->value->resolution == TldResolutionUnresolved) | ||
| 15827 | { | ||
| 15828 | resolve_top_level_decl(ira->codegen, curr_entry->value, false, curr_entry->value->source_node); | ||
| 15829 | if (curr_entry->value->resolution != TldResolutionOk) | ||
| 15830 | { | ||
| 15831 | return; | ||
| 15832 | } | ||
| 15833 | } | ||
| 15834 | |||
| 15835 | // Skip comptime blocks and test functions. | ||
| 15836 | if (curr_entry->value->id != TldIdCompTime) | ||
| 15837 | { | ||
| 15838 | if (curr_entry->value->id == TldIdFn) | ||
| 15839 | { | ||
| 15840 | FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry; | ||
| 15841 | if (fn_entry->is_test) | ||
| 15842 | continue; | ||
| 15843 | } | ||
| 15844 | |||
| 15845 | definition_count += 1; | ||
| 15846 | } | ||
| 15847 | } | ||
| 15848 | |||
| 15849 | ConstExprValue *definition_array = create_const_vals(1); | ||
| 15850 | definition_array->special = ConstValSpecialStatic; | ||
| 15851 | definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count); | ||
| 15852 | definition_array->data.x_array.special = ConstArraySpecialNone; | ||
| 15853 | definition_array->data.x_array.s_none.parent.id = ConstParentIdNone; | ||
| 15854 | definition_array->data.x_array.s_none.elements = create_const_vals(definition_count); | ||
| 15855 | init_const_slice(ira->codegen, out_val, definition_array, 0, definition_count, false); | ||
| 15856 | |||
| 15857 | // Loop through the definitions and generate info. | ||
| 15858 | decl_it = decls_scope->decl_table.entry_iterator(); | ||
| 15859 | curr_entry = nullptr; | ||
| 15860 | int definition_index = 0; | ||
| 15861 | while ((curr_entry = decl_it.next()) != nullptr) | ||
| 15862 | { | ||
| 15863 | // Skip comptime blocks and test functions. | ||
| 15864 | if (curr_entry->value->id == TldIdCompTime) | ||
| 15865 | continue; | ||
| 15866 | else if (curr_entry->value->id == TldIdFn) | ||
| 15867 | { | ||
| 15868 | FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry; | ||
| 15869 | if (fn_entry->is_test) | ||
| 15870 | continue; | ||
| 15871 | } | ||
| 15872 | |||
| 15873 | ConstExprValue *definition_val = &definition_array->data.x_array.s_none.elements[definition_index]; | ||
| 15874 | |||
| 15875 | definition_val->special = ConstValSpecialStatic; | ||
| 15876 | definition_val->type = type_info_definition_type; | ||
| 15877 | |||
| 15878 | ConstExprValue *inner_fields = create_const_vals(3); | ||
| 15879 | ConstExprValue *name = create_const_str_lit(ira->codegen, curr_entry->key); | ||
| 15880 | init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(curr_entry->key), true); | ||
| 15881 | inner_fields[1].special = ConstValSpecialStatic; | ||
| 15882 | inner_fields[1].type = ira->codegen->builtin_types.entry_bool; | ||
| 15883 | inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub; | ||
| 15884 | inner_fields[2].special = ConstValSpecialStatic; | ||
| 15885 | inner_fields[2].type = type_info_definition_data_type; | ||
| 15886 | inner_fields[2].data.x_union.parent.id = ConstParentIdStruct; | ||
| 15887 | inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val; | ||
| 15888 | inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1; | ||
| 15889 | |||
| 15890 | switch (curr_entry->value->id) | ||
| 15891 | { | ||
| 15892 | case TldIdVar: | ||
| 15893 | { | ||
| 15894 | VariableTableEntry *var = ((TldVar *)curr_entry->value)->var; | ||
| 15895 | ensure_complete_type(ira->codegen, var->value->type); | ||
| 15896 | if (var->value->type->id == TypeTableEntryIdMetaType) | ||
| 15897 | { | ||
| 15898 | // We have a variable of type 'type', so it's actually a type definition. | ||
| 15899 | // 0: Data.Type: type | ||
| 15900 | bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0); | ||
| 15901 | inner_fields[2].data.x_union.payload = var->value; | ||
| 15902 | } | ||
| 15903 | else | ||
| 15904 | { | ||
| 15905 | // We have a variable of another type, so we store the type of the variable. | ||
| 15906 | // 1: Data.Var: type | ||
| 15907 | bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 1); | ||
| 15908 | |||
| 15909 | ConstExprValue *payload = create_const_vals(1); | ||
| 15910 | payload->type = ira->codegen->builtin_types.entry_type; | ||
| 15911 | payload->data.x_type = var->value->type; | ||
| 15912 | |||
| 15913 | inner_fields[2].data.x_union.payload = payload; | ||
| 15914 | } | ||
| 15915 | |||
| 15916 | break; | ||
| 15917 | } | ||
| 15918 | case TldIdFn: | ||
| 15919 | { | ||
| 15920 | // 2: Data.Fn: Data.FnDef | ||
| 15921 | bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 2); | ||
| 15922 | |||
| 15923 | FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry; | ||
| 15924 | assert(!fn_entry->is_test); | ||
| 15925 | |||
| 15926 | analyze_fn_body(ira->codegen, fn_entry); | ||
| 15927 | if (fn_entry->anal_state == FnAnalStateInvalid) | ||
| 15928 | return; | ||
| 15929 | |||
| 15930 | AstNodeFnProto *fn_node = (AstNodeFnProto *)(fn_entry->proto_node); | ||
| 15931 | |||
| 15932 | ConstExprValue *fn_def_val = create_const_vals(1); | ||
| 15933 | fn_def_val->special = ConstValSpecialStatic; | ||
| 15934 | fn_def_val->type = type_info_fn_def_type; | ||
| 15935 | fn_def_val->data.x_struct.parent.id = ConstParentIdUnion; | ||
| 15936 | fn_def_val->data.x_struct.parent.data.p_union.union_val = &inner_fields[2]; | ||
| 15937 | |||
| 15938 | ConstExprValue *fn_def_fields = create_const_vals(9); | ||
| 15939 | fn_def_val->data.x_struct.fields = fn_def_fields; | ||
| 15940 | |||
| 15941 | // fn_type: type | ||
| 15942 | ensure_field_index(fn_def_val->type, "fn_type", 0); | ||
| 15943 | fn_def_fields[0].special = ConstValSpecialStatic; | ||
| 15944 | fn_def_fields[0].type = ira->codegen->builtin_types.entry_type; | ||
| 15945 | fn_def_fields[0].data.x_type = fn_entry->type_entry; | ||
| 15946 | // inline_type: Data.FnDef.Inline | ||
| 15947 | ensure_field_index(fn_def_val->type, "inline_type", 1); | ||
| 15948 | fn_def_fields[1].special = ConstValSpecialStatic; | ||
| 15949 | fn_def_fields[1].type = type_info_fn_def_inline_type; | ||
| 15950 | bigint_init_unsigned(&fn_def_fields[1].data.x_enum_tag, fn_entry->fn_inline); | ||
| 15951 | // calling_convention: TypeInfo.CallingConvention | ||
| 15952 | ensure_field_index(fn_def_val->type, "calling_convention", 2); | ||
| 15953 | fn_def_fields[2].special = ConstValSpecialStatic; | ||
| 15954 | fn_def_fields[2].type = ir_type_info_get_type(ira, "CallingConvention"); | ||
| 15955 | bigint_init_unsigned(&fn_def_fields[2].data.x_enum_tag, fn_node->cc); | ||
| 15956 | // is_var_args: bool | ||
| 15957 | ensure_field_index(fn_def_val->type, "is_var_args", 3); | ||
| 15958 | bool is_varargs = fn_node->is_var_args; | ||
| 15959 | fn_def_fields[3].special = ConstValSpecialStatic; | ||
| 15960 | fn_def_fields[3].type = ira->codegen->builtin_types.entry_bool; | ||
| 15961 | fn_def_fields[3].data.x_bool = is_varargs; | ||
| 15962 | // is_extern: bool | ||
| 15963 | ensure_field_index(fn_def_val->type, "is_extern", 4); | ||
| 15964 | fn_def_fields[4].special = ConstValSpecialStatic; | ||
| 15965 | fn_def_fields[4].type = ira->codegen->builtin_types.entry_bool; | ||
| 15966 | fn_def_fields[4].data.x_bool = fn_node->is_extern; | ||
| 15967 | // is_export: bool | ||
| 15968 | ensure_field_index(fn_def_val->type, "is_export", 5); | ||
| 15969 | fn_def_fields[5].special = ConstValSpecialStatic; | ||
| 15970 | fn_def_fields[5].type = ira->codegen->builtin_types.entry_bool; | ||
| 15971 | fn_def_fields[5].data.x_bool = fn_node->is_export; | ||
| 15972 | // lib_name: ?[]const u8 | ||
| 15973 | ensure_field_index(fn_def_val->type, "lib_name", 6); | ||
| 15974 | fn_def_fields[6].special = ConstValSpecialStatic; | ||
| 15975 | fn_def_fields[6].type = get_maybe_type(ira->codegen, | ||
| 15976 | get_slice_type(ira->codegen, get_pointer_to_type(ira->codegen, | ||
| 15977 | ira->codegen->builtin_types.entry_u8, true))); | ||
| 15978 | if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) | ||
| 15979 | { | ||
| 15980 | fn_def_fields[6].data.x_maybe = create_const_vals(1); | ||
| 15981 | ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name); | ||
| 15982 | init_const_slice(ira->codegen, fn_def_fields[6].data.x_maybe, lib_name, 0, buf_len(fn_node->lib_name), true); | ||
| 15983 | } | ||
| 15984 | else | ||
| 15985 | fn_def_fields[6].data.x_maybe = nullptr; | ||
| 15986 | // return_type: type | ||
| 15987 | ensure_field_index(fn_def_val->type, "return_type", 7); | ||
| 15988 | fn_def_fields[7].special = ConstValSpecialStatic; | ||
| 15989 | fn_def_fields[7].type = ira->codegen->builtin_types.entry_type; | ||
| 15990 | if (fn_entry->src_implicit_return_type != nullptr) | ||
| 15991 | fn_def_fields[7].data.x_type = fn_entry->src_implicit_return_type; | ||
| 15992 | else if (fn_entry->type_entry->data.fn.gen_return_type != nullptr) | ||
| 15993 | fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.gen_return_type; | ||
| 15994 | else | ||
| 15995 | fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; | ||
| 15996 | // arg_names: [][] const u8 | ||
| 15997 | ensure_field_index(fn_def_val->type, "arg_names", 8); | ||
| 15998 | size_t fn_arg_count = fn_entry->variable_list.length; | ||
| 15999 | ConstExprValue *fn_arg_name_array = create_const_vals(1); | ||
| 16000 | fn_arg_name_array->special = ConstValSpecialStatic; | ||
| 16001 | fn_arg_name_array->type = get_array_type(ira->codegen, get_slice_type(ira->codegen, | ||
| 16002 | get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true)), fn_arg_count); | ||
| 16003 | fn_arg_name_array->data.x_array.special = ConstArraySpecialNone; | ||
| 16004 | fn_arg_name_array->data.x_array.s_none.parent.id = ConstParentIdNone; | ||
| 16005 | fn_arg_name_array->data.x_array.s_none.elements = create_const_vals(fn_arg_count); | ||
| 16006 | |||
| 16007 | init_const_slice(ira->codegen, &fn_def_fields[8], fn_arg_name_array, 0, fn_arg_count, false); | ||
| 16008 | |||
| 16009 | for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) | ||
| 16010 | { | ||
| 16011 | VariableTableEntry *arg_var = fn_entry->variable_list.at(fn_arg_index); | ||
| 16012 | ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.s_none.elements[fn_arg_index]; | ||
| 16013 | ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name); | ||
| 16014 | init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, buf_len(&arg_var->name), true); | ||
| 16015 | fn_arg_name_val->data.x_struct.parent.id = ConstParentIdArray; | ||
| 16016 | fn_arg_name_val->data.x_struct.parent.data.p_array.array_val = fn_arg_name_array; | ||
| 16017 | fn_arg_name_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index; | ||
| 16018 | } | ||
| 16019 | |||
| 16020 | inner_fields[2].data.x_union.payload = fn_def_val; | ||
| 16021 | break; | ||
| 16022 | } | ||
| 16023 | case TldIdContainer: | ||
| 16024 | { | ||
| 16025 | TypeTableEntry *type_entry = ((TldContainer *)curr_entry->value)->type_entry; | ||
| 16026 | ensure_complete_type(ira->codegen, type_entry); | ||
| 16027 | // This is a type. | ||
| 16028 | bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0); | ||
| 16029 | |||
| 16030 | ConstExprValue *payload = create_const_vals(1); | ||
| 16031 | payload->type = ira->codegen->builtin_types.entry_type; | ||
| 16032 | payload->data.x_type = type_entry; | ||
| 16033 | |||
| 16034 | inner_fields[2].data.x_union.payload = payload; | ||
| 16035 | |||
| 16036 | break; | ||
| 16037 | } | ||
| 16038 | default: | ||
| 16039 | zig_unreachable(); | ||
| 16040 | } | ||
| 16041 | |||
| 16042 | definition_val->data.x_struct.fields = inner_fields; | ||
| 16043 | definition_index++; | ||
| 16044 | } | ||
| 16045 | |||
| 16046 | assert(definition_index == definition_count); | ||
| 16047 | } | ||
| 16048 | |||
| 16049 | static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *type_entry) | ||
| 16050 | { | ||
| 16051 | assert(type_entry != nullptr); | ||
| 16052 | assert(!type_is_invalid(type_entry)); | ||
| 16053 | |||
| 16054 | ensure_complete_type(ira->codegen, type_entry); | ||
| 16055 | |||
| 16056 | const auto make_enum_field_val = [ira](ConstExprValue *enum_field_val, TypeEnumField *enum_field, | ||
| 16057 | TypeTableEntry *type_info_enum_field_type) { | ||
| 16058 | enum_field_val->special = ConstValSpecialStatic; | ||
| 16059 | enum_field_val->type = type_info_enum_field_type; | ||
| 16060 | |||
| 16061 | ConstExprValue *inner_fields = create_const_vals(2); | ||
| 16062 | inner_fields[1].special = ConstValSpecialStatic; | ||
| 16063 | inner_fields[1].type = ira->codegen->builtin_types.entry_usize; | ||
| 16064 | |||
| 16065 | ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name); | ||
| 16066 | init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(enum_field->name), true); | ||
| 16067 | |||
| 16068 | bigint_init_bigint(&inner_fields[1].data.x_bigint, &enum_field->value); | ||
| 16069 | |||
| 16070 | enum_field_val->data.x_struct.fields = inner_fields; | ||
| 16071 | }; | ||
| 16072 | |||
| 16073 | ConstExprValue *result = nullptr; | ||
| 16074 | switch (type_entry->id) | ||
| 16075 | { | ||
| 16076 | case TypeTableEntryIdInvalid: | ||
| 16077 | zig_unreachable(); | ||
| 16078 | case TypeTableEntryIdMetaType: | ||
| 16079 | case TypeTableEntryIdVoid: | ||
| 16080 | case TypeTableEntryIdBool: | ||
| 16081 | case TypeTableEntryIdUnreachable: | ||
| 16082 | case TypeTableEntryIdNumLitFloat: | ||
| 16083 | case TypeTableEntryIdNumLitInt: | ||
| 16084 | case TypeTableEntryIdUndefLit: | ||
| 16085 | case TypeTableEntryIdNullLit: | ||
| 16086 | case TypeTableEntryIdNamespace: | ||
| 16087 | case TypeTableEntryIdBlock: | ||
| 16088 | case TypeTableEntryIdArgTuple: | ||
| 16089 | case TypeTableEntryIdOpaque: | ||
| 16090 | return nullptr; | ||
| 16091 | default: | ||
| 16092 | { | ||
| 16093 | // Lookup an available value in our cache. | ||
| 16094 | auto entry = ira->codegen->type_info_cache.maybe_get(type_entry); | ||
| 16095 | if (entry != nullptr) | ||
| 16096 | return entry->value; | ||
| 16097 | |||
| 16098 | // Fallthrough if we don't find one. | ||
| 16099 | } | ||
| 16100 | case TypeTableEntryIdInt: | ||
| 16101 | { | ||
| 16102 | result = create_const_vals(1); | ||
| 16103 | result->special = ConstValSpecialStatic; | ||
| 16104 | result->type = ir_type_info_get_type(ira, "Int"); | ||
| 16105 | |||
| 16106 | ConstExprValue *fields = create_const_vals(2); | ||
| 16107 | result->data.x_struct.fields = fields; | ||
| 16108 | |||
| 16109 | // is_signed: bool | ||
| 16110 | ensure_field_index(result->type, "is_signed", 0); | ||
| 16111 | fields[0].special = ConstValSpecialStatic; | ||
| 16112 | fields[0].type = ira->codegen->builtin_types.entry_bool; | ||
| 16113 | fields[0].data.x_bool = type_entry->data.integral.is_signed; | ||
| 16114 | // bits: u8 | ||
| 16115 | ensure_field_index(result->type, "bits", 1); | ||
| 16116 | fields[1].special = ConstValSpecialStatic; | ||
| 16117 | fields[1].type = ira->codegen->builtin_types.entry_u8; | ||
| 16118 | bigint_init_unsigned(&fields[1].data.x_bigint, type_entry->data.integral.bit_count); | ||
| 16119 | |||
| 16120 | break; | ||
| 16121 | } | ||
| 16122 | case TypeTableEntryIdFloat: | ||
| 16123 | { | ||
| 16124 | result = create_const_vals(1); | ||
| 16125 | result->special = ConstValSpecialStatic; | ||
| 16126 | result->type = ir_type_info_get_type(ira, "Float"); | ||
| 16127 | |||
| 16128 | ConstExprValue *fields = create_const_vals(1); | ||
| 16129 | result->data.x_struct.fields = fields; | ||
| 16130 | |||
| 16131 | // bits: u8 | ||
| 16132 | ensure_field_index(result->type, "bits", 0); | ||
| 16133 | fields[0].special = ConstValSpecialStatic; | ||
| 16134 | fields[0].type = ira->codegen->builtin_types.entry_u8; | ||
| 16135 | bigint_init_unsigned(&fields->data.x_bigint, type_entry->data.floating.bit_count); | ||
| 16136 | |||
| 16137 | break; | ||
| 16138 | } | ||
| 16139 | case TypeTableEntryIdPointer: | ||
| 16140 | { | ||
| 16141 | result = create_const_vals(1); | ||
| 16142 | result->special = ConstValSpecialStatic; | ||
| 16143 | result->type = ir_type_info_get_type(ira, "Pointer"); | ||
| 16144 | |||
| 16145 | ConstExprValue *fields = create_const_vals(4); | ||
| 16146 | result->data.x_struct.fields = fields; | ||
| 16147 | |||
| 16148 | // is_const: bool | ||
| 16149 | ensure_field_index(result->type, "is_const", 0); | ||
| 16150 | fields[0].special = ConstValSpecialStatic; | ||
| 16151 | fields[0].type = ira->codegen->builtin_types.entry_bool; | ||
| 16152 | fields[0].data.x_bool = type_entry->data.pointer.is_const; | ||
| 16153 | // is_volatile: bool | ||
| 16154 | ensure_field_index(result->type, "is_volatile", 1); | ||
| 16155 | fields[1].special = ConstValSpecialStatic; | ||
| 16156 | fields[1].type = ira->codegen->builtin_types.entry_bool; | ||
| 16157 | fields[1].data.x_bool = type_entry->data.pointer.is_volatile; | ||
| 16158 | // alignment: u32 | ||
| 16159 | ensure_field_index(result->type, "alignment", 2); | ||
| 16160 | fields[2].special = ConstValSpecialStatic; | ||
| 16161 | fields[2].type = ira->codegen->builtin_types.entry_u32; | ||
| 16162 | bigint_init_unsigned(&fields[2].data.x_bigint, type_entry->data.pointer.alignment); | ||
| 16163 | // child: type | ||
| 16164 | ensure_field_index(result->type, "child", 3); | ||
| 16165 | fields[3].special = ConstValSpecialStatic; | ||
| 16166 | fields[3].type = ira->codegen->builtin_types.entry_type; | ||
| 16167 | fields[3].data.x_type = type_entry->data.pointer.child_type; | ||
| 16168 | |||
| 16169 | break; | ||
| 16170 | } | ||
| 16171 | case TypeTableEntryIdArray: | ||
| 16172 | { | ||
| 16173 | result = create_const_vals(1); | ||
| 16174 | result->special = ConstValSpecialStatic; | ||
| 16175 | result->type = ir_type_info_get_type(ira, "Array"); | ||
| 16176 | |||
| 16177 | ConstExprValue *fields = create_const_vals(2); | ||
| 16178 | result->data.x_struct.fields = fields; | ||
| 16179 | |||
| 16180 | // len: usize | ||
| 16181 | ensure_field_index(result->type, "len", 0); | ||
| 16182 | fields[0].special = ConstValSpecialStatic; | ||
| 16183 | fields[0].type = ira->codegen->builtin_types.entry_usize; | ||
| 16184 | bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.array.len); | ||
| 16185 | // child: type | ||
| 16186 | ensure_field_index(result->type, "child", 1); | ||
| 16187 | fields[1].special = ConstValSpecialStatic; | ||
| 16188 | fields[1].type = ira->codegen->builtin_types.entry_type; | ||
| 16189 | fields[1].data.x_type = type_entry->data.array.child_type; | ||
| 16190 | |||
| 16191 | break; | ||
| 16192 | } | ||
| 16193 | case TypeTableEntryIdMaybe: | ||
| 16194 | { | ||
| 16195 | result = create_const_vals(1); | ||
| 16196 | result->special = ConstValSpecialStatic; | ||
| 16197 | result->type = ir_type_info_get_type(ira, "Nullable"); | ||
| 16198 | |||
| 16199 | ConstExprValue *fields = create_const_vals(1); | ||
| 16200 | result->data.x_struct.fields = fields; | ||
| 16201 | |||
| 16202 | // child: type | ||
| 16203 | ensure_field_index(result->type, "child", 0); | ||
| 16204 | fields[0].special = ConstValSpecialStatic; | ||
| 16205 | fields[0].type = ira->codegen->builtin_types.entry_type; | ||
| 16206 | fields[0].data.x_type = type_entry->data.maybe.child_type; | ||
| 16207 | |||
| 16208 | break; | ||
| 16209 | } | ||
| 16210 | case TypeTableEntryIdPromise: | ||
| 16211 | { | ||
| 16212 | result = create_const_vals(1); | ||
| 16213 | result->special = ConstValSpecialStatic; | ||
| 16214 | result->type = ir_type_info_get_type(ira, "Promise"); | ||
| 16215 | |||
| 16216 | ConstExprValue *fields = create_const_vals(1); | ||
| 16217 | result->data.x_struct.fields = fields; | ||
| 16218 | |||
| 16219 | // @TODO ?type instead of using @typeOf(undefined) when we have no type. | ||
| 16220 | // child: type | ||
| 16221 | ensure_field_index(result->type, "child", 0); | ||
| 16222 | fields[0].special = ConstValSpecialStatic; | ||
| 16223 | fields[0].type = ira->codegen->builtin_types.entry_type; | ||
| 16224 | |||
| 16225 | if (type_entry->data.promise.result_type == nullptr) | ||
| 16226 | fields[0].data.x_type = ira->codegen->builtin_types.entry_undef; | ||
| 16227 | else | ||
| 16228 | fields[0].data.x_type = type_entry->data.promise.result_type; | ||
| 16229 | |||
| 16230 | break; | ||
| 16231 | } | ||
| 16232 | case TypeTableEntryIdEnum: | ||
| 16233 | { | ||
| 16234 | result = create_const_vals(1); | ||
| 16235 | result->special = ConstValSpecialStatic; | ||
| 16236 | result->type = ir_type_info_get_type(ira, "Enum"); | ||
| 16237 | |||
| 16238 | ConstExprValue *fields = create_const_vals(4); | ||
| 16239 | result->data.x_struct.fields = fields; | ||
| 16240 | |||
| 16241 | // layout: ContainerLayout | ||
| 16242 | ensure_field_index(result->type, "layout", 0); | ||
| 16243 | fields[0].special = ConstValSpecialStatic; | ||
| 16244 | fields[0].type = ir_type_info_get_type(ira, "ContainerLayout"); | ||
| 16245 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.enumeration.layout); | ||
| 16246 | // tag_type: type | ||
| 16247 | ensure_field_index(result->type, "tag_type", 1); | ||
| 16248 | fields[1].special = ConstValSpecialStatic; | ||
| 16249 | fields[1].type = ira->codegen->builtin_types.entry_type; | ||
| 16250 | fields[1].data.x_type = type_entry->data.enumeration.tag_int_type; | ||
| 16251 | // fields: []TypeInfo.EnumField | ||
| 16252 | ensure_field_index(result->type, "fields", 2); | ||
| 16253 | |||
| 16254 | TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField"); | ||
| 16255 | uint32_t enum_field_count = type_entry->data.enumeration.src_field_count; | ||
| 16256 | |||
| 16257 | ConstExprValue *enum_field_array = create_const_vals(1); | ||
| 16258 | enum_field_array->special = ConstValSpecialStatic; | ||
| 16259 | enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count); | ||
| 16260 | enum_field_array->data.x_array.special = ConstArraySpecialNone; | ||
| 16261 | enum_field_array->data.x_array.s_none.parent.id = ConstParentIdNone; | ||
| 16262 | enum_field_array->data.x_array.s_none.elements = create_const_vals(enum_field_count); | ||
| 16263 | |||
| 16264 | init_const_slice(ira->codegen, &fields[2], enum_field_array, 0, enum_field_count, false); | ||
| 16265 | |||
| 16266 | for (uint32_t enum_field_index = 0; enum_field_index < enum_field_count; enum_field_index++) | ||
| 16267 | { | ||
| 16268 | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index]; | ||
| 16269 | ConstExprValue *enum_field_val = &enum_field_array->data.x_array.s_none.elements[enum_field_index]; | ||
| 16270 | make_enum_field_val(enum_field_val, enum_field, type_info_enum_field_type); | ||
| 16271 | enum_field_val->data.x_struct.parent.id = ConstParentIdArray; | ||
| 16272 | enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array; | ||
| 16273 | enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index; | ||
| 16274 | } | ||
| 16275 | // defs: []TypeInfo.Definition | ||
| 16276 | ensure_field_index(result->type, "defs", 3); | ||
| 16277 | ir_make_type_info_defs(ira, &fields[3], type_entry->data.enumeration.decls_scope); | ||
| 16278 | |||
| 16279 | break; | ||
| 16280 | } | ||
| 16281 | case TypeTableEntryIdErrorSet: | ||
| 16282 | { | ||
| 16283 | result = create_const_vals(1); | ||
| 16284 | result->special = ConstValSpecialStatic; | ||
| 16285 | result->type = ir_type_info_get_type(ira, "ErrorSet"); | ||
| 16286 | |||
| 16287 | ConstExprValue *fields = create_const_vals(1); | ||
| 16288 | result->data.x_struct.fields = fields; | ||
| 16289 | |||
| 16290 | // errors: []TypeInfo.Error | ||
| 16291 | ensure_field_index(result->type, "errors", 0); | ||
| 16292 | |||
| 16293 | TypeTableEntry *type_info_error_type = ir_type_info_get_type(ira, "Error"); | ||
| 16294 | uint32_t error_count = type_entry->data.error_set.err_count; | ||
| 16295 | ConstExprValue *error_array = create_const_vals(1); | ||
| 16296 | error_array->special = ConstValSpecialStatic; | ||
| 16297 | error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count); | ||
| 16298 | error_array->data.x_array.special = ConstArraySpecialNone; | ||
| 16299 | error_array->data.x_array.s_none.parent.id = ConstParentIdNone; | ||
| 16300 | error_array->data.x_array.s_none.elements = create_const_vals(error_count); | ||
| 16301 | |||
| 16302 | init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false); | ||
| 16303 | for (uint32_t error_index = 0; error_index < error_count; error_index++) | ||
| 16304 | { | ||
| 16305 | ErrorTableEntry *error = type_entry->data.error_set.errors[error_index]; | ||
| 16306 | ConstExprValue *error_val = &error_array->data.x_array.s_none.elements[error_index]; | ||
| 16307 | |||
| 16308 | error_val->special = ConstValSpecialStatic; | ||
| 16309 | error_val->type = type_info_error_type; | ||
| 16310 | |||
| 16311 | ConstExprValue *inner_fields = create_const_vals(2); | ||
| 16312 | inner_fields[1].special = ConstValSpecialStatic; | ||
| 16313 | inner_fields[1].type = ira->codegen->builtin_types.entry_usize; | ||
| 16314 | |||
| 16315 | ConstExprValue *name = nullptr; | ||
| 16316 | if (error->cached_error_name_val != nullptr) | ||
| 16317 | name = error->cached_error_name_val; | ||
| 16318 | if (name == nullptr) | ||
| 16319 | name = create_const_str_lit(ira->codegen, &error->name); | ||
| 16320 | init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(&error->name), true); | ||
| 16321 | bigint_init_unsigned(&inner_fields[1].data.x_bigint, error->value); | ||
| 16322 | |||
| 16323 | error_val->data.x_struct.fields = inner_fields; | ||
| 16324 | error_val->data.x_struct.parent.id = ConstParentIdArray; | ||
| 16325 | error_val->data.x_struct.parent.data.p_array.array_val = error_array; | ||
| 16326 | error_val->data.x_struct.parent.data.p_array.elem_index = error_index; | ||
| 16327 | } | ||
| 16328 | |||
| 16329 | break; | ||
| 16330 | } | ||
| 16331 | case TypeTableEntryIdErrorUnion: | ||
| 16332 | { | ||
| 16333 | result = create_const_vals(1); | ||
| 16334 | result->special = ConstValSpecialStatic; | ||
| 16335 | result->type = ir_type_info_get_type(ira, "ErrorUnion"); | ||
| 16336 | |||
| 16337 | ConstExprValue *fields = create_const_vals(2); | ||
| 16338 | result->data.x_struct.fields = fields; | ||
| 16339 | |||
| 16340 | // error_set: type | ||
| 16341 | ensure_field_index(result->type, "error_set", 0); | ||
| 16342 | fields[0].special = ConstValSpecialStatic; | ||
| 16343 | fields[0].type = ira->codegen->builtin_types.entry_type; | ||
| 16344 | fields[0].data.x_type = type_entry->data.error_union.err_set_type; | ||
| 16345 | |||
| 16346 | // payload: type | ||
| 16347 | ensure_field_index(result->type, "payload", 1); | ||
| 16348 | fields[1].special = ConstValSpecialStatic; | ||
| 16349 | fields[1].type = ira->codegen->builtin_types.entry_type; | ||
| 16350 | fields[1].data.x_type = type_entry->data.error_union.payload_type; | ||
| 16351 | |||
| 16352 | break; | ||
| 16353 | } | ||
| 16354 | case TypeTableEntryIdUnion: | ||
| 16355 | { | ||
| 16356 | result = create_const_vals(1); | ||
| 16357 | result->special = ConstValSpecialStatic; | ||
| 16358 | result->type = ir_type_info_get_type(ira, "Union"); | ||
| 16359 | |||
| 16360 | ConstExprValue *fields = create_const_vals(4); | ||
| 16361 | result->data.x_struct.fields = fields; | ||
| 16362 | |||
| 16363 | // layout: ContainerLayout | ||
| 16364 | ensure_field_index(result->type, "layout", 0); | ||
| 16365 | fields[0].special = ConstValSpecialStatic; | ||
| 16366 | fields[0].type = ir_type_info_get_type(ira, "ContainerLayout"); | ||
| 16367 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.unionation.layout); | ||
| 16368 | // tag_type: type | ||
| 16369 | ensure_field_index(result->type, "tag_type", 1); | ||
| 16370 | fields[1].special = ConstValSpecialStatic; | ||
| 16371 | fields[1].type = ira->codegen->builtin_types.entry_type; | ||
| 16372 | // @TODO ?type instead of using @typeOf(undefined) when we have no type. | ||
| 16373 | AstNode *union_decl_node = type_entry->data.unionation.decl_node; | ||
| 16374 | if (union_decl_node->data.container_decl.auto_enum || | ||
| 16375 | union_decl_node->data.container_decl.init_arg_expr != nullptr) | ||
| 16376 | { | ||
| 16377 | fields[1].data.x_type = type_entry->data.unionation.tag_type; | ||
| 16378 | } | ||
| 16379 | else | ||
| 16380 | fields[1].data.x_type = ira->codegen->builtin_types.entry_undef; | ||
| 16381 | // fields: []TypeInfo.UnionField | ||
| 16382 | ensure_field_index(result->type, "fields", 2); | ||
| 16383 | |||
| 16384 | TypeTableEntry *type_info_union_field_type = ir_type_info_get_type(ira, "UnionField"); | ||
| 16385 | uint32_t union_field_count = type_entry->data.unionation.src_field_count; | ||
| 16386 | |||
| 16387 | ConstExprValue *union_field_array = create_const_vals(1); | ||
| 16388 | union_field_array->special = ConstValSpecialStatic; | ||
| 16389 | union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count); | ||
| 16390 | union_field_array->data.x_array.special = ConstArraySpecialNone; | ||
| 16391 | union_field_array->data.x_array.s_none.parent.id = ConstParentIdNone; | ||
| 16392 | union_field_array->data.x_array.s_none.elements = create_const_vals(union_field_count); | ||
| 16393 | |||
| 16394 | init_const_slice(ira->codegen, &fields[2], union_field_array, 0, union_field_count, false); | ||
| 16395 | |||
| 16396 | TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField"); | ||
| 16397 | |||
| 16398 | for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) | ||
| 16399 | { | ||
| 16400 | TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index]; | ||
| 16401 | ConstExprValue *union_field_val = &union_field_array->data.x_array.s_none.elements[union_field_index]; | ||
| 16402 | |||
| 16403 | union_field_val->special = ConstValSpecialStatic; | ||
| 16404 | union_field_val->type = type_info_union_field_type; | ||
| 16405 | |||
| 16406 | ConstExprValue *inner_fields = create_const_vals(3); | ||
| 16407 | inner_fields[1].special = ConstValSpecialStatic; | ||
| 16408 | inner_fields[1].type = get_maybe_type(ira->codegen, type_info_enum_field_type); | ||
| 16409 | |||
| 16410 | if (fields[1].data.x_type == ira->codegen->builtin_types.entry_undef) | ||
| 16411 | inner_fields[1].data.x_maybe = nullptr; | ||
| 16412 | else | ||
| 16413 | { | ||
| 16414 | inner_fields[1].data.x_maybe = create_const_vals(1); | ||
| 16415 | make_enum_field_val(inner_fields[1].data.x_maybe, union_field->enum_field, type_info_enum_field_type); | ||
| 16416 | } | ||
| 16417 | |||
| 16418 | inner_fields[2].special = ConstValSpecialStatic; | ||
| 16419 | inner_fields[2].type = ira->codegen->builtin_types.entry_type; | ||
| 16420 | inner_fields[2].data.x_type = union_field->type_entry; | ||
| 16421 | |||
| 16422 | ConstExprValue *name = create_const_str_lit(ira->codegen, union_field->name); | ||
| 16423 | init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(union_field->name), true); | ||
| 16424 | |||
| 16425 | union_field_val->data.x_struct.fields = inner_fields; | ||
| 16426 | union_field_val->data.x_struct.parent.id = ConstParentIdArray; | ||
| 16427 | union_field_val->data.x_struct.parent.data.p_array.array_val = union_field_array; | ||
| 16428 | union_field_val->data.x_struct.parent.data.p_array.elem_index = union_field_index; | ||
| 16429 | } | ||
| 16430 | // defs: []TypeInfo.Definition | ||
| 16431 | ensure_field_index(result->type, "defs", 3); | ||
| 16432 | ir_make_type_info_defs(ira, &fields[3], type_entry->data.unionation.decls_scope); | ||
| 16433 | |||
| 16434 | break; | ||
| 16435 | } | ||
| 16436 | case TypeTableEntryIdStruct: | ||
| 16437 | { | ||
| 16438 | result = create_const_vals(1); | ||
| 16439 | result->special = ConstValSpecialStatic; | ||
| 16440 | result->type = ir_type_info_get_type(ira, "Struct"); | ||
| 16441 | |||
| 16442 | ConstExprValue *fields = create_const_vals(3); | ||
| 16443 | result->data.x_struct.fields = fields; | ||
| 16444 | |||
| 16445 | // layout: ContainerLayout | ||
| 16446 | ensure_field_index(result->type, "layout", 0); | ||
| 16447 | fields[0].special = ConstValSpecialStatic; | ||
| 16448 | fields[0].type = ir_type_info_get_type(ira, "ContainerLayout"); | ||
| 16449 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.structure.layout); | ||
| 16450 | // fields: []TypeInfo.StructField | ||
| 16451 | ensure_field_index(result->type, "fields", 1); | ||
| 16452 | |||
| 16453 | TypeTableEntry *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField"); | ||
| 16454 | uint32_t struct_field_count = type_entry->data.structure.src_field_count; | ||
| 16455 | |||
| 16456 | ConstExprValue *struct_field_array = create_const_vals(1); | ||
| 16457 | struct_field_array->special = ConstValSpecialStatic; | ||
| 16458 | struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count); | ||
| 16459 | struct_field_array->data.x_array.special = ConstArraySpecialNone; | ||
| 16460 | struct_field_array->data.x_array.s_none.parent.id = ConstParentIdNone; | ||
| 16461 | struct_field_array->data.x_array.s_none.elements = create_const_vals(struct_field_count); | ||
| 16462 | |||
| 16463 | init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false); | ||
| 16464 | |||
| 16465 | for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) | ||
| 16466 | { | ||
| 16467 | TypeStructField *struct_field = &type_entry->data.structure.fields[struct_field_index]; | ||
| 16468 | ConstExprValue *struct_field_val = &struct_field_array->data.x_array.s_none.elements[struct_field_index]; | ||
| 16469 | |||
| 16470 | struct_field_val->special = ConstValSpecialStatic; | ||
| 16471 | struct_field_val->type = type_info_struct_field_type; | ||
| 16472 | |||
| 16473 | ConstExprValue *inner_fields = create_const_vals(3); | ||
| 16474 | inner_fields[1].special = ConstValSpecialStatic; | ||
| 16475 | inner_fields[1].type = get_maybe_type(ira->codegen, ira->codegen->builtin_types.entry_usize); | ||
| 16476 | |||
| 16477 | if (!type_has_bits(struct_field->type_entry)) | ||
| 16478 | inner_fields[1].data.x_maybe = nullptr; | ||
| 16479 | else | ||
| 16480 | { | ||
| 16481 | size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index); | ||
| 16482 | inner_fields[1].data.x_maybe = create_const_vals(1); | ||
| 16483 | inner_fields[1].data.x_maybe->type = ira->codegen->builtin_types.entry_usize; | ||
| 16484 | bigint_init_unsigned(&inner_fields[1].data.x_maybe->data.x_bigint, byte_offset); | ||
| 16485 | } | ||
| 16486 | |||
| 16487 | inner_fields[2].special = ConstValSpecialStatic; | ||
| 16488 | inner_fields[2].type = ira->codegen->builtin_types.entry_type; | ||
| 16489 | inner_fields[2].data.x_type = struct_field->type_entry; | ||
| 16490 | |||
| 16491 | ConstExprValue *name = create_const_str_lit(ira->codegen, struct_field->name); | ||
| 16492 | init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(struct_field->name), true); | ||
| 16493 | |||
| 16494 | struct_field_val->data.x_struct.fields = inner_fields; | ||
| 16495 | struct_field_val->data.x_struct.parent.id = ConstParentIdArray; | ||
| 16496 | struct_field_val->data.x_struct.parent.data.p_array.array_val = struct_field_array; | ||
| 16497 | struct_field_val->data.x_struct.parent.data.p_array.elem_index = struct_field_index; | ||
| 16498 | } | ||
| 16499 | // defs: []TypeInfo.Definition | ||
| 16500 | ensure_field_index(result->type, "defs", 2); | ||
| 16501 | ir_make_type_info_defs(ira, &fields[2], type_entry->data.structure.decls_scope); | ||
| 16502 | |||
| 16503 | break; | ||
| 16504 | } | ||
| 16505 | case TypeTableEntryIdFn: | ||
| 16506 | { | ||
| 16507 | result = create_const_vals(1); | ||
| 16508 | result->special = ConstValSpecialStatic; | ||
| 16509 | result->type = ir_type_info_get_type(ira, "Fn"); | ||
| 16510 | |||
| 16511 | ConstExprValue *fields = create_const_vals(6); | ||
| 16512 | result->data.x_struct.fields = fields; | ||
| 16513 | |||
| 16514 | // @TODO Fix type = undefined with ?type | ||
| 16515 | |||
| 16516 | // calling_convention: TypeInfo.CallingConvention | ||
| 16517 | ensure_field_index(result->type, "calling_convention", 0); | ||
| 16518 | fields[0].special = ConstValSpecialStatic; | ||
| 16519 | fields[0].type = ir_type_info_get_type(ira, "CallingConvention"); | ||
| 16520 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.fn.fn_type_id.cc); | ||
| 16521 | // is_generic: bool | ||
| 16522 | ensure_field_index(result->type, "is_generic", 1); | ||
| 16523 | bool is_generic = type_entry->data.fn.is_generic; | ||
| 16524 | fields[1].special = ConstValSpecialStatic; | ||
| 16525 | fields[1].type = ira->codegen->builtin_types.entry_bool; | ||
| 16526 | fields[1].data.x_bool = is_generic; | ||
| 16527 | // is_varargs: bool | ||
| 16528 | ensure_field_index(result->type, "is_var_args", 2); | ||
| 16529 | bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args; | ||
| 16530 | fields[2].special = ConstValSpecialStatic; | ||
| 16531 | fields[2].type = ira->codegen->builtin_types.entry_bool; | ||
| 16532 | fields[2].data.x_bool = type_entry->data.fn.fn_type_id.is_var_args; | ||
| 16533 | // return_type: type | ||
| 16534 | ensure_field_index(result->type, "return_type", 3); | ||
| 16535 | fields[3].special = ConstValSpecialStatic; | ||
| 16536 | fields[3].type = ira->codegen->builtin_types.entry_type; | ||
| 16537 | if (type_entry->data.fn.fn_type_id.return_type == nullptr) | ||
| 16538 | fields[3].data.x_type = ira->codegen->builtin_types.entry_undef; | ||
| 16539 | else | ||
| 16540 | fields[3].data.x_type = type_entry->data.fn.fn_type_id.return_type; | ||
| 16541 | // async_allocator_type: type | ||
| 16542 | ensure_field_index(result->type, "async_allocator_type", 4); | ||
| 16543 | fields[4].special = ConstValSpecialStatic; | ||
| 16544 | fields[4].type = ira->codegen->builtin_types.entry_type; | ||
| 16545 | if (type_entry->data.fn.fn_type_id.async_allocator_type == nullptr) | ||
| 16546 | fields[4].data.x_type = ira->codegen->builtin_types.entry_undef; | ||
| 16547 | else | ||
| 16548 | fields[4].data.x_type = type_entry->data.fn.fn_type_id.async_allocator_type; | ||
| 16549 | // args: []TypeInfo.FnArg | ||
| 16550 | TypeTableEntry *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg"); | ||
| 16551 | size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count - | ||
| 16552 | (is_varargs && type_entry->data.fn.fn_type_id.cc != CallingConventionC); | ||
| 16553 | |||
| 16554 | ConstExprValue *fn_arg_array = create_const_vals(1); | ||
| 16555 | fn_arg_array->special = ConstValSpecialStatic; | ||
| 16556 | fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count); | ||
| 16557 | fn_arg_array->data.x_array.special = ConstArraySpecialNone; | ||
| 16558 | fn_arg_array->data.x_array.s_none.parent.id = ConstParentIdNone; | ||
| 16559 | fn_arg_array->data.x_array.s_none.elements = create_const_vals(fn_arg_count); | ||
| 16560 | |||
| 16561 | init_const_slice(ira->codegen, &fields[5], fn_arg_array, 0, fn_arg_count, false); | ||
| 16562 | |||
| 16563 | for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) | ||
| 16564 | { | ||
| 16565 | FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index]; | ||
| 16566 | ConstExprValue *fn_arg_val = &fn_arg_array->data.x_array.s_none.elements[fn_arg_index]; | ||
| 16567 | |||
| 16568 | fn_arg_val->special = ConstValSpecialStatic; | ||
| 16569 | fn_arg_val->type = type_info_fn_arg_type; | ||
| 16570 | |||
| 16571 | bool arg_is_generic = fn_param_info->type == nullptr; | ||
| 16572 | if (arg_is_generic) assert(is_generic); | ||
| 16573 | |||
| 16574 | ConstExprValue *inner_fields = create_const_vals(3); | ||
| 16575 | inner_fields[0].special = ConstValSpecialStatic; | ||
| 16576 | inner_fields[0].type = ira->codegen->builtin_types.entry_bool; | ||
| 16577 | inner_fields[0].data.x_bool = arg_is_generic; | ||
| 16578 | inner_fields[1].special = ConstValSpecialStatic; | ||
| 16579 | inner_fields[1].type = ira->codegen->builtin_types.entry_bool; | ||
| 16580 | inner_fields[1].data.x_bool = fn_param_info->is_noalias; | ||
| 16581 | inner_fields[2].special = ConstValSpecialStatic; | ||
| 16582 | inner_fields[2].type = ira->codegen->builtin_types.entry_type; | ||
| 16583 | |||
| 16584 | if (arg_is_generic) | ||
| 16585 | inner_fields[2].data.x_type = ira->codegen->builtin_types.entry_undef; | ||
| 16586 | else | ||
| 16587 | inner_fields[2].data.x_type = fn_param_info->type; | ||
| 16588 | |||
| 16589 | fn_arg_val->data.x_struct.fields = inner_fields; | ||
| 16590 | fn_arg_val->data.x_struct.parent.id = ConstParentIdArray; | ||
| 16591 | fn_arg_val->data.x_struct.parent.data.p_array.array_val = fn_arg_array; | ||
| 16592 | fn_arg_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index; | ||
| 16593 | } | ||
| 16594 | |||
| 16595 | break; | ||
| 16596 | } | ||
| 16597 | case TypeTableEntryIdBoundFn: | ||
| 16598 | { | ||
| 16599 | TypeTableEntry *fn_type = type_entry->data.bound_fn.fn_type; | ||
| 16600 | assert(fn_type->id == TypeTableEntryIdFn); | ||
| 16601 | result = ir_make_type_info_value(ira, fn_type); | ||
| 16602 | |||
| 16603 | break; | ||
| 16604 | } | ||
| 16605 | } | ||
| 16606 | |||
| 16607 | assert(result != nullptr); | ||
| 16608 | ira->codegen->type_info_cache.put(type_entry, result); | ||
| 16609 | return result; | ||
| 16610 | } | ||
| 16611 | |||
| 16612 | static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira, | ||
| 16613 | IrInstructionTypeInfo *instruction) | ||
| 16614 | { | ||
| 16615 | IrInstruction *type_value = instruction->type_value->other; | ||
| 16616 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); | ||
| 16617 | if (type_is_invalid(type_entry)) | ||
| 16618 | return ira->codegen->builtin_types.entry_invalid; | ||
| 16619 | |||
| 16620 | TypeTableEntry *result_type = ir_type_info_get_type(ira, nullptr); | ||
| 16621 | |||
| 16622 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | ||
| 16623 | out_val->type = result_type; | ||
| 16624 | bigint_init_unsigned(&out_val->data.x_union.tag, type_id_index(type_entry->id)); | ||
| 16625 | |||
| 16626 | ConstExprValue *payload = ir_make_type_info_value(ira, type_entry); | ||
| 16627 | out_val->data.x_union.payload = payload; | ||
| 16628 | |||
| 16629 | if (payload != nullptr) | ||
| 16630 | { | ||
| 16631 | assert(payload->type->id == TypeTableEntryIdStruct); | ||
| 16632 | payload->data.x_struct.parent.id = ConstParentIdUnion; | ||
| 16633 | payload->data.x_struct.parent.data.p_union.union_val = out_val; | ||
| 16634 | } | ||
| 16635 | |||
| 16636 | return result_type; | ||
| 16637 | } | ||
| 16638 | |||
| 15680 | static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira, | 16639 | static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira, |
| 15681 | IrInstructionTypeId *instruction) | 16640 | IrInstructionTypeId *instruction) |
| 15682 | { | 16641 | { |
| ... | @@ -18578,6 +19537,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -18578,6 +19537,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 18578 | return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction); | 19537 | return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction); |
| 18579 | case IrInstructionIdOffsetOf: | 19538 | case IrInstructionIdOffsetOf: |
| 18580 | return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction); | 19539 | return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction); |
| 19540 | case IrInstructionIdTypeInfo: | ||
| 19541 | return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction); | ||
| 18581 | case IrInstructionIdTypeId: | 19542 | case IrInstructionIdTypeId: |
| 18582 | return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction); | 19543 | return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction); |
| 18583 | case IrInstructionIdSetEvalBranchQuota: | 19544 | case IrInstructionIdSetEvalBranchQuota: |
| ... | @@ -18844,6 +19805,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -18844,6 +19805,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 18844 | case IrInstructionIdTagName: | 19805 | case IrInstructionIdTagName: |
| 18845 | case IrInstructionIdFieldParentPtr: | 19806 | case IrInstructionIdFieldParentPtr: |
| 18846 | case IrInstructionIdOffsetOf: | 19807 | case IrInstructionIdOffsetOf: |
| 19808 | case IrInstructionIdTypeInfo: | ||
| 18847 | case IrInstructionIdTypeId: | 19809 | case IrInstructionIdTypeId: |
| 18848 | case IrInstructionIdAlignCast: | 19810 | case IrInstructionIdAlignCast: |
| 18849 | case IrInstructionIdOpaqueType: | 19811 | 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 | } |
| 968 | 968 | ||
| 969 | static 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 | |||
| 969 | static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) { | 975 | static 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+39-69| ... | @@ -3746,6 +3746,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { | ... | @@ -3746,6 +3746,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { |
| 3746 | return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name); | 3746 | return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name); |
| 3747 | } | 3747 | } |
| 3748 | 3748 | ||
| 3749 | |||
| 3749 | bool pure_enum = true; | 3750 | bool pure_enum = true; |
| 3750 | uint32_t field_count = 0; | 3751 | uint32_t field_count = 0; |
| 3751 | for (auto it = enum_def->enumerator_begin(), | 3752 | for (auto it = enum_def->enumerator_begin(), |
| ... | @@ -3757,84 +3758,53 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { | ... | @@ -3757,84 +3758,53 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { |
| 3757 | pure_enum = false; | 3758 | pure_enum = false; |
| 3758 | } | 3759 | } |
| 3759 | } | 3760 | } |
| 3760 | |||
| 3761 | AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation()); | 3761 | AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation()); |
| 3762 | assert(tag_int_type); | 3762 | assert(tag_int_type); |
| 3763 | 3763 | ||
| 3764 | if (pure_enum) { | 3764 | AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); |
| 3765 | AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); | 3765 | enum_node->data.container_decl.kind = ContainerKindEnum; |
| 3766 | enum_node->data.container_decl.kind = ContainerKindEnum; | 3766 | enum_node->data.container_decl.layout = ContainerLayoutExtern; |
| 3767 | enum_node->data.container_decl.layout = ContainerLayoutExtern; | 3767 | // TODO only emit this tag type if the enum tag type is not the default. |
| 3768 | // TODO only emit this tag type if the enum tag type is not the default. | 3768 | // I don't know what the default is, need to figure out how clang is deciding. |
| 3769 | // I don't know what the default is, need to figure out how clang is deciding. | 3769 | // it appears to at least be different across gcc/msvc |
| 3770 | // it appears to at least be different across gcc/msvc | 3770 | if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) && |
| 3771 | if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) && | 3771 | !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int)) |
| 3772 | !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int)) | 3772 | { |
| 3773 | { | 3773 | enum_node->data.container_decl.init_arg_expr = tag_int_type; |
| 3774 | enum_node->data.container_decl.init_arg_expr = tag_int_type; | ||
| 3775 | } | ||
| 3776 | |||
| 3777 | enum_node->data.container_decl.fields.resize(field_count); | ||
| 3778 | uint32_t i = 0; | ||
| 3779 | for (auto it = enum_def->enumerator_begin(), | ||
| 3780 | it_end = enum_def->enumerator_end(); | ||
| 3781 | it != it_end; ++it, i += 1) | ||
| 3782 | { | ||
| 3783 | const EnumConstantDecl *enum_const = *it; | ||
| 3784 | |||
| 3785 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); | ||
| 3786 | Buf *field_name; | ||
| 3787 | if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) { | ||
| 3788 | field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name)); | ||
| 3789 | } else { | ||
| 3790 | field_name = enum_val_name; | ||
| 3791 | } | ||
| 3792 | |||
| 3793 | AstNode *field_node = trans_create_node(c, NodeTypeStructField); | ||
| 3794 | field_node->data.struct_field.name = field_name; | ||
| 3795 | field_node->data.struct_field.type = nullptr; | ||
| 3796 | enum_node->data.container_decl.fields.items[i] = field_node; | ||
| 3797 | |||
| 3798 | // in C each enum value is in the global namespace. so we put them there too. | ||
| 3799 | // at this point we can rely on the enum emitting successfully | ||
| 3800 | if (is_anonymous) { | ||
| 3801 | AstNode *lit_node = trans_create_node_unsigned(c, i); | ||
| 3802 | add_global_var(c, enum_val_name, lit_node); | ||
| 3803 | } else { | ||
| 3804 | AstNode *field_access_node = trans_create_node_field_access(c, | ||
| 3805 | trans_create_node_symbol(c, full_type_name), field_name); | ||
| 3806 | add_global_var(c, enum_val_name, field_access_node); | ||
| 3807 | } | ||
| 3808 | } | ||
| 3809 | |||
| 3810 | if (is_anonymous) { | ||
| 3811 | c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); | ||
| 3812 | return enum_node; | ||
| 3813 | } else { | ||
| 3814 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | ||
| 3815 | add_global_weak_alias(c, bare_name, full_type_name); | ||
| 3816 | add_global_var(c, full_type_name, enum_node); | ||
| 3817 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | ||
| 3818 | return enum_node; | ||
| 3819 | } | ||
| 3820 | } | 3774 | } |
| 3821 | 3775 | enum_node->data.container_decl.fields.resize(field_count); | |
| 3822 | // TODO after issue #305 is solved, make this be an enum with tag_int_type | 3776 | uint32_t i = 0; |
| 3823 | // as the integer type and set the custom enum values | ||
| 3824 | AstNode *enum_node = tag_int_type; | ||
| 3825 | |||
| 3826 | |||
| 3827 | // add variables for all the values with enum_node | ||
| 3828 | for (auto it = enum_def->enumerator_begin(), | 3777 | for (auto it = enum_def->enumerator_begin(), |
| 3829 | it_end = enum_def->enumerator_end(); | 3778 | it_end = enum_def->enumerator_end(); |
| 3830 | it != it_end; ++it) | 3779 | it != it_end; ++it, i += 1) |
| 3831 | { | 3780 | { |
| 3832 | const EnumConstantDecl *enum_const = *it; | 3781 | const EnumConstantDecl *enum_const = *it; |
| 3833 | 3782 | ||
| 3834 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); | 3783 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); |
| 3835 | AstNode *int_node = trans_create_node_apint(c, enum_const->getInitVal()); | 3784 | Buf *field_name; |
| 3836 | AstNode *var_node = add_global_var(c, enum_val_name, int_node); | 3785 | if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) { |
| 3837 | var_node->data.variable_declaration.type = tag_int_type; | 3786 | field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name)); |
| 3787 | } else { | ||
| 3788 | field_name = enum_val_name; | ||
| 3789 | } | ||
| 3790 | |||
| 3791 | AstNode *int_node = pure_enum && !is_anonymous ? nullptr : trans_create_node_apint(c, enum_const->getInitVal()); | ||
| 3792 | AstNode *field_node = trans_create_node(c, NodeTypeStructField); | ||
| 3793 | field_node->data.struct_field.name = field_name; | ||
| 3794 | field_node->data.struct_field.type = nullptr; | ||
| 3795 | field_node->data.struct_field.value = int_node; | ||
| 3796 | enum_node->data.container_decl.fields.items[i] = field_node; | ||
| 3797 | |||
| 3798 | // in C each enum value is in the global namespace. so we put them there too. | ||
| 3799 | // at this point we can rely on the enum emitting successfully | ||
| 3800 | if (is_anonymous) { | ||
| 3801 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); | ||
| 3802 | add_global_var(c, enum_val_name, int_node); | ||
| 3803 | } else { | ||
| 3804 | AstNode *field_access_node = trans_create_node_field_access(c, | ||
| 3805 | trans_create_node_symbol(c, full_type_name), field_name); | ||
| 3806 | add_global_var(c, enum_val_name, field_access_node); | ||
| 3807 | } | ||
| 3838 | } | 3808 | } |
| 3839 | 3809 | ||
| 3840 | if (is_anonymous) { | 3810 | if (is_anonymous) { |
| ... | @@ -3845,7 +3815,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { | ... | @@ -3845,7 +3815,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { |
| 3845 | add_global_weak_alias(c, bare_name, full_type_name); | 3815 | add_global_weak_alias(c, bare_name, full_type_name); |
| 3846 | add_global_var(c, full_type_name, enum_node); | 3816 | add_global_var(c, full_type_name, enum_node); |
| 3847 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | 3817 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); |
| 3848 | return symbol_node; | 3818 | return enum_node; |
| 3849 | } | 3819 | } |
| 3850 | } | 3820 | } |
| 3851 | 3821 |
std/array_list.zig+55-1| ... | @@ -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 | } |
| 46 | 46 | ||
| 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 been | 51 | /// 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`. |
| ... | @@ -128,6 +132,27 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ | ... | @@ -128,6 +132,27 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ |
| 128 | return null; | 132 | return null; |
| 129 | return self.pop(); | 133 | return self.pop(); |
| 130 | } | 134 | } |
| 135 | |||
| 136 | pub const Iterator = struct { | ||
| 137 | list: &const Self, | ||
| 138 | // how many items have we returned | ||
| 139 | count: usize, | ||
| 140 | |||
| 141 | pub fn next(it: &Iterator) ?T { | ||
| 142 | if (it.count >= it.list.len) return null; | ||
| 143 | const val = it.list.at(it.count); | ||
| 144 | it.count += 1; | ||
| 145 | return val; | ||
| 146 | } | ||
| 147 | |||
| 148 | pub fn reset(it: &Iterator) void { | ||
| 149 | it.count = 0; | ||
| 150 | } | ||
| 151 | }; | ||
| 152 | |||
| 153 | pub fn iterator(self: &Self) Iterator { | ||
| 154 | return Iterator { .list = self, .count = 0 }; | ||
| 155 | } | ||
| 131 | }; | 156 | }; |
| 132 | } | 157 | } |
| 133 | 158 | ||
| ... | @@ -157,6 +182,35 @@ test "basic ArrayList test" { | ... | @@ -157,6 +182,35 @@ test "basic ArrayList test" { |
| 157 | assert(list.len == 9); | 182 | assert(list.len == 9); |
| 158 | } | 183 | } |
| 159 | 184 | ||
| 185 | test "iterator ArrayList test" { | ||
| 186 | var list = ArrayList(i32).init(debug.global_allocator); | ||
| 187 | defer list.deinit(); | ||
| 188 | |||
| 189 | try list.append(1); | ||
| 190 | try list.append(2); | ||
| 191 | try list.append(3); | ||
| 192 | |||
| 193 | var count : i32 = 0; | ||
| 194 | var it = list.iterator(); | ||
| 195 | while (it.next()) |next| { | ||
| 196 | assert(next == count + 1); | ||
| 197 | count += 1; | ||
| 198 | } | ||
| 199 | |||
| 200 | assert(count == 3); | ||
| 201 | assert(it.next() == null); | ||
| 202 | it.reset(); | ||
| 203 | count = 0; | ||
| 204 | while (it.next()) |next| { | ||
| 205 | assert(next == count + 1); | ||
| 206 | count += 1; | ||
| 207 | if (count == 2) break; | ||
| 208 | } | ||
| 209 | |||
| 210 | it.reset(); | ||
| 211 | assert(?? it.next() == 1); | ||
| 212 | } | ||
| 213 | |||
| 160 | test "insert ArrayList test" { | 214 | test "insert ArrayList test" { |
| 161 | var list = ArrayList(i32).init(debug.global_allocator); | 215 | var list = ArrayList(i32).init(debug.global_allocator); |
| 162 | defer list.deinit(); | 216 | defer list.deinit(); |
| ... | @@ -174,4 +228,4 @@ test "insert ArrayList test" { | ... | @@ -174,4 +228,4 @@ test "insert ArrayList test" { |
| 174 | const items = []const i32 { 1 }; | 228 | const items = []const i32 { 1 }; |
| 175 | try list.insertSlice(0, items[0..0]); | 229 | try list.insertSlice(0, items[0..0]); |
| 176 | assert(list.items[0] == 5); | 230 | assert(list.items[0] == 5); |
| 177 | } | 231 | } |
| \ No newline at end of file | |||
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 | } |
| 32 | 32 | ||
| 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 bool | 50 | puts_done: u8, // TODO make this a bool |
| 51 | }; | 51 | }; |
| 52 | const 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 | ||
| 58 | const puts_per_thread = 500; | ||
| 53 | const put_thread_count = 3; | 59 | const put_thread_count = 3; |
| 54 | 60 | ||
| 55 | test "std.atomic.queue" { | 61 | test "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(); |
| 58 | 64 | ||
| 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); |
| 61 | 67 | ||
| 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 | } |
| 36 | 36 | ||
| 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 bool | 57 | puts_done: u8, // TODO make this a bool |
| 58 | }; | 58 | }; |
| 59 | const 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 | ||
| 64 | const puts_per_thread = 500; | ||
| 60 | const put_thread_count = 3; | 65 | const put_thread_count = 3; |
| 61 | 66 | ||
| 62 | test "std.atomic.stack" { | 67 | test "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(); |
| 65 | 70 | ||
| 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); |
| 68 | 73 | ||
| 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+2-2| ... | @@ -50,7 +50,7 @@ pub const BufMap = struct { | ... | @@ -50,7 +50,7 @@ pub const BufMap = struct { |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 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 | } |
| 55 | 55 | ||
| 56 | pub fn iterator(self: &const BufMap) BufMapHashMap.Iterator { | 56 | pub fn iterator(self: &const BufMap) BufMapHashMap.Iterator { |
| ... | @@ -87,4 +87,4 @@ test "BufMap" { | ... | @@ -87,4 +87,4 @@ test "BufMap" { |
| 87 | 87 | ||
| 88 | bufmap.delete("x"); | 88 | bufmap.delete("x"); |
| 89 | assert(0 == bufmap.count()); | 89 | assert(0 == bufmap.count()); |
| 90 | } | 90 | } |
| \ No newline at end of file | |||
std/buf_set.zig+1-2| ... | @@ -38,7 +38,7 @@ pub const BufSet = struct { | ... | @@ -38,7 +38,7 @@ pub const BufSet = struct { |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | pub fn count(self: &const BufSet) usize { | 40 | pub fn count(self: &const BufSet) usize { |
| 41 | return self.hash_map.size; | 41 | return self.hash_map.count(); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | pub fn iterator(self: &const BufSet) BufSetHashMap.Iterator { | 44 | pub fn iterator(self: &const BufSet) BufSetHashMap.Iterator { |
| ... | @@ -59,4 +59,3 @@ pub const BufSet = struct { | ... | @@ -59,4 +59,3 @@ pub const BufSet = struct { |
| 59 | return result; | 59 | return result; |
| 60 | } | 60 | } |
| 61 | }; | 61 | }; |
| 62 |
std/hash_map.zig+52-1| ... | @@ -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 item | 55 | 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 | }; |
| 58 | 66 | ||
| 59 | pub fn init(allocator: &Allocator) Self { | 67 | pub fn init(allocator: &Allocator) Self { |
| ... | @@ -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 | } |
| 81 | 89 | ||
| 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) { |
| ... | @@ -258,10 +270,49 @@ test "basic hash map usage" { | ... | @@ -258,10 +270,49 @@ test "basic hash map usage" { |
| 258 | assert(map.get(2) == null); | 270 | assert(map.get(2) == null); |
| 259 | } | 271 | } |
| 260 | 272 | ||
| 273 | test "iterator hash map" { | ||
| 274 | var direct_allocator = std.heap.DirectAllocator.init(); | ||
| 275 | defer direct_allocator.deinit(); | ||
| 276 | |||
| 277 | var reset_map = HashMap(i32, i32, hash_i32, eql_i32).init(&direct_allocator.allocator); | ||
| 278 | defer reset_map.deinit(); | ||
| 279 | |||
| 280 | assert((reset_map.put(1, 11) catch unreachable) == null); | ||
| 281 | assert((reset_map.put(2, 22) catch unreachable) == null); | ||
| 282 | assert((reset_map.put(3, 33) catch unreachable) == null); | ||
| 283 | |||
| 284 | var keys = []i32 { 1, 2, 3 }; | ||
| 285 | var values = []i32 { 11, 22, 33 }; | ||
| 286 | |||
| 287 | var it = reset_map.iterator(); | ||
| 288 | var count : usize = 0; | ||
| 289 | while (it.next()) |next| { | ||
| 290 | assert(next.key == keys[count]); | ||
| 291 | assert(next.value == values[count]); | ||
| 292 | count += 1; | ||
| 293 | } | ||
| 294 | |||
| 295 | assert(count == 3); | ||
| 296 | assert(it.next() == null); | ||
| 297 | it.reset(); | ||
| 298 | count = 0; | ||
| 299 | while (it.next()) |next| { | ||
| 300 | assert(next.key == keys[count]); | ||
| 301 | assert(next.value == values[count]); | ||
| 302 | count += 1; | ||
| 303 | if (count == 2) break; | ||
| 304 | } | ||
| 305 | |||
| 306 | it.reset(); | ||
| 307 | var entry = ?? it.next(); | ||
| 308 | assert(entry.key == keys[0]); | ||
| 309 | assert(entry.value == values[0]); | ||
| 310 | } | ||
| 311 | |||
| 261 | fn hash_i32(x: i32) u32 { | 312 | fn hash_i32(x: i32) u32 { |
| 262 | return @bitCast(u32, x); | 313 | return @bitCast(u32, x); |
| 263 | } | 314 | } |
| 264 | 315 | ||
| 265 | fn eql_i32(a: i32, b: i32) bool { | 316 | fn eql_i32(a: i32, b: i32) bool { |
| 266 | return a == b; | 317 | return a == b; |
| 267 | } | 318 | } |
| \ No newline at end of file | |||
std/index.zig+2| ... | @@ -23,6 +23,7 @@ pub const fmt = @import("fmt/index.zig"); | ... | @@ -23,6 +23,7 @@ pub const fmt = @import("fmt/index.zig"); |
| 23 | pub const hash = @import("hash/index.zig"); | 23 | pub const hash = @import("hash/index.zig"); |
| 24 | pub const heap = @import("heap.zig"); | 24 | pub const heap = @import("heap.zig"); |
| 25 | pub const io = @import("io.zig"); | 25 | pub const io = @import("io.zig"); |
| 26 | pub const json = @import("json.zig"); | ||
| 26 | pub const macho = @import("macho.zig"); | 27 | pub const macho = @import("macho.zig"); |
| 27 | pub const math = @import("math/index.zig"); | 28 | pub const math = @import("math/index.zig"); |
| 28 | pub const mem = @import("mem.zig"); | 29 | pub const mem = @import("mem.zig"); |
| ... | @@ -56,6 +57,7 @@ test "std" { | ... | @@ -56,6 +57,7 @@ test "std" { |
| 56 | _ = @import("fmt/index.zig"); | 57 | _ = @import("fmt/index.zig"); |
| 57 | _ = @import("hash/index.zig"); | 58 | _ = @import("hash/index.zig"); |
| 58 | _ = @import("io.zig"); | 59 | _ = @import("io.zig"); |
| 60 | _ = @import("json.zig"); | ||
| 59 | _ = @import("macho.zig"); | 61 | _ = @import("macho.zig"); |
| 60 | _ = @import("math/index.zig"); | 62 | _ = @import("math/index.zig"); |
| 61 | _ = @import("mem.zig"); | 63 | _ = @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 | |||
| 5 | const std = @import("index.zig"); | ||
| 6 | const mem = std.mem; | ||
| 7 | |||
| 8 | const u1 = @IntType(false, 1); | ||
| 9 | const 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. | ||
| 14 | pub 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. | ||
| 89 | const 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. | ||
| 857 | pub 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 | |||
| 872 | const Allocator = std.mem.Allocator; | ||
| 873 | const ArenaAllocator = std.heap.ArenaAllocator; | ||
| 874 | const ArrayList = std.ArrayList; | ||
| 875 | const HashMap = std.HashMap; | ||
| 876 | |||
| 877 | pub const ValueTree = struct { | ||
| 878 | arena: ArenaAllocator, | ||
| 879 | root: Value, | ||
| 880 | |||
| 881 | pub fn deinit(self: &ValueTree) void { | ||
| 882 | self.arena.deinit(); | ||
| 883 | } | ||
| 884 | }; | ||
| 885 | |||
| 886 | pub const ObjectMap = HashMap([]const u8, Value, mem.hash_slice_u8, mem.eql_slice_u8); | ||
| 887 | |||
| 888 | pub 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. | ||
| 1015 | const 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 | |||
| 1263 | const debug = std.debug; | ||
| 1264 | |||
| 1265 | test "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 | |||
| 6 | const std = @import("index.zig"); | ||
| 7 | |||
| 8 | fn ok(comptime s: []const u8) void { | ||
| 9 | std.debug.assert(std.json.validate(s)); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn err(comptime s: []const u8) void { | ||
| 13 | std.debug.assert(!std.json.validate(s)); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn any(comptime s: []const u8) void { | ||
| 17 | std.debug.assert(true); | ||
| 18 | } | ||
| 19 | |||
| 20 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 21 | |||
| 22 | test "y_array_arraysWithSpaces" { | ||
| 23 | ok( | ||
| 24 | \\[[] ] | ||
| 25 | ); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "y_array_empty" { | ||
| 29 | ok( | ||
| 30 | \\[] | ||
| 31 | ); | ||
| 32 | } | ||
| 33 | |||
| 34 | test "y_array_empty-string" { | ||
| 35 | ok( | ||
| 36 | \\[""] | ||
| 37 | ); | ||
| 38 | } | ||
| 39 | |||
| 40 | test "y_array_ending_with_newline" { | ||
| 41 | ok( | ||
| 42 | \\["a"] | ||
| 43 | ); | ||
| 44 | } | ||
| 45 | |||
| 46 | test "y_array_false" { | ||
| 47 | ok( | ||
| 48 | \\[false] | ||
| 49 | ); | ||
| 50 | } | ||
| 51 | |||
| 52 | test "y_array_heterogeneous" { | ||
| 53 | ok( | ||
| 54 | \\[null, 1, "1", {}] | ||
| 55 | ); | ||
| 56 | } | ||
| 57 | |||
| 58 | test "y_array_null" { | ||
| 59 | ok( | ||
| 60 | \\[null] | ||
| 61 | ); | ||
| 62 | } | ||
| 63 | |||
| 64 | test "y_array_with_1_and_newline" { | ||
| 65 | ok( | ||
| 66 | \\[1 | ||
| 67 | \\] | ||
| 68 | ); | ||
| 69 | } | ||
| 70 | |||
| 71 | test "y_array_with_leading_space" { | ||
| 72 | ok( | ||
| 73 | \\ [1] | ||
| 74 | ); | ||
| 75 | } | ||
| 76 | |||
| 77 | test "y_array_with_several_null" { | ||
| 78 | ok( | ||
| 79 | \\[1,null,null,null,2] | ||
| 80 | ); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "y_array_with_trailing_space" { | ||
| 84 | ok( | ||
| 85 | "[2] " | ||
| 86 | ); | ||
| 87 | } | ||
| 88 | |||
| 89 | test "y_number_0e+1" { | ||
| 90 | ok( | ||
| 91 | \\[0e+1] | ||
| 92 | ); | ||
| 93 | } | ||
| 94 | |||
| 95 | test "y_number_0e1" { | ||
| 96 | ok( | ||
| 97 | \\[0e1] | ||
| 98 | ); | ||
| 99 | } | ||
| 100 | |||
| 101 | test "y_number_after_space" { | ||
| 102 | ok( | ||
| 103 | \\[ 4] | ||
| 104 | ); | ||
| 105 | } | ||
| 106 | |||
| 107 | test "y_number_double_close_to_zero" { | ||
| 108 | ok( | ||
| 109 | \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] | ||
| 110 | ); | ||
| 111 | } | ||
| 112 | |||
| 113 | test "y_number_int_with_exp" { | ||
| 114 | ok( | ||
| 115 | \\[20e1] | ||
| 116 | ); | ||
| 117 | } | ||
| 118 | |||
| 119 | test "y_number" { | ||
| 120 | ok( | ||
| 121 | \\[123e65] | ||
| 122 | ); | ||
| 123 | } | ||
| 124 | |||
| 125 | test "y_number_minus_zero" { | ||
| 126 | ok( | ||
| 127 | \\[-0] | ||
| 128 | ); | ||
| 129 | } | ||
| 130 | |||
| 131 | test "y_number_negative_int" { | ||
| 132 | ok( | ||
| 133 | \\[-123] | ||
| 134 | ); | ||
| 135 | } | ||
| 136 | |||
| 137 | test "y_number_negative_one" { | ||
| 138 | ok( | ||
| 139 | \\[-1] | ||
| 140 | ); | ||
| 141 | } | ||
| 142 | |||
| 143 | test "y_number_negative_zero" { | ||
| 144 | ok( | ||
| 145 | \\[-0] | ||
| 146 | ); | ||
| 147 | } | ||
| 148 | |||
| 149 | test "y_number_real_capital_e" { | ||
| 150 | ok( | ||
| 151 | \\[1E22] | ||
| 152 | ); | ||
| 153 | } | ||
| 154 | |||
| 155 | test "y_number_real_capital_e_neg_exp" { | ||
| 156 | ok( | ||
| 157 | \\[1E-2] | ||
| 158 | ); | ||
| 159 | } | ||
| 160 | |||
| 161 | test "y_number_real_capital_e_pos_exp" { | ||
| 162 | ok( | ||
| 163 | \\[1E+2] | ||
| 164 | ); | ||
| 165 | } | ||
| 166 | |||
| 167 | test "y_number_real_exponent" { | ||
| 168 | ok( | ||
| 169 | \\[123e45] | ||
| 170 | ); | ||
| 171 | } | ||
| 172 | |||
| 173 | test "y_number_real_fraction_exponent" { | ||
| 174 | ok( | ||
| 175 | \\[123.456e78] | ||
| 176 | ); | ||
| 177 | } | ||
| 178 | |||
| 179 | test "y_number_real_neg_exp" { | ||
| 180 | ok( | ||
| 181 | \\[1e-2] | ||
| 182 | ); | ||
| 183 | } | ||
| 184 | |||
| 185 | test "y_number_real_pos_exponent" { | ||
| 186 | ok( | ||
| 187 | \\[1e+2] | ||
| 188 | ); | ||
| 189 | } | ||
| 190 | |||
| 191 | test "y_number_simple_int" { | ||
| 192 | ok( | ||
| 193 | \\[123] | ||
| 194 | ); | ||
| 195 | } | ||
| 196 | |||
| 197 | test "y_number_simple_real" { | ||
| 198 | ok( | ||
| 199 | \\[123.456789] | ||
| 200 | ); | ||
| 201 | } | ||
| 202 | |||
| 203 | test "y_object_basic" { | ||
| 204 | ok( | ||
| 205 | \\{"asd":"sdf"} | ||
| 206 | ); | ||
| 207 | } | ||
| 208 | |||
| 209 | test "y_object_duplicated_key_and_value" { | ||
| 210 | ok( | ||
| 211 | \\{"a":"b","a":"b"} | ||
| 212 | ); | ||
| 213 | } | ||
| 214 | |||
| 215 | test "y_object_duplicated_key" { | ||
| 216 | ok( | ||
| 217 | \\{"a":"b","a":"c"} | ||
| 218 | ); | ||
| 219 | } | ||
| 220 | |||
| 221 | test "y_object_empty" { | ||
| 222 | ok( | ||
| 223 | \\{} | ||
| 224 | ); | ||
| 225 | } | ||
| 226 | |||
| 227 | test "y_object_empty_key" { | ||
| 228 | ok( | ||
| 229 | \\{"":0} | ||
| 230 | ); | ||
| 231 | } | ||
| 232 | |||
| 233 | test "y_object_escaped_null_in_key" { | ||
| 234 | ok( | ||
| 235 | \\{"foo\u0000bar": 42} | ||
| 236 | ); | ||
| 237 | } | ||
| 238 | |||
| 239 | test "y_object_extreme_numbers" { | ||
| 240 | ok( | ||
| 241 | \\{ "min": -1.0e+28, "max": 1.0e+28 } | ||
| 242 | ); | ||
| 243 | } | ||
| 244 | |||
| 245 | test "y_object" { | ||
| 246 | ok( | ||
| 247 | \\{"asd":"sdf", "dfg":"fgh"} | ||
| 248 | ); | ||
| 249 | } | ||
| 250 | |||
| 251 | test "y_object_long_strings" { | ||
| 252 | ok( | ||
| 253 | \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} | ||
| 254 | ); | ||
| 255 | } | ||
| 256 | |||
| 257 | test "y_object_simple" { | ||
| 258 | ok( | ||
| 259 | \\{"a":[]} | ||
| 260 | ); | ||
| 261 | } | ||
| 262 | |||
| 263 | test "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 | |||
| 269 | test "y_object_with_newlines" { | ||
| 270 | ok( | ||
| 271 | \\{ | ||
| 272 | \\"a": "b" | ||
| 273 | \\} | ||
| 274 | ); | ||
| 275 | } | ||
| 276 | |||
| 277 | test "y_string_1_2_3_bytes_UTF-8_sequences" { | ||
| 278 | ok( | ||
| 279 | \\["\u0060\u012a\u12AB"] | ||
| 280 | ); | ||
| 281 | } | ||
| 282 | |||
| 283 | test "y_string_accepted_surrogate_pair" { | ||
| 284 | ok( | ||
| 285 | \\["\uD801\udc37"] | ||
| 286 | ); | ||
| 287 | } | ||
| 288 | |||
| 289 | test "y_string_accepted_surrogate_pairs" { | ||
| 290 | ok( | ||
| 291 | \\["\ud83d\ude39\ud83d\udc8d"] | ||
| 292 | ); | ||
| 293 | } | ||
| 294 | |||
| 295 | test "y_string_allowed_escapes" { | ||
| 296 | ok( | ||
| 297 | \\["\"\\\/\b\f\n\r\t"] | ||
| 298 | ); | ||
| 299 | } | ||
| 300 | |||
| 301 | test "y_string_backslash_and_u_escaped_zero" { | ||
| 302 | ok( | ||
| 303 | \\["\\u0000"] | ||
| 304 | ); | ||
| 305 | } | ||
| 306 | |||
| 307 | test "y_string_backslash_doublequotes" { | ||
| 308 | ok( | ||
| 309 | \\["\""] | ||
| 310 | ); | ||
| 311 | } | ||
| 312 | |||
| 313 | test "y_string_comments" { | ||
| 314 | ok( | ||
| 315 | \\["a/*b*/c/*d//e"] | ||
| 316 | ); | ||
| 317 | } | ||
| 318 | |||
| 319 | test "y_string_double_escape_a" { | ||
| 320 | ok( | ||
| 321 | \\["\\a"] | ||
| 322 | ); | ||
| 323 | } | ||
| 324 | |||
| 325 | test "y_string_double_escape_n" { | ||
| 326 | ok( | ||
| 327 | \\["\\n"] | ||
| 328 | ); | ||
| 329 | } | ||
| 330 | |||
| 331 | test "y_string_escaped_control_character" { | ||
| 332 | ok( | ||
| 333 | \\["\u0012"] | ||
| 334 | ); | ||
| 335 | } | ||
| 336 | |||
| 337 | test "y_string_escaped_noncharacter" { | ||
| 338 | ok( | ||
| 339 | \\["\uFFFF"] | ||
| 340 | ); | ||
| 341 | } | ||
| 342 | |||
| 343 | test "y_string_in_array" { | ||
| 344 | ok( | ||
| 345 | \\["asd"] | ||
| 346 | ); | ||
| 347 | } | ||
| 348 | |||
| 349 | test "y_string_in_array_with_leading_space" { | ||
| 350 | ok( | ||
| 351 | \\[ "asd"] | ||
| 352 | ); | ||
| 353 | } | ||
| 354 | |||
| 355 | test "y_string_last_surrogates_1_and_2" { | ||
| 356 | ok( | ||
| 357 | \\["\uDBFF\uDFFF"] | ||
| 358 | ); | ||
| 359 | } | ||
| 360 | |||
| 361 | test "y_string_nbsp_uescaped" { | ||
| 362 | ok( | ||
| 363 | \\["new\u00A0line"] | ||
| 364 | ); | ||
| 365 | } | ||
| 366 | |||
| 367 | test "y_string_nonCharacterInUTF-8_U+10FFFF" { | ||
| 368 | ok( | ||
| 369 | \\[""] | ||
| 370 | ); | ||
| 371 | } | ||
| 372 | |||
| 373 | test "y_string_nonCharacterInUTF-8_U+FFFF" { | ||
| 374 | ok( | ||
| 375 | \\[""] | ||
| 376 | ); | ||
| 377 | } | ||
| 378 | |||
| 379 | test "y_string_null_escape" { | ||
| 380 | ok( | ||
| 381 | \\["\u0000"] | ||
| 382 | ); | ||
| 383 | } | ||
| 384 | |||
| 385 | test "y_string_one-byte-utf-8" { | ||
| 386 | ok( | ||
| 387 | \\["\u002c"] | ||
| 388 | ); | ||
| 389 | } | ||
| 390 | |||
| 391 | test "y_string_pi" { | ||
| 392 | ok( | ||
| 393 | \\["π"] | ||
| 394 | ); | ||
| 395 | } | ||
| 396 | |||
| 397 | test "y_string_reservedCharacterInUTF-8_U+1BFFF" { | ||
| 398 | ok( | ||
| 399 | \\[""] | ||
| 400 | ); | ||
| 401 | } | ||
| 402 | |||
| 403 | test "y_string_simple_ascii" { | ||
| 404 | ok( | ||
| 405 | \\["asd "] | ||
| 406 | ); | ||
| 407 | } | ||
| 408 | |||
| 409 | test "y_string_space" { | ||
| 410 | ok( | ||
| 411 | \\" " | ||
| 412 | ); | ||
| 413 | } | ||
| 414 | |||
| 415 | test "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" { | ||
| 416 | ok( | ||
| 417 | \\["\uD834\uDd1e"] | ||
| 418 | ); | ||
| 419 | } | ||
| 420 | |||
| 421 | test "y_string_three-byte-utf-8" { | ||
| 422 | ok( | ||
| 423 | \\["\u0821"] | ||
| 424 | ); | ||
| 425 | } | ||
| 426 | |||
| 427 | test "y_string_two-byte-utf-8" { | ||
| 428 | ok( | ||
| 429 | \\["\u0123"] | ||
| 430 | ); | ||
| 431 | } | ||
| 432 | |||
| 433 | test "y_string_u+2028_line_sep" { | ||
| 434 | ok( | ||
| 435 | \\[" "] | ||
| 436 | ); | ||
| 437 | } | ||
| 438 | |||
| 439 | test "y_string_u+2029_par_sep" { | ||
| 440 | ok( | ||
| 441 | \\[" "] | ||
| 442 | ); | ||
| 443 | } | ||
| 444 | |||
| 445 | test "y_string_uescaped_newline" { | ||
| 446 | ok( | ||
| 447 | \\["new\u000Aline"] | ||
| 448 | ); | ||
| 449 | } | ||
| 450 | |||
| 451 | test "y_string_uEscape" { | ||
| 452 | ok( | ||
| 453 | \\["\u0061\u30af\u30EA\u30b9"] | ||
| 454 | ); | ||
| 455 | } | ||
| 456 | |||
| 457 | test "y_string_unescaped_char_delete" { | ||
| 458 | ok( | ||
| 459 | \\[""] | ||
| 460 | ); | ||
| 461 | } | ||
| 462 | |||
| 463 | test "y_string_unicode_2" { | ||
| 464 | ok( | ||
| 465 | \\["⍂㈴⍂"] | ||
| 466 | ); | ||
| 467 | } | ||
| 468 | |||
| 469 | test "y_string_unicodeEscapedBackslash" { | ||
| 470 | ok( | ||
| 471 | \\["\u005C"] | ||
| 472 | ); | ||
| 473 | } | ||
| 474 | |||
| 475 | test "y_string_unicode_escaped_double_quote" { | ||
| 476 | ok( | ||
| 477 | \\["\u0022"] | ||
| 478 | ); | ||
| 479 | } | ||
| 480 | |||
| 481 | test "y_string_unicode" { | ||
| 482 | ok( | ||
| 483 | \\["\uA66D"] | ||
| 484 | ); | ||
| 485 | } | ||
| 486 | |||
| 487 | test "y_string_unicode_U+10FFFE_nonchar" { | ||
| 488 | ok( | ||
| 489 | \\["\uDBFF\uDFFE"] | ||
| 490 | ); | ||
| 491 | } | ||
| 492 | |||
| 493 | test "y_string_unicode_U+1FFFE_nonchar" { | ||
| 494 | ok( | ||
| 495 | \\["\uD83F\uDFFE"] | ||
| 496 | ); | ||
| 497 | } | ||
| 498 | |||
| 499 | test "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" { | ||
| 500 | ok( | ||
| 501 | \\["\u200B"] | ||
| 502 | ); | ||
| 503 | } | ||
| 504 | |||
| 505 | test "y_string_unicode_U+2064_invisible_plus" { | ||
| 506 | ok( | ||
| 507 | \\["\u2064"] | ||
| 508 | ); | ||
| 509 | } | ||
| 510 | |||
| 511 | test "y_string_unicode_U+FDD0_nonchar" { | ||
| 512 | ok( | ||
| 513 | \\["\uFDD0"] | ||
| 514 | ); | ||
| 515 | } | ||
| 516 | |||
| 517 | test "y_string_unicode_U+FFFE_nonchar" { | ||
| 518 | ok( | ||
| 519 | \\["\uFFFE"] | ||
| 520 | ); | ||
| 521 | } | ||
| 522 | |||
| 523 | test "y_string_utf8" { | ||
| 524 | ok( | ||
| 525 | \\["€𝄞"] | ||
| 526 | ); | ||
| 527 | } | ||
| 528 | |||
| 529 | test "y_string_with_del_character" { | ||
| 530 | ok( | ||
| 531 | \\["aa"] | ||
| 532 | ); | ||
| 533 | } | ||
| 534 | |||
| 535 | test "y_structure_lonely_false" { | ||
| 536 | ok( | ||
| 537 | \\false | ||
| 538 | ); | ||
| 539 | } | ||
| 540 | |||
| 541 | test "y_structure_lonely_int" { | ||
| 542 | ok( | ||
| 543 | \\42 | ||
| 544 | ); | ||
| 545 | } | ||
| 546 | |||
| 547 | test "y_structure_lonely_negative_real" { | ||
| 548 | ok( | ||
| 549 | \\-0.1 | ||
| 550 | ); | ||
| 551 | } | ||
| 552 | |||
| 553 | test "y_structure_lonely_null" { | ||
| 554 | ok( | ||
| 555 | \\null | ||
| 556 | ); | ||
| 557 | } | ||
| 558 | |||
| 559 | test "y_structure_lonely_string" { | ||
| 560 | ok( | ||
| 561 | \\"asd" | ||
| 562 | ); | ||
| 563 | } | ||
| 564 | |||
| 565 | test "y_structure_lonely_true" { | ||
| 566 | ok( | ||
| 567 | \\true | ||
| 568 | ); | ||
| 569 | } | ||
| 570 | |||
| 571 | test "y_structure_string_empty" { | ||
| 572 | ok( | ||
| 573 | \\"" | ||
| 574 | ); | ||
| 575 | } | ||
| 576 | |||
| 577 | test "y_structure_trailing_newline" { | ||
| 578 | ok( | ||
| 579 | \\["a"] | ||
| 580 | ); | ||
| 581 | } | ||
| 582 | |||
| 583 | test "y_structure_true_in_array" { | ||
| 584 | ok( | ||
| 585 | \\[true] | ||
| 586 | ); | ||
| 587 | } | ||
| 588 | |||
| 589 | test "y_structure_whitespace_array" { | ||
| 590 | ok( | ||
| 591 | " [] " | ||
| 592 | ); | ||
| 593 | } | ||
| 594 | |||
| 595 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 596 | |||
| 597 | test "n_array_1_true_without_comma" { | ||
| 598 | err( | ||
| 599 | \\[1 true] | ||
| 600 | ); | ||
| 601 | } | ||
| 602 | |||
| 603 | test "n_array_a_invalid_utf8" { | ||
| 604 | err( | ||
| 605 | \\[aå] | ||
| 606 | ); | ||
| 607 | } | ||
| 608 | |||
| 609 | test "n_array_colon_instead_of_comma" { | ||
| 610 | err( | ||
| 611 | \\["": 1] | ||
| 612 | ); | ||
| 613 | } | ||
| 614 | |||
| 615 | test "n_array_comma_after_close" { | ||
| 616 | //err( | ||
| 617 | // \\[""], | ||
| 618 | //); | ||
| 619 | } | ||
| 620 | |||
| 621 | test "n_array_comma_and_number" { | ||
| 622 | err( | ||
| 623 | \\[,1] | ||
| 624 | ); | ||
| 625 | } | ||
| 626 | |||
| 627 | test "n_array_double_comma" { | ||
| 628 | err( | ||
| 629 | \\[1,,2] | ||
| 630 | ); | ||
| 631 | } | ||
| 632 | |||
| 633 | test "n_array_double_extra_comma" { | ||
| 634 | err( | ||
| 635 | \\["x",,] | ||
| 636 | ); | ||
| 637 | } | ||
| 638 | |||
| 639 | test "n_array_extra_close" { | ||
| 640 | err( | ||
| 641 | \\["x"]] | ||
| 642 | ); | ||
| 643 | } | ||
| 644 | |||
| 645 | test "n_array_extra_comma" { | ||
| 646 | //err( | ||
| 647 | // \\["",] | ||
| 648 | //); | ||
| 649 | } | ||
| 650 | |||
| 651 | test "n_array_incomplete_invalid_value" { | ||
| 652 | err( | ||
| 653 | \\[x | ||
| 654 | ); | ||
| 655 | } | ||
| 656 | |||
| 657 | test "n_array_incomplete" { | ||
| 658 | err( | ||
| 659 | \\["x" | ||
| 660 | ); | ||
| 661 | } | ||
| 662 | |||
| 663 | test "n_array_inner_array_no_comma" { | ||
| 664 | err( | ||
| 665 | \\[3[4]] | ||
| 666 | ); | ||
| 667 | } | ||
| 668 | |||
| 669 | test "n_array_invalid_utf8" { | ||
| 670 | err( | ||
| 671 | \\[ÿ] | ||
| 672 | ); | ||
| 673 | } | ||
| 674 | |||
| 675 | test "n_array_items_separated_by_semicolon" { | ||
| 676 | err( | ||
| 677 | \\[1:2] | ||
| 678 | ); | ||
| 679 | } | ||
| 680 | |||
| 681 | test "n_array_just_comma" { | ||
| 682 | err( | ||
| 683 | \\[,] | ||
| 684 | ); | ||
| 685 | } | ||
| 686 | |||
| 687 | test "n_array_just_minus" { | ||
| 688 | err( | ||
| 689 | \\[-] | ||
| 690 | ); | ||
| 691 | } | ||
| 692 | |||
| 693 | test "n_array_missing_value" { | ||
| 694 | err( | ||
| 695 | \\[ , ""] | ||
| 696 | ); | ||
| 697 | } | ||
| 698 | |||
| 699 | test "n_array_newlines_unclosed" { | ||
| 700 | err( | ||
| 701 | \\["a", | ||
| 702 | \\4 | ||
| 703 | \\,1, | ||
| 704 | ); | ||
| 705 | } | ||
| 706 | |||
| 707 | |||
| 708 | test "n_array_number_and_comma" { | ||
| 709 | err( | ||
| 710 | \\[1,] | ||
| 711 | ); | ||
| 712 | } | ||
| 713 | |||
| 714 | test "n_array_number_and_several_commas" { | ||
| 715 | err( | ||
| 716 | \\[1,,] | ||
| 717 | ); | ||
| 718 | } | ||
| 719 | |||
| 720 | test "n_array_spaces_vertical_tab_formfeed" { | ||
| 721 | err( | ||
| 722 | \\["a"\f] | ||
| 723 | ); | ||
| 724 | } | ||
| 725 | |||
| 726 | test "n_array_star_inside" { | ||
| 727 | err( | ||
| 728 | \\[*] | ||
| 729 | ); | ||
| 730 | } | ||
| 731 | |||
| 732 | test "n_array_unclosed" { | ||
| 733 | err( | ||
| 734 | \\["" | ||
| 735 | ); | ||
| 736 | } | ||
| 737 | |||
| 738 | test "n_array_unclosed_trailing_comma" { | ||
| 739 | err( | ||
| 740 | \\[1, | ||
| 741 | ); | ||
| 742 | } | ||
| 743 | |||
| 744 | test "n_array_unclosed_with_new_lines" { | ||
| 745 | err( | ||
| 746 | \\[1, | ||
| 747 | \\1 | ||
| 748 | \\,1 | ||
| 749 | ); | ||
| 750 | } | ||
| 751 | |||
| 752 | test "n_array_unclosed_with_object_inside" { | ||
| 753 | err( | ||
| 754 | \\[{} | ||
| 755 | ); | ||
| 756 | } | ||
| 757 | |||
| 758 | test "n_incomplete_false" { | ||
| 759 | err( | ||
| 760 | \\[fals] | ||
| 761 | ); | ||
| 762 | } | ||
| 763 | |||
| 764 | test "n_incomplete_null" { | ||
| 765 | err( | ||
| 766 | \\[nul] | ||
| 767 | ); | ||
| 768 | } | ||
| 769 | |||
| 770 | test "n_incomplete_true" { | ||
| 771 | err( | ||
| 772 | \\[tru] | ||
| 773 | ); | ||
| 774 | } | ||
| 775 | |||
| 776 | test "n_multidigit_number_then_00" { | ||
| 777 | err( | ||
| 778 | \\123 | ||
| 779 | ); | ||
| 780 | } | ||
| 781 | |||
| 782 | test "n_number_0.1.2" { | ||
| 783 | err( | ||
| 784 | \\[0.1.2] | ||
| 785 | ); | ||
| 786 | } | ||
| 787 | |||
| 788 | test "n_number_-01" { | ||
| 789 | err( | ||
| 790 | \\[-01] | ||
| 791 | ); | ||
| 792 | } | ||
| 793 | |||
| 794 | test "n_number_0.3e" { | ||
| 795 | err( | ||
| 796 | \\[0.3e] | ||
| 797 | ); | ||
| 798 | } | ||
| 799 | |||
| 800 | test "n_number_0.3e+" { | ||
| 801 | err( | ||
| 802 | \\[0.3e+] | ||
| 803 | ); | ||
| 804 | } | ||
| 805 | |||
| 806 | test "n_number_0_capital_E" { | ||
| 807 | err( | ||
| 808 | \\[0E] | ||
| 809 | ); | ||
| 810 | } | ||
| 811 | |||
| 812 | test "n_number_0_capital_E+" { | ||
| 813 | err( | ||
| 814 | \\[0E+] | ||
| 815 | ); | ||
| 816 | } | ||
| 817 | |||
| 818 | test "n_number_0.e1" { | ||
| 819 | err( | ||
| 820 | \\[0.e1] | ||
| 821 | ); | ||
| 822 | } | ||
| 823 | |||
| 824 | test "n_number_0e" { | ||
| 825 | err( | ||
| 826 | \\[0e] | ||
| 827 | ); | ||
| 828 | } | ||
| 829 | |||
| 830 | test "n_number_0e+" { | ||
| 831 | err( | ||
| 832 | \\[0e+] | ||
| 833 | ); | ||
| 834 | } | ||
| 835 | |||
| 836 | test "n_number_1_000" { | ||
| 837 | err( | ||
| 838 | \\[1 000.0] | ||
| 839 | ); | ||
| 840 | } | ||
| 841 | |||
| 842 | test "n_number_1.0e-" { | ||
| 843 | err( | ||
| 844 | \\[1.0e-] | ||
| 845 | ); | ||
| 846 | } | ||
| 847 | |||
| 848 | test "n_number_1.0e" { | ||
| 849 | err( | ||
| 850 | \\[1.0e] | ||
| 851 | ); | ||
| 852 | } | ||
| 853 | |||
| 854 | test "n_number_1.0e+" { | ||
| 855 | err( | ||
| 856 | \\[1.0e+] | ||
| 857 | ); | ||
| 858 | } | ||
| 859 | |||
| 860 | test "n_number_-1.0." { | ||
| 861 | err( | ||
| 862 | \\[-1.0.] | ||
| 863 | ); | ||
| 864 | } | ||
| 865 | |||
| 866 | test "n_number_1eE2" { | ||
| 867 | err( | ||
| 868 | \\[1eE2] | ||
| 869 | ); | ||
| 870 | } | ||
| 871 | |||
| 872 | test "n_number_.-1" { | ||
| 873 | err( | ||
| 874 | \\[.-1] | ||
| 875 | ); | ||
| 876 | } | ||
| 877 | |||
| 878 | test "n_number_+1" { | ||
| 879 | err( | ||
| 880 | \\[+1] | ||
| 881 | ); | ||
| 882 | } | ||
| 883 | |||
| 884 | test "n_number_.2e-3" { | ||
| 885 | err( | ||
| 886 | \\[.2e-3] | ||
| 887 | ); | ||
| 888 | } | ||
| 889 | |||
| 890 | test "n_number_2.e-3" { | ||
| 891 | err( | ||
| 892 | \\[2.e-3] | ||
| 893 | ); | ||
| 894 | } | ||
| 895 | |||
| 896 | test "n_number_2.e+3" { | ||
| 897 | err( | ||
| 898 | \\[2.e+3] | ||
| 899 | ); | ||
| 900 | } | ||
| 901 | |||
| 902 | test "n_number_2.e3" { | ||
| 903 | err( | ||
| 904 | \\[2.e3] | ||
| 905 | ); | ||
| 906 | } | ||
| 907 | |||
| 908 | test "n_number_-2." { | ||
| 909 | err( | ||
| 910 | \\[-2.] | ||
| 911 | ); | ||
| 912 | } | ||
| 913 | |||
| 914 | test "n_number_9.e+" { | ||
| 915 | err( | ||
| 916 | \\[9.e+] | ||
| 917 | ); | ||
| 918 | } | ||
| 919 | |||
| 920 | test "n_number_expression" { | ||
| 921 | err( | ||
| 922 | \\[1+2] | ||
| 923 | ); | ||
| 924 | } | ||
| 925 | |||
| 926 | test "n_number_hex_1_digit" { | ||
| 927 | err( | ||
| 928 | \\[0x1] | ||
| 929 | ); | ||
| 930 | } | ||
| 931 | |||
| 932 | test "n_number_hex_2_digits" { | ||
| 933 | err( | ||
| 934 | \\[0x42] | ||
| 935 | ); | ||
| 936 | } | ||
| 937 | |||
| 938 | test "n_number_infinity" { | ||
| 939 | err( | ||
| 940 | \\[Infinity] | ||
| 941 | ); | ||
| 942 | } | ||
| 943 | |||
| 944 | test "n_number_+Inf" { | ||
| 945 | err( | ||
| 946 | \\[+Inf] | ||
| 947 | ); | ||
| 948 | } | ||
| 949 | |||
| 950 | test "n_number_Inf" { | ||
| 951 | err( | ||
| 952 | \\[Inf] | ||
| 953 | ); | ||
| 954 | } | ||
| 955 | |||
| 956 | test "n_number_invalid+-" { | ||
| 957 | err( | ||
| 958 | \\[0e+-1] | ||
| 959 | ); | ||
| 960 | } | ||
| 961 | |||
| 962 | test "n_number_invalid-negative-real" { | ||
| 963 | err( | ||
| 964 | \\[-123.123foo] | ||
| 965 | ); | ||
| 966 | } | ||
| 967 | |||
| 968 | test "n_number_invalid-utf-8-in-bigger-int" { | ||
| 969 | err( | ||
| 970 | \\[123å] | ||
| 971 | ); | ||
| 972 | } | ||
| 973 | |||
| 974 | test "n_number_invalid-utf-8-in-exponent" { | ||
| 975 | err( | ||
| 976 | \\[1e1å] | ||
| 977 | ); | ||
| 978 | } | ||
| 979 | |||
| 980 | test "n_number_invalid-utf-8-in-int" { | ||
| 981 | err( | ||
| 982 | \\[0å] | ||
| 983 | ); | ||
| 984 | } | ||
| 985 | |||
| 986 | |||
| 987 | test "n_number_++" { | ||
| 988 | err( | ||
| 989 | \\[++1234] | ||
| 990 | ); | ||
| 991 | } | ||
| 992 | |||
| 993 | test "n_number_minus_infinity" { | ||
| 994 | err( | ||
| 995 | \\[-Infinity] | ||
| 996 | ); | ||
| 997 | } | ||
| 998 | |||
| 999 | test "n_number_minus_sign_with_trailing_garbage" { | ||
| 1000 | err( | ||
| 1001 | \\[-foo] | ||
| 1002 | ); | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | test "n_number_minus_space_1" { | ||
| 1006 | err( | ||
| 1007 | \\[- 1] | ||
| 1008 | ); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | test "n_number_-NaN" { | ||
| 1012 | err( | ||
| 1013 | \\[-NaN] | ||
| 1014 | ); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | test "n_number_NaN" { | ||
| 1018 | err( | ||
| 1019 | \\[NaN] | ||
| 1020 | ); | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | test "n_number_neg_int_starting_with_zero" { | ||
| 1024 | err( | ||
| 1025 | \\[-012] | ||
| 1026 | ); | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | test "n_number_neg_real_without_int_part" { | ||
| 1030 | err( | ||
| 1031 | \\[-.123] | ||
| 1032 | ); | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | test "n_number_neg_with_garbage_at_end" { | ||
| 1036 | err( | ||
| 1037 | \\[-1x] | ||
| 1038 | ); | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | test "n_number_real_garbage_after_e" { | ||
| 1042 | err( | ||
| 1043 | \\[1ea] | ||
| 1044 | ); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | test "n_number_real_with_invalid_utf8_after_e" { | ||
| 1048 | err( | ||
| 1049 | \\[1eå] | ||
| 1050 | ); | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | test "n_number_real_without_fractional_part" { | ||
| 1054 | err( | ||
| 1055 | \\[1.] | ||
| 1056 | ); | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | test "n_number_starting_with_dot" { | ||
| 1060 | err( | ||
| 1061 | \\[.123] | ||
| 1062 | ); | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | test "n_number_U+FF11_fullwidth_digit_one" { | ||
| 1066 | err( | ||
| 1067 | \\[ï¼] | ||
| 1068 | ); | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | test "n_number_with_alpha_char" { | ||
| 1072 | err( | ||
| 1073 | \\[1.8011670033376514H-308] | ||
| 1074 | ); | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | test "n_number_with_alpha" { | ||
| 1078 | err( | ||
| 1079 | \\[1.2a-3] | ||
| 1080 | ); | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | test "n_number_with_leading_zero" { | ||
| 1084 | err( | ||
| 1085 | \\[012] | ||
| 1086 | ); | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | test "n_object_bad_value" { | ||
| 1090 | err( | ||
| 1091 | \\["x", truth] | ||
| 1092 | ); | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | test "n_object_bracket_key" { | ||
| 1096 | err( | ||
| 1097 | \\{[: "x"} | ||
| 1098 | ); | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | test "n_object_comma_instead_of_colon" { | ||
| 1102 | err( | ||
| 1103 | \\{"x", null} | ||
| 1104 | ); | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | test "n_object_double_colon" { | ||
| 1108 | err( | ||
| 1109 | \\{"x"::"b"} | ||
| 1110 | ); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | test "n_object_emoji" { | ||
| 1114 | err( | ||
| 1115 | \\{ð¨ð} | ||
| 1116 | ); | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | test "n_object_garbage_at_end" { | ||
| 1120 | err( | ||
| 1121 | \\{"a":"a" 123} | ||
| 1122 | ); | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | test "n_object_key_with_single_quotes" { | ||
| 1126 | err( | ||
| 1127 | \\{key: 'value'} | ||
| 1128 | ); | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | test "n_object_lone_continuation_byte_in_key_and_trailing_comma" { | ||
| 1132 | err( | ||
| 1133 | \\{"¹":"0",} | ||
| 1134 | ); | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | test "n_object_missing_colon" { | ||
| 1138 | err( | ||
| 1139 | \\{"a" b} | ||
| 1140 | ); | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | test "n_object_missing_key" { | ||
| 1144 | err( | ||
| 1145 | \\{:"b"} | ||
| 1146 | ); | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | test "n_object_missing_semicolon" { | ||
| 1150 | err( | ||
| 1151 | \\{"a" "b"} | ||
| 1152 | ); | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | test "n_object_missing_value" { | ||
| 1156 | err( | ||
| 1157 | \\{"a": | ||
| 1158 | ); | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | test "n_object_no-colon" { | ||
| 1162 | err( | ||
| 1163 | \\{"a" | ||
| 1164 | ); | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | test "n_object_non_string_key_but_huge_number_instead" { | ||
| 1168 | err( | ||
| 1169 | \\{9999E9999:1} | ||
| 1170 | ); | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | test "n_object_non_string_key" { | ||
| 1174 | err( | ||
| 1175 | \\{1:1} | ||
| 1176 | ); | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | test "n_object_repeated_null_null" { | ||
| 1180 | err( | ||
| 1181 | \\{null:null,null:null} | ||
| 1182 | ); | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | test "n_object_several_trailing_commas" { | ||
| 1186 | err( | ||
| 1187 | \\{"id":0,,,,,} | ||
| 1188 | ); | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | test "n_object_single_quote" { | ||
| 1192 | err( | ||
| 1193 | \\{'a':0} | ||
| 1194 | ); | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | test "n_object_trailing_comma" { | ||
| 1198 | err( | ||
| 1199 | \\{"id":0,} | ||
| 1200 | ); | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | test "n_object_trailing_comment" { | ||
| 1204 | err( | ||
| 1205 | \\{"a":"b"}/**/ | ||
| 1206 | ); | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | test "n_object_trailing_comment_open" { | ||
| 1210 | err( | ||
| 1211 | \\{"a":"b"}/**// | ||
| 1212 | ); | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | test "n_object_trailing_comment_slash_open_incomplete" { | ||
| 1216 | err( | ||
| 1217 | \\{"a":"b"}/ | ||
| 1218 | ); | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | test "n_object_trailing_comment_slash_open" { | ||
| 1222 | err( | ||
| 1223 | \\{"a":"b"}// | ||
| 1224 | ); | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | test "n_object_two_commas_in_a_row" { | ||
| 1228 | err( | ||
| 1229 | \\{"a":"b",,"c":"d"} | ||
| 1230 | ); | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | test "n_object_unquoted_key" { | ||
| 1234 | err( | ||
| 1235 | \\{a: "b"} | ||
| 1236 | ); | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | test "n_object_unterminated-value" { | ||
| 1240 | err( | ||
| 1241 | \\{"a":"a | ||
| 1242 | ); | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | test "n_object_with_single_string" { | ||
| 1246 | err( | ||
| 1247 | \\{ "foo" : "bar", "a" } | ||
| 1248 | ); | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | test "n_object_with_trailing_garbage" { | ||
| 1252 | err( | ||
| 1253 | \\{"a":"b"}# | ||
| 1254 | ); | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | test "n_single_space" { | ||
| 1258 | err( | ||
| 1259 | " " | ||
| 1260 | ); | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | test "n_string_1_surrogate_then_escape" { | ||
| 1264 | err( | ||
| 1265 | \\["\uD800\"] | ||
| 1266 | ); | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | test "n_string_1_surrogate_then_escape_u1" { | ||
| 1270 | err( | ||
| 1271 | \\["\uD800\u1"] | ||
| 1272 | ); | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | test "n_string_1_surrogate_then_escape_u1x" { | ||
| 1276 | err( | ||
| 1277 | \\["\uD800\u1x"] | ||
| 1278 | ); | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | test "n_string_1_surrogate_then_escape_u" { | ||
| 1282 | err( | ||
| 1283 | \\["\uD800\u"] | ||
| 1284 | ); | ||
| 1285 | } | ||
| 1286 | |||
| 1287 | test "n_string_accentuated_char_no_quotes" { | ||
| 1288 | err( | ||
| 1289 | \\[é] | ||
| 1290 | ); | ||
| 1291 | } | ||
| 1292 | |||
| 1293 | test "n_string_backslash_00" { | ||
| 1294 | err( | ||
| 1295 | \\["\ "] | ||
| 1296 | ); | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | test "n_string_escaped_backslash_bad" { | ||
| 1300 | err( | ||
| 1301 | \\["\\\"] | ||
| 1302 | ); | ||
| 1303 | } | ||
| 1304 | |||
| 1305 | test "n_string_escaped_ctrl_char_tab" { | ||
| 1306 | err( | ||
| 1307 | \\["\	"] | ||
| 1308 | ); | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | test "n_string_escaped_emoji" { | ||
| 1312 | err( | ||
| 1313 | \\["\ð"] | ||
| 1314 | ); | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | test "n_string_escape_x" { | ||
| 1318 | err( | ||
| 1319 | \\["\x00"] | ||
| 1320 | ); | ||
| 1321 | } | ||
| 1322 | |||
| 1323 | test "n_string_incomplete_escaped_character" { | ||
| 1324 | err( | ||
| 1325 | \\["\u00A"] | ||
| 1326 | ); | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | test "n_string_incomplete_escape" { | ||
| 1330 | err( | ||
| 1331 | \\["\"] | ||
| 1332 | ); | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | test "n_string_incomplete_surrogate_escape_invalid" { | ||
| 1336 | err( | ||
| 1337 | \\["\uD800\uD800\x"] | ||
| 1338 | ); | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | test "n_string_incomplete_surrogate" { | ||
| 1342 | err( | ||
| 1343 | \\["\uD834\uDd"] | ||
| 1344 | ); | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | test "n_string_invalid_backslash_esc" { | ||
| 1348 | err( | ||
| 1349 | \\["\a"] | ||
| 1350 | ); | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | test "n_string_invalid_unicode_escape" { | ||
| 1354 | err( | ||
| 1355 | \\["\uqqqq"] | ||
| 1356 | ); | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | test "n_string_invalid_utf8_after_escape" { | ||
| 1360 | err( | ||
| 1361 | \\["\å"] | ||
| 1362 | ); | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | test "n_string_invalid-utf-8-in-escape" { | ||
| 1366 | err( | ||
| 1367 | \\["\uå"] | ||
| 1368 | ); | ||
| 1369 | } | ||
| 1370 | |||
| 1371 | test "n_string_leading_uescaped_thinspace" { | ||
| 1372 | err( | ||
| 1373 | \\[\u0020"asd"] | ||
| 1374 | ); | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | test "n_string_no_quotes_with_bad_escape" { | ||
| 1378 | err( | ||
| 1379 | \\[\n] | ||
| 1380 | ); | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | test "n_string_single_doublequote" { | ||
| 1384 | err( | ||
| 1385 | \\" | ||
| 1386 | ); | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | test "n_string_single_quote" { | ||
| 1390 | err( | ||
| 1391 | \\['single quote'] | ||
| 1392 | ); | ||
| 1393 | } | ||
| 1394 | |||
| 1395 | test "n_string_single_string_no_double_quotes" { | ||
| 1396 | err( | ||
| 1397 | \\abc | ||
| 1398 | ); | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | test "n_string_start_escape_unclosed" { | ||
| 1402 | err( | ||
| 1403 | \\["\ | ||
| 1404 | ); | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | test "n_string_unescaped_crtl_char" { | ||
| 1408 | err( | ||
| 1409 | \\["a a"] | ||
| 1410 | ); | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | test "n_string_unescaped_newline" { | ||
| 1414 | err( | ||
| 1415 | \\["new | ||
| 1416 | \\line"] | ||
| 1417 | ); | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | test "n_string_unescaped_tab" { | ||
| 1421 | err( | ||
| 1422 | \\["	"] | ||
| 1423 | ); | ||
| 1424 | } | ||
| 1425 | |||
| 1426 | test "n_string_unicode_CapitalU" { | ||
| 1427 | err( | ||
| 1428 | \\"\UA66D" | ||
| 1429 | ); | ||
| 1430 | } | ||
| 1431 | |||
| 1432 | test "n_string_with_trailing_garbage" { | ||
| 1433 | err( | ||
| 1434 | \\""x | ||
| 1435 | ); | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | test "n_structure_100000_opening_arrays" { | ||
| 1439 | err( | ||
| 1440 | "[" ** 100000 | ||
| 1441 | ); | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | test "n_structure_angle_bracket_." { | ||
| 1445 | err( | ||
| 1446 | \\<.> | ||
| 1447 | ); | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | test "n_structure_angle_bracket_null" { | ||
| 1451 | err( | ||
| 1452 | \\[<null>] | ||
| 1453 | ); | ||
| 1454 | } | ||
| 1455 | |||
| 1456 | test "n_structure_array_trailing_garbage" { | ||
| 1457 | err( | ||
| 1458 | \\[1]x | ||
| 1459 | ); | ||
| 1460 | } | ||
| 1461 | |||
| 1462 | test "n_structure_array_with_extra_array_close" { | ||
| 1463 | err( | ||
| 1464 | \\[1]] | ||
| 1465 | ); | ||
| 1466 | } | ||
| 1467 | |||
| 1468 | test "n_structure_array_with_unclosed_string" { | ||
| 1469 | err( | ||
| 1470 | \\["asd] | ||
| 1471 | ); | ||
| 1472 | } | ||
| 1473 | |||
| 1474 | test "n_structure_ascii-unicode-identifier" { | ||
| 1475 | err( | ||
| 1476 | \\aå | ||
| 1477 | ); | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | test "n_structure_capitalized_True" { | ||
| 1481 | err( | ||
| 1482 | \\[True] | ||
| 1483 | ); | ||
| 1484 | } | ||
| 1485 | |||
| 1486 | test "n_structure_close_unopened_array" { | ||
| 1487 | err( | ||
| 1488 | \\1] | ||
| 1489 | ); | ||
| 1490 | } | ||
| 1491 | |||
| 1492 | test "n_structure_comma_instead_of_closing_brace" { | ||
| 1493 | err( | ||
| 1494 | \\{"x": true, | ||
| 1495 | ); | ||
| 1496 | } | ||
| 1497 | |||
| 1498 | test "n_structure_double_array" { | ||
| 1499 | err( | ||
| 1500 | \\[][] | ||
| 1501 | ); | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | test "n_structure_end_array" { | ||
| 1505 | err( | ||
| 1506 | \\] | ||
| 1507 | ); | ||
| 1508 | } | ||
| 1509 | |||
| 1510 | test "n_structure_incomplete_UTF8_BOM" { | ||
| 1511 | err( | ||
| 1512 | \\ï»{} | ||
| 1513 | ); | ||
| 1514 | } | ||
| 1515 | |||
| 1516 | test "n_structure_lone-invalid-utf-8" { | ||
| 1517 | err( | ||
| 1518 | \\å | ||
| 1519 | ); | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | test "n_structure_lone-open-bracket" { | ||
| 1523 | err( | ||
| 1524 | \\[ | ||
| 1525 | ); | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | test "n_structure_no_data" { | ||
| 1529 | err( | ||
| 1530 | \\ | ||
| 1531 | ); | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | test "n_structure_null-byte-outside-string" { | ||
| 1535 | err( | ||
| 1536 | \\[ ] | ||
| 1537 | ); | ||
| 1538 | } | ||
| 1539 | |||
| 1540 | test "n_structure_number_with_trailing_garbage" { | ||
| 1541 | err( | ||
| 1542 | \\2@ | ||
| 1543 | ); | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | test "n_structure_object_followed_by_closing_object" { | ||
| 1547 | err( | ||
| 1548 | \\{}} | ||
| 1549 | ); | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | test "n_structure_object_unclosed_no_value" { | ||
| 1553 | err( | ||
| 1554 | \\{"": | ||
| 1555 | ); | ||
| 1556 | } | ||
| 1557 | |||
| 1558 | test "n_structure_object_with_comment" { | ||
| 1559 | err( | ||
| 1560 | \\{"a":/*comment*/"b"} | ||
| 1561 | ); | ||
| 1562 | } | ||
| 1563 | |||
| 1564 | test "n_structure_object_with_trailing_garbage" { | ||
| 1565 | err( | ||
| 1566 | \\{"a": true} "x" | ||
| 1567 | ); | ||
| 1568 | } | ||
| 1569 | |||
| 1570 | test "n_structure_open_array_apostrophe" { | ||
| 1571 | err( | ||
| 1572 | \\[' | ||
| 1573 | ); | ||
| 1574 | } | ||
| 1575 | |||
| 1576 | test "n_structure_open_array_comma" { | ||
| 1577 | err( | ||
| 1578 | \\[, | ||
| 1579 | ); | ||
| 1580 | } | ||
| 1581 | |||
| 1582 | test "n_structure_open_array_object" { | ||
| 1583 | err( | ||
| 1584 | "[{\"\":" ** 50000 | ||
| 1585 | ); | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | test "n_structure_open_array_open_object" { | ||
| 1589 | err( | ||
| 1590 | \\[{ | ||
| 1591 | ); | ||
| 1592 | } | ||
| 1593 | |||
| 1594 | test "n_structure_open_array_open_string" { | ||
| 1595 | err( | ||
| 1596 | \\["a | ||
| 1597 | ); | ||
| 1598 | } | ||
| 1599 | |||
| 1600 | test "n_structure_open_array_string" { | ||
| 1601 | err( | ||
| 1602 | \\["a" | ||
| 1603 | ); | ||
| 1604 | } | ||
| 1605 | |||
| 1606 | test "n_structure_open_object_close_array" { | ||
| 1607 | err( | ||
| 1608 | \\{] | ||
| 1609 | ); | ||
| 1610 | } | ||
| 1611 | |||
| 1612 | test "n_structure_open_object_comma" { | ||
| 1613 | err( | ||
| 1614 | \\{, | ||
| 1615 | ); | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | test "n_structure_open_object" { | ||
| 1619 | err( | ||
| 1620 | \\{ | ||
| 1621 | ); | ||
| 1622 | } | ||
| 1623 | |||
| 1624 | test "n_structure_open_object_open_array" { | ||
| 1625 | err( | ||
| 1626 | \\{[ | ||
| 1627 | ); | ||
| 1628 | } | ||
| 1629 | |||
| 1630 | test "n_structure_open_object_open_string" { | ||
| 1631 | err( | ||
| 1632 | \\{"a | ||
| 1633 | ); | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | test "n_structure_open_object_string_with_apostrophes" { | ||
| 1637 | err( | ||
| 1638 | \\{'a' | ||
| 1639 | ); | ||
| 1640 | } | ||
| 1641 | |||
| 1642 | test "n_structure_open_open" { | ||
| 1643 | err( | ||
| 1644 | \\["\{["\{["\{["\{ | ||
| 1645 | ); | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | test "n_structure_single_eacute" { | ||
| 1649 | err( | ||
| 1650 | \\é | ||
| 1651 | ); | ||
| 1652 | } | ||
| 1653 | |||
| 1654 | test "n_structure_single_star" { | ||
| 1655 | err( | ||
| 1656 | \\* | ||
| 1657 | ); | ||
| 1658 | } | ||
| 1659 | |||
| 1660 | test "n_structure_trailing_#" { | ||
| 1661 | err( | ||
| 1662 | \\{"a":"b"}#{} | ||
| 1663 | ); | ||
| 1664 | } | ||
| 1665 | |||
| 1666 | test "n_structure_U+2060_word_joined" { | ||
| 1667 | err( | ||
| 1668 | \\[â ] | ||
| 1669 | ); | ||
| 1670 | } | ||
| 1671 | |||
| 1672 | test "n_structure_uescaped_LF_before_string" { | ||
| 1673 | err( | ||
| 1674 | \\[\u000A""] | ||
| 1675 | ); | ||
| 1676 | } | ||
| 1677 | |||
| 1678 | test "n_structure_unclosed_array" { | ||
| 1679 | err( | ||
| 1680 | \\[1 | ||
| 1681 | ); | ||
| 1682 | } | ||
| 1683 | |||
| 1684 | test "n_structure_unclosed_array_partial_null" { | ||
| 1685 | err( | ||
| 1686 | \\[ false, nul | ||
| 1687 | ); | ||
| 1688 | } | ||
| 1689 | |||
| 1690 | test "n_structure_unclosed_array_unfinished_false" { | ||
| 1691 | err( | ||
| 1692 | \\[ true, fals | ||
| 1693 | ); | ||
| 1694 | } | ||
| 1695 | |||
| 1696 | test "n_structure_unclosed_array_unfinished_true" { | ||
| 1697 | err( | ||
| 1698 | \\[ false, tru | ||
| 1699 | ); | ||
| 1700 | } | ||
| 1701 | |||
| 1702 | test "n_structure_unclosed_object" { | ||
| 1703 | err( | ||
| 1704 | \\{"asd":"asd" | ||
| 1705 | ); | ||
| 1706 | } | ||
| 1707 | |||
| 1708 | test "n_structure_unicode-identifier" { | ||
| 1709 | err( | ||
| 1710 | \\Ã¥ | ||
| 1711 | ); | ||
| 1712 | } | ||
| 1713 | |||
| 1714 | test "n_structure_UTF8_BOM_no_data" { | ||
| 1715 | err( | ||
| 1716 | \\ | ||
| 1717 | ); | ||
| 1718 | } | ||
| 1719 | |||
| 1720 | test "n_structure_whitespace_formfeed" { | ||
| 1721 | err( | ||
| 1722 | \\[] | ||
| 1723 | ); | ||
| 1724 | } | ||
| 1725 | |||
| 1726 | test "n_structure_whitespace_U+2060_word_joiner" { | ||
| 1727 | err( | ||
| 1728 | \\[â ] | ||
| 1729 | ); | ||
| 1730 | } | ||
| 1731 | |||
| 1732 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 1733 | |||
| 1734 | test "i_number_double_huge_neg_exp" { | ||
| 1735 | any( | ||
| 1736 | \\[123.456e-789] | ||
| 1737 | ); | ||
| 1738 | } | ||
| 1739 | |||
| 1740 | test "i_number_huge_exp" { | ||
| 1741 | any( | ||
| 1742 | \\[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] | ||
| 1743 | ); | ||
| 1744 | } | ||
| 1745 | |||
| 1746 | test "i_number_neg_int_huge_exp" { | ||
| 1747 | any( | ||
| 1748 | \\[-1e+9999] | ||
| 1749 | ); | ||
| 1750 | } | ||
| 1751 | |||
| 1752 | test "i_number_pos_double_huge_exp" { | ||
| 1753 | any( | ||
| 1754 | \\[1.5e+9999] | ||
| 1755 | ); | ||
| 1756 | } | ||
| 1757 | |||
| 1758 | test "i_number_real_neg_overflow" { | ||
| 1759 | any( | ||
| 1760 | \\[-123123e100000] | ||
| 1761 | ); | ||
| 1762 | } | ||
| 1763 | |||
| 1764 | test "i_number_real_pos_overflow" { | ||
| 1765 | any( | ||
| 1766 | \\[123123e100000] | ||
| 1767 | ); | ||
| 1768 | } | ||
| 1769 | |||
| 1770 | test "i_number_real_underflow" { | ||
| 1771 | any( | ||
| 1772 | \\[123e-10000000] | ||
| 1773 | ); | ||
| 1774 | } | ||
| 1775 | |||
| 1776 | test "i_number_too_big_neg_int" { | ||
| 1777 | any( | ||
| 1778 | \\[-123123123123123123123123123123] | ||
| 1779 | ); | ||
| 1780 | } | ||
| 1781 | |||
| 1782 | test "i_number_too_big_pos_int" { | ||
| 1783 | any( | ||
| 1784 | \\[100000000000000000000] | ||
| 1785 | ); | ||
| 1786 | } | ||
| 1787 | |||
| 1788 | test "i_number_very_big_negative_int" { | ||
| 1789 | any( | ||
| 1790 | \\[-237462374673276894279832749832423479823246327846] | ||
| 1791 | ); | ||
| 1792 | } | ||
| 1793 | |||
| 1794 | test "i_object_key_lone_2nd_surrogate" { | ||
| 1795 | any( | ||
| 1796 | \\{"\uDFAA":0} | ||
| 1797 | ); | ||
| 1798 | } | ||
| 1799 | |||
| 1800 | test "i_string_1st_surrogate_but_2nd_missing" { | ||
| 1801 | any( | ||
| 1802 | \\["\uDADA"] | ||
| 1803 | ); | ||
| 1804 | } | ||
| 1805 | |||
| 1806 | test "i_string_1st_valid_surrogate_2nd_invalid" { | ||
| 1807 | any( | ||
| 1808 | \\["\uD888\u1234"] | ||
| 1809 | ); | ||
| 1810 | } | ||
| 1811 | |||
| 1812 | test "i_string_incomplete_surrogate_and_escape_valid" { | ||
| 1813 | any( | ||
| 1814 | \\["\uD800\n"] | ||
| 1815 | ); | ||
| 1816 | } | ||
| 1817 | |||
| 1818 | test "i_string_incomplete_surrogate_pair" { | ||
| 1819 | any( | ||
| 1820 | \\["\uDd1ea"] | ||
| 1821 | ); | ||
| 1822 | } | ||
| 1823 | |||
| 1824 | test "i_string_incomplete_surrogates_escape_valid" { | ||
| 1825 | any( | ||
| 1826 | \\["\uD800\uD800\n"] | ||
| 1827 | ); | ||
| 1828 | } | ||
| 1829 | |||
| 1830 | test "i_string_invalid_lonely_surrogate" { | ||
| 1831 | any( | ||
| 1832 | \\["\ud800"] | ||
| 1833 | ); | ||
| 1834 | } | ||
| 1835 | |||
| 1836 | test "i_string_invalid_surrogate" { | ||
| 1837 | any( | ||
| 1838 | \\["\ud800abc"] | ||
| 1839 | ); | ||
| 1840 | } | ||
| 1841 | |||
| 1842 | test "i_string_invalid_utf-8" { | ||
| 1843 | any( | ||
| 1844 | \\["ÿ"] | ||
| 1845 | ); | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | test "i_string_inverted_surrogates_U+1D11E" { | ||
| 1849 | any( | ||
| 1850 | \\["\uDd1e\uD834"] | ||
| 1851 | ); | ||
| 1852 | } | ||
| 1853 | |||
| 1854 | test "i_string_iso_latin_1" { | ||
| 1855 | any( | ||
| 1856 | \\["é"] | ||
| 1857 | ); | ||
| 1858 | } | ||
| 1859 | |||
| 1860 | test "i_string_lone_second_surrogate" { | ||
| 1861 | any( | ||
| 1862 | \\["\uDFAA"] | ||
| 1863 | ); | ||
| 1864 | } | ||
| 1865 | |||
| 1866 | test "i_string_lone_utf8_continuation_byte" { | ||
| 1867 | any( | ||
| 1868 | \\[""] | ||
| 1869 | ); | ||
| 1870 | } | ||
| 1871 | |||
| 1872 | test "i_string_not_in_unicode_range" { | ||
| 1873 | any( | ||
| 1874 | \\["ô¿¿¿"] | ||
| 1875 | ); | ||
| 1876 | } | ||
| 1877 | |||
| 1878 | test "i_string_overlong_sequence_2_bytes" { | ||
| 1879 | any( | ||
| 1880 | \\["À¯"] | ||
| 1881 | ); | ||
| 1882 | } | ||
| 1883 | |||
| 1884 | test "i_string_overlong_sequence_6_bytes" { | ||
| 1885 | any( | ||
| 1886 | \\["ü¿¿¿¿"] | ||
| 1887 | ); | ||
| 1888 | } | ||
| 1889 | |||
| 1890 | test "i_string_overlong_sequence_6_bytes_null" { | ||
| 1891 | any( | ||
| 1892 | \\["ü"] | ||
| 1893 | ); | ||
| 1894 | } | ||
| 1895 | |||
| 1896 | test "i_string_truncated-utf-8" { | ||
| 1897 | any( | ||
| 1898 | \\["àÿ"] | ||
| 1899 | ); | ||
| 1900 | } | ||
| 1901 | |||
| 1902 | test "i_string_utf16BE_no_BOM" { | ||
| 1903 | any( | ||
| 1904 | \\ [ " é | ||