tiny.chant.parse.expression
Defined in parse.
API (4)
Actions
Public operations.
Source
Source: lib/chant/src/parse/expression.zig
zig
const std = @import("std");const chant = @import("../root.zig");const ast = @import("../ast/root.zig");const ctype = @import("type/root.zig");const state = @import("state/root.zig");const cursor = state.cursor;const diagnostic = state.diagnostic;const memory = state.memory;const object = state.object;const start_mod = state.start;const Error = @import("error.zig").Error;const Parser = state.Parser;const token = chant.token;const Kind = token.Kind;pub fn parseExpression(parser: *Parser) Error!*ast.Expr { return parseAssignment(parser);}pub fn parseAssignment(parser: *Parser) Error!*ast.Expr { const target = try parseConditional(parser); const op: ?ast.expr.BinaryOp = switch (cursor.peek(parser).kind) { .assign => null, .plus_assign => .add, .minus_assign => .sub, .star_assign => .mul, .slash_assign => .div, .percent_assign => .rem, .amp_assign => .bit_and, .pipe_assign => .bit_or, .caret_assign => .bit_xor, .shl_assign => .shl, .shr_assign => .shr, else => return target, }; _ = cursor.advance(parser); const value = try parseAssignment(parser); return memory.create(parser, ast.Expr, .{ .assign = .{ .op = op, .target = target, .value = value } });}fn parseConditional(parser: *Parser) Error!*ast.Expr { const condition = try parseBinary(parser, 0); if (!cursor.consume(parser, .question)) return condition; const then_value = try parseExpression(parser); _ = try cursor.expect(parser, .colon); const else_value = try parseConditional(parser); return memory.create(parser, ast.Expr, .{ .conditional = .{ .condition = condition, .then_value = then_value, .else_value = else_value, } });}const Level = struct { kind: Kind, op: ast.expr.BinaryOp, precedence: u8,};const levels = [_]Level{ .{ .kind = .pipe_pipe, .op = .logical_or, .precedence = 1 }, .{ .kind = .amp_amp, .op = .logical_and, .precedence = 2 }, .{ .kind = .pipe, .op = .bit_or, .precedence = 3 }, .{ .kind = .caret, .op = .bit_xor, .precedence = 4 }, .{ .kind = .amp, .op = .bit_and, .precedence = 5 }, .{ .kind = .eq, .op = .eq, .precedence = 6 }, .{ .kind = .ne, .op = .ne, .precedence = 6 }, .{ .kind = .lt, .op = .lt, .precedence = 7 }, .{ .kind = .gt, .op = .gt, .precedence = 7 }, .{ .kind = .le, .op = .le, .precedence = 7 }, .{ .kind = .ge, .op = .ge, .precedence = 7 }, .{ .kind = .shl, .op = .shl, .precedence = 8 }, .{ .kind = .shr, .op = .shr, .precedence = 8 }, .{ .kind = .plus, .op = .add, .precedence = 9 }, .{ .kind = .minus, .op = .sub, .precedence = 9 }, .{ .kind = .star, .op = .mul, .precedence = 10 }, .{ .kind = .slash, .op = .div, .precedence = 10 }, .{ .kind = .percent, .op = .rem, .precedence = 10 },};fn binaryLevel(kind: Kind) ?Level { for (levels) |level| { if (level.kind == kind) return level; } return null;}fn parseBinary(parser: *Parser, min_precedence: u8) Error!*ast.Expr { var lhs = try parseUnary(parser); while (true) { const level = binaryLevel(cursor.peek(parser).kind) orelse break; if (level.precedence < min_precedence) break; _ = cursor.advance(parser); const rhs = try parseBinary(parser, level.precedence + 1); lhs = try memory.create(parser, ast.Expr, .{ .binary = .{ .op = level.op, .lhs = lhs, .rhs = rhs } }); } return lhs;}fn parseUnary(parser: *Parser) Error!*ast.Expr { switch (cursor.peek(parser).kind) { .plus => { _ = cursor.advance(parser); return parseUnary(parser); }, .minus => { _ = cursor.advance(parser); const operand = try parseUnary(parser); return memory.create(parser, ast.Expr, .{ .unary = .{ .op = .negate, .operand = operand } }); }, .bang => { _ = cursor.advance(parser); const operand = try parseUnary(parser); return memory.create(parser, ast.Expr, .{ .unary = .{ .op = .logical_not, .operand = operand } }); }, .tilde => { _ = cursor.advance(parser); const operand = try parseUnary(parser); return memory.create(parser, ast.Expr, .{ .unary = .{ .op = .bit_not, .operand = operand } }); }, .star => { _ = cursor.advance(parser); const operand = try parseUnary(parser); return memory.create(parser, ast.Expr, .{ .unary = .{ .op = .deref, .operand = operand } }); }, .amp => { const amp_index = parser.index; _ = cursor.advance(parser); const operand = try parseUnary(parser); return memory.createExprAt( parser, .{ .unary = .{ .op = .address_of, .operand = operand } }, amp_index, ); }, .plus_plus => { _ = cursor.advance(parser); return desugarIncrement(parser, try parseUnary(parser), .add); }, .minus_minus => { _ = cursor.advance(parser); return desugarIncrement(parser, try parseUnary(parser), .sub); }, .kw_sizeof => { _ = cursor.advance(parser); return parseSizeof(parser); }, .kw_alignof => { _ = cursor.advance(parser); return parseAlignof(parser); }, .lparen => { if (start_mod.typename(parser, 1)) { _ = cursor.advance(parser); const specifiers = try ctype.parseSpecifiers(parser); if (specifiers.requires_standalone_declaration) { return diagnostic.fail(parser, error.UnsupportedConstruct, "fixed enum forward declaration must be standalone"); } const declarator = try ctype.parseDeclarator(parser, specifiers.type, parseAssignment); if (declarator.name != null) { return diagnostic.fail(parser, error.UnexpectedToken, "cast names a declarator"); } _ = try cursor.expect(parser, .rparen); const operand = try parseUnary(parser); return memory.create(parser, ast.Expr, .{ .cast = .{ .target = declarator.type, .operand = operand } }); } return parsePostfixChain(parser, try parsePrimary(parser)); }, else => return parsePostfixChain(parser, try parsePrimary(parser)), }}fn desugarIncrement(parser: *Parser, target: *ast.Expr, op: ast.expr.BinaryOp) Error!*ast.Expr { const one = try memory.create(parser, ast.Expr, .{ .integer_literal = .{ .value = 1, .type = &ast.types.int_type } }); return memory.create(parser, ast.Expr, .{ .assign = .{ .op = op, .target = target, .value = one } });}fn integerConstantExpression(parser: *Parser, value: i128, c_type: *const ast.Type) Error!*ast.Expr { if (value >= 0) { const unsigned: u64 = std.math.cast(u64, value) orelse return diagnostic.fail(parser, error.InvalidConstant, "integer constant is too large"); return memory.create(parser, ast.Expr, .{ .integer_literal = .{ .value = unsigned, .type = c_type } }); } if (value == std.math.minInt(i128)) return diagnostic.fail(parser, error.InvalidConstant, "integer constant is too small"); const magnitude: u64 = std.math.cast(u64, -value) orelse return diagnostic.fail(parser, error.InvalidConstant, "integer constant is too small"); const operand = try memory.create(parser, ast.Expr, .{ .integer_literal = .{ .value = magnitude, .type = c_type } }); return memory.create(parser, ast.Expr, .{ .unary = .{ .op = .negate, .operand = operand } });}pub fn evaluateIntegerConstant(parser: *const Parser, expr: *ast.Expr) ?i128 { switch (expr.*) { .integer_literal => |literal| return @intCast(literal.value), .identifier => |identifier| return object.constantValue(parser, identifier.name), .float_literal, .string_literal, .call, .index, .initializer_list => return null, .unary => |unary| { const operand = evaluateIntegerConstant(parser, unary.operand) orelse return null; return switch (unary.op) { .negate => -operand, .logical_not => if (operand == 0) 1 else 0, .bit_not => ~operand, .address_of, .deref => null, }; }, .binary => |binary| { const lhs = evaluateIntegerConstant(parser, binary.lhs) orelse return null; const rhs = evaluateIntegerConstant(parser, binary.rhs) orelse return null; return switch (binary.op) { .add => lhs + rhs, .sub => lhs - rhs, .mul => lhs * rhs, .div => if (rhs == 0) null else @divTrunc(lhs, rhs), .rem => if (rhs == 0) null else @rem(lhs, rhs), .lt => if (lhs < rhs) 1 else 0, .gt => if (lhs > rhs) 1 else 0, .le => if (lhs <= rhs) 1 else 0, .ge => if (lhs >= rhs) 1 else 0, .eq => if (lhs == rhs) 1 else 0, .ne => if (lhs != rhs) 1 else 0, .logical_and => if (lhs != 0 and rhs != 0) 1 else 0, .logical_or => if (lhs != 0 or rhs != 0) 1 else 0, .bit_and => lhs & rhs, .bit_or => lhs | rhs, .bit_xor => lhs ^ rhs, .shl => if (rhs < 0 or rhs >= 128) null else lhs << @intCast(rhs), .shr => if (rhs < 0 or rhs >= 128) null else lhs >> @intCast(rhs), }; }, .assign => return null, .conditional => |conditional| { const condition = evaluateIntegerConstant(parser, conditional.condition) orelse return null; return evaluateIntegerConstant(parser, if (condition != 0) conditional.then_value else conditional.else_value); }, .cast => |cast| return evaluateIntegerConstant(parser, cast.operand), }}pub fn inferType(parser: *Parser, expr: *ast.Expr) Error!?*const ast.Type { switch (expr.*) { .integer_literal => |literal| return literal.type, .float_literal => |literal| return literal.type, .string_literal => return makePointerType( parser, expr, &ast.types.char_type, ), .identifier => |identifier| return state.object.lookup(parser, identifier.name), .call => |call| { const callee_type = state.object.lookup(parser, call.callee) orelse return null; if (callee_type.kind != .function) return null; return callee_type.child; }, .index => |index| { const base = try inferType(parser, index.base) orelse return null; return ast.types.element(base); }, .initializer_list => |list| return list.type, .unary => |unary| { const operand = try inferType(parser, unary.operand) orelse return null; return switch (unary.op) { .negate, .bit_not => if (ast.types.isArithmetic(operand)) operand else null, .logical_not => &ast.types.int_type, .address_of => makePointerType(parser, expr, operand), .deref => ast.types.element(operand), }; }, .binary => |binary| { const lhs = try inferType(parser, binary.lhs) orelse return null; const rhs = try inferType(parser, binary.rhs) orelse return null; return switch (binary.op) { .lt, .gt, .le, .ge, .eq, .ne, .logical_and, .logical_or => &ast.types.int_type, .shl, .shr => if (ast.types.isInteger(lhs) and ast.types.isInteger(rhs)) lhs else null, .add, .sub, .mul, .div, .rem, .bit_and, .bit_or, .bit_xor => if (ast.types.isArithmetic(lhs) and ast.types.isArithmetic(rhs)) ast.types.commonArithmetic(lhs, rhs) else null, }; }, .assign => |assign| return inferType(parser, assign.target), .conditional => |conditional| { const then_type = try inferType(parser, conditional.then_value) orelse return null; const else_type = try inferType(parser, conditional.else_value) orelse return null; if (ast.types.isArithmetic(then_type) and ast.types.isArithmetic(else_type)) { return ast.types.commonArithmetic(then_type, else_type); } if (then_type == else_type) return then_type; if (then_type.kind == .nullptr_type and ast.types.isPointerLike(else_type)) return else_type; if (else_type.kind == .nullptr_type and ast.types.isPointerLike(then_type)) return then_type; return null; }, .cast => |cast| return cast.target, }}fn makePointerType( parser: *Parser, expr: *ast.Expr, child: *const ast.Type,) Error!*const ast.Type { if (parser.nodes.inferredType(expr)) |cached| return cached; const token_index = parser.nodes.expressionOrigin(expr); const inferred = try memory.createType( parser, .{ .kind = .pointer, .child = child }, memory.directType(token_index, null), ); parser.nodes.setInferredType(expr, inferred); return inferred;}fn parseSizeof(parser: *Parser) Error!*ast.Expr { if (cursor.peek(parser).kind == .lparen and start_mod.typename(parser, 1)) { _ = cursor.advance(parser); const specifiers = try ctype.parseSpecifiers(parser); if (specifiers.requires_standalone_declaration) { return diagnostic.fail(parser, error.UnsupportedConstruct, "fixed enum forward declaration must be standalone"); } const declarator = try ctype.parseDeclarator(parser, specifiers.type, parseAssignment); _ = try cursor.expect(parser, .rparen); const size = ast.types.byteSize(declarator.type) orelse return diagnostic.fail(parser, error.UnsupportedConstruct, "sizeof of an incomplete type"); return memory.create(parser, ast.Expr, .{ .integer_literal = .{ .value = size, .type = &ast.types.ulong_type } }); } const operand = try parseUnary(parser); _ = operand; return diagnostic.fail(parser, error.UnsupportedConstruct, "sizeof of an expression");}fn parseAlignof(parser: *Parser) Error!*ast.Expr { if (cursor.peek(parser).kind == .lparen and start_mod.typename(parser, 1)) { _ = cursor.advance(parser); const specifiers = try ctype.parseSpecifiers(parser); if (specifiers.requires_standalone_declaration) { return diagnostic.fail(parser, error.UnsupportedConstruct, "fixed enum forward declaration must be standalone"); } const declarator = try ctype.parseDeclarator(parser, specifiers.type, parseAssignment); _ = try cursor.expect(parser, .rparen); const alignment = ast.types.byteAlign(declarator.type) orelse return diagnostic.fail(parser, error.UnsupportedConstruct, "alignof of an incomplete type"); return memory.create(parser, ast.Expr, .{ .integer_literal = .{ .value = alignment, .type = &ast.types.ulong_type } }); } const operand = try parseUnary(parser); _ = operand; return diagnostic.fail(parser, error.UnsupportedConstruct, "alignof of an expression");}fn parsePostfixChain(parser: *Parser, start: *ast.Expr) Error!*ast.Expr { var current = start; while (true) { switch (cursor.peek(parser).kind) { .lbracket => { _ = cursor.advance(parser); const subscript = try parseExpression(parser); _ = try cursor.expect(parser, .rbracket); current = try memory.create(parser, ast.Expr, .{ .index = .{ .base = current, .subscript = subscript } }); }, .plus_plus => { _ = cursor.advance(parser); current = try desugarIncrement(parser, current, .add); }, .minus_minus => { _ = cursor.advance(parser); current = try desugarIncrement(parser, current, .sub); }, else => return current, } }}fn parsePrimary(parser: *Parser) Error!*ast.Expr { switch (cursor.peek(parser).kind) { .integer => { const token_index = parser.index; const tok = cursor.advance(parser); const decoded = token.decodeInteger(tok.text) orelse return diagnostic.fail(parser, error.InvalidConstant, "invalid integer constant"); const literal_type: *const ast.Type = if (decoded.bit_width) |width| try memory.createType( parser, .{ .kind = .bitint_type, .is_unsigned = decoded.is_unsigned, .bit_width = width, }, memory.directType(token_index, null), ) else if (decoded.is_unsigned) (if (decoded.is_long) &ast.types.ulong_type else &ast.types.uint_type) else (if (decoded.is_long) &ast.types.long_type else &ast.types.int_type); return memory.create(parser, ast.Expr, .{ .integer_literal = .{ .value = decoded.value, .type = literal_type } }); }, .floating => { const tok = cursor.advance(parser); const decoded = token.decodeFloat(parser.arena, tok.text) orelse return diagnostic.fail(parser, error.InvalidConstant, "invalid float constant"); const literal_type: *const ast.Type = switch (decoded.kind) { .float => &ast.types.float_type, .double => &ast.types.double_type, .decimal32 => &ast.types.decimal32_type, .decimal64 => &ast.types.decimal64_type, .decimal128 => &ast.types.decimal128_type, }; return memory.create(parser, ast.Expr, .{ .float_literal = .{ .value = decoded.value, .type = literal_type } }); }, .kw_true, .kw_false => { const tok = cursor.advance(parser); const value: u64 = if (tok.kind == .kw_true) 1 else 0; return memory.create(parser, ast.Expr, .{ .integer_literal = .{ .value = value, .type = &ast.types.uchar_type } }); }, .kw_nullptr => { _ = cursor.advance(parser); return memory.create(parser, ast.Expr, .{ .integer_literal = .{ .value = 0, .type = &ast.types.nullptr_type } }); }, .character => { const tok = cursor.advance(parser); const value = token.decodeCharacter(tok.text) orelse return diagnostic.fail(parser, error.InvalidConstant, "invalid character constant"); return memory.create(parser, ast.Expr, .{ .integer_literal = .{ .value = value, .type = &ast.types.int_type } }); }, .string => { const token_index = parser.index; const tok = cursor.advance(parser); const text = token.decodeString(parser.arena, tok.text) orelse return diagnostic.fail(parser, error.InvalidConstant, "invalid string constant"); return memory.createExprAt( parser, .{ .string_literal = .{ .text = text } }, token_index, ); }, .identifier => { const tok = cursor.advance(parser); if (cursor.peek(parser).kind == .lparen) { _ = cursor.advance(parser); var arguments = std.ArrayListUnmanaged(*ast.Expr).empty; if (!cursor.consume(parser, .rparen)) { while (true) { try arguments.append(parser.arena, try parseAssignment(parser)); if (!cursor.consume(parser, .comma)) break; } _ = try cursor.expect(parser, .rparen); } return memory.create(parser, ast.Expr, .{ .call = .{ .callee = tok.text, .arguments = try arguments.toOwnedSlice(parser.arena), } }); } if (object.constantValue(parser, tok.text)) |value| { const constant_type = object.lookup(parser, tok.text) orelse &ast.types.int_type; return integerConstantExpression(parser, value, constant_type); } return memory.create(parser, ast.Expr, .{ .identifier = .{ .name = tok.text } }); }, .lparen => { _ = cursor.advance(parser); const inner = try parseExpression(parser); _ = try cursor.expect(parser, .rparen); return inner; }, else => return diagnostic.fail(parser, error.UnexpectedToken, "expected an expression"), }}fn parseSource(arena: std.mem.Allocator, source: []const u8) !*ast.Expr { const lexer = @import("../lexer/root.zig"); const token_survey = try lexer.survey(source, "expr.c"); const capacity = try lexer.Capacity.derive(token_survey.limits); const bytes = try arena.alignedAlloc( u8, .fromByteUnits(lexer.Storage.storage_alignment), capacity.storage_bytes, ); var storage = try lexer.Storage.init(bytes, token_survey.limits); storage.activate(); defer _ = storage.deinit(); const tokens = try storage.fill(token_survey, source, "expr.c"); var parser = try @import("state/test.zig").initParser(arena, tokens); return parseExpression(&parser);}test "precedence binds multiplication over addition" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); const sum = try parseSource(arena, "a + b * c"); try std.testing.expectEqual(ast.expr.BinaryOp.add, sum.binary.op); try std.testing.expectEqual(ast.expr.BinaryOp.mul, sum.binary.rhs.binary.op); const comparison = try parseSource(arena, "i * n + j < bound == 0"); try std.testing.expectEqual(ast.expr.BinaryOp.eq, comparison.binary.op); try std.testing.expectEqual(ast.expr.BinaryOp.lt, comparison.binary.lhs.binary.op);}test "assignments nest right and compound ops decode" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); const chain = try parseSource(arena, "a = b = 1"); try std.testing.expect(chain.assign.op == null); try std.testing.expect(chain.assign.value.assign.op == null); const compound = try parseSource(arena, "C[i][j] += alpha * A[i][k]"); try std.testing.expectEqual(ast.expr.BinaryOp.add, compound.assign.op.?); try std.testing.expect(compound.assign.target.* == .index); try std.testing.expect(compound.assign.target.index.base.* == .index);}test "unary postfix and casts parse" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); const increment = try parseSource(arena, "i++"); try std.testing.expectEqual(ast.expr.BinaryOp.add, increment.assign.op.?); const cast = try parseSource(arena, "(double)(i % n) / n"); try std.testing.expectEqual(ast.expr.BinaryOp.div, cast.binary.op); try std.testing.expect(cast.binary.lhs.* == .cast); const ternary = try parseSource(arena, "x > 0 ? f(x, 1) : -x"); try std.testing.expect(ternary.* == .conditional); try std.testing.expectEqual(@as(usize, 2), ternary.conditional.then_value.call.arguments.len); const size = try parseSource(arena, "sizeof(double)"); try std.testing.expectEqual(@as(u64, 8), size.integer_literal.value); const alignment = try parseSource(arena, "alignof(double)"); try std.testing.expectEqual(@as(u64, 8), alignment.integer_literal.value);}test "c23 constants parse as existing scalar expressions" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); const binary = try parseSource(arena, "0b1010'0101"); try std.testing.expectEqual(@as(u64, 0xa5), binary.integer_literal.value); const signed_bitint = try parseSource(arena, "3wb"); try std.testing.expectEqual(ast.types.Kind.bitint_type, signed_bitint.integer_literal.type.kind); try std.testing.expectEqual(@as(u16, 3), signed_bitint.integer_literal.type.bit_width); const unsigned_bitint = try parseSource(arena, "3uwb"); try std.testing.expectEqual(ast.types.Kind.bitint_type, unsigned_bitint.integer_literal.type.kind); try std.testing.expect(unsigned_bitint.integer_literal.type.is_unsigned); try std.testing.expectEqual(@as(u16, 2), unsigned_bitint.integer_literal.type.bit_width); const separated = try parseSource(arena, "1.25'5"); try std.testing.expectEqual(@as(f64, 1.255), separated.float_literal.value); const decimal32 = try parseSource(arena, "1.25df"); try std.testing.expectEqual(ast.types.Kind.decimal32_type, decimal32.float_literal.type.kind); const decimal64 = try parseSource(arena, "1.25DD"); try std.testing.expectEqual(ast.types.Kind.decimal64_type, decimal64.float_literal.type.kind); const decimal128 = try parseSource(arena, "1.25DL"); try std.testing.expectEqual(ast.types.Kind.decimal128_type, decimal128.float_literal.type.kind); const truth = try parseSource(arena, "true ? 299'792'458 : false"); try std.testing.expect(truth.* == .conditional); try std.testing.expectEqual(@as(u64, 1), truth.conditional.condition.integer_literal.value); try std.testing.expectEqual(@as(u64, 0), truth.conditional.else_value.integer_literal.value); const null_expr = try parseSource(arena, "nullptr"); try std.testing.expectEqual(ast.types.Kind.nullptr_type, null_expr.integer_literal.type.kind);}test "integer constant expressions evaluate" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); const expr = try parseSource(arena, "alignof(double) == 8 && (1 + 2 * 3) == 7"); var parser = try @import("state/test.zig").initParser(arena, &.{}); try std.testing.expectEqual(@as(i128, 1), evaluateIntegerConstant(&parser, expr).?);}test "expression types infer from parser objects" { const lexer = @import("../lexer/root.zig"); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); const source = "x + 1.0"; const token_survey = try lexer.survey(source, "expr.c"); const capacity = try lexer.Capacity.derive(token_survey.limits); const bytes = try arena.alignedAlloc( u8, .fromByteUnits(lexer.Storage.storage_alignment), capacity.storage_bytes, ); var storage = try lexer.Storage.init(bytes, token_survey.limits); storage.activate(); defer _ = storage.deinit(); const tokens = try storage.fill(token_survey, source, "expr.c"); var parser = try @import("state/test.zig").initParser(arena, tokens); try state.object.register(&parser, "x", &ast.types.int_type); const expr = try parseExpression(&parser); const inferred = (try inferType(&parser, expr)).?; try std.testing.expectEqual(ast.types.Kind.double_type, inferred.kind);}test "pointer inference reuses one charged type" { comptime { @stardustClaim( @import("alloc_phase").capacity.witness(@import("./state/root.zig").Storage, "chant_parser_type_cache"), null, null, null, null, null, null, ); } const lexer = @import("../lexer/root.zig"); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); const source = "&x"; const token_survey = try lexer.survey(source, "infer.c"); const capacity = try lexer.Capacity.derive(token_survey.limits); const bytes = try arena.alignedAlloc( u8, .fromByteUnits(lexer.Storage.storage_alignment), capacity.storage_bytes, ); var storage = try lexer.Storage.init(bytes, token_survey.limits); storage.activate(); defer _ = storage.deinit(); const tokens = try storage.fill(token_survey, source, "infer.c"); var parser = try @import("state/test.zig").initParser(arena, tokens); try state.object.register(&parser, "x", &ast.types.int_type); const expr = try parseExpression(&parser); const first = (try inferType(&parser, expr)).?; const after_first = parser.nodes.status(); const second = (try inferType(&parser, expr)).?; try std.testing.expectEqual(first, second); try std.testing.expectEqual(after_first, parser.nodes.status());}Source: lib/chant/src/parse/root.zig:11
zig
pub const expression = @import("expression.zig");Complete caller list for parse.expression.evaluateIntegerConstant
9 direct callers.
tiny.chant.parse.assertion.consume[function] atlib/chant/src/parse/assert.zig:10lib.chant.src.parse.constant.hasScalarConstantShape[function] — private source atlib/chant/src/parse/constant.zig:31in nearest public ownerlib.chant.src.parse.constantlib.chant.src.parse.constant.isScalar[function] — private source atlib/chant/src/parse/constant.zig:9in nearest public ownerlib.chant.src.parse.constantlib.chant.src.parse.constexpr.validateObject[function] — private source atlib/chant/src/parse/constexpr.zig:11in nearest public ownerlib.chant.src.parse.constexprlib.chant.src.parse.expression.test_integer_constant_expressions_evaluate[function] — test source atlib/chant/src/parse/expression.zig:571in nearest public ownertiny.chant.parse.expressionlib.chant.src.parse.initializer.parseDesignator[function] — private source atlib/chant/src/parse/initializer.zig:53in nearest public ownertiny.chant.parse.initializerlib.chant.src.parse.type.spec.parseAlignasExpression[function] — private source atlib/chant/src/parse/type/spec.zig:285in nearest public ownerlib.chant.src.parse.type.speclib.chant.src.parse.type.spec.parseBitIntWidth[function] — private source atlib/chant/src/parse/type/spec.zig:251in nearest public ownerlib.chant.src.parse.type.speclib.chant.src.parse.type.spec.parseEnumerators[function] — private source atlib/chant/src/parse/type/spec.zig:434in nearest public ownerlib.chant.src.parse.type.spec
Complete caller list for parse.expression.inferType
7 direct callers.
tiny.chant.parse.auto.resolve[function] atlib/chant/src/parse/auto.zig:11lib.chant.src.parse.constant.isScalar[function] — private source atlib/chant/src/parse/constant.zig:9in nearest public ownerlib.chant.src.parse.constantlib.chant.src.parse.constexpr.validateObject[function] — private source atlib/chant/src/parse/constexpr.zig:11in nearest public ownerlib.chant.src.parse.constexprlib.chant.src.parse.expression.test_expression_types_infer_from_parser_objects[function] — test source atlib/chant/src/parse/expression.zig:581in nearest public ownertiny.chant.parse.expressionlib.chant.src.parse.expression.test_pointer_inference_reuses_one_charged_type[function] — test source atlib/chant/src/parse/expression.zig:607in nearest public ownertiny.chant.parse.expressionlib.chant.src.parse.type.spec.explicitEnumeratorType[function] — private source atlib/chant/src/parse/type/spec.zig:483in nearest public ownerlib.chant.src.parse.type.speclib.chant.src.parse.type.spec.parseTypeofExpression[function] — private source atlib/chant/src/parse/type/spec.zig:605in nearest public ownerlib.chant.src.parse.type.spec
Complete caller list for parse.expression.parseExpression
17 direct callers.
tiny.chant.parse.assertion.consume[function] atlib/chant/src/parse/assert.zig:10lib.chant.src.parse.auto.test_auto_resolves_simple_and_pointer_declarations[function] — test source atlib/chant/src/parse/auto.zig:50in nearest public ownertiny.chant.parse.autolib.chant.src.parse.expression.parseConditional[function] — private source atlib/chant/src/parse/expression.zig:42in nearest public ownertiny.chant.parse.expressionlib.chant.src.parse.expression.parsePostfixChain[function] — private source atlib/chant/src/parse/expression.zig:346in nearest public ownertiny.chant.parse.expressionlib.chant.src.parse.expression.parsePrimary[function] — private source atlib/chant/src/parse/expression.zig:369in nearest public ownertiny.chant.parse.expressionlib.chant.src.parse.expression.parseSource[function] — private source atlib/chant/src/parse/expression.zig:464in nearest public ownertiny.chant.parse.expressionlib.chant.src.parse.expression.test_expression_types_infer_from_parser_objects[function] — test source atlib/chant/src/parse/expression.zig:581in nearest public ownertiny.chant.parse.expressionlib.chant.src.parse.expression.test_pointer_inference_reuses_one_charged_type[function] — test source atlib/chant/src/parse/expression.zig:607in nearest public ownertiny.chant.parse.expressionlib.chant.src.parse.statement.parseDo[function] — private source atlib/chant/src/parse/statement.zig:164in nearest public ownerlib.chant.src.parse.statementlib.chant.src.parse.statement.parseFor[function] — private source atlib/chant/src/parse/statement.zig:118in nearest public ownerlib.chant.src.parse.statementlib.chant.src.parse.statement.parseIf[function] — private source atlib/chant/src/parse/statement.zig:101in nearest public ownerlib.chant.src.parse.statementtiny.chant.parse.parseStatement[function] atlib/chant/src/parse/statement.zig:17lib.chant.src.parse.statement.parseWhile[function] — private source atlib/chant/src/parse/statement.zig:155in nearest public ownerlib.chant.src.parse.statementlib.chant.src.parse.type.declarator.parseSuffixes[function] — private source atlib/chant/src/parse/type/declarator.zig:72in nearest public ownerlib.chant.src.parse.type.declaratorlib.chant.src.parse.type.spec.parseAlignasExpression[function] — private source atlib/chant/src/parse/type/spec.zig:285in nearest public ownerlib.chant.src.parse.type.speclib.chant.src.parse.type.spec.parseBitIntWidth[function] — private source atlib/chant/src/parse/type/spec.zig:251in nearest public ownerlib.chant.src.parse.type.speclib.chant.src.parse.type.spec.parseTypeofExpression[function] — private source atlib/chant/src/parse/type/spec.zig:605in nearest public ownerlib.chant.src.parse.type.spec
Audit
| Definitions | 5 |
|---|---|
| Public names | 6 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |