value

package
v0.70.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2026 License: MIT Imports: 18 Imported by: 0

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

Examples

Constants

View Source
const ArrayDataBytes = int(unsafe.Sizeof(arrayData{}))

ArrayDataBytes is the heap footprint of the arrayData wrapper every KindArray value allocates, excluding the element backing it points at. Memory-quota accounting charges it once per distinct array so a workload retaining many small arrays cannot hold the per-array wrapper cost uncharged.

It is derived from the struct rather than restated as a number so that a field added to arrayData is charged by the same commit that adds it. head was added without one, which took the wrapper from 24 bytes to 32 and left 8 of them unmetered per array -- an under-count introduced by a fix for an under-count. 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).

View Source
const HashDataBytes = int(unsafe.Sizeof(hashData{}))

HashDataBytes is the heap footprint of the hashData wrapper every KindHash value allocates, excluding the entry map and order backing 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).

View Source
const ObjectDataBytes = int(unsafe.Sizeof(objectData{}))

ObjectDataBytes is the heap footprint of the objectData wrapper every KindObject value allocates around its entry map, for the sandbox's memory accounting.

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

View Source
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.

View Source
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).

View Source
var ErrStringRenderDepthExceeded = errors.New("value: string rendering exceeded nesting limit 16384")

ErrStringRenderDepthExceeded reports that StringBounded or InspectBounded stopped before descending beyond 16,384 nested composites. This limit applies independently of the byte budget, including when that budget is unbounded. Callers detect it with errors.Is; it is distinct from byte truncation.

View Source
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.

View Source
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).

View Source
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).

View Source
var RuntimeStringAppender func(v Value, buf *strings.Builder, limit int) (truncated, handled bool)

RuntimeStringAppender writes the bytes Value.String would return for a runtime-only kind straight into buf, so a rendering streamed into a caller's charged buffer never also exists as a temporary alongside it.

limit is the total byte budget for buf, matching appendBounded: a non-positive limit writes everything, and otherwise the hook writes at most limit-buf.Len() bytes and reports truncated when it had more to write. This keeps precision-qualified formats -- format("%.1s", Huge::Member) -- from materializing a whole rendering to throw nearly all of it away. 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).

View Source
var RuntimeStringLen func(v Value) (int, bool)

RuntimeStringLen reports the byte length Value.String would return for a runtime-only kind, computed from the payload rather than by building the string. A projection that answers through RuntimeStringer allocates the very rendering it is meant to decide about, which defeats the guard. 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).

View Source
var RuntimeStringRuneLen func(v Value) (int, bool)

RuntimeStringRuneLen reports the rune count Value.String would return for a runtime-only kind, counted from the payload rather than from a materialized rendering. Width-qualified formatting projects rune lengths, so this is the same guard RuntimeStringLen provides for the byte-length 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).

View Source
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

func ArrayIdentity(v Value) uintptr

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 and carries no compatibility promise (see docs/embedding-api-stability.md). Wrapper identity is not part of the supported host API: Value.Identical compares collection contents, not wrappers. Hosts that need provenance must track it outside Value.

func ArrayWindowHead added in v0.60.0

func ArrayWindowHead(v Value) int

ArrayWindowHead returns how many element slots an array's elements start past the beginning of the allocation they sit in, or 0 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 BigIntDecimalLenUpperBound added in v0.60.0

func BigIntDecimalLenUpperBound(v Value) int

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

func BigIntPayload(v Value) (*big.Int, bool)

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 BumpLocalMutationEpoch added in v0.70.0

func BumpLocalMutationEpoch()

BumpLocalMutationEpoch records a write tracked separately by its lexical environment. It preserves the process-wide signal used by contract checks without invalidating unrelated estimator graphs. It is intended for interpreter bookkeeping and carries no compatibility promise.

func BumpMutationEpoch added in v0.60.0

func BumpMutationEpoch()

BumpMutationEpoch conservatively invalidates every estimator. Use it for raw writes whose affected identities cannot be tracked. It is intended for interpreter bookkeeping and carries no compatibility promise.

func EitherIntPayload added in v0.60.0

func EitherIntPayload(a, b Value) bool

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

func FormatFloat(f float64) string

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 HashEntryCapacity added in v0.60.0

func HashEntryCapacity(v Value) int

HashEntryCapacity returns the minimum 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 buckets that may exceed the live entry count. 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

func HashIdentity(v Value) uintptr

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 are distinct.

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 and host guidance). It is intended for the interpreter's internal use and carries no compatibility promise (see docs/embedding-api-stability.md).

func HashIterationScratchBytes added in v0.60.0

func HashIterationScratchBytes(v Value) int

HashIterationScratchBytes is the heap []Value hashIterationKeys allocates when it cannot use the recorded order and the hash is larger than the inline key buffer. Rendering projections reserve this so a live-map fallback cannot push an otherwise admitted to_s past the memory quota. 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 HashKeyString added in v0.60.0

func HashKeyString(key Value) (string, error)

HashKeyString returns the entry a hash key value addresses. Strings and symbols are the only accepted key inputs and a symbol normalizes to its name, so `hash["name"]`, `hash[:name]`, and the literal label `name:` all address one entry. Every other kind is rejected, and the error names what is accepted.

func HashOrderCapacity added in v0.60.0

func HashOrderCapacity(v Value) int

HashOrderCapacity returns the capacity of the insertion-order backing a hash retains alongside its entries, or 0 when v is not a hash or tracks no order. Memory-quota accounting charges the backing's structural bytes; the key Values inside it alias key 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 MutationEpoch added in v0.60.0

func MutationEpoch() uint64

MutationEpoch returns the process-wide mutation sequence. It is intended for interpreter bookkeeping and carries no compatibility promise.

func NumericToSeconds

func NumericToSeconds(val Value) (int64, error)

NumericToSeconds converts an integer or floating-point Value to a count of whole seconds.

func ObjectIdentity added in v0.60.0

func ObjectIdentity(v Value) uintptr

ObjectIdentity returns the identity of the objectData wrapper a KindObject value allocates, or 0 for anything else. Each wrapper is a distinct allocation even when several share one entry map, so the sandbox's memory accounting deduplicates on this rather than on the map.

Like ArrayIdentity, it is a bare uintptr wrapper address (see ArrayIdentity for the stack-allocation caveat and host guidance). It is intended for the interpreter's internal use and carries no compatibility promise (see docs/embedding-api-stability.md).

func OpaqueMutationEpoch added in v0.70.0

func OpaqueMutationEpoch() uint64

OpaqueMutationEpoch returns the sequence of writes whose affected identities are unknown, including raw host writes. Every estimator must invalidate after one of these writes. It carries no compatibility promise.

func ParseLocation

func ParseLocation(val Value) (*time.Location, error)

ParseLocation parses a timezone specifier carried in a Value into a time.Location, returning (nil, nil) when val is nil.

func ParseLocationString

func ParseLocationString(spec string) (*time.Location, error)

ParseLocationString parses a timezone specifier string (named zone, fixed offset, or empty).

func ParseTimeString

func ParseTimeString(input, layout string, hasLayout bool, loc *time.Location) (time.Time, error)

ParseTimeString parses input into a time using layout when hasLayout is set, or the runtime's accepted timestamp forms otherwise. A nil loc keeps the zone rules described below; a non-nil loc resolves zoneless inputs in that location.

func PublishRefElems added in v0.60.0

func PublishRefElems(elems []Value)

PublishRefElems publishes every collection among elems. The array constructors call it, since an array adopts elements its caller may still hold, and so does every builder that hands NewArray a slice of values it did not itself construct.

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 PublishRefEntries added in v0.60.0

func PublishRefEntries(entries map[string]Value)

PublishRefEntries publishes every collection among a hash's values.

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 PublishReplacement added in v0.60.0

func PublishReplacement(previous, next Value)

PublishReplacement publishes next unless it is the wrapper previous already names, in which case the store duplicates no handle and must not count one.

It is what keeps `items = items.push(x)` linear. Writing a mutator's result back over the receiver it updated is the idiom value semantics asks for, and counting that store would leave the binding looking shared to the next iteration, so every push after the first would copy the whole 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 RegexSourceStepBytesForTest added in v0.60.0

func RegexSourceStepBytesForTest() int

