Help us shape the future of Go! Take the 2026 Go Developer Survey

gen

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package gen produces random numscript programs for differential testing.

Generation targets this package's own AST rather than builder/ directly: cleanup.go rewrites the tree in place, and builder's Source/Destination are opaque render closures. convert.go renders once cleanup has settled.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenerateScript

func GenerateScript(rng *rand.Rand) (vars map[string]string, balances map[BalanceKey]*big.Int, metadata map[MetaKey]string, script string)

GenerateScript is Generate without the Shape.

func RandFromBytes

func RandFromBytes(b []byte) *rand.Rand

RandFromBytes derives an RNG from arbitrary bytes, so a Go fuzz target can drive generation reproducibly from its []byte corpus.

Types

type AccountVarDecl

type AccountVarDecl struct {
	Value string
}

AccountVarDecl is an account-typed `vars {}` declaration bound at run time from the vars map, unlike VarDecl which the compiler computes from an origin call.

Value is sometimes "world": the oracle rejects a var resolving to @world in source position, the interpreter accepts it. Compare tolerates that direction.

type AccountVarFill

type AccountVarFill struct {
	Var   *builder.Var[builder.ExprTypeAccount]
	Value string
}

AccountVarFill pairs a declared account-typed var with the literal value it must be bound to at run time — collected during toBuilderScript and consumed by GenerateScript (api.go), which merges it into the vars bindings map builder.BuildProgram returns. Unlike a VarFromBalance/ VarFromMeta var (whose value the compiler computes from an origin call), a plain account-typed var has no origin — its value can only come from the caller-supplied vars map, exactly as GenerateScript already does for the account/asset/etc. pools.

type BalanceKey

type BalanceKey struct {
	Account string
	Asset   string
}

BalanceKey identifies one (account, asset) starting balance.

type DestAllotmentClause

type DestAllotmentClause struct {
	Portion *big.Rat
	// Same constraint as SourceAllotmentClause.PortionAsVar.
	PortionAsVar bool
	// Same meaning as SourceAllotmentClause.Div.
	Div        *PortionDiv
	KeptOrDest KeptOrDest
}

type DestInorderClause

type DestInorderClause struct {
	Max        Monetary
	KeptOrDest KeptOrDest
}

type DestKind

type DestKind int
const (
	DestAccount DestKind = iota
	DestInorder
	DestAllotment
	// numscript-only (experimental-oneof), same clause fields as DestInorder.
	DestOneof
)

type Destination

type Destination struct {
	Kind DestKind

	// DestAccount only
	Account      string
	AccountAsVar bool

	// DestInorder, DestOneof
	InorderClauses []DestInorderClause
	Remaining      *KeptOrDest

	// DestAllotment only
	AllotClauses []DestAllotmentClause
	// DestAllotment only: non-nil adds a trailing `remaining` clause, and the
	// clause portions sum to strictly less than 1.
	AllotRemaining *KeptOrDest
}

type ExtraStatement

type ExtraStatement struct {
	Kind ExtraStatementKind

	// ExtraSave: the amount to save, either a literal (Monetary) or a
	// reference to Script.Vars[*VarIdx] (a declared VarFromBalance var) —
	// exactly one of the two is set. ExtraSendFromAccountVar,
	// ExtraSendToAccountVar: the send amount (always a literal).
	Monetary *Monetary

	// ExtraSave, ExtraSendVar (must index a VarFromBalance decl),
	// ExtraSetTxMetaVar (must index a VarFromMeta decl)
	VarIdx *int

	// ExtraSendFromAccountVar, ExtraSendToAccountVar: index into
	// Script.AccountVars for the account-typed var used as source/
	// destination (respectively); the other side is the literal Account.
	AccountVarIdx *int

	// ExtraSave (source account), ExtraSetAccountMeta, ExtraSendVar (source),
	// ExtraSendFromAccountVar (destination), ExtraSendToAccountVar (source)
	Account      string
	AccountAsVar bool

	// ExtraSaveAll
	Asset      string
	AssetAsVar bool

	// ExtraSetTxMeta, ExtraSetAccountMeta, ExtraSetTxMetaVar
	Key   string
	Value NumExpr
	// ExtraSetTxMeta, ExtraSetAccountMeta: when non-nil the meta value is this
	// string rather than the Value expression, exercising string-typed values.
	StringValue      *string
	StringValueAsVar bool

	// ExtraSendVar: `send $<Vars[VarIdx]> (source = Account, destination = Destination)`
	Destination      string
	DestinationAsVar bool
}

ExtraStatement is one non-send statement. Only the fields relevant to Kind are populated.

type ExtraStatementKind

type ExtraStatementKind int

ExtraStatementKind enumerates the non-send statement kinds this generator can produce, on top of Program's send-only statements.

const (
	ExtraSave ExtraStatementKind = iota
	ExtraSaveAll
	ExtraSetTxMeta
	ExtraSetAccountMeta
	ExtraSendVar
	ExtraSetTxMetaVar
	ExtraSendFromAccountVar
	ExtraSendToAccountVar
)

