Documentation
¶
Overview ¶
Package value defines the runtime Value type and its supporting domain-shaped types (Money, Duration, Range, time helpers) used throughout Vibescript. Hosts import this package directly when passing arguments, reading results, building globals, or implementing first-party capability interfaces.
Scope: this package intentionally houses both the runtime-value plumbing (Value, ValueKind, constructors, accessors, kind conversions) AND the domain-shaped scalar types (Money, Duration, Range, time helpers). They live together because each domain type is also a Value payload: NewMoney(m) wraps a Money, KindMoney tags it, and Value.Money() unwraps it. Splitting the domain scalars into a separate vibes/domain package would force value/ to import domain/ purely to define those payload kinds. The Value-payload coupling outweighs the organizational benefit of a standalone domain package, so the scalars stay here.
Ownership and isolation ¶
The Script.Call boundary copies in both directions, so hosts and scripts never share mutable state:
- Values returned from Script.Call are the host's to keep and mutate. Every Call returns an independent copy; mutating a result (directly or through this package's hash and array operations) never changes what a later Call observes.
- Values passed INTO Script.Call — arguments and CallOptions.Globals — are never mutated by the script. Script-side mutation acts on the call's own copy; the host's originals are untouched when Call returns.
- The host still owns the Values it passed in. Mutating them BETWEEN calls is safe, and the next Call observes the new contents (globals are re-read from the host's map at each call).
Concurrency ¶
Value wrappers are not synchronized. Two goroutines may read the same Value concurrently, but any mutation concurrent with another access is a data race. In particular, mutating a Value while a Script.Call that was given that Value is running is forbidden: the interpreter materializes globals lazily during the call, and the race is not merely stale data — concurrent map access makes the Go runtime terminate the whole host process ("fatal error: concurrent map read and map write"), which cannot be recovered. Hand a Value to a running call and leave it alone until the call returns.
Quotas ¶
Engine quotas (steps, memory) meter script execution only. Host-side construction and mutation through this package are unmetered: no quota observes a host growing a Value between calls, and host-only graphs are never charged against a later call's memory quota because the estimator walks only state reachable from the execution.
Supported API versus internal plumbing ¶
Some exported symbols exist only because the interpreter's runtime lives in a separate package (internal/runtime) and needs cross-package access to Value internals. Their doc comments say "intended for the interpreter's internal use"; they carry no compatibility promise and may change or disappear in any release. The tier assignment for every exported symbol is declared in docs/embedding-api-stability.md.
Index ¶
- Constants
- Variables
- func ArrayIdentity(v Value) uintptr
- func BigIntDecimalLenUpperBound(v Value) int
- func BigIntPayload(v Value) (*big.Int, bool)
- func BumpMutationEpoch()
- func EitherIntPayload(a, b Value) bool
- func FormatFloat(f float64) string
- func HashDisplayKey(key Value) string
- func HashIdentity(v Value) uintptr
- func HashKey(key Value) (string, error)
- func HashOrderCapacity(v Value) int
- func HashTypedEntryCapacity(v Value) int
- func MutationEpoch() uint64
- func NumericToSeconds(val Value) (int64, error)
- func ParseLocation(val Value) (*time.Location, error)
- func ParseLocationString(spec string) (*time.Location, error)
- func ParseTimeString(input, layout string, hasLayout bool, loc *time.Location) (time.Time, error)
- func TimeFromCalendarParts(args []Value, defaultLoc *time.Location) (time.Time, error)
- func TimeFromEpochParts(secVal Value, subsecVal, unitVal *Value, loc *time.Location) (time.Time, error)
- func TimeFromParts(args []Value, defaultLoc *time.Location) (time.Time, error)
- func ValueToInt64(val Value) (int64, error)
- type BlockPayload
- type BuiltinPayload
- type ClassPayload
- type Duration
- type EnumPayload
- type EnumValuePayload
- type EqualityContext
- type FunctionPayload
- type HashEntry
- type HashLookupKey
- type InstancePayload
- type Money
- type Range
- type Regex
- type SliceIdentity
- type TypedHashEntry
- type Value
- func AdoptBigInt(i *big.Int) Value
- func HashDefaultProc(v Value) Value
- func HashDefaultValue(v Value) Value
- func NewArray(a []Value) Value
- func NewBigInt(i *big.Int) Value
- func NewBool(b bool) Value
- func NewDuration(d Duration) Value
- func NewFloat(f float64) Value
- func NewHash(h map[string]Value) Value
- func NewHashWithDefault(h map[string]Value, defaultValue, defaultProc Value) Value
- func NewInt(i int64) Value
- func NewMoney(m Money) Value
- func NewNil() Value
- func NewObject(attrs map[string]Value) Value
- func NewRange(r Range) Value
- func NewRegex(r Regex) Value
- func NewString(s string) Value
- func NewSymbol(name string) Value
- func NewTime(t time.Time) Value
- func NewTypedHash(capacity int) Value
- func NewValue(kind ValueKind, data any) Value
- func (v Value) Array() []Value
- func (v Value) BigInt() *big.Int
- func (v Value) Block() BlockPayload
- func (v Value) Bool() bool
- func (v Value) Builtin() BuiltinPayload
- func (v Value) Class() ClassPayload
- func (v Value) CompactInt() (int64, bool)
- func (v Value) Data() any
- func (v Value) Duration() Duration
- func (v Value) Enum() EnumPayload
- func (v Value) EnumValue() EnumValuePayload
- func (v Value) Eql(other Value) bool
- func (v Value) Equal(other Value) bool
- func (v Value) Float() float64
- func (v Value) Function() FunctionPayload
- func (v Value) Hash() map[string]Value
- func (v Value) HashClearEntries()
- func (v Value) HashDeleteKey(key Value) (Value, bool, error)
- func (v Value) HashEntries() []HashEntry
- func (v Value) HashEntriesInto(buf []HashEntry) []HashEntry
- func (v Value) HashGet(key Value) (Value, bool, error)
- func (v Value) HashHasTypedEntries() bool
- func (v Value) HashLen() int
- func (v Value) HashSet(key, val Value) error
- func (v Value) HashStringMapIfMaterialized() (map[string]Value, bool)
- func (v Value) Identical(other Value) bool
- func (v Value) Inspect() string
- func (v Value) InspectBounded(limit int) (string, error)
- func (v Value) InspectByteLenBounded(step func() error) (int, error)
- func (v Value) Instance() InstancePayload
- func (v Value) Int() int64
- func (v Value) IsBigInt() bool
- func (v Value) IsNil() bool
- func (v Value) Kind() ValueKind
- func (v Value) Money() Money
- func (v Value) Range() Range
- func (v Value) Regex() Regex
- func (v Value) ReserveHashOrder(n int)
- func (v Value) ReserveTypedHashOrder(n int)
- func (v Value) SetArrayElems(elems []Value)
- func (v Value) SetHashDefaults(defaultValue, defaultProc Value)
- func (v Value) String() string
- func (v Value) StringBounded(limit int) (string, error)
- func (v Value) StringByteLen() int
- func (v Value) StringByteLenBounded(step func() error) (int, error)
- func (v Value) StringByteLenBoundedUpTo(limit int, step func() error) (count int, truncated bool, err error)
- func (v Value) StringRuneLen() int
- func (v Value) StringRuneLenBounded(step func() error) (int, error)
- func (v Value) Time() time.Time
- func (v Value) Truthy() bool
- func (v Value) TypedHashEntriesInto(buf []TypedHashEntry) []TypedHashEntry
- func (v Value) WriteInspectTo(buf *strings.Builder)
- func (v Value) WriteStringTo(buf *strings.Builder)
- type ValueKind
Examples ¶
Constants ¶
const HashDataBytes = int(unsafe.Sizeof(hashData{}))
HashDataBytes is the heap footprint of the hashData wrapper every KindHash value allocates, excluding the entry map and default payloads it points at. Memory-quota accounting charges it once per distinct hash so an array of many small hashes cannot retain the per-hash wrapper cost uncharged. It is intended for the interpreter's internal use; hosts should not rely on it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
Variables ¶
var DefaultTimeParseLayouts = []string{ time.RFC3339Nano, time.RFC3339, time.RFC1123Z, time.RFC1123, "2006-01-02T15:04:05", "2006-01-02 15:04:05", "2006/01/02 15:04:05", "2006-01-02", "2006/01/02", "01/02/2006 15:04:05", "01/02/2006", }
DefaultTimeParseLayouts is the ordered list of layouts attempted by ParseTimeString when no explicit layout is supplied.
var ErrMoneyOverflow = errMoneyOverflow
ErrMoneyOverflow exposes the money-overflow sentinel so the runtime can report the same convention when an operand (for example a big integer factor) cannot fit money's int64 cents domain at all. It is intended for the interpreter's internal use; hosts should not rely on it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
var ErrStringRenderTruncated = errors.New("value: string rendering exceeded byte limit")
ErrStringRenderTruncated reports that a bounded rendering (StringBounded) stopped early because the formatted output would have exceeded the caller's byte budget. It lets host-facing rendering refuse to materialize an unbounded string for a large composite result instead of allocating until the process runs out of memory. Callers detect it with errors.Is.
var RuntimeEqualer func(left, right Value) (bool, bool)
RuntimeEqualer is the hook used by Value.Equal to compare runtime-only kinds whose payload types live in the vibes package. The vibes package installs this hook during initialization. If unset, equality for those kinds falls back to pointer identity of the underlying payload. It is intended for the interpreter's internal use; hosts should not rely on it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
var RuntimeIdenticaler func(left, right Value) (bool, bool)
RuntimeIdenticaler is the hook used by Value.Identical to compare runtime-only kinds by backing-storage identity. It differs from RuntimeEqualer because some runtime kinds (notably enums and enum values) define Equal as structural equivalence: two independently cloned enum members that share an owner script and name compare Equal, yet they do not share storage and so must not be Identical. The vibes package installs this hook during initialization. If unset, identity for those kinds falls back to the same comparison Value.Equal uses. It is intended for the interpreter's internal use; hosts should not rely on it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
var RuntimeStringer func(v Value) (string, bool)
RuntimeStringer is the hook used by Value.String to format runtime-only kinds (function, builtin, block, enum, enum value, class, instance) whose payload types live in the vibes package. The vibes package installs this hook during initialization. If unset, those kinds fall back to a generic rendering of the underlying payload. It is intended for the interpreter's internal use; hosts should not rely on it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
Functions ¶
func ArrayIdentity ¶ added in v0.60.0
ArrayIdentity returns an identity for an array wrapper, or 0 when v is not an array. It identifies the shared mutable wrapper itself rather than the current element backing, so identity survives in-place growth that reallocates the element slice. Two Values are the same array object exactly when their identities match.
The identity is the wrapper's address as a bare uintptr, so it is only meaningful between captures taken while the address cannot move: Go may stack-allocate a wrapper that never escapes its function, and a goroutine stack growth then relocates it, changing the identity of a still-live array. The runtime only compares identities captured within a single traversal of a heap-reachable graph, where this cannot happen. It is intended for the interpreter's internal use; hosts should use Value.Identical, which compares live wrapper pointers, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func BigIntDecimalLenUpperBound ¶ added in v0.60.0
BigIntDecimalLenUpperBound is bigIntDecimalLenUpperBound for a Value known to carry a big payload; it returns 0 for every other value. The runtime uses it to preflight rendering and conversion work against its quotas before calling the superlinear base conversion. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func BigIntPayload ¶ added in v0.60.0
BigIntPayload returns the big-integer payload of v without copying, and whether v carries one. Callers must treat the result as immutable. It is intended for the interpreter's internal use; hosts should use BigInt, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func BumpMutationEpoch ¶ added in v0.60.0
func BumpMutationEpoch()
BumpMutationEpoch advances the process-wide mutation epoch, invalidating every memoized estimator walk. Every code path that mutates state reachable by a memory-quota walk -- in this package's wrapper mutators and in the runtime -- must call it before the mutated state can be observed by a check. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func EitherIntPayload ¶ added in v0.60.0
EitherIntPayload reports whether either operand carries any payload beyond the compact scalar. Callers have already established both are KindInt, so a nil payload means the compact representation; the test is two nil compares, keeping the interpreter's compact arithmetic fast path free of type assertions. A true result sends the caller to the full big-integer probes. It is intended for the interpreter's internal use; hosts should use IsBigInt, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func FormatFloat ¶ added in v0.60.0
FormatFloat renders a float the way Vibescript displays it, matching Ruby's Float#to_s. Finite values use Go's shortest round-trippable form, while the IEEE special values render as Ruby spells them ("Infinity", "-Infinity", "NaN") instead of Go's "+Inf"/"-Inf"/"NaN".
func HashDisplayKey ¶
HashDisplayKey returns the legacy string-map key used by Hash() for callers that inspect ordinary hashes through the public map API. The encoding is not frozen; hosts that need original keys or reliable lookups use HashEntries and HashGet. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func HashIdentity ¶ added in v0.60.0
HashIdentity returns an identity for a hash wrapper, or 0 when v is not a hash. Unlike the entry-map pointer, this identifies the whole hashData wrapper, so two KindHash values that share an entry map but carry different default metadata are distinct. Cycle-detecting scanners that must also visit hash defaults key their seen-set on this value rather than the bare entry map, which would otherwise hide a second wrapper's distinct default payload.
Like ArrayIdentity, the identity is a bare uintptr wrapper address and is only meaningful between captures taken while the address cannot move (see ArrayIdentity for the stack-allocation caveat). It is intended for the interpreter's internal use; hosts should use Value.Identical, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func HashKey ¶
HashKey returns the canonical lookup key for a hash key value. The encoding is an internal detail of the hash tables; hosts look entries up with HashGet and read original keys from HashEntries. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func HashOrderCapacity ¶ added in v0.60.0
HashOrderCapacity returns the capacity of the insertion-order backing a hash retains alongside its typed entries, or 0 when v is not a hash or tracks no order. Memory-quota accounting charges the backing's structural bytes; the lookup keys inside it alias strings the entry storage already charges. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func HashTypedEntryCapacity ¶
HashTypedEntryCapacity returns the minimum typed-entry map capacity the hash is known to retain. Go does not expose current map bucket capacity, so this tracks explicit reservations plus the live entry count reached through HashSet. Memory-quota estimation uses it to charge reserved typed buckets that may exceed len(typedEntries). It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func MutationEpoch ¶ added in v0.60.0
func MutationEpoch() uint64
MutationEpoch returns the current process-wide mutation epoch. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func NumericToSeconds ¶
NumericToSeconds converts an integer or floating-point Value to a count of whole seconds.
func ParseLocation ¶
ParseLocation parses a timezone specifier carried in a Value into a time.Location, returning (nil, nil) when val is nil.
func ParseLocationString ¶
ParseLocationString parses a timezone specifier string (named zone, fixed offset, or empty).
func ParseTimeString ¶
ParseTimeString parses a time string, optionally using a caller-supplied layout. When hasLayout is false the default layouts are tried in order.
func TimeFromCalendarParts ¶ added in v0.60.0
TimeFromCalendarParts constructs a time.Time from a required year positional argument, with optional month/day/hour/minute/second and a subsecond argument. Unlike TimeFromParts (which backs Time.new and reads the seventh argument as a timezone), this matches Ruby's Time.local/mktime/utc/gm where the seventh argument is microseconds-with-fraction and the location is fixed by the constructor. As with Ruby, an omitted month or day defaults to 1 (January 1) and omitted time fields default to zero (midnight). An explicit nil in any of those positions is treated the same as omitting it, so Time.utc(2024, nil) yields January 1 rather than normalizing month 0 into the prior year. A nil defaultLoc falls back to the local timezone.
func TimeFromEpochParts ¶ added in v0.60.0
func TimeFromEpochParts(secVal Value, subsecVal, unitVal *Value, loc *time.Location) (time.Time, error)
TimeFromEpochParts converts Ruby-style Time.at arguments into a time.Time anchored to the supplied (or local) location.
The seconds argument may be an integer or float. The optional subsec argument adds a subsecond offset whose unit defaults to microseconds and may be overridden by the optional unit symbol (:microsecond/:usec, :millisecond, or :nanosecond/:nsec). Pass a nil pointer for subsec and/or unit when they are absent. A non-nil pointer to a nil Value represents a subsecond or unit that was explicitly supplied as nil, which Ruby rejects (Time.at does not treat an explicit nil subsecond as omitted the way the calendar constructors do).
The result is backed by time.Time, which has nanosecond resolution, so fractional nanoseconds (for example a float subsecond value) are truncated toward zero rather than retained as Ruby's arbitrary-precision rationals do.
func TimeFromParts ¶
TimeFromParts constructs a time.Time from a required year positional argument, with optional month/day/hour/minute/second and timezone arguments. Matching Ruby's Time.new, an omitted month or day defaults to 1 (January 1) and omitted time fields default to zero (midnight). An explicit nil in any of those positions is treated the same as omitting it, so Time.new(2024, nil) yields January 1 rather than normalizing month 0 into the prior year.
func ValueToInt64 ¶
ValueToInt64 coerces an integer or floating-point Value to int64, truncating fractional floats toward zero. Non-finite floats (Infinity/-Infinity/NaN) are rejected rather than coerced to a garbage int64, mirroring Ruby's FloatDomainError. Finite floats outside the int64 range are likewise rejected, as are integers outside the int64 range (IsBigInt) — never truncated. Any non-numeric kind returns an error.
Types ¶
type BlockPayload ¶
type BlockPayload interface{ ValueBlockMarker() }
BlockPayload is the marker implemented by the runtime block type.
type BuiltinPayload ¶
type BuiltinPayload interface{ ValueBuiltinMarker() }
BuiltinPayload is the marker implemented by the runtime builtin type.
type ClassPayload ¶
type ClassPayload interface{ ValueClassMarker() }
ClassPayload is the marker implemented by the runtime class type so Value.Class can return a typed result without importing the runtime.
type Duration ¶
type Duration struct {
// contains filtered or unexported fields
}
Duration stores an integer number of seconds for now.
func DurationFromParts ¶
DurationFromParts assembles a Duration from week, day, hour, minute, and second components.
func DurationFromSeconds ¶
DurationFromSeconds builds a Duration from a whole-second count.
func ParseDurationString ¶
ParseDurationString parses a duration in Go's time.ParseDuration format or in ISO-8601 form.
func SecondsDuration ¶
SecondsDuration returns a Duration corresponding to the given integer value interpreted in the named time unit (seconds, minutes, hours, days, weeks, and their singular forms).
type EnumPayload ¶
type EnumPayload interface{ ValueEnumMarker() }
EnumPayload is the marker implemented by the runtime enum type.
type EnumValuePayload ¶
type EnumValuePayload interface{ ValueEnumValueMarker() }
EnumValuePayload is the marker implemented by the runtime enum-value type.
type EqualityContext ¶ added in v0.60.0
type EqualityContext struct {
// contains filtered or unexported fields
}
EqualityContext reuses the cycle-detection scratch used by Value equality. The zero value is ready to use. It is not safe for concurrent use. It is intended for the interpreter's internal use; hosts should not rely on it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (*EqualityContext) Equal ¶ added in v0.60.0
func (c *EqualityContext) Equal(v, other Value) bool
Equal reports whether v and other hold the same kind and value.
type FunctionPayload ¶
type FunctionPayload interface{ ValueFunctionMarker() }
FunctionPayload is the marker implemented by the runtime script-function type.
type HashEntry ¶ added in v0.60.0
HashEntry is one hash entry with the original script key preserved.
type HashLookupKey ¶
type HashLookupKey struct {
// contains filtered or unexported fields
}
HashLookupKey is a comparable hash-key identity used for hash table lookups. It preserves Ruby-style key identity without materializing canonical strings for scalar keys on hot paths. It is intended for the interpreter's internal use; hosts should not rely on it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func NewHashLookupKey ¶
func NewHashLookupKey(key Value) (HashLookupKey, error)
NewHashLookupKey returns the comparable lookup key for a hash key value. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (HashLookupKey) ExtraPayloadBytes ¶
func (k HashLookupKey) ExtraPayloadBytes() int
ExtraPayloadBytes returns heap bytes stored only by this lookup key, excluding the fixed HashLookupKey struct itself. Scalar lookup keys either keep their payload in numeric fields or alias the original key value's string payload; array keys and big-integer keys retain a canonical lookup string that is not reachable otherwise. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
type InstancePayload ¶
type InstancePayload interface{ ValueInstanceMarker() }
InstancePayload is the marker implemented by the runtime instance type.
type Money ¶
type Money struct {
// contains filtered or unexported fields
}
Money represents an ISO-4217 currency amount stored as integer cents.
func NewMoneyFromCents ¶
NewMoneyFromCents constructs a Money from an integer cents value and a currency code.
func ParseMoneyLiteral ¶
ParseMoneyLiteral parses a textual money literal of the form "X.XX CUR".
func (Money) Add ¶
Add returns the sum of m and other, or an error if their currencies differ or the result would overflow the int64 cents range.
func (Money) DivInt ¶
DivInt divides m by the given integer divisor, returning an error on division by zero or on the one signed-division overflow case (MinInt64 / -1, whose true result is not representable in int64).
func (Money) MulInt ¶
MulInt multiplies m by the given integer factor, preserving the currency, or returns an error if the result would overflow the int64 cents range.
type Range ¶
type Range struct {
Start int64
End int64
Exclusive bool
// Beginless and Endless mark Ruby's open-ended ranges (..n and n..).
// The corresponding endpoint field is meaningless when its flag is set;
// both false is an ordinary bounded range, so existing constructors are
// unaffected. Both true is never produced (a bare .. is a parse error).
Beginless bool
Endless bool
}
Range represents an integer range. End is included unless Exclusive is true. It is a domain-shaped scalar that also serves as a Value payload (KindRange); it lives in the value package alongside Value itself because of that coupling. See doc.go for the rationale.
type Regex ¶ added in v0.60.0
Regex is the payload of a KindRegex value: a compiled Ruby-style regex literal. Source is the pattern text between the slashes exactly as written (Go RE2 syntax), Flags holds the literal's flag letters in source order, and Compiled is the ready-to-match engine program the runtime compiled with the flags applied. A Regex is immutable once constructed, so values share it freely across clones and task boundaries.
func (Regex) String ¶ added in v0.60.0
String renders the regex the way it is written in source: /pattern/flags. The source is escaped so wrapping it in delimiters yields a valid, round-trippable literal. Without this, a source built from a string (Regexp.new("a/b"), Regexp.new("\n")) would render /a/b/ or embed a raw newline, neither of which the lexer can re-parse.
type SliceIdentity ¶
SliceIdentity captures the identity of a slice header so cycle detection in value graphs can recognize revisits. It is intended for the interpreter's internal use; hosts should not rely on it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
type TypedHashEntry ¶
type TypedHashEntry struct {
LookupKey HashLookupKey
Entry HashEntry
}
TypedHashEntry is a typed hash entry paired with its stored lookup key. It is intended for the interpreter's internal use; hosts should not rely on it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
type Value ¶
type Value struct {
// contains filtered or unexported fields
}
Value is a tagged union holding any Vibescript runtime value.
func AdoptBigInt ¶ added in v0.60.0
AdoptBigInt wraps i in an integer Value without copying, taking ownership: the caller must not retain or mutate i afterwards, since big payloads are immutable once wrapped. Like NewBigInt it normalizes an int64-range value to the compact representation. It exists so the interpreter's arithmetic can promote freshly computed results without a defensive copy. It is intended for the interpreter's internal use; hosts should use NewBigInt, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func HashDefaultProc ¶
HashDefaultProc returns the default proc configured for a hash, or NewNil() when v is not a hash or carries no default proc. The returned value, when present, is the KindBlock the runtime invokes on missing-key lookup.
func HashDefaultValue ¶
HashDefaultValue returns the default value configured for a hash, or NewNil() when v is not a hash or carries no default value. It is the plain-value counterpart to HashDefaultProc.
func NewArray ¶
NewArray returns an array Value.
Example ¶
package main
import (
"fmt"
"github.com/mgomes/vibescript/vibes/value"
)
func main() {
v := value.NewArray([]value.Value{
value.NewInt(1),
value.NewInt(2),
value.NewInt(3),
})
fmt.Println(v.String())
}
Output: [1, 2, 3]
func NewBigInt ¶ added in v0.60.0
NewBigInt returns an integer Value holding i's value. The input is copied, so later mutations of i do not affect the returned Value. A value that fits in int64 is normalized to the same compact representation NewInt produces (see the canonical invariant above), so NewBigInt(big.NewInt(1)) and NewInt(1) are indistinguishable. A nil input yields the integer 0.
func NewDuration ¶
NewDuration returns a duration Value.
Example ¶
package main
import (
"fmt"
"github.com/mgomes/vibescript/vibes/value"
)
func main() {
v := value.NewDuration(value.DurationFromSeconds(90))
fmt.Println(v.String())
}
Output: 90s
func NewHash ¶
NewHash returns a hash (map) Value with no default.
Example ¶
package main
import (
"fmt"
"github.com/mgomes/vibescript/vibes/value"
)
func main() {
v := value.NewHash(map[string]value.Value{
"name": value.NewString("acme"),
})
fmt.Println(v.String())
}
Output: {name: acme}
func NewHashWithDefault ¶
NewHashWithDefault returns a hash (map) Value carrying Ruby-style default metadata. A non-nil defaultProc (a KindBlock value) takes precedence over defaultValue on missing-key lookup; pass NewNil() for whichever is unused.
func NewInt ¶
NewInt returns an integer Value.
Example ¶
package main
import (
"fmt"
"github.com/mgomes/vibescript/vibes/value"
)
func main() {
v := value.NewInt(42)
fmt.Println(v.String())
}
Output: 42
func NewMoney ¶
NewMoney returns a money Value.
Example ¶
package main
import (
"fmt"
"github.com/mgomes/vibescript/vibes/value"
)
func main() {
amount, err := value.NewMoneyFromCents(1999, "USD")
if err != nil {
panic(err)
}
v := value.NewMoney(amount)
fmt.Println(v.String())
}
Output: 19.99 USD
func NewObject ¶
NewObject returns an object Value with the given attributes. A nil map is replaced with a freshly allocated empty map so that every object has its own backing storage and thus a distinct object identity. (Hashes get the same per-instance identity from their hashData wrapper, which NewHash allocates fresh on every call.)
func NewString ¶
NewString returns a string Value.
Example ¶
package main
import (
"fmt"
"github.com/mgomes/vibescript/vibes/value"
)
func main() {
v := value.NewString("hello")
fmt.Println(v.String())
}
Output: hello
func NewTypedHash ¶
NewTypedHash returns a hash with typed-key storage and no materialized legacy string-key map. Hash() materializes that map lazily for legacy callers.
func NewValue ¶
NewValue constructs a Value with the given kind and underlying data. It is intended for use by the vibes package when wrapping runtime payloads (blocks, classes, instances, enums, functions, builtins) whose types live outside this package. Hosts should use the typed constructors (NewInt, NewArray, ...); NewValue carries no compatibility promise for payload shapes (see docs/embedding-api-stability.md).
func (Value) Array ¶
Array returns the array content of v, or nil if v is not an array. The returned slice is the array's live backing: element writes through it are visible to every alias of the array, but callers must not assume its length stays current across Ruby-style in-place mutators (push, pop, ...), which swap the wrapper's element slice.
func (Value) BigInt ¶ added in v0.60.0
BigInt returns the integer content of v as a *big.Int for every KindInt value, compact or big. The result is a fresh copy the caller owns; mutating it never affects v. It returns nil when v is not an integer.
func (Value) Block ¶
func (v Value) Block() BlockPayload
Block returns the underlying block payload of v, or nil if v is not a block. The concrete type is private to the runtime; callers operate through the BlockPayload marker.
func (Value) Builtin ¶
func (v Value) Builtin() BuiltinPayload
Builtin returns the underlying builtin payload of v, or nil if v is not a builtin. The concrete type is private to the runtime; callers operate through the BuiltinPayload marker.
func (Value) Class ¶
func (v Value) Class() ClassPayload
Class returns the underlying class payload of v, or nil if v is not a class. The concrete type is private to the runtime; callers operate through the ClassPayload marker.
func (Value) CompactInt ¶ added in v0.60.0
CompactInt returns v's integer content and true when v is an integer that fits in int64 (the compact representation). It returns (0, false) for big integers and non-integers, letting callers that require an int64 distinguish a genuine zero from an out-of-range value, which Int alone cannot. It is intended for the interpreter's internal use; hosts should combine IsBigInt with Int, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) Data ¶
Data returns the underlying payload stored in v. Callers are expected to type-assert against the payload type associated with v.Kind(). Prefer the typed accessors (Int, Array, Hash, ...): they cover every kind, and for the runtime-only kinds (functions, blocks, classes, instances, enums) the concrete payload type behind Data is internal to the interpreter and carries no compatibility promise.
An integer outside the int64 range exposes its live *big.Int payload, like arrays and hashes expose their live backing. Mutating it corrupts the value (big payloads are immutable by contract); callers that need an owned copy use BigInt instead.
func (Value) Duration ¶
Duration returns the duration content of v, or a zero Duration if v is not a duration.
func (Value) Enum ¶
func (v Value) Enum() EnumPayload
Enum returns the underlying enum definition payload of v, or nil if v is not an enum. The concrete type is private to the runtime; callers operate through the EnumPayload marker.
func (Value) EnumValue ¶
func (v Value) EnumValue() EnumValuePayload
EnumValue returns the underlying enum value payload of v, or nil if v is not an enum value. The concrete type is private to the runtime; callers operate through the EnumValuePayload marker.
func (Value) Eql ¶ added in v0.60.0
Eql reports whether v and other are equal under hash-key semantics: they must share the same kind and compare equal, so an Int never eql-matches a Float even when their numeric values coincide. It backs the Ruby-style `eql?` predicate. Because Equal already requires matching kinds (Vibescript `==` performs no cross-kind numeric coercion), Eql currently coincides with Equal; it exists as a distinct, documented contract aligned with hash-key equality rather than with broad value equivalence.
func (Value) Equal ¶
Equal reports whether v and other hold the same kind and value.
Example ¶
ExampleValue_Equal contrasts equal and unequal Values across kinds.
package main
import (
"fmt"
"github.com/mgomes/vibescript/vibes/value"
)
func main() {
a := value.NewInt(1)
b := value.NewInt(1)
c := value.NewString("1")
fmt.Println(a.Equal(b))
fmt.Println(a.Equal(c))
}
Output: true false
func (Value) Float ¶
Float returns the float content of v, coercing from int if needed. An integer outside the int64 range converts best-effort to the nearest float64; magnitudes beyond the float64 range yield +/-Infinity, matching Ruby's Integer#to_f.
func (Value) Function ¶
func (v Value) Function() FunctionPayload
Function returns the underlying script-function payload of v, or nil if v is not a function. The concrete type is private to the runtime; callers operate through the FunctionPayload marker.
func (Value) Hash ¶
Hash returns the hash content of v, or nil if v is not a hash or object. A KindHash payload wraps its entries in a hashData struct (to carry optional default metadata); a KindObject payload is a bare map.
func (Value) HashClearEntries ¶ added in v0.60.0
func (v Value) HashClearEntries()
HashClearEntries removes every entry from a hash or object in place, preserving a hash's Ruby-style default metadata (Ruby's Hash#clear keeps the default). The typed-entry map, insertion order, and any materialized legacy map are replaced with fresh empty storage so the old backings are released.
func (Value) HashDeleteKey ¶ added in v0.60.0
HashDeleteKey removes the entry for key from a hash or object in place, returning the removed value and whether the key was present. On a typed hash it removes the key's slot from the recorded insertion order (keeping the order/entries invariant HashSet maintains) and mirrors the removal into the materialized legacy map when one exists. A missing key leaves the hash untouched. An error is returned only for an unsupported key.
func (Value) HashEntries ¶ added in v0.60.0
HashEntries returns hash entries with original keys preserved. Objects are exposed as string-keyed entries.
func (Value) HashEntriesInto ¶ added in v0.60.0
HashEntriesInto appends hash entries with original keys preserved into buf when it has enough capacity. Typed entries appear in Ruby-style insertion order; legacy string-map entries appear in Go map order (callers that need determinism for legacy hashes sort by key themselves). It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) HashHasTypedEntries ¶
HashHasTypedEntries reports whether a hash carries canonical typed-key entries in addition to the legacy string-key map exposed by Hash(). It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) HashSet ¶ added in v0.60.0
HashSet stores key/value in a hash or object. On a hash it preserves Ruby-style insertion order: a new key is appended to the recorded order and an existing key keeps its original position while taking the new value.
func (Value) HashStringMapIfMaterialized ¶
HashStringMapIfMaterialized returns the legacy string-key map when one already exists, without forcing typed hashes to allocate that lossy compatibility view. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) Identical ¶ added in v0.60.0
Identical reports whether v and other refer to the same object, backing the Ruby-style `equal?` predicate. Immutable value kinds (nil, bool, int, float, string, symbol, money, duration, time, range) are identical when they share the same kind and value, since the language exposes no distinct identities for equal immutables. Integers outside the int64 range are the exception: they are heap objects and compare by payload identity, matching Ruby, where bignums are separate objects. Mutable composites (array, hash, object) and runtime-only kinds (function, builtin, block, class, instance, enum, enum value) are identical only when they share the same backing storage, so two independently constructed composites with equal contents are not identical.
NaN floats are the one immutable case where value equality is not enough: IEEE NaN != NaN, so deferring to Equal would make x.equal?(x) false for a NaN receiver and break reflexivity. Identity treats any two NaN floats as identical, keeping equal? reflexive while matching the value-identity model floats already follow.
Empty arrays are the one principled exception: any two empty arrays report identical regardless of their backing storage. This is harmless because an empty array has no element storage to alias — appending to one never affects another — so they behave as a single value-like empty rather than as distinct mutable objects. Backing pointers alone cannot establish this, because an empty result preallocated with spare capacity (for example array.select starting from make([]Value, 0, len(arr))) carries its own non-zerobase pointer and a different capacity than a literal []; only a length check captures the contract. Empty hashes and objects stay distinct because every hash carries its own hashData wrapper (NewHash allocates a fresh one per call) and NewObject allocates a fresh backing map for nil input, so each empty composite has a distinct identity rather than collapsing onto a shared zero pointer.
func (Value) Inspect ¶ added in v0.60.0
Inspect returns a debug representation of v, mirroring Ruby's Object#inspect. Unlike String (which is the to_s form), Inspect preserves quoting and escaping for strings, renders symbols with their leading colon, and recurses into arrays and hashes so the result is a stable, parseable debug rendering. Hash entries use Vibescript's colon-label key form (`{ name: "Ada" }`) rather than Ruby's hash-rocket syntax, which Vibescript does not support, so the output round-trips as a Vibescript literal. Cycles are collapsed to <cycle> exactly like String.
func (Value) InspectBounded ¶ added in v0.60.0
InspectBounded renders v like Inspect but stops once the formatted output would exceed limit bytes, returning the partial output and ErrStringRenderTruncated. A non-positive limit means unbounded and behaves exactly like Inspect. Like StringBounded, it writes into a single growing buffer and checks the budget after each piece, so a hostile composite cannot allocate an output much larger than limit before the budget trips. Cycle handling is identical to Inspect.
func (Value) InspectByteLenBounded ¶ added in v0.60.0
InspectByteLenBounded reports the number of bytes Inspect would produce for v without materializing the rendering, so callers can bound an allocation before it happens. It walks composites with the same cycle detection Inspect uses and invokes step once per node visited, so a caller can charge a sandbox step budget against the traversal and abort it when step returns an error. The first error step reports stops the walk and is returned alongside the partial count. See StringByteLenBounded for why driving step from inside the walk matters for shared-but-acyclic graphs. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) Instance ¶
func (v Value) Instance() InstancePayload
Instance returns the underlying instance payload of v, or nil if v is not an instance. The concrete type is private to the runtime; callers operate through the InstancePayload marker.
func (Value) Int ¶
Int returns the integer content of v, coercing from float if needed. An integer outside the int64 range (IsBigInt) returns 0, the same fallback a wrong-kind value gets — never a truncated or wrapped result. Callers that must handle big integers use BigInt (or IsBigInt to detect them first).
func (Value) IsBigInt ¶ added in v0.60.0
IsBigInt reports whether v is an integer whose value lies outside the int64 range (and therefore carries a big-integer payload). Int64-range integers always use the compact representation, so IsBigInt is equivalent to "this integer does not fit in an int64".
func (Value) Regex ¶ added in v0.60.0
Regex returns the regex payload of v. It panics when v is not a regex, like the other kind accessors.
func (Value) ReserveHashOrder ¶ added in v0.60.0
ReserveHashOrder pre-sizes the insertion-order backing to capacity n so a builder that knows its final entry count avoids the append growth overshoot, where a hash of 3 entries would otherwise retain 4 order slots. This keeps the backing's capacity equal to the entry count the memory-quota projection charges. It does not initialize typed-entry storage, so hash literals can reserve order capacity without allocating typed buckets before their per-entry accounting runs. It is a no-op when v is not a hash, n is non-positive, or the backing already has at least n slots. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) ReserveTypedHashOrder ¶
ReserveTypedHashOrder prepares an empty hash builder for typed-key writes and reserves its insertion-order backing. It preserves a materialized legacy map when one already exists, which keeps Hash() callers synchronized as HashSet populates typed entries. It is a no-op for non-hashes, negative capacities, or legacy hashes that already contain entries. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) SetArrayElems ¶ added in v0.60.0
SetArrayElems replaces the element slice of an existing array wrapper in place. It is the primitive behind the runtime's Ruby-style mutators: because the wrapper is shared by every Value that aliases the array, the new elements are visible through all of them. It is a no-op when v is not an array. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) SetHashDefaults ¶
SetHashDefaults overwrites the Ruby-style default metadata of an existing hash wrapper in place. It exists so a deep clone can register the destination wrapper in its seen-set before it walks the default value/proc: a default that reaches the hash itself (e.g. Hash.new { |_, _| h }) then dedups against the already-registered wrapper instead of cloning a second one whose defaults would close over the wrong object. v must be a hash whose wrapper is not yet shared; mutating a hash that other Values observe would change their defaults. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) String ¶
String returns the string representation of v.
Example ¶
package main
import (
"fmt"
"github.com/mgomes/vibescript/vibes/value"
)
func main() {
v := value.NewString("hello")
fmt.Println(v.String())
}
Output: hello
func (Value) StringBounded ¶ added in v0.60.0
StringBounded renders v like String but stops once the formatted output would exceed limit bytes, returning the partial output and ErrStringRenderTruncated. A non-positive limit means unbounded and behaves exactly like String. Rendering writes directly into a single growing buffer and checks the budget after each element, so a hostile composite cannot allocate intermediate per-element strings or a final joined buffer larger than roughly limit plus one element before the limit trips. Cycle handling is identical to String.
func (Value) StringByteLen ¶ added in v0.60.0
StringByteLen returns the number of bytes String would produce for v without materializing the rendered representation. Callers that must bound an allocation before it happens (such as the sandbox's interpolation memory guard) use it to reject an oversized rendering instead of building the string first and only then observing that it exceeded a quota. The byte count walks arrays and hashes with the same cycle detection String uses, so the projection matches the eventual output exactly. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) StringByteLenBounded ¶ added in v0.60.0
StringByteLenBounded reports the same byte count as StringByteLen but invokes step once per node visited during the projection walk, so a caller can charge a sandbox step budget against the traversal and abort it when step returns an error. The first error step reports stops the walk and is returned unchanged alongside the partial count.
StringByteLen's cycle detection only collapses references that are currently on the recursion stack: a shared but acyclic graph (for example the result of repeatedly evaluating a = [a, a], where each level holds two references to the same child slice) is fully re-walked at every occurrence, so the traversal is exponential in the nesting depth even though the value's memory and its eventual rendering both stay bounded by the cycle marker. The memory quota alone cannot bound that work because it is checked only after the walk completes. Driving step from inside the walk lets the step quota trip during the traversal instead of letting it run unbounded. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) StringByteLenBoundedUpTo ¶ added in v0.60.0
func (v Value) StringByteLenBoundedUpTo(limit int, step func() error) (count int, truncated bool, err error)
StringByteLenBoundedUpTo reports String's byte length up to limit bytes. It stops as soon as it can prove the rendering would exceed limit, returning truncated as true and limit+1 as the count. Like StringByteLenBounded, it invokes step during aggregate walks so callers can charge sandbox work before materializing any rendering. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) StringRuneLen ¶ added in v0.60.0
StringRuneLen returns the number of runes String would produce for v without materializing the rendered representation. It mirrors StringByteLen but counts display width in the unit fmt uses for string precision and padding. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) StringRuneLenBounded ¶ added in v0.60.0
StringRuneLenBounded reports the same rune count as StringRuneLen but invokes step once per node visited during the projection walk, matching StringByteLenBounded's sandbox accounting. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) TypedHashEntriesInto ¶
func (v Value) TypedHashEntriesInto(buf []TypedHashEntry) []TypedHashEntry
TypedHashEntriesInto appends typed hash entries and their stored lookup keys into buf. It returns nil for non-hash values and hashes that still use only the legacy string-key map. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) WriteInspectTo ¶ added in v0.60.0
WriteInspectTo streams the same bytes Inspect would return for v directly into buf, without first materializing the rendered representation as a separate string. It mirrors WriteStringTo: callers that have already bounded the rendering against a quota (such as the sandbox's inspect memory guard, which reserves the projected length before calling) use it to render straight into a builder they grew to the projected size, so the peak allocation stays the single backing array the quota already charged rather than the doubling growth a fresh zero-capacity builder would take. It delegates to the unbounded inspect renderer, so writing into a strings.Builder never fails. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
func (Value) WriteStringTo ¶ added in v0.60.0
WriteStringTo streams the same bytes String would return for v directly into buf, without first materializing the rendered representation as a separate string. Callers that have already bounded the rendering against a quota (such as the sandbox's interpolation memory guard, which reserves the projected length before calling) use it to stream an aggregate straight into their builder instead of allocating the full rendering and then copying it, which would transiently hold both the temporary and the destination copy and could exceed a memory limit the projected length already passed. It delegates to the unified unbounded renderer, so writing into a strings.Builder never fails. It is intended for the interpreter's internal use; hosts should not call it, and it carries no compatibility promise (see docs/embedding-api-stability.md).
type ValueKind ¶
type ValueKind int
ValueKind identifies the type of a runtime Value.
const ( // KindNil is the nil value kind. KindNil ValueKind = iota // KindBool tags a boolean payload (Bool). KindBool // KindInt tags a 64-bit integer payload (Int). KindInt // KindFloat tags a 64-bit floating-point payload (Float). KindFloat // KindString tags a string payload (String). KindString // KindArray tags a mutable array payload (Array). The payload is a // shared wrapper, so Value copies alias the same elements. KindArray // KindHash tags a mutable hash payload (Hash, HashGet, HashSet, ...). // Like arrays, the payload is a shared wrapper. KindHash // KindFunction tags a script-defined function (Function). The concrete // payload type lives in the runtime. KindFunction // KindBuiltin tags a Go-implemented builtin function (Builtin). KindBuiltin // KindMoney tags a Money payload (Money). KindMoney // KindDuration tags a Duration payload (Duration). KindDuration // KindTime tags a time.Time payload (Time). KindTime // KindSymbol tags a Ruby-style symbol; String returns its name without // the leading colon. KindSymbol // KindObject tags a string-keyed attribute bag (Hash exposes the map). // Unlike KindHash it never carries default metadata. KindObject // KindRange tags a Range payload (Range). KindRange // KindBlock tags a script block (Block). The concrete payload type // lives in the runtime. KindBlock // KindEnum tags an enum definition (Enum). The concrete payload type // lives in the runtime. KindEnum // KindEnumValue tags one member of an enum (EnumValue). The concrete // payload type lives in the runtime. KindEnumValue // KindClass tags a script-defined class (Class). The concrete payload // type lives in the runtime. KindClass // KindInstance tags an instance of a script-defined class (Instance). // The concrete payload type lives in the runtime. KindInstance // KindRegex tags a compiled regex literal payload (Regex). KindRegex )