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(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Program(pub ExpressionList); impl AstNode for Program {} #[derive(Clone)] #[cfg_attr(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 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(feature = "debug-ast", 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(feature = "debug-ast", 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), } #[derive(Clone)] #[cfg_attr(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct GroupedExpression { pub inner: Box<ValueExpression>, } #[derive(Clone)] #[cfg_attr(feature = "debug-ast", 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), } #[derive(Clone)] #[cfg_attr(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TypeofValue(pub Box<ValueExpression>); #[derive(Clone)] #[cfg_attr(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 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(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Conditional { pub blocks: Vec<GuardedBlock>, pub fallback: Option<ExpressionList>, } #[derive(Clone)] #[cfg_attr(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct GuardedBlock { pub guard: Box<ValueExpression>, pub block: ExpressionList, } #[derive(Clone)] #[cfg_attr(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Import { pub source: String, pub items: IdentifierList, } #[derive(Clone)] #[cfg_attr(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Export { pub items: IdentifierList, } #[derive(Clone)] #[cfg_attr(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Print { pub expr: Box<ValueExpression>, } impl From<ValueExpression> for Print { fn from(value: ValueExpression) -> Self { Print { expr: Box::new(value), } } } pub type IdentifierList = Vec<IdentifierNode>; pub type ParameterList = Vec<ValueExpression>; #[derive(Clone)] #[cfg_attr(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 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(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 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(feature = "debug-ast", 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(feature = "debug-ast", 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(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Assignment { pub ident: Identifier, pub value: Box<ValueExpression>, } #[derive(Clone)] #[cfg_attr(feature = "debug-ast", 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(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct DeclareFunction { pub ident: Identifier, pub params: Vec<DeclareIdent>, pub body: ExpressionList, } #[derive(Clone)] #[cfg_attr(feature = "debug-ast", derive(Debug))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct FunctionCall { pub name: Identifier, pub params: ParameterList, } macro_rules! impl_into_ast { ($($type: ty => $variant: expr),+) => { $( impl From<$type> for ValueExpression { fn from(other: $type) -> Self { $variant(other) } } )+ }; } impl_into_ast!( 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 );