Skip to content
Snippets Groups Projects
ast.rs 9.85 KiB
Newer Older
Louis's avatar
Louis committed
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()
	}
}
Louis's avatar
Louis committed
impl ExpressionList {
	pub fn empty() -> Self {
		ExpressionList {
			expressions: Vec::new(),
			is_void: true,
		}
	}
Louis's avatar
Louis committed
	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)]
Louis's avatar
Louis committed
#[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)]
Louis's avatar
Louis committed
#[cfg_attr(
	feature = "serde",
	derive(serde::Serialize, serde::Deserialize),
	serde(rename_all = "snake_case")
)]
pub enum BinaryOp {
	Add,
	Subtract,
	Multiply,
	Divide,
	Modulo,
	Equals,
Louis's avatar
Louis committed
	NotEquals,
	LessThan,
	GreaterThan,
	LessThanEqual,
	GreaterThanEqual,
}

impl BinaryOp {
	pub fn short_circuits(&self) -> bool {
		match self {
			Self::BoolAnd | Self::BoolOr => true,
			_ => false,
		}
	}
Louis's avatar
Louis committed
}

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 => "||",
Louis's avatar
Louis committed
				BinaryOp::NotEquals => "!=",
				BinaryOp::LessThan => "<",
				BinaryOp::GreaterThan => ">",
				BinaryOp::LessThanEqual => "<=",
				BinaryOp::GreaterThanEqual => ">=",
Louis's avatar
Louis committed
			}
		)
	}
}

#[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),
Louis's avatar
Louis committed
	FunctionCall(FunctionCall),
Louis's avatar
Louis committed
	DeclareFunction(DeclareFunction),
#[derive(Clone)]
#[cfg_attr(feature = "debug-ast", derive(Debug))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TypeofValue(pub Box<ValueExpression>);

Louis's avatar
Louis committed
#[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>;
Louis's avatar
Louis committed
pub type ParameterList = Vec<ValueExpression>;
Louis's avatar
Louis committed

#[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),
}
Louis's avatar
Louis committed

Louis's avatar
Louis committed
#[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,
}

Louis's avatar
Louis committed
#[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,
}
Louis's avatar
Louis committed

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
);