ast.rs 13.62 KiB
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))]
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))]
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),
}
#[derive(Clone)]
#[cfg_attr(any(feature = "debug-ast", test), derive(Debug))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
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))]
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))]
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))]
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))]
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))]
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))]
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))]
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(any(feature = "debug-ast", test), 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(any(feature = "debug-ast", test), 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(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
);