fix(pp): // line comment containing /* no longer eats subsequent lines
stripBlockComments scanned each line for a /* block-comment opener while tracking string literals but had no notion of // or && line comments. A line like `// see app/api/*.prg` would open a block comment from /*.prg that ran until EOF or the next */, silently dropping every FUNCTION declaration in between. The compiled file ended up with an empty symbols slice, and callers in other files panicked at runtime with "no function symbol for call". Hit while writing app/lib/text.prg in solmade — its `// build's \`app/api/*.prg\` glob doesn't pick it up` line dropped all three of QueryParamRaw / UrlDecodeBytes / IsAllDigits. Fix: detect // and && line-comment markers before the /* check. When one is seen, copy the rest of the line through verbatim (the lexer and #command machinery still need it) and stop scanning so the embedded /* can't open a block comment. Two regression tests cover both markers. Full mandatory test suite (go test ./..., FiveSql2 43/43, compat 56/56, std.ch 17/17, FRB 7/7, pgserver 11/11) still passes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -659,6 +659,10 @@ func (pp *Preprocessor) applyRules(line string) string {
|
||||
|
||||
// stripBlockComments removes /* ... */ comments from a line.
|
||||
// If a /* is found without closing */, sets inBlock to true.
|
||||
//
|
||||
// `//` and `&&` line-comment markers are detected first so a `/*`
|
||||
// substring inside one of them (e.g. `// see app/api/*.prg`) doesn't
|
||||
// start a runaway block comment that eats subsequent lines.
|
||||
func stripBlockComments(line string, inBlock *bool) string {
|
||||
var out strings.Builder
|
||||
i := 0
|
||||
@@ -679,6 +683,20 @@ func stripBlockComments(line string, inBlock *bool) string {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
// // line comment — copy the rest of the line through verbatim
|
||||
// (the lexer/`#command` machinery still needs to see it) but
|
||||
// don't scan it for `/*` so an embedded `/*` substring (e.g.
|
||||
// `// see app/api/*.prg`) can't open a runaway block comment
|
||||
// that eats subsequent lines.
|
||||
if i+1 < len(line) && line[i] == '/' && line[i+1] == '/' {
|
||||
out.WriteString(line[i:])
|
||||
return out.String()
|
||||
}
|
||||
// && Harbour-style line comment — same rule.
|
||||
if i+1 < len(line) && line[i] == '&' && line[i+1] == '&' {
|
||||
out.WriteString(line[i:])
|
||||
return out.String()
|
||||
}
|
||||
// Block comment start
|
||||
if i+1 < len(line) && line[i] == '/' && line[i+1] == '*' {
|
||||
// Find closing */
|
||||
|
||||
@@ -262,3 +262,34 @@ func TestMissingInclude(t *testing.T) {
|
||||
t.Error("code after missing include should continue")
|
||||
}
|
||||
}
|
||||
|
||||
// TestSlashStarInsideLineComment locks in that a `/*` substring inside
|
||||
// a `//` line comment does NOT open a runaway block comment. Before
|
||||
// the fix, a comment like "// see app/api/*.prg" would start a block
|
||||
// comment from `/*.prg` that ate every subsequent line until EOF or
|
||||
// the next `*/`, silently dropping FUNCTION declarations.
|
||||
func TestSlashStarInsideLineComment(t *testing.T) {
|
||||
p := New()
|
||||
src := `// see app/api/*.prg for the glob
|
||||
FUNCTION Foo()
|
||||
RETURN 1
|
||||
`
|
||||
result, _ := p.Process("test.prg", src)
|
||||
if !strings.Contains(result, "FUNCTION Foo") {
|
||||
t.Errorf("FUNCTION Foo() should survive a // line comment that contains /*; got:\n%s", result)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDoubleAmpInsideLineComment — same protection for Harbour's `&&`
|
||||
// line comment marker.
|
||||
func TestDoubleAmpInsideLineComment(t *testing.T) {
|
||||
p := New()
|
||||
src := `&& glob /*.prg
|
||||
FUNCTION Foo()
|
||||
RETURN 1
|
||||
`
|
||||
result, _ := p.Process("test.prg", src)
|
||||
if !strings.Contains(result, "FUNCTION Foo") {
|
||||
t.Errorf("FUNCTION Foo() should survive a && line comment that contains /*; got:\n%s", result)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user