- five-syntax-en/ko: Add Math comparison table (Harbour RTL vs Go math) - go_math_compare.prg: Detailed English comments explaining each section - Example lists updated with go_math_compare.prg Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
441 lines
12 KiB
Markdown
441 lines
12 KiB
Markdown
# Five Language Syntax Reference
|
|
|
|
Five = 100% Harbour compatible + Go extended syntax.
|
|
Existing PRG code runs without modification, and Go's powerful features are available in PRG syntax.
|
|
|
|
## Harbour Compatible Syntax (98% parsing)
|
|
|
|
Full support for all Harbour/Clipper/xBase syntax:
|
|
|
|
```prg
|
|
FUNCTION, PROCEDURE, RETURN, LOCAL, STATIC, PRIVATE, PUBLIC
|
|
IF/ELSEIF/ELSE/ENDIF, DO CASE/CASE/OTHERWISE/ENDCASE
|
|
FOR/NEXT, FOR EACH/NEXT, DO WHILE/ENDDO
|
|
BEGIN SEQUENCE/RECOVER/END, SWITCH/CASE/ENDSWITCH
|
|
CLASS/DATA/METHOD/ACCESS/ASSIGN/ENDCLASS
|
|
USE, SELECT, SEEK, SKIP, GO, APPEND, REPLACE, DELETE, PACK
|
|
@ SAY/GET/READ, MENU TO, SET, INDEX ON
|
|
```
|
|
|
|
## Five Go Extensions
|
|
|
|
### 1. IMPORT — Direct Go Package Access
|
|
|
|
```prg
|
|
IMPORT "strings" // Go standard library
|
|
IMPORT "database/sql" // SQL database
|
|
IMPORT _ "modernc.org/sqlite" // blank import (driver registration)
|
|
IMPORT myhttp "net/http" // aliased import
|
|
```
|
|
|
|
After IMPORT, use directly from PRG:
|
|
|
|
```prg
|
|
IMPORT "strings"
|
|
|
|
PROCEDURE Main()
|
|
LOCAL cResult
|
|
cResult := strings.ToUpper("hello five") // Direct Go function call
|
|
? strings.Contains(cResult, "FIVE") // .T.
|
|
? strings.Split("a,b,c", ",") // {"a","b","c"}
|
|
RETURN
|
|
```
|
|
|
|
**No #pragma BEGINDUMP needed. IMPORT gives access to Go's entire ecosystem.**
|
|
|
|
### 2. Multi-Return — Multiple Return Values
|
|
|
|
```prg
|
|
// Return multiple values from a function
|
|
FUNCTION GetUserInfo()
|
|
RETURN "Charles", 30, "Seoul"
|
|
|
|
// Receive multiple values
|
|
cName, nAge, cCity := GetUserInfo()
|
|
|
|
// Discard unwanted values with blank identifier
|
|
_, nAge, _ := GetUserInfo()
|
|
```
|
|
|
|
Natural support for Go's `(val, error)` pattern:
|
|
|
|
```prg
|
|
IMPORT "database/sql"
|
|
db, err := sql.Open("sqlite", ":memory:")
|
|
IF err != NIL
|
|
? "Error:", err
|
|
ENDIF
|
|
```
|
|
|
|
### 3. DEFER — Automatic Cleanup
|
|
|
|
Executes when the function returns. Guaranteed even on errors.
|
|
|
|
```prg
|
|
PROCEDURE ProcessFile(cPath)
|
|
LOCAL db
|
|
db := sql.Open("sqlite", cPath)
|
|
DEFER db:Close() // Auto-Close when function ends
|
|
|
|
db:Exec("INSERT ...") // Even if error occurs here
|
|
db:Exec("UPDATE ...") // db:Close() will always execute
|
|
RETURN // ← DEFER executes here
|
|
```
|
|
|
|
More concise than Harbour's `BEGIN SEQUENCE/RECOVER`:
|
|
|
|
```
|
|
Before (Harbour): After (Five):
|
|
─────────────────────────────── ─────────────────────
|
|
BEGIN SEQUENCE db := SqlOpen(...)
|
|
db := SqlOpen(...) DEFER db:Close()
|
|
db:Exec(...) db:Exec(...)
|
|
RECOVER RETURN
|
|
db:Close()
|
|
END SEQUENCE
|
|
db:Close()
|
|
```
|
|
|
|
### 4. Slice — Sub-array / Sub-string
|
|
|
|
```prg
|
|
LOCAL aData := {"a", "b", "c", "d", "e"}
|
|
|
|
aSub := aData[2:4] // {"b", "c", "d"}
|
|
aSub := aData[3:] // {"c", "d", "e"} (from 3 to end)
|
|
aSub := aData[:2] // {"a", "b"} (from start to 2)
|
|
```
|
|
|
|
Replaces verbose Harbour loops:
|
|
|
|
```
|
|
Before: After:
|
|
─────────────────────────────── ─────────────────────
|
|
LOCAL aSub := {} aSub := aData[3:7]
|
|
FOR i := 3 TO 7
|
|
AAdd(aSub, aData[i])
|
|
NEXT
|
|
```
|
|
|
|
### 5. Parallel Assignment — Simultaneous Assign
|
|
|
|
```prg
|
|
// Swap values (no temp variable needed!)
|
|
a, b := b, a
|
|
|
|
// Simultaneous initialization
|
|
x, y, z := 1, 2, 3
|
|
```
|
|
|
|
### 6. Nil-Safe Operator — `?:`
|
|
|
|
```prg
|
|
// Before: repeated NIL checks
|
|
IF oCustomer != NIL
|
|
IF oCustomer:Address != NIL
|
|
? oCustomer:Address:City
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Five: one line
|
|
? oCustomer?:Address?:City // Returns NIL if any part is NIL
|
|
```
|
|
|
|
### 7. String Interpolation — `f"..."`
|
|
|
|
```prg
|
|
LOCAL cName := "Charles", nAge := 30
|
|
|
|
// Before
|
|
? "Name: " + cName + " Age: " + Str(nAge)
|
|
|
|
// Five
|
|
? f"Name: {cName}, Age: {nAge}"
|
|
|
|
// With format specifiers
|
|
? f"Price: {nPrice:.2f}, Count: {nCount:05d}"
|
|
```
|
|
|
|
### 8. CONST Block — Constants / Enums
|
|
|
|
```prg
|
|
CONST
|
|
STATUS_ACTIVE := 1
|
|
STATUS_CLOSED := 2
|
|
STATUS_PENDING := 3
|
|
END CONST
|
|
```
|
|
|
|
### 9. SWITCH (Harbour compatible + extended)
|
|
|
|
```prg
|
|
// Standard Harbour syntax works as-is
|
|
SWITCH nStatus
|
|
CASE 1
|
|
? "Active"
|
|
CASE 2
|
|
? "Closed"
|
|
OTHERWISE
|
|
? "Unknown"
|
|
ENDSWITCH
|
|
```
|
|
|
|
## Five Concurrency Syntax
|
|
|
|
### 10. Channel Operators — `<-`
|
|
|
|
```prg
|
|
ch := Channel()
|
|
|
|
ch <- "hello" // Send to channel
|
|
msg := <- ch // Receive from channel
|
|
```
|
|
|
|
Harbour functions vs Five operators:
|
|
|
|
```
|
|
Harbour functions: Five operators:
|
|
─────────────────────────────── ─────────────────────
|
|
ChSend(ch, "hello") ch <- "hello"
|
|
msg := ChReceive(ch) msg := <- ch
|
|
ChSend(chOut, nResult) chOut <- nResult
|
|
```
|
|
|
|
### 11. SPAWN / LAUNCH / GOROUTINE — Inline Goroutine
|
|
|
|
Three keywords, same behavior — choose your preference:
|
|
|
|
```prg
|
|
SPAWN {|| DoHeavyWork() }
|
|
LAUNCH {|| ProcessData() }
|
|
GOROUTINE {|| SendNotification() }
|
|
```
|
|
|
|
### 12. WATCH — Channel Multiplexing (Go select)
|
|
|
|
Monitor multiple channels simultaneously, process the first one ready:
|
|
|
|
```prg
|
|
WATCH
|
|
CASE msg := <- chMessages // Message arrived
|
|
? "Message:", msg
|
|
CASE result := <- chResults // Result arrived
|
|
? "Result:", result
|
|
CASE <- chTimeout // Timeout
|
|
? "Timeout!"
|
|
OTHERWISE // No channel ready
|
|
? "No channel ready"
|
|
END WATCH
|
|
```
|
|
|
|
**Real-world pattern: Select fastest server response**
|
|
|
|
```prg
|
|
SPAWN {|| DelayAndSend(0.1, chFast, "Fast Server") }
|
|
SPAWN {|| DelayAndSend(2.0, chSlow, "Slow Server") }
|
|
SPAWN {|| DelayAndSend(3.0, chTimeout, "TIMEOUT") }
|
|
|
|
WATCH
|
|
CASE cResult := <- chFast
|
|
? "Winner:", cResult // ← Selected (fastest at 100ms)
|
|
CASE cResult := <- chSlow
|
|
? "Winner:", cResult
|
|
CASE <- chTimeout
|
|
? "Timeout!"
|
|
END WATCH
|
|
```
|
|
|
|
### 13. PARALLEL FOR — Parallel Loop
|
|
|
|
```prg
|
|
// Process 100K items across all CPU cores
|
|
PARALLEL FOR i := 1 TO 100000
|
|
aResult[i] := ProcessItem(aData[i])
|
|
NEXT
|
|
// Automatically waits for all goroutines to complete
|
|
```
|
|
|
|
### 14. ASYNC / AWAIT — Asynchronous Execution
|
|
|
|
```prg
|
|
// Start heavy work in background
|
|
future := ASYNC HeavyQuery("SELECT * FROM big_table")
|
|
|
|
// Do other work (non-blocking)
|
|
? "Loading..."
|
|
PrepareUI()
|
|
|
|
// Wait for result
|
|
aRows := AWAIT future
|
|
? "Got", Len(aRows), "rows"
|
|
```
|
|
|
|
### 15. WITH TIMEOUT — Timeout Context
|
|
|
|
```prg
|
|
// Auto-cancel if not completed within 3 seconds
|
|
WITH TIMEOUT 3
|
|
result := SlowNetworkCall()
|
|
END
|
|
|
|
IF result == NIL
|
|
? "Timeout!"
|
|
ENDIF
|
|
```
|
|
|
|
## Direct Go Object Manipulation
|
|
|
|
### `pkg.Func()` — Package Function Calls
|
|
|
|
```prg
|
|
IMPORT "strings"
|
|
IMPORT "math"
|
|
IMPORT "fmt"
|
|
|
|
? strings.ToUpper("hello") // "HELLO"
|
|
? math.Sqrt(144) // 12
|
|
? fmt.Sprintf("%.2f", 3.14159) // "3.14"
|
|
```
|
|
|
|
### `obj:Method()` — Go Object Method Calls
|
|
|
|
```prg
|
|
IMPORT "database/sql"
|
|
|
|
db := sql.Open("sqlite", ":memory:")
|
|
db:Exec("CREATE TABLE test (id INTEGER)")
|
|
rows := db:Query("SELECT * FROM test")
|
|
DO WHILE rows:Next()
|
|
? rows:Column(1)
|
|
END
|
|
rows:Close()
|
|
db:Close()
|
|
```
|
|
|
|
### Multiple Go Objects Simultaneously
|
|
|
|
```prg
|
|
dbSource := sql.Open("sqlite", "source.db")
|
|
dbTarget := sql.Open("sqlite", "target.db")
|
|
|
|
aRows := SqlScan(dbSource, "SELECT * FROM products")
|
|
FOR i := 1 TO Len(aRows)
|
|
dbTarget:Exec("INSERT INTO inventory VALUES (...)")
|
|
NEXT
|
|
|
|
dbSource:Close()
|
|
dbTarget:Close()
|
|
```
|
|
|
|
## Five vs Competitors
|
|
|
|
### xBase Family Comparison
|
|
|
|
| Feature | Harbour | xHarbour | FiveWin | **Five** |
|
|
|---------|---------|----------|---------|----------|
|
|
| DBF/NTX/CDX | Yes | Yes | Yes | **Yes** |
|
|
| SQL Database | No | Limited | ODBC | **All Go DBs** |
|
|
| HTTP Server | No | No | No | **net/http** |
|
|
| WebSocket | No | No | No | **Yes** |
|
|
| Goroutine | No | No | No | **Native** |
|
|
| Channel `<-` | No | No | No | **Yes** |
|
|
| JSON | Limited | Limited | Limited | **Go encoding/json** |
|
|
| Cross-platform | Partial | Partial | Windows | **Linux/Mac/Windows** |
|
|
| Package ecosystem | C libs | C libs | C libs | **All Go packages** |
|
|
|
|
### Transpiler Comparison
|
|
|
|
| Feature | TypeScript→JS | Kotlin→JVM | **Five (PRG→Go)** |
|
|
|---------|---------------|------------|---------------------|
|
|
| Type system | Static→Dynamic | Static→Static | Dynamic→Static |
|
|
| Concurrency | async/await | coroutine | **goroutine+channel** |
|
|
| External packages | npm | Maven | **Go modules** |
|
|
| Build output | JS code | bytecode | **Native binary** |
|
|
| Interop | Direct JS | Direct Java | **Direct Go (IMPORT)** |
|
|
| Performance | V8 runtime | JVM runtime | **Native speed** |
|
|
|
|
### What Makes Five Unique
|
|
|
|
1. **IMPORT gives access to all of Go** — No #pragma BEGINDUMP needed
|
|
2. **Native binary output** — Single executable, no JVM or V8 required
|
|
3. **goroutine + channel + WATCH** — Full Go concurrency in PRG syntax
|
|
4. **100% xBase compatible** — Existing DBF/NTX/CDX code runs as-is
|
|
5. **FastPath optimization** — Go function calls within 2x of native performance
|
|
6. **DEFER** — Safe resource management, cleaner than BEGIN SEQUENCE
|
|
7. **Multi-Return** — `a, b := Func()`, natural Go (val, error) pattern
|
|
8. **f-string** — String interpolation, `f"Hello {name}"`
|
|
9. **PARALLEL FOR** — Automatic parallel processing of large datasets
|
|
10. **Nil-safe `?:`** — Safe chaining, no runtime errors from NIL
|
|
|
|
## Performance
|
|
|
|
```
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
Call Type Direct Go Reflect FastPath
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
strings.ToUpper 34ns 242ns 66ns
|
|
strings.Contains 3ns 218ns 19ns
|
|
math.Sqrt 0.1ns 173ns 16ns
|
|
obj:Method() — 412ns 235ns
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
|
|
Throughput: 15M calls/sec (FastPath), 4.3M calls/sec (Method)
|
|
Stress tested: 40K calls, 1MB strings, 10K arrays,
|
|
20K concurrent goroutines, 5K random fuzz
|
|
```
|
|
|
|
## Math: Harbour RTL + Go math Together
|
|
|
|
Five gives you two math systems in one file:
|
|
|
|
```prg
|
|
IMPORT "math"
|
|
|
|
PROCEDURE Main()
|
|
LOCAL nVal
|
|
|
|
// Harbour RTL — simple, no IMPORT needed
|
|
? Abs(-42.5) // 42.5
|
|
? Sqrt(144) // 12
|
|
? Round(3.14159, 2) // 3.14
|
|
? Max(10, 20) // 20
|
|
|
|
// Go math — complete, 60+ functions
|
|
? math.Sin(math.Pi / 6) // 0.5
|
|
? math.Pow(2, 10) // 1024
|
|
? math.Hypot(3, 4) // 5
|
|
? math.Log2(1024) // 10
|
|
|
|
// Combined — use both freely
|
|
nVal := (1 / Sqrt(2 * math.Pi)) * Exp(-0.5 * math.Pow(0, 2))
|
|
? "Normal PDF at 0:", Round(nVal, 6)
|
|
|
|
RETURN
|
|
```
|
|
|
|
| | Harbour RTL | Go math |
|
|
|---|---|---|
|
|
| Functions | 9 (Abs, Sqrt, Round, Int, Max, Min, Log, Exp, Mod) | 60+ |
|
|
| IMPORT needed | No | `IMPORT "math"` |
|
|
| Best for | Business calculations | Scientific/financial |
|
|
| Precision | Standard | IEEE 754 |
|
|
| Trig/Hyperbolic | No | Sin, Cos, Tan, Sinh, Cosh, ... |
|
|
| Constants | No | Pi, E, Phi, Ln2, Sqrt2 |
|
|
| Special values | No | NaN, Inf, MaxFloat64 |
|
|
|
|
## Example Files
|
|
|
|
| File | Description |
|
|
|------|-------------|
|
|
| `examples/go_native.prg` | Direct Go package usage with IMPORT only |
|
|
| `examples/go_strings.prg` | Full strings package utilization |
|
|
| `examples/go_typetest.prg` | 18 type conversion tests |
|
|
| `examples/go_dual_db.prg` | Two SQLite databases simultaneously |
|
|
| `examples/go_channel.prg` | Channel operators + WATCH + Pipeline |
|
|
| `examples/go_httpserver.prg` | REST API server |
|
|
| `examples/go_concurrent.prg` | Parallel data pipeline |
|
|
| `examples/go_websocket.prg` | WebSocket chat server |
|
|
| `examples/go_extensions.prg` | All 9 extension syntax demo |
|
|
| `examples/go_math_compare.prg` | Harbour RTL vs Go math side-by-side |
|
|
| `examples/godump_demo.prg` | HB_FUNC Go API |
|