v0.5.0 macro: expand macros in a parsed document, moved from vif's pkg/tomlmacro
Test / test (push) Waiting to run
Test / test (push) Waiting to run
A macro is a [macros.<Name>] table with typed params, defaults, a doc line and a body; any table with a "macro" key invokes one, as a value or spliced into an array, once per zipped element under "each". Expansion runs on the parsed tree between Parse and Decode, is bounded, and reads nothing but the documents it is given. The package is the expander vif's scenarios, bot graphs and audio banks already use, placed here so that a module outside vif, the audio engine's coming spin-off first, can share it. Claude-Session: https://claude.ai/code/session_01RP6NsvbSaLTt1UbBXHNfL4 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
e5d5567beb
commit
5f0e9f30a4
3 files changed
+914
-2
No files matched your search
@@ -1,7 +1,7 @@
|
||||
# toml
|
||||
|
||||
A deterministic TOML subset encoder, decoder and formatter using Go standard library.
|
||||
Requires Go 1.27.1.
|
||||
A deterministic TOML subset encoder, decoder and formatter using Go standard library,
|
||||
with a macro expander for parsed documents (`macro`, below). Requires Go 1.27.1.
|
||||
|
||||
```go
|
||||
type Settings struct {
|
||||
@@ -171,6 +171,66 @@ would not parse to the same values is refused.
|
||||
`Parse`, `Unmarshal` and `Decode` never format: they skip a comment without
|
||||
reading its text.
|
||||
|
||||
## Macros
|
||||
|
||||
```go
|
||||
import "github.com/lixenwraith/toml/macro"
|
||||
|
||||
doc, err := toml.NewParser(data).Parse()
|
||||
doc, err = macro.ExpandDocument(doc) // a document that defines its own macros
|
||||
err = toml.Decode(doc, &target)
|
||||
|
||||
set := macro.NewSet() // one set shared by several documents
|
||||
err = set.Define(library) // takes library's [macros]; a name defined twice is an error
|
||||
doc, err = set.Expand(doc) // doc defines none; its invocations use the set
|
||||
```
|
||||
|
||||
A macro is data in the document, expanded on the parsed tree between `Parse`
|
||||
and `Decode`, so nothing downstream of decoding sees anything but plain tables.
|
||||
A macro is a `[macros.<Name>]` table:
|
||||
|
||||
- `params`: parameter name to type: `int`, `float` (an integer is accepted),
|
||||
`bool`, `string`, `table`, `array` or `any`; `macro` and `each` are reserved.
|
||||
- `defaults`: values for optional parameters; every other parameter is required.
|
||||
- `doc`: one line for authors.
|
||||
- `body`: any value: a table, an array, a string or a number.
|
||||
|
||||
Inside a body, `${name}` names a parameter, in a string or in a key. A string
|
||||
that is exactly one reference becomes the argument itself, of any type;
|
||||
elsewhere the argument is spliced into the text and must be a string, an integer
|
||||
or a boolean. `$$` is a literal `$`; any other `$` in a body is an error. Only
|
||||
bodies are templates: an argument's own text is never scanned.
|
||||
|
||||
Any table with a `macro` key is an invocation; its other keys are arguments,
|
||||
checked against the parameters' types. As a value it is replaced by the
|
||||
expansion. As an array element, an array expansion is spliced into the array and
|
||||
any other is one element; with `each`, a table of parameter = array, all of one
|
||||
length, it expands once per zipped element. Bodies may invoke other macros and
|
||||
arguments may be invocations: arguments are expanded where they are written,
|
||||
then bound, then the body is substituted and expanded in turn.
|
||||
|
||||
```toml
|
||||
[macros.Note]
|
||||
doc = "One note: pos, deg, dur in steps, vel"
|
||||
params = { pos = "int", deg = "int", dur = "int", vel = "float" }
|
||||
defaults = { dur = 1, vel = 0.5 }
|
||||
body = { pos = "${pos}", deg = "${deg}", dur = "${dur}", vel = "${vel}" }
|
||||
|
||||
[[track]]
|
||||
instr = "lead"
|
||||
event = [{ macro = "Note", each = { pos = [0, 4, 8], deg = [0, 2, 4] } }]
|
||||
```
|
||||
|
||||
Definitions are checked when read: an unknown key, an unknown type, a default of
|
||||
the wrong type and a `${name}` naming no parameter are errors before any use.
|
||||
Expansion is a pure function of the documents given, so equal bytes expand to
|
||||
equal trees. A macro reached again through its own expansion, nesting deeper
|
||||
than 32, and more than 2^18 values produced through one set are errors, and an
|
||||
error names the invocation path through every macro involved. `Expand` refuses
|
||||
a document holding `[macros]` that `Define` has not taken, so a file meant only
|
||||
to invoke cannot define. Arrays come back as `[]any`, whatever form the parser
|
||||
gave them.
|
||||
|
||||
## Deliberate subset and deviations
|
||||
|
||||
- Datetime syntax is unsupported. Use quoted strings and parse them in the
|
||||
|
||||
Reference in new issue
Block a user