Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/unreleased/positional-invoke-arguments.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **An operation is invoked with a positional argument list.** `Context.InvokeOperationWith` takes `OperationArguments`, positional or named, and `%invoke <object> <op>` accepts bare expressions (`%invoke rover drive 10 20`) beside its `<parameter>=<expression>` pairs. Positionals bind the operation's `in`/`inout` parameters in signature order, a trailing defaulted parameter may be omitted, and among same-named operations the one the arguments fit is selected as an invocation expression would. A list mixing the two forms is refused (`ErrMixedArguments`), as is a surplus argument (`ErrOperationArity`).
52 changes: 37 additions & 15 deletions docs/project/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -1396,9 +1396,30 @@ No IR change; proof fixtures written in the record; two routing points to settle
**Prioritize when** a model relies on an exhibited machine to refuse an arrival, or on a port
definition's machine at all.

## E6 — operation invocation with positional arguments

**Today.** `Context.InvokeOperation(inst, name, args map[string]Value)`
## E6 — operation invocation with positional arguments (landed)

**Landed.** `Context.InvokeOperationWith(inst, name, OperationArguments{Positional, Named})`
(`runtime/invoke_operation.go`) takes the ordered list; `InvokeOperation` keeps the named map and
delegates to it. A positional list binds to the operation's effective input parameters —
`semantics.Model.SignatureParametersOf`, the `in`/`inout` parameters `signatureOf` gives an
invocation expression in signature order, `out` and result excluded — so a trailing defaulted
parameter may be omitted, an `inout` parameter takes a position and comes back as a result, and an
`out` parameter takes none. Among same-named members, `operationOf` selects through
`semantics.Model.SelectAmongArguments`, the overload selection the expression evaluator uses, in
its `PerformsOperation` mode — every behavior admitted alike, an expression's preference for a
calc set aside — so two calcs of one name are told apart by arity, an action and a calc of one
name by the arguments' types, and a list none takes is refused. A surplus is
`ErrOperationArity` (`operation … takes N input parameter(s), got M argument(s)`), a list mixing
the two forms is `ErrMixedArguments`, and a required parameter left unbound is still
`ErrUnboundParameter`. The REPL's `%invoke <object> <op>` takes bare expressions or `<p>=<expr>`
pairs (`repl/meta.go` `parseInvokeArguments`), refusing a mixed list and a parameter named twice
before the object is reached. Proof: `runtime/classifier_behavior_test.go`
`TestInvokeOperationWithPositionalArguments`, `runtime/robustness_positional_invoke_test.go`,
`repl/classifier_behavior_test.go` `TestInvokeBindsPositionalArguments` and
`TestInvokeReportsItsFailureModes`; the bullet left the compliance list. The gRPC surface exposes
no operation invocation, so nothing there changed.

**Before it landed.** `Context.InvokeOperation(inst, name, args map[string]Value)`
(`runtime/invoke_operation.go`) runs a member of an object's type with the object as performer,
whichever behavior the member is — an action through `ExecuteActionPerformedBy`, a calc through
the calc invocation with the object as its featuring object, a constraint through condition
Expand Down Expand Up @@ -2987,9 +3008,11 @@ carried more than that list. By track, with the pull requests the tracks cite:
document's several views (#349) and opens on demand (#348), writes layout into the document
that declares the element across the workspace (#307), and reparents by drag (#305).
- **Track E** — E1 landed (`terminate` runs in every position, the PSSM `terminate-gap` bucket
retired); E9 and E10 landed as conformance findings; E8's refusal landed (#229), the item
itself is open; E3 closed by its design record ([expansion-regions.md](expansion-regions.md):
the iterative form is `for`, the parallel form is not SysML v2), no executor work following.
retired); E6 landed (a positional argument list on `InvokeOperationWith` and `%invoke`, bound
to the effective signature an invocation expression binds to); E9 and E10 landed as conformance
findings; E8's refusal landed (#229), the item itself is open; E3 closed by its design record
([expansion-regions.md](expansion-regions.md): the iterative form is `for`, the parallel form
is not SysML v2), no executor work following.
- **Track D** — D12 (the standard library's normative element ids) is done.
- **Release follow-through** — R4's Windows installer is published by `v0.7.0` and `v0.8.0`
alike; the release procedure runs git-flow (#151); `opensysml` 0.5.0 is on PyPI; the
Expand All @@ -3001,9 +3024,9 @@ The open items, by track, with the item that gates each where one does. Everythi
is landed or is a track the previous baseline left as it stands (D, N, M, I, V, B, R2–R5);
Tracks F, S, L and A are closed.

- **Track E** — eligible and first: E2, then E4 (E1 landed), then E6 on request, E3 closed by
its design record, E5 closed by its record (an optional follow-up waits on a model that needs
it), E7 behind its object-model item, E8 behind a model that needs it. The
- **Track E** — eligible and first: E2, then E4 (E1 and E6 landed), E3 closed by its design
record, E5 closed by its record (an optional follow-up waits on a model that needs it), E7
behind its object-model item, E8 behind a model that needs it. The
PSSM referee's 17 `fail` tests are the state side's measurement, every one attributed (#326):
eleven wait on the region-order choice point whose design record #342 wrote and left at two
maintainer decisions — the nine the record names to move `fail` → `pass`, plus *Terminate 001*
Expand Down Expand Up @@ -3116,12 +3139,11 @@ an empty action end its performance. The decision is the release checklist's, re
- **Track S.** Landed in the order agreed: S1 (#110), S2 (#123), S3 (#125), S4 (#134); #141 added
the region-order choice point afterwards. Nothing remains in the track.
- **Track E.** Eligible — step 1 above. **E1** (termination of an ongoing performance, which
**E2** and **E4** build on) is landed; the order is **E2**, then **E4**; **E6** whenever asked,
being a day's work; **E3**'s record is landed and closes the item; **E5**'s record is landed and
closes the item, its optional follow-up waiting on a model that needs it; **E7** after the
object-model item it depends on; **E8** when a model redefines run-to-completion, its refusal
(#229) standing until then; **E1**, **E9** and **E10** are landed; **E3** is closed by its
record, no work following.
**E2** and **E4** build on) is landed; the order is **E2**, then **E4**; **E6** is landed;
**E3**'s record is landed and closes the item; **E5**'s record is landed and closes the item,
its optional follow-up waiting on a model that needs it; **E7** after the object-model item it
depends on; **E8** when a model redefines run-to-completion, its refusal (#229) standing until
then; **E1**, **E9** and **E10** are landed; no work follows E3.
- **Track X.** X2, X3, X4, X5, X6, X7's values and X8's typing landed (#164, #115, #113, #211,
#122, #121, #112). What is left, in order: X8's harness halves (normalization and adjudication
in the pilot differential, a standalone RDF expression-tree round trip) so every later X item is
Expand Down
5 changes: 2 additions & 3 deletions docs/project/spec-compliance.md
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,7 @@ checked after the result is bound is not a form the runtime offers, and none is
| An object's parameter space is its own: an action's `out` parameter answers the caller even where the performing object declares a feature of that name | `runtime/action_statements.go` `assignOuter`; `runtime/action_executor.go` `declaresParameter` | `runtime/classifier_behavior_test.go:TestOperationOutputNamedLikeAFeatureAnswersTheCaller` | ✅ Faithful |
| A failed materialization leaves no behavior of the object attached or queued, and an edited model drops an object whose behavior body changed rather than resuming it on the values the old body wrote | `runtime/classifier_behavior.go` `startClassifierBehaviors`/`forgetBehaviorsFrom`; `runtime/adopt.go` `writeBoundBehaviors` | `runtime/classifier_behavior_test.go:TestFailedMaterializationLeavesNoBehaviorBehind`, `repl/classifier_behavior_test.go:TestRewritingTheExhibitedMachineDropsTheObject`, `:TestObjectMachineSurvivesAnUnrelatedDeclaration` | ⚠️ Approximate (tool-defined: the spec describes one fixed model, so what a live execution does when the model is edited is a REPL policy) |
| A second materialization of one name is a second object, with its own identity and its own behaviors; `occurrenceOf` remains the reuse path for a named occurrence | `runtime/instance.go` `instantiateOwnedBy`; `repl/query.go` `instantiateNamed` (which object the name now denotes) | `robustness_test.go:second_instantiation_of_one_type`, `repl/classifier_behavior_test.go:TestSecondInstantiateIsAnotherObject` | ⚠️ Approximate (tool-defined; the spec leaves object creation semantics open) |
| Invoking an operation of an object's type runs it with that object as performer, whichever behavior the member is — an action, a calc or a constraint — binding named arguments as the call machinery binds them | `runtime/invoke_operation.go` `InvokeOperation` (`operationOf` settles which behavior the member is; an action runs through `ExecuteActionPerformedBy`, a calc through the existing calc invocation with the object as its featuring object, a constraint through the existing condition evaluation against the object); `runtime/eval.go` `evalInvocation` preserves that performer for nested calc invocation expressions; `repl/meta.go` `%invoke` | `runtime/classifier_behavior_test.go:TestInvokeOperationPerformedByTheObject`, `:TestCalcInvocationExpressionSeesPerformingObject` (an action, direct and nested calcs reading a mutated feature, an anonymous result, and a constraint), `:TestInvokeOperationFailureModes`, `robustness_test.go:operation_invoked_with_unbound_parameters`, `:operation_constraint_body_cannot_be_evaluated`, `repl/classifier_behavior_test.go:TestInvokeRunsAnOperationOnTheObject`, `:TestInvokeReportsItsFailureModes` | ✅ Faithful, **self-assessed** (the pinned reference cannot invoke an operation on an object, so nothing external adjudicates this). A calc's value comes back under its result parameter's name, or `result` where the result is anonymous, and a constraint's verdict comes back under `result` — a `false` verdict is an answer, not `ErrViolated`, since the invocation asked for the value. A body that cannot be evaluated is still an error. A state member is refused with `ErrUnsupportedClassifierBehavior`; its exhibited state machine runs during materialization instead. A member that is no behavior at all is `ErrNotABehavior`. Arguments bind by name because no invocation surface expresses positional operation arguments — an operation *call written in a model* is an InvocationExpression and is bound by the expression machinery, not here |
| Invoking an operation of an object's type runs it with that object as performer, whichever behavior the member is — an action, a calc or a constraint — binding named arguments as the call machinery binds them, or a positional list to the effective input parameters in signature order (KerML §8.2.5.8.3: an `ArgumentList` is positional or named, never a mix; §8.4.4.9.5: a positional list binds parameters in declaration order) | `runtime/invoke_operation.go` `InvokeOperation` (named) and `InvokeOperationWith` (`OperationArguments`, positional or named; `operationOf` settles which behavior the member is and, among same-named members, selects one through `semantics.Model.SelectAmongArguments` in its `PerformsOperation` mode — the overload selection an invocation expression uses, without the expression's preference for a calc, so an action and a calc of one name are told apart by the arguments' types; `operationInputs` binds a positional list to `semantics.Model.SignatureParametersOf` — `signatureOf`'s `in`/`inout` parameters in signature order, `out` and result excluded — refusing a surplus with `ErrOperationArity` and a mixed list with `ErrMixedArguments`; an action runs through `ExecuteActionPerformedBy`, a calc through the existing calc invocation with the object as its featuring object, a constraint through the existing condition evaluation against the object); `runtime/eval.go` `evalInvocation` preserves that performer for nested calc invocation expressions; `repl/meta.go` `%invoke` (`parseInvokeArguments`: bare expressions or `<p>=<expr>` pairs, a mixed list and a parameter named twice refused before the object is reached) | `runtime/classifier_behavior_test.go:TestInvokeOperationPerformedByTheObject`, `:TestInvokeOperationWithPositionalArguments` (a defaulted trailing parameter omitted, an `inout` read and written, an `out` taking no position, two same-named calcs told apart by arity, a same-named action and calc by argument type, fewer, surplus and mixed lists), `robustness_positional_invoke_test.go:TestRuntimeRobustnessPositionalInvoke`, `repl/classifier_behavior_test.go:TestInvokeBindsPositionalArguments`, `:TestCalcInvocationExpressionSeesPerformingObject` (an action, direct and nested calcs reading a mutated feature, an anonymous result, and a constraint), `:TestInvokeOperationFailureModes`, `robustness_test.go:operation_invoked_with_unbound_parameters`, `:operation_constraint_body_cannot_be_evaluated`, `repl/classifier_behavior_test.go:TestInvokeRunsAnOperationOnTheObject`, `:TestInvokeReportsItsFailureModes` | ✅ Faithful, **self-assessed** (the pinned reference cannot invoke an operation on an object, so nothing external adjudicates this). A calc's value comes back under its result parameter's name, or `result` where the result is anonymous, and a constraint's verdict comes back under `result` — a `false` verdict is an answer, not `ErrViolated`, since the invocation asked for the value. A body that cannot be evaluated is still an error. A state member is refused with `ErrUnsupportedClassifierBehavior`; its exhibited state machine runs during materialization instead. A member that is no behavior at all is `ErrNotABehavior`. Arguments bind by name or by position on the Go API and the REPL alike; the gRPC surface exposes no operation invocation. A positional list is bound to the same effective signature an invocation expression is bound to, so the two surfaces cannot drift |
| An object typed by a behavior — a performance occurrence, the `action def` a v1 activity becomes when a part performs it — runs no classifier behaviors of its own: its `perform`/`exhibit` members are steps of the performance that runs it, not behaviors bound to the occurrence, so a body's `action call : Sub;` runs once as a step and `this` in it is the performer; a reference that is no action is `ErrNotABehavior` | `runtime/classifier_behavior.go` `classifierBehaviorsOf` (a behavior type binds none); `runtime/signal.go` `isBehaviorType`; `runtime/invoke_action.go` `actionCandidates` (`ErrNotABehavior`) | conformance `performed_action_def_perform_members_are_steps` + `.expected.json`; `migrate/opaque_migration_test.go:TestSwimlaneBodiesAndGuardsRunAgainstTheRepresentedPart` (a migrated workflow whose action body performs a sub-activity through its performer) | ✅ Faithful, **self-assessed** (KerML §8.4.4.3: `performances` are bound to the objects of a `Class` that is not itself a `Behavior`; a `Behavior`'s steps are its own `subperformances`) |
| A `perform action x ::> part.action;` usage (an action usage referencing a feature chain) performs the chain's last action with the object the chain reaches as its performer, so `this` in the performed body is that object — `tel.point` moves the telescope, not the station; an action usage referencing or typed by a qualified name still runs on the caller's own performer. The chain is evaluated in the caller's context when the node fires: a chain holding no object is `ErrPerformerNotObject`, one holding several objects is refused, one whose last segment is not an action is `ErrPerformerNotObject` too, and one reaching an object that was destroyed is `ErrOccurrenceDestroyed` naming when it was destroyed | `parser/defusage.go` (a `::>` reference to a feature chain on an action usage); `lower/action_graph.go` `performsAction` (`RelReferences` to a `FeatureChainExpr`); `runtime/invoke_action.go` `actionInvocation` (target or chain), `performerOf` (the chain evaluated over the caller's `self`, resolved to an instance through `Context.Instance`), `beginCallee`; `runtime/action_executor.go` `stepNestedAction` | `parse/perform_action_on_part.golden`; conformance `perform_action_on_part` + trace golden; `robustness_perform_on_part_test.go:performer_holds_no_object`, `:performer_holds_several_objects`, `:chain_ends_in_no_action` (`ErrPerformerNotObject`), `:performer_was_destroyed` (`ErrOccurrenceDestroyed`); `migrate/behavior_test.go:TestActivityMigratesToAnExecutableActionDef` (a migrated v1 `CallOperationAction` on a target pin runs through this form) | ✅ Faithful, **self-assessed** (SysML v2 §7.16: an action usage that references another performs it as a `subperformance` of the referenced feature's featuring occurrence; the pinned reference cannot execute one) |
| A typed usage that also references a feature chain, `perform action spin : Motor::Spin ::> drive.motor.spin { in rpm = 30.0; }`, performs the chain's last action on the object the chain reaches, as the untyped form does, and its body binds the callee's `in` parameters by name: the reference names both the action and its performer, so it settles what is performed where the typing only restates the action's definition; an unqualified name the body reads that no argument binds is read from the caller's scope when the callee is performed. A chain holding no object or ending in no action is refused with `ErrPerformerNotObject` | `parser/defusage.go` (a typing followed by a `::>` reference to a feature chain); `runtime/invoke_action.go` `nestedInvocation` (the reference subsetting wins over the typing), `referencedInvocation`; `runtime/action_frame.go` (invocation inputs bound from the body's `in p = …` arguments, then from the enclosing scope for an unqualified callee) | `parse/perform_typed_subsetting.golden`; conformance `perform_typed_action_on_nested_part`, `accept_payload_bound_into_typed_action` + trace goldens; `robustness_perform_typed_on_part_test.go:reference_names_the_performer`, `:performer_holds_no_object`, `:chain_ends_in_no_action`; `migrate/interaction_test.go`, `migrate/call_port_test.go`, `migrate/reception_test.go` (a migrated v1 call message, a `CallOperationAction` routed over a port and a reception's method run through this form) | ✅ Faithful, **self-assessed** (SysML v2 §7.16: an action usage typed by a definition and referencing a feature performs the referenced feature; the pinned reference cannot execute one) |
Expand Down Expand Up @@ -2366,7 +2366,7 @@ are tracked here):

### Major Features Not Implemented (UML-referenced; no SysML v2 notation or KerML performance)

The behavior-execution entries below — interruptible regions, expansion regions, streaming pins, positional operation arguments, routing to a second object — each have a stated scope, dependency order and acceptance gate as [Track E of the roadmap](roadmap.md#track-e--behavior-execution); none is near-term.
The behavior-execution entries below — interruptible regions, expansion regions, streaming pins, routing to a second object — each have a stated scope, dependency order and acceptance gate as [Track E of the roadmap](roadmap.md#track-e--behavior-execution); none is near-term.

**Actions (Advanced):**
- Interruptible regions
Expand All @@ -2392,7 +2392,6 @@ The behavior-execution entries below — interruptible regions, expansion region

**Object Model:**
- Dynamic object creation/destruction (an object is materialized once, and nothing destroys it)
- Operation invocation with positional arguments (an operation with named arguments runs, whether it is an action, a `calc` or a `constraint` — see the Classifier Behaviors map)
- Routing to a second object of one usage (a `via` send follows the connections and an addressed send resolves an object, but the object reached is the one this context holds as its target's occurrence — see Known Limitations)

**Type System:**
Expand Down
Loading
Loading