- 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>
287 lines
10 KiB
Plaintext
287 lines
10 KiB
Plaintext
// Five Go Interop — FULL Type Test
|
|
// Tests every Go ↔ PRG type conversion.
|
|
|
|
IMPORT "strings"
|
|
IMPORT "strconv"
|
|
IMPORT "fmt"
|
|
IMPORT "math"
|
|
IMPORT "os"
|
|
IMPORT "path/filepath"
|
|
IMPORT "time"
|
|
IMPORT "encoding/json"
|
|
IMPORT "encoding/base64"
|
|
IMPORT "crypto/sha256"
|
|
IMPORT "sort"
|
|
IMPORT "regexp"
|
|
IMPORT "net/url"
|
|
IMPORT "sync"
|
|
|
|
PROCEDURE Main()
|
|
LOCAL cResult, nResult, lResult, nFloat
|
|
LOCAL aParts, cJoined, i
|
|
LOCAL hMap, aKeys, aBytes
|
|
LOCAL cJSON, cB64, cHash
|
|
LOCAL cPath, cDir, cFile
|
|
LOCAL tNow, nYear
|
|
LOCAL oMutex, oURL
|
|
LOCAL nLong, cFormatted
|
|
|
|
? "=========================================="
|
|
? " Five Go Type Test — ALL Types"
|
|
? "=========================================="
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 1. STRING: PRG String ↔ Go string
|
|
// -------------------------------------------------------
|
|
? "[1] String ↔ string"
|
|
cResult := strings.ToUpper("hello five")
|
|
Assert(cResult == "HELLO FIVE", "ToUpper")
|
|
cResult := strings.TrimSpace(" spaced ")
|
|
Assert(cResult == "spaced", "TrimSpace")
|
|
cResult := strings.ReplaceAll("a-b-c", "-", "_")
|
|
Assert(cResult == "a_b_c", "ReplaceAll")
|
|
cResult := strings.Repeat("ab", 3)
|
|
Assert(cResult == "ababab", "Repeat")
|
|
cResult := strings.ToTitle("hello world")
|
|
Assert(cResult == "HELLO WORLD", "ToTitle")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 2. BOOL: PRG Logical ↔ Go bool
|
|
// -------------------------------------------------------
|
|
? "[2] Logical ↔ bool"
|
|
lResult := strings.Contains("hello five", "five")
|
|
Assert(lResult, "Contains true")
|
|
lResult := strings.Contains("hello five", "xyz")
|
|
Assert(!lResult, "Contains false")
|
|
lResult := strings.HasPrefix("hello", "hel")
|
|
Assert(lResult, "HasPrefix")
|
|
lResult := strings.HasSuffix("world", "rld")
|
|
Assert(lResult, "HasSuffix")
|
|
lResult := strings.EqualFold("Hello", "hello")
|
|
Assert(lResult, "EqualFold")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 3. INT: PRG Numeric(int) ↔ Go int
|
|
// -------------------------------------------------------
|
|
? "[3] Numeric(int) ↔ int"
|
|
nResult := strings.Count("aabbaab", "aa")
|
|
Assert(nResult == 2, "Count")
|
|
nResult := strings.Index("hello", "ll")
|
|
Assert(nResult == 2, "Index")
|
|
nResult := strings.LastIndex("abcabc", "bc")
|
|
Assert(nResult == 4, "LastIndex")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 4. LONG: PRG Numeric(long) ↔ Go int64
|
|
// -------------------------------------------------------
|
|
? "[4] Numeric(long) ↔ int64"
|
|
nLong := time.Now():UnixMilli()
|
|
Assert(nLong > 1000000000000, "UnixMilli is large int64")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 5. FLOAT: PRG Numeric(double) ↔ Go float64
|
|
// -------------------------------------------------------
|
|
? "[5] Numeric(double) ↔ float64"
|
|
nFloat := math.Sqrt(144)
|
|
Assert(nFloat == 12, "Sqrt(144)")
|
|
nFloat := math.Round(3.7)
|
|
Assert(nFloat == 4, "Round(3.7)")
|
|
nFloat := math.Abs(-42.5)
|
|
Assert(nFloat == 42.5, "Abs(-42.5)")
|
|
nFloat := math.Floor(3.9)
|
|
Assert(nFloat == 3, "Floor(3.9)")
|
|
nFloat := math.Ceil(3.1)
|
|
Assert(nFloat == 4, "Ceil(3.1)")
|
|
nFloat := math.Max(10, 20)
|
|
Assert(nFloat == 20, "Max(10,20)")
|
|
nFloat := math.Min(10, 20)
|
|
Assert(nFloat == 10, "Min(10,20)")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 6. ARRAY: PRG Array ↔ Go []string / []int
|
|
// -------------------------------------------------------
|
|
? "[6] Array ↔ slice"
|
|
aParts := strings.Split("one,two,three", ",")
|
|
Assert(Len(aParts) == 3, "Split len=3")
|
|
Assert(aParts[1] == "one", "Split[1]")
|
|
Assert(aParts[2] == "two", "Split[2]")
|
|
Assert(aParts[3] == "three", "Split[3]")
|
|
// PRG array → Go []string
|
|
cJoined := strings.Join(aParts, "-")
|
|
Assert(cJoined == "one-two-three", "Join")
|
|
// Split then Join roundtrip
|
|
cResult := strings.Join(strings.Split("x|y|z", "|"), ",")
|
|
Assert(cResult == "x,y,z", "Split+Join roundtrip")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 7. NIL: PRG NIL ↔ Go nil / zero value
|
|
// -------------------------------------------------------
|
|
? "[7] NIL ↔ nil"
|
|
cResult := strings.ToUpper("")
|
|
Assert(cResult == "", "empty string → empty")
|
|
// strconv.Atoi returns (int, error) — first val only
|
|
nResult := strconv.Atoi("0")
|
|
Assert(nResult == 0, "Atoi zero")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 8. VARIADIC: mixed types → Go ...interface{}
|
|
// -------------------------------------------------------
|
|
? "[8] Variadic (mixed types)"
|
|
cFormatted := fmt.Sprintf("s=%s i=%d f=%.1f b=%t", "abc", 42, 3.14, .T.)
|
|
Assert(cFormatted == "s=abc i=42 f=3.1 b=true", "Sprintf mixed")
|
|
cFormatted := fmt.Sprintf("%d+%d=%d", 10, 20, 30)
|
|
Assert(cFormatted == "10+20=30", "Sprintf ints")
|
|
cFormatted := fmt.Sprintf("[%10s]", "right")
|
|
Assert(cFormatted == "[ right]", "Sprintf padded")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 9. BYTES: PRG String ↔ Go []byte
|
|
// -------------------------------------------------------
|
|
? "[9] String ↔ []byte"
|
|
// base64 encode/decode uses []byte
|
|
cB64 := base64.StdEncoding:EncodeToString("Hello Five!")
|
|
Assert(cB64 == "SGVsbG8gRml2ZSE=", "Base64 encode")
|
|
// sha256 produces []byte → hex string
|
|
aBytes := sha256.Sum256("test")
|
|
Assert(aBytes != NIL, "SHA256 returns value")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 10. GO OBJECT: PRG Value wrapping Go *struct
|
|
// -------------------------------------------------------
|
|
? "[10] Go Object (pointer)"
|
|
// sync.Mutex — create and use Go object
|
|
oMutex := sync.Mutex{}
|
|
Assert(oMutex != NIL, "Mutex created")
|
|
// url.Parse returns *url.URL
|
|
oURL := url.Parse("https://five-lang.dev/docs?q=hello")
|
|
Assert(oURL != NIL, "URL parsed")
|
|
cResult := oURL:String()
|
|
Assert(strings.Contains(cResult, "five-lang"), "URL.String()")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 11. GO OBJECT METHOD CHAIN
|
|
// -------------------------------------------------------
|
|
? "[11] Method chain"
|
|
// strings.NewReplacer returns *Replacer with method Replace
|
|
LOCAL oReplacer
|
|
oReplacer := strings.NewReplacer("a", "1", "b", "2", "c", "3")
|
|
cResult := oReplacer:Replace("abc")
|
|
Assert(cResult == "123", "Replacer.Replace")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 12. strconv: int↔string roundtrip
|
|
// -------------------------------------------------------
|
|
? "[12] strconv roundtrip"
|
|
cResult := strconv.Itoa(12345)
|
|
Assert(cResult == "12345", "Itoa")
|
|
nResult := strconv.Atoi("67890")
|
|
Assert(nResult == 67890, "Atoi")
|
|
// FormatFloat
|
|
cResult := strconv.FormatFloat(3.14159, 102, 2, 64)
|
|
Assert(cResult == "3.14", "FormatFloat")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 13. CHAINED: nested Go calls
|
|
// -------------------------------------------------------
|
|
? "[13] Chained calls"
|
|
cResult := strings.ToUpper(strings.TrimSpace(" hello "))
|
|
Assert(cResult == "HELLO", "Upper(Trim())")
|
|
nResult := strings.Count(strings.ToLower("AABAA"), "a")
|
|
Assert(nResult == 4, "Count(Lower())")
|
|
cResult := strings.Join(strings.Split(strings.ToLower("A.B.C"), "."), "/")
|
|
Assert(cResult == "a/b/c", "Join(Split(Lower()))")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 14. LOOP: Go calls inside FOR loop
|
|
// -------------------------------------------------------
|
|
? "[14] Loop with Go calls"
|
|
aParts := strings.Split("alpha,beta,gamma,delta", ",")
|
|
FOR i := 1 TO Len(aParts)
|
|
aParts[i] := strings.ToUpper(aParts[i])
|
|
NEXT
|
|
cJoined := strings.Join(aParts, "/")
|
|
Assert(cJoined == "ALPHA/BETA/GAMMA/DELTA", "Loop ToUpper")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 15. FILE PATH: os / filepath
|
|
// -------------------------------------------------------
|
|
? "[15] os / filepath"
|
|
cPath := filepath.Join("usr", "local", "bin")
|
|
Assert(strings.Contains(cPath, "local"), "filepath.Join")
|
|
cDir := filepath.Dir("/home/user/file.txt")
|
|
Assert(strings.Contains(cDir, "user"), "filepath.Dir")
|
|
cFile := filepath.Base("/home/user/file.txt")
|
|
Assert(cFile == "file.txt", "filepath.Base")
|
|
cResult := filepath.Ext("document.pdf")
|
|
Assert(cResult == ".pdf", "filepath.Ext")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 16. TIME: Go time package
|
|
// -------------------------------------------------------
|
|
? "[16] time"
|
|
tNow := time.Now()
|
|
Assert(tNow != NIL, "time.Now()")
|
|
nYear := tNow:Year()
|
|
Assert(nYear >= 2026, "Year >= 2026")
|
|
cResult := tNow:Format("2006-01-02")
|
|
Assert(Len(cResult) == 10, "Format YYYY-MM-DD")
|
|
? " Today:", cResult
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 17. JSON: encode/decode
|
|
// -------------------------------------------------------
|
|
? "[17] JSON"
|
|
cJSON := json.Marshal({"name" => "Five", "version" => 1})
|
|
Assert(cJSON != NIL, "json.Marshal")
|
|
?
|
|
|
|
// -------------------------------------------------------
|
|
// 18. REGEXP
|
|
// -------------------------------------------------------
|
|
? "[18] regexp"
|
|
LOCAL oRe
|
|
oRe := regexp.MustCompile("[0-9]+")
|
|
lResult := oRe:MatchString("abc123def")
|
|
Assert(lResult, "regexp.MatchString")
|
|
cResult := oRe:FindString("abc123def")
|
|
Assert(cResult == "123", "regexp.FindString")
|
|
aParts := oRe:FindAllString("a1b22c333", -1)
|
|
Assert(Len(aParts) == 3, "FindAllString len")
|
|
Assert(aParts[1] == "1", "FindAllString[1]")
|
|
Assert(aParts[2] == "22", "FindAllString[2]")
|
|
Assert(aParts[3] == "333", "FindAllString[3]")
|
|
?
|
|
|
|
? "=========================================="
|
|
? " ALL TESTS COMPLETE"
|
|
? "=========================================="
|
|
|
|
RETURN
|
|
|
|
// Assert helper
|
|
PROCEDURE Assert(lCondition, cName)
|
|
IF lCondition
|
|
?? " " + PadR(cName, 30) + " OK"
|
|
ELSE
|
|
?? " " + PadR(cName, 30) + " *** FAIL ***"
|
|
ENDIF
|
|
?
|
|
RETURN
|