Skip to main content

Crate m2_syn

Crate m2_syn 

Source
Expand description

§m2-syn

crates.io docs.rs license

m2-syn is a parser-independent typed syntax graph for Macaulay2. One syntax! declaration describes the algebraic shape of the graph; generated implementations provide construction, traversal, source provenance, and conversion from a concrete syntax tree.

The API is experimental and may change while the typed grammar and parser adapter interfaces are being established.

§Project direction

This crate began as the syntax and analysis layer for the Macaulay2 language server. It grew into a standalone, syn-like foundation for M2: an owned, typed representation that can be constructed from source, traversed and rewritten, and emitted as code.

The current priority is the basic source pipeline:

  1. parse M2 source with Tree-sitter and reconstruct its typed graph directly;
  2. parse the lexer’s token stream with the independent native precedence parser;
  3. emit normalized M2 that parses back to the same structure.

The syntax model follows the grammar published as tree-sitter-macaulay2 6.0.0, resolved from the registry like any other dependency. Local builds and tests therefore exercise the same grammar downstream users get, rather than whatever happens to be checked out beside the repository.

Round-tripping through both the Tree-sitter and native parser backends works end to end, and quote_m2!/parse_quote_m2! are stable enough for everyday use (see Quoting). The next steps are a converter from M2’s own Core parser output and a macro-expansion engine built on the typed graph; Core’s own concrete tree is considerably less structured than either parser backend here (no named fields, several statement forms share one flat node shape distinguished only by which positional slots are populated), so the typed graph and its generated APIs must stay parser-independent rather than special-cased around it.

Longer term, m2-syn should support semantic and typechecking walks, incremental analysis after referenced code changes, selected node metadata, and procedural macros for M2. Visit, VisitMut, and Fold are intended as the basic traversal and transformation vocabulary for that work. The guiding design rule is to describe as little grammar as possible in syntax! and generate the repetitive construction, traversal, reconstruction, and printing machinery.

§Representation pipeline

The frontend has one raw syntax representation and one generated typed graph:

source --lex--> TokenStream --NativeParser-----------> typed CST
   |                                                     |
   +--> Tree-sitter CST --direct lowering----------------+
                                                         |
source <--Display-- TokenStream <---------Lex-------------+

TokenStream is the only raw representation. It is flat at the top level and recursive only through balanced Group token trees. The native parser decides top-level cell boundaries after lexing because semicolons and line breaks are grammatical in M2, not merely lexical.

Parse and Lex are the two directions at the typed boundary. For a typed value c, parsing its emission should recover c. Emitting a parsed raw stream may normalize insignificant layout:

Parse(Lex(c)) = c
Lex(Parse(tokens)) = normalize(tokens)

NativeParser constructs the graph directly from the shared token cursor. TreeSitterParser lowers the bundled grammar’s CST directly, including its muted, comma-pack, delimiter, operator, and control-form layouts. It does not re-lex or invoke NativeParser. TreeSitterNode, ExternalCstNode, and Reconstruct remain the parser-independent seam used by that adapter for schema-compatible leaves, operators, and tokens; they are not an alternative graph or traversal API. Typed traversal is generated as Visit, VisitMut, and Fold.

The ownership boundaries are intentionally narrow:

LocationOwns
lex/token_stream.rsraw atoms and recursive groups
lex/lexer.rsbyte recognition and delimiter balancing
parser/parse.rsthe shared token cursor and parser traits
parser/native.rscell boundaries, precedence, and typed-node construction
cst/the external-CST reconstruction adapter
schema/nodes.rsthe compact grammar and token parser metadata declaration
m2-syn-macros/src/generation of tokens, nodes, traversal, parsing, and emission
syntax! {
    // Structural precedences with no single owning token; every operator
    // below carries its own precedence inline instead.
    precedence: {
        PREC_CONTROL = 12,
    }

    tokens {
        // L/R is the binary associativity. A third slot overrides the
        // prefix strength when it differs from the precedence.
        [+] { bin, pref, aug } (50, L)
        [=] { infix }          (14, R)
        [if] [then] [else]     (PREC_CONTROL)
        [,]
    }

    #[operator(prefix)]
    enum PrefixOperator {}
    #[operator(binary)]
    enum BinaryOperator {}
    #[operator(postfix)]
    enum PostfixOperator {}

    struct Symbol;

    struct BinaryExpression {
        left: Expr,
        operator: BinaryOperator,
        right: Expr,
    }

    enum Expr {
        BinaryExpression,
        Symbol,
    }
}

The canonical declaration lives in src/schema/nodes.rs, where the syntax! procedural macro expands it into the token, node, traversal, and fold items, and into the visit, visit_mut, and fold modules re-exported at the crate root. The expansion is items only — no macro_rules! — so rust-analyzer resolves every generated name.

Token! and Delimiter! are ordinary source in src/schema/macros.rs instead of part of that expansion. Neither depends on the schema: Token! forwards the spelling to the token! procedural macro, and the delimiter families are a fixed set.

§Declaration model

DeclarationSyntax roleGenerated shape
PREC_CONTROL = 12a structural precedence with no single owning token, consumed directly by the native parsera crate-visible precedence constant
[+] { bin, pref, aug } (50, L)left-associative binary and prefix binding plus augmented-token generationtoken types, parser metadata, and inferred operator-enum membership
[=] { infix } (14, R)right-associative syntax-specific infix binding without generic operator membershipa typed token and parser metadata
[else] (PREC_CONTROL)a keyword and both of its parser strengthsa typed keyword token and parser metadata
struct Name;named text leafString and Span
#[leaf(qualified)] struct Name;one identifier with optional qualification metadatatext plus optional package and decimal-index subspans
struct Name { left: Expr, ... }concrete product nodedeclared children
field: Nested { value: Expr } or field: Pair(Expr, Symbol)a field whose type is declared in placea hoisted Nested or Pair declaration plus a field of that type
enum Name { Expr, ... }grouping category; each bare variant names the type it wraps, so the wrapped name doubles as the variant nameone declared alternative per variant
Variant(Expr, Symbol) or Variant { value: Expr }an enum alternative whose product type is declared in placea hoisted product and one alternative wrapping it
struct Name* ... or enum Name* ...a declaration whose recursive references require indirectionBox<Name> at references to that type
Token![=]literal token fieldthe type selected by the generated Token! macro
X?, Vec<T>, Punctuated<T>, Delimited<T>optional, repeated, nonempty comma-punctuated, or arbitrarily delimited childrenthe corresponding public wrapper type
(_)a child without a Tree-sitter field namepositional reconstruction from the next matching child
Lines<T>a Vec<T> printed one element per linethe separator travels with the functor
#[cst(kind = assignment)]a Rust name whose external CST node has another namereconstruction from the named CST kind
#[delimiter(parenthesis)]a product enclosed by a delimiter familya concrete node with its typed delimiter atom
#[literal(string)]a product spelled as a string literalemission as one literal token, with no delimiter atom

Every token is declared in tokens { ... }; adjacent spellings share the metadata written on their right. A binary role writes L or R, while a literal strength remains available for a non-associative rule. A prefix role binds at the token’s precedence unless a third slot overrides it, and post writes no strength at all. The separate precedence stage only holds names for structural precedences with no single owning operator token (delimiter/control-clause stoppers the native parser references directly); it is not a shared table operators look their numbers up in, so a level used by exactly one token is just written as a literal there and nowhere else. The aug tag generates the corresponding assignment token, which binds exactly like the = it abbreviates and so takes its rule from that declaration.

Boxing is explicit rather than inferred: put * after a declaration name when references to that type must be stored through Box. Only recursive cycles need it; ordinary fields, token types, and nonrecursive categories stay inline. Constructors still accept the types written in the declaration and hide the storage conversion. Generated signatures consistently refer to literal token types through Token![...]; their concrete Rust names are an implementation detail of the expansion.

Delimited<T> retains an arbitrary one of the four paired delimiter families; Delimited<T, Delimiter![()]> and the other concrete delimiter atoms refine the family statically. Every delimiter is spelled in source, so both boundary spans are read rather than inferred. The convenient type macros construct the statically refined forms:

use m2_syn::{Span, Lex};

type Parenthesized = m2_syn::paren!(m2_syn::Token![+]);
let value: Parenthesized = m2_syn::paren!(
    m2_syn::Token![+](Span::detached()),
    Span::detached(),
);
assert_eq!(value.to_m2(), "(+)");

paren!, brackets!, braces!, and angle_bars! cover all four families. punct!(T) names a nonempty comma-punctuated sequence; punct!(value first) and punct!(pairs first; comma => next) construct one while retaining every typed comma and its span. Absence belongs outside it as Option<Punctuated<T>>, while an empty component belongs in T itself. Every delimiter atom and each wrapper type implements both Parse and Lex, so they can be direct parse_quote_m2! targets.

A field normally uses its Rust name as its CST field name. Mark it (_) when it should consume the next matching unlabelled child instead. The schema deliberately permits only named struct fields and bare-type enum variants — a variant never spells out a separate name, since it’s always either the wrapped type’s own name or, for a variant wrapping a token, that token’s capitalized name — keeping both the declaration and generated API shaped like ordinary Rust rather than requiring the same fact to be written twice.

§Generated implementations

The declaration generates the following API without requiring per-node handwritten boilerplate. Runtime alternatives are represented only by the grammar-backed enums themselves; there is no parallel global node-kind enum.

Node formGenerated API
every node and categorySpanned, Reconstruct<N>, and traversal dispatch
tokenToken, constructor, reconstruction, and a Token![spelling] arm
text leaftext-plus-span constructor and exact CST reconstruction
product structconcrete-node matching, storage-aware constructor, child reconstruction, and default child walkers
coproduct enumcategory matching, alternative reconstruction, default dispatch, and unambiguous direct/transitive From conversions

