runtime

package
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package runtime provides the SysML v2 execution runtime: expression evaluation, instance materialization, and KerML operator library.

Usage Example

// Create runtime context
model := semantics.NewModel(resolver)
ctx := runtime.NewContext(model, resolver, runtime.DefaultMaxSteps)

// Instantiate a part
partSym := resolveSymbol(root, "MyCar")
inst, err := ctx.Instantiate(partSym)
if err != nil {
	log.Fatal(err)
}

// Evaluate an expression
exprNode := parseExpression("1 + 2")
result, err := ctx.Eval(exprNode)
if err != nil {
	log.Fatal(err)
}
fmt.Println(result.Const.Int) // 3

Architecture

The runtime is organized in three tiers:

  • Tier 1: Feature flattening (effective-feature lists per type)
  • Tier 2: Instance model (lazy feature value materialization, multiplicity-driven collections)
  • Tier 3: Expression evaluator (literals, operators, feature access, calc invocation, KerML builtins)

Key types:

  • Context: Runtime execution context (ID allocator, instance registry, memoization)
  • Value: Runtime-evaluable value (int/real/bool/string/null/instance/Sequence/Set)
  • EffectiveFeature: One entry in a type's effective feature list (Tier 1 schema)
  • Instance: Runtime-materialized object with typed feature values
  • EvalContext: Lexical environment for evaluation (frame stack)

Integration

  • Consumes semantics.Model (inherits features, multiplicity, constant folding)
  • Gates on pass-validated models (LevelConstraint success)
  • One Context per workspace session (LSP/REPL lifetime)

Behavioral simulation (actions, state machines) is out of scope (future Tiers 4–5).

Index

Constants

View Source
const (
	// DefaultMaxSteps bounds expression evaluations.
	DefaultMaxSteps int64 = 10000000
	// DefaultMaxActionSteps bounds the token-flow steps one action run performs.
	DefaultMaxActionSteps int64 = 1000000
	// DefaultMaxStateEvents bounds the events one state machine run dispatches.
	DefaultMaxStateEvents int64 = 1000000
	// DefaultMaxDoSteps bounds the do actions one state machine run
	// performs.
	DefaultMaxDoSteps int64 = 5000000
	// DefaultMaxElements bounds the collection elements one evaluation holds,
	// ~104MB of Values.
	DefaultMaxElements int64 = 1000000
	// DefaultMaxCalcDepth bounds the nested calc invocations one evaluation holds
	// on the stack, ~10KB each.
	DefaultMaxCalcDepth int64 = 10000
)

Default bounds on one run. Each one stops a different kind of runaway, so each counts a different thing and has its own variable.

The step and event bounds are sized by how long a runaway takes to report rather than by memory: those steps allocate nothing that outlives them, and the only thing they make grow is a %trace, at 34-83 bytes an entry. Measured rates are ~13.6M evaluation steps/s and ~1.9M events/s, so each default reports a runaway within about a second, and a fully traced run at those four ceilings holds ~320MB.

Collection elements are the exception, and MaxElements is the bound that reads as memory: a materialized element is a 104-byte Value living as long as the collection holding it, and `1..10000000` conjures one per step. It counts the elements one evaluation holds, not the elements a run produced in total, so a loop or a state machine building a small collection each step is not stopped by the steps before it.

View Source
const (
	MaxStepsEnvVar       = "SYSML_MAX_STEPS"
	MaxActionStepsEnvVar = "SYSML_MAX_ACTION_STEPS"
	MaxStateEventsEnvVar = "SYSML_MAX_EVENTS"
	MaxDoStepsEnvVar     = "SYSML_MAX_DO_STEPS"
	MaxElementsEnvVar    = "SYSML_MAX_ELEMENTS"
	MaxCalcDepthEnvVar   = "SYSML_MAX_CALC_DEPTH"
)

Environment variables overriding the defaults above, following the SYSML_LIBRARY_PATH convention.

View Source
const MaxCalcDepthCeiling int64 = 25000

MaxCalcDepthCeiling is the highest calc depth budget a run may be given: past it the goroutine stack, whose exhaustion is fatal, would stop a runaway first.

View Source
const UnsetText = "<unset>"

UnsetText is how every surface spells a feature value that holds no value: a valueless feature of a value type, whose instances are values rather than objects.

Variables

View Source
var (
	// ErrStepLimitExceeded is returned when the evaluation step counter exceeds maxSteps.
	ErrStepLimitExceeded = errors.New("evaluation step limit exceeded")

	// ErrElementLimitExceeded is returned when the collection elements one run
	// materializes exceed maxElements. It is a bound on memory rather than on
	// work, so it is its own error and its own budget.
	ErrElementLimitExceeded = errors.New("collection element limit exceeded")

	// ErrUnresolvedReference is returned when a feature reference cannot be resolved.
	ErrUnresolvedReference = errors.New("unresolved reference")

	// ErrTypeMismatch is returned when an operation receives a value of unexpected type.
	ErrTypeMismatch = errors.New("type mismatch")

	// ErrDivisionByZero is returned when a division or remainder has a zero
	// divisor. It is the answer to the expression, not a missing declaration.
	ErrDivisionByZero = errors.New("division by zero")

	// ErrMultiplicityViolation is returned when a feature value access/assignment violates multiplicity bounds.
	ErrMultiplicityViolation = errors.New("multiplicity violation")

	// ErrUninitializedFeatureValue is returned when accessing a feature value that has no value and no default.
	ErrUninitializedFeatureValue = errors.New("uninitialized feature value")

	// ErrBindingConflict is returned when two binding ends hold unequal values.
	ErrBindingConflict = errors.New("binding conflict")

	// ErrBindingCycle is returned when a binding component has no value.
	ErrBindingCycle = errors.New("binding cycle")

	// ErrBindingEnd is returned when a binding endpoint cannot be resolved to a feature.
	ErrBindingEnd = errors.New("binding end cannot be resolved")

	// ErrNotACalc is returned when a calc invocation targets a symbol that is
	// not a calc definition or usage.
	ErrNotACalc = errors.New("not a calc")

	// ErrNotAConstraint is returned when a symbol asked to be evaluated as a
	// constraint declares something else. It is a usage error about the request,
	// not a verdict about the model, so callers can tell the two apart.
	ErrNotAConstraint = errors.New("not a constraint")

	// ErrNotARequirement is returned when a symbol asked to be evaluated as a
	// requirement declares something else. Like ErrNotAConstraint it reports the
	// request, not the model.
	ErrNotARequirement = errors.New("not a requirement")

	// ErrNotAnAnalysis is returned when a symbol asked for its objectives is not
	// an analysis case. Like ErrNotAConstraint it reports the request, not the
	// model.
	ErrNotAnAnalysis = errors.New("not an analysis case")

	// ErrCalcArity is returned when a calc invocation passes more arguments than
	// the calc declares input parameters.
	ErrCalcArity = errors.New("calc argument count mismatch")

	// ErrUnboundParameter is returned when a calc input parameter receives
	// neither an argument nor a declared default.
	ErrUnboundParameter = errors.New("unbound parameter")

	// ErrUnknownParameter is returned when a named argument does not name any
	// input parameter of the invoked calc.
	ErrUnknownParameter = errors.New("unknown parameter")

	// ErrNoResultExpression is returned when a calc body declares no return
	// expression, directly or by inheritance.
	ErrNoResultExpression = errors.New("no result expression")

	// ErrUnsupportedOperator is returned when an operator has no runtime
	// evaluation, so an expression naming it fails rather than yielding nothing.
	ErrUnsupportedOperator = errors.New("unsupported operator")

	// ErrUnresolvedType is returned when a type classification operand names no
	// resolvable type.
	ErrUnresolvedType = errors.New("unresolved type")

	// ErrUndeterminedValueType is returned when a value classification has no
	// direct runtime type to compare.
	ErrUndeterminedValueType = errors.New("value type cannot be determined")

	// ErrCalcNoReturn is returned when a calc body runs to its end without
	// returning: it computed no result, which is not the same as a null one.
	ErrCalcNoReturn = errors.New("calculation returned no value")

	// ErrCalcSideEffect is returned when a calc body states an effect on the
	// world outside it — send, perform, accept, terminate. A calculation
	// computes a value, so an effect is rejected rather than performed.
	ErrCalcSideEffect = errors.New("side effect in a calculation body")

	// ErrCalcExternalAssignment is returned when a calc body assigns to a name it
	// does not declare itself, which would make the calculation impure.
	ErrCalcExternalAssignment = errors.New("assignment outside the calculation body")

	// ErrReturnOutsideCalc is returned when a `return` is executed by a host that
	// has no result to return, an action node's body.
	ErrReturnOutsideCalc = errors.New("'return' outside a calculation body")

	// ErrAcceptDeadlock is returned when an action can no longer progress
	// because every token it has left is parked at an accept, so no token can
	// post the message any of them waits for. An accept suspends the action
	// rather than failing, so this is how a suspension that can never end is
	// reported instead of hanging.
	ErrAcceptDeadlock = errors.New("accept deadlock")

	// ErrActionDeadlock is returned when action tokens cannot make progress.
	ErrActionDeadlock = errors.New("action deadlock")

	// ErrInvalidActionFlow is returned for a structurally invalid action graph.
	ErrInvalidActionFlow = errors.New("invalid action flow")

	// ErrNoEnabledSuccession is returned when a decision can select no branch.
	ErrNoEnabledSuccession = errors.New("no enabled succession")

	// ErrNoClock is returned when a behavior waits for a time event where no
	// clock advances: an action body has no time base of its own, so
	// `accept at t` / `accept after d` written among an action's nodes is
	// reported rather than passed through as if the instant had arrived.
	ErrNoClock = errors.New("no clock to wait on")

	// ErrCalcRecursionLimit is returned when calc invocation nests deeper than
	// the run's calc depth budget, which an unbounded recursion would otherwise
	// do until the process ran out of stack.
	ErrCalcRecursionLimit = errors.New("calc recursion limit exceeded")

	// ErrActionStepLimitExceeded is returned when an action executor exceeds
	// its token-flow step budget.
	ErrActionStepLimitExceeded = errors.New("action step limit exceeded")

	// ErrStateEventLimitExceeded is returned when state processing exceeds its
	// event budget.
	ErrStateEventLimitExceeded = errors.New("state event limit exceeded")

	// ErrStatePerformanceOccurrence is returned when an exhibited machine cannot
	// read or write the occurrence of its state usage.
	ErrStatePerformanceOccurrence = errors.New("state performance occurrence unavailable")

	// ErrActionPerformanceOccurrence is returned when a performed action cannot
	// read or write the occurrence of its action usage.
	ErrActionPerformanceOccurrence = errors.New("action performance occurrence unavailable")

	// ErrDoStepLimitExceeded is returned when a state do behavior exceeds its
	// action-step budget.
	ErrDoStepLimitExceeded = errors.New("state do-step limit exceeded")

	// ErrViolated is returned when an asserted constraint or a required
	// condition evaluates to false. It is a verdict about the model, not a
	// failure to evaluate, so callers can tell the two apart.
	ErrViolated = errors.New("evaluated to false")

	// ErrNoValue is returned when a feature a condition names carries no value:
	// neither a feature value on the object being checked nor a declared default.
	ErrNoValue = errors.New("no value")

	// ErrNoConditions is returned when a constraint or requirement carries no
	// condition to evaluate: reporting a verdict would claim a check that never ran.
	ErrNoConditions = errors.New("no condition to evaluate")

	// ErrCyclicFeatureValue is returned when a feature value's default value depends, directly or
	// through other feature values, on the one being computed.
	ErrCyclicFeatureValue = errors.New("cyclic feature value dependency")

	// ErrConnectorEnd is returned when a connector cannot be attached to the
	// features its ends name: an end naming nothing reachable from the object
	// owning the connector, or one carrying no value. A connector whose ends
	// cannot be attached relates nothing, so it is an error rather than an object
	// with defaults at its ends.
	ErrConnectorEnd = errors.New("connector end cannot be attached")

	// ErrNotAQuantity is returned when `x [y]` is not a quantity expression:
	// y names no measurement unit, or x is no magnitude.
	ErrNotAQuantity = errors.New("not a quantity expression")

	// ErrIncommensurableUnits is returned when an operation combines quantities
	// whose units measure different things, or whose conversion is not derivable
	// from the library. It is never answered by comparing magnitudes.
	ErrIncommensurableUnits = errors.New("incommensurable units")

	// ErrNotASatisfaction is returned when a satisfaction assertion is asked of
	// an element that states none.
	ErrNotASatisfaction = errors.New("not a satisfaction assertion")

	// ErrNoRequirement is returned when a satisfaction assertion states no
	// requirement to evaluate: it references none, or references one that
	// resolves to nothing.
	ErrNoRequirement = errors.New("no requirement to satisfy")

	// ErrUnresolvedClassifierBehavior is returned when a type exhibits or
	// performs a behavior whose body no element states, so the objects of that
	// type have nothing to run.
	ErrUnresolvedClassifierBehavior = errors.New("classifier behavior names no body")

	// ErrUnsupportedClassifierBehavior is returned when a type binds a behavior
	// the runtime does not execute on an object.
	ErrUnsupportedClassifierBehavior = errors.New("unsupported classifier behavior")

	// ErrNoSuchBehavior is returned when a behavior asked of an object is none
	// the object's type owns, exhibits or performs.
	ErrNoSuchBehavior = errors.New("object has no such behavior")

	// ErrNotABehavior is returned when a name invoked on an object resolves to an
	// element that states no behavior to run.
	ErrNotABehavior = errors.New("not a behavior")

	// ErrBehaviorBudget is returned when the behaviors of materialized objects
	// never reach quiescence within the event budget.
	ErrBehaviorBudget = errors.New("object behaviors exceeded their budget")

	// ErrNotACalcUsage is returned when an output feature is read from a symbol
	// that is not a calc usage: only a usage carries an evaluation whose outputs
	// are features.
	ErrNotACalcUsage = errors.New("not a calc usage")

	// ErrUnknownOutput is returned when a name read from a calc usage is not one
	// of the output features its calc declares.
	ErrUnknownOutput = errors.New("unknown output")

	// ErrOutputNotAssigned is returned when a declared output carries no value
	// because the activation never assigned it. It is a kind of ErrNoValue.
	ErrOutputNotAssigned = fmt.Errorf("%w: output never assigned", ErrNoValue)

	// ErrConflictingOutput is returned when one activation would bind an output
	// twice: by its declaration and by an assignment, or by two assignments.
	ErrConflictingOutput = errors.New("output bound more than once")

	// ErrCyclicOutput is returned when an output feature's binding depends,
	// directly or through other outputs, on the output being computed.
	ErrCyclicOutput = errors.New("cyclic output dependency")

	// ErrAmbiguousResult is returned when a calc declaring several output
	// features is invoked as an expression. A function invocation has exactly
	// one result (KerML 7.4.9), so a calc that designates none has no value to
	// hand back and is read through a calc usage's output features instead.
	ErrAmbiguousResult = errors.New("calculation has no single result")

	// ErrIndexOutOfRange is returned when an index names no position of the
	// sequence or string it indexes; indices are 1-based, so 0 is out of range
	// as much as size+1 is, and each operation names what it indexed.
	ErrIndexOutOfRange = errors.New("index out of range")

	// ErrBodyArity is returned when the body expression a collection operation
	// is given declares a number of parameters the operation cannot call it
	// with: `select` calls its selector with one element, so a selector
	// declaring two parameters has no second argument to receive.
	ErrBodyArity = errors.New("body parameter count mismatch")

	// ErrUnsupportedBodyDeclaration is returned when a body expression declares
	// features of its own: the evaluator binds its parameters, not its
	// declarations, so applying it would read them as unresolved.
	ErrUnsupportedBodyDeclaration = errors.New("unsupported declaration in a body expression")

	// ErrReceiverWithNamedArgs is returned when a receiver is written before a
	// call whose arguments are named, `x->f(a = 1)`. The receiver binds by
	// position and the arguments by name, so which parameter the receiver binds
	// to is unstated; it is reported rather than dropped.
	ErrReceiverWithNamedArgs = errors.New("receiver combined with named arguments")

	// ErrVariationUnselected is returned when a variation is read without having
	// been bound to one of its variants: it classifies its variants abstractly,
	// so it stands for no one value until a variant is selected.
	ErrVariationUnselected = errors.New("variation has no variant selected")

	// ErrNotAVariant is returned when a variation is bound to something that is
	// not one of the variants it offers.
	ErrNotAVariant = errors.New("not a variant of the variation")

	// ErrMultipleVariants is returned when a variation is bound to more than one
	// variant, which selects no single configuration.
	ErrMultipleVariants = errors.New("more than one variant selected")

	// ErrNotALiteral is returned when a name qualified by an enumeration
	// definition names something the enumeration does not declare as a literal.
	ErrNotALiteral = errors.New("not a literal of the enumeration")

	// ErrConflictingRedefinition is returned when one declaration values the
	// same feature under two of its names: a redefinition renames one feature,
	// so which of the two values it holds would be a silent pick.
	ErrConflictingRedefinition = errors.New("one feature valued under two names")

	// ErrValuedFeatureRestated is returned when a feature is both bound to a
	// value and given a body restating features of it: the bound value supplies
	// those features, so the restatement could only be silently dropped.
	ErrValuedFeatureRestated = errors.New("feature both valued and restated in a body")

	// ErrFeatureValueMaterialization marks an error as a feature value that could not be
	// materialized, whatever kept it from materializing. Reading a feature value is what
	// finds such a failure, so a surface reporting one answered nothing about
	// that feature value rather than deciding anything about the model.
	ErrFeatureValueMaterialization = errors.New("feature value could not be materialized")

	// ErrNoSuchFeature is returned when a chained assignment reaches an object
	// whose type declares no feature of the name the target's last segment
	// writes: the object has nowhere to hold the value.
	ErrNoSuchFeature = errors.New("object has no such feature")

	// ErrNoSubject is returned when the feature a satisfaction assertion names
	// with `by` cannot supply a subject: it resolves to nothing, or no object of
	// it can be created.
	ErrNoSubject = errors.New("no subject to satisfy the requirement")

	// ErrPerformerFeatureNotInScope is returned when a behavior body names a
	// feature only the object performing it declares: the performing object is
	// not a namespace the body's names resolve in, so the name has no referent.
	ErrPerformerFeatureNotInScope = errors.New("name is not in scope of the behavior body")

	// ErrThisNotAnObject is returned when `this` is read where no object owns
	// what is being evaluated: the context occurrence is the performance itself,
	// whose features a name written in its body does not reach.
	ErrThisNotAnObject = errors.New("this names no object here")
)
View Source
var ErrAmbiguousSubject = errors.New("ambiguous subject")

ErrAmbiguousSubject is returned when more than one object carries the checked element, so which one the verdict would be about is a question, not an answer.

View Source
var ErrAmbiguousSuccession = errors.New("more than one succession is enabled")

ErrAmbiguousSuccession reports a node whose flow could continue along more than one succession, which the token semantics do not resolve.

View Source
var ErrSendPortTypeMismatch = errors.New("send message type is not carried by the receiving port")

ErrSendPortTypeMismatch reports a typed receiving port rejecting a message.

View Source
var ErrSendViaUnknownPort = errors.New("send via names no port of the sender")

ErrSendViaUnknownPort reports a routed send naming no sender port.

View Source
var ErrUnevaluableLibraryFunction = errors.New("library function is not evaluable")

ErrUnevaluableLibraryFunction is returned for a function library declaration this runtime has no representation for the values of. It names the function, so a model is told which declaration it is rather than answered wrongly.

View Source
var ErrUnimportedExtensionFunction = errors.New("function is not in scope")

ErrUnimportedExtensionFunction is returned for an unqualified call to a OpenSysML extension function the model imports no declaration of.

View Source
var ErrUnreachableSendReceiver = errors.New("send receiver is unreachable")

ErrUnreachableSendReceiver reports a routed receiver that cannot be resolved.

View Source
var ErrUnroutableSend = errors.New("send reaches no receiving port")

ErrUnroutableSend is returned when a `send … via p` reaches no end able to receive it: p is joined to nothing, or only to ends whose flow features carry outward. It lives here rather than in errors.go because routing is the only thing that raises it.

Functions

func ActionNodeName

func ActionNodeName(node ast.Node) string

ActionNodeName returns the declared name of an action graph node, or "" when the node is anonymous or not a named node kind.

func ActionNodeNames

func ActionNodeNames(node ast.Node) []string

ActionNodeNames returns every name a node answers to: its name and, for a usage, its declared short name, which is a name of its own.

func FormatConst

func FormatConst(c semantics.Value) string

FormatConst renders a scalar constant using the runtime's user-facing numeric convention.

func FormatReal added in v0.3.1

func FormatReal(f float64) string

FormatReal renders a Real as the shortest decimal that reads back as the same float64, so no surface rounds a value away. A whole value keeps a ".0" so it is not mistaken for an Integer.

func FormatTraceValue

func FormatTraceValue(v Value) string

FormatTraceValue renders a runtime value canonically for a trace. Set elements are sorted by their rendering, since a set has no order of its own and its backing map does not iterate in a stable one.

func FormatValue

func FormatValue(v Value) string

FormatValue renders a value with the notation used by user-facing runtime results and diagnostics.

func NegatedDecl

func NegatedDecl(sym *symbols.Symbol) bool

NegatedDecl reports whether sym's declaration asserts that its conditions do not hold (`assert not constraint { … }`, `assert not satisfy … by …`).

func RequireAnalysis

func RequireAnalysis(sym *symbols.Symbol) error

RequireAnalysis returns an ErrNotAnAnalysis usage error unless sym declares an analysis case, so a caller can settle the kind before asking for objectives.

func RequireConstraint

func RequireConstraint(sym *symbols.Symbol) error

RequireConstraint returns an ErrNotAConstraint usage error unless sym declares a constraint, so a caller can settle the kind before evaluating.

func RequireRequirement

func RequireRequirement(sym *symbols.Symbol) error

RequireRequirement returns an ErrNotARequirement usage error unless sym declares a requirement.

func TraceLabel

func TraceLabel(node ast.Node) string

TraceLabel names an expression node for a trace: its kind plus the token that identifies it, which is stable across reformatting of the source.

Types

type AcceptWait

type AcceptWait struct {
	ParamName  string // the accept parameter the message will bind to
	SignalType string // the type awaited, empty when the accept named none
	ViaPort    string // the port awaited on, empty when the accept named none
	Since      int    // the step during which the token parked, numbered as the trace numbers steps
	// Trigger describes the time or change event awaited instead of a message
	// (`accept when x > 1`), empty when the accept waits for a message.
	Trigger string
}

AcceptWait describes the message a parked token is waiting for. It is the accept's lowered shape plus the step the token parked at, which is what lets a blocked run report which accept is waiting for what rather than only that it is stuck.

func (AcceptWait) String

func (w AcceptWait) String() string

String describes what a parked token is waiting for, and since when, for error messages and for the REPL's view of a suspended executor.

type ActionExecutor

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

ActionExecutor executes action bodies using token-flow semantics.

func (*ActionExecutor) ActionSymbol

func (e *ActionExecutor) ActionSymbol() *symbols.Symbol

ActionSymbol returns the action being executed.

func (*ActionExecutor) ClearBreakpoints

func (e *ActionExecutor) ClearBreakpoints()

ClearBreakpoints removes all breakpoints.

func (*ActionExecutor) Data

func (e *ActionExecutor) Data() map[string]Value

Data returns the action's live feature space, which its nodes read and write.

func (*ActionExecutor) HasPendingSignal

func (e *ActionExecutor) HasPendingSignal() bool

HasPendingSignal reports whether a message in flight would let a parked token proceed, without consuming it.

func (*ActionExecutor) NodeNames

func (e *ActionExecutor) NodeNames() []string

NodeNames returns the names of the action's graph nodes, in declaration order. Anonymous nodes are omitted; a debugger uses it to check that a breakpoint names a node that exists.

func (*ActionExecutor) PausedAt

func (e *ActionExecutor) PausedAt() string

PausedAt returns the breakpoint node the last run stopped at, or "" when the run was not stopped by a breakpoint.

func (*ActionExecutor) Results

func (e *ActionExecutor) Results() map[string]Value

Results returns the values the action's features currently hold: one space every token shares, so every branch's effects are reported. For a performed usage these mirror the performance occurrence, which every write goes through.

func (*ActionExecutor) RunToCompletion

func (e *ActionExecutor) RunToCompletion() error

RunToCompletion executes until StateCompleted, a breakpoint, or error. Includes infinite loop protection.

A run stops as soon as a token sits on a node a breakpoint was set on (see SetBreakpoint), leaving the tokens where they are so the run can be resumed by calling RunToCompletion again or stepped with Step; PausedAt names the node it stopped at. With no breakpoints set the run is unconditional.

Nothing outside the action can post a message while this runs, so an action whose every remaining token is parked at an accept can never be resumed: the suspension is a deadlock and is reported as ErrAcceptDeadlock at the first step that makes no progress. A parked action therefore cannot spend the step budget spinning — the budget is only consumed by steps that move something.

func (*ActionExecutor) RunToQuiescence

func (e *ActionExecutor) RunToQuiescence() error

RunToQuiescence runs the action until it completes, stops at a breakpoint, or parks every remaining token at an accept. Unlike RunToCompletion, a parked action is quiescence rather than a deadlock: this is what an object performing an action is run with, where a sibling object may still send the awaited message.

func (*ActionExecutor) SetBreakpoint

func (e *ActionExecutor) SetBreakpoint(nodeName string)

SetBreakpoint adds a breakpoint at the given node name.

func (*ActionExecutor) SetInputs

func (e *ActionExecutor) SetInputs(inputs map[string]Value)

SetInputs binds input parameter values into the action's feature space. Inputs are applied after attribute defaults, so they override defaults with the same name. Must be called before initialize().

func (*ActionExecutor) SetTrace

func (e *ActionExecutor) SetTrace(trace *TraceRecorder)

SetTrace sets the trace recorder for this executor and the context it evaluates in.

func (*ActionExecutor) State

func (e *ActionExecutor) State() ExecutionState

State returns current execution state.

func (*ActionExecutor) Step

func (e *ActionExecutor) Step() error

Step advances execution by one step for all active tokens. Safely handles token slice modifications (fork/join) by collecting indices first.

A token that reaches an accept with no message it can consume parks there rather than failing: the action is suspended until a matching message arrives. When a step moves nothing and at least one token is parked, the executor enters StateWaiting instead of reporting a deadlock — a caller driving Step itself (the REPL, or a state machine running in the same context) may still post the awaited message and step again, which resumes the parked token. RunToCompletion has no such caller, so it turns a step that leaves the executor waiting into ErrAcceptDeadlock.

Returns an error if a deadlock unrelated to accepts is detected (no progress made and nothing is waiting for a message).

func (*ActionExecutor) Tokens

func (e *ActionExecutor) Tokens() []Token

Tokens returns a copy of active tokens.

type AdoptError

type AdoptError struct {
	Type   string // qualified name of the object's type, as far as it is known
	Reason string
}

AdoptError says which object could not be carried over into a new context, and why, so the loss is reported rather than silently absorbed.

func (*AdoptError) Error

func (e *AdoptError) Error() string

type BindingConflictError

type BindingConflictError struct {
	Target     string
	Left       string
	Right      string
	LeftValue  Value
	RightValue Value
}

BindingConflictError reports unequal values held by the two ends of a binding connector.

func (*BindingConflictError) Error

func (e *BindingConflictError) Error() string

func (*BindingConflictError) Unwrap

func (e *BindingConflictError) Unwrap() error

type BindingCycleError

type BindingCycleError struct {
	Features []string
}

BindingCycleError reports a binding component that has no valued end.

func (*BindingCycleError) Error

func (e *BindingCycleError) Error() string

func (*BindingCycleError) Unwrap

func (e *BindingCycleError) Unwrap() error

type Budgets

type Budgets struct {
	MaxSteps       int64
	MaxActionSteps int64
	MaxStateEvents int64
	MaxDoSteps     int64
	MaxElements    int64
	MaxCalcDepth   int64
}

Budgets bounds one run of the runtime. The six bounds count incommensurable things — expression evaluations, action token-flow steps, state machine events, do actions, materialized collection elements and nested calc invocations — so raising one says nothing about the others.

func BudgetsFromEnv

func BudgetsFromEnv() (Budgets, error)

BudgetsFromEnv returns the bounds the environment asks for: for each variable the positive integer it holds, or the default when it is unset or empty. Every unusable value is reported, naming its variable and the value, so a typo is reported instead of silently leaving the default in place.

func DefaultBudgets

func DefaultBudgets() Budgets

DefaultBudgets returns the bounds a run uses when the environment names no override.

func (Budgets) Validate

func (b Budgets) Validate() error

Validate reports every bound that is not positive, which would let a run make no progress at all, or above its ceiling, which would fail unrecoverably.

type Builtin

type Builtin struct {
	Name   string
	FQN    string
	Params []string
	// Collection is true for the operations over sequences, collections and
	// bodies, which are the ones written in the postfix `x->name()` form.
	Collection bool
	// RequiresImport names the package a model must import for a call by this
	// unqualified name to be legal, and is empty for the OMG libraries, which
	// are in force whatever a model imports.
	RequiresImport string
}

Builtin is one library function this runtime implements directly, described for a caller that lists them: the unqualified name a call may use, the library declaration that name denotes, and the parameter names of that declaration when the registry knows them.

func Builtins

func Builtins() []Builtin

Builtins returns every library function this build implements, in name order, each with the unqualified name a call writes and the import that name needs, if any. It is the registry behind the REPL's %builtins listing, so what the REPL advertises is what this build implements.

type CalcFrameError

type CalcFrameError struct {
	Calc   string // the calc the error surfaced from
	Frames int    // calc frames the error propagated through
	Err    error
	// contains filtered or unexported fields
}

CalcFrameError reports an error raised inside a calc invocation, counting the calc frames it propagated through so a recursion reports a depth rather than one wrapped line per frame.

func (*CalcFrameError) Error

func (e *CalcFrameError) Error() string

func (*CalcFrameError) Unwrap

func (e *CalcFrameError) Unwrap() error

type CalcOutputValue

type CalcOutputValue struct {
	Name  string
	Value Value
}

CalcOutputValue is the value one output feature of a calc usage took, in the order the calc declares its outputs.

type Call

type Call struct {
	Operation string
	Args      map[string]Value
}

Call is the payload of an EventCall: the operation invoked and its arguments.

type CheckResult

type CheckResult struct {
	Holds       bool
	Subject     *Instance
	SubjectRoot *Instance
	SubjectPath string
}

CheckResult is the outcome of one check: whether it holds, the object its conditions were evaluated against — nil when they were evaluated against the declaration because no object carries the checked element — and, for a nested subject, the object the search started from plus the features walked from it — ending in the declaration the object materializes, as an ambiguity names it — which are how a caller names an object holding no name of its own.

type Condition

type Condition struct {
	// Expr is the condition's expression, nil for a group.
	Expr ast.Node

	// Scope is where Expr's names resolve, nil for a group.
	Scope *symbols.Scope

	// Group is the conditions a body states, all of which must hold; nil for a
	// condition stating an expression.
	Group []Condition

	// Negated is the negation the declaration wrote, applied to Expr or to the
	// whole conjunction Group stands for.
	Negated bool

	// Required distinguishes a required condition from an assumption, which is
	// trusted rather than required to hold.
	Required bool
}

Condition is one boolean check a constraint or requirement states, with the scope its expression resolves names in. A condition states either an expression or a group, which holds when all of its conditions hold.

func (Condition) Label

func (c Condition) Label() string

Label renders the condition as written, negation and grouping included.

func (Condition) Owner

func (c Condition) Owner() *symbols.Symbol

Owner is the element declaring the condition, which is the supertype it was inherited from for an inherited one, or nil when the scope has no owner.