RegexSourceStepBytesForTest exposes regexSourceStepBytes so the runtime's test suite can hold it equal to its own byte-work rate. The constant is duplicated because this package cannot import the runtime.

func TimeFromCalendarParts added in v0.60.0

func TimeFromCalendarParts(args []Value, defaultLoc *time.Location) (time.Time, error)

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

func TimeFromParts(args []Value, defaultLoc *time.Location) (time.Time, error)

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

func ValueToInt64(val Value) (int64, error)

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.

func WrapperMutationEpoch added in v0.70.0

func WrapperMutationEpoch() uint64

WrapperMutationEpoch returns the latest wrapper journal sequence. It is intended for interpreter bookkeeping and carries no compatibility promise.

func WrapperMutationsAffect added in v0.70.0

func WrapperMutationsAffect(after, through uint64, affects func(MutationKind, uintptr, uintptr) bool) bool

WrapperMutationsAffect reports whether writes in (after, through] affect a cached graph. Missing or overwritten records conservatively answer true. The fixed journal stores addresses rather than pointers, so it retains no values and allocates no memory per write. It is intended for interpreter bookkeeping and carries no compatibility promise.

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

func DurationFromParts(weeks, days, hours, minutes, seconds int64) Duration

DurationFromParts assembles a Duration from week, day, hour, minute, and second components.

func DurationFromSeconds

func DurationFromSeconds(seconds int64) Duration

DurationFromSeconds builds a Duration from a whole-second count.

func ParseDurationString

func ParseDurationString(input string) (Duration, error)

ParseDurationString parses a duration in Go's time.ParseDuration format or in ISO-8601 form.

func SecondsDuration

func SecondsDuration(value int64, unit string) Duration

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).

func (Duration) ISO8601

func (d Duration) ISO8601() string

ISO8601 returns the duration formatted as an ISO-8601 string.

func (Duration) Parts

func (d Duration) Parts() map[string]int64

Parts decomposes the duration into days, hours, minutes, and seconds.

func (Duration) Seconds

func (d Duration) Seconds() int64

Seconds returns the duration as a whole number of seconds.

func (Duration) String

func (d Duration) String() string

String returns the duration formatted as "<n>s".

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 and optionally carries a byte charge for the string payloads a comparison reads (see SetCharge). The zero value is ready to use and compares unmetered. 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) Eql added in v0.60.0

func (c *EqualityContext) Eql(v, other Value) bool

Eql reports whether v and other are equal under hash-key semantics: kinds must match at every level (see Value.Eql). It shares the context's scratch, charge hook, and sticky error with Equal.

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.

func (*EqualityContext) Err added in v0.60.0

func (c *EqualityContext) Err() error

Err returns the first charge failure recorded on this context, or nil. Once non-nil, comparison answers from this context are meaningless and the caller must surface the error instead.

func (*EqualityContext) SetCharge added in v0.60.0

func (c *EqualityContext) SetCharge(charge func(bytes int) error)

SetCharge installs a byte charge invoked for the string and symbol payloads a comparison reads: scalar leaves that pass the length screen, and string-like hash keys whose text is hashed or compared. A charge failure makes the current and every subsequent comparison on this context answer false; callers observe the failure through Err. A nil charge restores unmetered comparison.

func (*EqualityContext) SetScratchAllocRounder added in v0.60.0

func (c *EqualityContext) SetScratchAllocRounder(round func(bytes int) int)

SetScratchAllocRounder installs the allocator projection applied when the walk reserves an allocation of known size — the rendered display key of a composite hash key: round receives the requested byte size and returns the capacity the allocator will actually reserve for it. Reserving the unrounded request would let a budget that sits between the request and the realized size-class capacity admit an allocation exceeding it. A nil rounder reserves requests at their exact size.

func (*EqualityContext) SetScratchReleaser added in v0.60.0

func (c *EqualityContext) SetScratchReleaser(release func())

SetScratchReleaser installs a callback invoked when a comparison finishes with its transient scratch. A validator that only inspects the total it is handed needs nothing here. One that holds an accounting reservation against the walk's scratch — so that memory checks elsewhere account for it while the walk runs — retires that reservation here, since the slices are unreachable once the comparison returns. It is separate from the reserver so that the reserved figure stays a plain byte count rather than carrying a sentinel for the walk's lifecycle.

