Skip to main content

Syntax

Trait Syntax 

Source
pub trait Syntax {
    type Lang: Language;
    type Component: Display + Debug + Clone + PartialEq + Eq + Hash;
    type COMPONENTS: ArrayLength + Debug + Eq + Hash;
    type REQUIRED: ArrayLength + Debug + Eq + Hash;

    const KIND: <Self::Lang as Language>::SyntaxKind;

    // Required methods
    fn possible_components(    ) -> &'static GenericArrayDeque<Self::Component, Self::COMPONENTS>;
    fn required_components(    ) -> &'static GenericArrayDeque<Self::Component, Self::REQUIRED>;
}
Expand description

A trait representing a syntax with a type-level number of components.

This trait defines the structure of a syntax element that has a known number of required components. It uses typenum for type-level component count, enabling compile-time arithmetic and better integration with generic-array-based code.

§Type Parameters

  • Component: The type representing individual syntax components (usually an enum)
  • COMPONENTS: A type-level unsigned integer (via ArrayLength) specifying component count

§Examples

use tokora::{utils::{typenum, GenericArrayDeque}, syntax::{Syntax, Language}};
use typenum::U5;
use core::fmt;

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct MyLanguage;

impl Language for MyLanguage {
  type SyntaxKind = (); // () is a placeholder
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum LetStatementComponent {
    LetKeyword,
    Identifier,
    Equals,
    Expression,
    Semicolon,
}

impl fmt::Display for LetStatementComponent {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::LetKeyword => write!(f, "'let' keyword"),
            Self::Identifier => write!(f, "identifier"),
            Self::Equals => write!(f, "'=' operator"),
            Self::Expression => write!(f, "expression"),
            Self::Semicolon => write!(f, "';' semicolon"),
        }
    }
}

struct LetStatement;

impl Syntax for LetStatement {
    type Lang = MyLanguage;
    const KIND: () = (); // () is a placeholder
    type Component = LetStatementComponent;
    type COMPONENTS = U5;
    type REQUIRED = U5;

    fn possible_components() -> &'static GenericArrayDeque<Self::Component, Self::COMPONENTS> {
        static COMPONENTS: GenericArrayDeque<LetStatementComponent, typenum::U5> = {
            let mut deque = GenericArrayDeque::new();
            deque.push_back(LetStatementComponent::LetKeyword);
            deque.push_back(LetStatementComponent::Identifier);
            deque.push_back(LetStatementComponent::Equals);
            deque.push_back(LetStatementComponent::Expression);
            deque.push_back(LetStatementComponent::Semicolon);
            deque
        };
        &COMPONENTS
    }

    fn required_components() -> &'static GenericArrayDeque<Self::Component, Self::REQUIRED> {
        static REQUIRED: GenericArrayDeque<LetStatementComponent, typenum::U5> = {
            let mut deque = GenericArrayDeque::new();
            deque.push_back(LetStatementComponent::LetKeyword);
            deque.push_back(LetStatementComponent::Identifier);
            deque.push_back(LetStatementComponent::Equals);
            deque.push_back(LetStatementComponent::Expression);
            deque.push_back(LetStatementComponent::Semicolon);
            deque
        };
        &REQUIRED
    }
}

Required Associated Constants§

Source

const KIND: <Self::Lang as Language>::SyntaxKind

The kind of the syntax.

Required Associated Types§

Source

type Lang: Language

The language this syntax belongs to.

Source

type Component: Display + Debug + Clone + PartialEq + Eq + Hash

The component type of this syntax.

Usually this is an enum representing different variants of syntax components. This type is used for error reporting to specify which components are missing.

Do not implement this so that Eq, Hash, or Display can report something different for the same value over time — most easily done by deriving one of them from a Cell, an atomic, or other interior-mutable or ambient state. IncompleteSyntax stores Component values in a deduplicating set keyed on exactly those impls, and after insertion can only ever hand this type back out by shared reference — so Component’s own author is the only one able to keep that promise, or break it. See Uniqueness is a logic error on IncompleteSyntax for what breaking it costs.

Source

type COMPONENTS: ArrayLength + Debug + Eq + Hash

The number of components in this syntax, represented as a type-level unsigned integer.

Uses typenum to represent the count at the type level, enabling compile-time arithmetic without requiring unstable generic_const_exprs feature.

§Examples
use typenum::U3; // For a syntax with 3 components

impl Syntax for MySyntax {
    type COMPONENTS = U3;
    // ...
}
Source

type REQUIRED: ArrayLength + Debug + Eq + Hash

The number of required components in this syntax, represented as a type-level unsigned integer.

Uses typenum to represent the count at the type level, enabling compile-time arithmetic without requiring unstable generic_const_exprs feature.

§Examples
use typenum::U3; // For a syntax with 3 components

impl Syntax for MySyntax {
    type COMPONENTS = U3;
    // ...
}

Required Methods§

Source

fn possible_components() -> &'static GenericArrayDeque<Self::Component, Self::COMPONENTS>

Returns a static reference to all possible components for this syntax.

The deque contains all components that can be part of this syntax element, in a canonical order. The returned reference points to a static, never-changing collection that is initialized once at program startup.

§Implementation Pattern

Implementations should use a static item initialized in a const context:

fn possible_components() -> &'static GenericArrayDeque<Self::Component, Self::COMPONENTS> {
    static COMPONENTS: GenericArrayDeque<MyComponent, U3> = {
        let mut deque = GenericArrayDeque::new();
        // Push components in const context
        deque.push_back(MyComponent::Foo);
        deque.push_back(MyComponent::Bar);
        deque.push_back(MyComponent::Baz);
        deque
    };
    &COMPONENTS
}
§Examples
let components = MySyntax::possible_components();
for component in components.iter() {
    println!("{}", component);
}
Source

fn required_components() -> &'static GenericArrayDeque<Self::Component, Self::REQUIRED>

Returns a static reference to all required components for this syntax.

The deque contains all components that are required for this syntax element, in a canonical order. The returned reference points to a static, never-changing collection that is initialized once at program startup.

§Implementation Pattern

Implementations should use a static item initialized in a const context:

fn required_components() -> &'static GenericArrayDeque<Self::Component, Self::REQUIRED> {
    static REQUIRED: GenericArrayDeque<MyComponent, U2> = {
        let mut deque = GenericArrayDeque::new();
        deque.push_back(MyComponent::Foo);
        deque.push_back(MyComponent::Bar);
        deque
    };
    &REQUIRED
}
§Examples
let required = MySyntax::required_components();
assert_eq!(required.len(), 2);

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§

Source§

impl<T, S> Syntax for Recoverable<T, S>
where T: Syntax,