The traversal traits have ordinary, independently addressable modules: visit::Visit, visit_mut::VisitMut, and fold::Fold. Their node-specific method inventories and free default walkers are generated from the syntax declaration, so adding a node cannot leave one traversal API incomplete. An override can inspect a node and call its module’s free walker to continue into its children. VisitMut edits the owned typed graph in place. Fold consumes nodes and returns the reconstructed graph.

cargo run --example type_inference demonstrates the intended analysis path: generated Visit dispatch selects node-specific rules, and the binary rule consumes the neighbouring operand facts to compute an upward-closed result range. Graph storage and fixed-point solving belong in the analysis/LSP layer; this example only verifies the syntax traversal boundary. Its generic InferenceContext leaves concrete types, values, and deferred database or signature queries under the control of the consuming analysis layer.

§Spans

A Span is a byte range into a source buffer. Source-backed spans recover their text directly with span.text(); offset-only spans can still index an explicitly supplied str or String.

use m2_syn::{Span, TextEdit};

let source = "quotient ring";
let ring = Span::source(source).subspan(9, 13);
assert_eq!(ring.text(), Some("ring"));
assert_eq!(&source[&ring], "ring");

// An edit acts on the buffer and on the spans indexing it, and the two agree.
let edit = TextEdit::insertion(0, "the ");
let edited = edit.apply(source).unwrap();
assert_eq!(&edited[ring.shifted(&edit)], &source[&ring]);

Tokens and textual leaves retain no copied spelling: they keep a span and slice its shared source buffer. Product and category spans are derived from their children. Parser-independent syntax uses Span::detached() when no source location exists.

Line and column are deliberately absent — they are facts about a buffer’s contents rather than about a position, so they belong to whoever holds the buffer, exactly as rustc keeps byte positions in Span and a line table in SourceMap. A span is not the identity of a semantic object; incremental dependency identity belongs in the semantic layer.

§Native lexer

lex is the first native-parser layer. It accepts any byte iterator and returns the same source-spanned TokenStream used by quoting and emission. The only raw token categories are Group, Ident, Literal, Punct, and Trivia; the lexer does not synthesize typed nodes, adjacency, or cells. A lone carriage return and physical line breaks are both whitespace trivia, with Trivia::contains_line_break carrying the structural distinction. After greedy token recognition, structural delimiter pairs become recursive Group trees that retain exact opening and closing spans.

Generated Token![..] values are checked typed refinements of these raw atoms, not a sixth TokenTree variant. A punctuation atom retains its raw Punct, and a keyword retains its raw Ident. Adjacency is different: it is a parser-owned empty Adj node placed at the right operand’s boundary. It is independent of physical whitespace (f(x) and f (x) have the same operator), remains absent from return 1, and emits no token. The lexer applies context-free maximal munch across generated operators, delimiters, and comment openers. Consequently |--1 begins with the |- operator rather than a comment, while a token beginning with -- is a line comment. Likewise, (*) remains the single greedy operator rather than a parenthesized group. Quotation marks are part of a single literal token, not delimiter groups.

$ remains an identifier-continuation character. Package$name$12 is one IdentToken with one overall span; the typed Symbol additionally records package_qualifier = Package and index_qualifier = 12 as optional subspans. Only package$name, name$decimal, and their combined form are marked, so the representation permits at most one qualifier of each kind. This is metadata, not grammar-level tokenization. Exact Core$word spellings are a separate hardcoded renaming hook for declared word tokens: Core$not behaves as not, while Core$Core$not remains an ordinary symbol.

Decimal real literals retain precision before exponent: 1p53, .5p20, and 1.25p53e3 are each one FloatLiteral. Once an exponent has been consumed, p starts the following identifier instead, so 1e3p20 is adjacency between 1e3 and p20.

The lexer owns one validated source buffer and gives every lexical atom a span into that shared allocation. The byte-iterator entry point first materializes its finite input; lex_str starts directly from source text.

use m2_syn::{TokenTree, lex_str};

let tokens = lex_str("***1")?;
let spellings = tokens
    .into_iter()
    .filter_map(|token| match token {
        TokenTree::Literal(token) => Some(token.text().to_owned()),
        token => token.spelling().map(str::to_owned),
    })
    .collect::<Vec<_>>();

assert_eq!(spellings, ["**", "*", "1"]);

§Parser adapters

Generated reconstruction depends only on ExternalCstNode. TreeSitterNode adapts Tree-sitter identity, field names, source text, extras, and ranges to that interface. This homogeneous node view ends at the adapter: it is never stored inside a generated typed node. Parsers that already know the typed grammar should construct the graph directly, as NativeParser does.