func (*EqualityContext) SetScratchReserver added in v0.60.0

func (c *EqualityContext) SetScratchReserver(reserve func(bytes int, left, right Value) error)

SetScratchReserver installs a validator for the walk's transient scratch allocations (the key slices deterministic map traversal sorts and the rendered display keys): it is invoked with the walk's cumulative scratch bytes and the active comparison's top-level operands before each allocation, and an error aborts the comparison like a charge failure. The operands accompany every validation because they can be temporaries no other root reaches, and the scratch coexists with both compared graphs at its peak. A nil reserver leaves allocations unvalidated.

type FunctionPayload

type FunctionPayload interface{ ValueFunctionMarker() }

FunctionPayload is the marker implemented by the runtime script-function type.

type HashEntry added in v0.60.0

type HashEntry struct {
	Key   Value
	Value Value
}

HashEntry is one hash entry. Hash keys live in one string keyspace, so Key is always a KindString value.

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

func NewMoneyFromCents(cents int64, currency string) (Money, error)

NewMoneyFromCents constructs a Money from an integer cents value and a currency code.

func ParseMoneyLiteral

func ParseMoneyLiteral(input string) (Money, error)

ParseMoneyLiteral parses a textual money literal of the form "X.XX CUR".

func (Money) Add

func (m Money) Add(other Money) (Money, error)

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) Cents

func (m Money) Cents() int64

Cents returns the amount in the smallest currency unit.

func (Money) Currency

func (m Money) Currency() string

Currency returns the ISO-4217 currency code.

func (Money) DivInt

func (m Money) DivInt(divisor int64) (Money, error)

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

func (m Money) MulInt(factor int64) (Money, error)

MulInt multiplies m by the given integer factor, preserving the currency, or returns an error if the result would overflow the int64 cents range.

func (Money) String

func (m Money) String() string

String returns the amount formatted as "X.XX CUR".

func (Money) Sub

func (m Money) Sub(other Money) (Money, error)

Sub returns m minus other, or an error if their currencies differ or the result would overflow the int64 cents range.

type MutationKind added in v0.70.0

type MutationKind uint64

MutationKind identifies the estimator identity an observed mutation changes. It is internal interpreter bookkeeping and carries no compatibility promise.

const (
	// MutationSlice changes an existing array backing.
	MutationSlice MutationKind = iota + 1
	// MutationHash changes a hash wrapper or its backing.
	MutationHash
	// MutationObject changes an object wrapper or its backing.
	MutationObject
)

type ObjectTag added in v0.60.0

type ObjectTag uint8

ObjectTag records what an attribute bag is, for the few bags the runtime builds to stand for something specific.

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). Behavior that would otherwise have to be inferred from a bag's field names reads the tag instead: field names are public, host-settable data, so any bag could carry the same ones and claim the same treatment.

const (
	// ObjectTagNone marks an ordinary attribute bag, which is every bag
	// NewObject builds. It is the zero value, so untagged is the default.
	ObjectTagNone ObjectTag = iota
	// ObjectTagRescuedError marks the bag a rescue binds, whose to_s is the
	// error message.
	ObjectTagRescuedError
	// ObjectTagMatchData marks the bag a regexp match returns, whose to_s is
	// the matched text as in Ruby's MatchData.
	ObjectTagMatchData
)

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.

func (Range) String added in v0.60.0

func (r Range) String() string

String renders the range the way it is written in source, including the open-ended forms: 1..5, 1..., ..5, 1.., and so on.

type Regex added in v0.60.0

type Regex struct {
	Source   string
	Flags    string
	Compiled *regexp.Regexp
}

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 call boundaries.

func (Regex) String added in v0.60.0

func (r Regex) String() string

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.

func (Regex) StringLen added in v0.60.0

func (r Regex) StringLen() int

StringLen reports the length String would return without building it.

Sizing a regex by measuring String() performs the escaping and allocation being measured, which a quota cannot then prevent and a caller that renders afterwards pays for twice. This walks the source instead, mirroring escapeRegexLiteralSource case for case; TestRegexStringLenMatchesString holds the two together.

