dot-shorthand and more

This commit is contained in:
agra
2026-02-25 15:51:22 +02:00
parent 4abc7abb54
commit f0569a8a3e
9 changed files with 576 additions and 43 deletions

View File

@@ -742,6 +742,7 @@ pub const Parser = struct {
var field_defaults = std.ArrayList(?*Node).empty;
var using_entries = std.ArrayList(ast.UsingEntry).empty;
var methods = std.ArrayList(*Node).empty;
var constants = std.ArrayList(*Node).empty;
while (self.current.tag != .r_brace and self.current.tag != .eof) {
// Check for #using directive
@@ -769,17 +770,26 @@ pub const Parser = struct {
if (self.current.tag == .l_paren and self.isFunctionDef()) {
try methods.append(self.allocator, try self.parseFnDecl(method_name, method_start));
} else {
return self.fail("only function declarations are allowed inside struct bodies");
// Non-function constant: name :: value;
const value = try self.parseExpr();
if (self.current.tag == .semicolon) self.advance();
try constants.append(self.allocator, try self.createNode(method_start, .{ .const_decl = .{
.name = method_name,
.type_annotation = null,
.value = value,
} }));
}
continue;
}
// Parse field group: name1, name2, ...: type (= default)?;
// Or typed constant: name :Type: value;
var group_names = std.ArrayList([]const u8).empty;
if (self.current.tag != .identifier) {
return self.fail("expected field name in struct");
}
const field_start = self.current.loc.start;
try group_names.append(self.allocator, self.tokenSlice(self.current));
self.advance();
@@ -795,6 +805,19 @@ pub const Parser = struct {
try self.expect(.colon);
const field_type = try self.parseTypeExpr();
// Typed constant: name :Type: value; (second colon after type)
if (self.current.tag == .colon and group_names.items.len == 1) {
self.advance(); // skip second ':'
const value = try self.parseExpr();
if (self.current.tag == .semicolon) self.advance();
try constants.append(self.allocator, try self.createNode(field_start, .{ .const_decl = .{
.name = group_names.items[0],
.type_annotation = field_type,
.value = value,
} }));
continue;
}
// Check for default value: = expr
var default_val: ?*Node = null;
if (self.current.tag == .equal) {
@@ -828,6 +851,7 @@ pub const Parser = struct {
.type_params = try type_params.toOwnedSlice(self.allocator),
.using_entries = try using_entries.toOwnedSlice(self.allocator),
.methods = try methods.toOwnedSlice(self.allocator),
.constants = try constants.toOwnedSlice(self.allocator),
} });
}
@@ -1441,7 +1465,7 @@ pub const Parser = struct {
// Null coalescing: expr ?? default
if (self.current.tag == .question_question and Prec.null_coalesce >= min_prec) {
self.advance();
const rhs = try self.parseBinary(Prec.null_coalesce + 1);
const rhs = try self.parseBinary(Prec.null_coalesce);
lhs = try self.createNode(lhs.span.start, .{ .null_coalesce = .{ .lhs = lhs, .rhs = rhs } });
continue;
}
@@ -1760,16 +1784,7 @@ pub const Parser = struct {
}
const name = self.tokenSlice(self.current);
self.advance();
// Enum literal with payload: .variant(payload) — tagged enum (formerly union literal)
if (self.current.tag == .l_paren) {
self.advance(); // skip '('
const payload = try self.parseExpr();
try self.expect(.r_paren);
return try self.createNode(start, .{ .enum_literal = .{
.name = name,
.payload = payload,
} });
}
// Enum literal: .variant_name — parsePostfix handles optional (...) as a call
return try self.createNode(start, .{ .enum_literal = .{ .name = name } });
},
.l_paren => {