From c7ac4044f7662145a1e1b4aebecc1dc8ff2be87b Mon Sep 17 00:00:00 2001 From: Charles KWON OhJun Date: Wed, 27 May 2026 10:44:12 +0900 Subject: [PATCH] feat(json): hb_jsonDecode 2-arg byref form (Harbour-spec compatible) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously hb_jsonDecode took only (cJSON) and returned the value. That covers most uses but not the Harbour-spec second form nBytesParsed := hb_jsonDecode( cJSON, @xOut ) which mod_harbour / fivenode PRG (e.g. bridge_context.prg's ctx_get / ctx_set) and any other code that wants the parse-length relies on. The byref output was silently dropped, so a hash lookup went through the @hOut path that was always NIL and fell back to the default value — looking like a hash key was missing even though the JSON parsed fine. Now PCount() == 1 keeps the legacy return-value form; PCount() >= 2 writes the decoded value into local-2 via SetLocal (which is already byref-aware) and returns the byte count (0 on parse error). Verified: hb_jsonDecode('{"x":1,"y":2}', @h) writes the hash and returns 13; the 1-arg form still returns the value as before; Compat 56/56 + go test ./compiler/... ./hbrt/... ./hbrtl/... all pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- hbrtl/json.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/hbrtl/json.go b/hbrtl/json.go index db44c44..ece4e87 100644 --- a/hbrtl/json.go +++ b/hbrtl/json.go @@ -58,7 +58,17 @@ func HbJsonEncode(t *hbrt.Thread) { t.RetString(string(data)) } -// HB_JSONDECODE(cJSON) → xValue +// HB_JSONDECODE(cJSON [, @xOut]) → xValue | nBytesParsed +// +// Two Harbour-spec calling forms: +// +// - 1 arg : returns the decoded value (or NIL on parse error). +// - 2 args: writes the decoded value into the byref @xOut and +// returns the number of bytes parsed (0 on error). This is the +// form mod_harbour / fivenode PRG code uses for ctx_get and the +// like. Five previously implemented only the 1-arg form, so any +// PRG that relied on the byref output saw NIL and silently fell +// through to a default. func HbJsonDecode(t *hbrt.Thread) { nParams := t.ParamCount() t.Frame(nParams, 0) @@ -66,10 +76,21 @@ func HbJsonDecode(t *hbrt.Thread) { s := t.Local(1).AsString() var raw interface{} if err := json.Unmarshal([]byte(s), &raw); err != nil { - t.RetNil() + if nParams >= 2 { + t.SetLocal(2, hbrt.MakeNil()) + t.RetInt(0) + } else { + t.RetNil() + } return } - t.RetVal(goToValue(raw)) + v := goToValue(raw) + if nParams >= 2 { + t.SetLocal(2, v) + t.RetInt(int64(len(s))) + return + } + t.RetVal(v) } // === Five Extensions ===