func (Regex) StringRuneLen added in v0.60.0

func (r Regex) StringRuneLen() int

StringRuneLen reports the rune count String would return without building it.

Every escape the renderer emits is ASCII, so an escaped byte contributes as many runes as the escape has characters; a byte that passes through contributes as part of whatever rune it belongs to. Counting bytes will not do here, because a source may hold multibyte runes that survive unescaped.

type SliceIdentity

type SliceIdentity struct {
	Ptr uintptr
	Len int
	Cap int
}

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 Value

type Value struct {
	// contains filtered or unexported fields
}

Value is a tagged union holding any Vibescript runtime value.

func AdoptArray added in v0.60.0

func AdoptArray(a []Value) Value

AdoptArray wraps a without publishing its elements. Callers use it when those elements were already published as they entered the slice — a map that counted each block result at insert time — so wrapping the finished slice must not count the same slots again.

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 AdoptBigInt added in v0.60.0

func AdoptBigInt(i *big.Int) Value

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 AdoptHash added in v0.60.0

func AdoptHash(h map[string]Value) Value

AdoptHash wraps h without publishing its values. Callers use it when the map is accounting scratch that disappears after a memory check, so the wrapper must not mark those values retained.

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 NewArray

func NewArray(a []Value) Value

NewArray returns an array Value backed by a, which it takes ownership of.

The slice must not be one another array Value is already built over. An in-place shrink clears the slots it vacates, so a second array over the same storage would find elements it still shows blanked out, and a growing push through one of them reallocates without the other seeing it. Build a second array over the same contents with a copy of the slice, not the slice.

Every collection among the elements is published: an element slot now names it as well as wherever the caller got it from, so a later write through either must copy first. This is the one place array construction can see all of the elements at once, which is why the publish lives here rather than at the hundred builders that call it.

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

func NewBigInt(i *big.Int) Value

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 NewBool

func NewBool(b bool) Value

NewBool returns a boolean Value.

func NewDuration

func NewDuration(d Duration) Value

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 NewFloat

func NewFloat(f float64) Value

NewFloat returns a floating-point Value.

func NewHash

func NewHash(h map[string]Value) Value

NewHash returns a hash (map) Value over h. A non-empty map records no insertion order, so the hash iterates in sorted key order. The map is retained, not copied: if the caller keeps it, later mutation is treated like Hash() exposure and the recorded order stays untrusted.

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 NewHashWithCapacity added in v0.60.0

func NewHashWithCapacity(capacity int) Value

NewHashWithCapacity returns an empty hash whose entry map and insertion-order backing are pre-sized for capacity entries.

func NewHashWithOrder added in v0.60.0

func NewHashWithOrder(entries map[string]Value, order []Value) Value

NewHashWithOrder returns a hash over entries that iterates in the given key order. The order slice is adopted, so callers must not retain or reuse it; an order that does not cover entries falls back to sorted iteration. It exists for the copiers that clone an entry map wholesale and must reproduce the source's iteration order without rehashing every key. 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 NewHashWithTrustedOrder added in v0.60.0

func NewHashWithTrustedOrder(entries map[string]Value, order []Value) Value

NewHashWithTrustedOrder is NewHashWithOrder for an order that is already unique, such as HashKeyOrder() output. The inbound clone path uses this so Script.Call does not re-validate a snapshot it just took. 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 NewInt

func NewInt(i int64) Value

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

func NewMoney(m Money) Value

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 NewNil

func NewNil() Value

NewNil returns a nil Value.

func NewObject

func NewObject(attrs map[string]Value) Value

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 NewRange

func NewRange(r Range) Value

NewRange returns a range Value.

func NewRegex added in v0.60.0

func NewRegex(r Regex) Value

NewRegex returns a regex Value.

func NewString

func NewString(s string) Value

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 NewSymbol

func NewSymbol(name string) Value

NewSymbol returns a symbol Value.

func NewTaggedObject added in v0.60.0

func NewTaggedObject(attrs map[string]Value, tag ObjectTag, stringForm string) Value

