Files
five/compiler/analyzer/analyzer_test.go
Charles KWON OhJun 59568f3301 Five v0.9 — Harbour + Go fusion language
- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline
- Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch
- RTL: 351 Harbour-compatible functions
- RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization
- Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec)
- HB_FUNC API: Full Harbour C API compatible Go bridge
- Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT
- Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST
- Macro Compiler: Runtime AST parsing and evaluation
- Debugger: TUI debugger with source display, breakpoints, stepping
- FRB: Native + Pcode dual mode runtime binary
- Tests: 13 packages ALL PASS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:41:50 +09:00

137 lines
2.4 KiB
Go

package analyzer
import (
"five/compiler/parser"
"strings"
"testing"
)
func analyze(t *testing.T, source string) []Diagnostic {
t.Helper()
file, errs := parser.Parse("test.prg", source)
if len(errs) > 0 {
t.Fatalf("parse error: %s", errs[0])
}
return Analyze(file)
}
func TestCleanCode(t *testing.T) {
diags := analyze(t, `
PROCEDURE Main()
LOCAL cName, nAge
cName := "Charles"
nAge := 30
? cName, nAge
RETURN
`)
for _, d := range diags {
if d.Severity == SevError || d.Severity == SevWarning {
t.Errorf("unexpected diagnostic: %s", d)
}
}
}
func TestUndeclaredVariable(t *testing.T) {
diags := analyze(t, `
PROCEDURE Main()
LOCAL cName
cName := "Charles"
? cName, nAge
RETURN
`)
found := false
for _, d := range diags {
if strings.Contains(d.Message, "undeclared") && strings.Contains(d.Message, "nAge") {
found = true
}
}
if !found {
t.Error("expected 'undeclared variable nAge' warning")
}
}
func TestUnusedVariable(t *testing.T) {
diags := analyze(t, `
PROCEDURE Main()
LOCAL cUsed, cNeverTouched
cUsed := "hello"
? cUsed
RETURN
`)
found := false
for _, d := range diags {
if strings.Contains(d.Message, "unused") && strings.Contains(d.Message, "cNeverTouched") {
found = true
}
}
if !found {
t.Error("expected 'unused variable cNeverTouched' hint")
}
}
func TestParamsDeclared(t *testing.T) {
diags := analyze(t, `
FUNCTION Add(a, b)
LOCAL nResult
nResult := a + b
RETURN nResult
`)
for _, d := range diags {
if d.Severity == SevError || d.Severity == SevWarning {
t.Errorf("unexpected: %s", d)
}
}
}
func TestMultiFunction(t *testing.T) {
diags := analyze(t, `
PROCEDURE Main()
LOCAL n
n := GetValue()
? n
RETURN
FUNCTION GetValue()
LOCAL x
x := 42
RETURN x
`)
for _, d := range diags {
if d.Severity == SevWarning {
t.Errorf("unexpected warning: %s", d)
}
}
}
func TestForLoopVar(t *testing.T) {
diags := analyze(t, `
PROCEDURE Main()
LOCAL i, aData
aData := {1, 2, 3}
FOR i := 1 TO Len(aData)
? aData[i]
NEXT
RETURN
`)
for _, d := range diags {
if d.Severity == SevWarning {
t.Errorf("unexpected: %s", d)
}
}
}
func TestMultiAssignDeclared(t *testing.T) {
diags := analyze(t, `
PROCEDURE Main()
LOCAL cName, nAge
cName, nAge := "Charles", 30
? cName, nAge
RETURN
`)
for _, d := range diags {
if d.Severity == SevWarning {
t.Errorf("unexpected: %s", d)
}
}
}