Parser<T> is the parser-backend boundary. It receives a TokenStream and returns a generated syntax target. T defaults to SourceFile, while parsers may implement the trait again for more specific targets such as Expr. Both built-in backends implement this same token-stream API. A parser with its own CST can implement ExternalCstNode and call reconstruct; a parser whose native model already matches the generated graph can construct the target directly.

The target-owned Parse trait is the dual of Lex: parse2::<T> consumes one complete TokenStream as T. Generated Token![..] atoms, raw token categories, token streams, boxes, delimiters, comma-punctuated collections, and terminated bodies implement it. ParseStream shares immutable token storage through Rc<TokenStream>; end-of-input is cursor state rather than a synthetic token. A fork has an independent index and advance_to explicitly commits successful speculation. parse_quote_m2! composes quoting with type-inferred parsing.

Lex::to_token_stream is the inverse boundary. The native parser supports the normalized round trip TokenStream -> SourceFile -> TokenStream -> SourceFile. Generated concrete token structs are deliberately underscore-prefixed; use Token![..] to name their types and inspect the underlying TokenTree after Lex when working with a heterogeneous stream. Delimiter structs follow the same rule through Delimiter![..].

The lexer emits one flat TokenStream; splitting it into the cells evaluated at global scope is a parse result, because the judgment is grammatical. A ; ends a cell unless a quote specifier took it literally, and a line break ends one only where the tokens so far already form a complete expression. Wrapping a region in a delimiter therefore never rewrites its tokens.

use m2_syn::{Eof, Parser, SourceFile, Span, TokenStream, lex_str, parse_with};

struct EmptyParser;

impl Parser for EmptyParser {
    type Error = Infallible;

    fn parse_stream(&mut self, _tokens: TokenStream) -> Result<SourceFile, Self::Error> {
        Ok(SourceFile::new(Vec::new(), Eof::new("", Span::detached())))
    }
}

let tokens = lex_str("").unwrap();
let file = parse_with(&mut EmptyParser, tokens).unwrap();
assert!(file.cells.is_empty());

TreeSitterParser is the built-in implementation and can be retained across calls. parse_file remains the convenience function that creates one for a single parse.

parse_file is the concrete Macaulay2 parser entry point:

use m2_syn::{Lex, parse_file};

let file = parse_file("x + 1\ny + x * 2")?;
let normalized = file.to_m2();
assert_eq!(parse_file(&normalized)?.to_m2(), normalized);

parse_tokens connects generated or quoted M2 back to typed syntax:

use m2_syn::{Lex, parse_tokens, quote_m2};

let quoted = quote_m2! { left + (right) };
let file = parse_tokens(&quoted)?;
assert_eq!(file.to_m2(), "left + (right)");

ParsedFile provides the convenient source-to-source interface over these lower-level pieces. It owns one mutable typed CST and computes every current output from that tree, so a token projection cannot silently become stale after an edit. The original source remains available separately as an immutable snapshot. from_source uses Tree-sitter; from_source_native selects the direct precedence parser.

use m2_syn::{ParsedFile, Symbol, visit_mut::VisitMut};

struct Rename;

impl VisitMut for Rename {
    fn visit_symbol_mut(&mut self, symbol: &mut Symbol) {
        if symbol.text() == "left" {
            symbol.set_text("renamed");
        }
    }
}

let file = ParsedFile::from_source("left + right")?.edit(|cst| {
    Rename.visit_source_file_mut(cst);
});

assert_eq!(file.original_source(), "left + right");
assert_eq!(file.to_source(), "renamed + right");

// Stable, uncolored projections are useful in tests and diagnostics.
println!("{}", file.pretty_tokens());
println!("{}", file.pretty_cst());

// One terminal-aware report includes the retained input, recursively flattened
// tokens, and the generated typed CST.
file.print_pretty()?;

The CST view is generated from the same schema as node construction and traversal. Struct fields become labelled edges, category enums remain invisible implementation details, punctuated sequences expose both values and comma tokens, leaf source spellings precede their node types, and delimiters show separate opening and closing boundaries. The token view rotates primitive sequences into compact horizontal bands: centered token text occupies the first row and token type the second, with recursive group openings and closings represented as ordinary columns. End-of-cell markers are explicit, always end a band, and group delimiters provide the only soft wrapping boundaries. Trivia is hidden by default and coalesced when enabled. Source ranges can be disabled and ANSI styling can be selected explicitly through PrettyReport.

Run the inspector with its built-in example or give it an M2 source file:

cargo run --example inspect
cargo run --example inspect -- path/to/file.m2

Tree-sitter extras are not reconstructed yet. ChildCursor currently removes extra children, so comments are discarded instead of being retained as ordered trivia. They must be anchored relative to semantic children before comment-preserving round trips can be claimed.

§Quoting

