Expand description
Pratt expression-operator plugin for the tabnas parser engine, layered on the jsonic relaxed-JSON base grammar.
The algorithm is Pratt parsing, and draws heavily from the explanation
written by Aleksey Kladov at
https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html.
See prattify for the core.
Expressions parse into LISP-style S-expressions: an array whose first
element describes the operator and whose remaining elements are the
operand terms, so 1+2*3 becomes ["+", 1, ["*", 2, 3]] once the
operator descriptions are reduced to their source text. A caller
supplied evaluator can reduce the tree to a value during the parse.
TypeScript is canonical: ts/src/expr.ts defines the behaviour, the
option names, the defaults and the order of alternates. The shared
fixtures in test/spec/*.tsv are the parity contract across
TypeScript, Go and Rust.
fn main() -> Result<(), Box<dyn std::error::Error>> {
let value = tabnas_expr::parse("a:1+2*3")?;
assert_eq!(tabnas_expr::simplify(&value).to_string(),
r#"{"a":["+",1,["*",2,3]]}"#);
Ok(())
}§Untrusted input
A parsed expression is data, never instructions. This plugin reads expression text of unknown provenance and returns S-expressions for a caller supplied evaluator to reduce, and that hand-off is where hostile input could become execution. Treat every operand and operator as untrusted text, and never let a document select which evaluator or operator implementation runs.
Structs§
- Eval
Site - The site an evaluator is called from: the rule the reduction belongs to
and the live parse context, and neither when
evaluationis called on a finished tree. - Expr
Error - The error a failed parse produces, re-exported so callers need not depend on the engine crate directly.
- Expr
Options - Options for the plugin.
- Op
- The full operator description carried by a parsed expression and handed to an evaluator.
- OpDef
- One entry of the
opoption map: the definition of an operator. - OpRef
- One occurrence of an operator: the shared description and the token
that introduced it. The canonical
makeOpbuilds the same pair by copying the description and attaching the token. - Preval
Def - Paren preval configuration: whether a value may precede the opening
paren (
foo(1),a[1]), whether one is required, and which values are allowed to. - Translation
Part - One optional alchemy translation source and its explicit entry point.
- Translation
Parts - The package-local structural translation interface.
Constants§
- MAX_
SAFE_ INTEGER - JavaScript’s
Number.MAX_SAFE_INTEGER, the binding power an operator with no declaredrighttakes: it binds tightest on the right. - MIN_
SAFE_ INTEGER - JavaScript’s
Number.MIN_SAFE_INTEGER, the binding power an operator with no declaredlefttakes: it binds loosest on the left. - NODE_
LIMIT - The most nodes one expression may hold.
- PLUGIN_
NAME - The name this plugin registers under.
- RULE_
LIMIT - The deepest rule stack a parse may reach.
- VERSION
- VERSION is this crate’s version. It MUST equal
ts/package.json“version” and theversionfield inrs/Cargo.toml: the release orchestrator rewrites all of them, andtests/version_test.rsfails the build if they drift. MirrorsVERSIONints/src/expr.tsandconst VERSIONingo/expr.go.
Functions§
- apply
- Install the expression grammar on a parser through
Tabnas::use_plugin, so that a derived instance rebuilds it. - defaults
- The default operator table, as the plugin declares it to the engine.
- evaluation
- Reduce an expression tree with an evaluator, innermost first.
- expr
- Install the expression grammar on a parser that already carries the
jsonic base rules (
val,map,list,pair,elem). - is_op
- Whether a value is an expression node, the port of the canonical
isOp. - make
- Build a parser with the jsonic base grammar and the default operator table.
- make_
with - Build a parser with the jsonic base grammar and the given options.
- manifest_
text - The plugin’s manifest,
tabnas.plugin.json, as the repository carries it. Itstranslateobject is what a host that translates reads: the shape an expression document is read as and written from (tree), the root the render takes, the schema of the tree its events carry (expr), the files that hold the embedding of a plain tree in that schema and the render, and the sentences that say what a written document does not keep. The crate embeds its own copy,translate/manifest.json, since a packaged crate holds nothing outsiders/;tests/translate_test.rsholds the copy to the file. - op_of
- The operator heading an expression node.
- opify
- Normalize an operator built by hand, filling the derived term count
when it is unset, as the parser’s own operator builder does. The Rust
spelling of the canonical
testing.opify. - parse
- Parse one document with the default operator table.
- parse_
scope - Parse one document and hand the unrealized value to a closure, with the expression arena held open for as long as it runs.
- parse_
simplified - Parse one document and reduce it to the S-expression form the shared fixtures compare.
- parse_
with - Parse one document with a parser this crate configured, and realize the expression nodes in the result.
- plugin
- The plugin, for
Tabnas::use_plugin, carrying the default operator table as its declared defaults. - plugin_
with - The plugin with typed options, which is how an evaluator and any
operator data that no
Valuecan carry reach the grammar. - prattify
- Embed a new operator into an expression tree, in place, according to operator precedence.
- realize
- Replace every expression handle in a parsed value with the plain array the canonical port returns: the operator description followed by the operand terms.
- render_
text - The expression format’s render,
alchemy/render.alc, the file the manifest’stranslate.rendernames: a library of alchemy definitions, with noexport, whose entry pointexpr-renderwrites a tree’s events as one document. A host links it with its own program. The crate embeds its own copy,translate/render.alc, held to the file as the manifest’s is; the embedding,translate/embed.alc, istranslate().embed. - simplify
- Reduce a parsed value to the S-expression form the shared fixtures compare: every operator description becomes its source text, and a term that was never filled is dropped.
- terms_
of - The operand terms of an expression node.
- translate
- Return the expression format’s immutable translation parts.
Type Aliases§
- Evaluate
- Resolve the value of an operation. The Rust spelling of the canonical
Evaluatecallback: it takes the operator and its already reduced terms, and returns the value the expression stands for.