Files
five/hbrtl/console.go
Charles KWON OhJun 486e466592 feat: FiveSql2 43/43, @byref, mutable closure, RTL 479, DateTime fix
Major changes since last commit:
- FiveSql2 SQL:1999 engine (10,458 LOC) — 43/43 ALL PASS
- 21 compiler/runtime bugs fixed (short-circuit AND/OR, FOR LOOP, etc.)
- @byref pass-by-reference via RefCell pattern
- Mutable closure capture (EnsureLocalRef + RefCell sharing)
- RTL: 400 → 479 functions (+79: file, string, datetime, hash, UTF-8)
- DateTime/Timestamp fully working (hb_DateTime, hb_Hour/Min/Sec, display)
- Reserved word guard (39 keywords blocked from function calls)
- AEval arg order fix (element before index)
- Closure capture redecl fix (unique _cap_ names per block)
- Hash/string indexing in ArrayPush/ArrayPop
- Harbour compat test suite: 51/51
- 4 docs: Porting Report, Implementation Plan, Optimization Plan, Commercialization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 11:35:37 +09:00

87 lines
2.1 KiB
Go

// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
// All rights reserved.
// Console I/O functions for the Five runtime library.
// Implements Harbour's QOut (?), QQOut (??), and related output functions.
package hbrtl
import (
"five/hbrt"
"fmt"
"strings"
)
// QOut implements the ? command. Prints newline then values separated by space.
// Harbour: QOut() / hb_conOutStd()
func QOut(t *hbrt.Thread) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProcFast()
args := make([]hbrt.Value, nParams)
for i := 0; i < nParams; i++ {
args[i] = t.Local(i + 1)
}
qoutImpl(args)
t.RetNil()
}
// qoutImpl is the actual implementation called with pre-collected args.
func qoutImpl(args []hbrt.Value) {
parts := make([]string, len(args))
for i, v := range args {
parts[i] = valueToDisplay(v)
}
fmt.Print("\r\n" + strings.Join(parts, " "))
}
// qqoutImpl prints without leading newline (??).
func qqoutImpl(args []hbrt.Value) {
parts := make([]string, len(args))
for i, v := range args {
parts[i] = valueToDisplay(v)
}
fmt.Print(strings.Join(parts, " "))
}
// valueToDisplay converts a Value to its display string.
// Harbour: hb_itemString()
func valueToDisplay(v hbrt.Value) string {
switch {
case v.IsNil():
return "NIL"
case v.IsLogical():
if v.AsBool() {
return ".T."
}
return ".F."
case v.IsInt():
return fmt.Sprintf("%d", v.AsInt())
case v.IsLong():
return fmt.Sprintf("%d", v.AsLong())
case v.IsDouble():
dec := v.Decimal()
if dec == 255 {
return fmt.Sprintf("%g", v.AsDouble())
}
return fmt.Sprintf("%.*f", dec, v.AsDouble())
case v.IsString():
return v.AsString()
case v.IsDate():
return julianToDateStr(v.AsJulian())
case v.IsTimestamp():
y, m, d := julianToDate(v.AsJulian())
ms := v.AsTimeMs()
hh := ms / 3600000
mm := ms / 60000 % 60
ss := ms / 1000 % 60
return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", y, m, d, hh, mm, ss)
case v.IsArray():
return fmt.Sprintf("{Array(%d)}", len(v.AsArray().Items))
default:
return v.String()
}
}
// julianToDateStr and date formatting moved to datetime.go