type Focus

type Focus struct {
	Account string
	Asset   string
}

Focus is the (account, asset) every statement of a scenario block shares.

type Generated

type Generated struct {
	Vars     map[string]string
	Balances map[BalanceKey]*big.Int
	Metadata map[MetaKey]string
	Script   string
	Shape    Shape

	// Flags are the feature flags the script needs on the numscript engines
	// (interpreter and compiler+VM). Derived from Shape.
	Flags []string
	// OracleCompatible is false when the script uses shapes outside the legacy
	// machine's grammar or decided behavior (oneof, colors, division portions,
	// wrong-asset caps): the harness then runs only the two numscript engines
	// and compares them against each other.
	OracleCompatible bool
}

Generated is one runnable numscript program with the vars bindings it needs at run time, the starting balances and metadata it assumes, and the structural Shape of the program.

func Generate

func Generate(rng *rand.Rand) Generated

Generate formats a random Script as a runnable numscript program. The caller loads Balances and Metadata into each engine store before executing.

type KeptOrDest

type KeptOrDest struct {
	Kind KeptOrDestKind
	Dest *Destination // valid only when Kind == To
}

type KeptOrDestKind

type KeptOrDestKind int
const (
	Kept KeptOrDestKind = iota
	To
)

type MetaKey

type MetaKey struct {
	Account string
	Key     string
}

MetaKey identifies one (account, key) starting metadata entry.

type MetaType

type MetaType int

MetaType is the type a `meta()` origin var is declared as. meta() returns TypeAny, so the declaration decides how the stored string is parsed and the var only compiles if the type matches the preset value.

const (
	MetaNumber MetaType = iota
	MetaString
	MetaMonetary
	MetaAsset
	MetaAccount
	MetaPortion
)

type Monetary

type Monetary struct {
	Asset      string
	AssetAsVar bool
	// Ignored for negative amounts: they have no literal form to bind.
	AsVar  bool
	Amount *big.Int
}

