use crate::runtime::numbers::Number; use crate::runtime::value::ForgeValue; use std::fmt::{Display, Formatter}; use std::ops::Deref; pub trait AstNode {} #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct Program(pub ExpressionList); impl AstNode for Program {} #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct ExpressionList { pub expressions: Vec<Expression>, pub is_void: bool, } impl Default for ExpressionList { fn default() -> Self { ExpressionList::empty() } } impl ExpressionList { pub fn empty() -> Self { ExpressionList { expressions: Vec::new(), is_void: true, } } pub fn production(expressions: Vec<Expression>) -> Self { ExpressionList { expressions, is_void: false, } } pub fn voided(expressions: Vec<Expression>) -> Self { ExpressionList { expressions, is_void: true, } } } impl Deref for ExpressionList { type Target = Vec<Expression>; fn deref(&self) -> &Self::Target { &self.expressions } } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "node_type", content = "node_value", rename_all = "snake_case") )] pub enum Expression { #[cfg_attr(feature = "serde", serde(rename = "value_expression"))] Value(ValueExpression), #[cfg_attr(feature = "serde", serde(rename = "void_expression"))] Void(VoidExpression), } #[derive(Clone, Eq, Copy, PartialEq, Debug)] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub enum UnaryOp { Not, Negate, } impl Display for UnaryOp { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, "{}", match self { Self::Not => "!", Self::Negate => "-", } ) } } #[derive(Clone, Eq, Copy, PartialEq, Debug)] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub enum BinaryOp { Add, Subtract, Multiply, Divide, Modulo, Equals, BoolAnd, BoolOr, NotEquals, LessThan, GreaterThan, LessThanEqual, GreaterThanEqual, } impl BinaryOp { pub fn short_circuits(&self) -> bool { match self { Self::BoolAnd | Self::BoolOr => true, _ => false, } } } impl Display for BinaryOp { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, "{}", match self { BinaryOp::Add => "+", BinaryOp::Subtract => "-", BinaryOp::Multiply => "*", BinaryOp::Divide => "/", BinaryOp::Modulo => "%", BinaryOp::Equals => "==", BinaryOp::BoolAnd => "&&", BinaryOp::BoolOr => "||", BinaryOp::NotEquals => "!=", BinaryOp::LessThan => "<", BinaryOp::GreaterThan => ">", BinaryOp::LessThanEqual => "<=", BinaryOp::GreaterThanEqual => ">=", } ) } } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "node_type", content = "node_value", rename_all = "snake_case") )] pub enum VoidExpression { ConditionLoop(ConditionalLoop), Import(Import), Export(Export), Print(Print), Return(Return), } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct GroupedExpression { pub inner: Box<ValueExpression>, } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "node_type", content = "node_value", rename_all = "snake_case") )] pub enum ValueExpression { Unary { operator: UnaryOp, operand: Box<ValueExpression>, }, Binary { lhs: Box<ValueExpression>, rhs: Box<ValueExpression>, operator: BinaryOp, }, Grouped(GroupedExpression), Block(ExpressionList), Literal(LiteralNode), DeclareIdentifier(DeclareIdent), Assignment(Assignment), ConditionalBlock(Conditional), Identifier(Identifier), FunctionCall(FunctionCall), DeclareFunction(DeclareFunction), Typeof(TypeofValue), Accessor(AccessorPath), } impl ValueExpression { pub fn add(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::Add, } } pub fn sub(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::Subtract, } } pub fn mul(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::Multiply, } } pub fn div(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::Divide, } } pub fn modulo(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::Modulo, } } pub fn equals(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::Equals, } } pub fn bool_and(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::BoolAnd, } } pub fn bool_or(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::BoolOr, } } pub fn not_equals(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::NotEquals, } } pub fn less_than(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::LessThan, } } pub fn greater_than(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::GreaterThan, } } pub fn less_than_equal(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::LessThanEqual, } } pub fn greater_than_equal(lhs: ValueExpression, rhs: ValueExpression) -> Self { ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::GreaterThanEqual, } } } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct TypeofValue(pub Box<ValueExpression>); #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct ConditionalLoop { pub block: GuardedBlock, pub fallback: Option<ExpressionList>, } impl ConditionalLoop { pub fn expr_while(block: GuardedBlock) -> Self { Self { block, fallback: None, } } pub fn expr_while_else(block: GuardedBlock, fallback: ExpressionList) -> Self { Self { block, fallback: Some(fallback), } } } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct Conditional { pub blocks: Vec<GuardedBlock>, pub fallback: Option<ExpressionList>, } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct GuardedBlock { pub guard: Box<ValueExpression>, pub block: ExpressionList, } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct Import { pub source: String, pub items: IdentifierList, } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct Export { pub items: IdentifierList, } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct Print { pub expr: Box<ValueExpression>, } impl From<ValueExpression> for Print { fn from(value: ValueExpression) -> Self { Print { expr: Box::new(value), } } } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct Return { pub expr: Box<ValueExpression>, } impl From<ValueExpression> for Return { fn from(value: ValueExpression) -> Self { Return { expr: Box::new(value), } } } pub type IdentifierList = Vec<IdentifierNode>; pub type ParameterList = Vec<ValueExpression>; #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct Identifier(pub String); impl Display for Identifier { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } } /// Alias an identifier, to create a new way of referring to it /// IdentifierAlias(original, alias) => identifier "as" alias #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct IdentifierAlias(pub String, pub String); impl Display for IdentifierAlias { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{} as {}", self.0, self.1) } } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "node_type", content = "node_value", rename_all = "snake_case") )] pub enum IdentifierNode { Direct(Identifier), Alias(IdentifierAlias), } impl Display for IdentifierNode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Self::Direct(val) => val.fmt(f), Self::Alias(val) => val.fmt(f), } } } impl IdentifierNode { pub fn get_name(&self) -> &str { match self { Self::Direct(value) => &value.0, Self::Alias(value) => &value.1, } } pub fn get_base(&self) -> &str { match self { Self::Direct(value) => &value.0, Self::Alias(value) => &value.0, } } } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "node_type", content = "node_value", rename_all = "snake_case") )] pub enum LiteralNode { Number(Number), String(String), Boolean(bool), Null, } impl Display for LiteralNode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Self::Boolean(val) => write!(f, "{}", val), Self::Number(val) => write!(f, "{}", val), Self::String(val) => write!(f, r#""{}""#, val), Self::Null => write!(f, "null"), } } } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct Assignment { pub ident: Identifier, pub value: Box<ValueExpression>, } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "node_type", content = "node_value", rename_all = "snake_case") )] pub enum DeclareIdent { WithValue(Assignment), WithoutValue(Identifier), } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct DeclareFunction { pub ident: Identifier, pub params: Vec<DeclareIdent>, pub body: ExpressionList, } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct FunctionCall { pub name: Identifier, pub params: ParameterList, } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "node_type", content = "node_value", rename_all = "snake_case") )] pub enum AccessorType { Identifier(Identifier), FunctionCall(FunctionCall), } #[derive(Clone)] #[cfg_attr(any(feature = "debug-ast", test), derive(Debug))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case") )] pub struct AccessorPath { pub initialiser: Box<ValueExpression>, pub path: Vec<AccessorType>, } macro_rules! impl_into_void_expr { ($($type: ty => $variant: expr),+) => { $( impl From<$type> for VoidExpression { fn from(other: $type) -> Self { $variant(other) } } )+ }; } macro_rules! impl_into_value_expr { ($($type: ty => $variant: expr),+) => { $( impl From<$type> for ValueExpression { fn from(other: $type) -> Self { $variant(other) } } )+ }; } impl_into_value_expr!( GroupedExpression => ValueExpression::Grouped, ExpressionList => ValueExpression::Block, LiteralNode => ValueExpression::Literal, DeclareIdent => ValueExpression::DeclareIdentifier, Assignment => ValueExpression::Assignment, Conditional => ValueExpression::ConditionalBlock, Identifier => ValueExpression::Identifier, FunctionCall => ValueExpression::FunctionCall, DeclareFunction => ValueExpression::DeclareFunction, TypeofValue => ValueExpression::Typeof, AccessorPath => ValueExpression::Accessor ); impl_into_void_expr!( Print => VoidExpression::Print, ConditionalLoop => VoidExpression::ConditionLoop, Import => VoidExpression::Import, Export => VoidExpression::Export, Return => VoidExpression::Return );