type ConnectorEnd

type ConnectorEnd struct {
	Name  string
	Value Value
}

ConnectorEnd is one end of a materialized connector: the name of the end feature it occupies, empty for an end the model leaves unnamed, and the value the end attaches to. The value is the connected feature itself — an object held at an end is the very object the connected feature holds, not a copy of it (KerML 1.0 §7.4.6) — so writing through one is read through the other.

type ConnectorEndError

type ConnectorEndError struct {
	Connector string // the connector as declared
	End       string // the feature the end names, as written
	Location  string // file and position of the end
	Err       error  // why the end could not be attached
}

ConnectorEndError reports a connector end that cannot be attached to what it names, carrying where the end was written so the model can be corrected.

func (*ConnectorEndError) Error

func (e *ConnectorEndError) Error() string

func (*ConnectorEndError) Is

func (e *ConnectorEndError) Is(target error) bool

Is reports that this error is an ErrConnectorEnd, so a caller can test for the condition without knowing which end of which connector failed.

func (*ConnectorEndError) Unwrap

func (e *ConnectorEndError) Unwrap() error

type Context

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

Context carries runtime execution state. One per workspace session.

func NewContext

func NewContext(model *semantics.Model, resolver *resolve.Resolver, maxSteps int64) *Context

NewContext creates a runtime context backed by the given semantic model. maxSteps sets the runaway guard (step counter limit); the executor bounds take their defaults, which SetBudgets replaces. It panics if maxSteps <= 0: the limit is a programmer-supplied invariant, not user input, so callers must pass a positive value.

func (*Context) Adopt

func (ctx *Context) Adopt(prev *Context, shapes *Shapes, obj *Instance) ([]string, error)

Adopt takes obj — and every object it holds — over from prev into this context, keeping the identity and the values they carry across a re-analysis of the document they were materialized from. Each object is rebound to the declaration of the same qualified name here, which must resolve to the shape recorded in shapes; anything else is refused with the context left untouched. The objects are moved rather than copied, so prev holds them too afterwards and this context takes over its identity sequence; nothing new should be materialized through prev, which registers it there alone.

A behavior a carried object ran belongs to the analysis it started in, so it is started again here from its initial state rather than continued. The behaviors restarted are returned, so the carry-over reports what it cost.

func (*Context) AdoptIdentities

func (ctx *Context) AdoptIdentities(prev *Context)

AdoptIdentities takes over the identity sequence of a context this one replaces, without carrying any object over: objects a run started before still materializes through it, so neither context may hand out the other's.

func (*Context) Budgets

func (ctx *Context) Budgets() Budgets

Budgets returns the bounds this context runs under.

func (*Context) CalcUsageOutput

func (ctx *Context) CalcUsageOutput(sym *symbols.Symbol, name string, scope *symbols.Scope, self *Instance) (Value, error)

CalcUsageOutput evaluates a calc usage and returns the value of one of its output features. The usage's inputs bind from its own member values, falling back to the defaults declared along its specialization chain; self, when non-null, is the object the usage is a feature of, whose feature values the inputs may name. Reading several outputs of the same usage runs its body once.

func (*Context) CalcUsageOutputs

func (ctx *Context) CalcUsageOutputs(sym *symbols.Symbol, scope *symbols.Scope, self *Instance) ([]CalcOutputValue, error)

CalcUsageOutputs evaluates a calc usage and returns the value of every output feature it declares, in declaration order, from one run of its body.

func (*Context) CaseConditionsOf

func (ctx *Context) CaseConditionsOf(sym *symbols.Symbol, scope *symbols.Scope) []Condition

CaseConditionsOf returns the conditions a case states as what it holds true of its parameters: the conditions its own members state, and the ones stated by the constraints it requires, assumes or asserts in its body. A constraint declared without one of those keywords states nothing the case checks, so it is left out.

func (*Context) Changed

func (ctx *Context) Changed(shapes *Shapes) (string, bool)

Changed returns the declaration this context no longer resolves the way shapes recorded it, so a caller can name what invalidated the state it took those shapes for. They were recorded outwards, so reading them back names the one that changed rather than one that only holds it.

func (*Context) CheckConstraintOn

func (ctx *Context) CheckConstraintOn(sym *symbols.Symbol, scope *symbols.Scope, self *Instance) (CheckResult, error)

CheckConstraintOn evaluates a constraint as EvaluateConstraintOn does and also reports the object it turned out to be about, which a caller labelling the verdict needs: it is not always the instance supplied.

func (*Context) CheckRequirementOn

func (ctx *Context) CheckRequirementOn(sym *symbols.Symbol, scope *symbols.Scope, self *Instance) (CheckResult, error)

CheckRequirementOn evaluates a requirement as EvaluateRequirementOn does and also reports the object it turned out to be about.

func (*Context) CheckSatisfactionOn

func (ctx *Context) CheckSatisfactionOn(a *SatisfyAssertion, subject *Instance) (CheckResult, error)

CheckSatisfactionOn evaluates a satisfaction assertion as EvaluateSatisfactionOn does and also reports the object it turned out to be about.

func (*Context) CompositeTypeOf

func (ctx *Context) CompositeTypeOf(feat *EffectiveFeature) *symbols.Symbol

CompositeTypeOf returns what a feature is materialized from, or nil for one that holds a value rather than an object — a default that binds takes precedence over instantiation, as in GetFeatureValue above. A usage with features of its own is instantiated as itself, so its body governs and an untyped nested part materializes at all. Answering costs no allocation, so a caller walking an object graph can decide whether to descend before descending.

func (*Context) ConditionsOf

func (ctx *Context) ConditionsOf(sym *symbols.Symbol, scope *symbols.Scope) []Condition

ConditionsOf returns the conditions sym states, its inherited ones first: the same collection, in the same order, that evaluating sym checks. scope stands in for sym's own scope when sym declares none.

func (*Context) CreateActionExecutor

func (ctx *Context) CreateActionExecutor(action *symbols.Symbol) (*ActionExecutor, error)

CreateActionExecutor creates an action executor without starting execution. For REPL debugging - allows step-by-step execution control.

func (*Context) CreateActionExecutorFor

func (ctx *Context) CreateActionExecutorFor(action *symbols.Symbol, self *Instance) (*ActionExecutor, error)

CreateActionExecutorFor creates an action executor for an action performed by self, without starting execution.

func (*Context) CreateStateExecutor

func (ctx *Context) CreateStateExecutor(stateMachine *symbols.Symbol) (*StateExecutor, error)

CreateStateExecutor creates a state executor without starting execution. For REPL debugging - allows step-by-step execution control.

func (*Context) CreateStateExecutorFor

func (ctx *Context) CreateStateExecutorFor(stateMachine *symbols.Symbol, self *Instance) (*StateExecutor, error)

CreateStateExecutorFor creates a state executor for a machine performed by self, without starting execution.

func (*Context) EnumerationLiteralValue

func (ctx *Context) EnumerationLiteralValue(sym *symbols.Symbol) (Value, bool, error)

EnumerationLiteralValue is the value sym has when it is an enumeration literal, reported as such so a caller holding only a symbol — an `%eval` of a literal — answers with the value rather than "no value".

func (*Context) Eval

func (ctx *Context) Eval(node ast.Node) (Value, error)

Eval is the top-level entry point for evaluating an expression in an empty environment. Resolves names from the root scope.

func (*Context) EvalWithScope

func (ctx *Context) EvalWithScope(node ast.Node, scope *symbols.Scope) (Value, error)

EvalWithScope evaluates an expression with a given scope context for name resolution.

func (*Context) EvalWithScopeOn

func (ctx *Context) EvalWithScopeOn(node ast.Node, scope *symbols.Scope, self *Instance) (Value, error)

EvalWithScopeOn evaluates an expression against a concrete instance, so a feature it names reads that object's feature value. It brackets one run, as EvalWithScope does, which is what bounds the evaluation by the step budget.

func (*Context) EvaluateConstraint

func (ctx *Context) EvaluateConstraint(sym *symbols.Symbol, scope *symbols.Scope) (bool, error)

EvaluateConstraint evaluates a constraint definition/usage naming no object: against the single object of this runtime carrying it, the declared defaults when there is none, ErrAmbiguousSubject when there are several. Returns (satisfied, error). If IsAssert=true, violation is an error. If IsAssert=false (assume), always returns (true, nil) but logs assumptions.

func (*Context) EvaluateConstraintOn

func (ctx *Context) EvaluateConstraintOn(sym *symbols.Symbol, scope *symbols.Scope, self *Instance) (bool, error)

EvaluateConstraintOn evaluates a constraint against a concrete instance: a feature the constraint names resolves to that instance's feature value, so the same constraint can pass for one instance and fail for another. An instance that does not carry the constraint itself is searched for the nested object that does; a nil instance leaves the subject to EvaluateConstraint's rule.

func (*Context) EvaluateRequirement

func (ctx *Context) EvaluateRequirement(sym *symbols.Symbol, scope *symbols.Scope) (bool, error)

EvaluateRequirement evaluates a requirement definition/usage naming no object, choosing its subject as EvaluateConstraint does. Returns (satisfied, error). Validates subject/actor types and evaluates assume/require expressions. Assume members always pass (trusted), require members must evaluate to true.

func (*Context) EvaluateRequirementOn

func (ctx *Context) EvaluateRequirementOn(sym *symbols.Symbol, scope *symbols.Scope, self *Instance) (bool, error)

EvaluateRequirementOn evaluates a requirement against a concrete instance, binding the features it names to that instance's feature values. The subject is chosen as EvaluateConstraintOn chooses it, and the subject/actor bindings are evaluated against that same object.

func (*Context) EvaluateSatisfaction

func (ctx *Context) EvaluateSatisfaction(a *SatisfyAssertion) (bool, error)

EvaluateSatisfaction evaluates a satisfaction assertion against a fresh instance of its subject, so that the values the subject declares supply the requirement's own.

func (*Context) EvaluateSatisfactionOn

func (ctx *Context) EvaluateSatisfactionOn(a *SatisfyAssertion, subject *Instance) (bool, error)

EvaluateSatisfactionOn evaluates a satisfaction assertion against a given object as its subject: the requirement's subject parameter is bound to that object, so a feature the requirement's conditions reach through the subject reads the value that object holds. A nil subject instantiates the feature the assertion names with `by`.

A false verdict is returned as a *ViolationError, which unwraps to ErrViolated: it is an answer about the model, not a failure to evaluate.

func (*Context) ExecuteAction

func (ctx *Context) ExecuteAction(action *symbols.Symbol) (map[string]Value, error)

ExecuteAction executes an action definition/usage to completion. Returns the values the action's features hold when it completed.

func (*Context) ExecuteActionPerformedBy

