lib/chant/src/parse/declaration.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 const ast = @import("../ast/root.zig");
 3 const auto_mod = @import("auto.zig");
 4 const constexpr = @import("constexpr.zig");
 5 const ctype = @import("type/root.zig");
 6 const expression = @import("expression.zig");
 7 const initializer_mod = @import("initializer.zig");
 8 const state = @import("state/root.zig");
 9 const thread = @import("thread.zig");
10 const cursor = state.cursor;
11 const diagnostic = state.diagnostic;
12 const object = state.object;
13 const typedef = state.typedef;
14 const Error = @import("error.zig").Error;
15 
16 const Parser = state.Parser;
17 
18 pub fn parseLocal(parser: *Parser) Error![]ast.Variable {
19     const specifiers = try ctype.parseSpecifiers(parser);
20     var variables = std.ArrayListUnmanaged(ast.Variable).empty;
21     if (cursor.consume(parser, .semicolon)) {
22         return variables.toOwnedSlice(parser.arena);
23     }
24     if (specifiers.requires_standalone_declaration) {
25         return diagnostic.fail(parser, error.UnsupportedConstruct, "fixed enum forward declaration must be standalone");
26     }
27     while (true) {
28         try ctype.skipAttributes(parser);
29         const declarator = try ctype.parseDeclarator(parser, specifiers.type, expression.parseAssignment);
30         try ctype.skipAttributes(parser);
31         const name = declarator.name orelse return diagnostic.fail(parser, error.ExpectedIdentifier, "declaration requires a name");
32         if (specifiers.storage == .typedef_storage) {
33             try thread.validateTypedef(parser, specifiers.is_thread_local);
34             if (specifiers.is_constexpr) {
35                 return diagnostic.fail(parser, error.UnsupportedConstruct, "typedef cannot be constexpr");
36             }
37             if (auto_mod.contains(declarator.type)) {
38                 return diagnostic.fail(parser, error.ExpectedType, "typedef cannot infer auto");
39             }
40             try typedef.register(parser, name, declarator.type);
41         } else {
42             var initializer: ?*ast.Expr = null;
43             if (cursor.consume(parser, .assign)) {
44                 initializer = try initializer_mod.parse(parser, declarator.type);
45             }
46             const completed_type = try initializer_mod.completeType(parser, declarator.type, initializer);
47             const variable_type = try auto_mod.resolve(parser, completed_type, initializer);
48             const constant_value = if (specifiers.is_constexpr)
49                 try constexpr.validateObject(parser, variable_type, initializer)
50             else
51                 null;
52             try thread.validateObject(parser, .block, specifiers.storage, variable_type, initializer, specifiers.is_thread_local);
53             try variables.append(parser.arena, .{
54                 .name = name,
55                 .type = variable_type,
56                 .storage = specifiers.storage,
57                 .alignment = specifiers.alignment,
58                 .is_constexpr = specifiers.is_constexpr,
59                 .is_thread_local = specifiers.is_thread_local,
60                 .initializer = initializer,
61             });
62             if (specifiers.is_constexpr) {
63                 try constexpr.registerObject(parser, name, variable_type, constant_value);
64             } else {
65                 try object.register(parser, name, variable_type);
66             }
67         }
68         if (cursor.consume(parser, .comma)) continue;
69         _ = try cursor.expect(parser, .semicolon);
70         break;
71     }
72     return variables.toOwnedSlice(parser.arena);
73 }