https://github.com/drsensor/scdlang
One challenge when initiating a project is how to maintain the complexity. To make refactoring easy in the near futures, starting from this version, my strategy for each update is to introduce:
However, as it have more features, update in minor version (major.minor.patch) might only have one new syntax which implemented across several transpiler/code-generator/compiler.
In this update, I'm going to introduce new syntax symbols which desugar into several expressions. This concept was inspired from basic concept of multiplication. For example given this expressions:
2 ✕ 3
will desugar into:
3 + 3
3 + 3
Notice that by introducing only new symbol ✕, it can expand into multiple expressions. If we apply this concept into Scdlang then this is what we get:
A {SHORTCUT_SYMBOL} B @ C
will desugar into:
A {SYMBOL} B {@ C}?
A {SYMBOL} B {@ C}?
@ C can exists in one or both of the expressions. Some new shortcut syntax that introduced in this update are:
A <-> B @ Toggle
👆 will desugar into 👇
A -> B @ Toggle
A <- B @ Toggle
if we visualize that
Toggle
┌───────────────┐
▼ │
┌───┐ Toggle ┌───┐
│ A │ ────────▶ │ B │
└───┘ └───┘
A ->> B @ Loop
// or
B <<- A @ Loop
👆 will desugar into 👇
A -> B @ Loop
B -> B @ Loop
if we visualize that
Loop
┌──────┐
▼ │
┌───┐ Loop ┌──────────┐
│ A │ ──────▶ │ B │
└───┘ └──────────┘
A >-> B @ Loop
// or
B <-< A @ Loop
👆 will desugar into 👇
A -> B
B -> B @ Loop
if we visualize that
Loop
┌──────┐
▼ │
┌───┐ ┌──────────┐
│ A │ ──▶ │ B │
└───┘ └──────────┘
Not exactly desugar into multiple expressions but this new syntax can give a clear distinction between normal transition and self transition.
->> B @ Loop
👆 is same as 👇
B -> B @ Loop
// or
B <- B @ Loop
if we visualize that
Loop
┌──────┐
▼ │
┌──────────┐
│ B │
└──────────┘
State Machine Cat is a drawing language specialize for visualize statecharts. For me it's more like Graphviz but without hasle (decide tail/head of the edge, etc). It also has a CLI (smcat) and AST representation in JSON. Thankfully, it got the JSON schema of the AST which I can generate the Rust serde representation using quicktype then tweak it a bit. In this update, I only implement scdlang to smcat ast-json transpiler instead of the language itself because the CLI also accept JSON. I even create a PR because I find some bugs when piping JSON representation from stdin to the CLI.
Ah yes, it can visualize the error too 🙂
Now you can install Scdlang CLI via Cargo:
cargo install s-crap
$ scrap code --help
Generate from scdlang file declaration to another format
USAGE:
scrap code [FLAGS] [OPTIONS] <FILE> --format <target>
FLAGS:
-h, --help Prints help information
--stream Parse the file line by line
OPTIONS:
-o, --output <DIST> Output the result to this directory / file
--as <format> Select parser output [possible values: json, svg, dot, smcat, html, scxml, xmi, ascii, boxart, txt, bmp, gif, jpg, pdf, png, ps, ps2, tif, eps, fig, gd, gd2, jpeg, jpe,
json0, dot_json, xdot_json, pic, plain, plain-ext, svgz, tiff, tk, vml, vmlz, vrml, wbmp]
-f, --format <target> Select output format [possible values: xstate, smcat, graph]
ARGS:
<FILE> File to print / concatenate
$ scrap repl --help
Evaluate scdlang expression in interactive manner
USAGE:
scrap eval [FLAGS] [OPTIONS] --format <target>
FLAGS:
-h, --help
Prints help information
-i, --interactive
Prints result on each expression
--strict
Exit immediately if an error occurred
OPTIONS:
-o, --output <DIST>
The output depend if it's directory or file:
If directory => It will output a numbered file in sequence everytime the REPL produce output.
Useful if the input is from stdin.
If file => It will be overwriten everytime the REPL produce output, especially if `--interactive` is set.
Useful if combined with live preview
--as <format>
Select parser output [possible values: json, svg, dot, smcat, html, scxml, xmi, ascii, boxart, txt, bmp, gif, jpg, pdf, png, ps, ps2, tif, eps, fig, gd, gd2, jpeg, jpe, json0, dot_json,
xdot_json, pic, plain, plain-ext, svgz, tiff, tk, vml, vmlz, vrml, wbmp]
-f, --format <target>
Select output format [possible values: xstate, smcat, graph]
For more info, see scrap usage
code, positional argument [DIST] changes to -o, --output (cause by a bug in clap, probably 🤔)code and repl, flag --format <target> must be specified (to avoid favoritism)This features will prevent you to use invalid arguments which thanks to the awesome and flexible API that clap has! (it deserve a claps 👏, pun intended)
--output <DIST> will give an error messages that it must be specified if outputting --as <format> binary file (e.g --as jpg)--as <format> will give an error messages if paired with wrong --format <target> (e.g --format smcat --as boxart)--as <format> will be hidden and disabled if certain others CLI not being installedIn this update, scrap able to support others formats only if this CLI has been installed.
This brings several ability if combined with certain tools, for example:
print command in non-interactive mode of REPLcode, use special error handle when positional argument <FILE> is a directoryrepl -i piped from stdinline-number: expression when piped to stdout/stderrsmcat, graph-easy, and dot on each docker release 🐳version.py compatible with cargo publishSeems like there is performance boost since Rust 1.36 was released. Probably the performance boost is caused by switching
HashMap<K, V>implementation withhashbrown🤔
Summary, in this update I feel satisfied because not only I can make State Machine of D Flip-flop in 2 lines, it also give me visualization both in terminal and as an image. Hope I can also visualize them as a transition table and timing diagram too. Now, next update will be generating typescript declaration for XState 😎.