An "AsVar" field marks one value occurrence as written through a `vars {}` variable instead of inline. Per occurrence, not per value: the same account can be inline in one place and a var in another, which is what makes two resources alias one account (formancehq/ledger#2056).

Only the rendering changes, never the value, so cleanup.go is unaffected.

type NumExpr

type NumExpr struct {
	Kind NumExprKind

	// NumLit only
	Lit *big.Int
	// NumLit only.
	LitAsVar bool

	// NumAdd, NumSub only
	Left, Right *NumExpr
}

type NumExprKind

type NumExprKind int

NumExprKind is the arithmetic allowed in set_tx_meta/set_account_meta values. Only +/- over literals and vars: that is all NumScript.g4 has.

const (
	NumLit NumExprKind = iota
	NumAdd
	NumSub
)

type PortionDiv added in v0.1.1

type PortionDiv struct {
	Num *big.Int
	Den *big.Int
}

PortionDiv is a portion written as a division expression `$num/den` (the numerator always renders through a runtime-bound number var, so any sign is expressible without unary minus). Unlike literals and portion vars, the value is unconstrained: negative and over-one portions are reachable this way, and both engines must reject them the same way. numscript-only: the oracle's grammar has no division expression.

func (PortionDiv) Rat added in v0.1.1

func (d PortionDiv) Rat() *big.Rat

type Program

type Program []Statement

func GenerateProgram

func GenerateProgram(rng *rand.Rand) Program

GenerateProgram generates a random program (with its own randomized account-pool size) and applies the cleanup pass (cleanup.go) that removes constructs the legacy machine would reject.

type ScenarioStmt

type ScenarioStmt struct {
	Kind  string
	Send  *Statement
	Extra *ExtraStatement
}

ScenarioStmt is one statement of a scenario block. Exactly one of Send and Extra is set. Kind is the setup/observer kind that built it, for coverage counting.

type Script

type Script struct {
	Vars        []VarDecl
	AccountVars []AccountVarDecl
	Seeds       Program
	Program     Program
	Extra       []ExtraStatement
	Order       []bool
	Strategy    Strategy
	Focus       *Focus
	Scenario    []ScenarioStmt
	ScenarioPos int
	Balances    map[BalanceKey]*big.Int
	Metadata    map[MetaKey]string
}

Script is the full output of one round of generation: a `vars {}` block, optional seed-funding statements, the core send-only program, extra non-send statements, an optional scenario block, and/or pre-set starting balances/metadata (populated instead of, or alongside, Seeds — see genBalances). Order records a riffle-interleaving of Program and Extra (true = take next from Program, false = take next from Extra), so extra statements land throughout the script instead of only after every send. Scenario is emitted contiguously, just before the Order step at index ScenarioPos, or after the last step when ScenarioPos == len(Order). bodyStatements is the one walk of that layout.

type Shape

type Shape struct {
	Strategy Strategy

	HasSave             bool
	HasBoundedOverdraft bool
	// A save and a bounded-overdraft source on the same account, any assets.
	SaveOverdraftSameAccount bool
	// Same, on the same (account, asset).
	SaveOverdraftSameResource bool
	// Same, with the save executing before the overdraft draw.
	SaveOverdraftSameResourceInOrder bool
	// An in-order pair whose literal save amount exceeds the pair's starting
	// balance (preset plus seed funding), with no earlier statement touching
	// the pair. A var-valued or `*` save never counts.
	SaveOverdrawsInitial bool

	// An allotment (source or destination side) with a `remaining` clause.
	HasAllotmentRemaining bool
	// An allotment clause whose portion is a var rather than an n/d literal.
	HasPortionVar bool
	// A statement references a vars-block origin that reads through another
	// origin var (VarDecl.AccountFromVarIdx). Counted on references, not
	// declarations: an unreferenced origin var is never rendered into the
	// script.
	HasChainedOrigin bool

	// numscript-only shapes (see sourceOptions.numscriptOnly). Any of these
	// makes the script skip the oracle legs: the legacy machine's grammar has
	// no oneof, colors or division expressions, and its clause-evaluation
	// order on wrong-asset caps is not the behavior under test.
	HasOneof         bool
	HasColoredSource bool
	HasWrongAssetCap bool
	HasPortionDiv    bool

	// Scenario kinds in block order, empty without a scenario block.
	SetupKinds    []string
	ObserverKinds []string
}

Shape records structural facts about one Script, so a sweep can count how often the multi-statement shapes it cares about are actually generated. Everything here is read off the AST and the starting balances; no engine semantics are involved.

type Source

type Source struct {
	Kind SourceKind

	// SrcAccount, SrcAccountOverdraft
	Account      string
	AccountAsVar bool

	// SrcAccount, SrcAccountOverdraft: non-empty adds a `\ "COLOR"` clause.
	// numscript-only (experimental-asset-colors): scripts containing it skip
	// the oracle legs.
	Color      string
	ColorAsVar bool

	// SrcAccountOverdraft only: nil means unbounded overdraft
	Overdraft *Monetary

	// SrcCapped only
	Cap   *Monetary
	Inner *Source

	// SrcInorder, SrcOneof
	Sources []Source

	// SrcAllotment only
	Clauses []SourceAllotmentClause
	// SrcAllotment only: non-nil adds a trailing `remaining from` clause, and
	// the clause portions sum to strictly less than 1.
	AllotmentRemaining *Source
}

type SourceAllotmentClause

type SourceAllotmentClause struct {
	Portion *big.Rat
	// Rendered as a runtime-bound portion var instead of an n/d literal. Only
	// legal in an allotment with a remaining clause: without one, the oracle
	// rejects the block at compile time ("might be less than 100%").
	PortionAsVar bool
	// When non-nil, the clause portion is Div rendered as a division expression
	// and Portion/PortionAsVar are ignored.
	Div    *PortionDiv
	Source Source
}

type SourceKind

type SourceKind int
const (
	SrcAccount SourceKind = iota
	SrcAccountOverdraft
	SrcCapped
	SrcInorder
	SrcAllotment
	// numscript-only (experimental-oneof): scripts containing it skip the
	// oracle legs.
	SrcOneof
)

type Statement

type Statement struct {
	// If IsSendAll, Asset is used (unbounded send). Otherwise Amount is used.
	IsSendAll bool
	Amount    Monetary
	Asset     string
	// IsSendAll only.
	AssetAsVar  bool
	Source      Source
	Destination Destination
}

type Strategy

type Strategy int

Strategy is how one Script's body was assembled.

const (
	// Program and Extra only, riffled.
	StrategyUniform Strategy = iota
	// Program and Extra riffled, with a scenario block spliced in.
	StrategyScenarioMixed
	// Seeds and a scenario block only.
	StrategyScenarioOnly
)

type VarDecl

type VarDecl struct {
	Kind    VarDeclKind
	Account string
	// Makes `balance($accountN, ...)` and a literal `@acc` elsewhere alias
	// one account.
	AccountAsVar bool
	// Chains this origin onto an earlier declaration: the account read by
	// balance()/meta() is the origin var at this index, which must be an
	// earlier VarFromMeta declaration of MetaType MetaAccount. Account then
	// holds the account name that parent's meta value resolves to (known at
	// generation time), so the balance/metadata this declaration observes can
	// still be steered; AccountAsVar is ignored.
	AccountFromVarIdx *int

	// VarFromBalance only
	Asset      string
	AssetAsVar bool

	// VarFromMeta only
	Key string
	// VarFromMeta only. Must match how the preset value at (Account, Key) is
	// written.
	MetaType MetaType
}

VarDecl is a `vars {}` declaration whose value comes from the compiler, not from a runtime binding.

type VarDeclKind

type VarDeclKind int

VarDeclKind is the origin of a `vars {}` declaration this generator can produce: either `monetary $name = balance(<account>, <asset>)` or `number $name = meta(<account>, "<key>")`.

const (
	VarFromBalance VarDeclKind = iota
	VarFromMeta
)

Jump to

Keyboard shortcuts

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