func (ctx *Context) ExecuteActionPerformedBy(action *symbols.Symbol, self *Instance, inputs map[string]Value) (map[string]Value, error)

ExecuteActionPerformedBy executes an action performed by self, whose connections route what the action sends and whose variant selections decide which of them are realized. A nil self performs the action outside any object.

func (*Context) ExecuteActionWithInputs

func (ctx *Context) ExecuteActionWithInputs(action *symbols.Symbol, inputs map[string]Value) (map[string]Value, error)

ExecuteActionWithInputs executes an action, seeding its feature space with the provided input parameter bindings (keyed by parameter name). Inputs override action attribute defaults of the same name. Returns the final feature values.

func (*Context) ExecuteState

func (ctx *Context) ExecuteState(stateMachine *symbols.Symbol) (map[string]Value, error)

ExecuteState executes a state machine, processing events until completion or suspension. Returns final state data from the state machine's execution. Execution stops when: - A final state is reached (StateCompleted) - Event queue is empty (StateSuspended) - Max event processing steps exceeded (error)

func (*Context) ExecuteStatePerformedBy

func (ctx *Context) ExecuteStatePerformedBy(stateMachine *symbols.Symbol, self *Instance, events []string) (map[string]Value, []string, error)

ExecuteStatePerformedBy executes a state machine performed by self, whose connections route what the machine sends and whose variant selections decide which of them are realized. A nil self performs it outside any object.

func (*Context) ExecuteStateWithEvents

func (ctx *Context) ExecuteStateWithEvents(stateMachine *symbols.Symbol, events []string) (map[string]Value, []string, error)

ExecuteStateWithEvents executes a state machine, first injecting the provided signal events (by signal-type name) into the event queue, then processing all events until completion or suspension. Returns the final state data and the ordered list of visited state names.

func (*Context) FeaturesOf

func (ctx *Context) FeaturesOf(typeSym *symbols.Symbol) []EffectiveFeature

FeaturesOf returns the ordered, deduplicated effective-feature list for the given type symbol. Result: own + inherited − redefined/masked, memoized per symbol.

func (*Context) HoldsNoValue

func (ctx *Context) HoldsNoValue(val Value) bool

HoldsNoValue reports whether a value is an object materialized for a valueless feature of a value type. Such an object has no feature that could hold a value and is no value itself (KerML: a DataType classifies values), so it reads as unset rather than as an object.

func (*Context) Instance

func (ctx *Context) Instance(id int64) (*Instance, bool)

Instance retrieves an instance by ID, so a caller holding a ValInstance can reach the object it names.

func (*Context) Instantiate

func (ctx *Context) Instantiate(sym *symbols.Symbol) (*Instance, error)

Instantiate materializes an instance of the given usage/definition symbol. Allocates ID, creates feature values per FeaturesOf(sym), evaluates default values, leaves composite features lazy, then starts the behaviors the type exhibits or performs and runs them to quiescence. Returns the instance or an error.

Each call materializes a distinct object with an identity and behaviors of its own; occurrenceOf is the path that reads one object of a usage twice.

func (*Context) InvokeCalc

func (ctx *Context) InvokeCalc(sym *symbols.Symbol, args []Value, scope *symbols.Scope) (Value, error)

InvokeCalc invokes a calculation with the given positional arguments and returns its result. Arguments bind to the calc's input parameters in declaration order; a parameter with no argument falls back to its declared default. The body is evaluated in the calc's own scope, so scope is used only as a fallback for a symbol that owns no scope.

func (*Context) InvokeCalcNamed

func (ctx *Context) InvokeCalcNamed(sym *symbols.Symbol, args map[string]Value, scope *symbols.Scope) (Value, error)

InvokeCalcNamed invokes a calculation with arguments bound by parameter name. A parameter with no argument falls back to its declared default.

func (*Context) InvokeOperation

func (ctx *Context) InvokeOperation(inst *Instance, name string, args map[string]Value) (map[string]Value, error)

InvokeOperation runs a behavior the object's type owns with the object as the performer: what the body reads and writes is that object's feature values, and what it sends and accepts carries that object's identity. Arguments bind to the operation's `in` and `inout` parameters by name.

func (*Context) IsVariationFeature

func (ctx *Context) IsVariationFeature(feat *EffectiveFeature) bool

IsVariationFeature reports whether a feature is a variation point, whose feature value holds the variant it is bound to rather than an object of itself.

func (*Context) MaterializationErrors

func (ctx *Context) MaterializationErrors(inst *Instance) (errs []error, bounded bool)

MaterializationErrors reads every feature value of an object, and of the objects its feature values hold, and returns what materializing them reported, in the order the feature values were read. Feature values are lazy, so a default that does not conform to its feature's multiplicity is only found by reading it: a caller reporting on an object it created calls this rather than leaving those diagnostics to whoever reads a feature value next. bounded is true when the walk did not read every feature value — its budget was spent, or nesting it does not descend into was elided — so what it did not reach is unreported rather than clean.

func (*Context) Model

func (ctx *Context) Model() *semantics.Model

Model returns the semantic model this context operates over.

func (*Context) ObjectivesOf

func (ctx *Context) ObjectivesOf(sym *symbols.Symbol, scope *symbols.Scope) []Objective

ObjectivesOf returns the objectives sym states, its inherited ones first and in declaration order. An objective restating an inherited one by name stands where it is restated.

func (*Context) PendingMessages

func (ctx *Context) PendingMessages() []Message

PendingMessages returns the messages still in flight, oldest first.

func (*Context) PostMessage

func (ctx *Context) PostMessage(msg Message)

PostMessage puts a message on the context-wide bus, where every executor sharing this context can see it. Actions and state machines communicate through this bus rather than through per-executor queues, so a message a state machine's entry action sends can be accepted by one of its transitions.

A message posted with a destination but no Delivery — one injected from outside the model — is held to the destination it names.

func (*Context) RegisterSource

func (ctx *Context) RegisterSource(sf *source.SourceFile)

RegisterSource gives the context the text of a file the model was read from, so an error about a declaration in it reports a line and column.

func (*Context) Resolver

func (ctx *Context) Resolver() *resolve.Resolver

Resolver returns the name resolver this context resolves references with.

func (*Context) SatisfyAssertionOf

func (ctx *Context) SatisfyAssertionOf(sym *symbols.Symbol) (*SatisfyAssertion, error)

SatisfyAssertionOf returns the assertion sym declares, or an error when sym is not a satisfaction assertion. It names the one a `satisfy requirement r by p` form declares under a name.

func (*Context) SatisfyAssertionsIn

func (ctx *Context) SatisfyAssertionsIn(scope *symbols.Scope) []*SatisfyAssertion

SatisfyAssertionsIn returns the satisfaction assertions stated in scope and, recursively, in the scopes nested within it, in declaration order. An assertion is anonymous in its usual form, so it is reached through the element that states it rather than by name.

func (*Context) SatisfySubject

func (ctx *Context) SatisfySubject(a *SatisfyAssertion) (*Instance, error)

SatisfySubject returns an object of the feature a satisfaction assertion names with `by`: the object its requirement is evaluated against when the caller supplies none.

func (*Context) SetBudgets

func (ctx *Context) SetBudgets(b Budgets) error

SetBudgets replaces the bounds this context runs under, rejecting a set that holds a non-positive bound. The evaluation step counter already spent is left alone: the budget is a bound on the run, not a reset of it.

func (*Context) SetTrace

func (ctx *Context) SetTrace(tr *TraceRecorder)

SetTrace attaches a trace recorder to this context, so that every expression and calc evaluated through it is recorded. Pass nil to stop tracing.

func (*Context) ShapeDigest

func (ctx *Context) ShapeDigest(sym *symbols.Symbol) string

ShapeDigest renders what instantiating a type produces as this context resolves it now: the features an object of it gets, with the type, multiplicity and default of each, and the shapes of the types those features hold. Two contexts that agree on the digest agree on the object.

func (*Context) ShapesOf

func (ctx *Context) ShapesOf(obj *Instance) *Shapes

ShapesOf records the shapes obj and everything it holds were materialized against: the objects reachable through its feature values and connector ends, plus the variants its values selected. A connector no name reaches is materialized again rather than carried, so it is no part of this.

func (*Context) ShapesOfType

func (ctx *Context) ShapesOfType(sym *symbols.Symbol) *Shapes

ShapesOfType records the shape of one declaration as this context resolves it, which is what state held over a declaration rather than an object — a debugging session over an action — is invalidated by a change to.

func (*Context) SourceLocation

func (ctx *Context) SourceLocation(file string, span source.Span) string

SourceLocation renders where a span in a file was written, as `file:line:col`, falling back to a byte offset for a file whose text was not registered.

func (*Context) TakeMessage

func (ctx *Context) TakeMessage(match func(Message) bool) (Message, bool)

TakeMessage removes and returns the oldest message satisfying match. Messages that do not match keep their place in the queue, so a consumer looking for one type does not consume or reorder another's.

type DeliveryKind

type DeliveryKind uint8

DeliveryKind is what a message's destination resolved to, and so what a consumer must match: an unaddressed message resolved nothing and any consumer may take it, while every addressed or routed one names a destination in full.

const (
	// DeliverAnyone is a message no send addressed, such as one injected from
	// outside the model: it has no destination to hold a consumer to.
	DeliverAnyone DeliveryKind = iota
	// DeliverPort is the port of an object, reached by a connection or addressed.
	DeliverPort
	// DeliverPortReceiver is a receiver of an object reached through a port.
	DeliverPortReceiver
	// DeliverReceiver is the receiving node named within an object.
	DeliverReceiver
	// DeliverObject is an object itself, whichever of its consumers accepts.
	DeliverObject
)

type EffectiveFeature

type EffectiveFeature struct {
	Name         string
	Symbol       *symbols.Symbol // the declaring feature symbol
	OwnerType    *symbols.Symbol // type that declares this feature (may be supertype)
	Type         *symbols.Symbol // resolved type (nil if untyped)
	Multiplicity semantics.Range // declared or inherited (default 1..1)
	DefaultValue ast.Node        // value-binding expression (nil if none)
	DefaultDecl  *symbols.Symbol // feature the DefaultValue was written on (nil if none)
}

EffectiveFeature represents one feature value in a type's flattened schema: own + inherited − redefined/masked, carrying type + multiplicity + default.

func (*EffectiveFeature) DeclScope

func (f *EffectiveFeature) DeclScope() *symbols.Scope

DeclScope returns the scope the feature was declared in, which is the scope a default value written on it must be evaluated in: an inherited feature's default refers to names visible where the supertype was written, not where the instantiated type is.

func (*EffectiveFeature) DefaultScope

func (f *EffectiveFeature) DefaultScope() *symbols.Scope

DefaultScope returns the scope DefaultValue resolves its names in, which for an inherited default is where the redefined declaration wrote it.