NewTaggedObject returns an attribute bag carrying provenance. The tag rides in the scalar word, which an object otherwise leaves unused, so it costs nothing and cannot appear as an entry: it is invisible to keys, values, inspect, and JSON, and script code has no way to set it.

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 NewTime

func NewTime(t time.Time) Value

NewTime returns a time Value.

func NewValue

func NewValue(kind ValueKind, data any) Value

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) AdoptSoleRef added in v0.60.0

func (v Value) AdoptSoleRef()

AdoptSoleRef records that exactly one durable slot names the collection v. The copy a write makes when it finds a shared wrapper is installed at the one slot the write reached it through, so it starts again from sole ownership and the next write through that slot mutates in place. Without it a mutating loop would copy on every iteration.

Callers owe the invariant the name states: v must be a wrapper nothing else holds, installed at one slot.

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) AppendArrayElemNoEpoch added in v0.60.0

func (v Value) AppendArrayElemNoEpoch(elem Value)

AppendArrayElemNoEpoch appends elem to an array in place without bumping the mutation epoch. The epoch exists to invalidate memoized reachable-graph walks; the interpreter's charged-append path commits the element's bytes into that memo itself before appending, so the bump would only throw away accounting that is already correct. Callers that do not maintain the memo must use SetArrayElems. 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) Array

func (v Value) Array() []Value

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 through this wrapper, but callers must not assume its length stays current across the in-place mutators (push, pop, ...), which swap the wrapper's element slice.

func (Value) BigInt added in v0.60.0

func (v Value) BigInt() *big.Int

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) Bool

func (v Value) Bool() bool

Bool returns the boolean content of v, or false if v is not a bool.

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) BumpMutationEpoch added in v0.70.0

func (v Value) BumpMutationEpoch()

BumpMutationEpoch records an in-place write to v before its backing changes. The estimator already remembers hash/object wrappers and array backings, so it can invalidate only graphs containing that identity. Empty arrays retain the conservative fallback because their backing identity is not reliable in every supported build configuration. It is intended for interpreter bookkeeping and carries no compatibility promise.

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

func (v Value) CompactInt() (int64, bool)

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

func (v Value) Data() any

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

func (v Value) Duration() 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

func (v Value) Eql(other Value) bool

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

func (v Value) Equal(other Value) bool

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

func (v Value) Float() float64

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

func (v Value) Hash() map[string]Value

Hash returns the live entry map of v, or nil if v is not a hash or object. Hash keys are strings, so this is the whole content of the value; iteration order lives on the wrapper and is reached through HashEntries.

func (Value) HashClearEntries added in v0.60.0

func (v Value) HashClearEntries()

HashClearEntries removes every entry from a hash or object in place. A hash's entry map and insertion order are replaced with fresh empty storage so the old backings are released.

func (Value) HashDeleteKey added in v0.60.0

func (v Value) HashDeleteKey(key Value) (Value, bool, error)

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 hash it also removes the key's slot from the recorded insertion order, keeping the order/entries invariant HashSet maintains. A missing key leaves the hash untouched. An error is returned only for an unsupported key.

func (Value) HashEntries added in v0.60.0

func (v Value) HashEntries() []HashEntry

HashEntries returns hash entries in iteration order. Objects are exposed as string-keyed entries in sorted key order.

func (Value) HashEntriesInto added in v0.60.0

func (v Value) HashEntriesInto(buf []HashEntry) []HashEntry

HashEntriesInto appends hash entries into buf when it has enough capacity. Entries appear in the order the hash iterates: Ruby-style insertion order for a hash built through HashSet, and sorted key order for a bare map handed in by a host, which records no insertion order. The copy snapshots the entries, so a script block that mutates the receiver mid-iteration cannot skew the walk. 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 (Value) HashEntryMap added in v0.60.0

func (v Value) HashEntryMap() map[string]Value

HashEntryMap returns the live entry map without recording that a host can mutate it. Internal walks and clones use this; Hash() is the embedding API that exposes the map for mutation. 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 (Value) HashGet added in v0.60.0

func (v Value) HashGet(key Value) (Value, bool, error)

HashGet returns the value for key from a hash or object. A key that is neither a string nor a symbol is rejected rather than reported as a miss.

func (Value) HashKeyOrder added in v0.60.0

func (v Value) HashKeyOrder() []Value

HashKeyOrder returns a fresh snapshot of the key order v iterates in. It pairs with NewHashWithOrder so a copier that clones an entry map wholesale can give the copy its source's iteration order. 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) HashLen added in v0.60.0

func (v Value) HashLen() int

HashLen returns the number of entries in a hash or object.

func (Value) HashSet added in v0.60.0

func (v Value) HashSet(key, val Value) error

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) HashSetOwned added in v0.60.0

func (v Value) HashSetOwned(key, val Value) error

HashSetOwned stores key/value without publishing val. It is for the one write that does not create a handle: replacing an entry with a copy of what that same entry already held, which the runtime's copy-on-write path does as it makes a nested collection exclusively held. Publishing there would make the next write through the same path copy again.

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) HashSetUnpublished added in v0.60.0

func (v Value) HashSetUnpublished(key, val Value) error

HashSetUnpublished is HashSet without the mutation-epoch bump. The epoch exists solely to invalidate memoized reachable-graph walks, and a write into a container reachable from no execution root cannot stale one, so the interpreter's literal builder uses this while assembling a hash that nothing references yet. The caller must guarantee the hash is unreachable from every root until a publishing write (an env bind, a container store, an ivar store) bumps the epoch — exactly the discipline array literals already follow, since building a Go-local slice never bumps at all. 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) HashUsesRecordedOrder added in v0.60.0

func (v Value) HashUsesRecordedOrder() bool

HashUsesRecordedOrder reports whether v iterates in a recorded insertion order. Objects and hashes whose live map no longer matches that record iterate in sorted key order instead. 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

func (v Value) Identical(other Value) bool

Identical reports whether v and other are the same value, backing the Ruby-style `equal?` predicate.

Immutable scalars (nil, bool, int, float, string, symbol, money, duration, time, range) are identical when they share kind and value. Integers outside the int64 range are the exception: they are heap objects and compare by payload identity, matching Ruby, where bignums are separate objects.

Arrays, hashes, and objects are values (ADR-006 item 2): Identical asks about contents, the same question as Equal, because collections carry no identity. Two independently constructed arrays with the same elements are identical, and every empty array is identical to every other empty array (the same for hashes and objects).

Runtime-only kinds (function, builtin, block, class, instance) and enum values that hold distinct storage are not identical even when they compare Equal — for example an enum value cloned out to the host and handed back.

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.

func (Value) Inspect added in v0.60.0

func (v Value) Inspect() string

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

func (v Value) InspectBounded(limit int) (string, error)

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 disables the byte budget. Regardless of limit, descent beyond 16,384 nested composites stops with partial output and ErrStringRenderDepthExceeded. 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

func (v Value) InspectByteLenBounded(step func() error) (int, error)

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

func (v Value) Int() int64

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

func (v Value) IsBigInt() bool

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) IsNil

func (v Value) IsNil() bool

IsNil reports whether v is a nil value.

func (Value) Kind

func (v Value) Kind() ValueKind

Kind returns the ValueKind of v.

func (Value) MarkSharedRef added in v0.60.0

func (v Value) MarkSharedRef()

MarkSharedRef forces v to the shared state, so that the next write through it copies. The host boundary uses it for values it takes in, where the interpreter cannot see how many handles exist on the other side; values it hands out are independent copies (or sole graphs transferred whole), so nothing outbound needs marking.

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) Money

func (v Value) Money() Money

Money returns the money content of v, or a zero Money if v is not money.

func (Value) ObjectStringForm added in v0.60.0

func (v Value) ObjectStringForm() (string, bool)

ObjectStringForm returns the rendering a tagged bag published at construction, and reports false for an ordinary bag. It is fixed then and never read back out of the entries, so mutating them cannot change it.

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 (Value) ObjectTag added in v0.60.0

func (v Value) ObjectTag() ObjectTag

ObjectTag reports the provenance of an attribute bag, or ObjectTagNone for anything else.

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). A bag that has been rebuilt (merged, duplicated, or produced by host code) reports ObjectTagNone, so the tag only ever vouches for a bag the runtime built itself.

func (Value) PublishRef added in v0.60.0

