lib/chant/src/parse/statement.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const ast = @import("../ast/root.zig");
3 const assertion = @import("assert.zig");
4 const ctype = @import("type/root.zig");
5 const declaration = @import("declaration.zig");
6 const expression = @import("expression.zig");
7 const state = @import("state/root.zig");
8 const cursor = state.cursor;
9 const diagnostic = state.diagnostic;
10 const memory = state.memory;
11 const object = state.object;
12 const start = state.start;
13 const Error = @import("error.zig").Error;
14
15 const Parser = state.Parser;
16
17 pub fn parseStatement(parser: *Parser) Error!*ast.Stmt {
18 if (isLabel(parser)) return parseLabel(parser);
19 switch (cursor.peek(parser).kind) {
20 .lbrace => return parseCompound(parser),
21 .semicolon => {
22 _ = cursor.advance(parser);
23 return memory.create(parser, ast.Stmt, .empty);
24 },
25 .kw_if => return parseIf(parser),
26 .kw_for => return parseFor(parser),
27 .kw_while => return parseWhile(parser),
28 .kw_do => return parseDo(parser),
29 .kw_return => {
30 _ = cursor.advance(parser);
31 var value: ?*ast.Expr = null;
32 if (cursor.peek(parser).kind != .semicolon) {
33 value = try expression.parseExpression(parser);
34 }
35 _ = try cursor.expect(parser, .semicolon);
36 return memory.create(parser, ast.Stmt, .{ .return_stmt = value });
37 },
38 .kw_break => {
39 _ = cursor.advance(parser);
40 _ = try cursor.expect(parser, .semicolon);
41 return memory.create(parser, ast.Stmt, .break_stmt);
42 },
43 .kw_continue => {
44 _ = cursor.advance(parser);
45 _ = try cursor.expect(parser, .semicolon);
46 return memory.create(parser, ast.Stmt, .continue_stmt);
47 },
48 else => {
49 const value = try expression.parseExpression(parser);
50 _ = try cursor.expect(parser, .semicolon);
51 return memory.create(parser, ast.Stmt, .{ .expression = value });
52 },
53 }
54 }
55
56 pub fn parseCompound(parser: *Parser) Error!*ast.Stmt {
57 _ = try cursor.expect(parser, .lbrace);
58 try object.push(parser);
59 defer object.pop(parser);
60 var items = std.ArrayListUnmanaged(*ast.Stmt).empty;
61 while (cursor.peek(parser).kind != .rbrace) {
62 if (cursor.peek(parser).kind == .eof) {
63 return diagnostic.fail(parser, error.UnexpectedToken, "unterminated block");
64 }
65 try items.append(parser.arena, try parseBlockItem(parser));
66 }
67 _ = try cursor.expect(parser, .rbrace);
68 const stmt = try memory.create(parser, ast.Stmt, .{ .compound = try items.toOwnedSlice(parser.arena) });
69 return stmt;
70 }
71
72 fn parseBlockItem(parser: *Parser) Error!*ast.Stmt {
73 if (isLabel(parser)) return parseLabel(parser);
74 if (try assertion.consume(parser)) {
75 return memory.create(parser, ast.Stmt, .empty);
76 }
77 if (try ctype.consumeAttributeDeclaration(parser)) {
78 return memory.create(parser, ast.Stmt, .empty);
79 }
80 if (start.declaration(parser)) {
81 const variables = try declaration.parseLocal(parser);
82 return memory.create(parser, ast.Stmt, .{ .declaration = variables });
83 }
84 return parseStatement(parser);
85 }
86
87 fn isLabel(parser: *const Parser) bool {
88 return cursor.peek(parser).kind == .identifier and cursor.ahead(parser, 1).kind == .colon;
89 }
90
91 fn parseLabel(parser: *Parser) Error!*ast.Stmt {
92 const name = (try cursor.expect(parser, .identifier)).text;
93 _ = try cursor.expect(parser, .colon);
94 const body = if (cursor.peek(parser).kind == .rbrace)
95 try memory.create(parser, ast.Stmt, .empty)
96 else
97 try parseBlockItem(parser);
98 return memory.create(parser, ast.Stmt, .{ .label = .{ .name = name, .body = body } });
99 }
100
101 fn parseIf(parser: *Parser) Error!*ast.Stmt {
102 _ = try cursor.expect(parser, .kw_if);
103 _ = try cursor.expect(parser, .lparen);
104 const condition = try expression.parseExpression(parser);
105 _ = try cursor.expect(parser, .rparen);
106 const then_body = try parseStatement(parser);
107 var else_body: ?*ast.Stmt = null;
108 if (cursor.consume(parser, .kw_else)) {
109 else_body = try parseStatement(parser);
110 }
111 return memory.create(parser, ast.Stmt, .{ .if_stmt = .{
112 .condition = condition,
113 .then_body = then_body,
114 .else_body = else_body,
115 } });
116 }
117
118 fn parseFor(parser: *Parser) Error!*ast.Stmt {
119 _ = try cursor.expect(parser, .kw_for);
120 _ = try cursor.expect(parser, .lparen);
121
122 var init_stmt: ?*ast.Stmt = null;
123 if (!cursor.consume(parser, .semicolon)) {
124 if (start.declaration(parser)) {
125 const variables = try declaration.parseLocal(parser);
126 init_stmt = try memory.create(parser, ast.Stmt, .{ .declaration = variables });
127 } else {
128 const value = try expression.parseExpression(parser);
129 _ = try cursor.expect(parser, .semicolon);
130 init_stmt = try memory.create(parser, ast.Stmt, .{ .expression = value });
131 }
132 }
133
134 var condition: ?*ast.Expr = null;
135 if (cursor.peek(parser).kind != .semicolon) {
136 condition = try expression.parseExpression(parser);
137 }
138 _ = try cursor.expect(parser, .semicolon);
139
140 var step: ?*ast.Expr = null;
141 if (cursor.peek(parser).kind != .rparen) {
142 step = try expression.parseExpression(parser);
143 }
144 _ = try cursor.expect(parser, .rparen);
145
146 const body = try parseStatement(parser);
147 return memory.create(parser, ast.Stmt, .{ .for_stmt = .{
148 .init = init_stmt,
149 .condition = condition,
150 .step = step,
151 .body = body,
152 } });
153 }
154
155 fn parseWhile(parser: *Parser) Error!*ast.Stmt {
156 _ = try cursor.expect(parser, .kw_while);
157 _ = try cursor.expect(parser, .lparen);
158 const condition = try expression.parseExpression(parser);
159 _ = try cursor.expect(parser, .rparen);
160 const body = try parseStatement(parser);
161 return memory.create(parser, ast.Stmt, .{ .while_stmt = .{ .condition = condition, .body = body } });
162 }
163
164 fn parseDo(parser: *Parser) Error!*ast.Stmt {
165 _ = try cursor.expect(parser, .kw_do);
166 const body = try parseStatement(parser);
167 _ = try cursor.expect(parser, .kw_while);
168 _ = try cursor.expect(parser, .lparen);
169 const condition = try expression.parseExpression(parser);
170 _ = try cursor.expect(parser, .rparen);
171 _ = try cursor.expect(parser, .semicolon);
172 return memory.create(parser, ast.Stmt, .{ .do_stmt = .{ .condition = condition, .body = body } });
173 }
174
175 test "for statements carry declaration initializers" {
176 const lexer = @import("../lexer/root.zig");
177 var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);
178 defer arena_state.deinit();
179 const arena = arena_state.allocator();
180
181 const source = "for (int i = 0; i < n; i++) x += i;";
182 const token_survey = try lexer.survey(source, "loop.c");
183 const capacity = try lexer.Capacity.derive(token_survey.limits);
184 const bytes = try arena.alignedAlloc(
185 u8,
186 .fromByteUnits(lexer.Storage.storage_alignment),
187 capacity.storage_bytes,
188 );
189 var storage = try lexer.Storage.init(bytes, token_survey.limits);
190 storage.activate();
191 defer _ = storage.deinit();
192 const tokens = try storage.fill(token_survey, source, "loop.c");
193 var parser = try @import("state/test.zig").initParser(arena, tokens);
194 const stmt = try parseStatement(&parser);
195 const loop = stmt.for_stmt;
196 try std.testing.expect(loop.init.?.* == .declaration);
197 try std.testing.expectEqualStrings("i", loop.init.?.declaration[0].name);
198 try std.testing.expect(loop.condition != null);
199 try std.testing.expect(loop.step != null);
200 try std.testing.expect(loop.body.* == .expression);
201 }