fix: analyzer zero warnings — complete RTL coverage, cross-file awareness
- Register all 479 RTL functions from hbrtl/register.go (was ~60)
- Recognize module-level STATIC variables across all functions
- Declare RECOVER USING variables in analyzer scope
- Register code block parameters ({|x,y| ...}) as declared
- 2-pass multi-file build: collect cross-file function names before analysis
- Add QUIT, ERRORLEVEL, ALTSRC to builtin constants
All 3 test suites pass with 0 warnings:
go test ./... — ALL PASS
FiveSql2 43/43 — 100%
compat_harbour 51/51 — 100%
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ package main
|
||||
|
||||
import (
|
||||
"five/compiler/analyzer"
|
||||
"five/compiler/ast"
|
||||
"five/compiler/gengo"
|
||||
"five/compiler/genpc"
|
||||
"five/compiler/parser"
|
||||
@@ -199,10 +200,42 @@ func buildMultiPRG(prgFiles []string, output string) {
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
// Compile each PRG to a .go file
|
||||
// First file with MAIN gets Generate(), rest get GenerateLibrary()
|
||||
for i, prgFile := range prgFiles {
|
||||
goCode := compilePRGMode(prgFile, i > 0) // i>0 = library mode
|
||||
// Phase 1: Parse all files and collect cross-file function names
|
||||
type parsedFile struct {
|
||||
file *ast.File
|
||||
prgFile string
|
||||
}
|
||||
var parsed []parsedFile
|
||||
crossFileFuncs := make(map[string]bool)
|
||||
|
||||
for _, prgFile := range prgFiles {
|
||||
f := parsePRGFile(prgFile)
|
||||
parsed = append(parsed, parsedFile{file: f, prgFile: prgFile})
|
||||
for _, d := range f.Decls {
|
||||
switch decl := d.(type) {
|
||||
case *ast.FuncDecl:
|
||||
crossFileFuncs[strings.ToUpper(decl.Name)] = true
|
||||
case *ast.ClassDecl:
|
||||
crossFileFuncs[strings.ToUpper(decl.Name)] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2: Analyze and generate each file with cross-file function awareness
|
||||
for i, pf := range parsed {
|
||||
diags := analyzer.Analyze(pf.file, crossFileFuncs)
|
||||
for _, d := range diags {
|
||||
if d.Severity <= analyzer.SevWarning {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", d)
|
||||
}
|
||||
}
|
||||
|
||||
var goCode string
|
||||
if i > 0 {
|
||||
goCode = gengo.GenerateLibrary(pf.file)
|
||||
} else {
|
||||
goCode = gengo.Generate(pf.file)
|
||||
}
|
||||
goFile := fmt.Sprintf("prg_%d.go", i)
|
||||
writeFile(filepath.Join(tmpDir, goFile), goCode)
|
||||
}
|
||||
@@ -250,6 +283,48 @@ func buildMultiPRGWithIncludes(prgFiles []string, output string, includes []stri
|
||||
buildMultiPRG(prgFiles, output)
|
||||
}
|
||||
|
||||
// parsePRGFile preprocesses and parses a PRG file, returning the AST.
|
||||
func parsePRGFile(prgFile string) *ast.File {
|
||||
source, err := os.ReadFile(prgFile)
|
||||
if err != nil {
|
||||
fatal("cannot read file: " + err.Error())
|
||||
}
|
||||
|
||||
pre := pp.New()
|
||||
pre.AddIncludeDir(filepath.Dir(prgFile))
|
||||
pre.AddIncludeDir(filepath.Join(filepath.Dir(prgFile), "include"))
|
||||
fiveRoot := findFiveRoot()
|
||||
pre.AddIncludeDir(filepath.Join(fiveRoot, "include"))
|
||||
if exePath, err := os.Executable(); err == nil {
|
||||
pre.AddIncludeDir(filepath.Join(filepath.Dir(exePath), "include"))
|
||||
}
|
||||
for _, dir := range userIncludeDirs {
|
||||
pre.AddIncludeDir(dir)
|
||||
}
|
||||
if hbInc := os.Getenv("HB_INC"); hbInc != "" {
|
||||
pre.AddIncludeDir(hbInc)
|
||||
}
|
||||
for _, p := range []string{"/usr/local/include/harbour", "/usr/include/harbour"} {
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
pre.AddIncludeDir(p)
|
||||
}
|
||||
}
|
||||
|
||||
processed, ppErrors := pre.Process(prgFile, string(source))
|
||||
for _, e := range ppErrors {
|
||||
fmt.Fprintf(os.Stderr, "pp: %s\n", e)
|
||||
}
|
||||
|
||||
file, errs := parser.ParseWithGoDumps(prgFile, processed, pre.GoDumps)
|
||||
if len(errs) > 0 {
|
||||
for _, e := range errs {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", e)
|
||||
}
|
||||
fatal(fmt.Sprintf("%d parse error(s) in %s", len(errs), prgFile))
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
// compilePRGMode compiles with library flag support.
|
||||
func compilePRGMode(prgFile string, isLibrary bool) string {
|
||||
source, err := os.ReadFile(prgFile)
|
||||
|
||||
Reference in New Issue
Block a user