type EvalContext

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

EvalContext is the lexical environment during evaluation (Tier 3).

func NewEvalContext

func NewEvalContext(ctx *Context, scope *symbols.Scope) *EvalContext

NewEvalContext creates an evaluation context with an empty frame stack. It inherits the runtime context's trace recorder, so every evaluation reached from a traced context is recorded, including nested calc invocations.

func NewEvalContextIn

func NewEvalContextIn(ctx *Context, scope *symbols.Scope, self *Instance) *EvalContext

NewEvalContextIn creates an evaluation context bound to an instance, so that a feature name resolves to that instance's feature value rather than to the declared default of the same name.

func (*EvalContext) Eval

func (ec *EvalContext) Eval(node ast.Node) (Value, error)

Eval evaluates an expression node. Returns a Value or an error. Increments ctx.steps on each eval call; errors when ctx.steps >= ctx.maxSteps. When the context is traced, the evaluation is recorded after its sub-expressions, which makes sub-expression order part of the trace.

func (*EvalContext) Lookup

func (ec *EvalContext) Lookup(name string) (Value, bool)

Lookup searches for a name in the frame stack (innermost first).

func (*EvalContext) Pop

func (ec *EvalContext) Pop()

Pop removes the top frame from the stack (on return, lambda exit).

func (*EvalContext) Push

func (ec *EvalContext) Push(bindings map[string]Value)

Push adds a new frame to the stack (on calc invocation, lambda entry).

type Event

type Event struct {
	ID        int64       // Unique event ID
	Type      EventType   // Event type
	Timestamp float64     // Virtual time when event fires
	Payload   interface{} // Event-specific data
}

Event represents a state machine event.

func (Event) String

func (e Event) String() string

type EventQueue

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

EventQueue is a priority queue of events sorted by timestamp (min-heap).

func NewEventQueue

func NewEventQueue() *EventQueue

NewEventQueue creates an empty event queue.

func (*EventQueue) Len

func (q *EventQueue) Len() int

Len returns the number of pending events.

func (*EventQueue) Peek

func (q *EventQueue) Peek() Event

Peek returns the earliest event without removing it.

func (*EventQueue) Pop

func (q *EventQueue) Pop() Event

Pop removes and returns the earliest event.

func (*EventQueue) Push

func (q *EventQueue) Push(e Event)

Push adds an event to the queue.

func (*EventQueue) Withdraw

func (q *EventQueue) Withdraw(drop func(Event) bool)

Withdraw drops every pending event the predicate accepts, which cancels an occurrence a state no longer waits for.

type EventType

type EventType int

EventType identifies event kinds for state machines.

const (
	EventTime   EventType = iota // TimeEvent - fires after duration
	EventChange                  // ChangeEvent - fires when condition true
	EventAccept                  // AcceptEvent - fires when signal received
	EventCall                    // CallEvent - fires when operation invoked
)

func (EventType) String

func (t EventType) String() string

type ExecutionState

type ExecutionState int

ExecutionState tracks executor state.

const (
	StateReady     ExecutionState = iota // Not started
	StateRunning                         // In progress
	StateCompleted                       // Reached terminal state
	StateSuspended                       // Paused for debugging
	StateWaiting                         // Every remaining token is parked at an accept
)

func (ExecutionState) String

func (s ExecutionState) String() string

type FeatureValue

type FeatureValue struct {
	Feature        *EffectiveFeature
	Value          Value // scalar feature value (multiplicity [1])
	Values         Value // collection feature value (Sequence or Set)
	Materialized   bool  // lazy flag: has this feature value been instantiated?
	Written        bool  // a run assigned this value, so no default derives it again
	BindingDerived bool  // value came from binding propagation rather than a write
}

Feature value holds the runtime value(s) for one feature.

func (*FeatureValue) HeldValue

func (s *FeatureValue) HeldValue() Value

HeldValue is the value the feature value reads as: its collection when the feature is multi-valued, otherwise its scalar.

type FeatureValueError

type FeatureValueError struct {
	Err error
}

FeatureValueError marks a feature value that could not be materialized. It reads as the error that kept the feature value from materializing and unwraps to it as well as to ErrFeatureValueMaterialization, so a caller tests either.

func (*FeatureValueError) Error

func (e *FeatureValueError) Error() string

func (*FeatureValueError) Unwrap

func (e *FeatureValueError) Unwrap() []error

type Instance

type Instance struct {
	ID            int64                    // unique identity
	Type          *symbols.Symbol          // the def/usage symbol this instantiates
	FeatureValues map[string]*FeatureValue // feature name → feature value
	// Ends are the ends of the connector this object materializes, in declaration
	// order, and nil for an object that is no connector. A named end also reads
	// through the feature value of that name; the order is what an end with no name of its
	// own is identified by.
	Ends []ConnectorEnd
	// contains filtered or unexported fields
}

Instance is a runtime-materialized object (Tier 2).

func (*Instance) Behavior

func (inst *Instance) Behavior(name string) (*ObjectBehavior, bool)

Behavior returns the behavior of the given name the object runs. An unnamed behavior answers to no name and so is never returned.

func (*Instance) Behaviors

func (inst *Instance) Behaviors() []*ObjectBehavior

Behaviors are the behaviors the object runs, in declaration order.

func (*Instance) ExhibitedState

func (inst *Instance) ExhibitedState() (*ObjectBehavior, bool)

ExhibitedState returns the machine the object exhibits, and false when it exhibits none. With several, it returns the first declared.

func (*Instance) GetFeatureValue

func (inst *Instance) GetFeatureValue(ctx *Context, name string) (*FeatureValue, error)

GetFeatureValue retrieves the feature value for the named feature, materializing it lazily if it's a composite feature that hasn't been accessed yet. A feature value that could not be materialized is marked as such — it unwraps to ErrFeatureValueMaterialization — so a caller can tell it from any other failure to evaluate, whatever the expression it surfaced through.

func (*Instance) OwnedConnectors

func (inst *Instance) OwnedConnectors(ctx *Context) ([]*Instance, error)

OwnedConnectors returns the connectors the instance owns that no feature names — an anonymous `connect a.p to b.q` member — materializing them once, in declaration order. A named connector is reached through its feature value instead.

func (*Instance) Owner

func (inst *Instance) Owner() (*Instance, string)

Owner answers the object holding this one and the feature of it that does, or nil and "" for an object no other holds.

func (*Instance) SetFeatureValue

func (inst *Instance) SetFeatureValue(ctx *Context, name string, value Value) error

SetFeatureValue writes a value to the named feature value of the object, which is how a behavior the object performs updates the object's own state. The value must conform to the multiplicity governing the feature; a feature the object does not have is reported rather than added.

type Message

type Message struct {
	SignalType string
	Target     string
	Port       string
	Object     int64
	Delivery   DeliveryKind
	Payload    map[string]Value
}

Message is a signal instance in flight.

SignalType names the message's type: the type the send statement named, or the scalar type of the value it evaluated to. An accept whose parameter is typed consumes only messages of that type, so two sends of different types reach different accepts regardless of the order they were posted in.

Target names the receiving node of the sending behavior a `send m to r` addressed; a consumer accepts a message addressed to itself or to no one.

Port names the port the message reached — the peer end a `via p` send routed to, or the port an addressed send resolved to — and only an accept on that port consumes it, keeping port-routed and addressed traffic separate.

Object identifies the object the message reached, 0 for none, and Delivery what of that destination a consumer must satisfy to take the message.

type ObjectBehavior

type ObjectBehavior struct {
	// Name is the name the behavior answers to on the object.
	Name string
	Kind lower.ClassifierBehaviorKind
	// Symbol is the state machine or action holding the body being run, which is
	// the binding declaration itself when it states one.
	Symbol *symbols.Symbol
	// Object is the object performing the behavior.
	Object *Instance

	// State is the machine the object exhibits, nil for a performed action.
	State *StateExecutor
	// Action is the action the object performs, nil for an exhibited machine.
	Action *ActionExecutor
	// contains filtered or unexported fields
}

ObjectBehavior is a behavior one object runs because its type exhibits or performs it: an execution of its own, bound to that object's identity.

func (*ObjectBehavior) Describe

func (b *ObjectBehavior) Describe() string

Describe names the behavior and the object running it, for diagnostics.

type Objective

type Objective struct {
	// Name is the objective's name, empty for an anonymous one.
	Name string

	// Symbol is the objective usage's symbol.
	Symbol *symbols.Symbol

	// Type is the objective definition it is typed by, nil when untyped.
	Type *symbols.Symbol

	// Direction is the way its value is to be improved.
	Direction ObjectiveDirection

	// Value is the expression stating the value to improve, nil when the
	// objective states none.
	Value ast.Node

	// Scope is where Value's names resolve.
	Scope *symbols.Scope

	// Best is the feature restating the library's `best` whose value the
	// objective improves, nil when the objective states its value another way.
	Best *symbols.Symbol

	// Conditions are the conditions the objective states itself, its own body's
	// and the ones it inherits from the model's own objective definitions: the
	// trade-study library's own conditions are left out, being about choosing
	// among alternatives rather than about which values are feasible.
	Conditions []Condition
}

Objective is one objective an analysis case states: which way its value is to be improved, the expression stating that value, and the conditions it states itself.

func (Objective) Text

func (o Objective) Text() string

Text renders the expression stating the objective's value as written, empty when it states none.

type ObjectiveDirection

type ObjectiveDirection int

ObjectiveDirection is the way an objective's value is to be improved, taken from the trade-study objective definition it is typed by.

const (
	// NoDirection is an objective specializing neither MinimizeObjective nor
	// MaximizeObjective, whose direction the model therefore does not state.
	NoDirection ObjectiveDirection = iota
	// Minimize is an objective specializing TradeStudies::MinimizeObjective.
	Minimize
	// Maximize is an objective specializing TradeStudies::MaximizeObjective.
	Maximize
)

func (ObjectiveDirection) String

func (d ObjectiveDirection) String() string

String names the direction as the model states it.

type OperandTypeError

type OperandTypeError struct {
	Op    string      // the operator, as written
	Left  string      // description of the left operand's type
	Right string      // description of the right operand's type
	Span  source.Span // span of the operator expression
}

OperandTypeError reports an operator applied to operand types it is not defined for, naming the operator and both operands and carrying the span of the expression so a surface holding the source can point at it.

func (*OperandTypeError) Error

func (e *OperandTypeError) Error() string

func (*OperandTypeError) Unwrap

func (e *OperandTypeError) Unwrap() error

type Quantity

type Quantity struct {
	Num  semantics.Value
	Unit Unit
}

Quantity is a scalar quantity value: a magnitude and the measurement reference it is expressed in (Quantities::ScalarQuantityValue is exactly a number `num` and a reference `mRef`). The unit travels with the value, so `1.5 [m/s]` is never mistaken for `1.5 [km/h]`.

