mirror of
https://github.com/odin-lang/Odin.git
synced 2026-09-02 02:03:35 +00:00
Improve parsing field docs and comments (fixes #5353)
This commit is contained in:
@@ -318,9 +318,6 @@ consume_comment :: proc(p: ^Parser) -> (tok: tokenizer.Token, end_line: int) {
|
||||
}
|
||||
|
||||
_ = next_token0(p)
|
||||
if p.curr_tok.pos.line > tok.pos.line {
|
||||
end_line += 1
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -348,19 +345,13 @@ consume_comment_groups :: proc(p: ^Parser, prev: tokenizer.Token) {
|
||||
if p.curr_tok.kind != .Comment {
|
||||
return
|
||||
}
|
||||
comment: ^ast.Comment_Group
|
||||
end_line := 0
|
||||
|
||||
if p.curr_tok.pos.line == prev.pos.line {
|
||||
comment, end_line = consume_comment_group(p, 0)
|
||||
if p.curr_tok.pos.line != end_line ||
|
||||
p.curr_tok.pos.line == prev.pos.line+1 ||
|
||||
p.curr_tok.kind == .EOF {
|
||||
p.line_comment = comment
|
||||
}
|
||||
p.line_comment, _ = consume_comment_group(p, 0)
|
||||
}
|
||||
|
||||
end_line = -1
|
||||
comment: ^ast.Comment_Group
|
||||
end_line: int
|
||||
for p.curr_tok.kind == .Comment {
|
||||
comment, end_line = consume_comment_group(p, 1)
|
||||
}
|
||||
@@ -2048,13 +2039,14 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
|
||||
}
|
||||
}
|
||||
|
||||
line_comment := p.line_comment
|
||||
ok := expect_field_separator(p, type)
|
||||
|
||||
field := new_ast_field(names, type, default_value)
|
||||
field.tag = tag
|
||||
field.docs = docs
|
||||
field.flags = flags
|
||||
field.comment = p.line_comment
|
||||
field.comment = p.line_comment if p.line_comment != nil else line_comment
|
||||
append(fields, field)
|
||||
|
||||
return ok
|
||||
@@ -3862,6 +3854,8 @@ parse_value_decl :: proc(p: ^Parser, names: []^ast.Expr, docs: ^ast.Comment_Grou
|
||||
|
||||
end := p.prev_tok
|
||||
|
||||
end_comment := p.line_comment
|
||||
|
||||
if p.expr_level >= 0 {
|
||||
end: ^ast.Expr
|
||||
if !is_mutable && len(values) > 0 {
|
||||
@@ -3883,6 +3877,7 @@ parse_value_decl :: proc(p: ^Parser, names: []^ast.Expr, docs: ^ast.Comment_Grou
|
||||
|
||||
decl := ast.new(ast.Value_Decl, names[0].pos, end_pos(end))
|
||||
decl.docs = docs
|
||||
decl.comment = end_comment
|
||||
decl.names = names
|
||||
decl.type = type
|
||||
decl.values = values
|
||||
|
||||
@@ -65,6 +65,95 @@ Foo :: bit_field uint {
|
||||
|
||||
ok := parser.parse_file(&p, &file)
|
||||
testing.expect(t, ok, "bad parse")
|
||||
testing.expect(t, file.syntax_error_count == 0, "should contain zero errors")
|
||||
}
|
||||
|
||||
@test
|
||||
test_parse_struct_field_comments :: proc(t: ^testing.T) {
|
||||
context.allocator = context.temp_allocator
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
|
||||
expect_comments :: proc (t: ^testing.T, docs: ^ast.Comment_Group, expected: []string, loc := #caller_location) {
|
||||
if expected == nil {
|
||||
testing.expect_value(t, docs, nil, loc)
|
||||
} else {
|
||||
testing.expect(t, docs != nil, "comment should not be nil", loc=loc)
|
||||
testing.expect_value(t, len(docs.list), len(expected), loc)
|
||||
for tok, i in docs.list {
|
||||
testing.expect_value(t, tok.text, expected[i], loc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file := ast.File{
|
||||
fullpath = "test.odin",
|
||||
src = `
|
||||
package main
|
||||
|
||||
// foo doc
|
||||
Foo :: struct {
|
||||
// doc1
|
||||
a: int, // c1
|
||||
b: int, // c2
|
||||
// not included
|
||||
|
||||
// doc2
|
||||
// doc3
|
||||
c, d: int, /* c3
|
||||
c4 */
|
||||
|
||||
e: struct {
|
||||
} // c5
|
||||
// not included
|
||||
}
|
||||
|
||||
// not included
|
||||
|
||||
Bar :: struct {x, y: int /* c4 */} // after`,
|
||||
}
|
||||
|
||||
p := parser.default_parser()
|
||||
|
||||
p.err = proc(pos: tokenizer.Pos, format: string, args: ..any) {
|
||||
message := fmt.tprintf(format, ..args)
|
||||
log.errorf("%s(%d:%d): %s", pos.file, pos.line, pos.column, message)
|
||||
}
|
||||
|
||||
p.warn = proc(pos: tokenizer.Pos, format: string, args: ..any) {
|
||||
message := fmt.tprintf(format, ..args)
|
||||
log.warnf("%s(%d:%d): %s", pos.file, pos.line, pos.column, message)
|
||||
}
|
||||
|
||||
ok := parser.parse_file(&p, &file)
|
||||
|
||||
testing.expect(t, ok, "bad parse")
|
||||
testing.expect(t, file.syntax_error_count == 0, "should contain zero errors")
|
||||
|
||||
testing.expect_value(t, len(file.decls), 2)
|
||||
|
||||
foo_decl := file.decls[0].derived.(^ast.Value_Decl)
|
||||
expect_comments(t, foo_decl.docs, {"// foo doc"})
|
||||
expect_comments(t, foo_decl.comment, nil)
|
||||
|
||||
foo := foo_decl.values[0].derived.(^ast.Struct_Type)
|
||||
testing.expect_value(t, len(foo.fields.list), 4)
|
||||
expect_comments(t, foo.fields.list[0].docs, {"// doc1"})
|
||||
expect_comments(t, foo.fields.list[0].comment, {"// c1"})
|
||||
expect_comments(t, foo.fields.list[1].docs, nil)
|
||||
expect_comments(t, foo.fields.list[1].comment, {"// c2"})
|
||||
expect_comments(t, foo.fields.list[2].docs, {"// doc2", "// doc3"})
|
||||
expect_comments(t, foo.fields.list[2].comment, {"/* c3\nc4 */"})
|
||||
expect_comments(t, foo.fields.list[3].docs, nil)
|
||||
expect_comments(t, foo.fields.list[3].comment, {"// c5"})
|
||||
|
||||
bar_decl := file.decls[1].derived.(^ast.Value_Decl)
|
||||
expect_comments(t, bar_decl.docs, nil)
|
||||
expect_comments(t, bar_decl.comment, {"// after"})
|
||||
|
||||
bar := bar_decl.values[0].derived.(^ast.Struct_Type)
|
||||
testing.expect_value(t, len(bar.fields.list), 1)
|
||||
expect_comments(t, bar.fields.list[0].docs, nil)
|
||||
expect_comments(t, bar.fields.list[0].comment, {"/* c4 */"})
|
||||
}
|
||||
|
||||
@test
|
||||
|
||||
Reference in New Issue
Block a user