tinyscript 0.6.1

Tiny, C-like scripting language.
Documentation
// Copyright © 2025 Stephan Kunz
//!Parselet implementations.

mod assignment_parselet;
mod binary_parselet;
mod grouping_parselet;
mod literal_parselet;
mod logic_parselet;
mod unary_parselet;
mod value_parselet;

// flatten
pub use assignment_parselet::AssignmentParselet;
pub use binary_parselet::{BinaryKind, BinaryParselet};
pub use grouping_parselet::GroupingParselet;
pub use literal_parselet::LiteralParselet;
pub use logic_parselet::{LogicKind, LogicParselet};
pub use unary_parselet::UnaryParselet;
pub use value_parselet::ValueParselet;

use crate::{
	compilation::{CompilationError, Parser},
	execution::Chunk,
};

use super::{Lexer, precedence::Precedence, token::Token};

/// Interfaces used by the Pratt parser. A `PrefixParselet` is
/// associated with a token that appears at the beginning of an expression.
/// Its `parse()` method will be called with the consumed leading token, and the
/// parselet is responsible for parsing anything that comes after that token.
/// This interface is also used for single-token expressions like variables, in
/// which case `parse()` simply doesn't consume any more tokens.
pub trait PrefixParselet: Send + Sync {
	/// Parse the token
	fn parse(&self, lexer: &mut Lexer, parser: &mut Parser, chunk: &mut Chunk, token: Token)
	-> Result<(), CompilationError>;
}

/// Interfaces used by the Pratt parser. An `InfixParselet` is
/// associated with a token that appears in the middle of the expression it parses.
/// Its `parse()` method will be called after the left-hand side has been parsed,
/// and it in turn is responsible for parsing everything that comes after the token.
/// This interface is also used for postfix expressions, in
/// which case `parse()` simply doesn't consume any more tokens.
pub trait InfixParselet: Send + Sync {
	/// Parse the token together with the left hand expression
	fn parse(&self, lexer: &mut Lexer, parser: &mut Parser, chunk: &mut Chunk, token: Token)
	-> Result<(), CompilationError>;

	/// Get the precedence the parselet is executed with.
	fn get_precedence(&self) -> Precedence;
}

/// Concrete enum wrapping all prefix parselet types.
/// Avoids `Arc<dyn PrefixParselet>` so no atomic pointer-size ops are needed.
#[derive(Clone)]
pub enum AnyPrefixParselet {
	Assignment(AssignmentParselet),
	Grouping(GroupingParselet),
	Literal(LiteralParselet),
	Unary(UnaryParselet),
	Value(ValueParselet),
}

impl PrefixParselet for AnyPrefixParselet {
	fn parse(&self, lexer: &mut Lexer, parser: &mut Parser, chunk: &mut Chunk, token: Token)
	-> Result<(), CompilationError> {
		match self {
			Self::Assignment(p) => p.parse(lexer, parser, chunk, token),
			Self::Grouping(p) => p.parse(lexer, parser, chunk, token),
			Self::Literal(p) => p.parse(lexer, parser, chunk, token),
			Self::Unary(p) => p.parse(lexer, parser, chunk, token),
			Self::Value(p) => p.parse(lexer, parser, chunk, token),
		}
	}
}

/// Concrete enum wrapping all infix parselet types.
/// Avoids `Arc<dyn InfixParselet>` so no atomic pointer-size ops are needed.
#[derive(Clone)]
pub enum AnyInfixParselet {
	Binary(BinaryParselet),
	Logic(LogicParselet),
}

impl InfixParselet for AnyInfixParselet {
	fn parse(&self, lexer: &mut Lexer, parser: &mut Parser, chunk: &mut Chunk, token: Token)
	-> Result<(), CompilationError> {
		match self {
			Self::Binary(p) => p.parse(lexer, parser, chunk, token),
			Self::Logic(p) => p.parse(lexer, parser, chunk, token),
		}
	}

	fn get_precedence(&self) -> Precedence {
		match self {
			Self::Binary(p) => p.get_precedence(),
			Self::Logic(p) => p.get_precedence(),
		}
	}
}