tiny.chant.parse.initializer
Defined in parse.
API (2)
Actions
Public operations.
Source
Source: lib/chant/src/parse/initializer.zig
zig
const std = @import("std");const ast = @import("../ast/root.zig");const expression = @import("expression.zig");const state = @import("state/root.zig");const cursor = state.cursor;const diagnostic = state.diagnostic;const memory = state.memory;const Error = @import("error.zig").Error;const Parser = state.Parser;pub fn parse(parser: *Parser, c_type: *const ast.Type) Error!*ast.Expr { if (cursor.consume(parser, .lbrace)) { var items = std.ArrayListUnmanaged(ast.expr.InitializerItem).empty; if (!cursor.consume(parser, .rbrace)) { while (true) { const path = try parseDesignator(parser); const value_type = if (path.len == 0) ast.types.element(c_type) orelse c_type else blk: { _ = try cursor.expect(parser, .assign); break :blk try designatorType(parser, c_type, path); }; try items.append(parser.arena, .{ .designator = path, .value = try parse(parser, value_type) }); if (cursor.consume(parser, .comma)) { if (cursor.consume(parser, .rbrace)) break; continue; } _ = try cursor.expect(parser, .rbrace); break; } } const slice = try items.toOwnedSlice(parser.arena); if (ast.types.isArithmetic(c_type)) { if (slice.len == 0) { return memory.create(parser, ast.Expr, .{ .integer_literal = .{ .value = 0, .type = &ast.types.int_type } }); } if (slice.len == 1 and slice[0].designator.len == 0) return slice[0].value; return diagnostic.fail(parser, error.UnsupportedConstruct, "scalar initializer list has too many values"); } return memory.create(parser, ast.Expr, .{ .initializer_list = .{ .type = c_type, .items = slice } }); } return expression.parseAssignment(parser);}pub fn completeType(parser: *Parser, declared: *const ast.Type, initializer: ?*ast.Expr) Error!*const ast.Type { const value = initializer orelse return declared; const resolved = try completeArrayType(parser, declared, value); if (value.* == .initializer_list) value.initializer_list.type = resolved; return resolved;}fn parseDesignator(parser: *Parser) Error![]const u64 { var designator = std.ArrayListUnmanaged(u64).empty; while (true) { if (cursor.consume(parser, .lbracket)) { const index_expr = try expression.parseAssignment(parser); const index_value = expression.evaluateIntegerConstant(parser, index_expr) orelse return diagnostic.fail(parser, error.InvalidConstant, "array designator is not an integer constant"); const index = std.math.cast(u64, index_value) orelse return diagnostic.fail(parser, error.InvalidConstant, "array designator is negative"); try designator.append(parser.arena, index); _ = try cursor.expect(parser, .rbracket); continue; } if (cursor.consume(parser, .dot)) { return diagnostic.fail(parser, error.UnsupportedConstruct, "struct initializer designators are not supported"); } break; } return designator.toOwnedSlice(parser.arena);}fn designatorType(parser: *Parser, c_type: *const ast.Type, path: []const u64) Error!*const ast.Type { var current = c_type; for (path) |index| { if (current.kind != .array) { return diagnostic.fail(parser, error.UnsupportedConstruct, "array designator does not name an array element"); } if (current.array_len) |len| { if (index >= len) return diagnostic.fail(parser, error.InvalidConstant, "array designator exceeds array bound"); } current = current.child orelse return diagnostic.fail(parser, error.UnsupportedConstruct, "array designator names an incomplete element"); } return current;}fn completeArrayType(parser: *Parser, declared: *const ast.Type, initializer: *ast.Expr) Error!*const ast.Type { if (declared.kind != .array or declared.array_len != null) return declared; const len = try inferArrayLength(parser, declared, initializer); const type_origin = parser.nodes.typeOrigin(declared) orelse unreachable; const resolved = try memory.createType( parser, declared.*, memory.derivedType(type_origin, true), ); resolved.array_len = len; return resolved;}fn inferArrayLength(parser: *Parser, declared: *const ast.Type, initializer: *ast.Expr) Error!u64 { const child = declared.child orelse return diagnostic.fail(parser, error.UnsupportedConstruct, "array initializer has no element type"); switch (initializer.*) { .string_literal => |literal| { if (!isCharType(child)) return diagnostic.fail(parser, error.UnsupportedConstruct, "string initializer requires a character array"); return std.math.add(u64, literal.text.len, 1) catch return diagnostic.fail(parser, error.InvalidConstant, "string initializer is too large"); }, .initializer_list => |list| { const child_count = try staticElementCount(parser, child); var next_scalar: u64 = 0; var max_len: u64 = 0; for (list.items) |item| { if (item.designator.len == 0) { const consumed = try initializerScalarCount(parser, child, item.value); next_scalar = std.math.add(u64, next_scalar, consumed) catch return diagnostic.fail(parser, error.InvalidConstant, "array initializer is too large"); } else { const target = try designatorType(parser, declared, item.designator); const offset = try designatorOffset(parser, declared, item.designator); const consumed = try initializerScalarCount(parser, target, item.value); next_scalar = std.math.add(u64, offset, consumed) catch return diagnostic.fail(parser, error.InvalidConstant, "array initializer is too large"); } const len = std.math.divCeil(u64, next_scalar, child_count) catch return diagnostic.fail(parser, error.InvalidConstant, "array initializer is too large"); max_len = @max(max_len, len); } if (max_len == 0) return diagnostic.fail(parser, error.UnsupportedConstruct, "incomplete array initializer has no size"); return max_len; }, else => return diagnostic.fail(parser, error.UnsupportedConstruct, "array initializer does not determine array size"), }}fn isCharType(c_type: *const ast.Type) bool { return c_type.kind == .char_type;}fn isCharArray(c_type: *const ast.Type) bool { if (c_type.kind != .array) return false; var current = c_type; while (current.kind == .array) { current = current.child orelse return false; } return isCharType(current);}fn initializerScalarCount(parser: *Parser, target: *const ast.Type, initializer: *ast.Expr) Error!u64 { switch (initializer.*) { .initializer_list => |list| return staticElementCount(parser, list.type), .string_literal => { if (!isCharArray(target)) return 1; return staticElementCount(parser, target); }, else => return 1, }}fn designatorOffset(parser: *Parser, c_type: *const ast.Type, path: []const u64) Error!u64 { var current = c_type; var offset: u64 = 0; for (path) |index| { if (current.kind != .array) return diagnostic.fail(parser, error.UnsupportedConstruct, "array designator does not name an array element"); if (current.array_len) |len| { if (index >= len) return diagnostic.fail(parser, error.InvalidConstant, "array designator exceeds array bound"); } const child = current.child orelse return diagnostic.fail(parser, error.UnsupportedConstruct, "array designator names an incomplete element"); const stride = try staticElementCount(parser, child); const scaled = std.math.mul(u64, index, stride) catch return diagnostic.fail(parser, error.InvalidConstant, "array designator is too large"); offset = std.math.add(u64, offset, scaled) catch return diagnostic.fail(parser, error.InvalidConstant, "array designator is too large"); current = child; } return offset;}fn staticElementCount(parser: *Parser, c_type: *const ast.Type) Error!u64 { if (c_type.kind != .array) return 1; const len = c_type.array_len orelse return diagnostic.fail(parser, error.UnsupportedConstruct, "nested incomplete array initializer is unsupported"); const child = c_type.child orelse return diagnostic.fail(parser, error.UnsupportedConstruct, "array initializer has no element type"); const child_count = try staticElementCount(parser, child); return std.math.mul(u64, len, child_count) catch return diagnostic.fail(parser, error.InvalidConstant, "array initializer is too large");}Source: lib/chant/src/parse/root.zig:12
zig
pub const initializer = @import("initializer.zig");Complete call list for parse.initializer.parse
7 direct calls.
tiny.chant.parse.expression.parseAssignment[function] atlib/chant/src/parse/expression.zig:21lib.chant.src.parse.initializer.designatorType[function] — private source atlib/chant/src/parse/initializer.zig:74in nearest public ownertiny.chant.parse.initializerlib.chant.src.parse.initializer.parseDesignator[function] — private source atlib/chant/src/parse/initializer.zig:53in nearest public ownertiny.chant.parse.initializertiny.chant.parse.state.cursor.consume[function] atlib/chant/src/parse/state/cursor.zig:26tiny.chant.parse.state.cursor.expect[function] atlib/chant/src/parse/state/cursor.zig:34tiny.chant.parse.state.diagnostic.fail[function] atlib/chant/src/parse/state/diagnostic.zig:9tiny.chant.parse.state.memory.create[function] atlib/chant/src/parse/state/memory.zig:8
Audit
| Definitions | 3 |
|---|---|
| Public names | 3 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |