use std::{
collections::BTreeMap,
fmt,
hash::{Hash, Hasher},
iter::IntoIterator,
ops::Deref,
str::FromStr,
};
use crate::diagnostic::Span;
use crate::path::{OwnedTargetPath, OwnedValuePath, PathPrefix};
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
use ordered_float::NotNan;
use super::{Error, template_string::TemplateString};
#[derive(Clone, Eq, Ord, PartialOrd)]
pub struct Node<T> {
pub(crate) span: Span,
pub(crate) node: T,
}
impl<T> Node<T> {
pub fn map<R>(self, mut f: impl FnMut(T) -> R) -> Node<R> {
let Node { span, node } = self;
Node {
span,
node: f(node),
}
}
pub fn map_option<R>(self, mut f: impl FnMut(T) -> Option<R>) -> Option<Node<R>> {
let Node { span, node } = self;
let node = f(node)?;
Some(Node { span, node })
}
pub fn new(span: Span, node: T) -> Self {
Self { span, node }
}
pub fn span(&self) -> Span {
self.span
}
pub fn start(&self) -> usize {
self.span.start()
}
pub fn end(&self) -> usize {
self.span.end()
}
pub fn inner(&self) -> &T {
&self.node
}
pub fn take(self) -> (Span, T) {
(self.span, self.node)
}
pub fn into_inner(self) -> T {
self.node
}
pub fn into_spanned(self) -> (usize, T, usize) {
let Self { span, node } = self;
(span.start(), node, span.end())
}
pub fn as_deref(&self) -> &T::Target
where
T: Deref,
{
self.as_ref()
}
}
impl<T: fmt::Debug> fmt::Debug for Node<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.node.fmt(f)
}
}
impl<T: fmt::Display> fmt::Display for Node<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.node.fmt(f)
}
}
impl<T> Deref for Node<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.node
}
}
impl<T> AsRef<T> for Node<T> {
fn as_ref(&self) -> &T {
&self.node
}
}
impl<T: PartialEq> PartialEq for Node<T> {
fn eq(&self, other: &Self) -> bool {
self.node == other.node && self.span == other.span
}
}
impl<T: Hash> Hash for Node<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.node.hash(state);
self.span.hash(state);
}
}
#[derive(Clone, PartialEq)]
pub struct Program(pub Vec<Node<RootExpr>>);
impl fmt::Debug for Program {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for expr in &self.0 {
writeln!(f, "{expr:?}")?;
}
Ok(())
}
}
impl fmt::Display for Program {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for expr in &self.0 {
writeln!(f, "{expr}")?;
}
Ok(())
}
}
impl Deref for Program {
type Target = [Node<RootExpr>];
fn deref(&self) -> &Self::Target {
self.0.as_slice()
}
}
impl IntoIterator for Program {
type Item = Node<RootExpr>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone, PartialEq)]
pub enum RootExpr {
Expr(Node<Expr>),
Error(Error),
}
impl fmt::Debug for RootExpr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use RootExpr::{Error, Expr};
let value = match self {
Expr(v) => format!("{v:?}"),
Error(v) => format!("{v:?}"),
};
write!(f, "RootExpr({value})")
}
}
impl fmt::Display for RootExpr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use RootExpr::{Error, Expr};
match self {
Expr(v) => v.fmt(f),
Error(v) => v.fmt(f),
}
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone, PartialEq)]
pub enum Expr {
Literal(Node<Literal>),
Container(Node<Container>),
IfStatement(Node<IfStatement>),
Op(Node<Op>),
Assignment(Node<Assignment>),
Query(Node<Query>),
FunctionCall(Node<FunctionCall>),
Variable(Node<Ident>),
Unary(Node<Unary>),
Abort(Node<Abort>),
Return(Node<Return>),
}
impl fmt::Debug for Expr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Expr::{
Abort, Assignment, Container, FunctionCall, IfStatement, Literal, Op, Query, Return,
Unary, Variable,
};
let value = match self {
Literal(v) => format!("{v:?}"),
Container(v) => format!("{v:?}"),
Op(v) => format!("{v:?}"),
IfStatement(v) => format!("{v:?}"),
Assignment(v) => format!("{v:?}"),
Query(v) => format!("{v:?}"),
FunctionCall(v) => format!("{v:?}"),
Variable(v) => format!("{v:?}"),
Unary(v) => format!("{v:?}"),
Abort(v) => format!("{v:?}"),
Return(v) => format!("{v:?}"),
};
write!(f, "Expr({value})")
}
}
impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Expr::{
Abort, Assignment, Container, FunctionCall, IfStatement, Literal, Op, Query, Return,
Unary, Variable,
};
match self {
Literal(v) => v.fmt(f),
Container(v) => v.fmt(f),
Op(v) => v.fmt(f),
IfStatement(v) => v.fmt(f),
Assignment(v) => v.fmt(f),
Query(v) => v.fmt(f),
FunctionCall(v) => v.fmt(f),
Variable(v) => v.fmt(f),
Unary(v) => v.fmt(f),
Abort(v) => v.fmt(f),
Return(v) => v.fmt(f),
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Ident(pub(crate) String);
impl Ident {
pub fn new(ident: impl Into<String>) -> Self {
Self(ident.into())
}
#[must_use]
pub fn into_inner(self) -> String {
self.0
}
}
impl Deref for Ident {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl AsRef<str> for Ident {
fn as_ref(&self) -> &str {
&self.0
}
}
impl fmt::Display for Ident {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl fmt::Debug for Ident {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Ident({})", self.0)
}
}
impl From<String> for Ident {
fn from(ident: String) -> Self {
Ident(ident)
}
}
#[derive(Clone, PartialEq, Eq)]
pub enum Literal {
String(TemplateString),
RawString(String),
Integer(i64),
Float(NotNan<f64>),
Boolean(bool),
Regex(String),
Timestamp(String),
Null,
}
impl fmt::Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Literal::{Boolean, Float, Integer, Null, RawString, Regex, String, Timestamp};
match self {
String(v) => write!(f, r#""{v}""#),
RawString(v) => write!(f, "s'{v}'"),
Integer(v) => v.fmt(f),
Float(v) => v.fmt(f),
Boolean(v) => v.fmt(f),
Regex(v) => write!(f, "r'{v}'"),
Timestamp(v) => write!(f, "t'{v}'"),
Null => f.write_str("null"),
}
}
}
impl fmt::Debug for Literal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Literal({self})")
}
}
#[derive(Clone, PartialEq)]
pub enum Container {
Group(Box<Node<Group>>),
Block(Node<Block>),
Array(Node<Array>),
Object(Node<Object>),
}
impl fmt::Display for Container {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Container::{Array, Block, Group, Object};
match self {
Group(v) => v.fmt(f),
Block(v) => v.fmt(f),
Array(v) => v.fmt(f),
Object(v) => v.fmt(f),
}
}
}
impl fmt::Debug for Container {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Container::{Array, Block, Group, Object};
let value = match self {
Group(v) => format!("{v:?}"),
Block(v) => format!("{v:?}"),
Array(v) => format!("{v:?}"),
Object(v) => format!("{v:?}"),
};
write!(f, "Container({value})")
}
}
#[derive(Clone, PartialEq)]
pub struct Block(pub Vec<Node<Expr>>);
impl Block {
#[must_use]
pub fn into_inner(self) -> Vec<Node<Expr>> {
self.0
}
}
impl IntoIterator for Block {
type Item = Node<Expr>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl fmt::Display for Block {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("{\n")?;
let mut iter = self.0.iter().peekable();
while let Some(expr) = iter.next() {
f.write_str("\t")?;
expr.fmt(f)?;
if iter.peek().is_some() {
f.write_str("\n")?;
}
}
f.write_str("\n}")
}
}
impl fmt::Debug for Block {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Block(")?;
let mut iter = self.0.iter().peekable();
while let Some(expr) = iter.next() {
expr.fmt(f)?;
if iter.peek().is_some() {
f.write_str("; ")?;
}
}
f.write_str(")")
}
}
#[derive(Clone, PartialEq)]
pub struct Group(pub Node<Expr>);
impl Group {
#[must_use]
pub fn into_inner(self) -> Node<Expr> {
self.0
}
}
impl fmt::Display for Group {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({})", self.0)
}
}
impl fmt::Debug for Group {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Group({:?})", self.0)
}
}
#[derive(Clone, PartialEq)]
pub struct Array(pub(crate) Vec<Node<Expr>>);
impl fmt::Display for Array {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let exprs = self
.0
.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<_>>()
.join(", ");
write!(f, "[{exprs}]")
}
}
impl fmt::Debug for Array {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let exprs = self
.0
.iter()
.map(|e| format!("{e:?}"))
.collect::<Vec<_>>()
.join(", ");
write!(f, "Array([{exprs}])")
}
}
impl IntoIterator for Array {
type Item = Node<Expr>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl FromIterator<Node<Expr>> for Array {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = Node<Expr>>,
{
Self(iter.into_iter().collect())
}
}
#[derive(Clone, PartialEq)]
pub struct Object(pub(crate) BTreeMap<Node<String>, Node<Expr>>);
impl fmt::Display for Object {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let exprs = self
.0
.iter()
.map(|(k, v)| format!(r#""{k}": {v}"#))
.collect::<Vec<_>>()
.join(", ");
write!(f, "{{ {exprs} }}")
}
}
impl fmt::Debug for Object {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let exprs = self
.0
.iter()
.map(|(k, v)| format!(r#""{k}": {v:?}"#))
.collect::<Vec<_>>()
.join(", ");
write!(f, "{{ {exprs} }}")
}
}
impl IntoIterator for Object {
type Item = (Node<String>, Node<Expr>);
type IntoIter = std::collections::btree_map::IntoIter<Node<String>, Node<Expr>>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl FromIterator<(Node<String>, Node<Expr>)> for Object {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = (Node<String>, Node<Expr>)>,
{
Self(iter.into_iter().collect())
}
}
#[derive(Clone, PartialEq)]
pub struct IfStatement {
pub predicate: Node<Predicate>,
pub if_node: Node<Block>,
pub else_node: Option<Node<Block>>,
}
impl fmt::Debug for IfStatement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.else_node {
Some(alt) => write!(f, "{:?} ? {:?} : {alt:?}", self.predicate, self.if_node),
None => write!(f, "{:?} ? {:?}", self.predicate, self.if_node),
}
}
}
impl fmt::Display for IfStatement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("if ")?;
self.predicate.fmt(f)?;
f.write_str(" ")?;
self.if_node.fmt(f)?;
if let Some(alt) = &self.else_node {
f.write_str(" else")?;
alt.fmt(f)?;
}
Ok(())
}
}
#[derive(Clone, PartialEq)]
pub enum Predicate {
One(Box<Node<Expr>>),
Many(Vec<Node<Expr>>),
}
impl fmt::Display for Predicate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Predicate::One(expr) => expr.fmt(f),
Predicate::Many(exprs) => {
f.write_str("(")?;
let mut iter = exprs.iter().peekable();
while let Some(expr) = iter.next() {
expr.fmt(f)?;
if iter.peek().is_some() {
f.write_str("; ")?;
}
}
f.write_str(")")
}
}
}
}
impl fmt::Debug for Predicate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Predicate::One(expr) => write!(f, "Predicate({expr:?})"),
Predicate::Many(exprs) => {
f.write_str("Predicate(")?;
let mut iter = exprs.iter().peekable();
while let Some(expr) = iter.next() {
expr.fmt(f)?;
if iter.peek().is_some() {
f.write_str("; ")?;
}
}
f.write_str(")")
}
}
}
}
#[derive(Clone, PartialEq)]
pub struct Op(pub Box<Node<Expr>>, pub Node<Opcode>, pub Box<Node<Expr>>);
impl fmt::Display for Op {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {} {}", self.0, self.1, self.2)
}
}
impl fmt::Debug for Op {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Op({:?} {} {:?})", self.0, self.1, self.2)
}
}
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Opcode {
Mul,
Div,
Add,
Sub,
Or,
And,
Err,
Ne,
Eq,
Ge,
Gt,
Le,
Lt,
Merge,
}
impl fmt::Display for Opcode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
}
}
impl Opcode {
#[must_use]
pub fn as_str(self) -> &'static str {
use Opcode::{Add, And, Div, Eq, Err, Ge, Gt, Le, Lt, Merge, Mul, Ne, Or, Sub};
match self {
Mul => "*",
Div => "/",
Add => "+",
Sub => "-",
Merge => "|",
Or => "||",
And => "&&",
Err => "??",
Ne => "!=",
Eq => "==",
Ge => ">=",
Gt => ">",
Le => "<=",
Lt => "<",
}
}
}
impl FromStr for Opcode {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
use Opcode::{Add, And, Div, Eq, Err, Ge, Gt, Le, Lt, Merge, Mul, Ne, Or, Sub};
let op = match s {
"*" => Mul,
"/" => Div,
"+" => Add,
"-" => Sub,
"||" => Or,
"&&" => And,
"??" => Err,
"!=" => Ne,
"==" => Eq,
">=" => Ge,
">" => Gt,
"<=" => Le,
"<" => Lt,
"|" => Merge,
_ => return std::result::Result::Err(()),
};
Ok(op)
}
}
#[derive(Clone, PartialEq)]
#[allow(clippy::large_enum_variant)]
pub enum Assignment {
Single {
target: Node<AssignmentTarget>,
op: AssignmentOp,
expr: Box<Node<Expr>>,
},
Infallible {
ok: Node<AssignmentTarget>,
err: Node<AssignmentTarget>,
op: AssignmentOp,
expr: Box<Node<Expr>>,
},
}
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Clone, PartialEq, Eq)]
pub enum AssignmentOp {
Assign,
Merge,
}
impl fmt::Display for AssignmentOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use AssignmentOp::{Assign, Merge};
match self {
Assign => write!(f, "="),
Merge => write!(f, "|="),
}
}
}
impl fmt::Debug for AssignmentOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use AssignmentOp::{Assign, Merge};
match self {
Assign => write!(f, "AssignmentOp(=)"),
Merge => write!(f, "AssignmentOp(|=)"),
}
}
}
impl fmt::Display for Assignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Assignment::{Infallible, Single};
match self {
Single { target, op, expr } => write!(f, "{target} {op} {expr}"),
Infallible { ok, err, op, expr } => write!(f, "{ok}, {err} {op} {expr}"),
}
}
}
impl fmt::Debug for Assignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Assignment::{Infallible, Single};
match self {
Single { target, op, expr } => write!(f, "{target:?} {op:?} {expr:?}"),
Infallible { ok, err, op, expr } => {
write!(f, "Ok({ok:?}), Err({err:?}) {op:?} {expr:?}")
}
}
}
}
#[derive(Clone, PartialEq)]
pub enum AssignmentTarget {
Noop,
Query(Query),
Internal(Ident, Option<OwnedValuePath>),
External(Option<OwnedTargetPath>),
}
impl AssignmentTarget {
#[must_use]
pub fn to_expr(&self, span: Span) -> Expr {
match self {
AssignmentTarget::Noop => Expr::Literal(Node::new(span, Literal::Null)),
AssignmentTarget::Query(query) => Expr::Query(Node::new(span, query.clone())),
AssignmentTarget::Internal(ident, Some(path)) => Expr::Query(Node::new(
span,
Query {
target: Node::new(span, QueryTarget::Internal(ident.clone())),
path: Node::new(span, path.clone()),
},
)),
AssignmentTarget::Internal(ident, None) => {
Expr::Variable(Node::new(span, ident.clone()))
}
AssignmentTarget::External(path) => Expr::Query(Node::new(
span,
Query {
target: {
let prefix = path.as_ref().map_or(PathPrefix::Event, |x| x.prefix);
Node::new(span, QueryTarget::External(prefix))
},
path: Node::new(
span,
path.clone().map_or(OwnedValuePath::root(), |x| x.path),
),
},
)),
}
}
}
impl fmt::Display for AssignmentTarget {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use AssignmentTarget::{External, Internal, Noop, Query};
match self {
Noop => f.write_str("_"),
Query(query) => query.fmt(f),
Internal(ident, Some(path)) => write!(f, "{ident}{path}"),
Internal(ident, _) => ident.fmt(f),
External(Some(path)) => write!(f, "{path}"),
External(_) => f.write_str("."),
}
}
}
impl fmt::Debug for AssignmentTarget {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use AssignmentTarget::{External, Internal, Noop, Query};
match self {
Noop => f.write_str("Noop"),
Query(query) => query.fmt(f),
Internal(ident, Some(path)) => write!(f, "Internal({ident}{path})"),
Internal(ident, _) => write!(f, "Internal({ident})"),
External(Some(path)) => write!(f, "External({path})"),
External(_) => f.write_str("External(.)"),
}
}
}
#[derive(Clone, PartialEq)]
pub struct Query {
pub target: Node<QueryTarget>,
pub path: Node<OwnedValuePath>,
}
impl fmt::Display for Query {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}{}", self.target, self.path)
}
}
impl fmt::Debug for Query {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Query({:?}, {:?})", self.target, self.path)
}
}
#[derive(Clone, PartialEq)]
pub enum QueryTarget {
Internal(Ident),
External(PathPrefix),
FunctionCall(FunctionCall),
Container(Container),
}
impl fmt::Display for QueryTarget {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use QueryTarget::{Container, External, FunctionCall, Internal};
match self {
Internal(v) => v.fmt(f),
External(prefix) => match prefix {
PathPrefix::Event => write!(f, "."),
PathPrefix::Metadata => write!(f, "&"),
},
FunctionCall(v) => v.fmt(f),
Container(v) => v.fmt(f),
}
}
}
impl fmt::Debug for QueryTarget {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use QueryTarget::{Container, External, FunctionCall, Internal};
match self {
Internal(v) => write!(f, "Internal({v:?})"),
External(prefix) => match prefix {
PathPrefix::Event => f.write_str("External(Event)"),
PathPrefix::Metadata => f.write_str("External(Metadata)"),
},
FunctionCall(v) => v.fmt(f),
Container(v) => v.fmt(f),
}
}
}
#[derive(Clone, PartialEq)]
pub struct FunctionCall {
pub ident: Node<Ident>,
pub abort_on_error: bool,
pub arguments: Vec<Node<FunctionArgument>>,
pub closure: Option<Node<FunctionClosure>>,
}
impl fmt::Display for FunctionCall {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.ident.fmt(f)?;
f.write_str("(")?;
let mut iter = self.arguments.iter().peekable();
while let Some(arg) = iter.next() {
arg.fmt(f)?;
if iter.peek().is_some() {
f.write_str(", ")?;
}
}
f.write_str(")")?;
if let Some(closure) = &self.closure {
f.write_str(" ")?;
closure.fmt(f)?;
}
Ok(())
}
}
impl fmt::Debug for FunctionCall {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("FunctionCall(")?;
self.ident.fmt(f)?;
f.write_str("(")?;
let mut iter = self.arguments.iter().peekable();
while let Some(arg) = iter.next() {
arg.fmt(f)?;
if iter.peek().is_some() {
f.write_str(", ")?;
}
}
f.write_str(")")?;
if let Some(closure) = &self.closure {
f.write_str(" ")?;
closure.fmt(f)?;
}
f.write_str(")")
}
}
#[derive(Clone, PartialEq)]
pub struct FunctionArgument {
pub ident: Option<Node<Ident>>,
pub expr: Node<Expr>,
}
impl fmt::Display for FunctionArgument {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ident) = &self.ident {
write!(f, "{ident}: ")?;
}
self.expr.fmt(f)
}
}
impl fmt::Debug for FunctionArgument {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ident) = &self.ident {
write!(f, "Argument({ident:?}: {:?})", self.expr)
} else {
write!(f, "Argument({:?})", self.expr)
}
}
}
#[derive(Clone, PartialEq)]
pub struct FunctionClosure {
pub variables: Vec<Node<Ident>>,
pub block: Node<Block>,
}
impl fmt::Display for FunctionClosure {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("-> |")?;
let mut iter = self.variables.iter().peekable();
while let Some(var) = iter.next() {
var.fmt(f)?;
if iter.peek().is_some() {
f.write_str(", ")?;
}
}
f.write_str("| {\n")?;
let mut iter = self.block.0.iter().peekable();
while let Some(expr) = iter.next() {
f.write_str("\t")?;
expr.fmt(f)?;
if iter.peek().is_some() {
f.write_str("\n")?;
}
}
f.write_str("\n}")
}
}
impl fmt::Debug for FunctionClosure {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Closure(...)")
}
}
#[derive(Clone, PartialEq)]
pub enum Unary {
Not(Node<Not>),
}
impl fmt::Display for Unary {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Unary::Not;
match self {
Not(v) => v.fmt(f),
}
}
}
impl fmt::Debug for Unary {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Unary::Not;
let value = match self {
Not(v) => format!("{v:?}"),
};
write!(f, "Unary({value})")
}
}
#[derive(Clone, PartialEq)]
pub struct Not(pub(crate) Node<()>, pub(crate) Box<Node<Expr>>);
impl Not {
#[must_use]
pub fn take(self) -> (Node<()>, Box<Node<Expr>>) {
(self.0, self.1)
}
#[must_use]
pub fn new(span: Span, expr: Node<Expr>) -> Self {
Self(Node::new(span, ()), Box::new(expr))
}
}
impl fmt::Display for Not {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "!{}", self.1)
}
}
impl fmt::Debug for Not {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Not({:?})", self.1)
}
}
#[derive(Clone, PartialEq)]
pub struct Abort {
pub message: Option<Box<Node<Expr>>>,
}
impl fmt::Display for Abort {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(
&self
.message
.as_ref()
.map_or_else(|| "abort".to_owned(), |m| format!("abort: {m}")),
)
}
}
impl fmt::Debug for Abort {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Abort({:?})", self.message)
}
}
#[derive(Clone, PartialEq)]
pub struct Return {
pub expr: Box<Node<Expr>>,
}
impl fmt::Display for Return {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "return {}", self.expr)
}
}
impl fmt::Debug for Return {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Return({:?})", self.expr)
}
}