able-script/ablescript/src/ast.rs
2022-04-02 01:22:46 +02:00

222 lines
5.1 KiB
Rust

//! AbleScript's Abstract Syntax tree
//!
//! Statements are the type which is AST made of, as they
//! express an effect.
//!
//! Expressions are just operations and they cannot be
//! used as statements. Functions in AbleScript are in fact
//! just plain subroutines and they do not return any value,
//! so their calls are statements.
use std::{fmt::Debug, hash::Hash};
use crate::variables::Value;
type Span = std::ops::Range<usize>;
#[derive(Clone)]
pub struct Spanned<T> {
pub item: T,
pub span: Span,
}
impl<T> Spanned<T> {
pub fn new(item: T, span: Span) -> Self {
Self { item, span }
}
}
impl<T: Debug> Debug for Spanned<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
write!(f, "{:#?}", self.item)
} else {
write!(f, "{:?}", self.item)
}?;
write!(f, " @ {:?}", self.span)
}
}
impl<T: PartialEq> PartialEq for Spanned<T> {
fn eq(&self, other: &Self) -> bool {
self.item == other.item
}
}
impl<T: Hash> Hash for Spanned<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.item.hash(state);
}
}
#[derive(Debug, Clone)]
pub struct Ident {
pub ident: String,
pub span: Span,
}
impl Ident {
pub fn new(ident: String, span: Span) -> Self {
Self { ident, span }
}
}
impl PartialEq for Ident {
fn eq(&self, other: &Self) -> bool {
self.ident == other.ident
}
}
impl Hash for Ident {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.ident.hash(state)
}
}
#[derive(Debug, PartialEq, Clone, Hash)]
pub struct Assignable {
pub ident: Ident,
pub kind: AssignableKind,
}
#[derive(Debug, PartialEq, Clone, Hash)]
pub enum AssignableKind {
Variable,
Index { indices: Vec<Spanned<ExprKind>> },
}
pub struct InvalidAssignable;
impl Assignable {
pub fn from_expr(expr: Spanned<ExprKind>) -> Result<Assignable, InvalidAssignable> {
match expr.item {
ExprKind::Variable(ident) => Ok(Assignable {
ident: Ident::new(ident, expr.span),
kind: AssignableKind::Variable,
}),
ExprKind::Index { expr, index } => Self::from_index(*expr, *index),
_ => Err(InvalidAssignable),
}
}
fn from_index(mut buf: Spanned<ExprKind>, index: Spanned<ExprKind>) -> Result<Assignable, InvalidAssignable> {
let mut indices = vec![index];
let ident = loop {
match buf.item {
ExprKind::Variable(ident) => break ident,
ExprKind::Index { expr, index } => {
indices.push(*index);
buf = *expr;
}
_ => return Err(InvalidAssignable),
}
};
indices.reverse();
Ok(Assignable {
ident: Ident::new(ident, buf.span),
kind: AssignableKind::Index { indices },
})
}
}
#[derive(Debug, PartialEq, Clone, Hash)]
pub struct Block {
pub block: Vec<Spanned<StmtKind>>,
}
/// A syntactic unit expressing an effect.
#[derive(Debug, PartialEq, Clone, Hash)]
pub enum StmtKind {
// Control flow
If {
cond: Spanned<ExprKind>,
body: Block,
},
Loop {
body: Block,
},
Break,
HopBack,
Var {
ident: Ident,
init: Option<Spanned<ExprKind>>,
},
Assign {
assignable: Assignable,
value: Spanned<ExprKind>,
},
Functio {
ident: Ident,
params: Vec<Ident>,
body: Block,
},
BfFunctio {
ident: Ident,
tape_len: Option<Spanned<ExprKind>>,
code: Vec<u8>,
},
Call {
expr: Spanned<ExprKind>,
args: Vec<Spanned<ExprKind>>,
},
Print(Spanned<ExprKind>),
Read(Assignable),
Melo(Ident),
Rlyeh,
Rickroll,
}
/// Expression is parse unit which do not cause any effect,
/// like math and logical operations or values.
#[derive(Debug, PartialEq, Clone, Hash)]
pub enum ExprKind {
BinOp {
lhs: Box<Spanned<ExprKind>>,
rhs: Box<Spanned<ExprKind>>,
kind: BinOpKind,
},
Not(Box<Spanned<ExprKind>>),
Literal(Value),
Cart(Vec<(Spanned<ExprKind>, Spanned<ExprKind>)>),
Index {
expr: Box<Spanned<ExprKind>>,
index: Box<Spanned<ExprKind>>,
},
Len(Box<Spanned<ExprKind>>),
Variable(String),
}
#[derive(Debug, PartialEq, Clone, Hash)]
pub enum BinOpKind {
Add,
Subtract,
Multiply,
Divide,
Greater,
Less,
Equal,
NotEqual,
}
impl BinOpKind {
pub fn from_token(t: crate::lexer::Token) -> Result<Self, crate::error::ErrorKind> {
use crate::lexer::Token;
match t {
Token::Plus => Ok(Self::Add),
Token::Minus => Ok(Self::Subtract),
Token::Star => Ok(Self::Multiply),
Token::FwdSlash => Ok(Self::Divide),
Token::GreaterThan => Ok(Self::Greater),
Token::LessThan => Ok(Self::Less),
Token::EqualEqual => Ok(Self::Equal),
Token::NotEqual => Ok(Self::NotEqual),
t => Err(crate::error::ErrorKind::UnexpectedToken(t)),
}
}
}