fix(parser): peel stacked labels the way the formatter renders them

Assisted-by: GLM 5.3
This commit is contained in:
2026-10-02 00:40:20 +02:00
parent 9a5217d9c1
commit 6570709226
2 changed files with 19 additions and 11 deletions
@@ -0,0 +1,2 @@
go test fuzz v1
string("A:A:")
+17 -11
View File
@@ -160,12 +160,20 @@ func (p *state) parseLine(line []token.Token) {
return return
} }
// Label (ident immediately followed by a colon). // Label (ident immediately followed by a colon). Stacked labels
// share one line ("a: b: MOVQ …"): each peels off as its own Label,
// the same statement sequence the canonical layout puts on separate
// lines, so a file and its formatted image parse alike. A directive
// never peels: it stays with the instruction parse, as in the
// formatter's label handling.
if len(line) >= 2 && line[1].Kind == token.Colon { if len(line) >= 2 && line[1].Kind == token.Colon {
lbl := &ast.Label{Name: line[0], Colon: line[1]} rest := line
p.addStmt(lbl) for len(rest) >= 2 && rest[0].Kind == token.Ident && rest[1].Kind == token.Colon &&
// A label may share its line with an instruction: "loop: MOVQ …". !isDirective(rest[0].Text) {
if rest := dropColon(line); len(rest) > 0 { p.addStmt(&ast.Label{Name: rest[0], Colon: rest[1]})
rest = rest[2:]
}
if len(rest) > 0 {
p.parseInstr(rest) p.parseInstr(rest)
} }
p.pending = nil p.pending = nil
@@ -182,12 +190,10 @@ func (p *state) parseLine(line []token.Token) {
p.pending = nil p.pending = nil
} }
// dropColon removes the leading "ident :" of a label, returning the remainder. // isDirective reports whether the identifier names a top-level declaration
func dropColon(line []token.Token) []token.Token { // directive rather than an instruction or a label.
if len(line) >= 2 && line[1].Kind == token.Colon { func isDirective(s string) bool {
return line[2:] return s == "TEXT" || s == "DATA" || s == "GLOBL"
}
return nil
} }
func (p *state) addStmt(s ast.Stmt) { func (p *state) addStmt(s ast.Stmt) {