closures
This commit is contained in:
104
src/parser.zig
104
src/parser.zig
@@ -390,14 +390,28 @@ pub const Parser = struct {
|
||||
}
|
||||
// Function type: (ParamTypes) -> ReturnType
|
||||
// Tuple type: (T1, T2) or (T1) — no '->' after ')'
|
||||
// Named params (documentation only): (name: Type, ...) -> ReturnType
|
||||
if (self.current.tag == .l_paren) {
|
||||
self.advance(); // skip '('
|
||||
var param_types = std.ArrayList(*Node).empty;
|
||||
var param_names = std.ArrayList(?[]const u8).empty;
|
||||
var has_names = false;
|
||||
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; // trailing comma ok
|
||||
}
|
||||
// Check for optional param name: `name: Type`
|
||||
// An identifier followed by `:` (not `::` or `:=`) is a param name
|
||||
if (self.current.tag == .identifier and self.peekNext() == .colon) {
|
||||
const pname = self.tokenSlice(self.current);
|
||||
self.advance(); // skip name
|
||||
self.advance(); // skip ':'
|
||||
try param_names.append(self.allocator, pname);
|
||||
has_names = true;
|
||||
} else {
|
||||
try param_names.append(self.allocator, null);
|
||||
}
|
||||
try param_types.append(self.allocator, try self.parseTypeExpr());
|
||||
}
|
||||
try self.expect(.r_paren);
|
||||
@@ -407,6 +421,7 @@ pub const Parser = struct {
|
||||
const return_type = try self.parseTypeExpr();
|
||||
return try self.createNode(start, .{ .function_type_expr = .{
|
||||
.param_types = try param_types.toOwnedSlice(self.allocator),
|
||||
.param_names = if (has_names) try param_names.toOwnedSlice(self.allocator) else null,
|
||||
.return_type = return_type,
|
||||
} });
|
||||
}
|
||||
@@ -439,6 +454,42 @@ pub const Parser = struct {
|
||||
}
|
||||
}
|
||||
|
||||
// Closure type: Closure(params...) -> R
|
||||
if (std.mem.eql(u8, name, "Closure") and self.current.tag == .l_paren) {
|
||||
self.advance(); // skip '('
|
||||
var param_types = std.ArrayList(*Node).empty;
|
||||
var param_names = std.ArrayList(?[]const u8).empty;
|
||||
var has_names = false;
|
||||
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; // trailing comma ok
|
||||
}
|
||||
// Check for optional param name: `name: Type`
|
||||
if (self.current.tag == .identifier and self.peekNext() == .colon) {
|
||||
const pname = self.tokenSlice(self.current);
|
||||
self.advance(); // skip name
|
||||
self.advance(); // skip ':'
|
||||
try param_names.append(self.allocator, pname);
|
||||
has_names = true;
|
||||
} else {
|
||||
try param_names.append(self.allocator, null);
|
||||
}
|
||||
try param_types.append(self.allocator, try self.parseTypeExpr());
|
||||
}
|
||||
try self.expect(.r_paren);
|
||||
var return_type: ?*Node = null;
|
||||
if (self.current.tag == .arrow) {
|
||||
self.advance();
|
||||
return_type = try self.parseTypeExpr();
|
||||
}
|
||||
return try self.createNode(start, .{ .closure_type_expr = .{
|
||||
.param_types = try param_types.toOwnedSlice(self.allocator),
|
||||
.param_names = if (has_names) try param_names.toOwnedSlice(self.allocator) else null,
|
||||
.return_type = return_type,
|
||||
} });
|
||||
}
|
||||
|
||||
// Parameterized type: Vector(N, T) or later generic struct instantiation
|
||||
if (self.current.tag == .l_paren) {
|
||||
self.advance(); // skip '('
|
||||
@@ -1889,24 +1940,56 @@ pub const Parser = struct {
|
||||
self.prev_end = saved_prev_end;
|
||||
}
|
||||
|
||||
// Use shared paren-scanning, then check for lambda patterns
|
||||
const tag = self.peekPastParens() orelse return false;
|
||||
// Check upfront if parens look like function params (for block-body disambiguation)
|
||||
const has_param_parens = blk: {
|
||||
self.advance(); // skip '('
|
||||
if (self.current.tag == .r_paren) break :blk true; // empty parens
|
||||
if (self.current.tag != .identifier) break :blk false;
|
||||
self.advance();
|
||||
break :blk self.current.tag == .colon;
|
||||
};
|
||||
|
||||
// Restore to '(' and scan past parens inline (not via peekPastParens which restores state)
|
||||
self.lexer = saved_lexer;
|
||||
self.current = saved_current;
|
||||
self.prev_end = saved_prev_end;
|
||||
self.advance(); // skip '('
|
||||
var depth: u32 = 1;
|
||||
while (depth > 0 and self.current.tag != .eof) {
|
||||
if (self.current.tag == .l_paren) depth += 1;
|
||||
if (self.current.tag == .r_paren) depth -= 1;
|
||||
if (depth > 0) self.advance();
|
||||
}
|
||||
if (self.current.tag != .r_paren) return false;
|
||||
self.advance(); // skip ')' — now positioned on token after parens
|
||||
|
||||
const tag = self.current.tag;
|
||||
// (params) => expr
|
||||
if (tag == .fat_arrow) return true;
|
||||
// (params) -> ReturnType => expr
|
||||
// (params) -> ReturnType { stmts }
|
||||
if (tag == .arrow) {
|
||||
self.advance(); // skip '->'
|
||||
// Skip past the return type tokens until we see '=>' or something unexpected
|
||||
// Skip past the return type tokens until we see '=>', '{', or something unexpected
|
||||
while (self.current.tag != .eof) {
|
||||
if (self.current.tag == .fat_arrow) return true;
|
||||
if (self.current.tag == .l_brace) return true;
|
||||
if (self.current.tag == .identifier or self.current.tag.isTypeKeyword() or
|
||||
self.current.tag == .dot or self.current.tag == .dollar or
|
||||
self.current.tag == .l_bracket or self.current.tag == .r_bracket or
|
||||
self.current.tag == .l_paren or self.current.tag == .r_paren or
|
||||
self.current.tag == .comma or self.current.tag == .int_literal)
|
||||
self.current.tag == .comma or self.current.tag == .int_literal or
|
||||
self.current.tag == .star or self.current.tag == .question)
|
||||
{
|
||||
self.advance();
|
||||
} else break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// (params) { stmts } — block-body lambda
|
||||
// Only if contents look like function params (have `:` type annotations or is empty `()`)
|
||||
if (tag == .l_brace) {
|
||||
return has_param_parens;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1915,15 +1998,22 @@ pub const Parser = struct {
|
||||
const start = self.current.loc.start;
|
||||
const params = try self.parseParams();
|
||||
|
||||
// Optional return type: (params) -> Type => expr
|
||||
// Optional return type: (params) -> Type => expr OR (params) -> Type { stmts }
|
||||
var return_type: ?*Node = null;
|
||||
if (self.current.tag == .arrow) {
|
||||
self.advance();
|
||||
return_type = try self.parseTypeExpr();
|
||||
}
|
||||
|
||||
try self.expect(.fat_arrow);
|
||||
const body = try self.parseExpr();
|
||||
// Two body forms:
|
||||
// (params) => expr — expression lambda
|
||||
// (params) { stmts } — block-body lambda
|
||||
const body = if (self.current.tag == .l_brace)
|
||||
try self.parseBlock()
|
||||
else blk: {
|
||||
try self.expect(.fat_arrow);
|
||||
break :blk try self.parseExpr();
|
||||
};
|
||||
const type_params = try self.collectTypeParams(params);
|
||||
return try self.createNode(start, .{ .lambda = .{
|
||||
.params = params,
|
||||
|
||||
Reference in New Issue
Block a user