authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-04 13:39:27-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-04 13:39:27-04:00
log7e37d268c86ccc823c4a381a42029722d36c3975
tree1600a184f03fedd91131bcbaea2c5ee85dfa06a3
parent6309121f70ff88cf64267f2bf1d9e452090ca277
parentef3111be236fc389a696562d31bccd3a9b6d1c56

Merge remote-tracking branch 'origin/master' into llvm7


41 files changed, 5282 insertions(+), 129 deletions(-)

CMakeLists.txt+1
......@@ -454,6 +454,7 @@ set(ZIG_STD_FILES
454454 "heap.zig"
455455 "index.zig"
456456 "io.zig"
457 "json.zig"
457458 "linked_list.zig"
458459 "macho.zig"
459460 "math/acos.zig"
doc/langref.html.in+388-5
......@@ -4809,6 +4809,182 @@ pub const TypeId = enum {
48094809 BoundFn,
48104810 ArgTuple,
48114811 Opaque,
4812};
4813 {#code_end#}
4814 {#header_close#}
4815 {#header_open|@typeInfo#}
4816 <pre><code class="zig">@typeInfo(comptime T: type) -&gt; @import("builtin").TypeInfo</code></pre>
4817 <p>
4818 Returns information on the type. Returns a value of the following union:
4819 </p>
4820 {#code_begin|syntax#}
4821pub const TypeInfo = union(TypeId) {
4822 Type: void,
4823 Void: void,
4824 Bool: void,
4825 NoReturn: void,
4826 Int: Int,
4827 Float: Float,
4828 Pointer: Pointer,
4829 Array: Array,
4830 Struct: Struct,
4831 FloatLiteral: void,
4832 IntLiteral: void,
4833 UndefinedLiteral: void,
4834 NullLiteral: void,
4835 Nullable: Nullable,
4836 ErrorUnion: ErrorUnion,
4837 ErrorSet: ErrorSet,
4838 Enum: Enum,
4839 Union: Union,
4840 Fn: Fn,
4841 Namespace: void,
4842 Block: void,
4843 BoundFn: Fn,
4844 ArgTuple: void,
4845 Opaque: void,
4846 Promise: Promise,
4847
4848
4849 pub const Int = struct {
4850 is_signed: bool,
4851 bits: u8,
4852 };
4853
4854 pub const Float = struct {
4855 bits: u8,
4856 };
4857
4858 pub const Pointer = struct {
4859 is_const: bool,
4860 is_volatile: bool,
4861 alignment: u32,
4862 child: type,
4863 };
4864
4865 pub const Array = struct {
4866 len: usize,
4867 child: type,
4868 };
4869
4870 pub const ContainerLayout = enum {
4871 Auto,
4872 Extern,
4873 Packed,
4874 };
4875
4876 pub const StructField = struct {
4877 name: []const u8,
4878 offset: ?usize,
4879 field_type: type,
4880 };
4881
4882 pub const Struct = struct {
4883 layout: ContainerLayout,
4884 fields: []StructField,
4885 defs: []Definition,
4886 };
4887
4888 pub const Nullable = struct {
4889 child: type,
4890 };
4891
4892 pub const ErrorUnion = struct {
4893 error_set: type,
4894 payload: type,
4895 };
4896
4897 pub const Error = struct {
4898 name: []const u8,
4899 value: usize,
4900 };
4901
4902 pub const ErrorSet = struct {
4903 errors: []Error,
4904 };
4905
4906 pub const EnumField = struct {
4907 name: []const u8,
4908 value: usize,
4909 };
4910
4911 pub const Enum = struct {
4912 layout: ContainerLayout,
4913 tag_type: type,
4914 fields: []EnumField,
4915 defs: []Definition,
4916 };
4917
4918 pub const UnionField = struct {
4919 name: []const u8,
4920 enum_field: ?EnumField,
4921 field_type: type,
4922 };
4923
4924 pub const Union = struct {
4925 layout: ContainerLayout,
4926 tag_type: type,
4927 fields: []UnionField,
4928 defs: []Definition,
4929 };
4930
4931 pub const CallingConvention = enum {
4932 Unspecified,
4933 C,
4934 Cold,
4935 Naked,
4936 Stdcall,
4937 Async,
4938 };
4939
4940 pub const FnArg = struct {
4941 is_generic: bool,
4942 is_noalias: bool,
4943 arg_type: type,
4944 };
4945
4946 pub const Fn = struct {
4947 calling_convention: CallingConvention,
4948 is_generic: bool,
4949 is_var_args: bool,
4950 return_type: type,
4951 async_allocator_type: type,
4952 args: []FnArg,
4953 };
4954
4955 pub const Promise = struct {
4956 child: type,
4957 };
4958
4959 pub const Definition = struct {
4960 name: []const u8,
4961 is_pub: bool,
4962 data: Data,
4963
4964 pub const Data = union(enum) {
4965 Type: type,
4966 Var: type,
4967 Fn: FnDef,
4968
4969 pub const FnDef = struct {
4970 fn_type: type,
4971 inline_type: Inline,
4972 calling_convention: CallingConvention,
4973 is_var_args: bool,
4974 is_extern: bool,
4975 is_export: bool,
4976 lib_name: ?[]const u8,
4977 return_type: type,
4978 arg_names: [][] const u8,
4979
4980 pub const Inline = enum {
4981 Auto,
4982 Always,
4983 Never,
4984 };
4985 };
4986 };
4987 };
48124988};
48134989 {#code_end#}
48144990 {#header_close#}
......@@ -5226,7 +5402,6 @@ pub const Os = enum {
52265402 rtems,
52275403 nacl,
52285404 cnk,
5229 bitrig,
52305405 aix,
52315406 cuda,
52325407 nvcl,
......@@ -5237,10 +5412,12 @@ pub const Os = enum {
52375412 watchos,
52385413 mesa3d,
52395414 contiki,
5415 amdpal,
52405416 zen,
52415417};
52425418
52435419pub const Arch = enum {
5420 armv8_3a,
52445421 armv8_2a,
52455422 armv8_1a,
52465423 armv8,
......@@ -5260,9 +5437,29 @@ pub const Arch = enum {
52605437 armv5,
52615438 armv5te,
52625439 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,
52645460 aarch64,
52655461 aarch64_be,
5462 arc,
52665463 avr,
52675464 bpfel,
52685465 bpfeb,
......@@ -5315,6 +5512,7 @@ pub const Arch = enum {
53155512pub const Environ = enum {
53165513 unknown,
53175514 gnu,
5515 gnuabin32,
53185516 gnuabi64,
53195517 gnueabi,
53205518 gnueabihf,
......@@ -5332,6 +5530,7 @@ pub const Environ = enum {
53325530 amdopencl,
53335531 coreclr,
53345532 opencl,
5533 simulator,
53355534};
53365535
53375536pub const ObjectFormat = enum {
......@@ -5358,10 +5557,23 @@ pub const AtomicOrder = enum {
53585557 SeqCst,
53595558};
53605559
5560pub const AtomicRmwOp = enum {
5561 Xchg,
5562 Add,
5563 Sub,
5564 And,
5565 Nand,
5566 Or,
5567 Xor,
5568 Max,
5569 Min,
5570};
5571
53615572pub const Mode = enum {
53625573 Debug,
53635574 ReleaseSafe,
53645575 ReleaseFast,
5576 ReleaseSmall,
53655577};
53665578
53675579pub const TypeId = enum {
......@@ -5380,7 +5592,7 @@ pub const TypeId = enum {
53805592 NullLiteral,
53815593 Nullable,
53825594 ErrorUnion,
5383 Error,
5595 ErrorSet,
53845596 Enum,
53855597 Union,
53865598 Fn,
......@@ -5389,6 +5601,176 @@ pub const TypeId = enum {
53895601 BoundFn,
53905602 ArgTuple,
53915603 Opaque,
5604 Promise,
5605};
5606
5607pub const TypeInfo = union(TypeId) {
5608 Type: void,
5609 Void: void,
5610 Bool: void,
5611 NoReturn: void,
5612 Int: Int,
5613 Float: Float,
5614 Pointer: Pointer,
5615 Array: Array,
5616 Struct: Struct,
5617 FloatLiteral: void,
5618 IntLiteral: void,
5619 UndefinedLiteral: void,
5620 NullLiteral: void,
5621 Nullable: Nullable,
5622 ErrorUnion: ErrorUnion,
5623 ErrorSet: ErrorSet,
5624 Enum: Enum,
5625 Union: Union,
5626 Fn: Fn,
5627 Namespace: void,
5628 Block: void,
5629 BoundFn: Fn,
5630 ArgTuple: void,
5631 Opaque: void,
5632 Promise: Promise,
5633
5634
5635 pub const Int = struct {
5636 is_signed: bool,
5637 bits: u8,
5638 };
5639
5640 pub const Float = struct {
5641 bits: u8,
5642 };
5643
5644 pub const Pointer = struct {
5645 is_const: bool,
5646 is_volatile: bool,
5647 alignment: u32,
5648 child: type,
5649 };
5650
5651 pub const Array = struct {
5652 len: usize,
5653 child: type,
5654 };
5655
5656 pub const ContainerLayout = enum {
5657 Auto,
5658 Extern,
5659 Packed,
5660 };
5661
5662 pub const StructField = struct {
5663 name: []const u8,
5664 offset: ?usize,
5665 field_type: type,
5666 };
5667
5668 pub const Struct = struct {
5669 layout: ContainerLayout,
5670 fields: []StructField,
5671 defs: []Definition,
5672 };
5673
5674 pub const Nullable = struct {
5675 child: type,
5676 };
5677
5678 pub const ErrorUnion = struct {
5679 error_set: type,
5680 payload: type,
5681 };
5682
5683 pub const Error = struct {
5684 name: []const u8,
5685 value: usize,
5686 };
5687
5688 pub const ErrorSet = struct {
5689 errors: []Error,
5690 };
5691
5692 pub const EnumField = struct {
5693 name: []const u8,
5694 value: usize,
5695 };
5696
5697 pub const Enum = struct {
5698 layout: ContainerLayout,
5699 tag_type: type,
5700 fields: []EnumField,
5701 defs: []Definition,
5702 };
5703
5704 pub const UnionField = struct {
5705 name: []const u8,
5706 enum_field: ?EnumField,
5707 field_type: type,
5708 };
5709
5710 pub const Union = struct {
5711 layout: ContainerLayout,
5712 tag_type: type,
5713 fields: []UnionField,
5714 defs: []Definition,
5715 };
5716
5717 pub const CallingConvention = enum {
5718 Unspecified,
5719 C,
5720 Cold,
5721 Naked,
5722 Stdcall,
5723 Async,
5724 };
5725
5726 pub const FnArg = struct {
5727 is_generic: bool,
5728 is_noalias: bool,
5729 arg_type: type,
5730 };
5731
5732 pub const Fn = struct {
5733 calling_convention: CallingConvention,
5734 is_generic: bool,
5735 is_var_args: bool,
5736 return_type: type,
5737 async_allocator_type: type,
5738 args: []FnArg,
5739 };
5740
5741 pub const Promise = struct {
5742 child: type,
5743 };
5744
5745 pub const Definition = struct {
5746 name: []const u8,
5747 is_pub: bool,
5748 data: Data,
5749
5750 pub const Data = union(enum) {
5751 Type: type,
5752 Var: type,
5753 Fn: FnDef,
5754
5755 pub const FnDef = struct {
5756 fn_type: type,
5757 inline_type: Inline,
5758 calling_convention: CallingConvention,
5759 is_var_args: bool,
5760 is_extern: bool,
5761 is_export: bool,
5762 lib_name: ?[]const u8,
5763 return_type: type,
5764 arg_names: [][] const u8,
5765
5766 pub const Inline = enum {
5767 Auto,
5768 Always,
5769 Never,
5770 };
5771 };
5772 };
5773 };
53925774};
53935775
53945776pub const FloatMode = enum {
......@@ -5402,7 +5784,7 @@ pub const Endian = enum {
54025784};
54035785
54045786pub const endian = Endian.Little;
5405pub const is_test = false;
5787pub const is_test = true;
54065788pub const os = Os.linux;
54075789pub const arch = Arch.x86_64;
54085790pub const environ = Environ.gnu;
......@@ -5410,6 +5792,7 @@ pub const object_format = ObjectFormat.elf;
54105792pub const mode = Mode.Debug;
54115793pub const link_libc = false;
54125794pub const have_error_return_tracing = true;
5795pub const __zig_test_fn_slice = {}; // overwritten later
54135796 {#code_end#}
54145797 {#see_also|Build Mode#}
54155798 {#header_close#}
......@@ -6068,7 +6451,7 @@ hljs.registerLanguage("zig", function(t) {
60686451 a = t.IR + "\\s*\\(",
60696452 c = {
60706453 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",
60726455 literal: "true false null undefined"
60736456 },
60746457 n = [e, t.CLCM, t.CBCM, s, r];
src/all_types.hpp+9
......@@ -1293,6 +1293,7 @@ enum BuiltinFnId {
12931293 BuiltinFnIdMemberType,
12941294 BuiltinFnIdMemberName,
12951295 BuiltinFnIdField,
1296 BuiltinFnIdTypeInfo,
12961297 BuiltinFnIdTypeof,
12971298 BuiltinFnIdAddWithOverflow,
12981299 BuiltinFnIdSubWithOverflow,
......@@ -1506,6 +1507,7 @@ struct CodeGen {
15061507 HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names;
15071508 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
15081509 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;
15091511
15101512
15111513 ZigList<ImportTableEntry *> import_queue;
......@@ -2035,6 +2037,7 @@ enum IrInstructionId {
20352037 IrInstructionIdTagType,
20362038 IrInstructionIdFieldParentPtr,
20372039 IrInstructionIdOffsetOf,
2040 IrInstructionIdTypeInfo,
20382041 IrInstructionIdTypeId,
20392042 IrInstructionIdSetEvalBranchQuota,
20402043 IrInstructionIdPtrTypeOf,
......@@ -2856,6 +2859,12 @@ struct IrInstructionOffsetOf {
28562859 IrInstruction *field_name;
28572860};
28582861
2862struct IrInstructionTypeInfo {
2863 IrInstruction base;
2864
2865 IrInstruction *type_value;
2866};
2867
28592868struct IrInstructionTypeId {
28602869 IrInstruction base;
28612870
src/analyze.cpp+7-1
......@@ -2325,8 +2325,14 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
23252325 HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
23262326 occupied_tag_values.init(field_count);
23272327
2328 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
2328 TypeTableEntry *tag_int_type;
2329 if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
2330 tag_int_type = get_c_int_type(g, CIntTypeInt);
2331 } else {
2332 tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
2333 }
23292334
2335 // TODO: Are extern enums allowed to have an init_arg_expr?
23302336 if (decl_node->data.container_decl.init_arg_expr != nullptr) {
23312337 TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
23322338 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) {
728728 render_node_grouped(ar, field_node->data.struct_field.type);
729729 }
730730 if (field_node->data.struct_field.value != nullptr) {
731 fprintf(ar->f, "= ");
731 fprintf(ar->f, " = ");
732732 render_node_grouped(ar, field_node->data.struct_field.value);
733733 }
734734 fprintf(ar->f, ",\n");
src/codegen.cpp+187
......@@ -88,6 +88,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
8888 g->exported_symbol_names.init(8);
8989 g->external_prototypes.init(8);
9090 g->string_literals_table.init(16);
91 g->type_info_cache.init(32);
9192 g->is_test_build = false;
9293 g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
9394 buf_resize(&g->global_asm, 0);
......@@ -4417,6 +4418,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
44174418 case IrInstructionIdDeclRef:
44184419 case IrInstructionIdSwitchVar:
44194420 case IrInstructionIdOffsetOf:
4421 case IrInstructionIdTypeInfo:
44204422 case IrInstructionIdTypeId:
44214423 case IrInstructionIdSetEvalBranchQuota:
44224424 case IrInstructionIdPtrTypeOf:
......@@ -6040,6 +6042,7 @@ static void define_builtin_fns(CodeGen *g) {
60406042 create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
60416043 create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);
60426044 create_builtin_fn(g, BuiltinFnIdField, "field", 2);
6045 create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1);
60436046 create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
60446047 create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
60456048 create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
......@@ -6259,6 +6262,190 @@ static void define_builtin_compile_vars(CodeGen *g) {
62596262 }
62606263 buf_appendf(contents, "};\n\n");
62616264 }
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 }
62626449 {
62636450 buf_appendf(contents,
62646451 "pub const FloatMode = enum {\n"
src/ir.cpp+963-1
......@@ -145,6 +145,8 @@ static bool ir_should_inline(IrExecutable *exec, Scope *scope) {
145145 while (scope != nullptr) {
146146 if (scope->id == ScopeIdCompTime)
147147 return true;
148 if (scope->id == ScopeIdFnDef)
149 break;
148150 scope = scope->parent;
149151 }
150152 return false;
......@@ -615,6 +617,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) {
615617 return IrInstructionIdOffsetOf;
616618}
617619
620static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) {
621 return IrInstructionIdTypeInfo;
622}
623
618624static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeId *) {
619625 return IrInstructionIdTypeId;
620626}
......@@ -2440,6 +2446,16 @@ static IrInstruction *ir_build_offset_of(IrBuilder *irb, Scope *scope, AstNode *
24402446 return &instruction->base;
24412447}
24422448
2449static IrInstruction *ir_build_type_info(IrBuilder *irb, Scope *scope, AstNode *source_node,
2450 IrInstruction *type_value) {
2451 IrInstructionTypeInfo *instruction = ir_build_instruction<IrInstructionTypeInfo>(irb, scope, source_node);
2452 instruction->type_value = type_value;
2453
2454 ir_ref_instruction(type_value, irb->current_basic_block);
2455
2456 return &instruction->base;
2457}
2458
24432459static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node,
24442460 IrInstruction *type_value)
24452461{
......@@ -4083,6 +4099,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40834099
40844100 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
40854101 }
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 }
40864112 case BuiltinFnIdBreakpoint:
40874113 return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval);
40884114 case BuiltinFnIdReturnAddress:
......@@ -13386,7 +13412,6 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
1338613412 return ira->codegen->invalid_instruction;
1338713413}
1338813414
13389
1339013415static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
1339113416 IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type)
1339213417{
......@@ -13448,6 +13473,51 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
1344813473 } else if (bare_type->id == TypeTableEntryIdUnion) {
1344913474 TypeUnionField *field = find_union_type_field(bare_type, field_name);
1345013475 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
1345113521 IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field);
1345213522 result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
1345313523 get_abi_alignment(ira->codegen, field->type_entry), 0, 0);
......@@ -15677,6 +15747,895 @@ static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira,
1567715747 return ira->codegen->builtin_types.entry_num_lit_int;
1567815748}
1567915749
15750static 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
15761static 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
15801static 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
16049static 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
16612static 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
1568016639static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,
1568116640 IrInstructionTypeId *instruction)
1568216641{
......@@ -18578,6 +19537,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1857819537 return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction);
1857919538 case IrInstructionIdOffsetOf:
1858019539 return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction);
19540 case IrInstructionIdTypeInfo:
19541 return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction);
1858119542 case IrInstructionIdTypeId:
1858219543 return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction);
1858319544 case IrInstructionIdSetEvalBranchQuota:
......@@ -18844,6 +19805,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1884419805 case IrInstructionIdTagName:
1884519806 case IrInstructionIdFieldParentPtr:
1884619807 case IrInstructionIdOffsetOf:
19808 case IrInstructionIdTypeInfo:
1884719809 case IrInstructionIdTypeId:
1884819810 case IrInstructionIdAlignCast:
1884919811 case IrInstructionIdOpaqueType:
src/ir_print.cpp+9
......@@ -966,6 +966,12 @@ static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction)
966966 fprintf(irp->f, ")");
967967}
968968
969static void ir_print_type_info(IrPrint *irp, IrInstructionTypeInfo *instruction) {
970 fprintf(irp->f, "@typeInfo(");
971 ir_print_other_instruction(irp, instruction->type_value);
972 fprintf(irp->f, ")");
973}
974
969975static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) {
970976 fprintf(irp->f, "@typeId(");
971977 ir_print_other_instruction(irp, instruction->type_value);
......@@ -1536,6 +1542,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15361542 case IrInstructionIdOffsetOf:
15371543 ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction);
15381544 break;
1545 case IrInstructionIdTypeInfo:
1546 ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction);
1547 break;
15391548 case IrInstructionIdTypeId:
15401549 ir_print_type_id(irp, (IrInstructionTypeId *)instruction);
15411550 break;
src/translate_c.cpp+39-69
......@@ -3746,6 +3746,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
37463746 return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name);
37473747 }
37483748
3749
37493750 bool pure_enum = true;
37503751 uint32_t field_count = 0;
37513752 for (auto it = enum_def->enumerator_begin(),
......@@ -3757,84 +3758,53 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
37573758 pure_enum = false;
37583759 }
37593760 }
3760
37613761 AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation());
37623762 assert(tag_int_type);
37633763
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;
38203774 }
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;
38283777 for (auto it = enum_def->enumerator_begin(),
38293778 it_end = enum_def->enumerator_end();
3830 it != it_end; ++it)
3779 it != it_end; ++it, i += 1)
38313780 {
38323781 const EnumConstantDecl *enum_const = *it;
38333782
38343783 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 }
38383808 }
38393809
38403810 if (is_anonymous) {
......@@ -3845,7 +3815,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
38453815 add_global_weak_alias(c, bare_name, full_type_name);
38463816 add_global_var(c, full_type_name, enum_node);
38473817 c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node);
3848 return symbol_node;
3818 return enum_node;
38493819 }
38503820}
38513821
std/array_list.zig+55-1
......@@ -44,6 +44,10 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
4444 return l.toSliceConst()[n];
4545 }
4646
47 pub fn count(self: &const Self) usize {
48 return self.len;
49 }
50
4751 /// ArrayList takes ownership of the passed in slice. The slice must have been
4852 /// allocated with `allocator`.
4953 /// Deinitialize with `deinit` or use `toOwnedSlice`.
......@@ -128,6 +132,27 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
128132 return null;
129133 return self.pop();
130134 }
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 }
131156 };
132157}
133158
......@@ -157,6 +182,35 @@ test "basic ArrayList test" {
157182 assert(list.len == 9);
158183}
159184
185test "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
160214test "insert ArrayList test" {
161215 var list = ArrayList(i32).init(debug.global_allocator);
162216 defer list.deinit();
......@@ -174,4 +228,4 @@ test "insert ArrayList test" {
174228 const items = []const i32 { 1 };
175229 try list.insertSlice(0, items[0..0]);
176230 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 {
3131 }
3232
3333 pub fn get(self: &Self) ?&Node {
34 var head = @atomicLoad(&Node, &self.head, AtomicOrder.Acquire);
34 var head = @atomicLoad(&Node, &self.head, AtomicOrder.SeqCst);
3535 while (true) {
3636 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;
3838 }
3939 }
4040 };
......@@ -49,14 +49,20 @@ const Context = struct {
4949 get_count: usize,
5050 puts_done: u8, // TODO make this a bool
5151};
52const puts_per_thread = 10000;
52
53// TODO add lazy evaluated build options and then put puts_per_thread behind
54// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
55// CI we would use a less aggressive setting since at 1 core, while we still
56// want this test to pass, we need a smaller value since there is so much thrashing
57// we would also use a less aggressive setting when running in valgrind
58const puts_per_thread = 500;
5359const put_thread_count = 3;
5460
5561test "std.atomic.queue" {
5662 var direct_allocator = std.heap.DirectAllocator.init();
5763 defer direct_allocator.deinit();
5864
59 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 64 * 1024 * 1024);
65 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
6066 defer direct_allocator.allocator.free(plenty_of_memory);
6167
6268 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 {
3535 }
3636
3737 pub fn pop(self: &Self) ?&Node {
38 var root = @atomicLoad(?&Node, &self.root, AtomicOrder.Acquire);
38 var root = @atomicLoad(?&Node, &self.root, AtomicOrder.SeqCst);
3939 while (true) {
4040 root = @cmpxchgWeak(?&Node, &self.root, root, (root ?? return null).next, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return root;
4141 }
......@@ -56,14 +56,19 @@ const Context = struct {
5656 get_count: usize,
5757 puts_done: u8, // TODO make this a bool
5858};
59const puts_per_thread = 1000;
59// TODO add lazy evaluated build options and then put puts_per_thread behind
60// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
61// CI we would use a less aggressive setting since at 1 core, while we still
62// want this test to pass, we need a smaller value since there is so much thrashing
63// we would also use a less aggressive setting when running in valgrind
64const puts_per_thread = 500;
6065const put_thread_count = 3;
6166
6267test "std.atomic.stack" {
6368 var direct_allocator = std.heap.DirectAllocator.init();
6469 defer direct_allocator.deinit();
6570
66 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 64 * 1024 * 1024);
71 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
6772 defer direct_allocator.allocator.free(plenty_of_memory);
6873
6974 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 {
5050 }
5151
5252 pub fn count(self: &const BufMap) usize {
53 return self.hash_map.size;
53 return self.hash_map.count();
5454 }
5555
5656 pub fn iterator(self: &const BufMap) BufMapHashMap.Iterator {
......@@ -87,4 +87,4 @@ test "BufMap" {
8787
8888 bufmap.delete("x");
8989 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 {
3838 }
3939
4040 pub fn count(self: &const BufSet) usize {
41 return self.hash_map.size;
41 return self.hash_map.count();
4242 }
4343
4444 pub fn iterator(self: &const BufSet) BufSetHashMap.Iterator {
......@@ -59,4 +59,3 @@ pub const BufSet = struct {
5959 return result;
6060 }
6161};
62
std/hash_map.zig+52-1
......@@ -54,6 +54,14 @@ pub fn HashMap(comptime K: type, comptime V: type,
5454 }
5555 unreachable; // no next item
5656 }
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 }
5765 };
5866
5967 pub fn init(allocator: &Allocator) Self {
......@@ -79,6 +87,10 @@ pub fn HashMap(comptime K: type, comptime V: type,
7987 hm.incrementModificationCount();
8088 }
8189
90 pub fn count(hm: &const Self) usize {
91 return hm.size;
92 }
93
8294 /// Returns the value that was already there.
8395 pub fn put(hm: &Self, key: K, value: &const V) !?V {
8496 if (hm.entries.len == 0) {
......@@ -258,10 +270,49 @@ test "basic hash map usage" {
258270 assert(map.get(2) == null);
259271}
260272
273test "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
261312fn hash_i32(x: i32) u32 {
262313 return @bitCast(u32, x);
263314}
264315
265316fn eql_i32(a: i32, b: i32) bool {
266317 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");
2323pub const hash = @import("hash/index.zig");
2424pub const heap = @import("heap.zig");
2525pub const io = @import("io.zig");
26pub const json = @import("json.zig");
2627pub const macho = @import("macho.zig");
2728pub const math = @import("math/index.zig");
2829pub const mem = @import("mem.zig");
......@@ -56,6 +57,7 @@ test "std" {
5657 _ = @import("fmt/index.zig");
5758 _ = @import("hash/index.zig");
5859 _ = @import("io.zig");
60 _ = @import("json.zig");
5961 _ = @import("macho.zig");
6062 _ = @import("math/index.zig");
6163 _ = @import("mem.zig");
std/json.zig created+1304
......@@ -0,0 +1,1304 @@
1// JSON parser conforming to RFC8259.
2//
3// https://tools.ietf.org/html/rfc8259
4
5const std = @import("index.zig");
6const mem = std.mem;
7
8const u1 = @IntType(false, 1);
9const u256 = @IntType(false, 256);
10
11// A single token slice into the parent string.
12//
13// Use `token.slice()` on the inptu at the current position to get the current slice.
14pub const Token = struct {
15 id: Id,
16 // How many bytes do we skip before counting
17 offset: u1,
18 // Whether string contains a \uXXXX sequence and cannot be zero-copied
19 string_has_escape: bool,
20 // Whether number is simple and can be represented by an integer (i.e. no `.` or `e`)
21 number_is_integer: bool,
22 // How many bytes from the current position behind the start of this token is.
23 count: usize,
24
25 pub const Id = enum {
26 ObjectBegin,
27 ObjectEnd,
28 ArrayBegin,
29 ArrayEnd,
30 String,
31 Number,
32 True,
33 False,
34 Null,
35 };
36
37 pub fn init(id: Id, count: usize, offset: u1) Token {
38 return Token {
39 .id = id,
40 .offset = offset,
41 .string_has_escape = false,
42 .number_is_integer = true,
43 .count = count,
44 };
45 }
46
47 pub fn initString(count: usize, has_unicode_escape: bool) Token {
48 return Token {
49 .id = Id.String,
50 .offset = 0,
51 .string_has_escape = has_unicode_escape,
52 .number_is_integer = true,
53 .count = count,
54 };
55 }
56
57 pub fn initNumber(count: usize, number_is_integer: bool) Token {
58 return Token {
59 .id = Id.Number,
60 .offset = 0,
61 .string_has_escape = false,
62 .number_is_integer = number_is_integer,
63 .count = count,
64 };
65 }
66
67 // A marker token is a zero-length
68 pub fn initMarker(id: Id) Token {
69 return Token {
70 .id = id,
71 .offset = 0,
72 .string_has_escape = false,
73 .number_is_integer = true,
74 .count = 0,
75 };
76 }
77
78 // Slice into the underlying input string.
79 pub fn slice(self: &const Token, input: []const u8, i: usize) []const u8 {
80 return input[i + self.offset - self.count .. i + self.offset];
81 }
82};
83
84// A small streaming JSON parser. This accepts input one byte at a time and returns tokens as
85// they are encountered. No copies or allocations are performed during parsing and the entire
86// parsing state requires ~40-50 bytes of stack space.
87//
88// Conforms strictly to RFC8529.
89const StreamingJsonParser = struct {
90 // Current state
91 state: State,
92 // How many bytes we have counted for the current token
93 count: usize,
94 // What state to follow after parsing a string (either property or value string)
95 after_string_state: State,
96 // What state to follow after parsing a value (either top-level or value end)
97 after_value_state: State,
98 // If we stopped now, would the complete parsed string to now be a valid json string
99 complete: bool,
100 // Current token flags to pass through to the next generated, see Token.
101 string_has_escape: bool,
102 number_is_integer: bool,
103
104 // Bit-stack for nested object/map literals (max 255 nestings).
105 stack: u256,
106 stack_used: u8,
107
108 const object_bit = 0;
109 const array_bit = 1;
110 const max_stack_size = @maxValue(u8);
111
112 pub fn init() StreamingJsonParser {
113 var p: StreamingJsonParser = undefined;
114 p.reset();
115 return p;
116 }
117
118 pub fn reset(p: &StreamingJsonParser) void {
119 p.state = State.TopLevelBegin;
120 p.count = 0;
121 // Set before ever read in main transition function
122 p.after_string_state = undefined;
123 p.after_value_state = State.ValueEnd; // handle end of values normally
124 p.stack = 0;
125 p.stack_used = 0;
126 p.complete = false;
127 p.string_has_escape = false;
128 p.number_is_integer = true;
129 }
130
131 pub const State = enum {
132 // These must be first with these explicit values as we rely on them for indexing the
133 // bit-stack directly and avoiding a branch.
134 ObjectSeparator = 0,
135 ValueEnd = 1,
136
137 TopLevelBegin,
138 TopLevelEnd,
139
140 ValueBegin,
141 ValueBeginNoClosing,
142
143 String,
144 StringUtf8Byte3,
145 StringUtf8Byte2,
146 StringUtf8Byte1,
147 StringEscapeCharacter,
148 StringEscapeHexUnicode4,
149 StringEscapeHexUnicode3,
150 StringEscapeHexUnicode2,
151 StringEscapeHexUnicode1,
152
153 Number,
154 NumberMaybeDotOrExponent,
155 NumberMaybeDigitOrDotOrExponent,
156 NumberFractionalRequired,
157 NumberFractional,
158 NumberMaybeExponent,
159 NumberExponent,
160 NumberExponentDigitsRequired,
161 NumberExponentDigits,
162
163 TrueLiteral1,
164 TrueLiteral2,
165 TrueLiteral3,
166
167 FalseLiteral1,
168 FalseLiteral2,
169 FalseLiteral3,
170 FalseLiteral4,
171
172 NullLiteral1,
173 NullLiteral2,
174 NullLiteral3,
175
176 // Only call this function to generate array/object final state.
177 pub fn fromInt(x: var) State {
178 std.debug.assert(x == 0 or x == 1);
179 const T = @TagType(State);
180 return State(T(x));
181 }
182 };
183
184 pub const Error = error {
185 InvalidTopLevel,
186 TooManyNestedItems,
187 TooManyClosingItems,
188 InvalidValueBegin,
189 InvalidValueEnd,
190 UnbalancedBrackets,
191 UnbalancedBraces,
192 UnexpectedClosingBracket,
193 UnexpectedClosingBrace,
194 InvalidNumber,
195 InvalidSeparator,
196 InvalidLiteral,
197 InvalidEscapeCharacter,
198 InvalidUnicodeHexSymbol,
199 InvalidUtf8Byte,
200 InvalidTopLevelTrailing,
201 InvalidControlCharacter,
202 };
203
204 // Give another byte to the parser and obtain any new tokens. This may (rarely) return two
205 // tokens. token2 is always null if token1 is null.
206 //
207 // There is currently no error recovery on a bad stream.
208 pub fn feed(p: &StreamingJsonParser, c: u8, token1: &?Token, token2: &?Token) Error!void {
209 *token1 = null;
210 *token2 = null;
211 p.count += 1;
212
213 // unlikely
214 if (try p.transition(c, token1)) {
215 _ = try p.transition(c, token2);
216 }
217 }
218
219 // Perform a single transition on the state machine and return any possible token.
220 fn transition(p: &StreamingJsonParser, c: u8, token: &?Token) Error!bool {
221 switch (p.state) {
222 State.TopLevelBegin => switch (c) {
223 '{' => {
224 p.stack <<= 1;
225 p.stack |= object_bit;
226 p.stack_used += 1;
227
228 p.state = State.ValueBegin;
229 p.after_string_state = State.ObjectSeparator;
230
231 *token = Token.initMarker(Token.Id.ObjectBegin);
232 },
233 '[' => {
234 p.stack <<= 1;
235 p.stack |= array_bit;
236 p.stack_used += 1;
237
238 p.state = State.ValueBegin;
239 p.after_string_state = State.ValueEnd;
240
241 *token = Token.initMarker(Token.Id.ArrayBegin);
242 },
243 '-' => {
244 p.number_is_integer = true;
245 p.state = State.Number;
246 p.after_value_state = State.TopLevelEnd;
247 p.count = 0;
248 },
249 '0' => {
250 p.number_is_integer = true;
251 p.state = State.NumberMaybeDotOrExponent;
252 p.after_value_state = State.TopLevelEnd;
253 p.count = 0;
254 },
255 '1' ... '9' => {
256 p.number_is_integer = true;
257 p.state = State.NumberMaybeDigitOrDotOrExponent;
258 p.after_value_state = State.TopLevelEnd;
259 p.count = 0;
260 },
261 '"' => {
262 p.state = State.String;
263 p.after_value_state = State.TopLevelEnd;
264 // We don't actually need the following since after_value_state should override.
265 p.after_string_state = State.ValueEnd;
266 p.string_has_escape = false;
267 p.count = 0;
268 },
269 't' => {
270 p.state = State.TrueLiteral1;
271 p.after_value_state = State.TopLevelEnd;
272 p.count = 0;
273 },
274 'f' => {
275 p.state = State.FalseLiteral1;
276 p.after_value_state = State.TopLevelEnd;
277 p.count = 0;
278 },
279 'n' => {
280 p.state = State.NullLiteral1;
281 p.after_value_state = State.TopLevelEnd;
282 p.count = 0;
283 },
284 0x09, 0x0A, 0x0D, 0x20 => {
285 // whitespace
286 },
287 else => {
288 return error.InvalidTopLevel;
289 },
290 },
291
292 State.TopLevelEnd => switch (c) {
293 0x09, 0x0A, 0x0D, 0x20 => {
294 // whitespace
295 },
296 else => {
297 return error.InvalidTopLevelTrailing;
298 },
299 },
300
301 State.ValueBegin => switch (c) {
302 // NOTE: These are shared in ValueEnd as well, think we can reorder states to
303 // be a bit clearer and avoid this duplication.
304 '}' => {
305 // unlikely
306 if (p.stack & 1 != object_bit) {
307 return error.UnexpectedClosingBracket;
308 }
309 if (p.stack_used == 0) {
310 return error.TooManyClosingItems;
311 }
312
313 p.state = State.ValueBegin;
314 p.after_string_state = State.fromInt(p.stack & 1);
315
316 p.stack >>= 1;
317 p.stack_used -= 1;
318
319 switch (p.stack_used) {
320 0 => {
321 p.complete = true;
322 p.state = State.TopLevelEnd;
323 },
324 else => {},
325 }
326
327 *token = Token.initMarker(Token.Id.ObjectEnd);
328 },
329 ']' => {
330 if (p.stack & 1 != array_bit) {
331 return error.UnexpectedClosingBrace;
332 }
333 if (p.stack_used == 0) {
334 return error.TooManyClosingItems;
335 }
336
337 p.state = State.ValueBegin;
338 p.after_string_state = State.fromInt(p.stack & 1);
339
340 p.stack >>= 1;
341 p.stack_used -= 1;
342
343 switch (p.stack_used) {
344 0 => {
345 p.complete = true;
346 p.state = State.TopLevelEnd;
347 },
348 else => {},
349 }
350
351 *token = Token.initMarker(Token.Id.ArrayEnd);
352 },
353 '{' => {
354 if (p.stack_used == max_stack_size) {
355 return error.TooManyNestedItems;
356 }
357
358 p.stack <<= 1;
359 p.stack |= object_bit;
360 p.stack_used += 1;
361
362 p.state = State.ValueBegin;
363 p.after_string_state = State.ObjectSeparator;
364
365 *token = Token.initMarker(Token.Id.ObjectBegin);
366 },
367 '[' => {
368 if (p.stack_used == max_stack_size) {
369 return error.TooManyNestedItems;
370 }
371
372 p.stack <<= 1;
373 p.stack |= array_bit;
374 p.stack_used += 1;
375
376 p.state = State.ValueBegin;
377 p.after_string_state = State.ValueEnd;
378
379 *token = Token.initMarker(Token.Id.ArrayBegin);
380 },
381 '-' => {
382 p.state = State.Number;
383 p.count = 0;
384 },
385 '0' => {
386 p.state = State.NumberMaybeDotOrExponent;
387 p.count = 0;
388 },
389 '1' ... '9' => {
390 p.state = State.NumberMaybeDigitOrDotOrExponent;
391 p.count = 0;
392 },
393 '"' => {
394 p.state = State.String;
395 p.count = 0;
396 },
397 't' => {
398 p.state = State.TrueLiteral1;
399 p.count = 0;
400 },
401 'f' => {
402 p.state = State.FalseLiteral1;
403 p.count = 0;
404 },
405 'n' => {
406 p.state = State.NullLiteral1;
407 p.count = 0;
408 },
409 0x09, 0x0A, 0x0D, 0x20 => {
410 // whitespace
411 },
412 else => {
413 return error.InvalidValueBegin;
414 },
415 },
416
417 // TODO: A bit of duplication here and in the following state, redo.
418 State.ValueBeginNoClosing => switch (c) {
419 '{' => {
420 if (p.stack_used == max_stack_size) {
421 return error.TooManyNestedItems;
422 }
423
424 p.stack <<= 1;
425 p.stack |= object_bit;
426 p.stack_used += 1;
427
428 p.state = State.ValueBegin;
429 p.after_string_state = State.ObjectSeparator;
430
431 *token = Token.initMarker(Token.Id.ObjectBegin);
432 },
433 '[' => {
434 if (p.stack_used == max_stack_size) {
435 return error.TooManyNestedItems;
436 }
437
438 p.stack <<= 1;
439 p.stack |= array_bit;
440 p.stack_used += 1;
441
442 p.state = State.ValueBegin;
443 p.after_string_state = State.ValueEnd;
444
445 *token = Token.initMarker(Token.Id.ArrayBegin);
446 },
447 '-' => {
448 p.state = State.Number;
449 p.count = 0;
450 },
451 '0' => {
452 p.state = State.NumberMaybeDotOrExponent;
453 p.count = 0;
454 },
455 '1' ... '9' => {
456 p.state = State.NumberMaybeDigitOrDotOrExponent;
457 p.count = 0;
458 },
459 '"' => {
460 p.state = State.String;
461 p.count = 0;
462 },
463 't' => {
464 p.state = State.TrueLiteral1;
465 p.count = 0;
466 },
467 'f' => {
468 p.state = State.FalseLiteral1;
469 p.count = 0;
470 },
471 'n' => {
472 p.state = State.NullLiteral1;
473 p.count = 0;
474 },
475 0x09, 0x0A, 0x0D, 0x20 => {
476 // whitespace
477 },
478 else => {
479 return error.InvalidValueBegin;
480 },
481 },
482
483 State.ValueEnd => switch (c) {
484 ',' => {
485 p.after_string_state = State.fromInt(p.stack & 1);
486 p.state = State.ValueBeginNoClosing;
487 },
488 ']' => {
489 if (p.stack_used == 0) {
490 return error.UnbalancedBrackets;
491 }
492
493 p.state = State.ValueEnd;
494 p.after_string_state = State.fromInt(p.stack & 1);
495
496 p.stack >>= 1;
497 p.stack_used -= 1;
498
499 if (p.stack_used == 0) {
500 p.complete = true;
501 p.state = State.TopLevelEnd;
502 }
503
504 *token = Token.initMarker(Token.Id.ArrayEnd);
505 },
506 '}' => {
507 if (p.stack_used == 0) {
508 return error.UnbalancedBraces;
509 }
510
511 p.state = State.ValueEnd;
512 p.after_string_state = State.fromInt(p.stack & 1);
513
514 p.stack >>= 1;
515 p.stack_used -= 1;
516
517 if (p.stack_used == 0) {
518 p.complete = true;
519 p.state = State.TopLevelEnd;
520 }
521
522 *token = Token.initMarker(Token.Id.ObjectEnd);
523 },
524 0x09, 0x0A, 0x0D, 0x20 => {
525 // whitespace
526 },
527 else => {
528 return error.InvalidValueEnd;
529 },
530 },
531
532 State.ObjectSeparator => switch (c) {
533 ':' => {
534 p.state = State.ValueBegin;
535 p.after_string_state = State.ValueEnd;
536 },
537 0x09, 0x0A, 0x0D, 0x20 => {
538 // whitespace
539 },
540 else => {
541 return error.InvalidSeparator;
542 },
543 },
544
545 State.String => switch (c) {
546 0x00 ... 0x1F => {
547 return error.InvalidControlCharacter;
548 },
549 '"' => {
550 p.state = p.after_string_state;
551 if (p.after_value_state == State.TopLevelEnd) {
552 p.state = State.TopLevelEnd;
553 p.complete = true;
554 }
555
556 *token = Token.initString(p.count - 1, p.string_has_escape);
557 },
558 '\\' => {
559 p.state = State.StringEscapeCharacter;
560 },
561 0x20, 0x21, 0x23 ... 0x5B, 0x5D ... 0x7F => {
562 // non-control ascii
563 },
564 0xC0 ... 0xDF => {
565 p.state = State.StringUtf8Byte1;
566 },
567 0xE0 ... 0xEF => {
568 p.state = State.StringUtf8Byte2;
569 },
570 0xF0 ... 0xFF => {
571 p.state = State.StringUtf8Byte3;
572 },
573 else => {
574 return error.InvalidUtf8Byte;
575 },
576 },
577
578 State.StringUtf8Byte3 => switch (c >> 6) {
579 0b10 => p.state = State.StringUtf8Byte2,
580 else => return error.InvalidUtf8Byte,
581 },
582
583 State.StringUtf8Byte2 => switch (c >> 6) {
584 0b10 => p.state = State.StringUtf8Byte1,
585 else => return error.InvalidUtf8Byte,
586 },
587
588 State.StringUtf8Byte1 => switch (c >> 6) {
589 0b10 => p.state = State.String,
590 else => return error.InvalidUtf8Byte,
591 },
592
593 State.StringEscapeCharacter => switch (c) {
594 // NOTE: '/' is allowed as an escaped character but it also is allowed
595 // as unescaped according to the RFC. There is a reported errata which suggests
596 // removing the non-escaped variant but it makes more sense to simply disallow
597 // it as an escape code here.
598 //
599 // The current JSONTestSuite tests rely on both of this behaviour being present
600 // however, so we default to the status quo where both are accepted until this
601 // is further clarified.
602 '"', '\\', '/', 'b', 'f', 'n', 'r', 't' => {
603 p.string_has_escape = true;
604 p.state = State.String;
605 },
606 'u' => {
607 p.string_has_escape = true;
608 p.state = State.StringEscapeHexUnicode4;
609 },
610 else => {
611 return error.InvalidEscapeCharacter;
612 },
613 },
614
615 State.StringEscapeHexUnicode4 => switch (c) {
616 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
617 p.state = State.StringEscapeHexUnicode3;
618 },
619 else => return error.InvalidUnicodeHexSymbol,
620 },
621
622 State.StringEscapeHexUnicode3 => switch (c) {
623 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
624 p.state = State.StringEscapeHexUnicode2;
625 },
626 else => return error.InvalidUnicodeHexSymbol,
627 },
628
629 State.StringEscapeHexUnicode2 => switch (c) {
630 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
631 p.state = State.StringEscapeHexUnicode1;
632 },
633 else => return error.InvalidUnicodeHexSymbol,
634 },
635
636 State.StringEscapeHexUnicode1 => switch (c) {
637 '0' ... '9', 'A' ... 'F', 'a' ... 'f' => {
638 p.state = State.String;
639 },
640 else => return error.InvalidUnicodeHexSymbol,
641 },
642
643 State.Number => {
644 p.complete = p.after_value_state == State.TopLevelEnd;
645 switch (c) {
646 '0' => {
647 p.state = State.NumberMaybeDotOrExponent;
648 },
649 '1' ... '9' => {
650 p.state = State.NumberMaybeDigitOrDotOrExponent;
651 },
652 else => {
653 return error.InvalidNumber;
654 },
655 }
656 },
657
658 State.NumberMaybeDotOrExponent => {
659 p.complete = p.after_value_state == State.TopLevelEnd;
660 switch (c) {
661 '.' => {
662 p.number_is_integer = false;
663 p.state = State.NumberFractionalRequired;
664 },
665 'e', 'E' => {
666 p.number_is_integer = false;
667 p.state = State.NumberExponent;
668 },
669 else => {
670 p.state = p.after_value_state;
671 *token = Token.initNumber(p.count, p.number_is_integer);
672 return true;
673 },
674 }
675 },
676
677 State.NumberMaybeDigitOrDotOrExponent => {
678 p.complete = p.after_value_state == State.TopLevelEnd;
679 switch (c) {
680 '.' => {
681 p.number_is_integer = false;
682 p.state = State.NumberFractionalRequired;
683 },
684 'e', 'E' => {
685 p.number_is_integer = false;
686 p.state = State.NumberExponent;
687 },
688 '0' ... '9' => {
689 // another digit
690 },
691 else => {
692 p.state = p.after_value_state;
693 *token = Token.initNumber(p.count, p.number_is_integer);
694 return true;
695 },
696 }
697 },
698
699 State.NumberFractionalRequired => {
700 p.complete = p.after_value_state == State.TopLevelEnd;
701 switch (c) {
702 '0' ... '9' => {
703 p.state = State.NumberFractional;
704 },
705 else => {
706 return error.InvalidNumber;
707 },
708 }
709 },
710
711 State.NumberFractional => {
712 p.complete = p.after_value_state == State.TopLevelEnd;
713 switch (c) {
714 '0' ... '9' => {
715 // another digit
716 },
717 'e', 'E' => {
718 p.number_is_integer = false;
719 p.state = State.NumberExponent;
720 },
721 else => {
722 p.state = p.after_value_state;
723 *token = Token.initNumber(p.count, p.number_is_integer);
724 return true;
725 },
726 }
727 },
728
729 State.NumberMaybeExponent => {
730 p.complete = p.after_value_state == State.TopLevelEnd;
731 switch (c) {
732 'e', 'E' => {
733 p.number_is_integer = false;
734 p.state = State.NumberExponent;
735 },
736 else => {
737 p.state = p.after_value_state;
738 *token = Token.initNumber(p.count, p.number_is_integer);
739 return true;
740 },
741 }
742 },
743
744 State.NumberExponent => switch (c) {
745 '-', '+', => {
746 p.complete = false;
747 p.state = State.NumberExponentDigitsRequired;
748 },
749 '0' ... '9' => {
750 p.complete = p.after_value_state == State.TopLevelEnd;
751 p.state = State.NumberExponentDigits;
752 },
753 else => {
754 return error.InvalidNumber;
755 },
756 },
757
758 State.NumberExponentDigitsRequired => switch (c) {
759 '0' ... '9' => {
760 p.complete = p.after_value_state == State.TopLevelEnd;
761 p.state = State.NumberExponentDigits;
762 },
763 else => {
764 return error.InvalidNumber;
765 },
766 },
767
768 State.NumberExponentDigits => {
769 p.complete = p.after_value_state == State.TopLevelEnd;
770 switch (c) {
771 '0' ... '9' => {
772 // another digit
773 },
774 else => {
775 p.state = p.after_value_state;
776 *token = Token.initNumber(p.count, p.number_is_integer);
777 return true;
778 },
779 }
780 },
781
782 State.TrueLiteral1 => switch (c) {
783 'r' => p.state = State.TrueLiteral2,
784 else => return error.InvalidLiteral,
785 },
786
787 State.TrueLiteral2 => switch (c) {
788 'u' => p.state = State.TrueLiteral3,
789 else => return error.InvalidLiteral,
790 },
791
792 State.TrueLiteral3 => switch (c) {
793 'e' => {
794 p.state = p.after_value_state;
795 p.complete = p.state == State.TopLevelEnd;
796 *token = Token.init(Token.Id.True, p.count + 1, 1);
797 },
798 else => {
799 return error.InvalidLiteral;
800 },
801 },
802
803 State.FalseLiteral1 => switch (c) {
804 'a' => p.state = State.FalseLiteral2,
805 else => return error.InvalidLiteral,
806 },
807
808 State.FalseLiteral2 => switch (c) {
809 'l' => p.state = State.FalseLiteral3,
810 else => return error.InvalidLiteral,
811 },
812
813 State.FalseLiteral3 => switch (c) {
814 's' => p.state = State.FalseLiteral4,
815 else => return error.InvalidLiteral,
816 },
817
818 State.FalseLiteral4 => switch (c) {
819 'e' => {
820 p.state = p.after_value_state;
821 p.complete = p.state == State.TopLevelEnd;
822 *token = Token.init(Token.Id.False, p.count + 1, 1);
823 },
824 else => {
825 return error.InvalidLiteral;
826 },
827 },
828
829 State.NullLiteral1 => switch (c) {
830 'u' => p.state = State.NullLiteral2,
831 else => return error.InvalidLiteral,
832 },
833
834 State.NullLiteral2 => switch (c) {
835 'l' => p.state = State.NullLiteral3,
836 else => return error.InvalidLiteral,
837 },
838
839 State.NullLiteral3 => switch (c) {
840 'l' => {
841 p.state = p.after_value_state;
842 p.complete = p.state == State.TopLevelEnd;
843 *token = Token.init(Token.Id.Null, p.count + 1, 1);
844 },
845 else => {
846 return error.InvalidLiteral;
847 },
848 },
849 }
850
851 return false;
852 }
853};
854
855// Validate a JSON string. This does not limit number precision so a decoder may not necessarily
856// be able to decode the string even if this returns true.
857pub fn validate(s: []const u8) bool {
858 var p = StreamingJsonParser.init();
859
860 for (s) |c, i| {
861 var token1: ?Token = undefined;
862 var token2: ?Token = undefined;
863
864 p.feed(c, &token1, &token2) catch |err| {
865 return false;
866 };
867 }
868
869 return p.complete;
870}
871
872const Allocator = std.mem.Allocator;
873const ArenaAllocator = std.heap.ArenaAllocator;
874const ArrayList = std.ArrayList;
875const HashMap = std.HashMap;
876
877pub const ValueTree = struct {
878 arena: ArenaAllocator,
879 root: Value,
880
881 pub fn deinit(self: &ValueTree) void {
882 self.arena.deinit();
883 }
884};
885
886pub const ObjectMap = HashMap([]const u8, Value, mem.hash_slice_u8, mem.eql_slice_u8);
887
888pub const Value = union(enum) {
889 Null,
890 Bool: bool,
891 Integer: i64,
892 Float: f64,
893 String: []const u8,
894 Array: ArrayList(Value),
895 Object: ObjectMap,
896
897 pub fn dump(self: &const Value) void {
898 switch (*self) {
899 Value.Null => {
900 std.debug.warn("null");
901 },
902 Value.Bool => |inner| {
903 std.debug.warn("{}", inner);
904 },
905 Value.Integer => |inner| {
906 std.debug.warn("{}", inner);
907 },
908 Value.Float => |inner| {
909 std.debug.warn("{.5}", inner);
910 },
911 Value.String => |inner| {
912 std.debug.warn("\"{}\"", inner);
913 },
914 Value.Array => |inner| {
915 var not_first = false;
916 std.debug.warn("[");
917 for (inner.toSliceConst()) |value| {
918 if (not_first) {
919 std.debug.warn(",");
920 }
921 not_first = true;
922 value.dump();
923 }
924 std.debug.warn("]");
925 },
926 Value.Object => |inner| {
927 var not_first = false;
928 std.debug.warn("{{");
929 var it = inner.iterator();
930
931 while (it.next()) |entry| {
932 if (not_first) {
933 std.debug.warn(",");
934 }
935 not_first = true;
936 std.debug.warn("\"{}\":", entry.key);
937 entry.value.dump();
938 }
939 std.debug.warn("}}");
940 },
941 }
942 }
943
944 pub fn dumpIndent(self: &const Value, indent: usize) void {
945 if (indent == 0) {
946 self.dump();
947 } else {
948 self.dumpIndentLevel(indent, 0);
949 }
950 }
951
952 fn dumpIndentLevel(self: &const Value, indent: usize, level: usize) void {
953 switch (*self) {
954 Value.Null => {
955 std.debug.warn("null");
956 },
957 Value.Bool => |inner| {
958 std.debug.warn("{}", inner);
959 },
960 Value.Integer => |inner| {
961 std.debug.warn("{}", inner);
962 },
963 Value.Float => |inner| {
964 std.debug.warn("{.5}", inner);
965 },
966 Value.String => |inner| {
967 std.debug.warn("\"{}\"", inner);
968 },
969 Value.Array => |inner| {
970 var not_first = false;
971 std.debug.warn("[\n");
972
973 for (inner.toSliceConst()) |value| {
974 if (not_first) {
975 std.debug.warn(",\n");
976 }
977 not_first = true;
978 padSpace(level + indent);
979 value.dumpIndentLevel(indent, level + indent);
980 }
981 std.debug.warn("\n");
982 padSpace(level);
983 std.debug.warn("]");
984 },
985 Value.Object => |inner| {
986 var not_first = false;
987 std.debug.warn("{{\n");
988 var it = inner.iterator();
989
990 while (it.next()) |entry| {
991 if (not_first) {
992 std.debug.warn(",\n");
993 }
994 not_first = true;
995 padSpace(level + indent);
996 std.debug.warn("\"{}\": ", entry.key);
997 entry.value.dumpIndentLevel(indent, level + indent);
998 }
999 std.debug.warn("\n");
1000 padSpace(level);
1001 std.debug.warn("}}");
1002 },
1003 }
1004 }
1005
1006 fn padSpace(indent: usize) void {
1007 var i: usize = 0;
1008 while (i < indent) : (i += 1) {
1009 std.debug.warn(" ");
1010 }
1011 }
1012};
1013
1014// A non-stream JSON parser which constructs a tree of Value's.
1015const JsonParser = struct {
1016 allocator: &Allocator,
1017 state: State,
1018 copy_strings: bool,
1019 // Stores parent nodes and un-combined Values.
1020 stack: ArrayList(Value),
1021
1022 const State = enum {
1023 ObjectKey,
1024 ObjectValue,
1025 ArrayValue,
1026 Simple,
1027 };
1028
1029 pub fn init(allocator: &Allocator, copy_strings: bool) JsonParser {
1030 return JsonParser {
1031 .allocator = allocator,
1032 .state = State.Simple,
1033 .copy_strings = copy_strings,
1034 .stack = ArrayList(Value).init(allocator),
1035 };
1036 }
1037
1038 pub fn deinit(p: &JsonParser) void {
1039 p.stack.deinit();
1040 }
1041
1042 pub fn reset(p: &JsonParser) void {
1043 p.state = State.Simple;
1044 p.stack.shrink(0);
1045 }
1046
1047 pub fn parse(p: &JsonParser, input: []const u8) !ValueTree {
1048 var mp = StreamingJsonParser.init();
1049
1050 var arena = ArenaAllocator.init(p.allocator);
1051 errdefer arena.deinit();
1052
1053 for (input) |c, i| {
1054 var mt1: ?Token = undefined;
1055 var mt2: ?Token = undefined;
1056
1057 try mp.feed(c, &mt1, &mt2);
1058 if (mt1) |t1| {
1059 try p.transition(&arena.allocator, input, i, t1);
1060
1061 if (mt2) |t2| {
1062 try p.transition(&arena.allocator, input, i, t2);
1063 }
1064 }
1065 }
1066
1067 // Handle top-level lonely number values.
1068 {
1069 const i = input.len;
1070 var mt1: ?Token = undefined;
1071 var mt2: ?Token = undefined;
1072
1073 try mp.feed(' ', &mt1, &mt2);
1074 if (mt1) |t1| {
1075 try p.transition(&arena.allocator, input, i, t1);
1076 }
1077 }
1078
1079 if (!mp.complete) {
1080 return error.IncompleteJsonInput;
1081 }
1082
1083 std.debug.assert(p.stack.len == 1);
1084
1085 return ValueTree {
1086 .arena = arena,
1087 .root = p.stack.at(0),
1088 };
1089 }
1090
1091 // Even though p.allocator exists, we take an explicit allocator so that allocation state
1092 // can be cleaned up on error correctly during a `parse` on call.
1093 fn transition(p: &JsonParser, allocator: &Allocator, input: []const u8, i: usize, token: &const Token) !void {
1094 switch (p.state) {
1095 State.ObjectKey => switch (token.id) {
1096 Token.Id.ObjectEnd => {
1097 if (p.stack.len == 1) {
1098 return;
1099 }
1100
1101 var value = p.stack.pop();
1102 try p.pushToParent(value);
1103 },
1104 Token.Id.String => {
1105 try p.stack.append(try p.parseString(allocator, token, input, i));
1106 p.state = State.ObjectValue;
1107 },
1108 else => {
1109 unreachable;
1110 },
1111 },
1112 State.ObjectValue => {
1113 var object = &p.stack.items[p.stack.len - 2].Object;
1114 var key = p.stack.items[p.stack.len - 1].String;
1115
1116 switch (token.id) {
1117 Token.Id.ObjectBegin => {
1118 try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
1119 p.state = State.ObjectKey;
1120 },
1121 Token.Id.ArrayBegin => {
1122 try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
1123 p.state = State.ArrayValue;
1124 },
1125 Token.Id.String => {
1126 _ = try object.put(key, try p.parseString(allocator, token, input, i));
1127 _ = p.stack.pop();
1128 p.state = State.ObjectKey;
1129 },
1130 Token.Id.Number => {
1131 _ = try object.put(key, try p.parseNumber(token, input, i));
1132 _ = p.stack.pop();
1133 p.state = State.ObjectKey;
1134 },
1135 Token.Id.True => {
1136 _ = try object.put(key, Value { .Bool = true });
1137 _ = p.stack.pop();
1138 p.state = State.ObjectKey;
1139 },
1140 Token.Id.False => {
1141 _ = try object.put(key, Value { .Bool = false });
1142 _ = p.stack.pop();
1143 p.state = State.ObjectKey;
1144 },
1145 Token.Id.Null => {
1146 _ = try object.put(key, Value.Null);
1147 _ = p.stack.pop();
1148 p.state = State.ObjectKey;
1149 },
1150 else => {
1151 unreachable;
1152 },
1153 }
1154 },
1155 State.ArrayValue => {
1156 var array = &p.stack.items[p.stack.len - 1].Array;
1157
1158 switch (token.id) {
1159 Token.Id.ArrayEnd => {
1160 if (p.stack.len == 1) {
1161 return;
1162 }
1163
1164 var value = p.stack.pop();
1165 try p.pushToParent(value);
1166 },
1167 Token.Id.ObjectBegin => {
1168 try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
1169 p.state = State.ObjectKey;
1170 },
1171 Token.Id.ArrayBegin => {
1172 try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
1173 p.state = State.ArrayValue;
1174 },
1175 Token.Id.String => {
1176 try array.append(try p.parseString(allocator, token, input, i));
1177 },
1178 Token.Id.Number => {
1179 try array.append(try p.parseNumber(token, input, i));
1180 },
1181 Token.Id.True => {
1182 try array.append(Value { .Bool = true });
1183 },
1184 Token.Id.False => {
1185 try array.append(Value { .Bool = false });
1186 },
1187 Token.Id.Null => {
1188 try array.append(Value.Null);
1189 },
1190 else => {
1191 unreachable;
1192 },
1193 }
1194 },
1195 State.Simple => switch (token.id) {
1196 Token.Id.ObjectBegin => {
1197 try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
1198 p.state = State.ObjectKey;
1199 },
1200 Token.Id.ArrayBegin => {
1201 try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
1202 p.state = State.ArrayValue;
1203 },
1204 Token.Id.String => {
1205 try p.stack.append(try p.parseString(allocator, token, input, i));
1206 },
1207 Token.Id.Number => {
1208 try p.stack.append(try p.parseNumber(token, input, i));
1209 },
1210 Token.Id.True => {
1211 try p.stack.append(Value { .Bool = true });
1212 },
1213 Token.Id.False => {
1214 try p.stack.append(Value { .Bool = false });
1215 },
1216 Token.Id.Null => {
1217 try p.stack.append(Value.Null);
1218 },
1219 Token.Id.ObjectEnd, Token.Id.ArrayEnd => {
1220 unreachable;
1221 },
1222 },
1223 }
1224 }
1225
1226 fn pushToParent(p: &JsonParser, value: &const Value) !void {
1227 switch (p.stack.at(p.stack.len - 1)) {
1228 // Object Parent -> [ ..., object, <key>, value ]
1229 Value.String => |key| {
1230 _ = p.stack.pop();
1231
1232 var object = &p.stack.items[p.stack.len - 1].Object;
1233 _ = try object.put(key, value);
1234 p.state = State.ObjectKey;
1235 },
1236 // Array Parent -> [ ..., <array>, value ]
1237 Value.Array => |*array| {
1238 try array.append(value);
1239 p.state = State.ArrayValue;
1240 },
1241 else => {
1242 unreachable;
1243 },
1244 }
1245 }
1246
1247 fn parseString(p: &JsonParser, allocator: &Allocator, token: &const Token, input: []const u8, i: usize) !Value {
1248 // TODO: We don't strictly have to copy values which do not contain any escape
1249 // characters if flagged with the option.
1250 const slice = token.slice(input, i);
1251 return Value { .String = try mem.dupe(p.allocator, u8, slice) };
1252 }
1253
1254 fn parseNumber(p: &JsonParser, token: &const Token, input: []const u8, i: usize) !Value {
1255 return if (token.number_is_integer)
1256 Value { .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
1257 else
1258 @panic("TODO: fmt.parseFloat not yet implemented")
1259 ;
1260 }
1261};
1262
1263const debug = std.debug;
1264
1265test "json parser dynamic" {
1266 var p = JsonParser.init(std.debug.global_allocator, false);
1267 defer p.deinit();
1268
1269 const s =
1270 \\{
1271 \\ "Image": {
1272 \\ "Width": 800,
1273 \\ "Height": 600,
1274 \\ "Title": "View from 15th Floor",
1275 \\ "Thumbnail": {
1276 \\ "Url": "http://www.example.com/image/481989943",
1277 \\ "Height": 125,
1278 \\ "Width": 100
1279 \\ },
1280 \\ "Animated" : false,
1281 \\ "IDs": [116, 943, 234, 38793]
1282 \\ }
1283 \\}
1284 ;
1285
1286 var tree = try p.parse(s);
1287 defer tree.deinit();
1288
1289 var root = tree.root;
1290
1291 var image = (??root.Object.get("Image")).value;
1292
1293 const width = (??image.Object.get("Width")).value;
1294 debug.assert(width.Integer == 800);
1295
1296 const height = (??image.Object.get("Height")).value;
1297 debug.assert(height.Integer == 600);
1298
1299 const title = (??image.Object.get("Title")).value;
1300 debug.assert(mem.eql(u8, title.String, "View from 15th Floor"));
1301
1302 const animated = (??image.Object.get("Animated")).value;
1303 debug.assert(animated.Bool == false);
1304}
std/json_test.zig created+1942
......@@ -0,0 +1,1942 @@
1// RFC 8529 conformance tests.
2//
3// Tests are taken from https://github.com/nst/JSONTestSuite
4// Read also http://seriot.ch/parsing_json.php for a good overview.
5
6const std = @import("index.zig");
7
8fn ok(comptime s: []const u8) void {
9 std.debug.assert(std.json.validate(s));
10}
11
12fn err(comptime s: []const u8) void {
13 std.debug.assert(!std.json.validate(s));
14}
15
16fn any(comptime s: []const u8) void {
17 std.debug.assert(true);
18}
19
20////////////////////////////////////////////////////////////////////////////////////////////////////
21
22test "y_array_arraysWithSpaces" {
23 ok(
24 \\[[] ]
25 );
26}
27
28test "y_array_empty" {
29 ok(
30 \\[]
31 );
32}
33
34test "y_array_empty-string" {
35 ok(
36 \\[""]
37 );
38}
39
40test "y_array_ending_with_newline" {
41 ok(
42 \\["a"]
43 );
44}
45
46test "y_array_false" {
47 ok(
48 \\[false]
49 );
50}
51
52test "y_array_heterogeneous" {
53 ok(
54 \\[null, 1, "1", {}]
55 );
56}
57
58test "y_array_null" {
59 ok(
60 \\[null]
61 );
62}
63
64test "y_array_with_1_and_newline" {
65 ok(
66 \\[1
67 \\]
68 );
69}
70
71test "y_array_with_leading_space" {
72 ok(
73 \\ [1]
74 );
75}
76
77test "y_array_with_several_null" {
78 ok(
79 \\[1,null,null,null,2]
80 );
81}
82
83test "y_array_with_trailing_space" {
84 ok(
85 "[2] "
86 );
87}
88
89test "y_number_0e+1" {
90 ok(
91 \\[0e+1]
92 );
93}
94
95test "y_number_0e1" {
96 ok(
97 \\[0e1]
98 );
99}
100
101test "y_number_after_space" {
102 ok(
103 \\[ 4]
104 );
105}
106
107test "y_number_double_close_to_zero" {
108 ok(
109 \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001]
110 );
111}
112
113test "y_number_int_with_exp" {
114 ok(
115 \\[20e1]
116 );
117}
118
119test "y_number" {
120 ok(
121 \\[123e65]
122 );
123}
124
125test "y_number_minus_zero" {
126 ok(
127 \\[-0]
128 );
129}
130
131test "y_number_negative_int" {
132 ok(
133 \\[-123]
134 );
135}
136
137test "y_number_negative_one" {
138 ok(
139 \\[-1]
140 );
141}
142
143test "y_number_negative_zero" {
144 ok(
145 \\[-0]
146 );
147}
148
149test "y_number_real_capital_e" {
150 ok(
151 \\[1E22]
152 );
153}
154
155test "y_number_real_capital_e_neg_exp" {
156 ok(
157 \\[1E-2]
158 );
159}
160
161test "y_number_real_capital_e_pos_exp" {
162 ok(
163 \\[1E+2]
164 );
165}
166
167test "y_number_real_exponent" {
168 ok(
169 \\[123e45]
170 );
171}
172
173test "y_number_real_fraction_exponent" {
174 ok(
175 \\[123.456e78]
176 );
177}
178
179test "y_number_real_neg_exp" {
180 ok(
181 \\[1e-2]
182 );
183}
184
185test "y_number_real_pos_exponent" {
186 ok(
187 \\[1e+2]
188 );
189}
190
191test "y_number_simple_int" {
192 ok(
193 \\[123]
194 );
195}
196
197test "y_number_simple_real" {
198 ok(
199 \\[123.456789]
200 );
201}
202
203test "y_object_basic" {
204 ok(
205 \\{"asd":"sdf"}
206 );
207}
208
209test "y_object_duplicated_key_and_value" {
210 ok(
211 \\{"a":"b","a":"b"}
212 );
213}
214
215test "y_object_duplicated_key" {
216 ok(
217 \\{"a":"b","a":"c"}
218 );
219}
220
221test "y_object_empty" {
222 ok(
223 \\{}
224 );
225}
226
227test "y_object_empty_key" {
228 ok(
229 \\{"":0}
230 );
231}
232
233test "y_object_escaped_null_in_key" {
234 ok(
235 \\{"foo\u0000bar": 42}
236 );
237}
238
239test "y_object_extreme_numbers" {
240 ok(
241 \\{ "min": -1.0e+28, "max": 1.0e+28 }
242 );
243}
244
245test "y_object" {
246 ok(
247 \\{"asd":"sdf", "dfg":"fgh"}
248 );
249}
250
251test "y_object_long_strings" {
252 ok(
253 \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
254 );
255}
256
257test "y_object_simple" {
258 ok(
259 \\{"a":[]}
260 );
261}
262
263test "y_object_string_unicode" {
264 ok(
265 \\{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" }
266 );
267}
268
269test "y_object_with_newlines" {
270 ok(
271 \\{
272 \\"a": "b"
273 \\}
274 );
275}
276
277test "y_string_1_2_3_bytes_UTF-8_sequences" {
278 ok(
279 \\["\u0060\u012a\u12AB"]
280 );
281}
282
283test "y_string_accepted_surrogate_pair" {
284 ok(
285 \\["\uD801\udc37"]
286 );
287}
288
289test "y_string_accepted_surrogate_pairs" {
290 ok(
291 \\["\ud83d\ude39\ud83d\udc8d"]
292 );
293}
294
295test "y_string_allowed_escapes" {
296 ok(
297 \\["\"\\\/\b\f\n\r\t"]
298 );
299}
300
301test "y_string_backslash_and_u_escaped_zero" {
302 ok(
303 \\["\\u0000"]
304 );
305}
306
307test "y_string_backslash_doublequotes" {
308 ok(
309 \\["\""]
310 );
311}
312
313test "y_string_comments" {
314 ok(
315 \\["a/*b*/c/*d//e"]
316 );
317}
318
319test "y_string_double_escape_a" {
320 ok(
321 \\["\\a"]
322 );
323}
324
325test "y_string_double_escape_n" {
326 ok(
327 \\["\\n"]
328 );
329}
330
331test "y_string_escaped_control_character" {
332 ok(
333 \\["\u0012"]
334 );
335}
336
337test "y_string_escaped_noncharacter" {
338 ok(
339 \\["\uFFFF"]
340 );
341}
342
343test "y_string_in_array" {
344 ok(
345 \\["asd"]
346 );
347}
348
349test "y_string_in_array_with_leading_space" {
350 ok(
351 \\[ "asd"]
352 );
353}
354
355test "y_string_last_surrogates_1_and_2" {
356 ok(
357 \\["\uDBFF\uDFFF"]
358 );
359}
360
361test "y_string_nbsp_uescaped" {
362 ok(
363 \\["new\u00A0line"]
364 );
365}
366
367test "y_string_nonCharacterInUTF-8_U+10FFFF" {
368 ok(
369 \\["􏿿"]
370 );
371}
372
373test "y_string_nonCharacterInUTF-8_U+FFFF" {
374 ok(
375 \\["￿"]
376 );
377}
378
379test "y_string_null_escape" {
380 ok(
381 \\["\u0000"]
382 );
383}
384
385test "y_string_one-byte-utf-8" {
386 ok(
387 \\["\u002c"]
388 );
389}
390
391test "y_string_pi" {
392 ok(
393 \\["π"]
394 );
395}
396
397test "y_string_reservedCharacterInUTF-8_U+1BFFF" {
398 ok(
399 \\["𛿿"]
400 );
401}
402
403test "y_string_simple_ascii" {
404 ok(
405 \\["asd "]
406 );
407}
408
409test "y_string_space" {
410 ok(
411 \\" "
412 );
413}
414
415test "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" {
416 ok(
417 \\["\uD834\uDd1e"]
418 );
419}
420
421test "y_string_three-byte-utf-8" {
422 ok(
423 \\["\u0821"]
424 );
425}
426
427test "y_string_two-byte-utf-8" {
428 ok(
429 \\["\u0123"]
430 );
431}
432
433test "y_string_u+2028_line_sep" {
434 ok(
435 \\["
"]
436 );
437}
438
439test "y_string_u+2029_par_sep" {
440 ok(
441 \\["
"]
442 );
443}
444
445test "y_string_uescaped_newline" {
446 ok(
447 \\["new\u000Aline"]
448 );
449}
450
451test "y_string_uEscape" {
452 ok(
453 \\["\u0061\u30af\u30EA\u30b9"]
454 );
455}
456
457test "y_string_unescaped_char_delete" {
458 ok(
459 \\[""]
460 );
461}
462
463test "y_string_unicode_2" {
464 ok(
465 \\["⍂㈴⍂"]
466 );
467}
468
469test "y_string_unicodeEscapedBackslash" {
470 ok(
471 \\["\u005C"]
472 );
473}
474
475test "y_string_unicode_escaped_double_quote" {
476 ok(
477 \\["\u0022"]
478 );
479}
480
481test "y_string_unicode" {
482 ok(
483 \\["\uA66D"]
484 );
485}
486
487test "y_string_unicode_U+10FFFE_nonchar" {
488 ok(
489 \\["\uDBFF\uDFFE"]
490 );
491}
492
493test "y_string_unicode_U+1FFFE_nonchar" {
494 ok(
495 \\["\uD83F\uDFFE"]
496 );
497}
498
499test "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" {
500 ok(
501 \\["\u200B"]
502 );
503}
504
505test "y_string_unicode_U+2064_invisible_plus" {
506 ok(
507 \\["\u2064"]
508 );
509}
510
511test "y_string_unicode_U+FDD0_nonchar" {
512 ok(
513 \\["\uFDD0"]
514 );
515}
516
517test "y_string_unicode_U+FFFE_nonchar" {
518 ok(
519 \\["\uFFFE"]
520 );
521}
522
523test "y_string_utf8" {
524 ok(
525 \\["€𝄞"]
526 );
527}
528
529test "y_string_with_del_character" {
530 ok(
531 \\["aa"]
532 );
533}
534
535test "y_structure_lonely_false" {
536 ok(
537 \\false
538 );
539}
540
541test "y_structure_lonely_int" {
542 ok(
543 \\42
544 );
545}
546
547test "y_structure_lonely_negative_real" {
548 ok(
549 \\-0.1
550 );
551}
552
553test "y_structure_lonely_null" {
554 ok(
555 \\null
556 );
557}
558
559test "y_structure_lonely_string" {
560 ok(
561 \\"asd"
562 );
563}
564
565test "y_structure_lonely_true" {
566 ok(
567 \\true
568 );
569}
570
571test "y_structure_string_empty" {
572 ok(
573 \\""
574 );
575}
576
577test "y_structure_trailing_newline" {
578 ok(
579 \\["a"]
580 );
581}
582
583test "y_structure_true_in_array" {
584 ok(
585 \\[true]
586 );
587}
588
589test "y_structure_whitespace_array" {
590 ok(
591 " [] "
592 );
593}
594
595////////////////////////////////////////////////////////////////////////////////////////////////////
596
597test "n_array_1_true_without_comma" {
598 err(
599 \\[1 true]
600 );
601}
602
603test "n_array_a_invalid_utf8" {
604 err(
605 \\[aå]
606 );
607}
608
609test "n_array_colon_instead_of_comma" {
610 err(
611 \\["": 1]
612 );
613}
614
615test "n_array_comma_after_close" {
616 //err(
617 // \\[""],
618 //);
619}
620
621test "n_array_comma_and_number" {
622 err(
623 \\[,1]
624 );
625}
626
627test "n_array_double_comma" {
628 err(
629 \\[1,,2]
630 );
631}
632
633test "n_array_double_extra_comma" {
634 err(
635 \\["x",,]
636 );
637}
638
639test "n_array_extra_close" {
640 err(
641 \\["x"]]
642 );
643}
644
645test "n_array_extra_comma" {
646 //err(
647 // \\["",]
648 //);
649}
650
651test "n_array_incomplete_invalid_value" {
652 err(
653 \\[x
654 );
655}
656
657test "n_array_incomplete" {
658 err(
659 \\["x"
660 );
661}
662
663test "n_array_inner_array_no_comma" {
664 err(
665 \\[3[4]]
666 );
667}
668
669test "n_array_invalid_utf8" {
670 err(
671 \\[ÿ]
672 );
673}
674
675test "n_array_items_separated_by_semicolon" {
676 err(
677 \\[1:2]
678 );
679}
680
681test "n_array_just_comma" {
682 err(
683 \\[,]
684 );
685}
686
687test "n_array_just_minus" {
688 err(
689 \\[-]
690 );
691}
692
693test "n_array_missing_value" {
694 err(
695 \\[ , ""]
696 );
697}
698
699test "n_array_newlines_unclosed" {
700 err(
701 \\["a",
702 \\4
703 \\,1,
704 );
705}
706
707
708test "n_array_number_and_comma" {
709 err(
710 \\[1,]
711 );
712}
713
714test "n_array_number_and_several_commas" {
715 err(
716 \\[1,,]
717 );
718}
719
720test "n_array_spaces_vertical_tab_formfeed" {
721 err(
722 \\[" a"\f]
723 );
724}
725
726test "n_array_star_inside" {
727 err(
728 \\[*]
729 );
730}
731
732test "n_array_unclosed" {
733 err(
734 \\[""
735 );
736}
737
738test "n_array_unclosed_trailing_comma" {
739 err(
740 \\[1,
741 );
742}
743
744test "n_array_unclosed_with_new_lines" {
745 err(
746 \\[1,
747 \\1
748 \\,1
749 );
750}
751
752test "n_array_unclosed_with_object_inside" {
753 err(
754 \\[{}
755 );
756}
757
758test "n_incomplete_false" {
759 err(
760 \\[fals]
761 );
762}
763
764test "n_incomplete_null" {
765 err(
766 \\[nul]
767 );
768}
769
770test "n_incomplete_true" {
771 err(
772 \\[tru]
773 );
774}
775
776test "n_multidigit_number_then_00" {
777 err(
778 \\123
779 );
780}
781
782test "n_number_0.1.2" {
783 err(
784 \\[0.1.2]
785 );
786}
787
788test "n_number_-01" {
789 err(
790 \\[-01]
791 );
792}
793
794test "n_number_0.3e" {
795 err(
796 \\[0.3e]
797 );
798}
799
800test "n_number_0.3e+" {
801 err(
802 \\[0.3e+]
803 );
804}
805
806test "n_number_0_capital_E" {
807 err(
808 \\[0E]
809 );
810}
811
812test "n_number_0_capital_E+" {
813 err(
814 \\[0E+]
815 );
816}
817
818test "n_number_0.e1" {
819 err(
820 \\[0.e1]
821 );
822}
823
824test "n_number_0e" {
825 err(
826 \\[0e]
827 );
828}
829
830test "n_number_0e+" {
831 err(
832 \\[0e+]
833 );
834}
835
836test "n_number_1_000" {
837 err(
838 \\[1 000.0]
839 );
840}
841
842test "n_number_1.0e-" {
843 err(
844 \\[1.0e-]
845 );
846}
847
848test "n_number_1.0e" {
849 err(
850 \\[1.0e]
851 );
852}
853
854test "n_number_1.0e+" {
855 err(
856 \\[1.0e+]
857 );
858}
859
860test "n_number_-1.0." {
861 err(
862 \\[-1.0.]
863 );
864}
865
866test "n_number_1eE2" {
867 err(
868 \\[1eE2]
869 );
870}
871
872test "n_number_.-1" {
873 err(
874 \\[.-1]
875 );
876}
877
878test "n_number_+1" {
879 err(
880 \\[+1]
881 );
882}
883
884test "n_number_.2e-3" {
885 err(
886 \\[.2e-3]
887 );
888}
889
890test "n_number_2.e-3" {
891 err(
892 \\[2.e-3]
893 );
894}
895
896test "n_number_2.e+3" {
897 err(
898 \\[2.e+3]
899 );
900}
901
902test "n_number_2.e3" {
903 err(
904 \\[2.e3]
905 );
906}
907
908test "n_number_-2." {
909 err(
910 \\[-2.]
911 );
912}
913
914test "n_number_9.e+" {
915 err(
916 \\[9.e+]
917 );
918}
919
920test "n_number_expression" {
921 err(
922 \\[1+2]
923 );
924}
925
926test "n_number_hex_1_digit" {
927 err(
928 \\[0x1]
929 );
930}
931
932test "n_number_hex_2_digits" {
933 err(
934 \\[0x42]
935 );
936}
937
938test "n_number_infinity" {
939 err(
940 \\[Infinity]
941 );
942}
943
944test "n_number_+Inf" {
945 err(
946 \\[+Inf]
947 );
948}
949
950test "n_number_Inf" {
951 err(
952 \\[Inf]
953 );
954}
955
956test "n_number_invalid+-" {
957 err(
958 \\[0e+-1]
959 );
960}
961
962test "n_number_invalid-negative-real" {
963 err(
964 \\[-123.123foo]
965 );
966}
967
968test "n_number_invalid-utf-8-in-bigger-int" {
969 err(
970 \\[123å]
971 );
972}
973
974test "n_number_invalid-utf-8-in-exponent" {
975 err(
976 \\[1e1å]
977 );
978}
979
980test "n_number_invalid-utf-8-in-int" {
981 err(
982 \\[0å]
983 );
984}
985
986
987test "n_number_++" {
988 err(
989 \\[++1234]
990 );
991}
992
993test "n_number_minus_infinity" {
994 err(
995 \\[-Infinity]
996 );
997}
998
999test "n_number_minus_sign_with_trailing_garbage" {
1000 err(
1001 \\[-foo]
1002 );
1003}
1004
1005test "n_number_minus_space_1" {
1006 err(
1007 \\[- 1]
1008 );
1009}
1010
1011test "n_number_-NaN" {
1012 err(
1013 \\[-NaN]
1014 );
1015}
1016
1017test "n_number_NaN" {
1018 err(
1019 \\[NaN]
1020 );
1021}
1022
1023test "n_number_neg_int_starting_with_zero" {
1024 err(
1025 \\[-012]
1026 );
1027}
1028
1029test "n_number_neg_real_without_int_part" {
1030 err(
1031 \\[-.123]
1032 );
1033}
1034
1035test "n_number_neg_with_garbage_at_end" {
1036 err(
1037 \\[-1x]
1038 );
1039}
1040
1041test "n_number_real_garbage_after_e" {
1042 err(
1043 \\[1ea]
1044 );
1045}
1046
1047test "n_number_real_with_invalid_utf8_after_e" {
1048 err(
1049 \\[1eå]
1050 );
1051}
1052
1053test "n_number_real_without_fractional_part" {
1054 err(
1055 \\[1.]
1056 );
1057}
1058
1059test "n_number_starting_with_dot" {
1060 err(
1061 \\[.123]
1062 );
1063}
1064
1065test "n_number_U+FF11_fullwidth_digit_one" {
1066 err(
1067 \\[1]
1068 );
1069}
1070
1071test "n_number_with_alpha_char" {
1072 err(
1073 \\[1.8011670033376514H-308]
1074 );
1075}
1076
1077test "n_number_with_alpha" {
1078 err(
1079 \\[1.2a-3]
1080 );
1081}
1082
1083test "n_number_with_leading_zero" {
1084 err(
1085 \\[012]
1086 );
1087}
1088
1089test "n_object_bad_value" {
1090 err(
1091 \\["x", truth]
1092 );
1093}
1094
1095test "n_object_bracket_key" {
1096 err(
1097 \\{[: "x"}
1098 );
1099}
1100
1101test "n_object_comma_instead_of_colon" {
1102 err(
1103 \\{"x", null}
1104 );
1105}
1106
1107test "n_object_double_colon" {
1108 err(
1109 \\{"x"::"b"}
1110 );
1111}
1112
1113test "n_object_emoji" {
1114 err(
1115 \\{🇨🇭}
1116 );
1117}
1118
1119test "n_object_garbage_at_end" {
1120 err(
1121 \\{"a":"a" 123}
1122 );
1123}
1124
1125test "n_object_key_with_single_quotes" {
1126 err(
1127 \\{key: 'value'}
1128 );
1129}
1130
1131test "n_object_lone_continuation_byte_in_key_and_trailing_comma" {
1132 err(
1133 \\{"¹":"0",}
1134 );
1135}
1136
1137test "n_object_missing_colon" {
1138 err(
1139 \\{"a" b}
1140 );
1141}
1142
1143test "n_object_missing_key" {
1144 err(
1145 \\{:"b"}
1146 );
1147}
1148
1149test "n_object_missing_semicolon" {
1150 err(
1151 \\{"a" "b"}
1152 );
1153}
1154
1155test "n_object_missing_value" {
1156 err(
1157 \\{"a":
1158 );
1159}
1160
1161test "n_object_no-colon" {
1162 err(
1163 \\{"a"
1164 );
1165}
1166
1167test "n_object_non_string_key_but_huge_number_instead" {
1168 err(
1169 \\{9999E9999:1}
1170 );
1171}
1172
1173test "n_object_non_string_key" {
1174 err(
1175 \\{1:1}
1176 );
1177}
1178
1179test "n_object_repeated_null_null" {
1180 err(
1181 \\{null:null,null:null}
1182 );
1183}
1184
1185test "n_object_several_trailing_commas" {
1186 err(
1187 \\{"id":0,,,,,}
1188 );
1189}
1190
1191test "n_object_single_quote" {
1192 err(
1193 \\{'a':0}
1194 );
1195}
1196
1197test "n_object_trailing_comma" {
1198 err(
1199 \\{"id":0,}
1200 );
1201}
1202
1203test "n_object_trailing_comment" {
1204 err(
1205 \\{"a":"b"}/**/
1206 );
1207}
1208
1209test "n_object_trailing_comment_open" {
1210 err(
1211 \\{"a":"b"}/**//
1212 );
1213}
1214
1215test "n_object_trailing_comment_slash_open_incomplete" {
1216 err(
1217 \\{"a":"b"}/
1218 );
1219}
1220
1221test "n_object_trailing_comment_slash_open" {
1222 err(
1223 \\{"a":"b"}//
1224 );
1225}
1226
1227test "n_object_two_commas_in_a_row" {
1228 err(
1229 \\{"a":"b",,"c":"d"}
1230 );
1231}
1232
1233test "n_object_unquoted_key" {
1234 err(
1235 \\{a: "b"}
1236 );
1237}
1238
1239test "n_object_unterminated-value" {
1240 err(
1241 \\{"a":"a
1242 );
1243 }
1244
1245test "n_object_with_single_string" {
1246 err(
1247 \\{ "foo" : "bar", "a" }
1248 );
1249}
1250
1251test "n_object_with_trailing_garbage" {
1252 err(
1253 \\{"a":"b"}#
1254 );
1255}
1256
1257test "n_single_space" {
1258 err(
1259 " "
1260 );
1261}
1262
1263test "n_string_1_surrogate_then_escape" {
1264 err(
1265 \\["\uD800\"]
1266 );
1267}
1268
1269test "n_string_1_surrogate_then_escape_u1" {
1270 err(
1271 \\["\uD800\u1"]
1272 );
1273}
1274
1275test "n_string_1_surrogate_then_escape_u1x" {
1276 err(
1277 \\["\uD800\u1x"]
1278 );
1279}
1280
1281test "n_string_1_surrogate_then_escape_u" {
1282 err(
1283 \\["\uD800\u"]
1284 );
1285}
1286
1287test "n_string_accentuated_char_no_quotes" {
1288 err(
1289 \\[é]
1290 );
1291}
1292
1293test "n_string_backslash_00" {
1294 err(
1295 \\["\"]
1296 );
1297}
1298
1299test "n_string_escaped_backslash_bad" {
1300 err(
1301 \\["\\\"]
1302 );
1303}
1304
1305test "n_string_escaped_ctrl_char_tab" {
1306 err(
1307 \\["\ "]
1308 );
1309}
1310
1311test "n_string_escaped_emoji" {
1312 err(
1313 \\["\🌀"]
1314 );
1315}
1316
1317test "n_string_escape_x" {
1318 err(
1319 \\["\x00"]
1320 );
1321}
1322
1323test "n_string_incomplete_escaped_character" {
1324 err(
1325 \\["\u00A"]
1326 );
1327}
1328
1329test "n_string_incomplete_escape" {
1330 err(
1331 \\["\"]
1332 );
1333}
1334
1335test "n_string_incomplete_surrogate_escape_invalid" {
1336 err(
1337 \\["\uD800\uD800\x"]
1338 );
1339}
1340
1341test "n_string_incomplete_surrogate" {
1342 err(
1343 \\["\uD834\uDd"]
1344 );
1345}
1346
1347test "n_string_invalid_backslash_esc" {
1348 err(
1349 \\["\a"]
1350 );
1351}
1352
1353test "n_string_invalid_unicode_escape" {
1354 err(
1355 \\["\uqqqq"]
1356 );
1357}
1358
1359test "n_string_invalid_utf8_after_escape" {
1360 err(
1361 \\["\å"]
1362 );
1363}
1364
1365test "n_string_invalid-utf-8-in-escape" {
1366 err(
1367 \\["\uå"]
1368 );
1369}
1370
1371test "n_string_leading_uescaped_thinspace" {
1372 err(
1373 \\[\u0020"asd"]
1374 );
1375}
1376
1377test "n_string_no_quotes_with_bad_escape" {
1378 err(
1379 \\[\n]
1380 );
1381}
1382
1383test "n_string_single_doublequote" {
1384 err(
1385 \\"
1386 );
1387}
1388
1389test "n_string_single_quote" {
1390 err(
1391 \\['single quote']
1392 );
1393}
1394
1395test "n_string_single_string_no_double_quotes" {
1396 err(
1397 \\abc
1398 );
1399}
1400
1401test "n_string_start_escape_unclosed" {
1402 err(
1403 \\["\
1404 );
1405}
1406
1407test "n_string_unescaped_crtl_char" {
1408 err(
1409 \\["aa"]
1410 );
1411}
1412
1413test "n_string_unescaped_newline" {
1414 err(
1415 \\["new
1416 \\line"]
1417 );
1418}
1419
1420test "n_string_unescaped_tab" {
1421 err(
1422 \\[" "]
1423 );
1424}
1425
1426test "n_string_unicode_CapitalU" {
1427 err(
1428 \\"\UA66D"
1429 );
1430}
1431
1432test "n_string_with_trailing_garbage" {
1433 err(
1434 \\""x
1435 );
1436}
1437
1438test "n_structure_100000_opening_arrays" {
1439 err(
1440 "[" ** 100000
1441 );
1442}
1443
1444test "n_structure_angle_bracket_." {
1445 err(
1446 \\<.>
1447 );
1448}
1449
1450test "n_structure_angle_bracket_null" {
1451 err(
1452 \\[<null>]
1453 );
1454}
1455
1456test "n_structure_array_trailing_garbage" {
1457 err(
1458 \\[1]x
1459 );
1460}
1461
1462test "n_structure_array_with_extra_array_close" {
1463 err(
1464 \\[1]]
1465 );
1466}
1467
1468test "n_structure_array_with_unclosed_string" {
1469 err(
1470 \\["asd]
1471 );
1472}
1473
1474test "n_structure_ascii-unicode-identifier" {
1475 err(
1476 \\aå
1477 );
1478}
1479
1480test "n_structure_capitalized_True" {
1481 err(
1482 \\[True]
1483 );
1484}
1485
1486test "n_structure_close_unopened_array" {
1487 err(
1488 \\1]
1489 );
1490}
1491
1492test "n_structure_comma_instead_of_closing_brace" {
1493 err(
1494 \\{"x": true,
1495 );
1496}
1497
1498test "n_structure_double_array" {
1499 err(
1500 \\[][]
1501 );
1502}
1503
1504test "n_structure_end_array" {
1505 err(
1506 \\]
1507 );
1508}
1509
1510test "n_structure_incomplete_UTF8_BOM" {
1511 err(
1512 \\ï»{}
1513 );
1514}
1515
1516test "n_structure_lone-invalid-utf-8" {
1517 err(
1518 \\å
1519 );
1520}
1521
1522test "n_structure_lone-open-bracket" {
1523 err(
1524 \\[
1525 );
1526}
1527
1528test "n_structure_no_data" {
1529 err(
1530 \\
1531 );
1532}
1533
1534test "n_structure_null-byte-outside-string" {
1535 err(
1536 \\[]
1537 );
1538}
1539
1540test "n_structure_number_with_trailing_garbage" {
1541 err(
1542 \\2@
1543 );
1544}
1545
1546test "n_structure_object_followed_by_closing_object" {
1547 err(
1548 \\{}}
1549 );
1550}
1551
1552test "n_structure_object_unclosed_no_value" {
1553 err(
1554 \\{"":
1555 );
1556}
1557
1558test "n_structure_object_with_comment" {
1559 err(
1560 \\{"a":/*comment*/"b"}
1561 );
1562}
1563
1564test "n_structure_object_with_trailing_garbage" {
1565 err(
1566 \\{"a": true} "x"
1567 );
1568}
1569
1570test "n_structure_open_array_apostrophe" {
1571 err(
1572 \\['
1573 );
1574}
1575
1576test "n_structure_open_array_comma" {
1577 err(
1578 \\[,
1579 );
1580}
1581
1582test "n_structure_open_array_object" {
1583 err(
1584 "[{\"\":" ** 50000
1585 );
1586}
1587
1588test "n_structure_open_array_open_object" {
1589 err(
1590 \\[{
1591 );
1592}
1593
1594test "n_structure_open_array_open_string" {
1595 err(
1596 \\["a
1597 );
1598}
1599
1600test "n_structure_open_array_string" {
1601 err(
1602 \\["a"
1603 );
1604}
1605
1606test "n_structure_open_object_close_array" {
1607 err(
1608 \\{]
1609 );
1610}
1611
1612test "n_structure_open_object_comma" {
1613 err(
1614 \\{,
1615 );
1616}
1617
1618test "n_structure_open_object" {
1619 err(
1620 \\{
1621 );
1622}
1623
1624test "n_structure_open_object_open_array" {
1625 err(
1626 \\{[
1627 );
1628}
1629
1630test "n_structure_open_object_open_string" {
1631 err(
1632 \\{"a
1633 );
1634}
1635
1636test "n_structure_open_object_string_with_apostrophes" {
1637 err(
1638 \\{'a'
1639 );
1640}
1641
1642test "n_structure_open_open" {
1643 err(
1644 \\["\{["\{["\{["\{
1645 );
1646}
1647
1648test "n_structure_single_eacute" {
1649 err(
1650 \\é
1651 );
1652}
1653
1654test "n_structure_single_star" {
1655 err(
1656 \\*
1657 );
1658}
1659
1660test "n_structure_trailing_#" {
1661 err(
1662 \\{"a":"b"}#{}
1663 );
1664}
1665
1666test "n_structure_U+2060_word_joined" {
1667 err(
1668 \\[⁠]
1669 );
1670}
1671
1672test "n_structure_uescaped_LF_before_string" {
1673 err(
1674 \\[\u000A""]
1675 );
1676}
1677
1678test "n_structure_unclosed_array" {
1679 err(
1680 \\[1
1681 );
1682}
1683
1684test "n_structure_unclosed_array_partial_null" {
1685 err(
1686 \\[ false, nul
1687 );
1688}
1689
1690test "n_structure_unclosed_array_unfinished_false" {
1691 err(
1692 \\[ true, fals
1693 );
1694}
1695
1696test "n_structure_unclosed_array_unfinished_true" {
1697 err(
1698 \\[ false, tru
1699 );
1700}
1701
1702test "n_structure_unclosed_object" {
1703 err(
1704 \\{"asd":"asd"
1705 );
1706}
1707
1708test "n_structure_unicode-identifier" {
1709 err(
1710 \\Ã¥
1711 );
1712}
1713
1714test "n_structure_UTF8_BOM_no_data" {
1715 err(
1716 \\
1717 );
1718}
1719
1720test "n_structure_whitespace_formfeed" {
1721 err(
1722 \\[ ]
1723 );
1724}
1725
1726test "n_structure_whitespace_U+2060_word_joiner" {
1727 err(
1728 \\[⁠]
1729 );
1730}
1731
1732////////////////////////////////////////////////////////////////////////////////////////////////////
1733
1734test "i_number_double_huge_neg_exp" {
1735 any(
1736 \\[123.456e-789]
1737 );
1738}
1739
1740test "i_number_huge_exp" {
1741 any(
1742 \\[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006]
1743 );
1744}
1745
1746test "i_number_neg_int_huge_exp" {
1747 any(
1748 \\[-1e+9999]
1749 );
1750}
1751
1752test "i_number_pos_double_huge_exp" {
1753 any(
1754 \\[1.5e+9999]
1755 );
1756}
1757
1758test "i_number_real_neg_overflow" {
1759 any(
1760 \\[-123123e100000]
1761 );
1762}
1763
1764test "i_number_real_pos_overflow" {
1765 any(
1766 \\[123123e100000]
1767 );
1768}
1769
1770test "i_number_real_underflow" {
1771 any(
1772 \\[123e-10000000]
1773 );
1774}
1775
1776test "i_number_too_big_neg_int" {
1777 any(
1778 \\[-123123123123123123123123123123]
1779 );
1780}
1781
1782test "i_number_too_big_pos_int" {
1783 any(
1784 \\[100000000000000000000]
1785 );
1786}
1787
1788test "i_number_very_big_negative_int" {
1789 any(
1790 \\[-237462374673276894279832749832423479823246327846]
1791 );
1792}
1793
1794test "i_object_key_lone_2nd_surrogate" {
1795 any(
1796 \\{"\uDFAA":0}
1797 );
1798}
1799
1800test "i_string_1st_surrogate_but_2nd_missing" {
1801 any(
1802 \\["\uDADA"]
1803 );
1804}
1805
1806test "i_string_1st_valid_surrogate_2nd_invalid" {
1807 any(
1808 \\["\uD888\u1234"]
1809 );
1810}
1811
1812test "i_string_incomplete_surrogate_and_escape_valid" {
1813 any(
1814 \\["\uD800\n"]
1815 );
1816}
1817
1818test "i_string_incomplete_surrogate_pair" {
1819 any(
1820 \\["\uDd1ea"]
1821 );
1822}
1823
1824test "i_string_incomplete_surrogates_escape_valid" {
1825 any(
1826 \\["\uD800\uD800\n"]
1827 );
1828}
1829
1830test "i_string_invalid_lonely_surrogate" {
1831 any(
1832 \\["\ud800"]
1833 );
1834}
1835
1836test "i_string_invalid_surrogate" {
1837 any(
1838 \\["\ud800abc"]
1839 );
1840}
1841
1842test "i_string_invalid_utf-8" {
1843 any(
1844 \\["ÿ"]
1845 );
1846}
1847
1848test "i_string_inverted_surrogates_U+1D11E" {
1849 any(
1850 \\["\uDd1e\uD834"]
1851 );
1852}
1853
1854test "i_string_iso_latin_1" {
1855 any(
1856 \\["é"]
1857 );
1858}
1859
1860test "i_string_lone_second_surrogate" {
1861 any(
1862 \\["\uDFAA"]
1863 );
1864}
1865
1866test "i_string_lone_utf8_continuation_byte" {
1867 any(
1868 \\[""]
1869 );
1870}
1871
1872test "i_string_not_in_unicode_range" {
1873 any(
1874 \\["ô¿¿¿"]
1875 );
1876}
1877
1878test "i_string_overlong_sequence_2_bytes" {
1879 any(
1880 \\["À¯"]
1881 );
1882}
1883
1884test "i_string_overlong_sequence_6_bytes" {
1885 any(
1886 \\["üƒ¿¿¿¿"]
1887 );
1888}
1889
1890test "i_string_overlong_sequence_6_bytes_null" {
1891 any(
1892 \\["ü€€€€€"]
1893 );
1894}
1895
1896test "i_string_truncated-utf-8" {
1897 any(
1898 \\["àÿ"]
1899 );
1900}
1901
1902test "i_string_utf16BE_no_BOM" {
1903 any(
1904 \\["é"]
1905 );
1906}
1907
1908test "i_string_utf16LE_no_BOM" {
1909 any(
1910 \\["é"]
1911 );
1912}
1913
1914test "i_string_UTF-16LE_with_BOM" {
1915 any(
1916 \\ÿþ["é"]
1917 );
1918}
1919
1920test "i_string_UTF-8_invalid_sequence" {
1921 any(
1922 \\["日шú"]
1923 );
1924}
1925
1926test "i_string_UTF8_surrogate_U+D800" {
1927 any(
1928 \\["í €"]
1929 );
1930}
1931
1932test "i_structure_500_nested_arrays" {
1933 any(
1934 ("[" ** 500) ++ ("]" ** 500)
1935 );
1936}
1937
1938test "i_structure_UTF-8_BOM_empty_object" {
1939 any(
1940 \\{}
1941 );
1942}
std/os/index.zig+1
......@@ -2477,6 +2477,7 @@ pub const Thread = struct {
24772477 },
24782478 builtin.Os.windows => {
24792479 assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
2480 assert(windows.CloseHandle(self.data.handle) != 0);
24802481 assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);
24812482 },
24822483 else => @compileError("Unsupported OS"),
std/special/compiler_rt/fixuint.zig+1-1
......@@ -1,5 +1,5 @@
11const is_test = @import("builtin").is_test;
2const Log2Int = @import("../../math/index.zig").Log2Int;
2const Log2Int = @import("std").math.Log2Int;
33
44pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t {
55 @setRuntimeSafety(is_test);
std/special/compiler_rt/fixunsdfdi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunsdfdi(a: f64, expected: u64) void {
55 const x = __fixunsdfdi(a);
std/special/compiler_rt/fixunsdfsi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunsdfsi(a: f64, expected: u32) void {
55 const x = __fixunsdfsi(a);
std/special/compiler_rt/fixunsdfti_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunsdfti(a: f64, expected: u128) void {
55 const x = __fixunsdfti(a);
std/special/compiler_rt/fixunssfdi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunssfdi(a: f32, expected: u64) void {
55 const x = __fixunssfdi(a);
std/special/compiler_rt/fixunssfsi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunssfsi(a: f32, expected: u32) void {
55 const x = __fixunssfsi(a);
std/special/compiler_rt/fixunssfti_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunssfti(a: f32, expected: u128) void {
55 const x = __fixunssfti(a);
std/special/compiler_rt/fixunstfdi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunstfdi(a: f128, expected: u64) void {
55 const x = __fixunstfdi(a);
std/special/compiler_rt/fixunstfsi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunstfsi(a: f128, expected: u32) void {
55 const x = __fixunstfsi(a);
std/special/compiler_rt/fixunstfti_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;
2const assert = @import("../../index.zig").debug.assert;
2const assert = @import("std").debug.assert;
33
44fn test__fixunstfti(a: f128, expected: u128) void {
55 const x = __fixunstfti(a);
std/special/compiler_rt/index.zig+3-2
......@@ -71,7 +71,8 @@ comptime {
7171 }
7272}
7373
74const assert = @import("../../index.zig").debug.assert;
74const std = @import("std");
75const assert = std.debug.assert;
7576
7677const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
7778
......@@ -80,7 +81,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
8081pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn {
8182 @setCold(true);
8283 if (is_test) {
83 @import("std").debug.panic("{}", msg);
84 std.debug.panic("{}", msg);
8485 } else {
8586 unreachable;
8687 }
std/special/compiler_rt/udivmod.zig+1-1
......@@ -9,7 +9,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
99
1010 const SingleInt = @IntType(false, @divExact(DoubleInt.bit_count, 2));
1111 const SignedDoubleInt = @IntType(true, DoubleInt.bit_count);
12 const Log2SingleInt = @import("../../math/index.zig").Log2Int(SingleInt);
12 const Log2SingleInt = @import("std").math.Log2Int(SingleInt);
1313
1414 const n = *@ptrCast(&const [2]SingleInt, &a); // TODO issue #421
1515 const d = *@ptrCast(&const [2]SingleInt, &b); // TODO issue #421
std/zig/parser_test.zig+27-19
......@@ -1,3 +1,30 @@
1// TODO
2//if (sr > n_uword_bits - 1) // d > r
3// return 0;
4
5// TODO switch with no body
6// format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
7
8
9//TODO
10//test "zig fmt: same-line comptime" {
11// try testCanonical(
12// \\test "" {
13// \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
14// \\}
15// \\
16// );
17//}
18
19
20//TODO
21//test "zig fmt: number literals" {
22// try testCanonical(
23// \\pub const f64_true_min = 4.94065645841246544177e-324;
24// \\
25// );
26//}
27
128test "zig fmt: line comments in struct initializer" {
229 try testCanonical(
330 \\fn foo() void {
......@@ -20,25 +47,6 @@ test "zig fmt: line comments in struct initializer" {
2047 );
2148}
2249
23//TODO
24//test "zig fmt: same-line comptime" {
25// try testCanonical(
26// \\test "" {
27// \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
28// \\}
29// \\
30// );
31//}
32
33
34//TODO
35//test "zig fmt: number literals" {
36// try testCanonical(
37// \\pub const f64_true_min = 4.94065645841246544177e-324;
38// \\
39// );
40//}
41
4250test "zig fmt: doc comments before struct field" {
4351 try testCanonical(
4452 \\pub const Allocator = struct {
test/behavior.zig+2
......@@ -36,6 +36,7 @@ comptime {
3636 _ = @import("cases/pub_enum/index.zig");
3737 _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
3838 _ = @import("cases/reflection.zig");
39 _ = @import("cases/type_info.zig");
3940 _ = @import("cases/sizeof_and_typeof.zig");
4041 _ = @import("cases/slice.zig");
4142 _ = @import("cases/struct.zig");
......@@ -52,4 +53,5 @@ comptime {
5253 _ = @import("cases/var_args.zig");
5354 _ = @import("cases/void.zig");
5455 _ = @import("cases/while.zig");
56 _ = @import("cases/fn_in_struct_in_comptime.zig");
5557}
test/cases/coroutines.zig+3-2
......@@ -219,8 +219,9 @@ async fn printTrace(p: promise->error!void) void {
219219 std.debug.assert(e == error.Fail);
220220 if (@errorReturnTrace()) |trace| {
221221 assert(trace.index == 1);
222 } else if (builtin.mode != builtin.Mode.ReleaseFast) {
223 @panic("expected return trace");
222 } else switch (builtin.mode) {
223 builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"),
224 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {},
224225 }
225226 };
226227}
test/cases/enum.zig+9
......@@ -392,3 +392,12 @@ test "enum with 1 field but explicit tag type should still have the tag type" {
392392 const Enum = enum(u8) { B = 2 };
393393 comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
394394}
395
396test "empty extern enum with members" {
397 const E = extern enum {
398 A,
399 B,
400 C,
401 };
402 assert(@sizeOf(E) == @sizeOf(c_int));
403}
test/cases/fn_in_struct_in_comptime.zig created+17
......@@ -0,0 +1,17 @@
1const assert = @import("std").debug.assert;
2
3fn get_foo() fn(&u8)usize {
4 comptime {
5 return struct {
6 fn func(ptr: &u8) usize {
7 var u = @ptrToInt(ptr);
8 return u;
9 }
10 }.func;
11 }
12}
13
14test "define a function in an anonymous struct in comptime" {
15 const foo = get_foo();
16 assert(foo(@intToPtr(&u8, 12345)) == 12345);
17}
test/cases/type_info.zig created+181
......@@ -0,0 +1,181 @@
1const assert = @import("std").debug.assert;
2const mem = @import("std").mem;
3const TypeInfo = @import("builtin").TypeInfo;
4const TypeId = @import("builtin").TypeId;
5
6test "type info: tag type, void info" {
7 comptime {
8 assert(@TagType(TypeInfo) == TypeId);
9 const void_info = @typeInfo(void);
10 assert(TypeId(void_info) == TypeId.Void);
11 assert(void_info.Void == {});
12 }
13}
14
15test "type info: integer, floating point type info" {
16 comptime {
17 const u8_info = @typeInfo(u8);
18 assert(TypeId(u8_info) == TypeId.Int);
19 assert(!u8_info.Int.is_signed);
20 assert(u8_info.Int.bits == 8);
21
22 const f64_info = @typeInfo(f64);
23 assert(TypeId(f64_info) == TypeId.Float);
24 assert(f64_info.Float.bits == 64);
25 }
26}
27
28test "type info: pointer, array and nullable type info" {
29 comptime {
30 const u32_ptr_info = @typeInfo(&u32);
31 assert(TypeId(u32_ptr_info) == TypeId.Pointer);
32 assert(u32_ptr_info.Pointer.is_const == false);
33 assert(u32_ptr_info.Pointer.is_volatile == false);
34 assert(u32_ptr_info.Pointer.alignment == 4);
35 assert(u32_ptr_info.Pointer.child == u32);
36
37 const arr_info = @typeInfo([42]bool);
38 assert(TypeId(arr_info) == TypeId.Array);
39 assert(arr_info.Array.len == 42);
40 assert(arr_info.Array.child == bool);
41
42 const null_info = @typeInfo(?void);
43 assert(TypeId(null_info) == TypeId.Nullable);
44 assert(null_info.Nullable.child == void);
45 }
46}
47
48test "type info: promise info" {
49 comptime {
50 const null_promise_info = @typeInfo(promise);
51 assert(TypeId(null_promise_info) == TypeId.Promise);
52 assert(null_promise_info.Promise.child == @typeOf(undefined));
53
54 const promise_info = @typeInfo(promise->usize);
55 assert(TypeId(promise_info) == TypeId.Promise);
56 assert(promise_info.Promise.child == usize);
57 }
58
59}
60
61test "type info: error set, error union info" {
62 comptime {
63 const TestErrorSet = error {
64 First,
65 Second,
66 Third,
67 };
68
69 const error_set_info = @typeInfo(TestErrorSet);
70 assert(TypeId(error_set_info) == TypeId.ErrorSet);
71 assert(error_set_info.ErrorSet.errors.len == 3);
72 assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
73 assert(error_set_info.ErrorSet.errors[2].value == usize(TestErrorSet.Third));
74
75 const error_union_info = @typeInfo(TestErrorSet!usize);
76 assert(TypeId(error_union_info) == TypeId.ErrorUnion);
77 assert(error_union_info.ErrorUnion.error_set == TestErrorSet);
78 assert(error_union_info.ErrorUnion.payload == usize);
79 }
80}
81
82test "type info: enum info" {
83 comptime {
84 const Os = @import("builtin").Os;
85
86 const os_info = @typeInfo(Os);
87 assert(TypeId(os_info) == TypeId.Enum);
88 assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
89 assert(os_info.Enum.fields.len == 32);
90 assert(mem.eql(u8, os_info.Enum.fields[1].name, "ananas"));
91 assert(os_info.Enum.fields[10].value == 10);
92 assert(os_info.Enum.tag_type == u5);
93 assert(os_info.Enum.defs.len == 0);
94 }
95}
96
97test "type info: union info" {
98 comptime {
99 const typeinfo_info = @typeInfo(TypeInfo);
100 assert(TypeId(typeinfo_info) == TypeId.Union);
101 assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
102 assert(typeinfo_info.Union.tag_type == TypeId);
103 assert(typeinfo_info.Union.fields.len == 25);
104 assert(typeinfo_info.Union.fields[4].enum_field != null);
105 assert((??typeinfo_info.Union.fields[4].enum_field).value == 4);
106 assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
107 assert(typeinfo_info.Union.defs.len == 20);
108
109 const TestNoTagUnion = union {
110 Foo: void,
111 Bar: u32,
112 };
113
114 const notag_union_info = @typeInfo(TestNoTagUnion);
115 assert(TypeId(notag_union_info) == TypeId.Union);
116 assert(notag_union_info.Union.tag_type == @typeOf(undefined));
117 assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
118 assert(notag_union_info.Union.fields.len == 2);
119 assert(notag_union_info.Union.fields[0].enum_field == null);
120 assert(notag_union_info.Union.fields[1].field_type == u32);
121
122 const TestExternUnion = extern union {
123 foo: &c_void,
124 };
125
126 const extern_union_info = @typeInfo(TestExternUnion);
127 assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
128 assert(extern_union_info.Union.tag_type == @typeOf(undefined));
129 assert(extern_union_info.Union.fields[0].enum_field == null);
130 assert(extern_union_info.Union.fields[0].field_type == &c_void);
131 }
132}
133
134test "type info: struct info" {
135 comptime {
136 const struct_info = @typeInfo(TestStruct);
137 assert(TypeId(struct_info) == TypeId.Struct);
138 assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
139 assert(struct_info.Struct.fields.len == 3);
140 assert(struct_info.Struct.fields[1].offset == null);
141 assert(struct_info.Struct.fields[2].field_type == &TestStruct);
142 assert(struct_info.Struct.defs.len == 2);
143 assert(struct_info.Struct.defs[0].is_pub);
144 assert(!struct_info.Struct.defs[0].data.Fn.is_extern);
145 assert(struct_info.Struct.defs[0].data.Fn.lib_name == null);
146 assert(struct_info.Struct.defs[0].data.Fn.return_type == void);
147 assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn(&const TestStruct)void);
148 }
149}
150
151const TestStruct = packed struct {
152 const Self = this;
153
154 fieldA: usize,
155 fieldB: void,
156 fieldC: &Self,
157
158 pub fn foo(self: &const Self) void {}
159};
160
161test "type info: function type info" {
162 comptime {
163 const fn_info = @typeInfo(@typeOf(foo));
164 assert(TypeId(fn_info) == TypeId.Fn);
165 assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
166 assert(fn_info.Fn.is_generic);
167 assert(fn_info.Fn.args.len == 2);
168 assert(fn_info.Fn.is_var_args);
169 assert(fn_info.Fn.return_type == @typeOf(undefined));
170 assert(fn_info.Fn.async_allocator_type == @typeOf(undefined));
171
172 const test_instance: TestStruct = undefined;
173 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
174 assert(TypeId(bound_fn_info) == TypeId.BoundFn);
175 assert(bound_fn_info.BoundFn.args[0].arg_type == &const TestStruct);
176 }
177}
178
179fn foo(comptime a: usize, b: bool, args: ...) usize {
180 return 0;
181}
test/cases/union.zig+10
......@@ -45,6 +45,16 @@ test "basic unions" {
4545 assert(foo.float == 12.34);
4646}
4747
48test "comptime union field access" {
49 comptime {
50 var foo = Foo { .int = 0 };
51 assert(foo.int == 0);
52
53 foo = Foo { .float = 42.42 };
54 assert(foo.float == 42.42);
55 }
56}
57
4858test "init union with runtime value" {
4959 var foo: Foo = undefined;
5060
test/compile_errors.zig+12-1
......@@ -3210,6 +3210,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
32103210 ,
32113211 ".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset");
32123212
3213 cases.add("invalid union field access in comptime",
3214 \\const Foo = union {
3215 \\ Bar: u8,
3216 \\ Baz: void,
3217 \\};
3218 \\comptime {
3219 \\ var foo = Foo {.Baz = {}};
3220 \\ const bar_val = foo.Bar;
3221 \\}
3222 ,
3223 ".tmp_source.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set");
3224
32133225 cases.add("getting return type of generic function",
32143226 \\fn generic(a: var) void {}
32153227 \\comptime {
......@@ -3225,5 +3237,4 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
32253237 \\}
32263238 ,
32273239 ".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic");
3228
32293240}
test/tests.zig+4-4
......@@ -152,7 +152,7 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons
152152 const step = b.step(b.fmt("test-{}", name), desc);
153153 for (test_targets) |test_target| {
154154 const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch);
155 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
155 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {
156156 for ([]bool{false, true}) |link_libc| {
157157 if (link_libc and !is_native) {
158158 // don't assume we have a cross-compiling libc set up
......@@ -451,7 +451,7 @@ pub const CompareOutputContext = struct {
451451 self.step.dependOn(&run_and_cmp_output.step);
452452 },
453453 Special.None => {
454 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
454 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {
455455 const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})",
456456 "compare-output", case.name, @tagName(mode)) catch unreachable;
457457 if (self.test_filter) |filter| {
......@@ -705,7 +705,7 @@ pub const CompileErrorContext = struct {
705705 pub fn addCase(self: &CompileErrorContext, case: &const TestCase) void {
706706 const b = self.b;
707707
708 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
708 for ([]Mode{Mode.Debug, Mode.ReleaseFast}) |mode| {
709709 const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {} ({})",
710710 case.name, @tagName(mode)) catch unreachable;
711711 if (self.test_filter) |filter| {
......@@ -773,7 +773,7 @@ pub const BuildExamplesContext = struct {
773773 pub fn addAllArgs(self: &BuildExamplesContext, root_src: []const u8, link_libc: bool) void {
774774 const b = self.b;
775775
776 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
776 for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {
777777 const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {} ({})",
778778 root_src, @tagName(mode)) catch unreachable;
779779 if (self.test_filter) |filter| {
test/translate_c.zig+22
......@@ -53,6 +53,28 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
5353 \\pub const Foo = enum_Foo;
5454 );
5555
56 cases.add("enums",
57 \\enum Foo {
58 \\ FooA = 2,
59 \\ FooB = 5,
60 \\ Foo1,
61 \\};
62 ,
63 \\pub const enum_Foo = extern enum {
64 \\ A = 2,
65 \\ B = 5,
66 \\ @"1" = 6,
67 \\};
68 ,
69 \\pub const FooA = enum_Foo.A;
70 ,
71 \\pub const FooB = enum_Foo.B;
72 ,
73 \\pub const Foo1 = enum_Foo.@"1";
74 ,
75 \\pub const Foo = enum_Foo;
76 );
77
5678 cases.add("restrict -> noalias",
5779 \\void foo(void *restrict bar, void *restrict);
5880 ,