#![cfg_attr(not(feature = "std"), no_std)]
#![doc(html_root_url = "https://docs.rs/arithmetic-parser/0.3.0")]
#![warn(missing_docs, missing_debug_implementations)]
#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::missing_errors_doc,
clippy::must_use_candidate,
clippy::module_name_repetitions
)]
mod alloc {
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
pub use alloc::{borrow::ToOwned, boxed::Box, format, string::String, vec, vec::Vec};
#[cfg(feature = "std")]
pub use std::{borrow::ToOwned, boxed::Box, format, string::String, vec, vec::Vec};
}
pub use crate::{
error::{Context, Error, ErrorKind, SpannedError, UnsupportedType},
ops::{BinaryOp, Op, OpPriority, UnaryOp},
parser::is_valid_variable_name,
spans::{
with_span, CodeFragment, InputSpan, LocatedSpan, MaybeSpanned, NomResult, Spanned,
StripCode, StripResultExt,
},
};
use core::fmt;
use crate::{
alloc::{vec, Box, Vec},
grammars::Grammar,
};
mod error;
pub mod grammars;
mod ops;
mod parser;
mod spans;
#[derive(Debug)]
#[non_exhaustive]
pub struct ObjectExpr<'a, T: Grammar<'a>> {
pub fields: Vec<(Spanned<'a>, Option<SpannedExpr<'a, T>>)>,
}
impl<'a, T: Grammar<'a>> Clone for ObjectExpr<'a, T> {
fn clone(&self) -> Self {
Self {
fields: self.fields.clone(),
}
}
}
impl<'a, T: Grammar<'a>> PartialEq for ObjectExpr<'a, T> {
fn eq(&self, other: &Self) -> bool {
self.fields == other.fields
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Expr<'a, T: Grammar<'a>> {
Variable,
Literal(T::Lit),
FnDefinition(FnDefinition<'a, T>),
TypeCast {
value: Box<SpannedExpr<'a, T>>,
ty: Spanned<'a, T::Type>,
},
Function {
name: Box<SpannedExpr<'a, T>>,
args: Vec<SpannedExpr<'a, T>>,
},
FieldAccess {
name: Spanned<'a>,
receiver: Box<SpannedExpr<'a, T>>,
},
Method {
name: Spanned<'a>,
receiver: Box<SpannedExpr<'a, T>>,
args: Vec<SpannedExpr<'a, T>>,
},
Unary {
op: Spanned<'a, UnaryOp>,
inner: Box<SpannedExpr<'a, T>>,
},
Binary {
lhs: Box<SpannedExpr<'a, T>>,
op: Spanned<'a, BinaryOp>,
rhs: Box<SpannedExpr<'a, T>>,
},
Tuple(Vec<SpannedExpr<'a, T>>),
Block(Block<'a, T>),
Object(ObjectExpr<'a, T>),
}
impl<'a, T: Grammar<'a>> Expr<'a, T> {
pub fn binary_lhs(&self) -> Option<&SpannedExpr<'a, T>> {
match self {
Expr::Binary { ref lhs, .. } => Some(lhs),
_ => None,
}
}
pub fn binary_rhs(&self) -> Option<&SpannedExpr<'a, T>> {
match self {
Expr::Binary { ref rhs, .. } => Some(rhs),
_ => None,
}
}
pub fn ty(&self) -> ExprType {
match self {
Self::Variable => ExprType::Variable,
Self::Literal(_) => ExprType::Literal,
Self::FnDefinition(_) => ExprType::FnDefinition,
Self::TypeCast { .. } => ExprType::Cast,
Self::Tuple(_) => ExprType::Tuple,
Self::Object(_) => ExprType::Object,
Self::Block(_) => ExprType::Block,
Self::Function { .. } => ExprType::Function,
Self::FieldAccess { .. } => ExprType::FieldAccess,
Self::Method { .. } => ExprType::Method,
Self::Unary { .. } => ExprType::Unary,
Self::Binary { .. } => ExprType::Binary,
}
}
}
impl<'a, T: Grammar<'a>> Clone for Expr<'a, T> {
fn clone(&self) -> Self {
match self {
Self::Variable => Self::Variable,
Self::Literal(lit) => Self::Literal(lit.clone()),
Self::FnDefinition(function) => Self::FnDefinition(function.clone()),
Self::TypeCast { value, ty } => Self::TypeCast {
value: value.clone(),
ty: ty.clone(),
},
Self::Tuple(tuple) => Self::Tuple(tuple.clone()),
Self::Object(statements) => Self::Object(statements.clone()),
Self::Block(block) => Self::Block(block.clone()),
Self::Function { name, args } => Self::Function {
name: name.clone(),
args: args.clone(),
},
Self::FieldAccess { name, receiver } => Self::FieldAccess {
name: *name,
receiver: receiver.clone(),
},
Self::Method {
name,
receiver,
args,
} => Self::Method {
name: *name,
receiver: receiver.clone(),
args: args.clone(),
},
Self::Unary { op, inner } => Self::Unary {
op: *op,
inner: inner.clone(),
},
Self::Binary { op, lhs, rhs } => Self::Binary {
op: *op,
lhs: lhs.clone(),
rhs: rhs.clone(),
},
}
}
}
impl<'a, T> PartialEq for Expr<'a, T>
where
T: Grammar<'a>,
T::Lit: PartialEq,
T::Type: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Variable, Self::Variable) => true,
(Self::Literal(this), Self::Literal(that)) => this == that,
(Self::FnDefinition(this), Self::FnDefinition(that)) => this == that,
(
Self::TypeCast { value, ty },
Self::TypeCast {
value: other_value,
ty: other_ty,
},
) => value == other_value && ty == other_ty,
(Self::Tuple(this), Self::Tuple(that)) => this == that,
(Self::Object(this), Self::Object(that)) => this == that,
(Self::Block(this), Self::Block(that)) => this == that,
(
Self::Function { name, args },
Self::Function {
name: that_name,
args: that_args,
},
) => name == that_name && args == that_args,
(
Self::FieldAccess { name, receiver },
Self::FieldAccess {
name: that_name,
receiver: that_receiver,
},
) => name == that_name && receiver == that_receiver,
(
Self::Method {
name,
receiver,
args,
},
Self::Method {
name: that_name,
receiver: that_receiver,
args: that_args,
},
) => name == that_name && receiver == that_receiver && args == that_args,
(
Self::Unary { op, inner },
Self::Unary {
op: that_op,
inner: that_inner,
},
) => op == that_op && inner == that_inner,
(
Self::Binary { lhs, op, rhs },
Self::Binary {
lhs: that_lhs,
op: that_op,
rhs: that_rhs,
},
) => op == that_op && lhs == that_lhs && rhs == that_rhs,
_ => false,
}
}
}
pub type SpannedExpr<'a, T> = Spanned<'a, Expr<'a, T>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ExprType {
Variable,
Literal,
FnDefinition,
Cast,
Function,
FieldAccess,
Method,
Unary,
Binary,
Tuple,
Object,
Block,
}
impl fmt::Display for ExprType {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(match self {
Self::Variable => "variable",
Self::Literal => "literal",
Self::FnDefinition => "function definition",
Self::Cast => "type cast",
Self::Function => "function call",
Self::FieldAccess => "field access",
Self::Method => "method call",
Self::Unary => "unary operation",
Self::Binary => "binary operation",
Self::Tuple => "tuple",
Self::Object => "object",
Self::Block => "block",
})
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum LvalueLen {
Exact(usize),
AtLeast(usize),
}
impl LvalueLen {
pub fn matches(self, value: usize) -> bool {
match self {
Self::Exact(len) => value == len,
Self::AtLeast(len) => value >= len,
}
}
}
impl fmt::Display for LvalueLen {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Exact(len) => write!(formatter, "{}", len),
Self::AtLeast(len) => write!(formatter, "at least {}", len),
}
}
}
impl From<usize> for LvalueLen {
fn from(value: usize) -> Self {
Self::Exact(value)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Destructure<'a, T> {
pub start: Vec<SpannedLvalue<'a, T>>,
pub middle: Option<Spanned<'a, DestructureRest<'a, T>>>,
pub end: Vec<SpannedLvalue<'a, T>>,
}
impl<T> Destructure<'_, T> {
pub fn len(&self) -> LvalueLen {
if self.middle.is_some() {
LvalueLen::AtLeast(self.start.len() + self.end.len())
} else {
LvalueLen::Exact(self.start.len())
}
}
pub fn is_empty(&self) -> bool {
self.start.is_empty()
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum DestructureRest<'a, T> {
Unnamed,
Named {
variable: Spanned<'a>,
ty: Option<Spanned<'a, T>>,
},
}
impl<'a, T> DestructureRest<'a, T> {
pub fn to_lvalue(&self) -> Option<SpannedLvalue<'a, T>> {
match self {
Self::Named { variable, .. } => {
Some(variable.copy_with_extra(Lvalue::Variable { ty: None }))
}
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct ObjectDestructure<'a, T> {
pub fields: Vec<ObjectDestructureField<'a, T>>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ObjectDestructureField<'a, T> {
pub field_name: Spanned<'a>,
pub binding: Option<SpannedLvalue<'a, T>>,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum Lvalue<'a, T> {
Variable {
ty: Option<Spanned<'a, T>>,
},
Tuple(Destructure<'a, T>),
Object(ObjectDestructure<'a, T>),
}
impl<T> Lvalue<'_, T> {
pub fn ty(&self) -> LvalueType {
match self {
Self::Variable { .. } => LvalueType::Variable,
Self::Tuple(_) => LvalueType::Tuple,
Self::Object(_) => LvalueType::Object,
}
}
}
pub type SpannedLvalue<'a, T> = Spanned<'a, Lvalue<'a, T>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum LvalueType {
Variable,
Tuple,
Object,
}
impl fmt::Display for LvalueType {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(match self {
Self::Variable => "simple variable",
Self::Tuple => "tuple destructuring",
Self::Object => "object destructuring",
})
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Statement<'a, T: Grammar<'a>> {
Expr(SpannedExpr<'a, T>),
Assignment {
lhs: SpannedLvalue<'a, T::Type>,
rhs: Box<SpannedExpr<'a, T>>,
},
}
impl<'a, T: Grammar<'a>> Statement<'a, T> {
pub fn ty(&self) -> StatementType {
match self {
Self::Expr(_) => StatementType::Expr,
Self::Assignment { .. } => StatementType::Assignment,
}
}
}
impl<'a, T: Grammar<'a>> Clone for Statement<'a, T> {
fn clone(&self) -> Self {
match self {
Self::Expr(expr) => Self::Expr(expr.clone()),
Self::Assignment { lhs, rhs } => Self::Assignment {
lhs: lhs.clone(),
rhs: rhs.clone(),
},
}
}
}
impl<'a, T> PartialEq for Statement<'a, T>
where
T: Grammar<'a>,
T::Lit: PartialEq,
T::Type: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Expr(this), Self::Expr(that)) => this == that,
(
Self::Assignment { lhs, rhs },
Self::Assignment {
lhs: that_lhs,
rhs: that_rhs,
},
) => lhs == that_lhs && rhs == that_rhs,
_ => false,
}
}
}
pub type SpannedStatement<'a, T> = Spanned<'a, Statement<'a, T>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum StatementType {
Expr,
Assignment,
}
impl fmt::Display for StatementType {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(match self {
Self::Expr => "expression",
Self::Assignment => "variable assignment",
})
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct Block<'a, T: Grammar<'a>> {
pub statements: Vec<SpannedStatement<'a, T>>,
pub return_value: Option<Box<SpannedExpr<'a, T>>>,
}
impl<'a, T: Grammar<'a>> Clone for Block<'a, T> {
fn clone(&self) -> Self {
Self {
statements: self.statements.clone(),
return_value: self.return_value.clone(),
}
}
}
impl<'a, T> PartialEq for Block<'a, T>
where
T: Grammar<'a>,
T::Lit: PartialEq,
T::Type: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.return_value == other.return_value && self.statements == other.statements
}
}
impl<'a, T: Grammar<'a>> Block<'a, T> {
pub fn empty() -> Self {
Self {
statements: vec![],
return_value: None,
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct FnDefinition<'a, T: Grammar<'a>> {
pub args: Spanned<'a, Destructure<'a, T::Type>>,
pub body: Block<'a, T>,
}
impl<'a, T: Grammar<'a>> Clone for FnDefinition<'a, T> {
fn clone(&self) -> Self {
Self {
args: self.args.clone(),
body: self.body.clone(),
}
}
}
impl<'a, T> PartialEq for FnDefinition<'a, T>
where
T: Grammar<'a>,
T::Lit: PartialEq,
T::Type: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.args == other.args && self.body == other.body
}
}