func (*Quantity) String

func (q *Quantity) String() string

String renders the quantity as a magnitude in its unit: `1.5 [m/s]`.

func (*Quantity) TextWithMagnitude

func (q *Quantity) TextWithMagnitude(magnitude string) string

TextWithMagnitude renders the quantity from an already-rendered magnitude, so a caller with its own convention for numbers — a trace, which distinguishes a whole Real from an Integer, or a result table, which rounds a Real for display — keeps it and still names the unit the same way. The stored magnitude is untouched.

type SatisfyAssertion

type SatisfyAssertion struct {
	// Symbol is the satisfy usage itself, which is anonymous in the usual
	// `assert satisfy r by p;` form.
	Symbol *symbols.Symbol

	// Owner is the element stating the assertion (the enclosing part or
	// package), or nil at the root of a document.
	Owner *symbols.Symbol

	// Requirement is the requirement the assertion satisfies: the target of the
	// usage's reference subsetting. It is nil when the reference names nothing
	// resolvable, and when the assertion declares the requirement itself
	// (`satisfy requirement r by p { ... }`), which states its conditions.
	Requirement *symbols.Symbol

	// RequirementRef is the requirement reference as written, so an unresolved
	// one can be reported by name.
	RequirementRef string

	// Subject is the feature named by `by`, whose values the requirement is
	// evaluated against. It is nil when the assertion names no subject, and
	// when the name resolves to nothing.
	Subject *symbols.Symbol

	// SubjectRef is the `by` operand as written.
	SubjectRef string

	// Negated is `assert not satisfy ...`: the assertion holds when the
	// requirement is not satisfied.
	Negated bool
}

SatisfyAssertion is one satisfaction assertion an element states: `assert satisfy <requirement> by <subject>` (SysML v2 §8.3.17.15). The assertion is a requirement usage of its own — it reference-subsets the requirement it satisfies and binds that requirement's subject parameter to the feature named by `by` — so it carries a verdict the requirement alone does not: one about the values that feature actually holds.

func (*SatisfyAssertion) Text

func (a *SatisfyAssertion) Text() string

Text renders the assertion as it was written, so an anonymous one can be named in a verdict. A `satisfy requirement r by p` form declares the requirement rather than referencing one, so it is named by the usage itself.

type SendPortTypeMismatchError added in v0.2.0

type SendPortTypeMismatchError struct {
	Port       string
	Receiver   string
	SignalType string
}

SendPortTypeMismatchError gives the routed send's incompatible type.

func (*SendPortTypeMismatchError) Error added in v0.2.0

func (e *SendPortTypeMismatchError) Error() string

func (*SendPortTypeMismatchError) Unwrap added in v0.2.0

func (e *SendPortTypeMismatchError) Unwrap() error

type Sequence

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

Sequence is an ordered collection (slice-backed).

func NewSequence

func NewSequence() *Sequence

NewSequence creates an empty Sequence.

func (*Sequence) Append

func (s *Sequence) Append(val Value)

Append adds a value to the end of the sequence.

func (*Sequence) At

func (s *Sequence) At(index int) (Value, error)

At returns the element at the given index (0-based).

func (*Sequence) Elements

func (s *Sequence) Elements() []Value

Elements returns the underlying slice (for iteration).

func (*Sequence) Size

func (s *Sequence) Size() int

Size returns the number of elements.

type Set

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

Set is a unique collection backed by hash buckets and exact comparisons. A set has no inherent order, but enumerating one has to answer in some order, and insertion order is the one order a set does carry: it makes a sequence derived from a set — what `select` and `collect` over a set return — reproducible instead of dependent on map iteration.

func NewSet

func NewSet() *Set

NewSet creates an empty Set.

func (*Set) Add

func (s *Set) Add(val Value)

Add inserts a value into the set (deduplicates by exact value equality).

func (*Set) Contains

func (s *Set) Contains(val Value) bool

Contains checks if the value is in the set.

func (*Set) Elements

func (s *Set) Elements() []Value

Elements returns all elements, in the order they were added.

func (*Set) Size

func (s *Set) Size() int

Size returns the number of unique elements.

type Shapes

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

Shapes records the resolved shape of every type a set of objects was materialized against, taken while that resolution is still the current one. It is what a later context compares its own resolution against to decide whether those objects still mean the same thing.

type StateConfiguration

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

StateConfiguration represents the active state configuration (simple or multi-region).

type StateExecutor

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

StateExecutor executes state machines using event-driven semantics.

func (*StateExecutor) ActiveStates

func (e *StateExecutor) ActiveStates() []*ast.StateNode

ActiveStates returns the machine's active state configuration: the single active state, or one state per orthogonal region, in declaration order.

func (*StateExecutor) ChangeWaits

func (e *StateExecutor) ChangeWaits() []string

ChangeWaits describes the change conditions the active configuration was waiting on as of the last poll, and nothing when it watches none.

func (*StateExecutor) CurrentState

func (e *StateExecutor) CurrentState() ast.Node

CurrentState returns the current active state node.

func (*StateExecutor) CurrentTime

func (e *StateExecutor) CurrentTime() float64

CurrentTime returns the current simulation time.

func (*StateExecutor) EventQueue

func (e *StateExecutor) EventQueue() *EventQueue

EventQueue returns the event queue (not copied - read-only access).

func (*StateExecutor) GetStateVisits

func (e *StateExecutor) GetStateVisits() []string

GetStateVisits returns the ordered list of visited state names.

func (*StateExecutor) HasDueEvent

func (e *StateExecutor) HasDueEvent() bool

HasDueEvent reports whether an event scheduled no later than the machine's current time is queued, which a run holding time where it is dispatches.

func (*StateExecutor) HasPendingDoWork

func (e *StateExecutor) HasPendingDoWork() bool

HasPendingDoWork reports whether some active state's do behavior still has an action to run. Such work is due now, unlike a queued event's timestamp.

func (*StateExecutor) HasPendingSignal

func (e *StateExecutor) HasPendingSignal() bool

HasPendingSignal reports whether a signal this machine accepts is in flight. Such a signal is due now, unlike a queued event's timestamp: the next step delivers and dispatches it.

func (*StateExecutor) HasPendingWork

func (e *StateExecutor) HasPendingWork() bool

HasPendingWork reports whether stepping the machine can still make progress: an event is queued, a signal this machine accepts is in flight, or a state's do behavior has actions left to run.

func (*StateExecutor) InvokeOperation

func (e *StateExecutor) InvokeOperation(operation string, args map[string]Value)

InvokeOperation injects a call event for the named operation. Transitions triggered by that operation fire; transitions triggered by another do not.

func (*StateExecutor) PollChangeEvents

func (e *StateExecutor) PollChangeEvents() (bool, error)

PollChangeEvents re-tests the change conditions the active configuration watches and takes the transitions they enable, reporting whether any fired: the step RunToCompletion takes, for a driver that steps the machine itself.

func (*StateExecutor) ProcessNextEvent

func (e *StateExecutor) ProcessNextEvent() error

ProcessNextEvent processes the next event from the queue (for REPL stepping). It is the same step RunToCompletion repeats: every active state's do behavior advances by one action, then the next event is dispatched. Advancing the do behaviors is progress in itself, so a step that ran one and found no event to dispatch succeeds — the completion transition it enables is queued next.

func (*StateExecutor) Resume

func (e *StateExecutor) Resume() bool

Resume returns a machine suspended at quiescence to running, so a driver that makes work available — advancing time, or delivering an event — can step it again. A completed or failed machine is left as it is.

func (*StateExecutor) RunDoRound

func (e *StateExecutor) RunDoRound() (int, error)

RunDoRound advances every active state's do behavior by one action, without dispatching any event, and reports how many actions ran.

func (*StateExecutor) RunToCompletion

func (e *StateExecutor) RunToCompletion() error

RunToCompletion processes queued events until the machine completes or has no event or running do behavior left, at which point it suspends. A state's do behavior runs while the state is active: each run-to-completion step advances every active state's do behavior by one action and then dispatches one event, so concurrently active states interleave instead of one running to the end at entry, and leaving a state abandons the rest of its do behavior.

Change conditions are re-tested per micro-step — after the do round, before the next queued event, and again at quiescence — a tool-defined cadence, since KerML has no clock (docs/project/spec-compliance.md).

The run is bounded by the context's event and do action budgets (SYSML_MAX_EVENTS, SYSML_MAX_DO_STEPS), so a cyclic machine reports a typed error instead of spinning forever. A poll that fires nothing costs no budget; a change transition taken counts as one step, like a dispatched event.

func (*StateExecutor) RunToQuiescence

func (e *StateExecutor) RunToQuiescence() error

RunToQuiescence runs the machine as RunToCompletion does, but leaves an event scheduled for a later time queued rather than advancing to it: the configuration an object settles into is the one reached at the time it was materialized, and a timer it is waiting on is driven by advancing time.

func (*StateExecutor) SendSignal

func (e *StateExecutor) SendSignal(signalType string, args map[string]Value)

SendSignal injects a signal event into the state machine. This is the primary API for driving state machines with external signals. The signal is enqueued and will be processed on the next ProcessNextEvent call.

func (*StateExecutor) SetTrace

func (e *StateExecutor) SetTrace(trace *TraceRecorder)

SetTrace sets the trace recorder for this executor and the context it evaluates in.

func (*StateExecutor) State

func (e *StateExecutor) State() ExecutionState

State returns current execution state.

func (*StateExecutor) StateData

func (e *StateExecutor) StateData() map[string]Value

StateData returns a copy of state machine local data, together with the attributes each state owns under that state's path (`nested.hits`), which two usages of one state definition hold separately.

func (*StateExecutor) StateMachineSymbol

func (e *StateExecutor) StateMachineSymbol() *symbols.Symbol

StateMachineSymbol returns the state machine being executed.

func (*StateExecutor) StateStack

func (e *StateExecutor) StateStack() []*ast.StateNode

StateStack returns a copy of the state stack (active configuration).

func (*StateExecutor) Suspend

func (e *StateExecutor) Suspend() bool

Suspend parks a running machine back at quiescence, for a driver that resumed it, found nothing to do and must not report it as running.

func (*StateExecutor) SuspendReason

func (e *StateExecutor) SuspendReason() string

SuspendReason says why a machine that cannot progress cannot: the change conditions it waits on, or that nothing is left that could fire.

func (*StateExecutor) WatchesChangeCondition

func (e *StateExecutor) WatchesChangeCondition() bool

WatchesChangeCondition reports whether the active configuration watches a change condition, which data written outside the machine can make true.

type Token

type Token struct {
	ID       int64    // Unique token ID
	Location ast.Node // Current node position

	// Wait records that this token is parked at an accept node: the accept
	// found no message it could consume, so the action is suspended there
	// until one arrives. It is nil for every token that is free to advance.
	Wait *AcceptWait
	// contains filtered or unexported fields
}

