trailing commas

This commit is contained in:
agra
2026-03-03 09:42:01 +02:00
parent 03074472e5
commit 6c5672c7df
4 changed files with 49 additions and 4 deletions

View File

@@ -3120,5 +3120,31 @@ END;
}
}
// ── Trailing commas ──────────────────────────────────────────
print("=== Trailing Commas ===\n");
{
// Struct literal with trailing comma
Vec4 :: struct { x: f64; y: f64; z: f64; w: f64; }
v := Vec4.{
x = 1.0,
y = 2.0,
z = 3.0,
w = 4.0,
};
assert(v.x == 1.0);
assert(v.w == 4.0);
// Function call with trailing comma
add :: (a: s64, b: s64) -> s64 { return a + b; }
r := add(10, 20,);
assert(r == 30);
// Array literal with trailing comma
arr := s64.[1, 2, 3,];
assert(arr[2] == 3);
print("trailing commas ok\n");
}
print("=== DONE ===\n");
}

View File

@@ -92,7 +92,7 @@ GLSL;
| `:` | type annotation |
| `=` | assignment (in typed var decl) |
| `;` | statement terminator |
| `,` | separator |
| `,` | separator (trailing commas allowed) |
| `.` | field access / enum literal prefix |
| `->` | return type annotation |
| `=>` | lambda arrow |
@@ -244,6 +244,14 @@ v3 := Vec4.{ w=0, x=2, y=3, z=4 };
z := 5.0;
w := 6.0;
v4 := Vec4.{ y=3, x=9, w, z };
// Trailing commas are allowed in all comma-separated lists
v5 := Vec4.{
x = 1.0,
y = 2.0,
z = 3.0,
w = 4.0,
};
```
#### Field Access and Assignment
@@ -1779,7 +1787,7 @@ enum_decl = IDENT '::' 'enum' '{' (IDENT ';')* '}'
struct_decl = IDENT '::' 'struct' '{' struct_member* '}'
struct_member = field_group | '#using' IDENT ';'
field_group = IDENT (',' IDENT)* ':' type ('=' expr)? ';'
params = param (',' param)*
params = param (',' param)* ','?
param = IDENT ':' type
block = '{' stmt* '}'
stmt = decl | assignment ';' | multi_assign ';' | return_stmt | defer_stmt | insert_stmt
@@ -1803,7 +1811,7 @@ postfix = primary ('(' args? ')' | '.' IDENT | '.{' field_init_list '}')
primary = INT | HEX_INT | BIN_INT | FLOAT | STRING | BOOL | IDENT | '---'
| '.' IDENT | '.' '{' field_init_list '}'
| '(' expr ')' | block | '#run' expr
field_init_list = field_init (',' field_init)*
field_init_list = field_init (',' field_init)* ','?
field_init = IDENT '=' expr | IDENT | expr
if_expr = 'if' expr 'then' expr ('else' expr)?
| 'if' expr block ('else' block)?
@@ -1812,7 +1820,7 @@ case_arm = 'case' pattern ':' (stmt* | 'break' ';')
else_arm = 'else' ':' stmt*
pattern = '.' IDENT | INT | BOOL | IDENT
lambda = '(' params? ')' ('->' type)? '=>' expr
args = expr (',' expr)*
args = expr (',' expr)* ','?
type = '$' IDENT | 's32' | 'f32' | 'f64' | 'bool' | 'string'
| 'Any' | 'Type' | '..' type | '[' expr ']' type | IDENT
```

View File

@@ -714,6 +714,7 @@ pub const Parser = struct {
while (self.current.tag != .r_paren and self.current.tag != .eof) {
if (type_params.items.len > 0) {
try self.expect(.comma);
if (self.current.tag == .r_paren) break;
}
// Expect $name : constraint
try self.expect(.dollar);
@@ -899,6 +900,7 @@ pub const Parser = struct {
while (self.current.tag != .r_paren and self.current.tag != .eof) {
if (param_types.items.len > 0) {
try self.expect(.comma);
if (self.current.tag == .r_paren) break;
}
// Parse: name: type
if (self.current.tag != .identifier and self.current.tag != .kw_Self) {
@@ -976,6 +978,7 @@ pub const Parser = struct {
while (self.current.tag != .r_paren and self.current.tag != .eof) {
if (target_type_params.items.len > 0) {
try self.expect(.comma);
if (self.current.tag == .r_paren) break;
}
try self.expect(.dollar);
if (self.current.tag != .identifier) {
@@ -1036,6 +1039,7 @@ pub const Parser = struct {
while (self.current.tag != .r_brace and self.current.tag != .eof) {
if (field_inits.items.len > 0) {
try self.expect(.comma);
if (self.current.tag == .r_brace) break;
}
// Check if this is a named field: identifier followed by '='
@@ -1104,6 +1108,7 @@ pub const Parser = struct {
while (self.current.tag != .r_paren and self.current.tag != .eof) {
if (params.items.len > 0) {
try self.expect(.comma);
if (self.current.tag == .r_paren) break;
}
var is_ct_param = false;
if (self.current.tag == .dollar) {
@@ -1606,6 +1611,7 @@ pub const Parser = struct {
while (self.current.tag != .r_paren and self.current.tag != .eof) {
if (args.items.len > 0) {
try self.expect(.comma);
if (self.current.tag == .r_paren) break;
}
// Spread operator: ..expr
if (self.current.tag == .dot_dot) {
@@ -1641,6 +1647,7 @@ pub const Parser = struct {
while (self.current.tag != .r_bracket and self.current.tag != .eof) {
if (elements.items.len > 0) {
try self.expect(.comma);
if (self.current.tag == .r_bracket) break;
}
const elem = try self.parseExpr();
try elements.append(self.allocator, elem);
@@ -1805,6 +1812,7 @@ pub const Parser = struct {
while (self.current.tag != .r_bracket and self.current.tag != .eof) {
if (elements.items.len > 0) {
try self.expect(.comma);
if (self.current.tag == .r_bracket) break;
}
const elem = try self.parseExpr();
try elements.append(self.allocator, elem);
@@ -2203,6 +2211,7 @@ pub const Parser = struct {
try elements.append(self.allocator, .{ .name = name, .value = value });
if (self.current.tag == .comma) {
self.advance();
if (self.current.tag == .r_paren) break;
} else break;
}
try self.expect(.r_paren);

View File

@@ -602,4 +602,6 @@ usize->s64: 42
not wasm
known os
desktop 64-bit
=== Trailing Commas ===
trailing commas ok
=== DONE ===