Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 32 additions & 9 deletions lib/std/zig/Ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex {
.container_field,
=> {
const name_token = main_tokens[n];
if (token_tags[name_token + 1] != .colon) return name_token - end_offset;
if (name_token > 0 and token_tags[name_token - 1] == .keyword_comptime) {
end_offset += 1;
}
Expand Down Expand Up @@ -1320,33 +1321,39 @@ pub fn containerField(tree: Ast, node: Node.Index) full.ContainerField {
assert(tree.nodes.items(.tag)[node] == .container_field);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.rhs, Node.ContainerField);
const main_token = tree.nodes.items(.main_token)[node];
return tree.fullContainerField(.{
.name_token = tree.nodes.items(.main_token)[node],
.main_token = main_token,
.type_expr = data.lhs,
.value_expr = extra.value_expr,
.align_expr = extra.align_expr,
.tuple_like = tree.tokens.items(.tag)[main_token + 1] != .colon,
});
}

pub fn containerFieldInit(tree: Ast, node: Node.Index) full.ContainerField {
assert(tree.nodes.items(.tag)[node] == .container_field_init);
const data = tree.nodes.items(.data)[node];
const main_token = tree.nodes.items(.main_token)[node];
return tree.fullContainerField(.{
.name_token = tree.nodes.items(.main_token)[node],
.main_token = main_token,
.type_expr = data.lhs,
.value_expr = data.rhs,
.align_expr = 0,
.tuple_like = tree.tokens.items(.tag)[main_token + 1] != .colon,
});
}

pub fn containerFieldAlign(tree: Ast, node: Node.Index) full.ContainerField {
assert(tree.nodes.items(.tag)[node] == .container_field_align);
const data = tree.nodes.items(.data)[node];
const main_token = tree.nodes.items(.main_token)[node];
return tree.fullContainerField(.{
.name_token = tree.nodes.items(.main_token)[node],
.main_token = main_token,
.type_expr = data.lhs,
.value_expr = 0,
.align_expr = data.rhs,
.tuple_like = tree.tokens.items(.tag)[main_token + 1] != .colon,
});
}

Expand Down Expand Up @@ -1944,10 +1951,14 @@ fn fullContainerField(tree: Ast, info: full.ContainerField.Components) full.Cont
.ast = info,
.comptime_token = null,
};
// comptime name: type = init,
// ^
if (info.name_token > 0 and token_tags[info.name_token - 1] == .keyword_comptime) {
result.comptime_token = info.name_token - 1;
if (token_tags[info.main_token] == .keyword_comptime) {
// comptime type = init,
// ^
result.comptime_token = info.main_token;
} else if (info.main_token > 0 and token_tags[info.main_token - 1] == .keyword_comptime) {
// comptime name: type = init,
// ^
result.comptime_token = info.main_token - 1;
}
return result;
}
Expand Down Expand Up @@ -2256,14 +2267,26 @@ pub const full = struct {
ast: Components,

pub const Components = struct {
name_token: TokenIndex,
main_token: TokenIndex,
type_expr: Node.Index,
value_expr: Node.Index,
align_expr: Node.Index,
tuple_like: bool,
};

pub fn firstToken(cf: ContainerField) TokenIndex {
return cf.comptime_token orelse cf.ast.name_token;
return cf.comptime_token orelse cf.ast.main_token;
}

pub fn convertToNonTupleLike(cf: *ContainerField, nodes: NodeList.Slice) void {
if (!cf.ast.tuple_like) return;
if (cf.ast.type_expr == 0) return;
if (nodes.items(.tag)[cf.ast.type_expr] != .identifier) return;

const ident = nodes.items(.main_token)[cf.ast.type_expr];
cf.ast.tuple_like = false;
cf.ast.main_token = ident;
cf.ast.type_expr = 0;
}
};

