...
This commit is contained in:
113
src/parser.zig
113
src/parser.zig
@@ -711,16 +711,11 @@ pub const Parser = struct {
|
||||
/// Collect generic type params and comptime value params from parameter annotations.
|
||||
fn collectTypeParams(self: *Parser, params: []const ast.Param) ![]const ast.StructTypeParam {
|
||||
var type_params = std.ArrayList(ast.StructTypeParam).empty;
|
||||
var seen = std.StringHashMap(void).init(self.allocator);
|
||||
for (params) |param| {
|
||||
if (param.is_comptime) {
|
||||
var found = false;
|
||||
for (type_params.items) |existing| {
|
||||
if (std.mem.eql(u8, existing.name, param.name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (!seen.contains(param.name)) {
|
||||
try seen.put(param.name, {});
|
||||
try type_params.append(self.allocator, .{ .name = param.name, .constraint = param.type_expr });
|
||||
}
|
||||
} else {
|
||||
@@ -728,14 +723,8 @@ pub const Parser = struct {
|
||||
var generic_names = std.ArrayList([]const u8).empty;
|
||||
collectGenericNames(param.type_expr, &generic_names, self.allocator);
|
||||
for (generic_names.items) |gen_name| {
|
||||
var found = false;
|
||||
for (type_params.items) |existing| {
|
||||
if (std.mem.eql(u8, existing.name, gen_name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (!seen.contains(gen_name)) {
|
||||
try seen.put(gen_name, {});
|
||||
const type_constraint = self.createNode(param.type_expr.span.start, .{ .type_expr = .{ .name = "Type" } }) catch continue;
|
||||
type_params.append(self.allocator, .{ .name = gen_name, .constraint = type_constraint }) catch {};
|
||||
}
|
||||
@@ -1506,8 +1495,30 @@ pub const Parser = struct {
|
||||
return try self.createNode(start_pos, .{ .match_expr = .{ .subject = subject, .arms = try arms.toOwnedSlice(self.allocator) } });
|
||||
}
|
||||
|
||||
/// Save state, skip past matching parens, return the tag of the next token, then restore.
|
||||
/// Returns null if no matching ')' found before EOF.
|
||||
fn peekPastParens(self: *Parser) ?Tag {
|
||||
const saved_lexer = self.lexer;
|
||||
const saved_current = self.current;
|
||||
const saved_prev_end = self.prev_end;
|
||||
defer {
|
||||
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 null;
|
||||
self.advance(); // skip ')'
|
||||
return self.current.tag;
|
||||
}
|
||||
|
||||
fn isLambda(self: *Parser) bool {
|
||||
// Peek ahead: save state, scan to matching ), check if => or -> ... => follows
|
||||
const saved_lexer = self.lexer;
|
||||
const saved_current = self.current;
|
||||
const saved_prev_end = self.prev_end;
|
||||
@@ -1517,32 +1528,23 @@ pub const Parser = struct {
|
||||
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) {
|
||||
self.advance(); // skip ')'
|
||||
if (self.current.tag == .fat_arrow) return true;
|
||||
// (params) -> ReturnType => expr
|
||||
if (self.current.tag == .arrow) {
|
||||
self.advance(); // skip '->'
|
||||
// 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;
|
||||
// Return type tokens: identifiers, dots, parens, type keywords, dollar, brackets
|
||||
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.advance();
|
||||
} else break;
|
||||
}
|
||||
// Use shared paren-scanning, then check for lambda patterns
|
||||
const tag = self.peekPastParens() orelse return false;
|
||||
if (tag == .fat_arrow) return true;
|
||||
// (params) -> ReturnType => expr
|
||||
if (tag == .arrow) {
|
||||
self.advance(); // skip '->'
|
||||
// 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 == .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.advance();
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -1573,29 +1575,8 @@ pub const Parser = struct {
|
||||
// ---- Helpers ----
|
||||
|
||||
fn isFunctionDef(self: *Parser) bool {
|
||||
// Peek ahead: save state, scan to matching ), check what follows
|
||||
const saved_lexer = self.lexer;
|
||||
const saved_current = self.current;
|
||||
const saved_prev_end = self.prev_end;
|
||||
defer {
|
||||
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) {
|
||||
self.advance(); // skip ')'
|
||||
// Function if followed by '{', '->', '#builtin', '#foreign', or '=>'
|
||||
return self.current.tag == .l_brace or self.current.tag == .arrow or self.current.tag == .hash_builtin or self.current.tag == .hash_foreign or self.current.tag == .fat_arrow;
|
||||
}
|
||||
return false;
|
||||
const tag = self.peekPastParens() orelse return false;
|
||||
return tag == .l_brace or tag == .arrow or tag == .hash_builtin or tag == .hash_foreign or tag == .fat_arrow;
|
||||
}
|
||||
|
||||
fn isAssignOp(self: *const Parser) bool {
|
||||
|
||||
Reference in New Issue
Block a user