- 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>
137 lines
2.6 KiB
Go
137 lines
2.6 KiB
Go
// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
|
|
// All rights reserved.
|
|
|
|
// Goroutine support for Five runtime.
|
|
// Provides Go's goroutine, channel, and WaitGroup primitives
|
|
// as first-class Harbour values.
|
|
|
|
package hbrt
|
|
|
|
import (
|
|
"sync"
|
|
)
|
|
|
|
// --- Channel ---
|
|
|
|
// HbChannel wraps Go's chan Value for use in PRG code.
|
|
type HbChannel struct {
|
|
Ch chan Value
|
|
}
|
|
|
|
// MakeChannel creates a channel Value with optional buffer size.
|
|
func MakeChannel(size int) Value {
|
|
return MakePointer(&HbChannel{Ch: make(chan Value, size)})
|
|
}
|
|
|
|
// AsChannel extracts HbChannel from a Pointer value.
|
|
func (v Value) AsChannel() *HbChannel {
|
|
if !v.IsPointer() {
|
|
return nil
|
|
}
|
|
if ch, ok := v.AsPointer().(*HbChannel); ok {
|
|
return ch
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Send sends a value into the channel.
|
|
func (ch *HbChannel) Send(val Value) {
|
|
ch.Ch <- val
|
|
}
|
|
|
|
// Receive receives a value from the channel.
|
|
func (ch *HbChannel) Receive() Value {
|
|
return <-ch.Ch
|
|
}
|
|
|
|
// TryReceive attempts non-blocking receive. Returns (value, true) or (nil, false).
|
|
func (ch *HbChannel) TryReceive() (Value, bool) {
|
|
select {
|
|
case v := <-ch.Ch:
|
|
return v, true
|
|
default:
|
|
return MakeNil(), false
|
|
}
|
|
}
|
|
|
|
// Close closes the channel.
|
|
func (ch *HbChannel) Close() {
|
|
close(ch.Ch)
|
|
}
|
|
|
|
// --- WaitGroup ---
|
|
|
|
// HbWaitGroup wraps sync.WaitGroup.
|
|
type HbWaitGroup struct {
|
|
WG sync.WaitGroup
|
|
}
|
|
|
|
// MakeWaitGroup creates a WaitGroup Value with initial count.
|
|
func MakeWaitGroup(n int) Value {
|
|
wg := &HbWaitGroup{}
|
|
if n > 0 {
|
|
wg.WG.Add(n)
|
|
}
|
|
return MakePointer(wg)
|
|
}
|
|
|
|
// AsWaitGroup extracts HbWaitGroup from a Pointer value.
|
|
func (v Value) AsWaitGroup() *HbWaitGroup {
|
|
if !v.IsPointer() {
|
|
return nil
|
|
}
|
|
if wg, ok := v.AsPointer().(*HbWaitGroup); ok {
|
|
return wg
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// --- Mutex ---
|
|
|
|
// HbMutex wraps sync.Mutex.
|
|
type HbMutex struct {
|
|
Mu sync.Mutex
|
|
}
|
|
|
|
// MakeMutex creates a Mutex Value.
|
|
func MakeMutex() Value {
|
|
return MakePointer(&HbMutex{})
|
|
}
|
|
|
|
// AsMutex extracts HbMutex from a Pointer value.
|
|
func (v Value) AsMutex() *HbMutex {
|
|
if !v.IsPointer() {
|
|
return nil
|
|
}
|
|
if mu, ok := v.AsPointer().(*HbMutex); ok {
|
|
return mu
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// --- GoRoutine launcher ---
|
|
|
|
// GoLaunch spawns a new goroutine that runs a function on a new Thread.
|
|
func (vm *VM) GoLaunch(fn func(*Thread), args []Value) {
|
|
go func() {
|
|
t := vm.NewThread()
|
|
for _, a := range args {
|
|
t.push(a)
|
|
}
|
|
t.PendingParams2(len(args))
|
|
fn(t)
|
|
}()
|
|
}
|
|
|
|
// GoLaunchBlock spawns a goroutine that evaluates a code block.
|
|
func (vm *VM) GoLaunchBlock(blk *HbBlock, args []Value) {
|
|
go func() {
|
|
t := vm.NewThread()
|
|
for _, a := range args {
|
|
t.push(a)
|
|
}
|
|
t.PendingParams2(len(args))
|
|
blk.Fn(t)
|
|
}()
|
|
}
|