quote_m2! constructs an M2 TokenStream from Rust tokens. $(...) interpolates any Rust expression implementing Lex. Each interpolation is first emitted as a real fragment, so punctuation, identifiers, literals, and groups compose according to their actual token boundaries rather than the Rust expression’s type. Parentheses, brackets, braces, and M2 angle bars are emitted as recursive raw groups.

$[pattern in iterator] { ... } repeats a recursively quoted template using an ordinary Rust for loop. The iterator and pattern are explicit; interpolations that do not depend on the pattern are reused normally on each iteration.

use m2_syn::{Span, Symbol, quote_m2};

let value = Symbol::new("value", Span::detached());
let tokens = quote_m2! {
    result = $(value) + 1;
    return result
};

assert_eq!(tokens.to_string(), "result=value+1;return result");

let values = [
    Symbol::new("left", Span::detached()),
    Symbol::new("right", Span::detached()),
];
let comma = m2_syn::Token![,](Span::detached());
let repeated = quote_m2! {
    $[value in &values] { $(value) $(comma) }
};
assert_eq!(repeated.to_string(), "left,right,");

The rendered text is normalized M2 source, not a lossless reproduction of whitespace or comments discarded by the typed graph.

§Development

Run the complete workspace checks from the repository root:

cargo fmt --all --check
cargo check --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace

The schema is expanded by the syntax! procedural macro, so changes to src/schema/nodes.rs are picked up by the next compile; there is no generated source to refresh or commit.

m2-syn is licensed under the GNU General Public License v3.0.

Re-exports§

pub use treesitter::ParseError;
pub use treesitter::RealtimeParser;
pub use treesitter::TreeSitterParser;
pub use treesitter::parse_file;
pub use treesitter::parse_file_recovering;
pub use treesitter::parse_tokens;
pub use parse::FragmentParseError;
pub use parse::Parse;
pub use parse::ParseStream;
pub use parse::Parser;
pub use parse::TokenParseError;
pub use parse::parse_fragment_str;
pub use parse::parse_with;
pub use parse::parse2;
pub use parse::reconstruct;
pub use lexer::LexError;
pub use lexer::LexErrorKind;
pub use lexer::lex;
pub use lexer::lex_recovering;
pub use lexer::lex_str;
pub use lexer::lex_str_recovering;
pub use native::NativeParseError;
pub use native::NativeParser;
pub use native::parse_native;
pub use native::parse_native_recovering;
pub use pretty::PrettyOptions;
pub use pretty::PrettyReport;
pub use pretty::PrettyTree;
pub use pretty::format_pretty_tokens;
pub use pretty::format_pretty_tree;
pub use punctuated::PunctPair;
pub use punctuated::Punctuated;

Modules§

fold
Owning rebuild of the typed graph.
lexer
Native source-to-token conversion.
native
Direct construction of the typed graph from a flat token stream.
parse
Parsing boundaries over the shared raw token representation.
pretty
Terminal-oriented inspection of source, raw tokens, and typed syntax trees.
punctuated
Nonempty syntax sequences separated by typed punctuation tokens.
treesitter
Tree-sitter parser adapter.
visit
Shared-reference traversal over the typed graph.
visit_mut
In-place traversal over the typed graph.

Macros§

Delimiter
Names the delimiter atom for a delimiter family, as in Delimiter![()].
Token
Names the token type generated for a spelling, as in Token![;].
angle_bars
Names or constructs angle-bar-delimited syntax.
braces
Names or constructs brace-delimited syntax.
brackets
Names or constructs bracket-delimited syntax.
paren
Names or constructs parenthesized syntax.
parse_quote_m2
Quotes M2 syntax and parses it as the type inferred at the call site.
punc
Names or constructs a nonempty comma-punctuated sequence.
quote_m2
Constructs an M2 token stream with recursive Rust interpolation.
syntax
Declares typed syntax nodes, token atoms, and traversal implementations.

Structs§

