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)
|
||||
|
||||
@@ -65,20 +65,23 @@ type VarInfo struct {
|
||||
|
||||
// Analyzer performs semantic analysis on a parsed AST file.
|
||||
type Analyzer struct {
|
||||
file *ast.File
|
||||
diagnostics []Diagnostic
|
||||
scope *Scope
|
||||
funcNames map[string]bool // declared function names
|
||||
file *ast.File
|
||||
diagnostics []Diagnostic
|
||||
scope *Scope
|
||||
funcNames map[string]bool // declared function names (this file + external)
|
||||
moduleStatics map[string]VarInfo // module-level STATIC variables
|
||||
}
|
||||
|
||||
// Analyze runs semantic analysis and returns diagnostics.
|
||||
func Analyze(file *ast.File) []Diagnostic {
|
||||
// externalFuncs (optional) provides function names from other files in multi-file builds.
|
||||
func Analyze(file *ast.File, externalFuncs ...map[string]bool) []Diagnostic {
|
||||
a := &Analyzer{
|
||||
file: file,
|
||||
funcNames: make(map[string]bool),
|
||||
file: file,
|
||||
funcNames: make(map[string]bool),
|
||||
moduleStatics: make(map[string]VarInfo),
|
||||
}
|
||||
|
||||
// Phase 1: Collect all function names
|
||||
// Phase 1: Collect all function names from this file
|
||||
for _, d := range file.Decls {
|
||||
switch decl := d.(type) {
|
||||
case *ast.FuncDecl:
|
||||
@@ -88,6 +91,26 @@ func Analyze(file *ast.File) []Diagnostic {
|
||||
}
|
||||
}
|
||||
|
||||
// Merge external function names (from other PRG files in multi-file build)
|
||||
for _, ext := range externalFuncs {
|
||||
for name := range ext {
|
||||
a.funcNames[name] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 1.5: Collect module-level STATIC variables
|
||||
for _, d := range file.Decls {
|
||||
if vd, ok := d.(*ast.VarDecl); ok && vd.Scope == ast.ScopeStatic {
|
||||
for _, v := range vd.Vars {
|
||||
a.moduleStatics[strings.ToUpper(v.Name)] = VarInfo{
|
||||
Name: v.Name,
|
||||
Pos: v.NamePos,
|
||||
Kind: ast.ScopeStatic,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2: Analyze each function
|
||||
for _, d := range file.Decls {
|
||||
switch decl := d.(type) {
|
||||
@@ -106,6 +129,11 @@ func (a *Analyzer) analyzeFunc(fn *ast.FuncDecl) {
|
||||
Used: make(map[string]bool),
|
||||
}
|
||||
|
||||
// Register module-level STATIC variables (visible to all functions in this file)
|
||||
for name, info := range a.moduleStatics {
|
||||
a.scope.Declared[name] = info
|
||||
}
|
||||
|
||||
// Register parameters as declared
|
||||
for _, p := range fn.Params {
|
||||
a.scope.Declared[strings.ToUpper(p.Name)] = VarInfo{
|
||||
@@ -211,6 +239,14 @@ func (a *Analyzer) analyzeStmt(stmt ast.Stmt) {
|
||||
for _, st := range s.Body {
|
||||
a.analyzeStmt(st)
|
||||
}
|
||||
// RECOVER USING var — declare the variable in scope
|
||||
if s.RecoverVar != "" {
|
||||
a.scope.Declared[strings.ToUpper(s.RecoverVar)] = VarInfo{
|
||||
Name: s.RecoverVar,
|
||||
Pos: s.BeginPos,
|
||||
Kind: ast.ScopeLocal,
|
||||
}
|
||||
}
|
||||
for _, st := range s.RecoverBody {
|
||||
a.analyzeStmt(st)
|
||||
}
|
||||
@@ -330,6 +366,14 @@ func (a *Analyzer) analyzeExpr(expr ast.Expr) {
|
||||
a.analyzeExpr(e.Values[i])
|
||||
}
|
||||
case *ast.BlockExpr:
|
||||
// Register block parameters (e.g., {|x,y| x + y})
|
||||
for _, p := range e.Params {
|
||||
a.scope.Declared[strings.ToUpper(p)] = VarInfo{
|
||||
Name: p,
|
||||
Pos: e.LBrace,
|
||||
IsParam: true,
|
||||
}
|
||||
}
|
||||
a.analyzeExpr(e.Body)
|
||||
case *ast.AliasExpr:
|
||||
a.analyzeExpr(e.Alias)
|
||||
@@ -388,48 +432,213 @@ func (a *Analyzer) markUsed(name string) {
|
||||
}
|
||||
}
|
||||
|
||||
// rtlFunctions contains all 479 RTL functions registered in hbrtl/register.go.
|
||||
// Generated from: grep -o 'hbrt.Sym("[^"]*"' hbrtl/register.go
|
||||
var rtlFunctions = map[string]bool{
|
||||
// Console
|
||||
"QOUT": true, "QQOUT": true,
|
||||
// String/Conversion
|
||||
"STR": true, "VAL": true, "LEN": true, "SUBSTR": true, "UPPER": true, "LOWER": true,
|
||||
"ALLTRIM": true, "LTRIM": true, "RTRIM": true, "TRIM": true, "SPACE": true,
|
||||
"PADR": true, "PADL": true, "PADC": true, "REPLICATE": true,
|
||||
// Type/Conversion
|
||||
"VALTYPE": true, "EMPTY": true, "ABS": true, "INT": true,
|
||||
// Array
|
||||
"AADD": true, "ADEL": true, "AINS": true, "ASIZE": true, "ACLONE": true,
|
||||
"ACOPY": true, "AFILL": true, "ASORT": true, "AEVAL": true, "ASCAN": true, "ATAIL": true,
|
||||
// Hash
|
||||
"HB_HASH": true, "HB_HGET": true, "HB_HSET": true, "HB_HDEL": true,
|
||||
"HB_HHASKEY": true, "HB_HKEYS": true, "HB_HVALUES": true,
|
||||
"HB_HPOS": true, "HB_HKEYAT": true, "HB_HVALUEAT": true, "HB_HCLONE": true,
|
||||
// Date/Time
|
||||
"DATE": true, "TIME": true, "YEAR": true, "MONTH": true, "DAY": true, "DOW": true,
|
||||
"SECONDS": true, "DTOC": true, "DTOS": true, "STOD": true, "CTOD": true,
|
||||
"CDOW": true, "CMONTH": true, "DAYS": true, "ELAPTIME": true, "AMPM": true, "SECS": true,
|
||||
// Eval
|
||||
"EVAL": true,
|
||||
// String Extended
|
||||
"AT": true, "LEFT": true, "RIGHT": true, "ASC": true, "CHR": true,
|
||||
"STRTRAN": true, "STUFF": true, "RAT": true, "HARDCR": true,
|
||||
"HB_STRREPLACE": true, "HB_NTOS": true, "DESCEND": true,
|
||||
"HB_VALTOSTR": true, "HB_VALTOEXP": true, "HB_CSTR": true,
|
||||
// Math
|
||||
"ROUND": true, "MAX": true, "MIN": true, "SQRT": true, "LOG": true, "EXP": true, "MOD": true,
|
||||
// Misc
|
||||
"TYPE": true, "PCOUNT": true, "BREAK": true, "ARRAY": true, "FCOUNT": true,
|
||||
"FIELDNAME": true, "SELECT": true, "FILE": true, "INKEY": true, "TRANSFORM": true,
|
||||
"SETDATEFORMAT": true, "SETEPOCH": true, "SETCENTURY": true,
|
||||
"IIF": true, "IF": true, "STRZERO": true, "OUTSTD": true,
|
||||
"CENTER": true, "SOUNDEX": true, "TONE": true,
|
||||
// Terminal
|
||||
"SETPOS": true, "ROW": true, "COL": true, "DEVPOS": true, "DEVOUT": true,
|
||||
"DISPOUT": true, "DEVOUTPICT": true, "DISPBOX": true, "CLS": true, "SCROLL": true,
|
||||
"SETCOLOR": true, "SETCURSOR": true, "MAXROW": true, "MAXCOL": true,
|
||||
// dbEdit/Browse
|
||||
"DBEDIT": true, "TBROWSEDB": true, "TBROWSENEW": true, "TBCOLUMNNEW": true,
|
||||
// RDD
|
||||
"EOF": true, "BOF": true, "FOUND": true, "RECNO": true, "RECCOUNT": true,
|
||||
"LASTREC": true, "DELETED": true, "FIELDGET": true, "FIELDPUT": true,
|
||||
"FIELDPOS": true, "FIELDBLOCK": true, "FIELDWBLOCK": true, "AFIELDS": true,
|
||||
"DBSTRUCT": true,
|
||||
// Database
|
||||
"ALIAS": true, "DBEVAL": true, "USED": true, "DBUSEAREA": true,
|
||||
"DBCLOSEAREA": true, "DBCLOSEALL": true, "DBGOTO": true, "DBSKIP": true,
|
||||
"DBGOTOP": true, "DBGOBOTTOM": true, "DBAPPEND": true, "DBDELETE": true,
|
||||
"DBRECALL": true, "DBCOMMIT": true, "DBRLOCK": true, "DBRUNLOCK": true,
|
||||
"DBSEEK": true, "DBSELECTAREA": true, "DBPACK": true, "DBZAP": true,
|
||||
"DBCREATE": true, "DBINFO": true, "DBORDERINFO": true, "DBSETINDEX": true,
|
||||
"RECALL": true, "PACK": true, "ZAP": true,
|
||||
"__DBPACK": true, "__DBZAP": true,
|
||||
// Locate/Filter
|
||||
"DBLOCATE": true, "__DBLOCATE": true, "__DBCONTINUE": true,
|
||||
"DBSETFILTER": true, "DBCLEARFILTER": true, "DBFILTER": true,
|
||||
// Encoding/Hashing
|
||||
"HB_MD5": true, "HB_SHA256": true, "HB_BASE64ENCODE": true,
|
||||
"HB_BASE64DECODE": true, "HB_CRC32": true,
|
||||
// Bit Operations
|
||||
"HB_BITAND": true, "HB_BITOR": true, "HB_BITXOR": true, "HB_BITNOT": true,
|
||||
"HB_BITSHIFT": true, "HB_BITTEST": true, "HB_BITSET": true, "HB_BITRESET": true,
|
||||
// Regex
|
||||
"HB_REGEXCOMP": true, "HB_REGEXMATCH": true, "HB_REGEXSPLIT": true,
|
||||
"HB_REGEXALL": true, "HB_REGEXREPLACE": true,
|
||||
// Memo
|
||||
"MEMOREAD": true, "MEMOWRIT": true, "MEMOTRAN": true, "MEMOLINE": true, "MLCOUNT": true,
|
||||
// Binary Conversion
|
||||
"BIN2I": true, "BIN2L": true, "BIN2W": true, "I2BIN": true, "L2BIN": true, "W2BIN": true,
|
||||
// Keyboard
|
||||
"LASTKEY": true, "NEXTKEY": true, "READKEY": true, "SETKEY": true,
|
||||
"KEYBOARD": true, "HB_KEYPUT": true, "HB_KEYCHAR": true, "HB_KEYINS": true,
|
||||
// Display
|
||||
"DISPBEGIN": true, "DISPEND": true, "DISPCOUNT": true,
|
||||
"SAVESCREEN": true, "RESTSCREEN": true, "ALERT": true,
|
||||
// Error Handling
|
||||
"ERRORBLOCK": true, "ERRORNEW": true, "DOSERROR": true, "FERROR": true, "ERRORSYS": true,
|
||||
// SET Commands
|
||||
"SET": true, "__SETDATEFORMAT": true, "__SETDECIMALS": true, "__SETEPOCH": true,
|
||||
"SETDELETED": true, "SETEXACT": true, "SETSOFTSEEK": true, "SETEXCLUSIVE": true,
|
||||
"SETFIXED": true, "SETCANCEL": true, "SETBELL": true, "SETCONFIRM": true,
|
||||
"SETINSERT": true, "SETESCAPE": true, "SETWRAP": true,
|
||||
"_SET_EXACT": true, "_SET_DELETED": true, "_SET_SOFTSEEK": true,
|
||||
"_SET_EXCLUSIVE": true, "_SET_DATEFORMAT": true, "_SET_DECIMALS": true, "_SET_EPOCH": true,
|
||||
// File I/O
|
||||
"FOPEN": true, "FCREATE": true, "FCLOSE": true, "FREAD": true, "FWRITE": true,
|
||||
"FSEEK": true, "FERASE": true, "FRENAME": true, "HB_FILEEXISTS": true,
|
||||
// Directory/Disk
|
||||
"CURDIR": true, "DIRCHANGE": true, "DIRECTORY": true, "DIRMAKE": true,
|
||||
"DIRREMOVE": true, "DISKSPACE": true,
|
||||
// Type Checking
|
||||
"HB_ISARRAY": true, "HB_ISBLOCK": true, "HB_ISCHAR": true, "HB_ISSTRING": true,
|
||||
"HB_ISDATE": true, "HB_ISDATETIME": true, "HB_ISLOGICAL": true, "HB_ISNUMERIC": true,
|
||||
"HB_ISOBJECT": true, "HB_ISHASH": true, "HB_ISNIL": true, "HB_ISPOINTER": true,
|
||||
"HB_ISEVALITEM": true, "HB_ISNULL": true,
|
||||
// OS/Environment
|
||||
"GETENV": true, "HB_GETENV": true, "SETENV": true, "HB_SETENV": true,
|
||||
"OS": true, "VERSION": true, "HB_RUN": true,
|
||||
"HB_FNAMEDIR": true, "HB_FNAMEEXT": true, "HB_FNAMENAME": true, "HB_FNAMEMERGE": true,
|
||||
"HB_FNAMESPLIT": true, "HB_FNAMEEXISTS": true, "HB_FNAMEEXTSET": true, "HB_FNAMENAMEEXT": true,
|
||||
// Character Classification
|
||||
"ISDIGIT": true, "ISALPHA": true, "ISALNUM": true,
|
||||
"ISUPPER": true, "ISLOWER": true, "ISSPACE": true,
|
||||
// Harbour Extensions
|
||||
"HB_ASCIIUPPER": true, "HB_ASCIILOWER": true,
|
||||
"HB_DEFAULT": true, "HB_DEFAULTVALUE": true,
|
||||
"HB_DISPOUTAT": true, "HB_DISPOUTATBOX": true, "HB_DISPBOX": true,
|
||||
"HB_COLORINDEX": true, "HB_LEFTEQ": true, "HB_LEFTEQI": true,
|
||||
"HB_VAL": true, "HB_TOKENGET": true, "HB_TOKENCOUNT": true,
|
||||
"__DEFAULTNIL": true, "MEMVARBLOCK": true,
|
||||
// Bitmap/Rushmore
|
||||
"BM_DBSETFILTER": true, "BM_DBSEEKWILD": true, "BM_TURBO": true,
|
||||
"BM_DBGETFILTERARRAY": true, "BM_DBSETFILTERARRAY": true,
|
||||
"BM_DBSETFILTERARRAYADD": true, "BM_DBSETFILTERARRAYDEL": true,
|
||||
// HBSIX Compatibility
|
||||
"SX_SETTAG": true, "SX_INDEXTAG": true, "SX_TAGORDER": true,
|
||||
"SX_TAGCOUNT": true, "SX_TAGS": true, "SX_SETFILEORD": true,
|
||||
"SX_ISDBT": true, "SX_ISFPT": true, "SX_ISSMT": true,
|
||||
"SX_AUTOOPEN": true, "SX_AUTOSHARE": true, "SX_BLOB2FILE": true,
|
||||
"SX_FILE2BLOB": true, "SX_SETTRIGGER": true, "SX_VFGET": true,
|
||||
"SX_DBFENCRYPT": true, "SX_DBFDECRYPT": true, "SX_COMPRESS": true,
|
||||
"SX_DECOMPRESS": true, "RDDINFO": true, "RDDNAME": true, "RDDLIST": true,
|
||||
// Timestamp
|
||||
"HB_DATETIME": true, "HB_HOUR": true, "HB_MINUTE": true, "HB_SEC": true,
|
||||
"HB_TTOC": true, "HB_CTOT": true, "HB_SECOND": true, "HB_ATOKENS": true,
|
||||
"HB_CDPSELECT": true, "HB_TTOS": true, "HB_STOT": true, "HB_MILLISECONDS": true,
|
||||
"HB_DATE": true, "HB_CTOD": true, "HB_DTOC": true, "HB_STOD": true,
|
||||
"HB_DTOT": true, "HB_TTOD": true, "HB_TTOHOUR": true, "HB_TTOMIN": true,
|
||||
"HB_TTOSEC": true, "HB_TTOMSEC": true, "HB_TTON": true, "HB_NTOT": true,
|
||||
"HB_NTOHOUR": true, "HB_NTOMIN": true, "HB_NTOSEC": true,
|
||||
"HB_WEEK": true, "HB_CDAY": true,
|
||||
// Index/DB Introspection
|
||||
"INDEXORD": true, "INDEXKEY": true, "ORDSETFOCUS": true, "ORDCOUNT": true,
|
||||
"ORDNAME": true, "ORDKEY": true, "ORDFOR": true, "ORDINFO": true,
|
||||
"ORDSCOPE": true, "RDDSETDEFAULT": true,
|
||||
// Directory/Temp
|
||||
"HB_DIREXISTS": true, "HB_DIRCREATE": true, "HB_FTEMPCREATE": true, "HB_DIRTEMP": true,
|
||||
// File Extended
|
||||
"HB_FSIZE": true, "HB_FCOPY": true, "HB_FEOF": true, "HB_FCOMMIT": true,
|
||||
"HB_FREADLEN": true, "HB_FGETATTR": true, "HB_FSETATTR": true,
|
||||
"HB_FGETDATETIME": true, "HB_FSETDATETIME": true, "HB_FLOCK": true, "HB_FUNLOCK": true,
|
||||
"HB_FILEDELETE": true, "HB_FILEMATCH": true,
|
||||
"HB_MEMOREAD": true, "HB_MEMOWRIT": true, "HB_DISKSPACE": true,
|
||||
// String Extended 2
|
||||
"HB_AT": true, "HB_RAT": true, "HB_ATI": true, "HB_ATX": true,
|
||||
"HB_ASCIIISALPHA": true, "HB_ASCIIISDIGIT": true,
|
||||
"HB_ASCIIISLOWER": true, "HB_ASCIIISUPPER": true,
|
||||
"HB_STRISUTF8": true, "HB_STRDECODESCAPE": true, "HB_STRXOR": true,
|
||||
"HB_WILDMATCH": true, "HB_WILDMATCHI": true,
|
||||
"HB_STRTOHEX": true, "HB_HEXTOSTR": true, "HB_STRFORMAT": true,
|
||||
// Hex Conversion
|
||||
"HB_NUMTOHEX": true, "HB_HEXTONUM": true,
|
||||
// Token
|
||||
"TOKEN": true, "NUMTOKEN": true,
|
||||
// Stack Introspection
|
||||
"PROCNAME": true, "PROCLINE": true, "PROCFILE": true, "ERRORLEVEL": true,
|
||||
// JSON
|
||||
"HB_JSONENCODE": true, "HB_JSONDECODE": true,
|
||||
"JSONPRETTY": true, "JSONTO": true, "JSONFROM": true, "JSONPATH": true,
|
||||
"JSONMERGE": true, "JSONTYPE": true, "JSONVALID": true,
|
||||
"JSONHTTPGET": true, "JSONHTTPPOST": true,
|
||||
// Random
|
||||
"HB_RANDOM": true, "HB_RANDOMINT": true, "HB_RANDOMSEED": true, "HB_RANDSTR": true,
|
||||
// OS Info
|
||||
"HB_VERSION": true, "HB_COMPILER": true, "HB_OSNEWLINE": true,
|
||||
"HB_OSPATHSEPARATOR": true, "HB_CWD": true, "HB_DIRBASE": true,
|
||||
"HB_PROGNAME": true, "HB_USERNAME": true, "HB_GETHOSTNAME": true,
|
||||
// Process
|
||||
"HB_PROCESSRUN": true, "WAIT": true,
|
||||
// UTF-8
|
||||
"HB_UTF8TOSTR": true, "HB_STRTOUTF8": true, "HB_UTF8LEN": true,
|
||||
"HB_UTF8SUBSTR": true, "HB_UTF8LEFT": true, "HB_UTF8RIGHT": true, "HB_UTF8AT": true,
|
||||
// FRB
|
||||
"FRBLOAD": true, "FRBDO": true, "FRBUNLOAD": true, "FRBRUN": true,
|
||||
"FRBCOMPILE": true, "FRBEXEC": true,
|
||||
// Concurrency
|
||||
"GO": true, "CHANNEL": true, "CHSEND": true, "CHRECEIVE": true, "CHCLOSE": true,
|
||||
"WAITGROUP": true, "WGDONE": true, "WGWAIT": true, "WGADD": true,
|
||||
"MUTEX": true, "LOCK": true, "UNLOCK": true, "SLEEP": true,
|
||||
// Harbour compat aliases
|
||||
"HB_SYMBOL_UNUSED": true, "HB_IDLEADD": true, "HB_IDLESLEEP": true,
|
||||
"HB_PS": true, "HB_EOL": true,
|
||||
}
|
||||
|
||||
func (a *Analyzer) isKnownFunction(name string) bool {
|
||||
// Check declared functions in this file
|
||||
// Check declared functions in this file (and external files)
|
||||
if a.funcNames[name] {
|
||||
return true
|
||||
}
|
||||
// Common RTL functions
|
||||
rtl := map[string]bool{
|
||||
"LEN": true, "SUBSTR": true, "LEFT": true, "RIGHT": true,
|
||||
"UPPER": true, "LOWER": true, "TRIM": true, "LTRIM": true, "RTRIM": true,
|
||||
"STR": true, "VAL": true, "STRTRAN": true, "AT": true, "RAT": true,
|
||||
"SPACE": true, "REPLICATE": true, "PADR": true, "PADL": true, "PADC": true,
|
||||
"VALTYPE": true, "TYPE": true, "EMPTY": true, "HB_ISSTRING": true,
|
||||
"EVAL": true, "AEVAL": true, "ASCAN": true, "ASORT": true,
|
||||
"AADD": true, "ADEL": true, "AINS": true, "ASIZE": true, "ACOPY": true, "ACLONE": true,
|
||||
"ARRAY": true, "HASH": true, "HB_HASH": true,
|
||||
"DTOC": true, "CTOD": true, "DTOS": true, "DATE": true, "TIME": true, "YEAR": true, "MONTH": true, "DAY": true,
|
||||
"QOUT": true, "QQOUT": true, "OUTSTD": true, "ALERT": true,
|
||||
"INKEY": true, "LASTKEY": true, "CHR": true, "ASC": true,
|
||||
"FILE": true, "FOPEN": true, "FCLOSE": true, "FREAD": true, "FWRITE": true,
|
||||
"IIF": true, "IF": true, "STRZERO": true, "TRANSFORM": true,
|
||||
"FIELDNAME": true, "FIELDPUT": true, "FIELDGET": true, "FCOUNT": true,
|
||||
"ALIAS": true, "DBAPPEND": true, "DBDELETE": true, "DBSKIP": true,
|
||||
"DBGOTO": true, "DBGOTOP": true, "DBGOBOTTOM": true, "DBCOMMIT": true,
|
||||
"RECNO": true, "RECCOUNT": true, "EOF": true, "BOF": true, "FOUND": true,
|
||||
"CHANNEL": true, "CHSEND": true, "CHRECEIVE": true,
|
||||
"SLEEP": true, "HB_IDLEADD": true, "SECONDS": true,
|
||||
"ERRORBLOCK": true, "BREAK": true, "PCOUNT": true, "PROCNAME": true,
|
||||
"SETPOS": true, "ROW": true, "COL": true, "MAXROW": true, "MAXCOL": true,
|
||||
"ABS": true, "INT": true, "ROUND": true, "SQRT": true, "LOG": true, "EXP": true,
|
||||
"MAX": true, "MIN": true, "MOD": true,
|
||||
"SETCOLOR": true, "DISPBOX": true, "DISPBEGIN": true, "DISPEND": true,
|
||||
"HB_SYMBOL_UNUSED": true, "HB_DEFAULT": true, "HB_NTOS": true,
|
||||
}
|
||||
return rtl[name]
|
||||
return rtlFunctions[name]
|
||||
}
|
||||
|
||||
func (a *Analyzer) isBuiltinConstant(name string) bool {
|
||||
constants := map[string]bool{
|
||||
"NIL": true, "TRUE": true, "FALSE": true,
|
||||
"SELF": true, "SUPER": true,
|
||||
// Harbour commands treated as identifiers
|
||||
"QUIT": true, "ERRORLEVEL": true,
|
||||
// Keyboard constants
|
||||
"K_ESC": true, "K_ENTER": true, "K_UP": true, "K_DOWN": true,
|
||||
"K_LEFT": true, "K_RIGHT": true, "K_PGUP": true, "K_PGDN": true,
|
||||
// Alternate source (SET ALTERNATE)
|
||||
"ALTSRC": true,
|
||||
}
|
||||
return constants[name]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user