Token represents a control token in action execution. It carries no values of its own: the action's features are one space every token shares (see ActionExecutor.Data).

type TraceRecorder

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

TraceRecorder captures deterministic execution traces for testing. Used by golden trace tests to detect ordering/scheduling regressions.

Evaluation entries are recorded in post-order: the sub-expressions of an expression appear before it, indented one level deeper, so sibling evaluation order and nesting are both readable off the trace. A constant sub-expression is answered by the semantic constant folder without evaluating its operands, so it appears with no children.

func NewTraceRecorder

func NewTraceRecorder() *TraceRecorder

NewTraceRecorder creates a new trace recorder.

func (*TraceRecorder) BeginEval

func (tr *TraceRecorder) BeginEval()

BeginEval opens a nesting level for one expression's sub-expressions.

func (*TraceRecorder) Clear

func (tr *TraceRecorder) Clear()

Clear clears all recorded entries and resets nesting depth.

func (*TraceRecorder) Disable

func (tr *TraceRecorder) Disable()

Disable disables trace recording.

func (*TraceRecorder) Enable

func (tr *TraceRecorder) Enable()

Enable enables trace recording.

func (*TraceRecorder) EndEval

func (tr *TraceRecorder) EndEval(label string, value Value, err error)

EndEval closes the level BeginEval opened and records the expression's outcome, so the entry appears after the sub-expressions it consumed.

func (*TraceRecorder) EndStatement

func (tr *TraceRecorder) EndStatement()

EndStatement closes the level RecordStatement or RecordLoopIteration opened.

func (*TraceRecorder) Entries

func (tr *TraceRecorder) Entries() []string

Entries returns all recorded trace entries.

func (*TraceRecorder) RecordActionNodeEnter added in v0.4.0

func (tr *TraceRecorder) RecordActionNodeEnter(node string)

RecordActionNodeEnter records a token entering the flow an action node owns, whose steps are that node's subperformances.

func (*TraceRecorder) RecordActionNodeExit added in v0.4.0

func (tr *TraceRecorder) RecordActionNodeExit(node string)

RecordActionNodeExit records the flow an action node owns having completed, which is when the node itself completes.

func (*TraceRecorder) RecordActionStep

func (tr *TraceRecorder) RecordActionStep(step int, tokens []Token)

RecordActionStep records an action executor step with active tokens. Tokens are sorted by ID for deterministic output.

func (*TraceRecorder) RecordBehaviorRun

func (tr *TraceRecorder) RecordBehaviorRun(kind, name string, id int64)

RecordBehaviorRun records an object's behavior being advanced, which is how the interleaving of several objects' behaviors becomes visible.

func (*TraceRecorder) RecordBehaviorStart

func (tr *TraceRecorder) RecordBehaviorStart(kind, name string, id int64)

RecordBehaviorStart records an object's own execution of a behavior its type exhibits or performs starting.

func (*TraceRecorder) RecordCalcBind

func (tr *TraceRecorder) RecordCalcBind(param string, value Value, source string)

RecordCalcBind records binding one calc input parameter. source names where the value came from ("argument" or "default").

func (*TraceRecorder) RecordCalcEnter

func (tr *TraceRecorder) RecordCalcEnter(name string)

RecordCalcEnter records entering a calc invocation and opens a nesting level.

func (*TraceRecorder) RecordCalcExit

func (tr *TraceRecorder) RecordCalcExit(name string, result Value)

RecordCalcExit closes a calc invocation's nesting level and records its result.

func (*TraceRecorder) RecordCalcExitError

func (tr *TraceRecorder) RecordCalcExitError(name string, err error)

RecordCalcExitError closes a calc invocation that failed, recording why. The failure is part of the ordering contract: it says how far binding and evaluation got before the calc gave up.

func (*TraceRecorder) RecordCalcOutput

func (tr *TraceRecorder) RecordCalcOutput(calc, output string, value Value)

RecordCalcOutput records the value one output feature of a calc usage took. The outputs appear after the one evaluation of the usage's body they are read from, which is how the trace shows that reading several of them ran it once.

func (*TraceRecorder) RecordCalcUsageExit

func (tr *TraceRecorder) RecordCalcUsageExit(name string)

RecordCalcUsageExit closes the nesting level of a calc usage's evaluation, which computes the usage's output features rather than one result, so there is no single value to record for it.

func (*TraceRecorder) RecordCalcUsageReuse

func (tr *TraceRecorder) RecordCalcUsageReuse(name string)

RecordCalcUsageReuse records a calc usage read again with the inputs it already ran over, whose values come from that one run. It opens no nesting level of its own, since nothing runs.

func (*TraceRecorder) RecordDoStep

func (tr *TraceRecorder) RecordDoStep(state string)

RecordDoStep records one action of a state's do behavior, which is how the interleaving of concurrently active states' do behaviors becomes visible.

func (*TraceRecorder) RecordEvent

func (tr *TraceRecorder) RecordEvent(event string, time float64)

RecordEvent records an event being processed.

func (*TraceRecorder) RecordLoopIteration

func (tr *TraceRecorder) RecordLoopIteration(iteration int)

RecordLoopIteration records one iteration of a loop and opens a nesting level for what that iteration does, which is how a loop's progress is readable off the trace.

func (*TraceRecorder) RecordObjectMaterialized

func (tr *TraceRecorder) RecordObjectMaterialized(typeName string, id int64)

RecordObjectMaterialized records an object being materialized, before any behavior of it starts.

func (*TraceRecorder) RecordStateEntry

func (tr *TraceRecorder) RecordStateEntry(state string, hasEntryAction bool)

RecordStateEntry records entering a state with optional entry action execution.

func (*TraceRecorder) RecordStateExit

func (tr *TraceRecorder) RecordStateExit(state string, hasExitAction bool)

RecordStateExit records exiting a state with optional exit action execution.

func (*TraceRecorder) RecordStateTransition

func (tr *TraceRecorder) RecordStateTransition(fromState, toState string, event string)

RecordStateTransition records a state transition with event.

func (*TraceRecorder) RecordStatement

func (tr *TraceRecorder) RecordStatement(label string)

RecordStatement records one body statement about to run and opens a nesting level for the expressions it evaluates and the statements it contains.

func (*TraceRecorder) String

func (tr *TraceRecorder) String() string

String returns the trace as a single string (newline-separated entries).

type Unit

type Unit struct {
	Text string
	Term semantics.UnitTerm
}

Unit is a measurement reference as a quantity carries it: the expression it was written as, for diagnostics and printing, and its reduction to base units, which is what decides whether two quantities can be combined.

func (Unit) String

func (u Unit) String() string

String renders the unit as written, falling back to its reduction for a unit composed by an operation rather than written down.

type UnknownSendPortError added in v0.2.0

type UnknownSendPortError struct {
	Port     string
	Receiver string
}

UnknownSendPortError gives the routed send's invalid port and receiver.

func (*UnknownSendPortError) Error added in v0.2.0

func (e *UnknownSendPortError) Error() string

func (*UnknownSendPortError) Unwrap added in v0.2.0

func (e *UnknownSendPortError) Unwrap() error

type UnreachableSendReceiverError added in v0.2.0

type UnreachableSendReceiverError struct {
	Port     string
	Receiver string
}

UnreachableSendReceiverError gives the routed send's unresolved receiver.

func (*UnreachableSendReceiverError) Error added in v0.2.0

func (*UnreachableSendReceiverError) Unwrap added in v0.2.0

func (e *UnreachableSendReceiverError) Unwrap() error

type UnroutableSendError

type UnroutableSendError struct {
	Port     string   // the port or target the send named, as written
	Outbound []string // ends joined to Port that only carry outward
	Address  bool     // the send addressed a target rather than routing through a port
}

UnroutableSendError reports a send that could not be delivered, naming the port it was sent through and the ends joined to it that refused it, so the model can be corrected. An addressed send names a target rather than a port it routes through, so it reports the path that reached no port of any object.

func (*UnroutableSendError) Error

func (e *UnroutableSendError) Error() string

func (*UnroutableSendError) Unwrap

func (e *UnroutableSendError) Unwrap() error

type Value

type Value struct {
	Kind     ValueKind
	Const    semantics.Value // ValConst: reuse static evaluator
	Str      string          // ValString
	Instance int64           // ValInstance: instance ID
	Sequence *Sequence       // ValSequence
	Set      *Set            // ValSet
	Expr     ast.Node        // ValExpr: unevaluated AST for delayed evaluation
	Quantity *Quantity       // ValQuantity: magnitude and measurement unit
	// Variant is the variant a variation was bound to (ValVariant). Instance
	// holds the object materialized for it, 0 when it materializes none.
	Variant *symbols.Symbol
	// Literal is the enumeration literal the value is (ValEnumLiteral). A literal
	// is its own identity: two values are the same literal exactly when they name
	// the same declaration.
	Literal *symbols.Symbol
}

Value is a runtime-evaluable value.

func NewEnumLiteral

func NewEnumLiteral(sym *symbols.Symbol) Value

NewEnumLiteral is the value an enumeration literal that declares no value of its own evaluates to: the identity of that literal.

func (Value) LiteralText

func (v Value) LiteralText() string

LiteralText renders an enumeration literal as it is written, qualified by the enumeration it is a literal of: `Color::red`.

func (Value) Object

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

Object returns the object a value denotes: an instance, or the object a selected variant materialized.

type ValueKind

type ValueKind int

ValueKind distinguishes runtime value types.

const (
	ValInvalid ValueKind = iota
	ValConst             // wraps semantics.Value (int/real/bool/infinity)
	ValNull
	ValString
	ValInstance
	ValSequence
	ValSet
	ValExpr        // wraps unevaluated AST node for delayed evaluation (e.g., BodyExpr for select/collect)
	ValQuantity    // a magnitude and the measurement unit it is expressed in
	ValVariant     // the variant selected for a variation, and the object it materializes
	ValEnumLiteral // one literal of an enumeration definition, identified by itself
)

func (ValueKind) String

func (k ValueKind) String() string

String names the kind, so diagnostics quoting it read as more than an index.

type ViolationError

type ViolationError struct {
	Kind      string // "constraint" or "requirement"
	Element   string // name of the element stating the condition
	What      string // "assertion" or "require condition"
	Condition string // the condition, rendered
}

ViolationError reports a condition that evaluated to false, naming the condition so a verdict says which one failed. It unwraps to ErrViolated, since it is a verdict about the model rather than a failure to evaluate.

func (*ViolationError) Error

func (e *ViolationError) Error() string

func (*ViolationError) Unwrap

func (e *ViolationError) Unwrap() error

Jump to

Keyboard shortcuts

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