@zigc/lib 0.16.0-test.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/LICENSE +19 -0
  2. package/c/math.zig +135 -35
  3. package/c/stropts.zig +17 -0
  4. package/c.zig +1 -0
  5. package/compiler/aro/aro/Attribute/names.zig +604 -589
  6. package/compiler/aro/aro/Attribute.zig +202 -116
  7. package/compiler/aro/aro/Builtins/common.zig +874 -863
  8. package/compiler/aro/aro/Builtins/eval.zig +15 -7
  9. package/compiler/aro/aro/Builtins.zig +0 -1
  10. package/compiler/aro/aro/CodeGen.zig +3 -1
  11. package/compiler/aro/aro/Compilation.zig +120 -97
  12. package/compiler/aro/aro/Diagnostics.zig +21 -17
  13. package/compiler/aro/aro/Driver/GCCDetector.zig +635 -0
  14. package/compiler/aro/aro/Driver.zig +124 -50
  15. package/compiler/aro/aro/LangOpts.zig +12 -2
  16. package/compiler/aro/aro/Parser/Diagnostic.zig +79 -19
  17. package/compiler/aro/aro/Parser.zig +336 -142
  18. package/compiler/aro/aro/Preprocessor/Diagnostic.zig +21 -0
  19. package/compiler/aro/aro/Preprocessor.zig +127 -56
  20. package/compiler/aro/aro/Target.zig +17 -12
  21. package/compiler/aro/aro/Tokenizer.zig +31 -14
  22. package/compiler/aro/aro/Toolchain.zig +4 -7
  23. package/compiler/aro/aro/Tree.zig +178 -148
  24. package/compiler/aro/aro/TypeStore.zig +82 -24
  25. package/compiler/aro/aro/Value.zig +13 -17
  26. package/compiler/aro/aro/features.zig +1 -0
  27. package/compiler/aro/aro/pragmas/once.zig +0 -1
  28. package/compiler/aro/aro/record_layout.zig +3 -3
  29. package/compiler/aro/assembly_backend/x86_64.zig +3 -4
  30. package/compiler/aro/backend/Assembly.zig +1 -2
  31. package/compiler/aro/backend/Interner.zig +2 -2
  32. package/compiler/aro/backend/Ir.zig +100 -92
  33. package/compiler/aro/include/ptrcheck.h +49 -0
  34. package/compiler/aro/main.zig +26 -10
  35. package/compiler/build_runner.zig +1 -0
  36. package/compiler/objdump.zig +93 -0
  37. package/compiler/reduce.zig +5 -1
  38. package/compiler/resinator/compile.zig +2 -2
  39. package/compiler/resinator/main.zig +7 -1
  40. package/compiler/resinator/preprocess.zig +1 -3
  41. package/compiler/std-docs.zig +8 -1
  42. package/compiler/test_runner.zig +193 -61
  43. package/compiler/translate-c/MacroTranslator.zig +80 -11
  44. package/compiler/translate-c/PatternList.zig +1 -9
  45. package/compiler/translate-c/Scope.zig +43 -6
  46. package/compiler/translate-c/Translator.zig +364 -126
  47. package/compiler/translate-c/ast.zig +19 -11
  48. package/compiler/translate-c/main.zig +75 -16
  49. package/compiler_rt/cos.zig +141 -52
  50. package/compiler_rt/limb64.zig +266 -0
  51. package/compiler_rt/long_double.zig +37 -0
  52. package/compiler_rt/mulo.zig +6 -1
  53. package/compiler_rt/rem_pio2l.zig +173 -0
  54. package/compiler_rt/sin.zig +140 -55
  55. package/compiler_rt/sincos.zig +279 -72
  56. package/compiler_rt/tan.zig +118 -47
  57. package/compiler_rt/trig.zig +256 -6
  58. package/compiler_rt.zig +2 -0
  59. package/fuzzer.zig +855 -307
  60. package/libc/musl/src/math/pow.c +343 -0
  61. package/package.json +1 -1
  62. package/std/Build/Fuzz.zig +6 -19
  63. package/std/Build/Module.zig +1 -1
  64. package/std/Build/Step/CheckObject.zig +3 -3
  65. package/std/Build/Step/Compile.zig +18 -0
  66. package/std/Build/Step/ConfigHeader.zig +49 -33
  67. package/std/Build/Step/InstallArtifact.zig +18 -0
  68. package/std/Build/Step/Run.zig +536 -87
  69. package/std/Build/Step/TranslateC.zig +0 -6
  70. package/std/Build/Step.zig +8 -15
  71. package/std/Build/WebServer.zig +29 -17
  72. package/std/Build/abi.zig +47 -11
  73. package/std/Build.zig +17 -14
  74. package/std/Io/Dispatch.zig +2 -0
  75. package/std/Io/File/Reader.zig +3 -1
  76. package/std/Io/File.zig +1 -0
  77. package/std/Io/Kqueue.zig +2 -2
  78. package/std/Io/Threaded.zig +181 -143
  79. package/std/Io/Uring.zig +2 -1
  80. package/std/Io.zig +970 -2
  81. package/std/Target.zig +3 -2
  82. package/std/Thread.zig +8 -3
  83. package/std/array_hash_map.zig +96 -555
  84. package/std/array_list.zig +22 -31
  85. package/std/bit_set.zig +22 -6
  86. package/std/builtin/assembly.zig +68 -0
  87. package/std/c.zig +17 -17
  88. package/std/compress/flate/Compress.zig +3 -3
  89. package/std/crypto/Certificate/Bundle.zig +15 -1
  90. package/std/crypto/codecs/asn1.zig +33 -18
  91. package/std/crypto/codecs/base64_hex_ct.zig +14 -4
  92. package/std/debug/Dwarf.zig +29 -9
  93. package/std/debug/Info.zig +4 -0
  94. package/std/debug/MachOFile.zig +46 -8
  95. package/std/debug/Pdb.zig +539 -36
  96. package/std/debug/SelfInfo/Elf.zig +19 -18
  97. package/std/debug/SelfInfo/MachO.zig +18 -7
  98. package/std/debug/SelfInfo/Windows.zig +138 -36
  99. package/std/debug.zig +179 -65
  100. package/std/enums.zig +25 -19
  101. package/std/heap/ArenaAllocator.zig +145 -154
  102. package/std/heap/debug_allocator.zig +7 -7
  103. package/std/http/Client.zig +10 -6
  104. package/std/http.zig +11 -9
  105. package/std/json/Stringify.zig +3 -3
  106. package/std/json/dynamic.zig +4 -4
  107. package/std/math/big/int.zig +16 -17
  108. package/std/mem/Allocator.zig +4 -5
  109. package/std/mem.zig +48 -0
  110. package/std/os/emscripten.zig +1 -17
  111. package/std/os/linux.zig +7 -2
  112. package/std/os/windows.zig +2 -2
  113. package/std/pdb.zig +143 -4
  114. package/std/posix.zig +6 -12
  115. package/std/priority_dequeue.zig +13 -12
  116. package/std/priority_queue.zig +5 -4
  117. package/std/process/Child.zig +1 -1
  118. package/std/process/Environ.zig +1 -1
  119. package/std/start.zig +17 -4
  120. package/std/std.zig +19 -6
  121. package/std/testing/FailingAllocator.zig +4 -4
  122. package/std/testing/Smith.zig +37 -2
  123. package/std/zig/Ast/Render.zig +186 -458
  124. package/std/zig/Ast.zig +0 -4
  125. package/std/zig/AstGen.zig +44 -7
  126. package/std/zig/AstSmith.zig +2602 -0
  127. package/std/zig/Client.zig +8 -3
  128. package/std/zig/Parse.zig +83 -74
  129. package/std/zig/Server.zig +26 -0
  130. package/std/zig/Zir.zig +17 -0
  131. package/std/zig/c_translation/helpers.zig +14 -9
  132. package/std/zig/llvm/Builder.zig +107 -48
  133. package/std/zig/system.zig +20 -4
  134. package/std/zig/tokenizer.zig +2 -1
  135. package/std/zig.zig +6 -0
  136. package/compiler/aro/aro/Driver/Filesystem.zig +0 -241
  137. package/libc/mingw/complex/cabs.c +0 -48
  138. package/libc/mingw/complex/cabsf.c +0 -48
  139. package/libc/mingw/complex/cacos.c +0 -50
  140. package/libc/mingw/complex/cacosf.c +0 -50
  141. package/libc/mingw/complex/carg.c +0 -48
  142. package/libc/mingw/complex/cargf.c +0 -48
  143. package/libc/mingw/complex/casin.c +0 -50
  144. package/libc/mingw/complex/casinf.c +0 -50
  145. package/libc/mingw/complex/catan.c +0 -50
  146. package/libc/mingw/complex/catanf.c +0 -50
  147. package/libc/mingw/complex/ccos.c +0 -50
  148. package/libc/mingw/complex/ccosf.c +0 -50
  149. package/libc/mingw/complex/cexp.c +0 -48
  150. package/libc/mingw/complex/cexpf.c +0 -48
  151. package/libc/mingw/complex/cimag.c +0 -48
  152. package/libc/mingw/complex/cimagf.c +0 -48
  153. package/libc/mingw/complex/clog.c +0 -48
  154. package/libc/mingw/complex/clog10.c +0 -49
  155. package/libc/mingw/complex/clog10f.c +0 -49
  156. package/libc/mingw/complex/clogf.c +0 -48
  157. package/libc/mingw/complex/conj.c +0 -48
  158. package/libc/mingw/complex/conjf.c +0 -48
  159. package/libc/mingw/complex/cpow.c +0 -48
  160. package/libc/mingw/complex/cpowf.c +0 -48
  161. package/libc/mingw/complex/cproj.c +0 -48
  162. package/libc/mingw/complex/cprojf.c +0 -48
  163. package/libc/mingw/complex/creal.c +0 -48
  164. package/libc/mingw/complex/crealf.c +0 -48
  165. package/libc/mingw/complex/csin.c +0 -50
  166. package/libc/mingw/complex/csinf.c +0 -50
  167. package/libc/mingw/complex/csqrt.c +0 -48
  168. package/libc/mingw/complex/csqrtf.c +0 -48
  169. package/libc/mingw/complex/ctan.c +0 -50
  170. package/libc/mingw/complex/ctanf.c +0 -50
  171. package/libc/mingw/math/arm/s_rint.c +0 -86
  172. package/libc/mingw/math/arm/s_rintf.c +0 -51
  173. package/libc/mingw/math/arm/sincos.S +0 -30
  174. package/libc/mingw/math/arm-common/sincosl.c +0 -13
  175. package/libc/mingw/math/arm64/rint.c +0 -12
  176. package/libc/mingw/math/arm64/rintf.c +0 -12
  177. package/libc/mingw/math/arm64/sincos.S +0 -32
  178. package/libc/mingw/math/bsd_private_base.h +0 -148
  179. package/libc/mingw/math/frexpf.c +0 -13
  180. package/libc/mingw/math/frexpl.c +0 -71
  181. package/libc/mingw/math/x86/acosf.c +0 -29
  182. package/libc/mingw/math/x86/atanf.c +0 -23
  183. package/libc/mingw/math/x86/atanl.c +0 -18
  184. package/libc/mingw/math/x86/cos.def.h +0 -65
  185. package/libc/mingw/math/x86/cosl.c +0 -46
  186. package/libc/mingw/math/x86/cosl_internal.S +0 -55
  187. package/libc/mingw/math/x86/ldexp.c +0 -23
  188. package/libc/mingw/math/x86/scalbn.S +0 -41
  189. package/libc/mingw/math/x86/scalbnf.S +0 -40
  190. package/libc/mingw/math/x86/sin.def.h +0 -65
  191. package/libc/mingw/math/x86/sinl.c +0 -46
  192. package/libc/mingw/math/x86/sinl_internal.S +0 -58
  193. package/libc/mingw/math/x86/tanl.S +0 -62
  194. package/libc/mingw/misc/btowc.c +0 -28
  195. package/libc/mingw/misc/wcstof.c +0 -66
  196. package/libc/mingw/misc/wcstoimax.c +0 -132
  197. package/libc/mingw/misc/wcstoumax.c +0 -126
  198. package/libc/mingw/misc/wctob.c +0 -29
  199. package/libc/mingw/misc/winbs_uint64.c +0 -6
  200. package/libc/mingw/misc/winbs_ulong.c +0 -6
  201. package/libc/mingw/misc/winbs_ushort.c +0 -6
  202. package/libc/mingw/stdio/_Exit.c +0 -10
  203. package/libc/mingw/stdio/_findfirst64i32.c +0 -21
  204. package/libc/mingw/stdio/_findnext64i32.c +0 -21
  205. package/libc/mingw/stdio/_fstat64i32.c +0 -37
  206. package/libc/mingw/stdio/_stat64i32.c +0 -37
  207. package/libc/mingw/stdio/_wfindfirst64i32.c +0 -21
  208. package/libc/mingw/stdio/_wfindnext64i32.c +0 -21
  209. package/libc/mingw/stdio/_wstat64i32.c +0 -37
  210. package/libc/musl/src/legacy/isastream.c +0 -7
  211. package/libc/musl/src/legacy/valloc.c +0 -8
  212. package/libc/musl/src/math/__cosl.c +0 -96
  213. package/libc/musl/src/math/__sinl.c +0 -78
  214. package/libc/musl/src/math/__tanl.c +0 -143
  215. package/libc/musl/src/math/aarch64/lrint.c +0 -10
  216. package/libc/musl/src/math/aarch64/lrintf.c +0 -10
  217. package/libc/musl/src/math/aarch64/rintf.c +0 -7
  218. package/libc/musl/src/math/cosl.c +0 -39
  219. package/libc/musl/src/math/fdim.c +0 -10
  220. package/libc/musl/src/math/finite.c +0 -7
  221. package/libc/musl/src/math/finitef.c +0 -7
  222. package/libc/musl/src/math/frexp.c +0 -23
  223. package/libc/musl/src/math/frexpf.c +0 -23
  224. package/libc/musl/src/math/frexpl.c +0 -29
  225. package/libc/musl/src/math/i386/lrint.c +0 -8
  226. package/libc/musl/src/math/i386/lrintf.c +0 -8
  227. package/libc/musl/src/math/i386/rintf.c +0 -7
  228. package/libc/musl/src/math/lrint.c +0 -72
  229. package/libc/musl/src/math/lrintf.c +0 -8
  230. package/libc/musl/src/math/powerpc64/lrint.c +0 -16
  231. package/libc/musl/src/math/powerpc64/lrintf.c +0 -16
  232. package/libc/musl/src/math/rintf.c +0 -30
  233. package/libc/musl/src/math/s390x/rintf.c +0 -15
  234. package/libc/musl/src/math/sincosl.c +0 -60
  235. package/libc/musl/src/math/sinl.c +0 -41
  236. package/libc/musl/src/math/tanl.c +0 -29
  237. package/libc/musl/src/math/x32/lrint.s +0 -5
  238. package/libc/musl/src/math/x32/lrintf.s +0 -5
  239. package/libc/musl/src/math/x86_64/lrint.c +0 -8
  240. package/libc/musl/src/math/x86_64/lrintf.c +0 -8
  241. package/libc/wasi/libc-bottom-half/sources/reallocarray.c +0 -14
@@ -0,0 +1,2602 @@
1
+ //! Generates a valid AST and corresponding source.
2
+ //!
3
+ //! This is based directly off grammer.peg
4
+
5
+ const std = @import("../std.zig");
6
+ const assert = std.debug.assert;
7
+ const Token = std.zig.Token;
8
+ const Smith = std.testing.Smith;
9
+ const Weight = Smith.Weight;
10
+ const AstSmith = @This();
11
+
12
+ smith: *Smith,
13
+
14
+ source_buf: [16384]u8,
15
+ source_len: usize,
16
+
17
+ token_tag_buf: [2048]Token.Tag,
18
+ token_start_buf: [2048]std.zig.Ast.ByteOffset,
19
+ tokens_len: usize,
20
+
21
+ /// For `.asterisk`, this also includes `.asterisk2`
22
+ not_token: ?Token.Tag,
23
+ not_token_comptime: bool,
24
+ /// ExprSuffix
25
+ /// <- KEYWORD_or
26
+ /// / KEYWORD_and
27
+ /// / CompareOp
28
+ /// / BitwiseOp
29
+ /// / BitShiftOp
30
+ /// / AdditionOp
31
+ /// / MultiplyOp
32
+ /// / EXCLAMATIONMARK
33
+ /// / SuffixOp
34
+ /// / FnCallArguments
35
+ not_expr_suffix: bool,
36
+ /// LabelableExpr
37
+ /// <- Block
38
+ /// / SwitchExpr
39
+ /// / LoopExpr
40
+ not_labelable_expr: ?enum { colon, expr },
41
+ not_label: bool,
42
+ not_break_label: bool,
43
+ not_block_expr: bool,
44
+ not_expr_statement: bool,
45
+
46
+ prev_ids_buf: [256]struct { start: u16, len: u16 },
47
+ /// This may be larger than `prev_ids` in which case,
48
+ /// x % prev_ids.len = next index
49
+ /// @min(x, prev_ids) = length
50
+ prev_ids_len: usize,
51
+
52
+ /// `generate` must be called on the returned value before any other methods
53
+ pub fn init(smith: *Smith) AstSmith {
54
+ return .{
55
+ .smith = smith,
56
+
57
+ .source_buf = undefined,
58
+ .source_len = 0,
59
+
60
+ .token_tag_buf = undefined,
61
+ .token_start_buf = undefined,
62
+ .tokens_len = 0,
63
+
64
+ .not_token = null,
65
+ .not_token_comptime = false,
66
+ .not_expr_suffix = false,
67
+ .not_labelable_expr = null,
68
+ .not_label = false,
69
+ .not_break_label = false,
70
+ .not_block_expr = false,
71
+ .not_expr_statement = false,
72
+
73
+ .prev_ids_buf = undefined,
74
+ .prev_ids_len = 0,
75
+ };
76
+ }
77
+
78
+ pub fn source(t: *AstSmith) [:0]u8 {
79
+ return t.source_buf[0..t.source_len :0];
80
+ }
81
+
82
+ /// The Slice is not backed by a MultiArrayList, so calling deinit or toMultiArrayList is illegal.
83
+ pub fn tokens(t: *AstSmith) std.zig.Ast.TokenList.Slice {
84
+ var slice: std.zig.Ast.TokenList.Slice = .{
85
+ .ptrs = undefined,
86
+ .len = t.tokens_len,
87
+ .capacity = t.tokens_len,
88
+ };
89
+ comptime assert(slice.ptrs.len == 2);
90
+ slice.ptrs[@intFromEnum(std.zig.Ast.TokenList.Field.tag)] = @ptrCast(&t.token_tag_buf);
91
+ slice.ptrs[@intFromEnum(std.zig.Ast.TokenList.Field.start)] = @ptrCast(&t.token_start_buf);
92
+ return slice;
93
+ }
94
+
95
+ pub const Error = error{ OutOfMemory, SkipZigTest };
96
+ const SourceError = error{SkipZigTest};
97
+
98
+ pub fn generate(a: *AstSmith, gpa: std.mem.Allocator) Error!std.zig.Ast {
99
+ try a.generateSource();
100
+ const ast = try std.zig.Ast.parseTokens(gpa, a.source(), a.tokens(), .zig);
101
+ assert(ast.errors.len == 0);
102
+ return ast;
103
+ }
104
+
105
+ pub fn generateSource(a: *AstSmith) SourceError!void {
106
+ try a.pegRoot();
107
+ try a.ensureSourceCapacity(1);
108
+ a.source_buf[a.source_len] = 0;
109
+ try a.addTokenTag(.eof);
110
+ }
111
+
112
+ /// For choices which can introduce a variable number of expressions, this should be used to reduce
113
+ /// unbounded recursion.
114
+ //
115
+ // `inline` to propogate caller's return address
116
+ inline fn smithListItemBool(a: *AstSmith) bool {
117
+ return a.smith.boolWeighted(63, 1);
118
+ }
119
+
120
+ /// For choices which can introduce a variable number of expressions, this should be used to reduce
121
+ /// unbounded recursion.
122
+ //
123
+ // `inline` to propogate caller's return address
124
+ inline fn smithListItemEos(a: *AstSmith) bool {
125
+ return a.smith.eosWeightedSimple(1, 63);
126
+ }
127
+
128
+ fn sourceCapacity(a: *AstSmith) []u8 {
129
+ return a.source_buf[a.source_len..];
130
+ }
131
+
132
+ fn sourceCapacityLen(a: *AstSmith) usize {
133
+ return a.source_buf.len - a.source_len;
134
+ }
135
+
136
+ fn ensureSourceCapacity(a: *AstSmith, n: usize) SourceError!void {
137
+ if (a.sourceCapacityLen() < n) return error.SkipZigTest;
138
+ }
139
+
140
+ fn addSourceByte(a: *AstSmith, byte: u8) SourceError!void {
141
+ try a.ensureSourceCapacity(1);
142
+ a.addSourceByteAssumeCapacity(byte);
143
+ }
144
+
145
+ fn addSourceByteAssumeCapacity(a: *AstSmith, byte: u8) void {
146
+ a.sourceCapacity()[0] = byte;
147
+ a.source_len += 1;
148
+ }
149
+
150
+ fn addSource(a: *AstSmith, bytes: []const u8) SourceError!void {
151
+ try a.ensureSourceCapacity(bytes.len);
152
+ a.addSourceAssumeCapacity(bytes);
153
+ }
154
+
155
+ fn addSourceAssumeCapacity(a: *AstSmith, bytes: []const u8) void {
156
+ @memcpy(a.sourceCapacity()[0..bytes.len], bytes);
157
+ a.source_len += bytes.len;
158
+ }
159
+
160
+ fn addSourceAsSlice(a: *AstSmith, len: usize) SourceError![]u8 {
161
+ try a.ensureSourceCapacity(len);
162
+ return a.addSourceAsSliceAssumeCapacity(len);
163
+ }
164
+
165
+ fn addSourceAsSliceAssumeCapacity(a: *AstSmith, len: usize) []u8 {
166
+ const slice = a.sourceCapacity()[0..len];
167
+ a.source_len += len;
168
+ return slice;
169
+ }
170
+
171
+ fn tokenCapacityLen(a: *AstSmith) usize {
172
+ return a.token_tag_buf.len - a.tokens_len;
173
+ }
174
+
175
+ fn ensureTokenCapacity(a: *AstSmith, n: usize) SourceError!void {
176
+ if (a.tokenCapacityLen() < n) return error.SkipZigTest;
177
+ }
178
+
179
+ fn isAlphanumeric(c: u8) bool {
180
+ return switch (c) {
181
+ '_', 'a'...'z', 'A'...'Z', '0'...'9' => true,
182
+ else => false,
183
+ };
184
+ }
185
+
186
+ /// For tokens starting with alphanumerics, this ensures
187
+ /// previous tokens followed by end_of_word aren't altered.
188
+ ///
189
+ /// end_of_word <- ![a-zA-Z0-9_] skip
190
+ fn preservePegEndOfWord(a: *AstSmith) SourceError!void {
191
+ if (a.source_len > 0 and isAlphanumeric(a.source_buf[a.source_len - 1])) {
192
+ try a.addSourceByte(' ');
193
+ }
194
+ }
195
+
196
+ /// Assumes the token has not been written yet
197
+ fn addTokenTag(a: *AstSmith, tag: Token.Tag) SourceError!void {
198
+ assert(tag != a.not_token);
199
+ if (a.not_token == .asterisk) assert(tag != .asterisk_asterisk);
200
+ a.not_token = null;
201
+
202
+ if (a.not_token_comptime) assert(tag != .keyword_comptime);
203
+ a.not_token_comptime = false;
204
+
205
+ if (a.not_label and tag == .identifier) {
206
+ a.not_token = .colon;
207
+ }
208
+ a.not_label = false;
209
+
210
+ if (a.not_break_label and tag == .colon) {
211
+ a.not_token = .identifier;
212
+ }
213
+ a.not_break_label = false;
214
+
215
+ if (a.not_labelable_expr) |part| switch (part) {
216
+ .colon => a.not_labelable_expr = if (tag == .colon) .expr else null,
217
+ .expr => switch (tag) {
218
+ .l_brace => unreachable,
219
+ .keyword_inline => {},
220
+ .keyword_for => unreachable,
221
+ .keyword_while => unreachable,
222
+ .keyword_switch => unreachable,
223
+ else => a.not_labelable_expr = null,
224
+ },
225
+ };
226
+
227
+ a.not_expr_suffix = false;
228
+ a.not_block_expr = false;
229
+ a.not_expr_statement = false;
230
+
231
+ try a.ensureTokenCapacity(1);
232
+ a.token_tag_buf[a.tokens_len] = tag;
233
+ a.token_start_buf[a.tokens_len] = @intCast(a.source_len);
234
+ a.tokens_len += 1;
235
+ }
236
+
237
+ /// Asserts the token has a lexeme (those without have corresponding methods)
238
+ fn pegToken(a: *AstSmith, tag: Token.Tag) SourceError!void {
239
+ const lexeme = tag.lexeme().?;
240
+
241
+ switch (lexeme[0]) {
242
+ '_', 'a'...'z', 'A'...'Z', '0'...'9' => try a.preservePegEndOfWord(),
243
+ '*' => if (a.tokens_len > 0 and a.source_buf[a.source_len - 1] == '*' and
244
+ a.token_tag_buf[a.tokens_len - 1] != .asterisk_asterisk)
245
+ {
246
+ try a.addSourceByte(' ');
247
+ },
248
+ '.' => if (a.tokens_len > 0 and switch (a.source_buf[a.source_len - 1]) {
249
+ '.' => true,
250
+ '0'...'9', 'a'...'z', 'A'...'Z' => a.token_tag_buf[a.tokens_len - 1] == .number_literal,
251
+ else => false,
252
+ }) {
253
+ try a.addSourceByte(' ');
254
+ },
255
+ '+', '-' => if (a.tokens_len > 0 and a.token_tag_buf[a.tokens_len - 1] == .number_literal and
256
+ switch (a.source_buf[a.source_len - 1]) {
257
+ 'e', 'E', 'p', 'P' => true,
258
+ else => false,
259
+ })
260
+ {
261
+ // Would otherwise be tokenized as the sign of a float's exponent
262
+ //
263
+ // e.g. "0xFE" ++ "+" ++ "2" (number_literal, plus, number_literal)
264
+ try a.addSourceByte(' ');
265
+ },
266
+ else => {},
267
+ }
268
+
269
+ if (isAlphanumeric(lexeme[0])) try a.preservePegEndOfWord();
270
+
271
+ try a.addTokenTag(tag);
272
+ try a.addSource(lexeme);
273
+ try a.pegSkip();
274
+ }
275
+
276
+ /// Asserts `a.source_len != 0`
277
+ fn pegTokenWhitespaceAround(a: *AstSmith, tag: Token.Tag) SourceError!void {
278
+ switch (a.source_buf[a.source_len - 1]) {
279
+ ' ', '\n' => {},
280
+ else => try a.addSourceByte(' '),
281
+ }
282
+ try a.addTokenTag(tag);
283
+ try a.addSource(tag.lexeme().?);
284
+ switch (a.smith.value(enum { space, line_break, cr_line_break })) {
285
+ // This is not the same as 'skip' since comments are not whitespace
286
+ .space => try a.addSourceByte(' '),
287
+ .line_break => try a.addSourceByte('\n'),
288
+ .cr_line_break => try a.addSource("\r\n"),
289
+ }
290
+ try a.pegSkip();
291
+ }
292
+
293
+ /// Root <- skip ContainerMembers eof
294
+ fn pegRoot(a: *AstSmith) SourceError!void {
295
+ try a.pegSkip();
296
+ try a.pegContainerMembers();
297
+ }
298
+
299
+ /// ContainerMembers <- container_doc_comment? ContainerDeclaration* (ContainerField COMMA)*
300
+ /// (ContainerField / ContainerDeclaration*)
301
+ fn pegContainerMembers(a: *AstSmith) SourceError!void {
302
+ if (a.smith.boolWeighted(63, 1)) {
303
+ try a.pegContainerDocComment();
304
+ }
305
+ while (!a.smithListItemEos()) {
306
+ try a.pegContainerDeclaration();
307
+ }
308
+ while (!a.smithListItemEos()) {
309
+ try a.pegContainerField();
310
+ try a.pegToken(.comma);
311
+ }
312
+ if (a.smithListItemBool()) {
313
+ if (a.smith.value(bool)) {
314
+ try a.pegContainerField();
315
+ } else while (true) {
316
+ try a.pegContainerDeclaration();
317
+ if (a.smithListItemEos()) break;
318
+ }
319
+ }
320
+ }
321
+
322
+ /// ContainerDeclaration <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl
323
+ fn pegContainerDeclaration(a: *AstSmith) SourceError!void {
324
+ switch (a.smith.value(enum { TestDecl, ComptimeDecl, Decl })) {
325
+ .TestDecl => try a.pegTestDecl(),
326
+ .ComptimeDecl => try a.pegComptimeDecl(),
327
+ .Decl => {
328
+ try a.pegMaybeDocComment();
329
+ if (a.smith.value(bool)) {
330
+ try a.pegToken(.keyword_pub);
331
+ }
332
+ try a.pegDecl();
333
+ },
334
+ }
335
+ }
336
+
337
+ /// KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block
338
+ fn pegTestDecl(a: *AstSmith) SourceError!void {
339
+ try a.pegToken(.keyword_test);
340
+ switch (a.smith.value(enum { none, string, id })) {
341
+ .none => {},
342
+ .string => try a.pegStringLiteralSingle(),
343
+ .id => try a.pegIdentifier(),
344
+ }
345
+ try a.pegBlock();
346
+ }
347
+
348
+ /// ComptimeDecl <- KEYWORD_comptime Block
349
+ fn pegComptimeDecl(a: *AstSmith) SourceError!void {
350
+ try a.pegToken(.keyword_comptime);
351
+ try a.pegBlock();
352
+ }
353
+
354
+ /// Decl
355
+ /// <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block)
356
+ /// / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON
357
+ /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal?
358
+ /// GlobalVarDecl
359
+ fn pegDecl(a: *AstSmith) SourceError!void {
360
+ const Modifier = enum(u8) {
361
+ none,
362
+ @"export",
363
+ @"extern",
364
+ extern_library,
365
+ @"inline",
366
+ @"noinline",
367
+ };
368
+ const is_fn = a.smith.value(bool);
369
+ const fn_modifiers = Smith.baselineWeights(Modifier);
370
+ const var_modifiers: []const Weight = &.{.rangeAtMost(Modifier, .none, .extern_library, 1)};
371
+ const modifier = a.smith.valueWeighted(Modifier, if (is_fn) fn_modifiers else var_modifiers);
372
+
373
+ switch (modifier) {
374
+ .none => {},
375
+ .@"export" => try a.pegToken(.keyword_export),
376
+ .@"extern" => try a.pegToken(.keyword_extern),
377
+ .extern_library => {
378
+ try a.pegToken(.keyword_extern);
379
+ try a.pegStringLiteralSingle();
380
+ },
381
+ .@"inline" => try a.pegToken(.keyword_inline),
382
+ .@"noinline" => try a.pegToken(.keyword_noinline),
383
+ }
384
+
385
+ if (is_fn) {
386
+ try a.pegFnProto();
387
+ if (modifier == .@"extern" or modifier == .extern_library or a.smith.value(bool)) {
388
+ try a.pegToken(.semicolon);
389
+ } else {
390
+ try a.pegBlock();
391
+ }
392
+ } else {
393
+ if (a.smith.value(bool)) try a.pegToken(.keyword_threadlocal);
394
+ try a.pegGlobalVarDecl();
395
+ }
396
+ }
397
+
398
+ /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace?
399
+ /// LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr !ExprSuffix
400
+ fn pegFnProto(a: *AstSmith) SourceError!void {
401
+ try a.pegToken(.keyword_fn);
402
+ if (a.smith.value(bool)) {
403
+ try a.pegIdentifier();
404
+ }
405
+ try a.pegToken(.l_paren);
406
+ try a.pegParamDeclList();
407
+ try a.pegToken(.r_paren);
408
+ if (a.smith.value(bool)) {
409
+ try a.pegByteAlign();
410
+ }
411
+ if (a.smith.value(bool)) {
412
+ try a.pegAddrSpace();
413
+ }
414
+ if (a.smith.value(bool)) {
415
+ try a.pegLinkSection();
416
+ }
417
+ if (a.smith.value(bool)) {
418
+ try a.pegCallConv();
419
+ }
420
+ if (a.smith.value(bool)) {
421
+ try a.pegToken(.bang);
422
+ }
423
+ try a.pegTypeExpr();
424
+ a.not_expr_suffix = true;
425
+ }
426
+
427
+ /// VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign?
428
+ /// AddrSpace? LinkSection?
429
+ fn pegVarDeclProto(a: *AstSmith) SourceError!void {
430
+ try a.pegToken(if (a.smith.value(bool)) .keyword_var else .keyword_const);
431
+ try a.pegIdentifier();
432
+
433
+ if (a.smith.value(bool)) {
434
+ try a.pegToken(.colon);
435
+ try a.pegTypeExpr();
436
+ }
437
+
438
+ if (a.smith.value(bool)) {
439
+ try a.pegByteAlign();
440
+ }
441
+
442
+ if (a.smith.value(bool)) {
443
+ try a.pegAddrSpace();
444
+ }
445
+
446
+ if (a.smith.value(bool)) {
447
+ try a.pegLinkSection();
448
+ }
449
+ }
450
+
451
+ /// GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON
452
+ fn pegGlobalVarDecl(a: *AstSmith) SourceError!void {
453
+ try a.pegVarDeclProto();
454
+ if (a.smithListItemBool()) {
455
+ try a.pegToken(.equal);
456
+ try a.pegExpr();
457
+ }
458
+ try a.pegToken(.semicolon);
459
+ }
460
+
461
+ /// ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_fn
462
+ /// (IDENTIFIER COLON !(IDENTIFIER COLON)) TypeExpr ByteAlign? (EQUAL Expr)?
463
+ fn pegContainerField(a: *AstSmith) SourceError!void {
464
+ try a.pegMaybeDocComment();
465
+ if (a.smith.value(bool)) {
466
+ try a.pegToken(.keyword_comptime);
467
+ }
468
+ if (a.smith.value(bool)) {
469
+ try a.pegIdentifier();
470
+ try a.pegToken(.colon);
471
+ } else {
472
+ a.not_token = .keyword_fn;
473
+ a.not_token_comptime = true;
474
+ a.not_label = true;
475
+ }
476
+ try a.pegTypeExpr();
477
+ if (a.smith.value(bool)) {
478
+ try a.pegByteAlign();
479
+ }
480
+ if (a.smith.value(bool)) {
481
+ try a.pegToken(.equal);
482
+ try a.pegExpr();
483
+ }
484
+ }
485
+
486
+ /// BlockStatement
487
+ /// <- Statement
488
+ /// / KEYWORD_defer BlockExprStatement
489
+ /// / KEYWORD_errdefer Payload? BlockExprStatement
490
+ /// / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement
491
+ fn pegBlockStatement(a: *AstSmith) SourceError!void {
492
+ const Kind = enum {
493
+ statement,
494
+ defer_statement,
495
+ errdefer_statement,
496
+ var_assign,
497
+ comptime_var_assign,
498
+ };
499
+ const weights = Smith.baselineWeights(Kind) ++ &[1]Weight{.value(Kind, .statement, 4)};
500
+ switch (a.smith.valueWeighted(Kind, weights)) {
501
+ .statement => try a.pegStatement(),
502
+ .defer_statement, .errdefer_statement => |kind| {
503
+ try a.pegToken(switch (kind) {
504
+ .defer_statement => .keyword_defer,
505
+ .errdefer_statement => .keyword_errdefer,
506
+ else => unreachable,
507
+ });
508
+ try a.pegBlockExprStatement();
509
+ },
510
+ .var_assign, .comptime_var_assign => |kind| {
511
+ a.not_expr_statement = true;
512
+ if (kind == .comptime_var_assign) {
513
+ try a.pegToken(.keyword_comptime);
514
+ a.not_block_expr = true;
515
+ }
516
+ try a.pegVarAssignStatement();
517
+ },
518
+ }
519
+ }
520
+
521
+ /// Statement
522
+ /// <- ExprStatement
523
+ /// / KEYWORD_suspend BlockExprStatement
524
+ /// / !ExprStatement (KEYWORD_comptime !BlockExpr)? AssignExpr SEMICOLON
525
+ ///
526
+ /// ExprStatement
527
+ /// <- IfStatement
528
+ /// / LabeledStatement
529
+ /// / KEYWORD_nosuspend BlockExprStatement
530
+ /// / KEYWORD_comptime BlockExpr
531
+ fn pegStatement(a: *AstSmith) SourceError!void {
532
+ switch (a.smith.value(enum {
533
+ if_statement,
534
+ labeled_statement,
535
+ comptime_block_expr,
536
+
537
+ nosuspend_statement,
538
+ suspend_statement,
539
+ assign_expr,
540
+ comptime_assign_expr,
541
+ })) {
542
+ .if_statement => try a.pegIfStatement(),
543
+ .labeled_statement => try a.pegLabeledStatement(),
544
+ .comptime_block_expr => {
545
+ try a.pegToken(.keyword_comptime);
546
+ try a.pegBlockExpr();
547
+ },
548
+
549
+ .nosuspend_statement,
550
+ .suspend_statement,
551
+ => |kind| {
552
+ try a.pegToken(switch (kind) {
553
+ .nosuspend_statement => .keyword_nosuspend,
554
+ .suspend_statement => .keyword_suspend,
555
+ else => unreachable,
556
+ });
557
+ try a.pegBlockExprStatement();
558
+ },
559
+ .assign_expr, .comptime_assign_expr => |kind| {
560
+ a.not_expr_statement = true;
561
+ if (kind == .comptime_assign_expr) {
562
+ try a.pegToken(.keyword_comptime);
563
+ a.not_block_expr = true;
564
+ }
565
+ try a.pegAssignExpr();
566
+ try a.pegToken(.semicolon);
567
+ },
568
+ }
569
+ }
570
+
571
+ /// IfStatement
572
+ /// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
573
+ /// / IfPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
574
+ fn pegIfStatement(a: *AstSmith) SourceError!void {
575
+ try a.pegIfPrefix();
576
+ const is_assign = a.smith.value(bool);
577
+ if (!is_assign) {
578
+ try a.pegBlockExpr();
579
+ } else {
580
+ a.not_block_expr = true;
581
+ try a.pegAssignExpr();
582
+ }
583
+ if (a.not_token != .keyword_else and a.smithListItemBool()) {
584
+ try a.pegToken(.keyword_else);
585
+ if (a.smith.value(bool)) {
586
+ try a.pegPayload();
587
+ }
588
+ try a.pegStatement();
589
+ } else if (is_assign) {
590
+ try a.pegToken(.semicolon);
591
+ } else {
592
+ a.not_token = .keyword_else;
593
+ }
594
+ }
595
+
596
+ /// LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr)
597
+ fn pegLabeledStatement(a: *AstSmith) SourceError!void {
598
+ if (a.smith.value(bool)) {
599
+ try a.pegBlockLabel();
600
+ }
601
+ switch (a.smith.value(enum { block, loop_statement, switch_expr })) {
602
+ .block => try a.pegBlock(),
603
+ .loop_statement => try a.pegLoopStatement(),
604
+ .switch_expr => try a.pegSwitchExpr(),
605
+ }
606
+ }
607
+
608
+ /// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
609
+ fn pegLoopStatement(a: *AstSmith) SourceError!void {
610
+ if (a.smith.value(bool)) {
611
+ try a.pegToken(.keyword_inline);
612
+ }
613
+ if (a.smith.value(bool)) {
614
+ try a.pegForStatement();
615
+ } else {
616
+ try a.pegWhileStatement();
617
+ }
618
+ }
619
+
620
+ /// ForStatement
621
+ /// <- ForPrefix BlockExpr ( KEYWORD_else Statement / !KEYWORD_else )
622
+ /// / ForPrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Statement )
623
+ fn pegForStatement(a: *AstSmith) SourceError!void {
624
+ try a.pegForPrefix();
625
+ const is_assign = a.smith.value(bool);
626
+ if (!is_assign) {
627
+ try a.pegBlockExpr();
628
+ } else {
629
+ a.not_block_expr = true;
630
+ try a.pegAssignExpr();
631
+ }
632
+ if (a.not_token != .keyword_else and a.smithListItemBool()) {
633
+ try a.pegToken(.keyword_else);
634
+ try a.pegStatement();
635
+ } else if (is_assign) {
636
+ try a.pegToken(.semicolon);
637
+ } else {
638
+ a.not_token = .keyword_else;
639
+ }
640
+ }
641
+
642
+ /// WhileStatement
643
+ /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
644
+ /// / WhilePrefix !BlockExpr AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
645
+ fn pegWhileStatement(a: *AstSmith) SourceError!void {
646
+ try a.pegWhilePrefix();
647
+ const is_assign = a.smith.value(bool);
648
+ if (!is_assign) {
649
+ try a.pegBlockExpr();
650
+ } else {
651
+ a.not_block_expr = true;
652
+ try a.pegAssignExpr();
653
+ }
654
+ if (a.not_token != .keyword_else and a.smithListItemBool()) {
655
+ try a.pegToken(.keyword_else);
656
+ if (a.smith.value(bool)) {
657
+ try a.pegPayload();
658
+ }
659
+ try a.pegStatement();
660
+ } else if (is_assign) {
661
+ try a.pegToken(.semicolon);
662
+ } else {
663
+ a.not_token = .keyword_else;
664
+ }
665
+ }
666
+
667
+ /// BlockExprStatement
668
+ /// <- BlockExpr
669
+ /// / !BlockExpr AssignExpr SEMICOLON
670
+ fn pegBlockExprStatement(a: *AstSmith) SourceError!void {
671
+ if (a.smith.value(bool)) {
672
+ try a.pegBlockExpr();
673
+ } else {
674
+ a.not_block_expr = true;
675
+ try a.pegAssignExpr();
676
+ try a.pegToken(.semicolon);
677
+ }
678
+ }
679
+
680
+ /// BlockExpr <- BlockLabel? Block
681
+ fn pegBlockExpr(a: *AstSmith) SourceError!void {
682
+ if (a.smith.value(bool)) {
683
+ try a.pegBlockLabel();
684
+ }
685
+ try a.pegBlock();
686
+ }
687
+
688
+ /// VarAssignStatement <- (Expr / VarDeclProto) (COMMA (Expr / VarDeclProto))* EQUAL Expr SEMICOLON
689
+ fn pegVarAssignStatement(a: *AstSmith) SourceError!void {
690
+ while (true) {
691
+ if (a.smith.value(bool)) {
692
+ try a.pegVarDeclProto();
693
+ } else {
694
+ try a.pegExpr();
695
+ }
696
+
697
+ if (a.smithListItemEos()) {
698
+ break;
699
+ } else {
700
+ try a.pegToken(.comma);
701
+ }
702
+ }
703
+
704
+ try a.pegToken(.equal);
705
+ try a.pegExpr();
706
+ try a.pegToken(.semicolon);
707
+ }
708
+
709
+ /// AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr)?
710
+ fn pegAssignExpr(a: *AstSmith) SourceError!void {
711
+ try a.pegExpr();
712
+ if (a.smith.value(bool)) {
713
+ if (!a.smithListItemBool()) {
714
+ try a.pegAssignOp();
715
+ } else {
716
+ while (true) {
717
+ try a.pegToken(.comma);
718
+ try a.pegExpr();
719
+ if (a.smithListItemEos()) break;
720
+ }
721
+ try a.pegToken(.equal);
722
+ }
723
+ try a.pegExpr();
724
+ }
725
+ }
726
+
727
+ /// SingleAssignExpr <- Expr (AssignOp Expr)?
728
+ fn pegSingleAssignExpr(a: *AstSmith) SourceError!void {
729
+ try a.pegExpr();
730
+ if (a.smith.value(bool)) {
731
+ try a.pegAssignOp();
732
+ try a.pegExpr();
733
+ }
734
+ }
735
+
736
+ /// Expr <- BoolOrExpr
737
+ const pegExpr = pegBoolOrExpr;
738
+
739
+ /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
740
+ fn pegBoolOrExpr(a: *AstSmith) SourceError!void {
741
+ try a.pegBoolAndExpr();
742
+ while (!a.not_expr_suffix and !a.smithListItemEos()) {
743
+ try a.pegTokenWhitespaceAround(.keyword_or);
744
+ try a.pegBoolAndExpr();
745
+ }
746
+ }
747
+
748
+ /// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)*
749
+ fn pegBoolAndExpr(a: *AstSmith) SourceError!void {
750
+ try a.pegCompareExpr();
751
+ while (!a.not_expr_suffix and !a.smithListItemEos()) {
752
+ try a.pegTokenWhitespaceAround(.keyword_and);
753
+ try a.pegCompareExpr();
754
+ }
755
+ }
756
+
757
+ /// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
758
+ fn pegCompareExpr(a: *AstSmith) SourceError!void {
759
+ try a.pegBitwiseExpr();
760
+ if (!a.not_expr_suffix and a.smithListItemBool()) {
761
+ try a.pegCompareOp();
762
+ try a.pegBitwiseExpr();
763
+ }
764
+ }
765
+
766
+ /// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
767
+ fn pegBitwiseExpr(a: *AstSmith) SourceError!void {
768
+ try a.pegBitShiftExpr();
769
+ while (!a.not_expr_suffix and !a.smithListItemEos()) {
770
+ try a.pegBitwiseOp();
771
+ try a.pegBitShiftExpr();
772
+ }
773
+ }
774
+
775
+ /// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)*
776
+ fn pegBitShiftExpr(a: *AstSmith) SourceError!void {
777
+ try a.pegAdditionExpr();
778
+ while (!a.not_expr_suffix and !a.smithListItemEos()) {
779
+ try a.pegBitShiftOp();
780
+ try a.pegAdditionExpr();
781
+ }
782
+ }
783
+
784
+ /// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)*
785
+ fn pegAdditionExpr(a: *AstSmith) SourceError!void {
786
+ try a.pegMultiplyExpr();
787
+ while (!a.not_expr_suffix and !a.smithListItemEos()) {
788
+ try a.pegAdditionOp();
789
+ try a.pegMultiplyExpr();
790
+ }
791
+ }
792
+
793
+ /// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)*
794
+ fn pegMultiplyExpr(a: *AstSmith) SourceError!void {
795
+ try a.pegPrefixExpr();
796
+ while (!a.not_expr_suffix and !a.smithListItemEos()) {
797
+ try a.pegMultiplyOp();
798
+ try a.pegPrefixExpr();
799
+ }
800
+ }
801
+
802
+ /// PrefixExpr <- PrefixOp* PrimaryExpr
803
+ fn pegPrefixExpr(a: *AstSmith) SourceError!void {
804
+ while (!a.smithListItemEos()) {
805
+ try a.pegPrefixOp();
806
+ }
807
+ try a.pegPrimaryExpr();
808
+ }
809
+
810
+ /// PrimaryExpr
811
+ /// <- AsmExpr
812
+ /// / IfExpr
813
+ /// / KEYWORD_break (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
814
+ /// / KEYWORD_comptime Expr !ExprSuffix
815
+ /// / KEYWORD_nosuspend Expr !ExprSuffix
816
+ /// / KEYWORD_continue (BreakLabel / !BreakLabel) (Expr !ExprSuffix / !SinglePtrTypeStart)
817
+ /// / KEYWORD_resume Expr !ExprSuffix
818
+ /// / KEYWORD_return (Expr !ExprSuffix / !SinglePtrTypeStart)
819
+ /// / BlockLabel? LoopExpr
820
+ /// / Block
821
+ /// / CurlySuffixExpr
822
+ fn pegPrimaryExpr(a: *AstSmith) SourceError!void {
823
+ const Kind = enum(u8) {
824
+ curly_suffix_expr,
825
+ @"return",
826
+ @"continue",
827
+ @"break",
828
+ block,
829
+ asm_expr,
830
+ // Always contain more expressions
831
+ if_expr,
832
+ loop_expr,
833
+ @"resume",
834
+ @"comptime",
835
+ @"nosuspend",
836
+ };
837
+
838
+ switch (a.smith.valueWeighted(Kind, &.{
839
+ .value(Kind, .curly_suffix_expr, 75),
840
+ .rangeAtMost(Kind, .@"return", .asm_expr, 4),
841
+ .rangeAtMost(Kind, .if_expr, .@"nosuspend", 1),
842
+ })) {
843
+ .curly_suffix_expr => try a.pegCurlySuffixExpr(),
844
+
845
+ .block => if (a.not_labelable_expr != .expr and !a.not_block_expr and !a.not_expr_statement) {
846
+ try a.pegBlock();
847
+ } else {
848
+ // Group
849
+ try a.pegToken(.l_paren);
850
+ try a.pegBlock();
851
+ try a.pegToken(.r_paren);
852
+ },
853
+ .asm_expr => try a.pegAsmExpr(),
854
+ .if_expr => if (!a.not_expr_statement) {
855
+ try a.pegIfExpr();
856
+ } else {
857
+ // Group
858
+ try a.pegToken(.l_paren);
859
+ try a.pegIfExpr();
860
+ try a.pegToken(.r_paren);
861
+ },
862
+ .loop_expr => {
863
+ const group = a.not_labelable_expr == .expr or a.not_expr_statement;
864
+ if (group) try a.pegToken(.l_paren);
865
+ if (!a.not_label and a.not_token != .identifier and a.smith.value(bool)) {
866
+ try a.pegBlockLabel();
867
+ }
868
+ try a.pegLoopExpr();
869
+ if (group) try a.pegToken(.r_paren);
870
+ },
871
+
872
+ .@"return",
873
+ .@"comptime",
874
+ .@"nosuspend",
875
+ .@"resume",
876
+ .@"break",
877
+ .@"continue",
878
+ => |t| {
879
+ const group = a.not_expr_statement and (t == .@"nosuspend" or t == .@"comptime");
880
+ if (group) try a.pegToken(.l_paren);
881
+
882
+ const kw: Token.Tag, const label, const expr = switch (t) {
883
+ .@"return" => .{ .keyword_return, false, a.smithListItemBool() },
884
+ .@"comptime" => .{ .keyword_comptime, false, true },
885
+ .@"nosuspend" => .{ .keyword_nosuspend, false, true },
886
+ .@"resume" => .{ .keyword_resume, false, true },
887
+ .@"break" => .{ .keyword_break, a.smith.value(bool), a.smithListItemBool() },
888
+ .@"continue" => .{ .keyword_continue, a.smith.value(bool), a.smithListItemBool() },
889
+ else => unreachable,
890
+ };
891
+ try a.pegToken(kw);
892
+ if (label) {
893
+ try a.pegBreakLabel();
894
+ } else {
895
+ a.not_break_label = true;
896
+ }
897
+ if (expr) {
898
+ try a.pegExpr();
899
+ a.not_expr_suffix = true;
900
+ } else {
901
+ a.not_token = .asterisk;
902
+ }
903
+
904
+ if (group) try a.pegToken(.r_paren);
905
+ },
906
+ }
907
+ }
908
+
909
+ /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
910
+ fn pegIfExpr(a: *AstSmith) SourceError!void {
911
+ try a.pegIfPrefix();
912
+ try a.pegExpr();
913
+ const Else = enum { none, @"else", else_payload };
914
+ switch (if (a.not_token != .keyword_else) a.smith.value(Else) else .none) {
915
+ .none => a.not_token = .keyword_else,
916
+ .@"else" => {
917
+ try a.pegToken(.keyword_else);
918
+ try a.pegExpr();
919
+ },
920
+ .else_payload => {
921
+ try a.pegToken(.keyword_else);
922
+ try a.pegPayload();
923
+ try a.pegExpr();
924
+ },
925
+ }
926
+ a.not_expr_suffix = true;
927
+ }
928
+
929
+ /// Block <- LBRACE Statement* RBRACE
930
+ fn pegBlock(a: *AstSmith) SourceError!void {
931
+ try a.pegToken(.l_brace);
932
+ while (!a.smithListItemEos()) {
933
+ try a.pegBlockStatement();
934
+ }
935
+ try a.pegToken(.r_brace);
936
+ }
937
+
938
+ /// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
939
+ fn pegLoopExpr(a: *AstSmith) SourceError!void {
940
+ if (a.smith.value(bool)) {
941
+ try a.pegToken(.keyword_inline);
942
+ }
943
+
944
+ if (a.smith.value(bool)) {
945
+ try a.pegForExpr();
946
+ } else {
947
+ try a.pegWhileExpr();
948
+ }
949
+ }
950
+
951
+ /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) !ExprSuffix
952
+ fn pegForExpr(a: *AstSmith) SourceError!void {
953
+ try a.pegForPrefix();
954
+ try a.pegExpr();
955
+ if (a.not_token != .keyword_else and a.smith.value(bool)) {
956
+ try a.pegToken(.keyword_else);
957
+ try a.pegExpr();
958
+ } else {
959
+ a.not_token = .keyword_else;
960
+ }
961
+ a.not_expr_suffix = true;
962
+ }
963
+
964
+ /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? !ExprSuffix
965
+ fn pegWhileExpr(a: *AstSmith) SourceError!void {
966
+ try a.pegWhilePrefix();
967
+ try a.pegExpr();
968
+ const Else = enum { none, @"else", else_payload };
969
+ switch (if (a.not_token != .keyword_else) a.smith.value(Else) else .none) {
970
+ .none => a.not_token = .keyword_else,
971
+ .@"else" => {
972
+ try a.pegToken(.keyword_else);
973
+ try a.pegExpr();
974
+ },
975
+ .else_payload => {
976
+ try a.pegToken(.keyword_else);
977
+ try a.pegPayload();
978
+ try a.pegExpr();
979
+ },
980
+ }
981
+ a.not_expr_suffix = true;
982
+ }
983
+
984
+ /// CurlySuffixExpr <- TypeExpr InitList?
985
+ fn pegCurlySuffixExpr(a: *AstSmith) SourceError!void {
986
+ try a.pegTypeExpr();
987
+ if (!a.not_expr_suffix and a.smith.value(bool)) {
988
+ try a.pegInitList();
989
+ }
990
+ }
991
+
992
+ /// InitList
993
+ /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
994
+ /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE
995
+ /// / LBRACE RBRACE
996
+ fn pegInitList(a: *AstSmith) SourceError!void {
997
+ try a.pegToken(.l_brace);
998
+ if (a.smithListItemBool()) {
999
+ if (a.smith.value(bool)) {
1000
+ try a.pegFieldInit();
1001
+ while (!a.smithListItemEos()) {
1002
+ try a.pegToken(.comma);
1003
+ try a.pegFieldInit();
1004
+ }
1005
+ } else {
1006
+ try a.pegExpr();
1007
+ while (!a.smithListItemEos()) {
1008
+ try a.pegToken(.comma);
1009
+ try a.pegExpr();
1010
+ }
1011
+ }
1012
+ if (a.smith.value(bool)) {
1013
+ try a.pegToken(.comma);
1014
+ }
1015
+ }
1016
+ try a.pegToken(.r_brace);
1017
+ }
1018
+
1019
+ /// PrefixTypeOp* ErrorUnionExpr
1020
+ fn pegTypeExpr(a: *AstSmith) SourceError!void {
1021
+ while (!a.smithListItemEos()) {
1022
+ try a.pegPrefixTypeOp();
1023
+ }
1024
+ try a.pegErrorUnionExpr();
1025
+ }
1026
+
1027
+ /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
1028
+ fn pegErrorUnionExpr(a: *AstSmith) SourceError!void {
1029
+ try a.pegSuffixExpr();
1030
+ if (!a.not_expr_suffix and a.smithListItemBool()) {
1031
+ try a.pegToken(.bang);
1032
+ try a.pegTypeExpr();
1033
+ }
1034
+ }
1035
+
1036
+ /// SuffixExpr
1037
+ /// <- PrimaryTypeExpr (SuffixOp / FnCallArguments)*
1038
+ fn pegSuffixExpr(a: *AstSmith) SourceError!void {
1039
+ try a.pegPrimaryTypeExpr();
1040
+ while (!a.not_expr_suffix and !a.smithListItemEos()) {
1041
+ if (a.smith.value(bool)) {
1042
+ try a.pegSuffixOp();
1043
+ } else {
1044
+ try a.pegFnCallArguments();
1045
+ }
1046
+ }
1047
+ }
1048
+
1049
+ /// PrimaryTypeExpr
1050
+ /// <- BUILTINIDENTIFIER FnCallArguments
1051
+ /// / CHAR_LITERAL
1052
+ /// / ContainerDecl
1053
+ /// / DOT IDENTIFIER
1054
+ /// / DOT InitList
1055
+ /// / ErrorSetDecl
1056
+ /// / FLOAT
1057
+ /// / FnProto
1058
+ /// / GroupedExpr
1059
+ /// / LabeledTypeExpr
1060
+ /// / IDENTIFIER !(COLON LabelableExpr)
1061
+ /// / IfTypeExpr
1062
+ /// / INTEGER
1063
+ /// / KEYWORD_comptime TypeExpr !ExprSuffix
1064
+ /// / KEYWORD_error DOT IDENTIFIER
1065
+ /// / KEYWORD_anyframe
1066
+ /// / KEYWORD_unreachable
1067
+ /// / STRINGLITERAL
1068
+ fn pegPrimaryTypeExpr(a: *AstSmith) SourceError!void {
1069
+ const Kind = enum(u8) {
1070
+ identifier,
1071
+ float,
1072
+ integer,
1073
+ char_literal,
1074
+ string_literal,
1075
+ enum_literal,
1076
+ error_literal,
1077
+ unreachable_type,
1078
+ anyframe_type,
1079
+
1080
+ // Containing zero or more expressions
1081
+ builtin_call,
1082
+ array_literal,
1083
+ container_decl,
1084
+ fn_proto,
1085
+ error_set,
1086
+
1087
+ // Containing one or more epressions
1088
+ grouped,
1089
+ labeled_type_expr,
1090
+ if_type_expr,
1091
+ comptime_expr,
1092
+ };
1093
+
1094
+ switch (a.smith.valueWeighted(Kind, &.{
1095
+ .rangeAtMost(Kind, .identifier, .anyframe_type, 5),
1096
+ .rangeAtMost(Kind, .builtin_call, .error_set, 2),
1097
+ .rangeAtMost(Kind, .grouped, .comptime_expr, 1),
1098
+ })) {
1099
+ .identifier => if (a.not_token != .identifier) {
1100
+ try a.pegIdentifier();
1101
+ a.not_labelable_expr = .colon;
1102
+ } else {
1103
+ // Group
1104
+ try a.pegToken(.l_paren);
1105
+ try a.pegIdentifier();
1106
+ try a.pegToken(.r_paren);
1107
+ },
1108
+ .float => try a.pegFloat(),
1109
+ .integer => try a.pegInteger(),
1110
+ .char_literal => try a.pegCharLiteral(),
1111
+ .string_literal => try a.pegStringLiteral(),
1112
+ .enum_literal => {
1113
+ try a.pegToken(.period);
1114
+ try a.pegIdentifier();
1115
+ },
1116
+ .error_literal => {
1117
+ try a.pegToken(.keyword_error);
1118
+ try a.pegToken(.period);
1119
+ try a.pegIdentifier();
1120
+ },
1121
+ .unreachable_type => try a.pegToken(.keyword_unreachable),
1122
+ .anyframe_type => try a.pegToken(.keyword_anyframe),
1123
+
1124
+ .builtin_call => {
1125
+ try a.pegBuiltinIdentifier();
1126
+ try a.pegFnCallArguments();
1127
+ },
1128
+ .array_literal => {
1129
+ try a.pegToken(.period);
1130
+ try a.pegInitList();
1131
+ },
1132
+ .container_decl => try a.pegContainerDecl(),
1133
+ .fn_proto => if (a.not_token != .keyword_fn) {
1134
+ try a.pegFnProto();
1135
+ } else {
1136
+ // Group
1137
+ try a.pegToken(.l_paren);
1138
+ try a.pegFnProto();
1139
+ try a.pegToken(.r_paren);
1140
+ },
1141
+ .error_set => try a.pegErrorSetDecl(),
1142
+
1143
+ .grouped => try a.pegGroupedExpr(),
1144
+ .labeled_type_expr => try a.pegLabeledTypeExpr(),
1145
+ .if_type_expr => if (!a.not_expr_statement) {
1146
+ try a.pegIfTypeExpr();
1147
+ } else {
1148
+ // Group
1149
+ try a.pegToken(.l_paren);
1150
+ try a.pegIfTypeExpr();
1151
+ try a.pegToken(.r_paren);
1152
+ },
1153
+ .comptime_expr => if (!a.not_token_comptime and !a.not_expr_statement) {
1154
+ try a.pegToken(.keyword_comptime);
1155
+ try a.pegTypeExpr();
1156
+ } else {
1157
+ // Group
1158
+ try a.pegToken(.l_paren);
1159
+ try a.pegToken(.keyword_comptime);
1160
+ try a.pegTypeExpr();
1161
+ try a.pegToken(.r_paren);
1162
+ },
1163
+ }
1164
+ }
1165
+
1166
+ /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
1167
+ fn pegContainerDecl(a: *AstSmith) SourceError!void {
1168
+ switch (a.smith.value(enum { auto, @"extern", @"packed" })) {
1169
+ .auto => {},
1170
+ .@"extern" => try a.pegToken(.keyword_extern),
1171
+ .@"packed" => try a.pegToken(.keyword_packed),
1172
+ }
1173
+ try a.pegContainerDeclAuto();
1174
+ }
1175
+
1176
+ /// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE
1177
+ fn pegErrorSetDecl(a: *AstSmith) SourceError!void {
1178
+ try a.pegToken(.keyword_error);
1179
+ try a.pegToken(.l_brace);
1180
+ try a.pegIdentifierList();
1181
+ try a.pegToken(.r_brace);
1182
+ }
1183
+
1184
+ /// GroupedExpr <- LPAREN Expr RPAREN
1185
+ fn pegGroupedExpr(a: *AstSmith) SourceError!void {
1186
+ try a.pegToken(.l_paren);
1187
+ try a.pegExpr();
1188
+ try a.pegToken(.r_paren);
1189
+ }
1190
+
1191
+ /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
1192
+ fn pegIfTypeExpr(a: *AstSmith) SourceError!void {
1193
+ try a.pegIfPrefix();
1194
+ try a.pegTypeExpr();
1195
+ const Else = enum { none, @"else", else_payload };
1196
+ switch (if (a.not_token != .keyword_else) a.smith.value(Else) else .none) {
1197
+ .none => a.not_token = .keyword_else,
1198
+ .@"else" => {
1199
+ try a.pegToken(.keyword_else);
1200
+ try a.pegTypeExpr();
1201
+ },
1202
+ .else_payload => {
1203
+ try a.pegToken(.keyword_else);
1204
+ try a.pegPayload();
1205
+ try a.pegTypeExpr();
1206
+ },
1207
+ }
1208
+ a.not_expr_suffix = true;
1209
+ }
1210
+
1211
+ /// LabeledTypeExpr
1212
+ /// <- BlockLabel Block
1213
+ /// / BlockLabel? LoopTypeExpr
1214
+ /// / BlockLabel? SwitchExpr
1215
+ fn pegLabeledTypeExpr(a: *AstSmith) SourceError!void {
1216
+ const kind = a.smith.value(enum { block, loop, @"switch" });
1217
+ const not_any = a.not_labelable_expr == .expr or a.not_expr_statement;
1218
+ const no_label = a.not_label or a.not_token == .identifier;
1219
+ const no_block = no_label or a.not_block_expr;
1220
+ const group = not_any or (kind == .block and no_block);
1221
+ if (group) try a.pegToken(.l_paren);
1222
+
1223
+ switch (kind) {
1224
+ .block => {
1225
+ try a.pegBlockLabel();
1226
+ try a.pegBlock();
1227
+ },
1228
+ .loop => {
1229
+ if (!no_label and a.smith.value(bool)) {
1230
+ try a.pegBlockLabel();
1231
+ }
1232
+ try a.pegLoopTypeExpr();
1233
+ },
1234
+ .@"switch" => {
1235
+ if (!no_label and a.smith.value(bool)) {
1236
+ try a.pegBlockLabel();
1237
+ }
1238
+ try a.pegSwitchExpr();
1239
+ },
1240
+ }
1241
+
1242
+ if (group) try a.pegToken(.r_paren);
1243
+ }
1244
+
1245
+ /// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
1246
+ fn pegLoopTypeExpr(a: *AstSmith) SourceError!void {
1247
+ if (a.smith.value(bool)) {
1248
+ try a.pegToken(.keyword_inline);
1249
+ }
1250
+
1251
+ if (a.smith.value(bool)) {
1252
+ try a.pegForTypeExpr();
1253
+ } else {
1254
+ try a.pegWhileTypeExpr();
1255
+ }
1256
+ }
1257
+
1258
+ /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) !ExprSuffix
1259
+ fn pegForTypeExpr(a: *AstSmith) SourceError!void {
1260
+ try a.pegForPrefix();
1261
+ try a.pegTypeExpr();
1262
+ if (a.not_token != .keyword_else and a.smith.value(bool)) {
1263
+ try a.pegToken(.keyword_else);
1264
+ try a.pegTypeExpr();
1265
+ } else {
1266
+ a.not_token = .keyword_else;
1267
+ }
1268
+ a.not_expr_suffix = true;
1269
+ }
1270
+
1271
+ /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? !ExprSuffix
1272
+ fn pegWhileTypeExpr(a: *AstSmith) SourceError!void {
1273
+ try a.pegWhilePrefix();
1274
+ try a.pegTypeExpr();
1275
+ const Else = enum { none, @"else", else_payload };
1276
+ switch (if (a.not_token != .keyword_else) a.smith.value(Else) else .none) {
1277
+ .none => a.not_token = .keyword_else,
1278
+ .@"else" => {
1279
+ try a.pegToken(.keyword_else);
1280
+ try a.pegTypeExpr();
1281
+ },
1282
+ .else_payload => {
1283
+ try a.pegToken(.keyword_else);
1284
+ try a.pegPayload();
1285
+ try a.pegTypeExpr();
1286
+ },
1287
+ }
1288
+ a.not_expr_suffix = true;
1289
+ }
1290
+
1291
+ /// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE
1292
+ fn pegSwitchExpr(a: *AstSmith) SourceError!void {
1293
+ try a.pegToken(.keyword_switch);
1294
+ try a.pegToken(.l_paren);
1295
+ try a.pegExpr();
1296
+ try a.pegToken(.r_paren);
1297
+
1298
+ try a.pegToken(.l_brace);
1299
+ try a.pegSwitchProngList();
1300
+ try a.pegToken(.r_brace);
1301
+ }
1302
+
1303
+ /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
1304
+ fn pegAsmExpr(a: *AstSmith) SourceError!void {
1305
+ try a.pegToken(.keyword_asm);
1306
+ if (a.smith.value(bool)) {
1307
+ try a.pegToken(.keyword_volatile);
1308
+ }
1309
+ try a.pegToken(.l_paren);
1310
+ try a.pegExpr();
1311
+ if (a.smith.value(bool)) {
1312
+ try a.pegAsmOutput();
1313
+ }
1314
+ try a.pegToken(.r_paren);
1315
+ }
1316
+
1317
+ /// AsmOutput <- COLON AsmOutputList AsmInput?
1318
+ fn pegAsmOutput(a: *AstSmith) SourceError!void {
1319
+ try a.pegToken(.colon);
1320
+ try a.pegAsmOutputList();
1321
+ if (a.smith.value(bool)) {
1322
+ try a.pegAsmInput();
1323
+ }
1324
+ }
1325
+
1326
+ /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
1327
+ fn pegAsmOutputItem(a: *AstSmith) SourceError!void {
1328
+ try a.pegToken(.l_bracket);
1329
+ try a.pegIdentifier();
1330
+ try a.pegToken(.r_bracket);
1331
+ try a.pegStringLiteralSingle();
1332
+ try a.pegToken(.l_paren);
1333
+ if (a.smith.value(bool)) {
1334
+ try a.pegToken(.arrow);
1335
+ try a.pegTypeExpr();
1336
+ } else {
1337
+ try a.pegIdentifier();
1338
+ }
1339
+ try a.pegToken(.r_paren);
1340
+ }
1341
+
1342
+ /// AsmInput <- COLON AsmInputList AsmClobbers?
1343
+ fn pegAsmInput(a: *AstSmith) SourceError!void {
1344
+ try a.pegToken(.colon);
1345
+ try a.pegAsmInputList();
1346
+ if (a.smith.value(bool)) {
1347
+ try a.pegAsmClobbers();
1348
+ }
1349
+ }
1350
+
1351
+ /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN
1352
+ fn pegAsmInputItem(a: *AstSmith) SourceError!void {
1353
+ try a.pegToken(.l_bracket);
1354
+ try a.pegIdentifier();
1355
+ try a.pegToken(.r_bracket);
1356
+ try a.pegStringLiteralSingle();
1357
+ try a.pegToken(.l_paren);
1358
+ try a.pegExpr();
1359
+ try a.pegToken(.r_paren);
1360
+ }
1361
+
1362
+ /// AsmClobbers <- COLON Expr
1363
+ fn pegAsmClobbers(a: *AstSmith) SourceError!void {
1364
+ try a.pegToken(.colon);
1365
+ try a.pegExpr();
1366
+ }
1367
+
1368
+ /// BreakLabel <- COLON IDENTIFIER
1369
+ fn pegBreakLabel(a: *AstSmith) SourceError!void {
1370
+ try a.pegToken(.colon);
1371
+ try a.pegIdentifier();
1372
+ }
1373
+
1374
+ /// BlockLabel <- IDENTIFIER COLON
1375
+ fn pegBlockLabel(a: *AstSmith) SourceError!void {
1376
+ try a.pegIdentifier();
1377
+ try a.pegToken(.colon);
1378
+ }
1379
+
1380
+ /// FieldInit <- DOT IDENTIFIER EQUAL Expr
1381
+ fn pegFieldInit(a: *AstSmith) SourceError!void {
1382
+ try a.pegToken(.period);
1383
+ try a.pegIdentifier();
1384
+ try a.pegToken(.equal);
1385
+ try a.pegExpr();
1386
+ }
1387
+
1388
+ /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
1389
+ fn pegWhileContinueExpr(a: *AstSmith) SourceError!void {
1390
+ try a.pegToken(.colon);
1391
+ try a.pegToken(.l_paren);
1392
+ try a.pegAssignExpr();
1393
+ try a.pegToken(.r_paren);
1394
+ }
1395
+
1396
+ /// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
1397
+ fn pegLinkSection(a: *AstSmith) SourceError!void {
1398
+ try a.pegToken(.keyword_linksection);
1399
+ try a.pegToken(.l_paren);
1400
+ try a.pegExpr();
1401
+ try a.pegToken(.r_paren);
1402
+ }
1403
+
1404
+ /// AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN
1405
+ fn pegAddrSpace(a: *AstSmith) SourceError!void {
1406
+ try a.pegToken(.keyword_addrspace);
1407
+ try a.pegToken(.l_paren);
1408
+ try a.pegExpr();
1409
+ try a.pegToken(.r_paren);
1410
+ }
1411
+
1412
+ /// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN
1413
+ fn pegCallConv(a: *AstSmith) SourceError!void {
1414
+ try a.pegToken(.keyword_callconv);
1415
+ try a.pegToken(.l_paren);
1416
+ try a.pegExpr();
1417
+ try a.pegToken(.r_paren);
1418
+ }
1419
+
1420
+ /// ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime)?
1421
+ /// ((IDENTIFIER COLON) / !KEYWORD_comptime !(IDENTIFIER COLON))
1422
+ /// ParamType
1423
+ fn pegParamDecl(a: *AstSmith) SourceError!void {
1424
+ try a.pegMaybeDocComment();
1425
+ const modifier = a.smith.value(enum { none, @"noalias", @"comptime" });
1426
+ switch (modifier) {
1427
+ .none => a.not_token_comptime = true,
1428
+ .@"noalias" => try a.pegToken(.keyword_noalias),
1429
+ .@"comptime" => try a.pegToken(.keyword_comptime),
1430
+ }
1431
+ if (a.smith.value(bool)) {
1432
+ try a.pegIdentifier();
1433
+ try a.pegToken(.colon);
1434
+ } else {
1435
+ a.not_label = true;
1436
+ }
1437
+ try a.pegParamType();
1438
+ }
1439
+
1440
+ /// ParamType
1441
+ /// <- KEYWORD_anytype
1442
+ /// / TypeExpr
1443
+ fn pegParamType(a: *AstSmith) SourceError!void {
1444
+ if (a.smith.value(bool)) {
1445
+ try a.pegToken(.keyword_anytype);
1446
+ } else {
1447
+ try a.pegTypeExpr();
1448
+ }
1449
+ }
1450
+
1451
+ /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload?
1452
+ fn pegIfPrefix(a: *AstSmith) SourceError!void {
1453
+ try a.pegToken(.keyword_if);
1454
+ try a.pegToken(.l_paren);
1455
+ try a.pegExpr();
1456
+ try a.pegToken(.r_paren);
1457
+ try a.pegPtrPayload();
1458
+ }
1459
+
1460
+ /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?
1461
+ fn pegWhilePrefix(a: *AstSmith) SourceError!void {
1462
+ try a.pegToken(.keyword_while);
1463
+ try a.pegToken(.l_paren);
1464
+ try a.pegExpr();
1465
+ try a.pegToken(.r_paren);
1466
+
1467
+ if (a.smith.value(bool)) {
1468
+ try a.pegPtrPayload();
1469
+ }
1470
+
1471
+ if (a.smith.value(bool)) {
1472
+ try a.pegWhileContinueExpr();
1473
+ }
1474
+ }
1475
+
1476
+ /// ForPrefix <- KEYWORD_for LPAREN ForArgumentsList RPAREN PtrListPayload
1477
+ ///
1478
+ /// An additional requirement checked in the Parser is that the number of
1479
+ /// arguments and payload elements are the same.
1480
+ fn pegForPrefix(a: *AstSmith) SourceError!void {
1481
+ try a.pegToken(.keyword_for);
1482
+ try a.pegToken(.l_paren);
1483
+ const n = try a.pegForArgumentsList();
1484
+ try a.pegToken(.r_paren);
1485
+ try a.pegPtrListPayload(n);
1486
+ }
1487
+
1488
+ /// Payload <- PIPE IDENTIFIER PIPE
1489
+ fn pegPayload(a: *AstSmith) SourceError!void {
1490
+ try a.pegToken(.pipe);
1491
+ try a.pegIdentifier();
1492
+ try a.pegToken(.pipe);
1493
+ }
1494
+
1495
+ /// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE
1496
+ fn pegPtrPayload(a: *AstSmith) SourceError!void {
1497
+ try a.pegToken(.pipe);
1498
+ if (a.smith.value(bool)) {
1499
+ try a.pegToken(.asterisk);
1500
+ }
1501
+ try a.pegIdentifier();
1502
+ try a.pegToken(.pipe);
1503
+ }
1504
+
1505
+ /// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
1506
+ fn pegPtrIndexPayload(a: *AstSmith) SourceError!void {
1507
+ try a.pegToken(.pipe);
1508
+ if (a.smith.value(bool)) {
1509
+ try a.pegToken(.asterisk);
1510
+ }
1511
+ try a.pegIdentifier();
1512
+ if (a.smith.value(bool)) {
1513
+ try a.pegToken(.comma);
1514
+ try a.pegIdentifier();
1515
+ }
1516
+ try a.pegToken(.pipe);
1517
+ }
1518
+
1519
+ /// PtrListPayload <- PIPE ASTERISK? IDENTIFIER (COMMA ASTERISK? IDENTIFIER)* COMMA? PIPE
1520
+ fn pegPtrListPayload(a: *AstSmith, n: usize) SourceError!void {
1521
+ try a.pegToken(.pipe);
1522
+ if (a.smith.value(bool)) {
1523
+ try a.pegToken(.asterisk);
1524
+ }
1525
+ try a.pegIdentifier();
1526
+
1527
+ for (1..n) |_| {
1528
+ try a.pegToken(.comma);
1529
+ if (a.smith.value(bool)) {
1530
+ try a.pegToken(.asterisk);
1531
+ }
1532
+ try a.pegIdentifier();
1533
+ }
1534
+
1535
+ if (a.smith.value(bool)) {
1536
+ try a.pegToken(.comma);
1537
+ }
1538
+ try a.pegToken(.pipe);
1539
+ }
1540
+
1541
+ /// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? SingleAssignExpr
1542
+ fn pegSwitchProng(a: *AstSmith) SourceError!void {
1543
+ if (a.smith.value(bool)) {
1544
+ try a.pegToken(.keyword_inline);
1545
+ }
1546
+ try a.pegSwitchCase();
1547
+ try a.pegToken(.equal_angle_bracket_right);
1548
+ if (a.smith.value(bool)) {
1549
+ try a.pegPtrIndexPayload();
1550
+ }
1551
+ try a.pegSingleAssignExpr();
1552
+ }
1553
+
1554
+ /// SwitchCase
1555
+ /// <- SwitchItem (COMMA SwitchItem)* COMMA?
1556
+ /// / KEYWORD_else
1557
+ fn pegSwitchCase(a: *AstSmith) SourceError!void {
1558
+ if (a.smith.value(bool)) {
1559
+ try a.pegSwitchItem();
1560
+ while (!a.smithListItemEos()) {
1561
+ try a.pegToken(.comma);
1562
+ try a.pegSwitchItem();
1563
+ }
1564
+ if (a.smith.value(bool)) {
1565
+ try a.pegToken(.comma);
1566
+ }
1567
+ } else {
1568
+ try a.pegToken(.keyword_else);
1569
+ }
1570
+ }
1571
+
1572
+ /// SwitchItem <- Expr (DOT3 Expr)?
1573
+ fn pegSwitchItem(a: *AstSmith) SourceError!void {
1574
+ try a.pegExpr();
1575
+ if (a.smith.value(bool)) {
1576
+ try a.pegToken(.ellipsis3);
1577
+ try a.pegExpr();
1578
+ }
1579
+ }
1580
+
1581
+ /// ForArgumentsList <- ForItem (COMMA ForItem)* COMMA?
1582
+ fn pegForArgumentsList(a: *AstSmith) SourceError!usize {
1583
+ try a.pegForItem();
1584
+ var n: usize = 1;
1585
+ while (!a.smithListItemEos()) {
1586
+ try a.pegToken(.comma);
1587
+ try a.pegForItem();
1588
+ n += 1;
1589
+ }
1590
+ if (a.smith.value(bool)) {
1591
+ try a.pegToken(.comma);
1592
+ }
1593
+ return n;
1594
+ }
1595
+
1596
+ /// ForItem <- Expr (DOT2 Expr?)?
1597
+ fn pegForItem(a: *AstSmith) SourceError!void {
1598
+ try a.pegExpr();
1599
+ const components = a.smith.valueRangeAtMost(u2, 0, 2);
1600
+ if (components >= 1) try a.pegToken(.ellipsis2);
1601
+ if (components >= 2) try a.pegExpr();
1602
+ }
1603
+
1604
+ /// AssignOp
1605
+ /// <- ASTERISKEQUAL
1606
+ /// / ASTERISKPIPEEQUAL
1607
+ /// / SLASHEQUAL
1608
+ /// / PERCENTEQUAL
1609
+ /// / PLUSEQUAL
1610
+ /// / PLUSPIPEEQUAL
1611
+ /// / MINUSEQUAL
1612
+ /// / MINUSPIPEEQUAL
1613
+ /// / LARROW2EQUAL
1614
+ /// / LARROW2PIPEEQUAL
1615
+ /// / RARROW2EQUAL
1616
+ /// / AMPERSANDEQUAL
1617
+ /// / CARETEQUAL
1618
+ /// / PIPEEQUAL
1619
+ /// / ASTERISKPERCENTEQUAL
1620
+ /// / PLUSPERCENTEQUAL
1621
+ /// / MINUSPERCENTEQUAL
1622
+ /// / EQUAL
1623
+ fn pegAssignOp(a: *AstSmith) SourceError!void {
1624
+ const tags = [_]Token.Tag{
1625
+ .asterisk_equal,
1626
+ .asterisk_pipe_equal,
1627
+ .slash_equal,
1628
+ .percent_equal,
1629
+ .plus_equal,
1630
+ .plus_pipe_equal,
1631
+ .minus_equal,
1632
+ .minus_pipe_equal,
1633
+ .angle_bracket_angle_bracket_left_equal,
1634
+ .angle_bracket_angle_bracket_left_pipe_equal,
1635
+ .angle_bracket_angle_bracket_right_equal,
1636
+ .ampersand_equal,
1637
+ .caret_equal,
1638
+ .pipe_equal,
1639
+ .asterisk_percent_equal,
1640
+ .plus_percent_equal,
1641
+ .minus_percent_equal,
1642
+ .equal,
1643
+ };
1644
+ try a.pegToken(tags[a.smith.index(tags.len)]);
1645
+ }
1646
+
1647
+ /// CompareOp
1648
+ /// <- EQUALEQUAL
1649
+ /// / EXCLAMATIONMARKEQUAL
1650
+ /// / LARROW
1651
+ /// / RARROW
1652
+ /// / LARROWEQUAL
1653
+ /// / RARROWEQUAL
1654
+ fn pegCompareOp(a: *AstSmith) SourceError!void {
1655
+ const tags = [_]Token.Tag{
1656
+ .equal_equal,
1657
+ .bang_equal,
1658
+ .angle_bracket_left,
1659
+ .angle_bracket_right,
1660
+ .angle_bracket_left_equal,
1661
+ .angle_bracket_right_equal,
1662
+ };
1663
+ try a.pegTokenWhitespaceAround(tags[a.smith.index(tags.len)]);
1664
+ }
1665
+
1666
+ /// BitwiseOp
1667
+ /// <- AMPERSAND
1668
+ /// / CARET
1669
+ /// / PIPE
1670
+ /// / KEYWORD_orelse
1671
+ /// / KEYWORD_catch Payload?
1672
+ fn pegBitwiseOp(a: *AstSmith) SourceError!void {
1673
+ const tags = [_]Token.Tag{
1674
+ .ampersand,
1675
+ .caret,
1676
+ .pipe,
1677
+ .keyword_orelse,
1678
+ .keyword_catch,
1679
+ };
1680
+ const tag = tags[a.smith.index(tags.len)];
1681
+ try a.pegTokenWhitespaceAround(tag);
1682
+ if (tag == .keyword_catch and a.smith.value(bool)) {
1683
+ try a.pegPayload();
1684
+ }
1685
+ }
1686
+
1687
+ /// BitShiftOp
1688
+ /// <- LARROW2
1689
+ /// / RARROW2
1690
+ /// / LARROW2PIPE
1691
+ fn pegBitShiftOp(a: *AstSmith) SourceError!void {
1692
+ const tags = [_]Token.Tag{
1693
+ .angle_bracket_angle_bracket_left,
1694
+ .angle_bracket_angle_bracket_right,
1695
+ .angle_bracket_angle_bracket_left_pipe,
1696
+ };
1697
+ try a.pegTokenWhitespaceAround(tags[a.smith.index(tags.len)]);
1698
+ }
1699
+
1700
+ /// AdditionOp
1701
+ /// <- PLUS
1702
+ /// / MINUS
1703
+ /// / PLUS2
1704
+ /// / PLUSPERCENT
1705
+ /// / MINUSPERCENT
1706
+ /// / PLUSPIPE
1707
+ /// / MINUSPIPE
1708
+ fn pegAdditionOp(a: *AstSmith) SourceError!void {
1709
+ const tags = [_]Token.Tag{
1710
+ .plus,
1711
+ .minus,
1712
+ .plus_plus,
1713
+ .plus_percent,
1714
+ .minus_percent,
1715
+ .plus_pipe,
1716
+ .minus_pipe,
1717
+ };
1718
+ try a.pegTokenWhitespaceAround(tags[a.smith.index(tags.len)]);
1719
+ }
1720
+
1721
+ /// MultiplyOp
1722
+ /// <- PIPE2
1723
+ /// / ASTERISK
1724
+ /// / SLASH
1725
+ /// / PERCENT
1726
+ /// / ASTERISK2
1727
+ /// / ASTERISKPERCENT
1728
+ /// / ASTERISKPIPE
1729
+ fn pegMultiplyOp(a: *AstSmith) SourceError!void {
1730
+ const tags = [_]Token.Tag{
1731
+ .asterisk,
1732
+ .asterisk_asterisk,
1733
+ .pipe_pipe,
1734
+ .slash,
1735
+ .percent,
1736
+ .asterisk_percent,
1737
+ .asterisk_pipe,
1738
+ };
1739
+ const start = @as(u8, 2) * @intFromBool(a.not_token == .asterisk);
1740
+ try a.pegTokenWhitespaceAround(tags[a.smith.valueRangeLessThan(u8, start, tags.len)]);
1741
+ }
1742
+
1743
+ /// PrefixOp
1744
+ /// <- EXCLAMATIONMARK
1745
+ /// / MINUS
1746
+ /// / TILDE
1747
+ /// / MINUSPERCENT
1748
+ /// / AMPERSAND
1749
+ /// / KEYWORD_try
1750
+ fn pegPrefixOp(a: *AstSmith) SourceError!void {
1751
+ const tags = [_]Token.Tag{
1752
+ .bang,
1753
+ .minus,
1754
+ .tilde,
1755
+ .minus_percent,
1756
+ .ampersand,
1757
+ .keyword_try,
1758
+ };
1759
+ try a.pegToken(tags[a.smith.index(tags.len)]);
1760
+ }
1761
+
1762
+ /// PrefixTypeOp
1763
+ /// <- QUESTIONMARK
1764
+ /// / KEYWORD_anyframe MINUSRARROW
1765
+ /// / (ManyPtrTypeStart / SliceTypeStart) KEYWORD_allowzero? ByteAlign? AddrSpace?
1766
+ /// KEYWORD_const? KEYWORD_volatile?
1767
+ /// / SinglePtrTypeStart KEYWORD_allowzero? BitAlign? AddrSpace?
1768
+ /// KEYWORD_const? KEYWORD_volatile?
1769
+ /// / ArrayTypeStart
1770
+ fn pegPrefixTypeOp(a: *AstSmith) SourceError!void {
1771
+ switch (a.smith.value(enum {
1772
+ optional,
1773
+ anyframe_arrow,
1774
+ array,
1775
+ single_pointer,
1776
+ many_pointer,
1777
+ slice,
1778
+ })) {
1779
+ .optional => try a.pegToken(.question_mark),
1780
+ .anyframe_arrow => {
1781
+ try a.pegToken(.keyword_anyframe);
1782
+ try a.pegToken(.arrow);
1783
+ },
1784
+ .array => try a.pegArrayTypeStart(),
1785
+ .single_pointer, .many_pointer, .slice => |kind| {
1786
+ const is_single = kind == .single_pointer and a.not_token != .asterisk;
1787
+ if (is_single) {
1788
+ try a.pegSinglePtrTypeStart();
1789
+ } else if (kind == .many_pointer) {
1790
+ try a.pegManyPtrTypeStart();
1791
+ } else {
1792
+ try a.pegSliceTypeStart();
1793
+ }
1794
+
1795
+ if (a.smith.value(bool)) {
1796
+ try a.pegToken(.keyword_allowzero);
1797
+ }
1798
+ if (a.smith.value(bool)) {
1799
+ if (is_single) {
1800
+ try a.pegBitAlign();
1801
+ } else {
1802
+ try a.pegByteAlign();
1803
+ }
1804
+ }
1805
+ if (a.smith.value(bool)) {
1806
+ try a.pegAddrSpace();
1807
+ }
1808
+ if (a.smith.value(bool)) {
1809
+ try a.pegToken(.keyword_const);
1810
+ }
1811
+ if (a.smith.value(bool)) {
1812
+ try a.pegToken(.keyword_volatile);
1813
+ }
1814
+ },
1815
+ }
1816
+ }
1817
+
1818
+ /// SuffixOp
1819
+ /// <- LBRACKET Expr (DOT2 (Expr? (COLON Expr)?)?)? RBRACKET
1820
+ /// / DOT IDENTIFIER
1821
+ /// / DOTASTERISK
1822
+ /// / DOTQUESTIONMARK
1823
+ fn pegSuffixOp(a: *AstSmith) SourceError!void {
1824
+ switch (a.smith.value(enum { slice, field, deref, unwrap })) {
1825
+ .slice => {
1826
+ try a.pegToken(.l_bracket);
1827
+ try a.pegExpr();
1828
+
1829
+ const components = a.smith.value(u2);
1830
+ if (components >= 1) try a.pegToken(.ellipsis2);
1831
+ if (components >= 2) try a.pegExpr();
1832
+ if (components >= 3) {
1833
+ try a.pegToken(.colon);
1834
+ try a.pegExpr();
1835
+ }
1836
+
1837
+ try a.pegToken(.r_bracket);
1838
+ },
1839
+ .field => {
1840
+ try a.pegToken(.period);
1841
+ try a.pegIdentifier();
1842
+ },
1843
+ .deref => try a.pegToken(.period_asterisk),
1844
+ .unwrap => {
1845
+ try a.pegToken(.period);
1846
+ try a.pegToken(.question_mark);
1847
+ },
1848
+ }
1849
+ }
1850
+
1851
+ /// FnCallArguments <- LPAREN ExprList RPAREN
1852
+ fn pegFnCallArguments(a: *AstSmith) SourceError!void {
1853
+ try a.pegToken(.l_paren);
1854
+ try a.pegExprList();
1855
+ try a.pegToken(.r_paren);
1856
+ }
1857
+
1858
+ /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
1859
+ fn pegSliceTypeStart(a: *AstSmith) SourceError!void {
1860
+ try a.pegToken(.l_bracket);
1861
+ if (a.smith.value(bool)) {
1862
+ try a.pegToken(.colon);
1863
+ try a.pegExpr();
1864
+ }
1865
+ try a.pegToken(.r_bracket);
1866
+ }
1867
+
1868
+ /// SinglePtrTypeStart <- ASTERISK / ASTERISK2
1869
+ fn pegSinglePtrTypeStart(a: *AstSmith) SourceError!void {
1870
+ try a.pegToken(if (!a.smith.value(bool)) .asterisk else .asterisk_asterisk);
1871
+ }
1872
+
1873
+ /// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
1874
+ fn pegManyPtrTypeStart(a: *AstSmith) SourceError!void {
1875
+ try a.pegToken(.l_bracket);
1876
+ try a.pegToken(.asterisk);
1877
+ switch (a.smith.value(enum { many, many_c, many_sentinel })) {
1878
+ .many => {},
1879
+ .many_c => {
1880
+ // No need for `preservePegEndOfWord` because the previous token is an asterisk
1881
+ try a.addTokenTag(.identifier);
1882
+ try a.addSourceByte('c');
1883
+ },
1884
+ .many_sentinel => {
1885
+ try a.pegToken(.colon);
1886
+ try a.pegExpr();
1887
+ },
1888
+ }
1889
+ try a.pegToken(.r_bracket);
1890
+ }
1891
+
1892
+ /// ArrayTypeStart <- LBRACKET !(ASTERISK / ASTERISK2) Expr (COLON Expr)? RBRACKET
1893
+ fn pegArrayTypeStart(a: *AstSmith) SourceError!void {
1894
+ try a.pegToken(.l_bracket);
1895
+ a.not_token = .asterisk;
1896
+ try a.pegExpr();
1897
+ if (a.smith.value(bool)) {
1898
+ try a.pegToken(.colon);
1899
+ try a.pegExpr();
1900
+ }
1901
+ try a.pegToken(.r_bracket);
1902
+ }
1903
+
1904
+ /// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
1905
+ fn pegContainerDeclAuto(a: *AstSmith) SourceError!void {
1906
+ try a.pegContainerDeclType();
1907
+ try a.pegToken(.l_brace);
1908
+ try a.pegContainerMembers();
1909
+ try a.pegToken(.r_brace);
1910
+ }
1911
+
1912
+ /// ContainerDeclType
1913
+ /// <- KEYWORD_struct (LPAREN Expr RPAREN)?
1914
+ /// / KEYWORD_opaque
1915
+ /// / KEYWORD_enum (LPAREN Expr RPAREN)?
1916
+ /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / !KEYWORD_enum Expr) RPAREN)?
1917
+ fn pegContainerDeclType(a: *AstSmith) SourceError!void {
1918
+ switch (a.smith.value(enum { @"struct", @"opaque", @"enum", @"union" })) {
1919
+ .@"struct", .@"enum" => |c| {
1920
+ const is_struct = c == .@"struct" or a.not_token == .keyword_enum;
1921
+ try a.pegToken(if (is_struct) .keyword_struct else .keyword_enum);
1922
+ if (a.smith.value(bool)) {
1923
+ try a.pegToken(.l_paren);
1924
+ try a.pegExpr();
1925
+ try a.pegToken(.r_paren);
1926
+ }
1927
+ },
1928
+ .@"opaque" => try a.pegToken(.keyword_opaque),
1929
+ .@"union" => {
1930
+ try a.pegToken(.keyword_union);
1931
+ switch (a.smith.value(enum { no_tag, expr_tag, enum_tag, enum_expr_tag })) {
1932
+ .no_tag => {},
1933
+ .expr_tag => {
1934
+ try a.pegToken(.l_paren);
1935
+ a.not_token = .keyword_enum;
1936
+ try a.pegExpr();
1937
+ try a.pegToken(.r_paren);
1938
+ },
1939
+ .enum_tag => {
1940
+ try a.pegToken(.l_paren);
1941
+ try a.pegToken(.keyword_enum);
1942
+ try a.pegToken(.r_paren);
1943
+ },
1944
+ .enum_expr_tag => {
1945
+ try a.pegToken(.l_paren);
1946
+ try a.pegToken(.keyword_enum);
1947
+ try a.pegToken(.l_paren);
1948
+ try a.pegExpr();
1949
+ try a.pegToken(.r_paren);
1950
+ try a.pegToken(.r_paren);
1951
+ },
1952
+ }
1953
+ },
1954
+ }
1955
+ }
1956
+
1957
+ /// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN
1958
+ fn pegByteAlign(a: *AstSmith) SourceError!void {
1959
+ try a.pegToken(.keyword_align);
1960
+ try a.pegToken(.l_paren);
1961
+ try a.pegExpr();
1962
+ try a.pegToken(.r_paren);
1963
+ }
1964
+
1965
+ /// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
1966
+ fn pegBitAlign(a: *AstSmith) SourceError!void {
1967
+ try a.pegToken(.keyword_align);
1968
+ try a.pegToken(.l_paren);
1969
+ try a.pegExpr();
1970
+ if (a.smith.value(bool)) {
1971
+ try a.pegToken(.colon);
1972
+ try a.pegExpr();
1973
+ try a.pegToken(.colon);
1974
+ try a.pegExpr();
1975
+ }
1976
+ try a.pegToken(.r_paren);
1977
+ }
1978
+
1979
+ /// IdentifierList <- (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)?
1980
+ fn pegIdentifierList(a: *AstSmith) SourceError!void {
1981
+ while (!a.smith.eos()) {
1982
+ try a.pegMaybeDocComment();
1983
+ try a.pegIdentifier();
1984
+ try a.pegToken(.comma);
1985
+ }
1986
+ if (a.smith.value(bool)) {
1987
+ try a.pegMaybeDocComment();
1988
+ try a.pegIdentifier();
1989
+ }
1990
+ }
1991
+
1992
+ /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
1993
+ fn pegSwitchProngList(a: *AstSmith) SourceError!void {
1994
+ while (!a.smithListItemEos()) {
1995
+ try a.pegSwitchProng();
1996
+ try a.pegToken(.comma);
1997
+ }
1998
+ if (a.smithListItemBool()) {
1999
+ try a.pegSwitchProng();
2000
+ }
2001
+ }
2002
+
2003
+ /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
2004
+ fn pegAsmOutputList(a: *AstSmith) SourceError!void {
2005
+ while (!a.smithListItemEos()) {
2006
+ try a.pegAsmOutputItem();
2007
+ try a.pegToken(.comma);
2008
+ }
2009
+ if (a.smithListItemBool()) {
2010
+ try a.pegAsmOutputItem();
2011
+ }
2012
+ }
2013
+
2014
+ /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
2015
+ fn pegAsmInputList(a: *AstSmith) SourceError!void {
2016
+ while (!a.smithListItemEos()) {
2017
+ try a.pegAsmInputItem();
2018
+ try a.pegToken(.comma);
2019
+ }
2020
+ if (a.smithListItemBool()) {
2021
+ try a.pegAsmInputItem();
2022
+ }
2023
+ }
2024
+
2025
+ /// ParamDeclList <- (ParamDecl COMMA)* (ParamDecl / DOT3 COMMA?)?
2026
+ fn pegParamDeclList(a: *AstSmith) SourceError!void {
2027
+ while (!a.smithListItemEos()) {
2028
+ try a.pegParamDecl();
2029
+ try a.pegToken(.comma);
2030
+ }
2031
+ const Final = enum { none, dot3, dot3_comma, param };
2032
+ switch (a.smith.valueWeighted(Final, &.{
2033
+ .rangeLessThan(Final, .none, .param, 2),
2034
+ .value(Final, .param, 1),
2035
+ })) {
2036
+ .none => {},
2037
+ .dot3 => try a.pegToken(.ellipsis3),
2038
+ .dot3_comma => {
2039
+ try a.pegToken(.ellipsis3);
2040
+ try a.pegToken(.comma);
2041
+ },
2042
+ .param => try a.pegParamDecl(),
2043
+ }
2044
+ }
2045
+
2046
+ /// ExprList <- (Expr COMMA)* Expr?
2047
+ fn pegExprList(a: *AstSmith) SourceError!void {
2048
+ while (!a.smithListItemEos()) {
2049
+ try a.pegExpr();
2050
+ try a.pegToken(.comma);
2051
+ }
2052
+ if (a.smithListItemBool()) {
2053
+ try a.pegExpr();
2054
+ }
2055
+ }
2056
+
2057
+ /// container_doc_comment <- ('//!' non_control_utf8* [ \n]* skip)+
2058
+ fn pegContainerDocComment(a: *AstSmith) SourceError!void {
2059
+ while (true) {
2060
+ try a.addTokenTag(.container_doc_comment);
2061
+ try a.pegGenericLine("//!", .any);
2062
+ try a.pegSkip();
2063
+ if (a.smith.eos()) break;
2064
+ }
2065
+ }
2066
+
2067
+ /// doc_comment?
2068
+ fn pegMaybeDocComment(a: *AstSmith) SourceError!void {
2069
+ // A specific hash is provided here since this function is likely to be inlined,
2070
+ // however having all doc comments with the same uid is beneficial.
2071
+ if (a.smith.boolWeightedWithHash(63, 1, 0x39b94392)) {
2072
+ try a.pegDocComment();
2073
+ }
2074
+ }
2075
+
2076
+ /// doc_comment <- ('///' non_control_utf8* [ \n]* skip)+
2077
+ fn pegDocComment(a: *AstSmith) SourceError!void {
2078
+ if (a.source_len > 0 and a.source_buf[a.source_len - 1] != '\n') {
2079
+ try a.addSourceByte('\n');
2080
+ }
2081
+ while (true) {
2082
+ try a.addTokenTag(.doc_comment);
2083
+ try a.pegGenericLine("///", .doc_comment);
2084
+ try a.pegSkip();
2085
+ if (a.smith.eosWeightedSimple(1, 3)) break;
2086
+ }
2087
+ }
2088
+
2089
+ /// line_comment <- '//' ![!/] non_control_utf8* / '////' non_control_utf8*
2090
+ fn pegLineComment(a: *AstSmith) SourceError!void {
2091
+ return a.pegGenericLine("//", .line_comment);
2092
+ }
2093
+
2094
+ /// line_string <- '\\\\' non_control_utf8* [ \n]*
2095
+ fn pegLineString(a: *AstSmith) SourceError!void {
2096
+ try a.addTokenTag(.multiline_string_literal_line);
2097
+ return a.pegGenericLine("\\\\", .any);
2098
+ }
2099
+
2100
+ /// non_control_utf8 <- [\040-\377]
2101
+ ///
2102
+ /// Used for line, doc, and container comments as well as
2103
+ /// multiline string literal lines.
2104
+ fn pegGenericLine(
2105
+ a: *AstSmith,
2106
+ prefix: []const u8,
2107
+ /// Adds constraints to what the line contains
2108
+ prefix_kind: enum { any, line_comment, doc_comment },
2109
+ ) SourceError!void {
2110
+ const cr = a.smith.value(bool);
2111
+ const newline_len = @intFromBool(cr) + @as(usize, 1);
2112
+
2113
+ try a.ensureSourceCapacity(prefix.len + newline_len);
2114
+ a.addSourceAssumeCapacity(prefix);
2115
+
2116
+ const line = a.variableChar(newline_len, 0, &.{
2117
+ .rangeAtMost(u8, ' ', 0x7f - 1, 1),
2118
+ .rangeAtMost(u8, 0x7f + 1, 0xff, 1),
2119
+ });
2120
+ if (line.len >= 1) switch (prefix_kind) {
2121
+ .any => {},
2122
+ .line_comment => {
2123
+ // Convert doc comments to quadruple slashes when possible;
2124
+ // Otherwise, and for container doc comments, erase the '/' or '!'
2125
+ if (line[0] == '/' and line.len >= 2) {
2126
+ line[1] = '/';
2127
+ } else if (line[0] == '/' or line[0] == '!') {
2128
+ line[0] = ' ';
2129
+ }
2130
+ },
2131
+ .doc_comment => {
2132
+ // Avoid quadruple slashes
2133
+ if (line[0] == '/') {
2134
+ line[0] = ' ';
2135
+ }
2136
+ },
2137
+ };
2138
+
2139
+ if (cr) a.addSourceByteAssumeCapacity('\r');
2140
+ a.addSourceByteAssumeCapacity('\n');
2141
+ }
2142
+
2143
+ /// skip <- ([ \n] / line_comment)*
2144
+ fn pegSkip(a: *AstSmith) SourceError!void {
2145
+ if (a.smith.boolWeighted(63, 1)) {
2146
+ while (true) {
2147
+ const Kind = enum {
2148
+ space,
2149
+ line_break,
2150
+ cr_line_break,
2151
+ line_comment,
2152
+ line_comment_zig_fmt_off,
2153
+ line_comment_zig_fmt_on,
2154
+ };
2155
+
2156
+ const weights = Smith.baselineWeights(Kind) ++
2157
+ [_]Weight{.value(Kind, .space, 11)};
2158
+ switch (a.smith.valueWeighted(Kind, weights)) {
2159
+ .space => try a.addSourceByte(' '),
2160
+ .line_break => try a.addSourceByte('\n'),
2161
+ .cr_line_break => try a.addSource("\r\n"),
2162
+ .line_comment => try a.pegLineComment(),
2163
+ .line_comment_zig_fmt_off => try a.addSource("//zig fmt: off\n"),
2164
+ .line_comment_zig_fmt_on => try a.addSource("//zig fmt: on\n"),
2165
+ }
2166
+
2167
+ if (a.smith.eos()) break;
2168
+ }
2169
+ }
2170
+ }
2171
+
2172
+ const bin_weights: []const Weight = &.{.rangeAtMost(u8, '0', '1', 1)};
2173
+ const oct_weights: []const Weight = &.{.rangeAtMost(u8, '0', '7', 1)};
2174
+ const dec_weights: []const Weight = &.{.rangeAtMost(u8, '0', '9', 1)};
2175
+ const hex_weights: []const Weight = &.{
2176
+ .rangeAtMost(u8, '0', '9', 1),
2177
+ .rangeAtMost(u8, 'a', 'f', 1),
2178
+ .rangeAtMost(u8, 'A', 'F', 1),
2179
+ };
2180
+
2181
+ /// Asserts enough capacity for at `min + reserved_capacity`
2182
+ fn variableChar(
2183
+ a: *AstSmith,
2184
+ reserved_capacity: usize,
2185
+ min: usize,
2186
+ weights: []const Weight,
2187
+ ) []u8 {
2188
+ const capacity = a.sourceCapacity();
2189
+ const max_out = capacity.len - reserved_capacity;
2190
+
2191
+ const len_weights: [3]Weight = .{
2192
+ .rangeAtMost(u32, @intCast(min), @min(2, max_out), 32678),
2193
+ // For the below `.rangeAtMost` is not used because max may be less than min.
2194
+ // In this case, the weights are omitted.
2195
+ .{ .min = 3, .max = @min(16, max_out), .weight = 512 },
2196
+ // Still allow much longer sequences to test parsing overflows
2197
+ .{ .min = 17, .max = @min(256, max_out), .weight = 1 },
2198
+ };
2199
+ const n_weights = @as(usize, 1) + @intFromBool(max_out >= 3) + @intFromBool(max_out >= 17);
2200
+
2201
+ const len = a.smith.sliceWeighted(capacity, len_weights[0..n_weights], weights);
2202
+ a.source_len += len;
2203
+ return capacity[0..len];
2204
+ }
2205
+
2206
+ /// char_escape
2207
+ /// <- "\\x" hex hex
2208
+ /// / "\\u{" hex+ "}"
2209
+ /// / "\\" [nr\\t'"]
2210
+ /// char_char
2211
+ /// <- multibyte_utf8
2212
+ /// / char_escape
2213
+ /// / ![\\'\n] non_control_ascii
2214
+ ///
2215
+ /// string_char
2216
+ /// <- multibyte_utf8
2217
+ /// / char_escape
2218
+ /// / ![\\"\n] non_control_ascii
2219
+ fn pegChar(a: *AstSmith, quote: u8) SourceError!void {
2220
+ const Char = enum(u8) {
2221
+ ascii,
2222
+ unicode_2,
2223
+ unicode_3,
2224
+ unicode_4,
2225
+ hex_escape,
2226
+ unicode_escape,
2227
+ char_escape,
2228
+ };
2229
+ const weights = Smith.baselineWeights(Char) ++ &[_]Weight{.value(Char, .ascii, 32)};
2230
+ switch (a.smith.valueWeighted(Char, weights)) {
2231
+ .ascii => try a.addSourceByte(a.smith.valueWeighted(u8, &.{
2232
+ .rangeAtMost(u8, ' ', quote - 1, 1),
2233
+ .rangeAtMost(u8, quote + 1, '\\' - 1, 1),
2234
+ .rangeAtMost(u8, '\\' + 1, 0x7e, 1),
2235
+ })),
2236
+ .unicode_2 => assert(2 == std.unicode.wtf8Encode(
2237
+ a.smith.valueRangeLessThan(u21, 0x80, 0x800),
2238
+ try a.addSourceAsSlice(2),
2239
+ ) catch unreachable),
2240
+ .unicode_3 => assert(3 == std.unicode.wtf8Encode(
2241
+ a.smith.valueRangeLessThan(u21, 0x800, 0x10000),
2242
+ try a.addSourceAsSlice(3),
2243
+ ) catch unreachable),
2244
+ .unicode_4 => assert(4 == std.unicode.wtf8Encode(
2245
+ a.smith.valueRangeLessThan(u21, 0x10000, 0x110000),
2246
+ try a.addSourceAsSlice(4),
2247
+ ) catch unreachable),
2248
+ .hex_escape => {
2249
+ try a.ensureSourceCapacity(4);
2250
+ a.addSourceAssumeCapacity("\\x");
2251
+ a.smith.bytesWeighted(a.addSourceAsSliceAssumeCapacity(2), hex_weights);
2252
+ },
2253
+ .unicode_escape => {
2254
+ try a.ensureSourceCapacity(5);
2255
+ a.addSourceAssumeCapacity("\\u{");
2256
+ _ = a.variableChar(1, 1, hex_weights);
2257
+ a.addSourceByteAssumeCapacity('}');
2258
+ },
2259
+ .char_escape => {
2260
+ try a.ensureSourceCapacity(2);
2261
+ a.addSourceByteAssumeCapacity('\\');
2262
+ a.addSourceByteAssumeCapacity(a.smith.valueWeighted(u8, &.{
2263
+ .value(u8, 'n', 1),
2264
+ .value(u8, 'r', 1),
2265
+ .value(u8, 't', 1),
2266
+ .value(u8, '\\', 1),
2267
+ .value(u8, '\'', 1),
2268
+ .value(u8, '"', 1),
2269
+ }));
2270
+ },
2271
+ }
2272
+ }
2273
+
2274
+ /// CHAR_LITERAL <- ['] char_char ['] skip
2275
+ fn pegCharLiteral(a: *AstSmith) SourceError!void {
2276
+ try a.addTokenTag(.char_literal);
2277
+ try a.addSourceByte('\'');
2278
+ try a.pegChar('\'');
2279
+ try a.addSourceByte('\'');
2280
+ try a.pegSkip();
2281
+ }
2282
+
2283
+ ///FLOAT
2284
+ /// <- '0x' hex_int '.' hex_int ([pP] [-+]? dec_int)? skip
2285
+ /// / dec_int '.' dec_int ([eE] [-+]? dec_int)? skip
2286
+ /// / '0x' hex_int [pP] [-+]? dec_int skip
2287
+ /// / dec_int [eE] [-+]? dec_int skip
2288
+ fn pegFloat(a: *AstSmith) SourceError!void {
2289
+ try a.preservePegEndOfWord();
2290
+ try a.addTokenTag(.number_literal);
2291
+
2292
+ const hex = a.smith.value(bool);
2293
+ const exp = a.smith.value(packed struct(u3) {
2294
+ kind: enum(u2) { none, no_sign, minus, plus },
2295
+ upper: bool,
2296
+ });
2297
+ const dot = exp.kind == .none or a.smith.value(bool);
2298
+
2299
+ var reserved: usize = @intFromBool(hex) * "0x".len + "0".len + @intFromBool(dot) * ".0".len +
2300
+ switch (exp.kind) {
2301
+ .none => 0,
2302
+ .no_sign => "e0".len,
2303
+ .minus => "e-0".len,
2304
+ .plus => "e+0".len,
2305
+ };
2306
+ try a.ensureSourceCapacity(reserved);
2307
+
2308
+ if (hex) {
2309
+ reserved -= 2;
2310
+ a.addSourceAssumeCapacity("0x");
2311
+ }
2312
+ const digits = if (hex) hex_weights else dec_weights;
2313
+
2314
+ reserved -= 1;
2315
+ _ = a.variableChar(reserved, 1, digits);
2316
+
2317
+ if (dot) {
2318
+ reserved -= 2;
2319
+ a.addSourceByteAssumeCapacity('.');
2320
+ _ = a.variableChar(reserved, 1, digits);
2321
+ }
2322
+
2323
+ if (exp.kind != .none) {
2324
+ reserved -= 1;
2325
+ const case_diff = @as(u8, 'a' - 'A') * @intFromBool(exp.upper);
2326
+ a.addSourceByteAssumeCapacity(@as(u8, if (hex) 'p' else 'e') - case_diff);
2327
+
2328
+ if (exp.kind != .no_sign) {
2329
+ reserved -= 1;
2330
+ a.addSourceByteAssumeCapacity(if (exp.kind == .plus) '+' else '-');
2331
+ }
2332
+
2333
+ reserved -= 1;
2334
+ assert(reserved == 0);
2335
+ _ = a.variableChar(reserved, 1, dec_weights);
2336
+ }
2337
+ }
2338
+
2339
+ ///INTEGER
2340
+ /// <- '0b' bin_int skip
2341
+ /// / '0o' oct_int skip
2342
+ /// / '0x' hex_int skip
2343
+ /// / dec_int skip
2344
+ fn pegInteger(a: *AstSmith) SourceError!void {
2345
+ try a.preservePegEndOfWord();
2346
+ try a.addTokenTag(.number_literal);
2347
+ const Base = enum { bin, dec, oct, hex };
2348
+ const base_weights: []const Weight = Smith.baselineWeights(Base) ++
2349
+ &[_]Weight{ .value(Base, .dec, 6), .value(Base, .hex, 2) };
2350
+ const digits, const prefix = switch (a.smith.valueWeighted(Base, base_weights)) {
2351
+ .bin => .{ bin_weights, "0b" },
2352
+ .oct => .{ oct_weights, "0o" },
2353
+ .dec => .{ dec_weights, "" },
2354
+ .hex => .{ hex_weights, "0x" },
2355
+ };
2356
+ try a.ensureSourceCapacity(prefix.len + 1);
2357
+ if (prefix.len != 0) a.addSourceAssumeCapacity(prefix);
2358
+ _ = a.variableChar(0, 1, digits);
2359
+ }
2360
+
2361
+ /// Does not include 'skip'. Does not add any token tag.
2362
+ fn stringLiteralSingleInner(a: *AstSmith) SourceError!void {
2363
+ try a.addSourceByte('"');
2364
+ while (!a.smith.eosWeightedSimple(3, 1)) {
2365
+ try a.pegChar('"');
2366
+ }
2367
+ try a.addSourceByte('"');
2368
+ }
2369
+
2370
+ /// STRINGLITERALSINGLE <- ["] string_char* ["] skip
2371
+ fn pegStringLiteralSingle(a: *AstSmith) SourceError!void {
2372
+ try a.addTokenTag(.string_literal);
2373
+ try a.stringLiteralSingleInner();
2374
+ try a.pegSkip();
2375
+ }
2376
+
2377
+ /// STRINGLITERAL
2378
+ /// <- STRINGLITERALSINGLE
2379
+ /// / (line_string skip)+
2380
+ fn pegStringLiteral(a: *AstSmith) SourceError!void {
2381
+ if (a.smith.value(bool)) {
2382
+ try a.pegStringLiteralSingle();
2383
+ } else {
2384
+ while (true) {
2385
+ try a.pegLineString();
2386
+ try a.pegSkip();
2387
+ if (a.smith.eos()) break;
2388
+ }
2389
+ }
2390
+ }
2391
+
2392
+ const alphanumeric_weights: [4]Weight = .{
2393
+ .rangeAtMost(u8, '0', '9', 1),
2394
+ .rangeAtMost(u8, 'A', 'Z', 1),
2395
+ .rangeAtMost(u8, 'a', 'z', 1),
2396
+ .value(u8, '_', 1),
2397
+ };
2398
+
2399
+ /// IDENTIFIER
2400
+ /// <- !keyword [A-Za-z_] [A-Za-z0-9_]* skip
2401
+ /// / '@' STRINGLITERALSINGLE
2402
+ fn pegIdentifier(a: *AstSmith) SourceError!void {
2403
+ const Kind = enum(u2) { underscore, regular_identifier, quoted_identifier, copy_identifier };
2404
+ const kind_weights: [4]Weight = .{
2405
+ .value(Kind, .underscore, 6),
2406
+ .value(Kind, .regular_identifier, 3),
2407
+ .value(Kind, .quoted_identifier, 1),
2408
+ .value(Kind, .copy_identifier, 6),
2409
+ };
2410
+ const n_weights = @as(usize, kind_weights.len) - @intFromBool(a.prev_ids_len == 0);
2411
+ const kind = a.smith.valueWeighted(Kind, kind_weights[0..n_weights]);
2412
+
2413
+ switch (kind) {
2414
+ .underscore => {
2415
+ try a.preservePegEndOfWord();
2416
+ try a.addTokenTag(.identifier);
2417
+ try a.addSourceByte('_');
2418
+ },
2419
+ .regular_identifier => {
2420
+ try a.preservePegEndOfWord();
2421
+ try a.addTokenTag(.identifier);
2422
+
2423
+ const start = a.source_len;
2424
+ try a.addSourceByte(a.smith.valueWeighted(u8, alphanumeric_weights[1..]));
2425
+ _ = a.variableChar(0, 0, &alphanumeric_weights);
2426
+
2427
+ if (Token.getKeyword(a.source_buf[start..a.source_len]) != null) {
2428
+ a.source_buf[start] = '_'; // No keywords start with '_'
2429
+ }
2430
+ },
2431
+ .quoted_identifier => {
2432
+ try a.addTokenTag(.identifier);
2433
+ try a.addSourceByte('@');
2434
+ try a.stringLiteralSingleInner();
2435
+ },
2436
+ .copy_identifier => {
2437
+ const n_prev = @min(a.prev_ids_len, a.prev_ids_buf.len);
2438
+ const prev_i = a.smith.valueRangeLessThan(u16, 0, n_prev);
2439
+ const prev = a.prev_ids_buf[prev_i];
2440
+
2441
+ if (a.source_buf[prev.start] != '@') try a.preservePegEndOfWord();
2442
+ try a.addTokenTag(.identifier);
2443
+ try a.addSource(a.source_buf[prev.start..][0..prev.len]);
2444
+ },
2445
+ }
2446
+ try a.pegSkip();
2447
+ if (kind != .copy_identifier) {
2448
+ const start = a.token_start_buf[a.tokens_len - 1];
2449
+ a.prev_ids_buf[a.prev_ids_len % a.prev_ids_buf.len] = .{
2450
+ .start = @intCast(start),
2451
+ .len = @intCast(a.source_len - start),
2452
+ };
2453
+ a.prev_ids_len += 1;
2454
+ }
2455
+ }
2456
+
2457
+ /// BUILTINIDENTIFIER <- '@'[A-Za-z_][A-Za-z0-9_]* skip
2458
+ fn pegBuiltinIdentifier(a: *AstSmith) SourceError!void {
2459
+ try a.addTokenTag(.builtin);
2460
+ if (a.smith.boolWeighted(1, 31)) {
2461
+ if (a.smith.boolWeighted(1, 8)) {
2462
+ // Pointer cast (reordable with zig fmt)
2463
+ const ids = [_][]const u8{
2464
+ "@ptrCast",
2465
+ "@addrspaceCast",
2466
+ "@alignCast",
2467
+ "@constCast",
2468
+ "@volatileCast",
2469
+ };
2470
+ try a.addSource(ids[a.smith.index(ids.len)]);
2471
+ } else {
2472
+ const ids = std.zig.BuiltinFn.list.keys();
2473
+ try a.addSource(ids[a.smith.index(ids.len)]);
2474
+ }
2475
+ } else {
2476
+ try a.ensureSourceCapacity(2);
2477
+ a.addSourceByteAssumeCapacity('@');
2478
+ a.addSourceByteAssumeCapacity(a.smith.valueWeighted(u8, alphanumeric_weights[1..]));
2479
+ _ = a.variableChar(0, 0, &alphanumeric_weights);
2480
+ }
2481
+ try a.pegSkip();
2482
+ }
2483
+
2484
+ test AstSmith {
2485
+ try std.testing.fuzz({}, checkGenerated, .{});
2486
+ }
2487
+
2488
+ fn checkGenerated(_: void, smith: *Smith) !void {
2489
+ var a: AstSmith = .init(smith);
2490
+ try a.generateSource();
2491
+
2492
+ { // Check tokenization matches source
2493
+ errdefer a.logBadSource(null);
2494
+
2495
+ const token_tags = a.token_tag_buf[0..a.tokens_len];
2496
+ const token_starts = a.token_start_buf[0..a.tokens_len];
2497
+ try std.testing.expectEqual(Token.Tag.eof, token_tags[token_tags.len - 1]);
2498
+
2499
+ var tokenizer: std.zig.Tokenizer = .init(a.source());
2500
+ for (token_tags, token_starts) |tag, start| {
2501
+ const tok = tokenizer.next();
2502
+ try std.testing.expectEqual(tok.tag, tag);
2503
+ try std.testing.expectEqual(tok.loc.start, start);
2504
+ if (tag == .invalid) return error.InvalidToken;
2505
+ }
2506
+ }
2507
+
2508
+ var fba_buf: [1 << 18]u8 = undefined;
2509
+ var fba: std.heap.FixedBufferAllocator = .init(&fba_buf);
2510
+ const ast = std.zig.Ast.parseTokens(fba.allocator(), a.source(), a.tokens(), .zig) catch
2511
+ return error.SkipZigTest;
2512
+
2513
+ errdefer a.logBadSource(ast);
2514
+ try std.testing.expectEqual(0, ast.errors.len);
2515
+ }
2516
+
2517
+ fn logBadSource(a: *AstSmith, ast: ?std.zig.Ast) void {
2518
+ var buf: [256]u8 = undefined;
2519
+ const ls = std.debug.lockStderr(&buf);
2520
+ defer std.debug.unlockStderr();
2521
+ a.logBadSourceInner(ls.terminal(), ast) catch {};
2522
+ }
2523
+
2524
+ fn logBadSourceInner(a: *AstSmith, t: std.Io.Terminal, ast: ?std.zig.Ast) std.Io.Writer.Error!void {
2525
+ try a.logSourceInner(t);
2526
+ const w = t.writer;
2527
+
2528
+ if (ast) |bad_ast| {
2529
+ try w.writeAll("=== Parse Errors ===\n");
2530
+ for (bad_ast.errors) |err| {
2531
+ const loc = bad_ast.tokenLocation(0, err.token);
2532
+ try w.print("{}:{}: ", .{ loc.line + 1, loc.column + 1 });
2533
+ try bad_ast.renderError(err, w);
2534
+ try w.writeByte('\n');
2535
+ }
2536
+ } else {
2537
+ t.setColor(.dim) catch {};
2538
+ try w.writeAll("=== Tokens ===\n");
2539
+ t.setColor(.reset) catch {};
2540
+ for (
2541
+ 0..,
2542
+ a.token_tag_buf[0..a.tokens_len],
2543
+ a.token_start_buf[0..a.tokens_len],
2544
+ ) |i, tag, start| {
2545
+ try w.print("#{} @{}: {t}\n", .{ i, start, tag });
2546
+ }
2547
+
2548
+ t.setColor(.dim) catch {};
2549
+ try w.writeAll("\n=== Expected Tokens ===\n");
2550
+ t.setColor(.reset) catch {};
2551
+
2552
+ var tokenizer: std.zig.Tokenizer = .init(a.source());
2553
+ var i: usize = 0;
2554
+ while (true) {
2555
+ const tok = tokenizer.next();
2556
+ try w.print("#{} @{}-{}: {t}\n", .{ i, tok.loc.start, tok.loc.end, tok.tag });
2557
+ i += 1;
2558
+ if (tok.tag == .invalid or tok.tag == .eof) break;
2559
+ }
2560
+ }
2561
+ }
2562
+
2563
+ pub fn logSource(a: *AstSmith) void {
2564
+ var buf: [256]u8 = undefined;
2565
+ const ls = std.debug.lockStderr(&buf);
2566
+ defer std.debug.unlockStderr();
2567
+ a.logSourceInner(ls.terminal()) catch {};
2568
+ }
2569
+
2570
+ fn logSourceInner(a: *AstSmith, t: std.Io.Terminal) std.Io.Writer.Error!void {
2571
+ const w = t.writer;
2572
+
2573
+ t.setColor(.dim) catch {};
2574
+ try w.writeAll("=== Source ===\n");
2575
+ t.setColor(.reset) catch {};
2576
+
2577
+ var line: usize = 1;
2578
+ try w.print("{: >5} ", .{line});
2579
+ for (a.source()) |c| switch (c) {
2580
+ ' '...0x7e => try w.writeByte(c),
2581
+ '\n' => {
2582
+ line += 1;
2583
+ try w.print("\n{: >5} ", .{line});
2584
+ },
2585
+ '\r' => {
2586
+ t.setColor(.cyan) catch {};
2587
+ try w.writeAll("\\r");
2588
+ t.setColor(.reset) catch {};
2589
+ },
2590
+ '\t' => {
2591
+ t.setColor(.cyan) catch {};
2592
+ try w.writeAll("\\t");
2593
+ t.setColor(.reset) catch {};
2594
+ },
2595
+ else => {
2596
+ t.setColor(.cyan) catch {};
2597
+ try w.print("\\x{x:0>2}", .{c});
2598
+ t.setColor(.reset) catch {};
2599
+ },
2600
+ };
2601
+ try w.writeByte('\n');
2602
+ }