Skip to content

Commit ab44939

Browse files
committedDec 17, 2017
roughly parsing infix operators
·
0.15.20.2.0
1 parent 39e96d9 commit ab44939

File tree

3 files changed

+274
-144
lines changed

3 files changed

+274
-144
lines changed
 

‎src-self-hosted/ast.zig‎

Lines changed: 63 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -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

173-
pub const NodeAddrOfExpr = struct {
173+
pub 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

198-
pub const NodeBlock = struct {
189+
pub 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

214-
pub const NodeReturn = struct {
219+
pub 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‎

Lines changed: 178 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -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,41 +721,13 @@ 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);
655727
%return dest_ptr.store(&node.base);
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‎

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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;

0 commit comments

Comments
 (0)
Please sign in to comment.