Expand Down
220 changes: 107 additions & 113 deletions lib/std/zig/parse.zig
Original file line number Diff line number Diff line change
Expand Up @@ -272,53 +272,6 @@ const Parser = struct {
trailing = false;
},
.keyword_comptime => switch (p.token_tags[p.tok_i + 1]) {
.identifier => {
p.tok_i += 1;
const identifier = p.tok_i;
defer last_field = identifier;
const container_field = try p.expectContainerFieldRecoverable();
if (container_field != 0) {
switch (field_state) {
.none => field_state = .seen,
.err, .seen => {},
.end => |node| {
try p.warnMsg(.{
.tag = .decl_between_fields,
.token = p.nodes.items(.main_token)[node],
});
try p.warnMsg(.{
.tag = .previous_field,
.is_note = true,
.token = last_field,
});
try p.warnMsg(.{
.tag = .next_field,
.is_note = true,
.token = identifier,
});
// Continue parsing; error will be reported later.
field_state = .err;
},
}
try p.scratch.append(p.gpa, container_field);
switch (p.token_tags[p.tok_i]) {
.comma => {
p.tok_i += 1;
trailing = true;
continue;
},
.r_brace, .eof => {
trailing = false;
break;
},
else => {},
}
// There is not allowed to be a decl after a field with no comma.
// Report error but recover parser.
try p.warn(.expected_comma_after_field);
p.findNextContainerMember();
}
},
.l_brace => {
if (doc_comment) |some| {
try p.warnMsg(.{ .tag = .test_doc_comment, .token = some });
Expand Down Expand Up @@ -349,53 +302,15 @@ const Parser = struct {
},
else => {
p.tok_i += 1;
try p.warn(.expected_block_or_field);
},
},
.keyword_pub => {
p.tok_i += 1;
const top_level_decl = try p.expectTopLevelDeclRecoverable();
if (top_level_decl != 0) {
if (field_state == .seen) {
field_state = .{ .end = top_level_decl };
}
try p.scratch.append(p.gpa, top_level_decl);
}
trailing = p.token_tags[p.tok_i - 1] == .semicolon;
},
.keyword_usingnamespace => {
const node = try p.expectUsingNamespaceRecoverable();
if (node != 0) {
if (field_state == .seen) {
field_state = .{ .end = node };
}
try p.scratch.append(p.gpa, node);
}
trailing = p.token_tags[p.tok_i - 1] == .semicolon;
},
.keyword_const,
.keyword_var,
.keyword_threadlocal,
.keyword_export,
.keyword_extern,
.keyword_inline,
.keyword_noinline,
.keyword_fn,
=> {
const top_level_decl = try p.expectTopLevelDeclRecoverable();
if (top_level_decl != 0) {
if (field_state == .seen) {
field_state = .{ .end = top_level_decl };
}
try p.scratch.append(p.gpa, top_level_decl);
}
trailing = p.token_tags[p.tok_i - 1] == .semicolon;
},
.identifier => {
const identifier = p.tok_i;
defer last_field = identifier;
const container_field = try p.expectContainerFieldRecoverable();
if (container_field != 0) {
const identifier = p.tok_i;
defer last_field = identifier;
const container_field = p.expectContainerField() catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.ParseError => {
p.findNextContainerMember();
continue;
},
};
switch (field_state) {
.none => field_state = .seen,
.err, .seen => {},
Expand Down Expand Up @@ -435,7 +350,46 @@ const Parser = struct {
// Report error but recover parser.
try p.warn(.expected_comma_after_field);
p.findNextContainerMember();
},
},
.keyword_pub => {
p.tok_i += 1;
const top_level_decl = try p.expectTopLevelDeclRecoverable();
if (top_level_decl != 0) {
if (field_state == .seen) {
field_state = .{ .end = top_level_decl };
}
try p.scratch.append(p.gpa, top_level_decl);
}
trailing = p.token_tags[p.tok_i - 1] == .semicolon;
},
.keyword_usingnamespace => {
const node = try p.expectUsingNamespaceRecoverable();
if (node != 0) {
if (field_state == .seen) {
field_state = .{ .end = node };
}
try p.scratch.append(p.gpa, node);
}
trailing = p.token_tags[p.tok_i - 1] == .semicolon;
},
.keyword_const,
.keyword_var,
.keyword_threadlocal,
.keyword_export,
.keyword_extern,
.keyword_inline,
.keyword_noinline,
.keyword_fn,
=> {
const top_level_decl = try p.expectTopLevelDeclRecoverable();
if (top_level_decl != 0) {
if (field_state == .seen) {
field_state = .{ .end = top_level_decl };
}
try p.scratch.append(p.gpa, top_level_decl);
}
trailing = p.token_tags[p.tok_i - 1] == .semicolon;
},
.eof, .r_brace => {
if (doc_comment) |tok| {
Expand All @@ -451,11 +405,57 @@ const Parser = struct {
error.OutOfMemory => return error.OutOfMemory,
error.ParseError => false,
};
if (!c_container) {
try p.warn(.expected_container_members);
// This was likely not supposed to end yet; try to find the next declaration.
p.findNextContainerMember();
if (c_container) continue;

const identifier = p.tok_i;
defer last_field = identifier;
const container_field = p.expectContainerField() catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.ParseError => {
p.findNextContainerMember();
continue;
},
};
switch (field_state) {
.none => field_state = .seen,
.err, .seen => {},
.end => |node| {
try p.warnMsg(.{
.tag = .decl_between_fields,
.token = p.nodes.items(.main_token)[node],
});
try p.warnMsg(.{
.tag = .previous_field,
.is_note = true,
.token = last_field,
});
try p.warnMsg(.{
.tag = .next_field,
.is_note = true,
.token = identifier,
});
// Continue parsing; error will be reported later.
field_state = .err;
},
}
try p.scratch.append(p.gpa, container_field);
switch (p.token_tags[p.tok_i]) {
.comma => {
p.tok_i += 1;
trailing = true;
continue;
},
.r_brace, .eof => {
trailing = false;
break;
},
else => {},
}
// There is not allowed to be a decl after a field with no comma.
// Report error but recover parser.
try p.warn(.expected_comma_after_field);
p.findNextContainerMember();
continue;
},
}
}
Expand Down Expand Up @@ -875,12 +875,16 @@ const Parser = struct {

/// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
fn expectContainerField(p: *Parser) !Node.Index {
var main_token = p.tok_i;
_ = p.eatToken(.keyword_comptime);
const name_token = p.assertToken(.identifier);
const tuple_like = p.token_tags[p.tok_i] != .identifier or p.token_tags[p.tok_i + 1] != .colon;
if (!tuple_like) {
main_token = p.assertToken(.identifier);
}

var align_expr: Node.Index = 0;
var type_expr: Node.Index = 0;
if (p.eatToken(.colon)) |_| {
if (p.eatToken(.colon) != null or tuple_like) {
type_expr = try p.expectTypeExpr();
align_expr = try p.parseByteAlign();
}
Expand All @@ -890,7 +894,7 @@ const Parser = struct {
if (align_expr == 0) {
return p.addNode(.{
.tag = .container_field_init,
.main_token = name_token,
.main_token = main_token,
.data = .{
.lhs = type_expr,
.rhs = value_expr,
Expand All @@ -899,7 +903,7 @@ const Parser = struct {
} else if (value_expr == 0) {
return p.addNode(.{
.tag = .container_field_align,
.main_token = name_token,
.main_token = main_token,
.data = .{
.lhs = type_expr,
.rhs = align_expr,
Expand All @@ -908,7 +912,7 @@ const Parser = struct {
} else {
return p.addNode(.{
.tag = .container_field,
.main_token = name_token,
.main_token = main_token,
.data = .{
.lhs = type_expr,
.rhs = try p.addExtra(Node.ContainerField{
Expand All @@ -920,16 +924,6 @@ const Parser = struct {
}
}

fn expectContainerFieldRecoverable(p: *Parser) error{OutOfMemory}!Node.Index {
return p.expectContainerField() catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.ParseError => {
p.findNextContainerMember();
return null_node;
},
};
}

/// Statement
/// <- KEYWORD_comptime? VarDecl
/// / KEYWORD_comptime BlockExprStatement
Expand Down
Loading