This is an aggressively simple Tcl-like language optimized for binary size, code complexity, and performance, in that order. That is, it's mostly intended to be small, but with readable code and ok performance.
wartcl has been used on a Cortex-M0 for basic boundary scan and
manufacturing test scripting. In that application it required 10 kiB of
flash and 8 kiB of RAM.
Putting this in your application
wartcl is designed to be very easy to embed in a larger application,
including exposing custom commands. Here's a toy example:
let mut tcl = default;
tcl.register;
match tcl.eval
The wartcl language
The language implemented by wartcl is intended to be very close to Tcl,
but smaller. Most (all?) wartcl programs should be valid Tcl programs, but
not vice versa.
wartcl supports the following Tcl-like commands by default. Some are
controlled by a Cargo feature in case you want to disable them.
breakcontinue+,-,*,/(featurearithmetic)>,>=,<,<=,==,!=(featurecomparison)ifincr(featureincr)proc(featureproc)puts(featurestd)returnsetsubstwhile
Probably the biggest difference is that the expr command, which does
math-style expression parsing, is not included. You can still do math, but
in prefix notation; instead of expr 2*(3+4), you must write * 2 [+ 3 4].
This isn't ideal, but expression parsing is big and wartcl is small.
Implementation design and theory of operation
The Tcl language is an extended meditation on the idea "everything is a string." All of Tcl's data types are --- notionally, at least --- represented as strings, and they can be converted from one to the other by parsing. Modern Tcl implementations provide this illusion while using more efficient representations under the hood.
wartcl takes it literally. Everything is a string, a heap-allocated
sequence of human-readable bytes, encoded in either ASCII (if you leave the
top bit of each byte clear) or UTF-8 (if you don't). wartcl doesn't
actually care about character encoding.
This keeps the implementation very simple but has significant performance
costs. Want to add two numbers? Well, you'll have to parse two numeric
strings, add the result, and then re-format the result into another
(heap-allocated) numeric string. (This is not the fastest way to use a
computer, but wartcl is not really designed for arithmetic-heavy
applications.)
Basically every value, from the program's source code on up, is represented
as a Box<[u8]>. This is an owned pointer to a slice of bytes. Cloning it
implies a full copy of its contents; dropping it deallocates the contents.
The advantages of Box<[u8]> over Vec<u8> are:
Vecmay retain extra memory for expansion, which we don't generally need because values are immutable once constructed.Vecis one word larger, making it correspondingly more expensive to store and pass around.
To clarify intent, in the implementation, [u8] is given the type alias
Value.
About the name
wartcl stands for "wartcl Ain't Really Tcl" because the language differs
from standard Tcl in a whole bunch of ways.
It's also a pun on the C partcl library's name, after the "warticle" term
humorously used to describe phenomena exhibiting wave/partical duality in
quantum physics.