Adj
A typed Macaulay2 adj syntax leaf.
AdjacentExpr
A typed Macaulay2 adjacent_expr syntax node.
AngleBarList
A typed Macaulay2 angle_bar_list syntax node.
Array
A typed Macaulay2 array syntax node.
AssignmentPack
A typed Macaulay2 assignment_pack syntax node.
BinaryExpr
A typed Macaulay2 binary_expr syntax node.
Body
Statements discarded by semicolons followed by an optional returned tail.
BreakExpr
A typed Macaulay2 break_expr syntax node.
CSTNodeClassLabel
Backend-local node identity used only during external CST reconstruction.
Catch
A typed Macaulay2 catch syntax node.
Cell
A typed Macaulay2 cell syntax node.
ChildCursor
Single-pass field selection used only by generated reconstruction code.
ContinueExpr
A typed Macaulay2 continue_expr syntax node.
DebugExpr
A typed Macaulay2 debug_expr syntax node.
Delimited
Syntax contained by an arbitrary or statically known delimiter family.
Delimiter
Type-erased delimiter data stored by a raw TokenGroup.
DoStep
A typed Macaulay2 do_step syntax node.
DoubleSpan
The real opening and closing boundaries of a paired delimiter.
ElseClause
A typed Macaulay2 else_clause syntax node.
Empty
A typed Macaulay2 empty syntax leaf.
Eoc
A typed Macaulay2 eoc syntax leaf.
EocToken
A zero-width boundary terminating one top-level source cell.
Eof
A typed Macaulay2 eof syntax leaf.
EscapeSequence
A typed Macaulay2 escape_sequence syntax leaf.
EvaluatedAssignment
A typed Macaulay2 evaluated_assignment syntax node.
ExceptDo
A typed Macaulay2 except_do syntax node.
ExprPack
A typed Macaulay2 expr_pack syntax node.
ExternalCstChild
One child supplied by an external CST backend.
FixedArity
A typed Macaulay2 fixed_arity syntax node.
FloatLiteral
A typed Macaulay2 float_literal syntax leaf.
ForLoop
A typed Macaulay2 for_loop syntax node.
FromInstance
A typed Macaulay2 from_instance syntax node.
GlobalBinding
A typed Macaulay2 global_binding syntax node.
GlobalParallelAssignment
A typed Macaulay2 global_parallel_assignment syntax node.
Holder
A typed Macaulay2 holder syntax node.
IdentToken
An identifier spelling and its source span.
IfStatement
A typed Macaulay2 if_statement syntax node.
IntegerLiteral
A typed Macaulay2 integer_literal syntax leaf.
IterIn
A typed Macaulay2 iter_in syntax node.
IterRange
A typed Macaulay2 iter_range syntax node.
LambdaExpression
A typed Macaulay2 lambda_expression syntax node.
List
A typed Macaulay2 list syntax node.
ListStep
A typed Macaulay2 list_step syntax node.
LiteralToken
A literal spelling together with its lexical category and source span.
LocalBinding
A typed Macaulay2 local_binding syntax node.
LocalParallelAssignment
A typed Macaulay2 local_parallel_assignment syntax node.
LoopBody
A typed Macaulay2 loop_body syntax node.
MethodInstallation
A typed Macaulay2 method_installation syntax node.
NewInstallation
A typed Macaulay2 new_installation syntax node.
NewStatement
A typed Macaulay2 new_statement syntax node.
OfClass
A typed Macaulay2 of_class syntax node.
OperatorAssignment
A typed Macaulay2 operator_assignment syntax node.
OperatorInstallation
A typed Macaulay2 operator_installation syntax node.
OptionExpression
A typed Macaulay2 option_expression syntax node.
ParsedFile
An owned typed CST together with the original input.
PostfixExpr
A typed Macaulay2 postfix_expr syntax node.
PrefixExpr
A typed Macaulay2 prefix_expr syntax node.
ProfilingExpr
A typed Macaulay2 profiling_expr syntax node.
Punct
One maximal-munch M2 punctuation token.
QuoteExpression
A typed Macaulay2 quote_expression syntax node.
RangeBoundFrom
A typed Macaulay2 range_bound_from syntax node.
RangeBoundTo
A typed Macaulay2 range_bound_to syntax node.
RawStringContent
A typed Macaulay2 raw_string_content syntax leaf.
RawStringLiteral
A typed Macaulay2 raw_string_literal syntax node.
Recovered
A successfully produced value accompanied by non-fatal diagnostics.
ReturnExpr
A typed Macaulay2 return_expr syntax node.
Sequence
A typed Macaulay2 sequence syntax node.
SourceFile
A typed Macaulay2 source_file syntax node.
Span
Where syntax originated and, when available, the source buffer it indexes.
Statement
A typed Macaulay2 statement syntax node.
StringContent
A typed Macaulay2 string_content syntax leaf.
StringLiteral
A typed Macaulay2 string_literal syntax node.
Symbol
A typed Macaulay2 symbol syntax leaf.
Terminated
A statement whose value is discarded by a trailing semicolon.
ThenClause
A typed Macaulay2 then_clause syntax node.
Throw
A typed Macaulay2 throw syntax node.
TokenGroup
A delimited raw token stream.
TokenStream
An owned sequence of raw M2 token trees.
Trap
A typed Macaulay2 trap syntax node.
Trivia
Whitespace or a comment retained in the raw token stream.
TryStatement
A typed Macaulay2 try_statement syntax node.
TypeAnnotation
A typed Macaulay2 type_annotation syntax node.
Variadic
A typed Macaulay2 variadic syntax node.
WhenCondition
A typed Macaulay2 when_condition syntax node.
WhileLoop
A typed Macaulay2 while_loop syntax node.
_Add
The typed Token![+] atom.
_AddAdd
The typed Token![++] atom.
_AddAddEql
The typed Token![++=] atom.
_AddEql
The typed Token![+=] atom.
_Amp
The typed Token![&] atom.
_AmpEql
The typed Token![&=] atom.
_And
The typed Token![and] atom.
_AngleBarDelimiter
The typed _AngleBarDelimiter delimiter atom.
_Att
The typed Token![@] atom.
_AttAtt
The typed Token![@@] atom.
_AttAttEql
The typed Token![@@=] atom.
_AttAttQsm
The typed Token![@@?] atom.
_AttAttQsmEql
The typed Token![@@?=] atom.
_AttEql
The typed Token![@=] atom.
_Bng
The typed Token![!] atom.
_BngEql
The typed Token![!=] atom.
_Box
The typed Token![⊠] atom.
_BoxEql
The typed Token![⊠=] atom.
_BraceDelimiter
The typed _BraceDelimiter delimiter atom.
_BracketDelimiter
The typed _BracketDelimiter delimiter atom.
_Break
The typed Token![break] atom.
_Breakpoint
The typed Token![breakpoint] atom.
_Bsl
The typed Token![\] atom.
_BslBsl
The typed Token![\\] atom.
_BslBslEql
The typed Token![\\=] atom.
_BslEql
The typed Token![\=] atom.
_Catch
The typed Token![catch] atom.
_Cdt
The typed Token![·] atom.
_CdtEql
The typed Token![·=] atom.
_Cma
The typed Token![,] atom.
_Col
The typed Token![:] atom.
_ColEql
The typed Token![:=] atom.
_Continue
The typed Token![continue] atom.
_Crt
The typed Token![^] atom.
_CrtBng
The typed Token![^!] atom.
_CrtCrt
The typed Token![^^] atom.
_CrtCrtEql
The typed Token![^^=] atom.
_CrtEql
The typed Token![^=] atom.
_CrtGst
The typed Token![^>] atom.
_CrtGstEql
The typed Token![^>=] atom.
_CrtLst
The typed Token![^<] atom.
_CrtLstEql
The typed Token![^<=] atom.
_CrtMul
The typed Token![^*] atom.
_CrtMulMul
The typed Token![^**] atom.
_CrtMulMulEql
The typed Token![^**=] atom.
_CrtTld
The typed Token![^~] atom.
_Do
The typed Token![do] atom.
_Dot
The typed Token![.] atom.
_DotDot
The typed Token![..] atom.
_DotDotEql
The typed Token![..=] atom.
_DotDotLst
The typed Token![..<] atom.
_DotDotLstEql
The typed Token![..<=] atom.
_DotQsm
The typed Token![.?] atom.
_ElapsedTime
The typed Token![elapsedTime] atom.
_ElapsedTiming
The typed Token![elapsedTiming] atom.
_Else
The typed Token![else] atom.
_Eql
The typed Token![=] atom.
_EqlBngEql
The typed Token![=!=] atom.
_EqlEql
The typed Token![==] atom.
_EqlEqlEql
The typed Token![===] atom.
_EqlEqlEqlGst
The typed Token![===>] atom.
_EqlEqlEqlGstEql
The typed Token![===>=] atom.
_EqlEqlGst
The typed Token![==>] atom.
_EqlEqlGstEql
The typed Token![==>=] atom.
_EqlGst
The typed Token![=>] atom.
_Except
The typed Token![except] atom.
_Finish
The typed Token![finish] atom.
_For
The typed Token![for] atom.
_From
The typed Token![from] atom.
_Global
The typed Token![global] atom.
_Graded
The typed Token![(*)] atom.
_Gst
The typed Token![>] atom.
_GstEql
The typed Token![>=] atom.
_GstGst
The typed Token![>>] atom.
_GstGstEql
The typed Token![>>=] atom.
_Hsh
The typed Token![#] atom.
_HshQsm
The typed Token![#?] atom.
_If
The typed Token![if] atom.
_In
The typed Token![in] atom.
_List
The typed Token![list] atom.
_Local
The typed Token![local] atom.
_Lst
The typed Token![<] atom.
_LstEql
The typed Token![<=] atom.
_LstEqlEql
The typed Token![<==] atom.
_LstEqlEqlEql
The typed Token![<===] atom.
_LstEqlEqlGst
The typed Token![<==>] atom.
_LstEqlEqlGstEql
The typed Token![<==>=] atom.
_LstLst
The typed Token![<<] atom.
_LstLstEql
The typed Token![<<=] atom.
_LstSub
The typed Token![<-] atom.
_Mod
The typed Token![%] atom.
_ModEql
The typed Token![%=] atom.
_Mul
The typed Token![*] atom.
_MulEql
The typed Token![*=] atom.
_MulMul
The typed Token![**] atom.
_MulMulEql
The typed Token![**=] atom.
_New
The typed Token![new] atom.
_Not
The typed Token![not] atom.
_Of
The typed Token![of] atom.
_Or
The typed Token![or] atom.
_ParenthesisDelimiter
The typed _ParenthesisDelimiter delimiter atom.
_Pip
The typed Token![|] atom.
_PipEql
The typed Token![|=] atom.
_PipPip
The typed Token![||] atom.
_PipPipEql
The typed Token![||=] atom.
_PipSub
The typed Token![|-] atom.
_PipSubEql
The typed Token![|-=] atom.
_PipUbs
The typed Token![|_] atom.
_PipUbsEql
The typed Token![|_=] atom.
_Profile
The typed Token![profile] atom.
_Qsm
The typed Token![?] atom.
_QsmQsm
The typed Token![??] atom.
_QsmQsmEql
The typed Token![??=] atom.
_Return
The typed Token![return] atom.
_Scl
The typed Token![;] atom.
_Sfp
The typed Token![⧢] atom.
_SfpEql
The typed Token![⧢=] atom.
_Shield
The typed Token![shield] atom.
_Slh
The typed Token![/] atom.
_SlhEql
The typed Token![/=] atom.
_SlhSlh
The typed Token![//] atom.
_SlhSlhEql
The typed Token![//=] atom.
_Step
The typed Token![step] atom.
_Sub
The typed Token![-] atom.
_SubEql
The typed Token![-=] atom.
_SubGst
The typed Token![->] atom.
_Symbol
The typed Token![symbol] atom.
_Test
The typed Token![TEST] atom.
_Then
The typed Token![then] atom.
_ThreadLocal
The typed Token![threadLocal] atom.
_ThreadVariable
The typed Token![threadVariable] atom.
_Throw
The typed Token![throw] atom.
_Time
The typed Token![time] atom.
_Timing
The typed Token![timing] atom.
_Tld
The typed Token![~] atom.
_TldEql
The typed Token![~=] atom.
_To
The typed Token![to] atom.
_Trap
The typed Token![trap] atom.
_Try
The typed Token![try] atom.
_Ubs
The typed Token![_] atom.
_UbsBng
The typed Token![_!] atom.
_UbsEql
The typed Token![_=] atom.
_UbsGst
The typed Token![_>] atom.
_UbsGstEql
The typed Token![_>=] atom.
_UbsLst
The typed Token![_<] atom.
_UbsLstEql
The typed Token![_<=] atom.
_UbsMul
The typed Token![_*] atom.
_UbsTld
The typed Token![_~] atom.
_When
The typed Token![when] atom.
_While
The typed Token![while] atom.
_Xor
The typed Token![xor] atom.

Enums§

Assignment
The typed Assignment syntax category.
AssignmentPackComponent
The typed AssignmentPackComponent syntax category.
BinaryOperator
The typed BinaryOperator syntax category.
Collection
The typed Collection syntax category.
Component
The typed Component syntax category.
ControlFlow
The typed ControlFlow syntax category.
DebugKeyword
The typed DebugKeyword syntax category.
DelimiterKind
The delimiter families recognized by raw syntax containers.
Expr
The typed Expr syntax category.
Installation
The typed Installation syntax category.
IterationDomain
The typed IterationDomain syntax category.
LambdaParameters
The typed LambdaParameters syntax category.
Literal
The typed Literal syntax category.
LiteralKind
The lexical category of a literal token.
OperatorExpr
The typed OperatorExpr syntax category.
ParallelAssignment
The typed ParallelAssignment syntax category.
PostfixOperator
The typed PostfixOperator syntax category.
PrefixOperator
The typed PrefixOperator syntax category.
ProfilingModifier
The typed ProfilingModifier syntax category.
QuoteSpecifier
The typed QuoteSpecifier syntax category.
RawStringElement
The typed RawStringElement syntax category.
ReconstructError
A typed reconstruction failure.
SimpleBinding
The typed SimpleBinding syntax category.
StringElement
The typed StringElement syntax category.
TextEdit
One text change: the text a buffer gains at a point, or the stretch it loses.
TokenParseRule
What a declared token does when the parser reaches it: its parsing precedence, plus the binding strengths its role needs.
TokenTree
One raw M2 token tree.
TriviaKind
The lexical category of source trivia.
TryFallback
The typed TryFallback syntax category.

Constants§

TOKEN_PARSE_RULES
Every declared token that carries a parse rule, sorted by spelling. Tokens the declaration gives no role are absent.

Traits§

DelimiterToken
A generated typed refinement of one raw delimiter kind.
DelimiterValue
Delimiter data that can surround typed syntax.
ExternalCstNode
Minimal untyped view required to reconstruct generated typed nodes.
Lex
Emits a typed or raw syntax value into the shared token representation.
Reconstruct
Reconstructs one typed value from a parser backend’s untyped CST node.
Spanned
A syntax value that reports its source extent.
Token
A generated closed token atom backed by one matching raw TokenTree.

Type Aliases§

Offset
A boundary in a source buffer, as a byte offset.

Derive Macros§

Spanned
Derives m2_syn::Spanned by joining the spans of a value’s fields.