| 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 | 454 | "heap.zig" |
| 455 | 455 | "index.zig" |
| 456 | 456 | "io.zig" |
| 457 | "json.zig" | |
| 457 | 458 | "linked_list.zig" |
| 458 | 459 | "macho.zig" |
| 459 | 460 | "math/acos.zig" |
doc/langref.html.in+388-5| ... | ... | @@ -4809,6 +4809,182 @@ pub const TypeId = enum { |
| 4809 | 4809 | BoundFn, |
| 4810 | 4810 | ArgTuple, |
| 4811 | 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 | 4989 | {#code_end#} |
| 4814 | 4990 | {#header_close#} |
| ... | ... | @@ -5226,7 +5402,6 @@ pub const Os = enum { |
| 5226 | 5402 | rtems, |
| 5227 | 5403 | nacl, |
| 5228 | 5404 | cnk, |
| 5229 | bitrig, | |
| 5230 | 5405 | aix, |
| 5231 | 5406 | cuda, |
| 5232 | 5407 | nvcl, |
| ... | ... | @@ -5237,10 +5412,12 @@ pub const Os = enum { |
| 5237 | 5412 | watchos, |
| 5238 | 5413 | mesa3d, |
| 5239 | 5414 | contiki, |
| 5415 | amdpal, | |
| 5240 | 5416 | zen, |
| 5241 | 5417 | }; |
| 5242 | 5418 | |
| 5243 | 5419 | pub const Arch = enum { |
| 5420 | armv8_3a, | |
| 5244 | 5421 | armv8_2a, |
| 5245 | 5422 | armv8_1a, |
| 5246 | 5423 | armv8, |
| ... | ... | @@ -5260,9 +5437,29 @@ pub const Arch = enum { |
| 5260 | 5437 | armv5, |
| 5261 | 5438 | armv5te, |
| 5262 | 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 | 5460 | aarch64, |
| 5265 | 5461 | aarch64_be, |
| 5462 | arc, | |
| 5266 | 5463 | avr, |
| 5267 | 5464 | bpfel, |
| 5268 | 5465 | bpfeb, |
| ... | ... | @@ -5315,6 +5512,7 @@ pub const Arch = enum { |
| 5315 | 5512 | pub const Environ = enum { |
| 5316 | 5513 | unknown, |
| 5317 | 5514 | gnu, |
| 5515 | gnuabin32, | |
| 5318 | 5516 | gnuabi64, |
| 5319 | 5517 | gnueabi, |
| 5320 | 5518 | gnueabihf, |
| ... | ... | @@ -5332,6 +5530,7 @@ pub const Environ = enum { |
| 5332 | 5530 | amdopencl, |
| 5333 | 5531 | coreclr, |
| 5334 | 5532 | opencl, |
| 5533 | simulator, | |
| 5335 | 5534 | }; |
| 5336 | 5535 | |
| 5337 | 5536 | pub const ObjectFormat = enum { |
| ... | ... | @@ -5358,10 +5557,23 @@ pub const AtomicOrder = enum { |
| 5358 | 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 | 5572 | pub const Mode = enum { |
| 5362 | 5573 | Debug, |
| 5363 | 5574 | ReleaseSafe, |
| 5364 | 5575 | ReleaseFast, |
| 5576 | ReleaseSmall, | |
| 5365 | 5577 | }; |
| 5366 | 5578 | |
| 5367 | 5579 | pub const TypeId = enum { |
| ... | ... | @@ -5380,7 +5592,7 @@ pub const TypeId = enum { |
| 5380 | 5592 | NullLiteral, |
| 5381 | 5593 | Nullable, |
| 5382 | 5594 | ErrorUnion, |
| 5383 | Error, | |
| 5595 | ErrorSet, | |
| 5384 | 5596 | Enum, |
| 5385 | 5597 | Union, |
| 5386 | 5598 | Fn, |
| ... | ... | @@ -5389,6 +5601,176 @@ pub const TypeId = enum { |
| 5389 | 5601 | BoundFn, |
| 5390 | 5602 | ArgTuple, |
| 5391 | 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 | 5776 | pub const FloatMode = enum { |
| ... | ... | @@ -5402,7 +5784,7 @@ pub const Endian = enum { |
| 5402 | 5784 | }; |
| 5403 | 5785 | |
| 5404 | 5786 | pub const endian = Endian.Little; |
| 5405 | pub const is_test = false; | |
| 5787 | pub const is_test = true; | |
| 5406 | 5788 | pub const os = Os.linux; |
| 5407 | 5789 | pub const arch = Arch.x86_64; |
| 5408 | 5790 | pub const environ = Environ.gnu; |
| ... | ... | @@ -5410,6 +5792,7 @@ pub const object_format = ObjectFormat.elf; |
| 5410 | 5792 | pub const mode = Mode.Debug; |
| 5411 | 5793 | pub const link_libc = false; |
| 5412 | 5794 | pub const have_error_return_tracing = true; |
| 5795 | pub const __zig_test_fn_slice = {}; // overwritten later | |
| 5413 | 5796 | {#code_end#} |
| 5414 | 5797 | {#see_also|Build Mode#} |
| 5415 | 5798 | {#header_close#} |
| ... | ... | @@ -6068,7 +6451,7 @@ hljs.registerLanguage("zig", function(t) { |
| 6068 | 6451 | a = t.IR + "\\s*\\(", |
| 6069 | 6452 | c = { |
| 6070 | 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 | 6455 | literal: "true false null undefined" |
| 6073 | 6456 | }, |
| 6074 | 6457 | n = [e, t.CLCM, t.CBCM, s, r]; |
src/all_types.hpp+9| ... | ... | @@ -1293,6 +1293,7 @@ enum BuiltinFnId { |
| 1293 | 1293 | BuiltinFnIdMemberType, |
| 1294 | 1294 | BuiltinFnIdMemberName, |
| 1295 | 1295 | BuiltinFnIdField, |
| 1296 | BuiltinFnIdTypeInfo, | |
| 1296 | 1297 | BuiltinFnIdTypeof, |
| 1297 | 1298 | BuiltinFnIdAddWithOverflow, |
| 1298 | 1299 | BuiltinFnIdSubWithOverflow, |
| ... | ... | @@ -1506,6 +1507,7 @@ struct CodeGen { |
| 1506 | 1507 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names; |
| 1507 | 1508 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; |
| 1508 | 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 | 1513 | ZigList<ImportTableEntry *> import_queue; |
| ... | ... | @@ -2035,6 +2037,7 @@ enum IrInstructionId { |
| 2035 | 2037 | IrInstructionIdTagType, |
| 2036 | 2038 | IrInstructionIdFieldParentPtr, |
| 2037 | 2039 | IrInstructionIdOffsetOf, |
| 2040 | IrInstructionIdTypeInfo, | |
| 2038 | 2041 | IrInstructionIdTypeId, |
| 2039 | 2042 | IrInstructionIdSetEvalBranchQuota, |
| 2040 | 2043 | IrInstructionIdPtrTypeOf, |
| ... | ... | @@ -2856,6 +2859,12 @@ struct IrInstructionOffsetOf { |
| 2856 | 2859 | IrInstruction *field_name; |
| 2857 | 2860 | }; |
| 2858 | 2861 | |
| 2862 | struct IrInstructionTypeInfo { | |
| 2863 | IrInstruction base; | |
| 2864 | ||
| 2865 | IrInstruction *type_value; | |
| 2866 | }; | |
| 2867 | ||
| 2859 | 2868 | struct IrInstructionTypeId { |
| 2860 | 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 | 2325 | HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {}; |
| 2326 | 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 | 2336 | if (decl_node->data.container_decl.init_arg_expr != nullptr) { |
| 2331 | 2337 | TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); |
| 2332 | 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 | 728 | render_node_grouped(ar, field_node->data.struct_field.type); |
| 729 | 729 | } |
| 730 | 730 | if (field_node->data.struct_field.value != nullptr) { |
| 731 | fprintf(ar->f, "= "); | |
| 731 | fprintf(ar->f, " = "); | |
| 732 | 732 | render_node_grouped(ar, field_node->data.struct_field.value); |
| 733 | 733 | } |
| 734 | 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 | 88 | g->exported_symbol_names.init(8); |
| 89 | 89 | g->external_prototypes.init(8); |
| 90 | 90 | g->string_literals_table.init(16); |
| 91 | g->type_info_cache.init(32); | |
| 91 | 92 | g->is_test_build = false; |
| 92 | 93 | g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); |
| 93 | 94 | buf_resize(&g->global_asm, 0); |
| ... | ... | @@ -4417,6 +4418,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4417 | 4418 | case IrInstructionIdDeclRef: |
| 4418 | 4419 | case IrInstructionIdSwitchVar: |
| 4419 | 4420 | case IrInstructionIdOffsetOf: |
| 4421 | case IrInstructionIdTypeInfo: | |
| 4420 | 4422 | case IrInstructionIdTypeId: |
| 4421 | 4423 | case IrInstructionIdSetEvalBranchQuota: |
| 4422 | 4424 | case IrInstructionIdPtrTypeOf: |
| ... | ... | @@ -6040,6 +6042,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 6040 | 6042 | create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2); |
| 6041 | 6043 | create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2); |
| 6042 | 6044 | create_builtin_fn(g, BuiltinFnIdField, "field", 2); |
| 6045 | create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1); | |
| 6043 | 6046 | create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf |
| 6044 | 6047 | create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4); |
| 6045 | 6048 | create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4); |
| ... | ... | @@ -6259,6 +6262,190 @@ static void define_builtin_compile_vars(CodeGen *g) { |
| 6259 | 6262 | } |
| 6260 | 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 | 6450 | buf_appendf(contents, |
| 6264 | 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 | 145 | while (scope != nullptr) { |
| 146 | 146 | if (scope->id == ScopeIdCompTime) |
| 147 | 147 | return true; |
| 148 | if (scope->id == ScopeIdFnDef) | |
| 149 | break; | |
| 148 | 150 | scope = scope->parent; |
| 149 | 151 | } |
| 150 | 152 | return false; |
| ... | ... | @@ -615,6 +617,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) { |
| 615 | 617 | return IrInstructionIdOffsetOf; |
| 616 | 618 | } |
| 617 | 619 | |
| 620 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) { | |
| 621 | return IrInstructionIdTypeInfo; | |
| 622 | } | |
| 623 | ||
| 618 | 624 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeId *) { |
| 619 | 625 | return IrInstructionIdTypeId; |
| 620 | 626 | } |
| ... | ... | @@ -2440,6 +2446,16 @@ static IrInstruction *ir_build_offset_of(IrBuilder *irb, Scope *scope, AstNode * |
| 2440 | 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 | 2459 | static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2444 | 2460 | IrInstruction *type_value) |
| 2445 | 2461 | { |
| ... | ... | @@ -4083,6 +4099,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4083 | 4099 | |
| 4084 | 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 | 4112 | case BuiltinFnIdBreakpoint: |
| 4087 | 4113 | return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval); |
| 4088 | 4114 | case BuiltinFnIdReturnAddress: |
| ... | ... | @@ -13386,7 +13412,6 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 13386 | 13412 | return ira->codegen->invalid_instruction; |
| 13387 | 13413 | } |
| 13388 | 13414 | |
| 13389 | ||
| 13390 | 13415 | static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, |
| 13391 | 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 | 13473 | } else if (bare_type->id == TypeTableEntryIdUnion) { |
| 13449 | 13474 | TypeUnionField *field = find_union_type_field(bare_type, field_name); |
| 13450 | 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 | 13521 | IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field); |
| 13452 | 13522 | result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, |
| 13453 | 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 | 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 | 16639 | static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira, |
| 15681 | 16640 | IrInstructionTypeId *instruction) |
| 15682 | 16641 | { |
| ... | ... | @@ -18578,6 +19537,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 18578 | 19537 | return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction); |
| 18579 | 19538 | case IrInstructionIdOffsetOf: |
| 18580 | 19539 | return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction); |
| 19540 | case IrInstructionIdTypeInfo: | |
| 19541 | return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction); | |
| 18581 | 19542 | case IrInstructionIdTypeId: |
| 18582 | 19543 | return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction); |
| 18583 | 19544 | case IrInstructionIdSetEvalBranchQuota: |
| ... | ... | @@ -18844,6 +19805,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 18844 | 19805 | case IrInstructionIdTagName: |
| 18845 | 19806 | case IrInstructionIdFieldParentPtr: |
| 18846 | 19807 | case IrInstructionIdOffsetOf: |
| 19808 | case IrInstructionIdTypeInfo: | |
| 18847 | 19809 | case IrInstructionIdTypeId: |
| 18848 | 19810 | case IrInstructionIdAlignCast: |
| 18849 | 19811 | case IrInstructionIdOpaqueType: |
src/ir_print.cpp+9| ... | ... | @@ -966,6 +966,12 @@ static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction) |
| 966 | 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 | 975 | static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) { |
| 970 | 976 | fprintf(irp->f, "@typeId("); |
| 971 | 977 | ir_print_other_instruction(irp, instruction->type_value); |
| ... | ... | @@ -1536,6 +1542,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1536 | 1542 | case IrInstructionIdOffsetOf: |
| 1537 | 1543 | ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction); |
| 1538 | 1544 | break; |
| 1545 | case IrInstructionIdTypeInfo: | |
| 1546 | ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction); | |
| 1547 | break; | |
| 1539 | 1548 | case IrInstructionIdTypeId: |
| 1540 | 1549 | ir_print_type_id(irp, (IrInstructionTypeId *)instruction); |
| 1541 | 1550 | break; |
src/translate_c.cpp+39-69| ... | ... | @@ -3746,6 +3746,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { |
| 3746 | 3746 | return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name); |
| 3747 | 3747 | } |
| 3748 | 3748 | |
| 3749 | ||
| 3749 | 3750 | bool pure_enum = true; |
| 3750 | 3751 | uint32_t field_count = 0; |
| 3751 | 3752 | for (auto it = enum_def->enumerator_begin(), |
| ... | ... | @@ -3757,84 +3758,53 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { |
| 3757 | 3758 | pure_enum = false; |
| 3758 | 3759 | } |
| 3759 | 3760 | } |
| 3760 | ||
| 3761 | 3761 | AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation()); |
| 3762 | 3762 | assert(tag_int_type); |
| 3763 | 3763 | |
| 3764 | if (pure_enum) { | |
| 3765 | AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); | |
| 3766 | enum_node->data.container_decl.kind = ContainerKindEnum; | |
| 3767 | enum_node->data.container_decl.layout = ContainerLayoutExtern; | |
| 3768 | // TODO only emit this tag type if the enum tag type is not the default. | |
| 3769 | // I don't know what the default is, need to figure out how clang is deciding. | |
| 3770 | // it appears to at least be different across gcc/msvc | |
| 3771 | if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) && | |
| 3772 | !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int)) | |
| 3773 | { | |
| 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 | } | |
| 3764 | AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); | |
| 3765 | enum_node->data.container_decl.kind = ContainerKindEnum; | |
| 3766 | enum_node->data.container_decl.layout = ContainerLayoutExtern; | |
| 3767 | // 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 | // it appears to at least be different across gcc/msvc | |
| 3770 | if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) && | |
| 3771 | !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int)) | |
| 3772 | { | |
| 3773 | enum_node->data.container_decl.init_arg_expr = tag_int_type; | |
| 3820 | 3774 | } |
| 3821 | ||
| 3822 | // TODO after issue #305 is solved, make this be an enum with tag_int_type | |
| 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 | |
| 3775 | enum_node->data.container_decl.fields.resize(field_count); | |
| 3776 | uint32_t i = 0; | |
| 3828 | 3777 | for (auto it = enum_def->enumerator_begin(), |
| 3829 | 3778 | it_end = enum_def->enumerator_end(); |
| 3830 | it != it_end; ++it) | |
| 3779 | it != it_end; ++it, i += 1) | |
| 3831 | 3780 | { |
| 3832 | 3781 | const EnumConstantDecl *enum_const = *it; |
| 3833 | 3782 | |
| 3834 | 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()); | |
| 3836 | AstNode *var_node = add_global_var(c, enum_val_name, int_node); | |
| 3837 | var_node->data.variable_declaration.type = tag_int_type; | |
| 3784 | Buf *field_name; | |
| 3785 | if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) { | |
| 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 | 3810 | if (is_anonymous) { |
| ... | ... | @@ -3845,7 +3815,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { |
| 3845 | 3815 | add_global_weak_alias(c, bare_name, full_type_name); |
| 3846 | 3816 | add_global_var(c, full_type_name, enum_node); |
| 3847 | 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 | 44 | return l.toSliceConst()[n]; |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | pub fn count(self: &const Self) usize { | |
| 48 | return self.len; | |
| 49 | } | |
| 50 | ||
| 47 | 51 | /// ArrayList takes ownership of the passed in slice. The slice must have been |
| 48 | 52 | /// allocated with `allocator`. |
| 49 | 53 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| ... | ... | @@ -128,6 +132,27 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{ |
| 128 | 132 | return null; |
| 129 | 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 | 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 | 214 | test "insert ArrayList test" { |
| 161 | 215 | var list = ArrayList(i32).init(debug.global_allocator); |
| 162 | 216 | defer list.deinit(); |
| ... | ... | @@ -174,4 +228,4 @@ test "insert ArrayList test" { |
| 174 | 228 | const items = []const i32 { 1 }; |
| 175 | 229 | try list.insertSlice(0, items[0..0]); |
| 176 | 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 | 31 | } |
| 32 | 32 | |
| 33 | 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 | 35 | while (true) { |
| 36 | 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 | 49 | get_count: usize, |
| 50 | 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 | 59 | const put_thread_count = 3; |
| 54 | 60 | |
| 55 | 61 | test "std.atomic.queue" { |
| 56 | 62 | var direct_allocator = std.heap.DirectAllocator.init(); |
| 57 | 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 | 66 | defer direct_allocator.allocator.free(plenty_of_memory); |
| 61 | 67 | |
| 62 | 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 | 35 | } |
| 36 | 36 | |
| 37 | 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 | 39 | while (true) { |
| 40 | 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 | 56 | get_count: usize, |
| 57 | 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 | 65 | const put_thread_count = 3; |
| 61 | 66 | |
| 62 | 67 | test "std.atomic.stack" { |
| 63 | 68 | var direct_allocator = std.heap.DirectAllocator.init(); |
| 64 | 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 | 72 | defer direct_allocator.allocator.free(plenty_of_memory); |
| 68 | 73 | |
| 69 | 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 | 50 | } |
| 51 | 51 | |
| 52 | 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 | 56 | pub fn iterator(self: &const BufMap) BufMapHashMap.Iterator { |
| ... | ... | @@ -87,4 +87,4 @@ test "BufMap" { |
| 87 | 87 | |
| 88 | 88 | bufmap.delete("x"); |
| 89 | 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 | 38 | } |
| 39 | 39 | |
| 40 | 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 | 44 | pub fn iterator(self: &const BufSet) BufSetHashMap.Iterator { |
| ... | ... | @@ -59,4 +59,3 @@ pub const BufSet = struct { |
| 59 | 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 | 54 | } |
| 55 | 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 | 67 | pub fn init(allocator: &Allocator) Self { |
| ... | ... | @@ -79,6 +87,10 @@ pub fn HashMap(comptime K: type, comptime V: type, |
| 79 | 87 | hm.incrementModificationCount(); |
| 80 | 88 | } |
| 81 | 89 | |
| 90 | pub fn count(hm: &const Self) usize { | |
| 91 | return hm.size; | |
| 92 | } | |
| 93 | ||
| 82 | 94 | /// Returns the value that was already there. |
| 83 | 95 | pub fn put(hm: &Self, key: K, value: &const V) !?V { |
| 84 | 96 | if (hm.entries.len == 0) { |
| ... | ... | @@ -258,10 +270,49 @@ test "basic hash map usage" { |
| 258 | 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 | 312 | fn hash_i32(x: i32) u32 { |
| 262 | 313 | return @bitCast(u32, x); |
| 263 | 314 | } |
| 264 | 315 | |
| 265 | 316 | fn eql_i32(a: i32, b: i32) bool { |
| 266 | 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 | 23 | pub const hash = @import("hash/index.zig"); |
| 24 | 24 | pub const heap = @import("heap.zig"); |
| 25 | 25 | pub const io = @import("io.zig"); |
| 26 | pub const json = @import("json.zig"); | |
| 26 | 27 | pub const macho = @import("macho.zig"); |
| 27 | 28 | pub const math = @import("math/index.zig"); |
| 28 | 29 | pub const mem = @import("mem.zig"); |
| ... | ... | @@ -56,6 +57,7 @@ test "std" { |
| 56 | 57 | _ = @import("fmt/index.zig"); |
| 57 | 58 | _ = @import("hash/index.zig"); |
| 58 | 59 | _ = @import("io.zig"); |
| 60 | _ = @import("json.zig"); | |
| 59 | 61 | _ = @import("macho.zig"); |
| 60 | 62 | _ = @import("math/index.zig"); |
| 61 | 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 | \\ [ " é |