Skip to content

Releases: frame-lang/frame_transpiler

Frame v0.10.0

31 Aug 09:05

Choose a tag to compare

Frame v0.10.0 brings a lot of exciting additions to the Frame language, adding both power and standardization to the notation. In addition, the transpiler now can read from stdin as well as still accepting file paths as in the past. This enables improved CI/CD processes involving Frame.

New Language Features

Note: The new language features are now supported in Golang, Javascript, Python3. Other languages will be supported in coming releases.

  • Compartments - v0.10 formalizes the idea of state closures called Compartments. Compartments are data structures that hold a state's local data as well as other metadata enabling new advanced features like Event Forwarding (see below).
  • Deferred transitions - deferred transitions address challenges with the previous approach of executing a transition immediately when called. Each immediate transition makes a function call and under certain situations, can blow up the stack if too many occur before returning to the caller. Deferred transitions avoid this situation and enable Frame controllers to make any number of sequential transitions. This architecture change enables Frame controllers to be launched as background daemons that run indefinitely until stopped as well as to be used to solve iterative problems.
  • System parameters - system parameters enable initializing the system in a more standardized, flexible and direct manner. This includes syntax for setting the start state parameters, the start state's enter parameters as well as override domain variable initialization. This change normalizes the start state to behave like all other states in the machine.
  • Event forwarding - event forwarding syntax enables passing events from one state to another. This capability enables system designers to easily receive events in one state and forward them on to other states that can handle them appropriately.
  • Persistance - A new system attribute enables code generation for Marshaling and Unmarshaling system data as JSON.

Stdin support

The CLI has been updated to support stdin:

framec -language rust < HelloWorld.frm > HelloWorld.rs

or

cat HellowWorld.frm | framec -language golang > HellowWorld.go

Frame v0.9.0

09 Apr 04:36

Choose a tag to compare

Frame v0.9.0 brings a lot of exciting additions to the Frame language, adding both power and standardization to the notation. In addition, the transpiler now can read from stdin as well as still accepting file paths as in the past. This enables improved CI/CD processes involving Frame.

New Language Features

Note: The new language features are currently only supported in Golang. Other languages will be supported in coming releases.

  • Compartments - v0.9 formalizes the idea of state closures called Compartments. Compartments are data structures that hold a state's local data as well as other metadata enabling new advanced features like Event Forwarding (see below).
  • Deferred transitions - deferred transitions address challenges with the previous approach of executing a transition immediately when called. Each immediate transition makes a function call and under certain situations, can blow up the stack if too many occur before returning to the caller. Deferred transitions avoid this situation and enable Frame controllers to make any number of sequential transitions. This architecture change enables Frame controllers to be launched as background daemons that run indefinitely until stopped as well as to be used to solve iterative problems.
  • System parameters - system parameters enable initializing the system in a more standardized, flexible and direct manner. This includes syntax for setting the start state parameters, the start state's enter parameters as well as override domain variable initialization. This change normalizes the start state to behave like all other states in the machine.
  • Event forwarding - event forwarding syntax enables passing events from one state to another. This capability enables system designers to easily receive events in one state and forward them on to other states that can handle them appropriately.
  • Persistance - A new system attribute enables code generation for Marshaling and Unmarshaling system data as JSON.

Stdin support

The CLI has been updated to support stdin:

framec -language rust < HelloWorld.frm > HelloWorld.rs

or

cat HellowWorld.frm | framec -language golang > HellowWorld.go

Frame v0.8.0

23 Feb 21:17

Choose a tag to compare

This release adds a new crate frame_build that provides a configurable build process for compiling Frame source files as part of building a larger Rust package.

See the crate's documentation for instructions on how to use it and for some brief notes on how best to integrate Frame and Rust.

Frame v0.7.5

09 Feb 19:15

Choose a tag to compare

This release makes information about the Frame specification file that was used to generate a state machine available via the runtime system for the Rust backend. Specifically, it adds the path to the .frm file passed to Framec, as well as a SHA-256 hash of that file, which can be used to verify that a state machine was generated by the expected version of the specification.

Frame v0.7.4

07 Feb 02:12
cbecbac

Choose a tag to compare

This release adds golang as the latest Frame language target.

Full Changelog: v0.7.3...v0.7.4

Frame v0.7.3

05 Jan 21:51

Choose a tag to compare

This release refactors the runtime interface to reduce its impact on the types of generated code, and to make it easier to program against in a generic way. In particular:

  • The interface is no longer split into sync/unsync variants corresponding to whether the thread_safe feature is enabled or not. The traits instead contain associated types and type bounds that enable them to work with both variations of the generated code.

  • The runtime interface no longer requires a lifetime annotation on the machine type.

The new trait bounds on the Machine type must often be propagated to use sites. Additionally callbacks must now own all their references, and the type annotations required on callback arguments have gotten a bit more complicated. See the frame_runtime documentation for details on these issues.

Frame v0.7.2

08 Dec 23:43

Choose a tag to compare

This release adds a new feature to the Rust backend: codegen.rust.features.thread_safe.

Generating Send- and Sync-compatible state machines

When the new thread_safe feature is enabled, Framec will generate a state machine that implements Rust's standard Send and Sync traits, as long as all of declared domain variables also implement these traits.

The feature is disabled by default.

Impact on the runtime interface

By far the biggest impact of the new thread_safe feature is on the runtime interface (see the Release Notes for v0.7.0 and v0.7.1), which has been split into two variants:

  • frame_runtime::sync, which is implemented by machines compiled with runtime_support=true and thread_safe=true

  • frame_runtime::unsync, which is implemented by machines compiled with runtime_support=true and thread_safe=false

Note that the treatment of environments in the sync runtime interface is less efficient than in the unsync variant, and the sync variant also requires that all domain variables implement Clone. These issues/limitations may be resolved in the future.

Frame v0.7.1

23 Nov 18:52
4f0fabe

Choose a tag to compare

This release adds a bunch of new functionality to the Rust runtime interface. As before, runtime support can be enabled by configuring Framec with codegen.rust.features.runtime_support=true.

Live rendering of state machines to smcat

Framec already supported rendering state machines can now be rendered to smcat. However, now this can be done for live state machines via the runtime interface. The advantage of doing this at runtime is that we can modify the visualization to reflect things like the currently active state and the last transition.

The rendering interface includes a lot of configurability in the styling of generated smcat visualizations. Two built-in styles are provided: a SimpleStyle that embeds simple styling info directly in the smcat file (e.g. highlighting the active state by thick red lines), and a CssStyle that generates an smcat file where each element is annotated by CSS classes that can be styled in a separate CSS file.

For more details, see the code and documentation at frame_runtime::smcat.

New callback interface for events

Frame events include interface method calls and state enter/exit events--basically, anything that can be handled in Frame by defining a corresponding handler associated with a state.

You can now register callbacks to be notified of Frame events. Callbacks can be registered via two methods, both associated with the EventMonitor obtainable via the runtime interface from a state machine instance:

  • add_event_sent_callback -- Adds a callback that will be invoked whenever an event is sent.
  • add_event_handled_callback -- Adds a callback that will be invoked whenever an event has been completely handled.

The sent callbacks will be invoked for events in the more intuitive order. For example, if calling method m triggers a transition from state A to state B, then the callbacks will be invoked for events "m" (the method call), "A:<" (old state exit event), and "B:>" (new state enter event), in that order. However, because the handler for m will not have terminated yet until the transition is complete, the event "m" received by the callback will not yet contain the return value of m (since it hasn't been computed yet).

The handled callbacks will be invoked when the handlers for each event have completed. So, for the scenario above, the callbacks will be invoked in the order "A:<", "B:>", "m", since the handler for m doesn't terminate until after the transition. However, in this case, the event "m" received by the callback will contain the return value.

In all cases, the events received by the callback are references wrapped in Rc<..>, so they can be freely saved. The return value for an event received via a sent callback will be updated when the handler terminates, so if this event is saved, it's return value will be accessible later.

Most clients will probably want to be notified of events in the more intuitive order provided by add_event_sent_callback. However, add_event_handled_callback is provided in case the return value is needed at the time the callback is invoked.

Configurable event and transition history

The runtime interface (again via the EventMonitor) now maintains a history of recent events and transitions. The histories can be obtained via get_event_history and get_transition_history.

The length of history maintained can be configured via set_event_history_capacity and set_transition_history_capacity, which take values of type Option<usize>. A None value indicates an unbounded history, while Some(n) indicates a history bounded to size n. The history feature can be disabled by setting the capacity to Some(0).

By default, the history capacities are set to Some(0) (disabled) for the event history and Some(1) (maintain the last transition only) for the transition history. This minimizes memory impact if these features are not needed.

The default values can be configured via the new Framec configuration options codegen.rust.runtime.event_history_capacity and codegen.rust.runtime.transition_history_capacity, configurable via YAML or the attribute system, as usual. As with the built-in defaults, these can be overridden at runtime using the set_ methods listed above.

Events in the event history are listed in the order the events were sent. The history stores Rc<..> references to each event, which will be updated as the event is handled. In particular, the return value of an event (if any) will be set once the event has been fully handled.

Smaller changes

The runtime interface now provides the following additional features:

  • A method to get the initial state from a state machine.
  • A method to get all top-level states from a machine.
  • A unique ID is associated with each transition to enable disambiguating between multiple transitions between the same two states.
  • A convenience method to get the last transition from the transition history.

Frame v0.7.0

01 Nov 21:33
fe481c3

Choose a tag to compare

This release includes two major new features and several small improvements and bug fixes.

Runtime system for Rust

The biggest new feature of this release is an optional Frame runtime system for Rust. The runtime system can be used by doing the following:

  1. Compile your Frame spec to Rust with the runtime_support feature enabled.
  2. Include the new frame_runtime crate in your project that uses the generated state machine.

The runtime system provides comprehensive introspection of state machines generated by Frame, and some simple monitoring capabilities that will likely be expanded in the future. More specifically:

  • For any state machine generated by Frame:
    • Enumerate its states, domain variables, events, actions, and edges (potential transitions).
    • Get hierarchy information for states within a machine.
    • For each state: enumerate its parameters and variables, the handlers it defines, and its incoming and outgoing edges.
    • For each edge within the machine: get its kind (transition/change-state), source, target, triggering event, and label.
  • For a currently running state machine:
    • Get the current values of all domain variables.
    • Get the currently active state and the values of its parameters and variables.
    • Register callbacks to be notified of any transitions that occur.
    • For transition notifications, get access to the values of enter/exit arguments.

New configuration system

Frame's configuration system has been overhauled to make it simpler and more flexible to use going forward.

Frame can still be configured using a config.yaml file in the current working directory, but this file is no longer mandatory and no longer needs to contain a complete set of configuration values. Instead, the file may contain only the values the user chooses to override.

A default config.yaml file can be generated by running:

framec --generate-config

This file will contain a complete set of configuration options initialized to the default values.

Additionally, Frame can now be configured through attributes embedded directly in Frame specifications. These attributes use the syntax #[path.to.config.option:type="value"] where path.to.config.option is the full path of the configuration option in config.yaml; type is one of bool, int, or str depending on the type of the configuration option; and value is the value to set it to.

For example, to enable the new runtime_support feature for a particular state machine, one could either set the following option in config.yaml:

codegen:
  rust:
    features:
      runtime_support: true

Or include the following attribute setting at the top of the corresponding .frm file:

#[codegen.rust.features.runtime_support:bool="true"]

An advantage of the attribute interface is that it enables configuring two different state machines in the same project differently.

Other fixes and improvements

  • (Feature) Added configurable style attributes to the output generated by the smcat backend.
  • (Bug fix) Can now directly invoke event handlers from within Frame, even in state machines that require a state context. Note that for now, direct handler invocations must occur as the last step in the calling handler. This constraint may be lifted in the future.
  • (Bug fix) State stacks now push a snapshot of the current state context rather than a reference. This means that changes after a state is pushed will not be reflected when that state is restored later by a pop.
  • (Code cleanup) Fixed or suppressed all outstanding cargo clippy warnings and added clippy to Github Actions to be applied on every push.
  • (Code cleanup) Simplified the visitor interface a bit, enabling the removal of over 3000 lines of code!
  • Lots of new tests!

Frame v0.6.0

30 Sep 17:51
7e0a062

Choose a tag to compare

This release includes a lot of work on the Rust back-end:

  • New feature: the current state of the machine is stored as a value of a simple enum type, which can be accessed to determine the state of a running machine.

  • New feature: a new follow_rust_naming feature option has been added and enabled by default. This option significantly improves the conformance of generated code with Rust naming conventions and style guidelines.

  • New feature: a new generate_hook_methods feature option has been added that generates methods that are invoked on each transition or change-state. The names of these methods can be configured via config.yaml.

  • Completed feature: hierarchical state machines. This enables defining states as children of other states. Event handlers on child states may defer to the corresponding handler on a parent state by terminating the child handler with the "continue" terminator :>. The parent handler will be immediately invoked after a child handler that terminates in :>, if the child handler does not otherwise transition or return.

  • Completed feature: change-state transitions. Change-states (->>) are transitions that do not trigger the usual exit/enter events. Previously, this feature only worked for simple states (states without variables, parameters, or enter event arguments). Now it works in all expected scenarios.

  • Completed feature: state stacks/history. This feature enables pushing states (with corresponding state variables and arguments) to a stack. These states can later be returned to by a "pop transition" using the syntax -> $$[-]. This pops a state from the stack and restores the machine to that state.

  • Refactors and simplifies the generated code, particularly the representation of states and the initialization of state contexts.

  • More names in the generated code are now customizable via the config.yaml interface.

  • Significantly improved test coverage and corresponding bug fixes:

    • Initial states are now initialized correctly and may contain state variables and enter parameters.
    • Transitions inside of match or conditional statements now terminate the execution of a handler.
    • Negated conditional statements (?!) now work as expected.
    • ... and many more!