trailing commas
This commit is contained in:
@@ -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");
|
print("=== DONE ===\n");
|
||||||
}
|
}
|
||||||
|
|||||||
16
specs.md
16
specs.md
@@ -92,7 +92,7 @@ GLSL;
|
|||||||
| `:` | type annotation |
|
| `:` | type annotation |
|
||||||
| `=` | assignment (in typed var decl) |
|
| `=` | assignment (in typed var decl) |
|
||||||
| `;` | statement terminator |
|
| `;` | statement terminator |
|
||||||
| `,` | separator |
|
| `,` | separator (trailing commas allowed) |
|
||||||
| `.` | field access / enum literal prefix |
|
| `.` | field access / enum literal prefix |
|
||||||
| `->` | return type annotation |
|
| `->` | return type annotation |
|
||||||
| `=>` | lambda arrow |
|
| `=>` | lambda arrow |
|
||||||
@@ -244,6 +244,14 @@ v3 := Vec4.{ w=0, x=2, y=3, z=4 };
|
|||||||
z := 5.0;
|
z := 5.0;
|
||||||
w := 6.0;
|
w := 6.0;
|
||||||
v4 := Vec4.{ y=3, x=9, w, z };
|
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
|
#### Field Access and Assignment
|
||||||
@@ -1779,7 +1787,7 @@ enum_decl = IDENT '::' 'enum' '{' (IDENT ';')* '}'
|
|||||||
struct_decl = IDENT '::' 'struct' '{' struct_member* '}'
|
struct_decl = IDENT '::' 'struct' '{' struct_member* '}'
|
||||||
struct_member = field_group | '#using' IDENT ';'
|
struct_member = field_group | '#using' IDENT ';'
|
||||||
field_group = IDENT (',' IDENT)* ':' type ('=' expr)? ';'
|
field_group = IDENT (',' IDENT)* ':' type ('=' expr)? ';'
|
||||||
params = param (',' param)*
|
params = param (',' param)* ','?
|
||||||
param = IDENT ':' type
|
param = IDENT ':' type
|
||||||
block = '{' stmt* '}'
|
block = '{' stmt* '}'
|
||||||
stmt = decl | assignment ';' | multi_assign ';' | return_stmt | defer_stmt | insert_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 | '---'
|
primary = INT | HEX_INT | BIN_INT | FLOAT | STRING | BOOL | IDENT | '---'
|
||||||
| '.' IDENT | '.' '{' field_init_list '}'
|
| '.' IDENT | '.' '{' field_init_list '}'
|
||||||
| '(' expr ')' | block | '#run' expr
|
| '(' expr ')' | block | '#run' expr
|
||||||
field_init_list = field_init (',' field_init)*
|
field_init_list = field_init (',' field_init)* ','?
|
||||||
field_init = IDENT '=' expr | IDENT | expr
|
field_init = IDENT '=' expr | IDENT | expr
|
||||||
if_expr = 'if' expr 'then' expr ('else' expr)?
|
if_expr = 'if' expr 'then' expr ('else' expr)?
|
||||||
| 'if' expr block ('else' block)?
|
| 'if' expr block ('else' block)?
|
||||||
@@ -1812,7 +1820,7 @@ case_arm = 'case' pattern ':' (stmt* | 'break' ';')
|
|||||||
else_arm = 'else' ':' stmt*
|
else_arm = 'else' ':' stmt*
|
||||||
pattern = '.' IDENT | INT | BOOL | IDENT
|
pattern = '.' IDENT | INT | BOOL | IDENT
|
||||||
lambda = '(' params? ')' ('->' type)? '=>' expr
|
lambda = '(' params? ')' ('->' type)? '=>' expr
|
||||||
args = expr (',' expr)*
|
args = expr (',' expr)* ','?
|
||||||
type = '$' IDENT | 's32' | 'f32' | 'f64' | 'bool' | 'string'
|
type = '$' IDENT | 's32' | 'f32' | 'f64' | 'bool' | 'string'
|
||||||
| 'Any' | 'Type' | '..' type | '[' expr ']' type | IDENT
|
| 'Any' | 'Type' | '..' type | '[' expr ']' type | IDENT
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -714,6 +714,7 @@ pub const Parser = struct {
|
|||||||
while (self.current.tag != .r_paren and self.current.tag != .eof) {
|
while (self.current.tag != .r_paren and self.current.tag != .eof) {
|
||||||
if (type_params.items.len > 0) {
|
if (type_params.items.len > 0) {
|
||||||
try self.expect(.comma);
|
try self.expect(.comma);
|
||||||
|
if (self.current.tag == .r_paren) break;
|
||||||
}
|
}
|
||||||
// Expect $name : constraint
|
// Expect $name : constraint
|
||||||
try self.expect(.dollar);
|
try self.expect(.dollar);
|
||||||
@@ -899,6 +900,7 @@ pub const Parser = struct {
|
|||||||
while (self.current.tag != .r_paren and self.current.tag != .eof) {
|
while (self.current.tag != .r_paren and self.current.tag != .eof) {
|
||||||
if (param_types.items.len > 0) {
|
if (param_types.items.len > 0) {
|
||||||
try self.expect(.comma);
|
try self.expect(.comma);
|
||||||
|
if (self.current.tag == .r_paren) break;
|
||||||
}
|
}
|
||||||
// Parse: name: type
|
// Parse: name: type
|
||||||
if (self.current.tag != .identifier and self.current.tag != .kw_Self) {
|
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) {
|
while (self.current.tag != .r_paren and self.current.tag != .eof) {
|
||||||
if (target_type_params.items.len > 0) {
|
if (target_type_params.items.len > 0) {
|
||||||
try self.expect(.comma);
|
try self.expect(.comma);
|
||||||
|
if (self.current.tag == .r_paren) break;
|
||||||
}
|
}
|
||||||
try self.expect(.dollar);
|
try self.expect(.dollar);
|
||||||
if (self.current.tag != .identifier) {
|
if (self.current.tag != .identifier) {
|
||||||
@@ -1036,6 +1039,7 @@ pub const Parser = struct {
|
|||||||
while (self.current.tag != .r_brace and self.current.tag != .eof) {
|
while (self.current.tag != .r_brace and self.current.tag != .eof) {
|
||||||
if (field_inits.items.len > 0) {
|
if (field_inits.items.len > 0) {
|
||||||
try self.expect(.comma);
|
try self.expect(.comma);
|
||||||
|
if (self.current.tag == .r_brace) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is a named field: identifier followed by '='
|
// 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) {
|
while (self.current.tag != .r_paren and self.current.tag != .eof) {
|
||||||
if (params.items.len > 0) {
|
if (params.items.len > 0) {
|
||||||
try self.expect(.comma);
|
try self.expect(.comma);
|
||||||
|
if (self.current.tag == .r_paren) break;
|
||||||
}
|
}
|
||||||
var is_ct_param = false;
|
var is_ct_param = false;
|
||||||
if (self.current.tag == .dollar) {
|
if (self.current.tag == .dollar) {
|
||||||
@@ -1606,6 +1611,7 @@ pub const Parser = struct {
|
|||||||
while (self.current.tag != .r_paren and self.current.tag != .eof) {
|
while (self.current.tag != .r_paren and self.current.tag != .eof) {
|
||||||
if (args.items.len > 0) {
|
if (args.items.len > 0) {
|
||||||
try self.expect(.comma);
|
try self.expect(.comma);
|
||||||
|
if (self.current.tag == .r_paren) break;
|
||||||
}
|
}
|
||||||
// Spread operator: ..expr
|
// Spread operator: ..expr
|
||||||
if (self.current.tag == .dot_dot) {
|
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) {
|
while (self.current.tag != .r_bracket and self.current.tag != .eof) {
|
||||||
if (elements.items.len > 0) {
|
if (elements.items.len > 0) {
|
||||||
try self.expect(.comma);
|
try self.expect(.comma);
|
||||||
|
if (self.current.tag == .r_bracket) break;
|
||||||
}
|
}
|
||||||
const elem = try self.parseExpr();
|
const elem = try self.parseExpr();
|
||||||
try elements.append(self.allocator, elem);
|
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) {
|
while (self.current.tag != .r_bracket and self.current.tag != .eof) {
|
||||||
if (elements.items.len > 0) {
|
if (elements.items.len > 0) {
|
||||||
try self.expect(.comma);
|
try self.expect(.comma);
|
||||||
|
if (self.current.tag == .r_bracket) break;
|
||||||
}
|
}
|
||||||
const elem = try self.parseExpr();
|
const elem = try self.parseExpr();
|
||||||
try elements.append(self.allocator, elem);
|
try elements.append(self.allocator, elem);
|
||||||
@@ -2203,6 +2211,7 @@ pub const Parser = struct {
|
|||||||
try elements.append(self.allocator, .{ .name = name, .value = value });
|
try elements.append(self.allocator, .{ .name = name, .value = value });
|
||||||
if (self.current.tag == .comma) {
|
if (self.current.tag == .comma) {
|
||||||
self.advance();
|
self.advance();
|
||||||
|
if (self.current.tag == .r_paren) break;
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
try self.expect(.r_paren);
|
try self.expect(.r_paren);
|
||||||
|
|||||||
@@ -602,4 +602,6 @@ usize->s64: 42
|
|||||||
not wasm
|
not wasm
|
||||||
known os
|
known os
|
||||||
desktop 64-bit
|
desktop 64-bit
|
||||||
|
=== Trailing Commas ===
|
||||||
|
trailing commas ok
|
||||||
=== DONE ===
|
=== DONE ===
|
||||||
|
|||||||
Reference in New Issue
Block a user