able-script/ablescript/src/ast.rs

213 lines
5 KiB
Rust
Raw Normal View History

//! 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 crate::{base_55::char2num, variables::Value};
2022-04-02 07:13:49 -05:00
use std::{fmt::Debug, hash::Hash};
2021-06-06 14:09:18 -05:00
type Span = std::ops::Range<usize>;
2022-04-01 18:22:46 -05:00
#[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() {
2022-04-01 18:42:13 -05:00
write!(f, "{:#?} @ {:?}", self.item, self.span)
2022-04-01 18:22:46 -05:00
} else {
2022-04-01 18:42:13 -05:00
write!(f, "{:?} @ {:?}", self.item, self.span)
}
2022-04-01 18:22:46 -05:00
}
}
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, PartialEq, Clone, Hash)]
pub struct Assignable {
2022-04-01 18:34:25 -05:00
pub ident: Spanned<String>,
pub kind: AssignableKind,
}
#[derive(Debug, PartialEq, Clone, Hash)]
pub enum AssignableKind {
Variable,
2022-04-01 18:34:25 -05:00
Index { indices: Vec<Spanned<Expr>> },
}
pub struct InvalidAssignable;
2021-10-21 13:51:24 -05:00
impl Assignable {
2022-04-01 18:34:25 -05:00
pub fn from_expr(expr: Spanned<Expr>) -> Result<Assignable, InvalidAssignable> {
2022-04-01 18:22:46 -05:00
match expr.item {
2022-04-01 18:34:25 -05:00
Expr::Variable(ident) => Ok(Assignable {
ident: Spanned::new(ident, expr.span),
2021-10-21 13:51:24 -05:00
kind: AssignableKind::Variable,
}),
2022-04-01 18:34:25 -05:00
Expr::Index { expr, index } => Self::from_index(*expr, *index),
_ => Err(InvalidAssignable),
2021-10-21 13:51:24 -05:00
}
}
2022-04-02 07:13:49 -05:00
fn from_index(
mut buf: Spanned<Expr>,
index: Spanned<Expr>,
) -> Result<Assignable, InvalidAssignable> {
2021-10-21 13:51:24 -05:00
let mut indices = vec![index];
let ident = loop {
2022-04-01 18:22:46 -05:00
match buf.item {
2022-04-01 18:34:25 -05:00
Expr::Variable(ident) => break ident,
Expr::Index { expr, index } => {
2021-10-21 13:51:24 -05:00
indices.push(*index);
buf = *expr;
}
_ => return Err(InvalidAssignable),
2021-10-21 13:51:24 -05:00
}
};
indices.reverse();
Ok(Assignable {
2022-04-01 18:34:25 -05:00
ident: Spanned::new(ident, buf.span),
2021-10-21 13:51:24 -05:00
kind: AssignableKind::Index { indices },
})
}
}
2022-04-01 18:34:25 -05:00
pub type Block = Vec<Spanned<Stmt>>;
2021-06-06 14:09:18 -05:00
/// A syntactic unit expressing an effect.
2021-08-07 17:33:28 -05:00
#[derive(Debug, PartialEq, Clone, Hash)]
2022-04-01 18:34:25 -05:00
pub enum Stmt {
2021-06-06 14:09:18 -05:00
// Control flow
2022-04-18 14:42:26 -05:00
Unless {
2022-04-01 18:34:25 -05:00
cond: Spanned<Expr>,
2021-06-06 14:09:18 -05:00
body: Block,
},
Loop {
body: Block,
},
Break,
HopBack,
Dim {
2022-04-01 18:34:25 -05:00
ident: Spanned<String>,
init: Option<Spanned<Expr>>,
2021-06-06 14:09:18 -05:00
},
Assign {
assignable: Assignable,
2022-04-01 18:34:25 -05:00
value: Spanned<Expr>,
},
2021-06-06 14:09:18 -05:00
Functio {
2022-04-01 18:34:25 -05:00
ident: Spanned<String>,
params: Vec<Spanned<String>>,
2021-06-06 14:09:18 -05:00
body: Block,
},
2021-06-11 10:52:47 -05:00
BfFunctio {
2022-04-01 18:34:25 -05:00
ident: Spanned<String>,
tape_len: Option<Spanned<Expr>>,
2021-06-11 11:10:11 -05:00
code: Vec<u8>,
2021-06-11 10:52:47 -05:00
},
2021-06-06 14:09:18 -05:00
Call {
2022-04-01 18:34:25 -05:00
expr: Spanned<Expr>,
args: Vec<Spanned<Expr>>,
2021-06-06 14:09:18 -05:00
},
2022-04-01 18:34:25 -05:00
Print(Spanned<Expr>),
Read(Assignable),
2022-04-01 18:34:25 -05:00
Melo(Spanned<String>),
2021-06-07 04:07:50 -05:00
Rlyeh,
2021-06-13 20:40:42 -05:00
Rickroll,
2021-06-06 14:09:18 -05:00
}
/// Expression is parse unit which do not cause any effect,
/// like math and logical operations or values.
2021-08-07 17:33:28 -05:00
#[derive(Debug, PartialEq, Clone, Hash)]
2022-04-01 18:34:25 -05:00
pub enum Expr {
BinOp {
2022-04-01 18:34:25 -05:00
lhs: Box<Spanned<Expr>>,
rhs: Box<Spanned<Expr>>,
2021-06-06 14:09:18 -05:00
kind: BinOpKind,
},
2022-04-08 10:39:14 -05:00
Aint(Box<Spanned<Expr>>),
Literal(Literal),
2022-04-01 18:34:25 -05:00
Cart(Vec<(Spanned<Expr>, Spanned<Expr>)>),
2021-07-27 04:51:05 -05:00
Index {
2022-04-01 18:34:25 -05:00
expr: Box<Spanned<Expr>>,
index: Box<Spanned<Expr>>,
2021-07-27 04:51:05 -05:00
},
2022-04-01 18:34:25 -05:00
Len(Box<Spanned<Expr>>),
2022-04-25 07:56:35 -05:00
Keys(Box<Spanned<Expr>>),
Variable(String),
2021-06-06 14:09:18 -05:00
}
#[derive(Debug, PartialEq, Clone, Hash)]
pub enum Literal {
Char(char),
Int(isize),
Str(String),
}
impl From<Literal> for Value {
fn from(lit: Literal) -> Self {
match lit {
Literal::Char(c) => Self::Int(char2num(c)),
Literal::Int(i) => Self::Int(i),
Literal::Str(s) => Self::Str(s),
}
}
}
2021-08-07 17:33:28 -05:00
#[derive(Debug, PartialEq, Clone, Hash)]
2021-06-06 14:09:18 -05:00
pub enum BinOpKind {
Add,
Subtract,
Multiply,
Divide,
Greater,
Less,
Equal,
NotEqual,
}
2021-06-07 02:17:18 -05:00
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::Equals => Ok(Self::Equal),
2022-04-08 10:44:35 -05:00
Token::Aint => Ok(Self::NotEqual),
t => Err(crate::error::ErrorKind::UnexpectedToken(t)),
2021-06-07 02:17:18 -05:00
}
}
}