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>
This commit is contained in:
263
tests/hello_test.go
Normal file
263
tests/hello_test.go
Normal file
@@ -0,0 +1,263 @@
|
||||
// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
|
||||
// All rights reserved.
|
||||
|
||||
// Integration tests: simulates what generated Go code would look like.
|
||||
// Each test is the equivalent of a PRG file compiled by Five.
|
||||
package tests
|
||||
|
||||
import (
|
||||
"five/hbrt"
|
||||
"five/hbrtl"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func newTestVM() *hbrt.VM {
|
||||
vm := hbrt.NewVM()
|
||||
hbrtl.RegisterRTL(vm)
|
||||
return vm
|
||||
}
|
||||
|
||||
// TestHelloWorld simulates:
|
||||
//
|
||||
// FUNCTION Main()
|
||||
// ? "Hello, World!"
|
||||
// ? 1 + 2
|
||||
// RETURN NIL
|
||||
func TestHelloWorld(t *testing.T) {
|
||||
vm := newTestVM()
|
||||
mod := hbrt.NewModule("HELLO",
|
||||
hbrt.Sym("MAIN", hbrt.FsPublic|hbrt.FsLocal|hbrt.FsFirst, func(th *hbrt.Thread) {
|
||||
th.Frame(0, 0)
|
||||
defer th.EndProc()
|
||||
th.PushSymbol(vm.FindSymbol("QOUT"))
|
||||
th.PushNil()
|
||||
th.PushString("Hello, World!")
|
||||
th.Function(1)
|
||||
th.PushSymbol(vm.FindSymbol("QOUT"))
|
||||
th.PushNil()
|
||||
th.PushInt(1)
|
||||
th.PushInt(2)
|
||||
th.Plus()
|
||||
th.Function(1)
|
||||
th.RetNil()
|
||||
}),
|
||||
)
|
||||
vm.RegisterModule(mod)
|
||||
result := vm.Run("MAIN")
|
||||
if !result.IsNil() {
|
||||
t.Errorf("Main should return NIL, got %v", result)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSumLoop simulates:
|
||||
//
|
||||
// FUNCTION Main()
|
||||
// LOCAL nSum := 0, i := 1
|
||||
// DO WHILE i <= 10
|
||||
// nSum += i
|
||||
// i++
|
||||
// ENDDO
|
||||
// ? "Sum 1..10 =", nSum
|
||||
// RETURN nSum
|
||||
func TestSumLoop(t *testing.T) {
|
||||
vm := newTestVM()
|
||||
mod := hbrt.NewModule("SUMTEST",
|
||||
hbrt.Sym("MAIN", hbrt.FsPublic|hbrt.FsLocal|hbrt.FsFirst, func(th *hbrt.Thread) {
|
||||
th.Frame(0, 2)
|
||||
defer th.EndProc()
|
||||
th.LocalSetInt(1, 0)
|
||||
th.LocalSetInt(2, 1)
|
||||
lab_for:
|
||||
th.PushLocal(2)
|
||||
th.PushInt(10)
|
||||
th.LessEqual()
|
||||
if !th.PopLogical() {
|
||||
goto lab_endfor
|
||||
}
|
||||
th.PushLocal(2)
|
||||
th.LocalAdd(1)
|
||||
th.LocalAddInt(2, 1)
|
||||
goto lab_for
|
||||
lab_endfor:
|
||||
th.PushSymbol(vm.FindSymbol("QOUT"))
|
||||
th.PushNil()
|
||||
th.PushString("Sum 1..10 =")
|
||||
th.PushLocal(1)
|
||||
th.Function(2)
|
||||
th.PushLocal(1)
|
||||
th.RetValue()
|
||||
}),
|
||||
)
|
||||
vm.RegisterModule(mod)
|
||||
result := vm.Run("MAIN")
|
||||
if result.AsNumInt() != 55 {
|
||||
t.Errorf("Sum 1..10 = %d, want 55", result.AsNumInt())
|
||||
}
|
||||
}
|
||||
|
||||
// TestStringConcat simulates:
|
||||
//
|
||||
// FUNCTION Main()
|
||||
// LOCAL cName := "World"
|
||||
// LOCAL cGreeting := "Hello, " + cName + "!"
|
||||
// ? cGreeting
|
||||
// RETURN cGreeting
|
||||
func TestStringConcat(t *testing.T) {
|
||||
vm := newTestVM()
|
||||
mod := hbrt.NewModule("STRTEST",
|
||||
hbrt.Sym("MAIN", hbrt.FsPublic|hbrt.FsLocal|hbrt.FsFirst, func(th *hbrt.Thread) {
|
||||
th.Frame(0, 2)
|
||||
defer th.EndProc()
|
||||
th.PushString("World")
|
||||
th.PopLocal(1)
|
||||
th.PushString("Hello, ")
|
||||
th.PushLocal(1)
|
||||
th.Plus()
|
||||
th.PushString("!")
|
||||
th.Plus()
|
||||
th.PopLocal(2)
|
||||
th.PushSymbol(vm.FindSymbol("QOUT"))
|
||||
th.PushNil()
|
||||
th.PushLocal(2)
|
||||
th.Function(1)
|
||||
th.PushLocal(2)
|
||||
th.RetValue()
|
||||
}),
|
||||
)
|
||||
vm.RegisterModule(mod)
|
||||
result := vm.Run("MAIN")
|
||||
if result.AsString() != "Hello, World!" {
|
||||
t.Errorf("greeting = %q, want %q", result.AsString(), "Hello, World!")
|
||||
}
|
||||
}
|
||||
|
||||
// TestFunctionCallWithSTR simulates:
|
||||
//
|
||||
// FUNCTION Main()
|
||||
// LOCAL n := 42
|
||||
// ? "Value: " + Str(n)
|
||||
// RETURN n
|
||||
func TestFunctionCallWithSTR(t *testing.T) {
|
||||
vm := newTestVM()
|
||||
mod := hbrt.NewModule("STRFUNC",
|
||||
hbrt.Sym("MAIN", hbrt.FsPublic|hbrt.FsLocal|hbrt.FsFirst, func(th *hbrt.Thread) {
|
||||
th.Frame(0, 1)
|
||||
defer th.EndProc()
|
||||
th.LocalSetInt(1, 42)
|
||||
// Str(n)
|
||||
th.PushSymbol(vm.FindSymbol("STR"))
|
||||
th.PushNil()
|
||||
th.PushLocal(1)
|
||||
th.Function(1)
|
||||
// "Value: " + Str(n)
|
||||
strResult := th.GetRetValue()
|
||||
th.Pop() // pop Function result from stack
|
||||
th.PushString("Value: ")
|
||||
th.PushValue(strResult)
|
||||
th.Plus()
|
||||
// ? result
|
||||
concatResult := th.Pop2()
|
||||
th.PushSymbol(vm.FindSymbol("QOUT"))
|
||||
th.PushNil()
|
||||
th.PushValue(concatResult)
|
||||
th.Function(1)
|
||||
th.PushLocal(1)
|
||||
th.RetValue()
|
||||
}),
|
||||
)
|
||||
vm.RegisterModule(mod)
|
||||
result := vm.Run("MAIN")
|
||||
if result.AsNumInt() != 42 {
|
||||
t.Errorf("result = %d, want 42", result.AsNumInt())
|
||||
}
|
||||
}
|
||||
|
||||
// TestNestedFunctionCalls simulates:
|
||||
//
|
||||
// FUNCTION Double(n) → n * 2
|
||||
// FUNCTION Main() → ? Double(Double(5))
|
||||
func TestNestedFunctionCalls(t *testing.T) {
|
||||
vm := newTestVM()
|
||||
mod := hbrt.NewModule("NESTED",
|
||||
hbrt.Sym("DOUBLE", hbrt.FsPublic|hbrt.FsLocal, func(th *hbrt.Thread) {
|
||||
th.Frame(1, 0)
|
||||
defer th.EndProc()
|
||||
th.RetInt(th.Local(1).AsNumInt() * 2)
|
||||
}),
|
||||
hbrt.Sym("MAIN", hbrt.FsPublic|hbrt.FsLocal|hbrt.FsFirst, func(th *hbrt.Thread) {
|
||||
th.Frame(0, 0)
|
||||
defer th.EndProc()
|
||||
// Double(5) → 10
|
||||
th.PushSymbol(vm.FindSymbol("DOUBLE"))
|
||||
th.PushNil()
|
||||
th.PushInt(5)
|
||||
th.Function(1)
|
||||
// Double(10) → 20
|
||||
inner := th.Pop2()
|
||||
th.PushSymbol(vm.FindSymbol("DOUBLE"))
|
||||
th.PushNil()
|
||||
th.PushValue(inner)
|
||||
th.Function(1)
|
||||
// ? and return
|
||||
outer := th.Pop2()
|
||||
th.PushSymbol(vm.FindSymbol("QOUT"))
|
||||
th.PushNil()
|
||||
th.PushValue(outer)
|
||||
th.Function(1)
|
||||
th.PushValue(outer)
|
||||
th.RetValue()
|
||||
}),
|
||||
)
|
||||
vm.RegisterModule(mod)
|
||||
result := vm.Run("MAIN")
|
||||
if result.AsNumInt() != 20 {
|
||||
t.Errorf("Double(Double(5)) = %d, want 20", result.AsNumInt())
|
||||
}
|
||||
}
|
||||
|
||||
// TestIfElse simulates:
|
||||
//
|
||||
// FUNCTION Main()
|
||||
// LOCAL n := 55
|
||||
// IF n > 50
|
||||
// ? "Greater"
|
||||
// RETURN .T.
|
||||
// ELSE
|
||||
// ? "Not greater"
|
||||
// RETURN .F.
|
||||
// ENDIF
|
||||
func TestIfElse(t *testing.T) {
|
||||
vm := newTestVM()
|
||||
mod := hbrt.NewModule("IFTEST",
|
||||
hbrt.Sym("MAIN", hbrt.FsPublic|hbrt.FsLocal|hbrt.FsFirst, func(th *hbrt.Thread) {
|
||||
th.Frame(0, 1)
|
||||
defer th.EndProc()
|
||||
th.LocalSetInt(1, 55)
|
||||
th.PushLocal(1)
|
||||
th.PushInt(50)
|
||||
th.Greater()
|
||||
if !th.PopLogical() {
|
||||
goto lab_else
|
||||
}
|
||||
th.PushSymbol(vm.FindSymbol("QOUT"))
|
||||
th.PushNil()
|
||||
th.PushString("Greater")
|
||||
th.Function(1)
|
||||
th.PushBool(true)
|
||||
th.RetValue()
|
||||
return
|
||||
lab_else:
|
||||
th.PushSymbol(vm.FindSymbol("QOUT"))
|
||||
th.PushNil()
|
||||
th.PushString("Not greater")
|
||||
th.Function(1)
|
||||
th.PushBool(false)
|
||||
th.RetValue()
|
||||
}),
|
||||
)
|
||||
vm.RegisterModule(mod)
|
||||
result := vm.Run("MAIN")
|
||||
if !result.AsBool() {
|
||||
t.Error("55 > 50 should return .T.")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user