func (v Value) PublishRef()

PublishRef records that another durable slot now names the collection v, so that a later write through any of them copies rather than mutating a value something else can still see. It is a no-op for values that carry no wrapper.

Every site that places a collection somewhere outliving the current expression calls it: environment binds and assignments, instance and class variable stores, hash entry stores, and the array builders that take elements they did not construct. Missing one is an aliasing bug, so the runtime's always-copy verification mode exists to find one (see docs/collections.md).

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) Range

func (v Value) Range() Range

Range returns the range content of v, or a zero Range if v is not a range.

func (Value) RangeHashEntries added in v0.60.0

func (v Value) RangeHashEntries(visit func(key string, val Value))

RangeHashEntries calls visit for each entry of v in iteration order without materializing an intermediate slice. It is a no-op for non-hash values. Callers that only need a read-only pass (memory estimation) use it to avoid the per-call slice HashEntriesInto allocates for a hash larger than the caller's buffer. Because it holds no shared state it is safe to nest, which a buffer-reusing variant would not be. A visit that mutates v is undefined, so callers that can re-enter script code snapshot with HashEntriesInto instead. 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) Regex added in v0.60.0

func (v Value) Regex() Regex

Regex returns the regex payload of v. It panics when v is not a regex, like the other kind accessors.

func (Value) ReserveHashCapacity added in v0.60.0

func (v Value) ReserveHashCapacity(n int)

ReserveHashCapacity pre-sizes a hash's entry map and insertion-order backing to n entries. It is a no-op for non-hashes and negative capacities. 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) ReserveHashOrder added in v0.60.0

func (v Value) ReserveHashOrder(n int)

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 pre-size the entry map, so hash literals can reserve order capacity without allocating 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) ReserveHashOrderUnpublished added in v0.60.0

func (v Value) ReserveHashOrderUnpublished(n int)

ReserveHashOrderUnpublished is ReserveHashOrder without the mutation-epoch bump, for a hash still reachable from no execution root. See HashSetUnpublished for the invariant the caller owes.

func (Value) SetArrayElems added in v0.60.0

func (v Value) SetArrayElems(elems []Value)

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) SetArrayWindow added in v0.60.0

func (v Value) SetArrayWindow(elems []Value, head int)

SetArrayWindow narrows an array onto a window of the allocation its elements already sit in, recording how many slots of that allocation now sit in front of the window. head is counted from the start of the allocation, not from the elements the array showed before.

It exists because a narrowed array goes on holding the whole allocation while the slice header it keeps describes less and less of it, and nothing about that header says how much is in front. 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) SoleRef added in v0.60.0

func (v Value) SoleRef() bool

SoleRef reports whether the collection v may be written through in place -- that is, whether at most one durable slot names its wrapper. It reports true for every value that carries no wrapper, since those have nothing to alias.

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

func (v Value) String() 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

func (v Value) StringBounded(limit int) (string, error)

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 disables the byte budget. Regardless of limit, descent beyond 16,384 nested composites stops with partial output and ErrStringRenderDepthExceeded. 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

func (v Value) StringByteLen() int

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

func (v Value) StringByteLenBounded(step func() error) (int, error)

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

func (v Value) StringRuneLen() int

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

func (v Value) StringRuneLenBounded(step func() error) (int, error)

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) Time

func (v Value) Time() time.Time

Time returns the time content of v, or a zero time if v is not a time.

func (Value) Truthy

func (v Value) Truthy() bool

Truthy reports whether v is considered true in a boolean context.

func (Value) Unpublished added in v0.60.0

func (v Value) Unpublished() bool

Unpublished reports whether no durable slot names the collection v -- that it is still solely held by the operation that built it. A write through such a wrapper is safe from any route, because nothing else can reach it.

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

func (v Value) WriteInspectTo(buf *strings.Builder)

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

func (v Value) WriteStringTo(buf *strings.Builder)

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
	// KindShape tags a shape type used as a first-class value (the shape
	// argument of JSON.parse_as). The concrete payload type lives in the
	// runtime.
	KindShape
)

func (ValueKind) String

func (k ValueKind) String() string

String returns the human-readable name of the ValueKind.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL