authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-12-12 22:41:21-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-12-17 11:16:55-07:00
logab44939941215a753ca51f7b2d84a90d52bfebcf
tree0764925c68e694a4ecbdbb9346bb3a5a9acf81d9
parent39e96d933ec3611017edccfdd443fece826a7207

roughly parsing infix operators


3 files changed, 274 insertions(+), 144 deletions(-)

src-self-hosted/ast.zig+63-35
......@@ -13,9 +13,9 @@ pub const Node = struct {
1313 Identifier,
1414 FnProto,
1515 ParamDecl,
16 AddrOfExpr,
1716 Block,
18 Return,
17 InfixOp,
18 PrefixOp,
1919 IntegerLiteral,
2020 FloatLiteral,
2121 };
......@@ -27,9 +27,9 @@ pub const Node = struct {
2727 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).iterate(index),
2828 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index),
2929 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index),
30 Id.AddrOfExpr => @fieldParentPtr(NodeAddrOfExpr, "base", base).iterate(index),
3130 Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index),
32 Id.Return => @fieldParentPtr(NodeReturn, "base", base).iterate(index),
31 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index),
32 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index),
3333 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index),
3434 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index),
3535 };
......@@ -42,9 +42,9 @@ pub const Node = struct {
4242 Id.Identifier => allocator.destroy(@fieldParentPtr(NodeIdentifier, "base", base)),
4343 Id.FnProto => allocator.destroy(@fieldParentPtr(NodeFnProto, "base", base)),
4444 Id.ParamDecl => allocator.destroy(@fieldParentPtr(NodeParamDecl, "base", base)),
45 Id.AddrOfExpr => allocator.destroy(@fieldParentPtr(NodeAddrOfExpr, "base", base)),
4645 Id.Block => allocator.destroy(@fieldParentPtr(NodeBlock, "base", base)),
47 Id.Return => allocator.destroy(@fieldParentPtr(NodeReturn, "base", base)),
46 Id.InfixOp => allocator.destroy(@fieldParentPtr(NodeInfixOp, "base", base)),
47 Id.PrefixOp => allocator.destroy(@fieldParentPtr(NodePrefixOp, "base", base)),
4848 Id.IntegerLiteral => allocator.destroy(@fieldParentPtr(NodeIntegerLiteral, "base", base)),
4949 Id.FloatLiteral => allocator.destroy(@fieldParentPtr(NodeFloatLiteral, "base", base)),
5050 };
......@@ -170,56 +170,84 @@ pub const NodeParamDecl = struct {
170170 }
171171};
172172
173pub const NodeAddrOfExpr = struct {
173pub const NodeBlock = struct {
174174 base: Node,
175 op_token: Token,
176 align_expr: ?&Node,
177 bit_offset_start_token: ?Token,
178 bit_offset_end_token: ?Token,
179 const_token: ?Token,
180 volatile_token: ?Token,
181 op_expr: &Node,
182
183 pub fn iterate(self: &NodeAddrOfExpr, index: usize) -> ?&Node {
184 var i = index;
175 begin_token: Token,
176 end_token: Token,
177 statements: ArrayList(&Node),
185178
186 if (self.align_expr) |align_expr| {
187 if (i < 1) return align_expr;
188 i -= 1;
189 }
179 pub fn iterate(self: &NodeBlock, index: usize) -> ?&Node {
180 var i = index;
190181
191 if (i < 1) return self.op_expr;
192 i -= 1;
182 if (i < self.statements.len) return self.statements.items[i];
183 i -= self.statements.len;
193184
194185 return null;
195186 }
196187};
197188
198pub const NodeBlock = struct {
189pub const NodeInfixOp = struct {
199190 base: Node,
200 begin_token: Token,
201 end_token: Token,
202 statements: ArrayList(&Node),
191 op_token: Token,
192 lhs: &Node,
193 op: InfixOp,
194 rhs: &Node,
203195
204 pub fn iterate(self: &NodeBlock, index: usize) -> ?&Node {
196 const InfixOp = enum {
197 EqualEqual,
198 BangEqual,
199 };
200
201 pub fn iterate(self: &NodeInfixOp, index: usize) -> ?&Node {
205202 var i = index;
206203
207 if (i < self.statements.len) return self.statements.items[i];
208 i -= self.statements.len;
204 if (i < 1) return self.lhs;
205 i -= 1;
206
207 switch (self.op) {
208 InfixOp.EqualEqual => {},
209 InfixOp.BangEqual => {},
210 }
211
212 if (i < 1) return self.rhs;
213 i -= 1;
209214
210215 return null;
211216 }
212217};
213218
214pub const NodeReturn = struct {
219pub const NodePrefixOp = struct {
215220 base: Node,
216 return_token: Token,
217 expr: &Node,
221 op_token: Token,
222 op: PrefixOp,
223 rhs: &Node,
218224
219 pub fn iterate(self: &NodeReturn, index: usize) -> ?&Node {
225 const PrefixOp = union(enum) {
226 Return,
227 AddrOf: AddrOfInfo,
228 };
229 const AddrOfInfo = struct {
230 align_expr: ?&Node,
231 bit_offset_start_token: ?Token,
232 bit_offset_end_token: ?Token,
233 const_token: ?Token,
234 volatile_token: ?Token,
235 };
236
237 pub fn iterate(self: &NodePrefixOp, index: usize) -> ?&Node {
220238 var i = index;
221239
222 if (i < 1) return self.expr;
240 switch (self.op) {
241 PrefixOp.Return => {},
242 PrefixOp.AddrOf => |addr_of_info| {
243 if (addr_of_info.align_expr) |align_expr| {
244 if (i < 1) return align_expr;
245 i -= 1;
246 }
247 },
248 }
249
250 if (i < 1) return self.rhs;
223251 i -= 1;
224252
225253 return null;
src-self-hosted/parser.zig+178-106
......@@ -68,7 +68,12 @@ pub const Parser = struct {
6868 TopLevelExtern: ?Token,
6969 TopLevelDecl: TopLevelDeclCtx,
7070 Expression: DestPtr,
71 AddrOfModifiers: &ast.NodeAddrOfExpr,
71 ExpectOperand,
72 Operand: &ast.Node,
73 AfterOperand,
74 InfixOp: &ast.NodeInfixOp,
75 PrefixOp: &ast.NodePrefixOp,
76 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
7277 TypeExpr: DestPtr,
7378 VarDecl: &ast.NodeVarDecl,
7479 VarDeclAlign: &ast.NodeVarDecl,
......@@ -265,63 +270,140 @@ pub const Parser = struct {
265270 _ = %return self.eatToken(token_id);
266271 continue;
267272 },
273
268274 State.Expression => |dest_ptr| {
275 // save the dest_ptr for later
276 stack.append(state) %% unreachable;
277 %return stack.append(State.ExpectOperand);
278 continue;
279 },
280 State.ExpectOperand => {
281 // we'll either get an operand (like 1 or x),
282 // or a prefix operator (like ~ or return).
269283 const token = self.getNextToken();
270284 switch (token.id) {
271285 Token.Id.Keyword_return => {
272 const return_node = %return self.createAttachReturn(dest_ptr, token);
273 stack.append(State {.Expression = DestPtr {.Field = &return_node.expr} }) %% unreachable;
286 %return stack.append(State { .PrefixOp = %return self.createPrefixOp(token,
287 ast.NodePrefixOp.PrefixOp.Return) });
288 %return stack.append(State.ExpectOperand);
289 continue;
290 },
291 Token.Id.Ampersand => {
292 const prefix_op = %return self.createPrefixOp(token, ast.NodePrefixOp.PrefixOp{
293 .AddrOf = ast.NodePrefixOp.AddrOfInfo {
294 .align_expr = null,
295 .bit_offset_start_token = null,
296 .bit_offset_end_token = null,
297 .const_token = null,
298 .volatile_token = null,
299 }
300 });
301 %return stack.append(State { .PrefixOp = prefix_op });
302 %return stack.append(State.ExpectOperand);
303 %return stack.append(State { .AddrOfModifiers = &prefix_op.op.AddrOf });
274304 continue;
275305 },
276306 Token.Id.Identifier => {
277 _ = %return self.createAttachIdentifier(dest_ptr, token);
307 %return stack.append(State {
308 .Operand = &(%return self.createIdentifier(token)).base
309 });
310 %return stack.append(State.AfterOperand);
278311 continue;
279312 },
280313 Token.Id.IntegerLiteral => {
281 _ = %return self.createAttachIntegerLiteral(dest_ptr, token);
314 %return stack.append(State {
315 .Operand = &(%return self.createIntegerLiteral(token)).base
316 });
317 %return stack.append(State.AfterOperand);
282318 continue;
283319 },
284320 Token.Id.FloatLiteral => {
285 _ = %return self.createAttachFloatLiteral(dest_ptr, token);
321 %return stack.append(State {
322 .Operand = &(%return self.createFloatLiteral(token)).base
323 });
324 %return stack.append(State.AfterOperand);
286325 continue;
287326 },
288 Token.Id.Ampersand => {
289 const addr_of_expr = %return self.createAttachAddrOfExpr(dest_ptr, token);
290 stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable;
327 else => return self.parseError(token, "expected primary expression, found {}", @tagName(token.id)),
328 }
329 },
330
331 State.AfterOperand => {
332 // we'll either get an infix operator (like != or ^),
333 // or a postfix operator (like () or {}),
334 // otherwise this expression is done (like on a ; or else).
335 var token = self.getNextToken();
336 switch (token.id) {
337 Token.Id.EqualEqual => {
338 %return stack.append(State {
339 .InfixOp = %return self.createInfixOp(token, ast.NodeInfixOp.InfixOp.EqualEqual)
340 });
341 %return stack.append(State.ExpectOperand);
342 continue;
343 },
344 Token.Id.BangEqual => {
345 %return stack.append(State {
346 .InfixOp = %return self.createInfixOp(token, ast.NodeInfixOp.InfixOp.BangEqual)
347 });
348 %return stack.append(State.ExpectOperand);
349 continue;
350 },
351 else => {
352 // no postfix/infix operator after this operand.
353 self.putBackToken(token);
354 // reduce the stack
355 var expression: &ast.Node = stack.pop().Operand;
356 while (true) {
357 switch (stack.pop()) {
358 State.Expression => |dest_ptr| {
359 // we're done
360 %return dest_ptr.store(expression);
361 break;
362 },
363 State.InfixOp => |infix_op| {
364 infix_op.rhs = expression;
365 infix_op.lhs = stack.pop().Operand;
366 expression = &infix_op.base;
367 continue;
368 },
369 State.PrefixOp => |prefix_op| {
370 prefix_op.rhs = expression;
371 expression = &prefix_op.base;
372 continue;
373 },
374 else => unreachable,
375 }
376 }
291377 continue;
292378 },
293 else => return self.parseError(token, "expected primary expression, found {}", @tagName(token.id)),
294379 }
295380 },
296381
297 State.AddrOfModifiers => |addr_of_expr| {
382 State.AddrOfModifiers => |addr_of_info| {
298383 var token = self.getNextToken();
299384 switch (token.id) {
300385 Token.Id.Keyword_align => {
301 stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable;
302 if (addr_of_expr.align_expr != null) return self.parseError(token, "multiple align qualifiers");
386 stack.append(state) %% unreachable;
387 if (addr_of_info.align_expr != null) return self.parseError(token, "multiple align qualifiers");
303388 _ = %return self.eatToken(Token.Id.LParen);
304389 %return stack.append(State { .ExpectToken = Token.Id.RParen });
305 %return stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_expr.align_expr} });
390 %return stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} });
306391 continue;
307392 },
308393 Token.Id.Keyword_const => {
309 if (addr_of_expr.const_token != null) return self.parseError(token, "duplicate qualifier: const");
310 addr_of_expr.const_token = token;
311 stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable;
394 stack.append(state) %% unreachable;
395 if (addr_of_info.const_token != null) return self.parseError(token, "duplicate qualifier: const");
396 addr_of_info.const_token = token;
312397 continue;
313398 },
314399 Token.Id.Keyword_volatile => {
315 if (addr_of_expr.volatile_token != null) return self.parseError(token, "duplicate qualifier: volatile");
316 addr_of_expr.volatile_token = token;
317 stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable;
400 stack.append(state) %% unreachable;
401 if (addr_of_info.volatile_token != null) return self.parseError(token, "duplicate qualifier: volatile");
402 addr_of_info.volatile_token = token;
318403 continue;
319404 },
320405 else => {
321406 self.putBackToken(token);
322 stack.append(State {
323 .Expression = DestPtr { .Field = &addr_of_expr.op_expr},
324 }) %% unreachable;
325407 continue;
326408 },
327409 }
......@@ -482,8 +564,14 @@ pub const Parser = struct {
482564 %return stack.append(State { .Expression = DestPtr{.List = &block.statements} });
483565 continue;
484566 },
567
568 // These are data, not control flow.
569 State.InfixOp => unreachable,
570 State.PrefixOp => unreachable,
571 State.Operand => unreachable,
485572 }
486 unreachable;
573 @import("std").debug.panic("{}", @tagName(state));
574 //unreachable;
487575 }
488576 }
489577
......@@ -560,23 +648,6 @@ pub const Parser = struct {
560648 return node;
561649 }
562650
563 fn createAddrOfExpr(self: &Parser, op_token: &const Token) -> %&ast.NodeAddrOfExpr {
564 const node = %return self.allocator.create(ast.NodeAddrOfExpr);
565 %defer self.allocator.destroy(node);
566
567 *node = ast.NodeAddrOfExpr {
568 .base = ast.Node {.id = ast.Node.Id.AddrOfExpr},
569 .align_expr = null,
570 .op_token = *op_token,
571 .bit_offset_start_token = null,
572 .bit_offset_end_token = null,
573 .const_token = null,
574 .volatile_token = null,
575 .op_expr = undefined,
576 };
577 return node;
578 }
579
580651 fn createBlock(self: &Parser, begin_token: &const Token) -> %&ast.NodeBlock {
581652 const node = %return self.allocator.create(ast.NodeBlock);
582653 %defer self.allocator.destroy(node);
......@@ -590,14 +661,29 @@ pub const Parser = struct {
590661 return node;
591662 }
592663
593 fn createReturn(self: &Parser, return_token: &const Token) -> %&ast.NodeReturn {
594 const node = %return self.allocator.create(ast.NodeReturn);
664 fn createInfixOp(self: &Parser, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) -> %&ast.NodeInfixOp {
665 const node = %return self.allocator.create(ast.NodeInfixOp);
666 %defer self.allocator.destroy(node);
667
668 *node = ast.NodeInfixOp {
669 .base = ast.Node {.id = ast.Node.Id.InfixOp},
670 .op_token = *op_token,
671 .lhs = undefined,
672 .op = *op,
673 .rhs = undefined,
674 };
675 return node;
676 }
677
678 fn createPrefixOp(self: &Parser, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) -> %&ast.NodePrefixOp {
679 const node = %return self.allocator.create(ast.NodePrefixOp);
595680 %defer self.allocator.destroy(node);
596681
597 *node = ast.NodeReturn {
598 .base = ast.Node {.id = ast.Node.Id.Return},
599 .return_token = *return_token,
600 .expr = undefined,
682 *node = ast.NodePrefixOp {
683 .base = ast.Node {.id = ast.Node.Id.PrefixOp},
684 .op_token = *op_token,
685 .op = *op,
686 .rhs = undefined,
601687 };
602688 return node;
603689 }
......@@ -635,20 +721,6 @@ pub const Parser = struct {
635721 return node;
636722 }
637723
638 fn createAttachFloatLiteral(self: &Parser, dest_ptr: &const DestPtr, token: &const Token) -> %&ast.NodeFloatLiteral {
639 const node = %return self.createFloatLiteral(token);
640 %defer self.allocator.destroy(node);
641 %return dest_ptr.store(&node.base);
642 return node;
643 }
644
645 fn createAttachIntegerLiteral(self: &Parser, dest_ptr: &const DestPtr, token: &const Token) -> %&ast.NodeIntegerLiteral {
646 const node = %return self.createIntegerLiteral(token);
647 %defer self.allocator.destroy(node);
648 %return dest_ptr.store(&node.base);
649 return node;
650 }
651
652724 fn createAttachIdentifier(self: &Parser, dest_ptr: &const DestPtr, name_token: &const Token) -> %&ast.NodeIdentifier {
653725 const node = %return self.createIdentifier(name_token);
654726 %defer self.allocator.destroy(node);
......@@ -656,20 +728,6 @@ pub const Parser = struct {
656728 return node;
657729 }
658730
659 fn createAttachReturn(self: &Parser, dest_ptr: &const DestPtr, return_token: &const Token) -> %&ast.NodeReturn {
660 const node = %return self.createReturn(return_token);
661 %defer self.allocator.destroy(node);
662 %return dest_ptr.store(&node.base);
663 return node;
664 }
665
666 fn createAttachAddrOfExpr(self: &Parser, dest_ptr: &const DestPtr, op_token: &const Token) -> %&ast.NodeAddrOfExpr {
667 const node = %return self.createAddrOfExpr(op_token);
668 %defer self.allocator.destroy(node);
669 %return dest_ptr.store(&node.base);
670 return node;
671 }
672
673731 fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) -> %&ast.NodeParamDecl {
674732 const node = %return self.createParamDecl();
675733 %defer self.allocator.destroy(node);
......@@ -783,7 +841,6 @@ pub const Parser = struct {
783841 ParamDecl: &ast.Node,
784842 Text: []const u8,
785843 Expression: &ast.Node,
786 AddrOfExprBit: &ast.NodeAddrOfExpr,
787844 VarDecl: &ast.NodeVarDecl,
788845 Statement: &ast.Node,
789846 PrintIndent,
......@@ -912,17 +969,6 @@ pub const Parser = struct {
912969 const identifier = @fieldParentPtr(ast.NodeIdentifier, "base", base);
913970 %return stream.print("{}", self.tokenizer.getTokenSlice(identifier.name_token));
914971 },
915 ast.Node.Id.AddrOfExpr => {
916 const addr_of_expr = @fieldParentPtr(ast.NodeAddrOfExpr, "base", base);
917 %return stream.print("{}", self.tokenizer.getTokenSlice(addr_of_expr.op_token));
918 %return stack.append(RenderState { .AddrOfExprBit = addr_of_expr});
919
920 if (addr_of_expr.align_expr) |align_expr| {
921 %return stream.print("align(");
922 %return stack.append(RenderState { .Text = ") "});
923 %return stack.append(RenderState { .Expression = align_expr});
924 }
925 },
926972 ast.Node.Id.Block => {
927973 const block = @fieldParentPtr(ast.NodeBlock, "base", base);
928974 %return stream.write("{");
......@@ -940,10 +986,43 @@ pub const Parser = struct {
940986 %return stack.append(RenderState { .Text = "\n" });
941987 }
942988 },
943 ast.Node.Id.Return => {
944 const return_node = @fieldParentPtr(ast.NodeReturn, "base", base);
945 %return stream.write("return ");
946 %return stack.append(RenderState { .Expression = return_node.expr });
989 ast.Node.Id.InfixOp => {
990 const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base);
991 %return stack.append(RenderState { .Expression = prefix_op_node.rhs });
992 switch (prefix_op_node.op) {
993 ast.NodeInfixOp.InfixOp.EqualEqual => {
994 %return stack.append(RenderState { .Text = " == "});
995 },
996 ast.NodeInfixOp.InfixOp.BangEqual => {
997 %return stack.append(RenderState { .Text = " != "});
998 },
999 else => unreachable,
1000 }
1001 %return stack.append(RenderState { .Expression = prefix_op_node.lhs });
1002 },
1003 ast.Node.Id.PrefixOp => {
1004 const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base);
1005 %return stack.append(RenderState { .Expression = prefix_op_node.rhs });
1006 switch (prefix_op_node.op) {
1007 ast.NodePrefixOp.PrefixOp.Return => {
1008 %return stream.write("return ");
1009 },
1010 ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| {
1011 %return stream.write("&");
1012 if (addr_of_info.volatile_token != null) {
1013 %return stack.append(RenderState { .Text = "volatile "});
1014 }
1015 if (addr_of_info.const_token != null) {
1016 %return stack.append(RenderState { .Text = "const "});
1017 }
1018 if (addr_of_info.align_expr) |align_expr| {
1019 %return stream.print("align(");
1020 %return stack.append(RenderState { .Text = ") "});
1021 %return stack.append(RenderState { .Expression = align_expr});
1022 }
1023 },
1024 else => unreachable,
1025 }
9471026 },
9481027 ast.Node.Id.IntegerLiteral => {
9491028 const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base);
......@@ -955,21 +1034,6 @@ pub const Parser = struct {
9551034 },
9561035 else => unreachable,
9571036 },
958 RenderState.AddrOfExprBit => |addr_of_expr| {
959 if (addr_of_expr.bit_offset_start_token) |bit_offset_start_token| {
960 %return stream.print("{} ", self.tokenizer.getTokenSlice(bit_offset_start_token));
961 }
962 if (addr_of_expr.bit_offset_end_token) |bit_offset_end_token| {
963 %return stream.print("{} ", self.tokenizer.getTokenSlice(bit_offset_end_token));
964 }
965 if (addr_of_expr.const_token) |const_token| {
966 %return stream.print("{} ", self.tokenizer.getTokenSlice(const_token));
967 }
968 if (addr_of_expr.volatile_token) |volatile_token| {
969 %return stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token));
970 }
971 %return stack.append(RenderState { .Expression = addr_of_expr.op_expr});
972 },
9731037 RenderState.FnProtoRParen => |fn_proto| {
9741038 %return stream.print(")");
9751039 if (fn_proto.align_expr != null) {
......@@ -1128,4 +1192,12 @@ test "zig fmt" {
11281192 \\extern fn f3(s: &align(1) const volatile u8) -> c_int;
11291193 \\
11301194 );
1195
1196 testCanonical(
1197 \\fn f1(a: bool, b: bool) -> bool {
1198 \\ a != b;
1199 \\ return a == b;
1200 \\}
1201 \\
1202 );
11311203}
src-self-hosted/tokenizer.zig+33-3
......@@ -71,7 +71,10 @@ pub const Token = struct {
7171 StringLiteral: StrLitKind,
7272 Eof,
7373 Builtin,
74 Bang,
7475 Equal,
76 EqualEqual,
77 BangEqual,
7578 LParen,
7679 RParen,
7780 Semicolon,
......@@ -187,6 +190,8 @@ pub const Tokenizer = struct {
187190 C,
188191 StringLiteral,
189192 StringLiteralBackslash,
193 Equal,
194 Bang,
190195 Minus,
191196 Slash,
192197 LineComment,
......@@ -232,9 +237,10 @@ pub const Tokenizer = struct {
232237 result.id = Token.Id.Builtin;
233238 },
234239 '=' => {
235 result.id = Token.Id.Equal;
236 self.index += 1;
237 break;
240 state = State.Equal;
241 },
242 '!' => {
243 state = State.Bang;
238244 },
239245 '(' => {
240246 result.id = Token.Id.LParen;
......@@ -356,6 +362,30 @@ pub const Tokenizer = struct {
356362 },
357363 },
358364
365 State.Bang => switch (c) {
366 '=' => {
367 result.id = Token.Id.BangEqual;
368 self.index += 1;
369 break;
370 },
371 else => {
372 result.id = Token.Id.Bang;
373 break;
374 },
375 },
376
377 State.Equal => switch (c) {
378 '=' => {
379 result.id = Token.Id.EqualEqual;
380 self.index += 1;
381 break;
382 },
383 else => {
384 result.id = Token.Id.Equal;
385 break;
386 },
387 },
388
359389 State.Minus => switch (c) {
360390 '>' => {
361391 result.id = Token.Id.Arrow;