Implemented finally

trunk
ondra05 2022-07-01 22:56:22 +02:00
parent 7e31c857bf
commit 4a2674a035
5 changed files with 26 additions and 21 deletions

View File

@ -142,6 +142,7 @@ pub enum Stmt {
}, },
Read(Assignable), Read(Assignable),
Melo(Spanned<String>), Melo(Spanned<String>),
Finally(Block),
Rlyeh, Rlyeh,
Rickroll, Rickroll,
} }

View File

@ -9,7 +9,7 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use crate::{ use crate::{
ast::{Assignable, AssignableKind, Expr, Spanned, Stmt}, ast::{Assignable, AssignableKind, Block, Expr, Spanned, Stmt},
consts::ablescript_consts, consts::ablescript_consts,
error::{Error, ErrorKind}, error::{Error, ErrorKind},
value::{Functio, Value, ValueRef, Variable}, value::{Functio, Value, ValueRef, Variable},
@ -37,6 +37,9 @@ pub struct ExecEnv {
/// (via the `read` statement). We store each of those bits as /// (via the `read` statement). We store each of those bits as
/// booleans to facilitate easy manipulation. /// booleans to facilitate easy manipulation.
read_buf: VecDeque<bool>, read_buf: VecDeque<bool>,
/// Vector of blocks to be executed at the end of the program
finalisers: Vec<Block>,
} }
/// A set of visible variable and function definitions in a single /// A set of visible variable and function definitions in a single
@ -51,6 +54,7 @@ impl Default for ExecEnv {
Self { Self {
stack: vec![Default::default()], stack: vec![Default::default()],
read_buf: Default::default(), read_buf: Default::default(),
finalisers: vec![],
} }
} }
} }
@ -99,7 +103,7 @@ impl ExecEnv {
Self { Self {
stack: vec![scope], stack: vec![scope],
read_buf: Default::default(), ..Default::default()
} }
} }
@ -115,7 +119,13 @@ impl ExecEnv {
kind: ErrorKind::TopLevelEnough, kind: ErrorKind::TopLevelEnough,
span, span,
}), }),
}?;
for block in std::mem::take(&mut self.finalisers) {
self.eval_stmts_hs(&block, true)?;
} }
Ok(())
} }
/// The same as `eval_stmts`, but report "enough" and "and again" /// The same as `eval_stmts`, but report "enough" and "and again"
@ -302,6 +312,7 @@ impl ExecEnv {
} }
} }
}, },
Stmt::Finally(block) => self.finalisers.push(block.clone()),
Stmt::Rlyeh => { Stmt::Rlyeh => {
// Maybe print a creepy error message or something // Maybe print a creepy error message or something
// here at some point. ~~Alex // here at some point. ~~Alex
@ -468,7 +479,9 @@ impl ExecEnv {
} }
}; };
} }
Functio::Eval(code) => self.eval_stmts(&crate::parser::parse(&code)?)?, Functio::Eval(code) => {
self.eval_stmts_hs(&crate::parser::parse(&code)?, false)?;
}
} }
Ok(()) Ok(())
} }

View File

@ -101,6 +101,10 @@ pub enum Token {
#[token("and again")] #[token("and again")]
AndAgain, AndAgain,
/// Run at the end of the program
#[token("finally")]
Finally,
/// Crash with random error (see discussion #17) /// Crash with random error (see discussion #17)
#[token("rlyeh")] #[token("rlyeh")]
Rlyeh, Rlyeh,

View File

@ -70,9 +70,10 @@ impl<'source> Parser<'source> {
Token::Functio => self.functio_flow(), Token::Functio => self.functio_flow(),
Token::Bff => self.bff_flow(), Token::Bff => self.bff_flow(),
Token::Melo => self.melo_flow(), Token::Melo => self.melo_flow(),
Token::Loop => self.loop_flow(), Token::Loop => self.get_block().map(|body| Stmt::Loop { body }),
Token::Enough => self.semicolon_terminated(Stmt::Enough), Token::Enough => self.semicolon_terminated(Stmt::Enough),
Token::AndAgain => self.semicolon_terminated(Stmt::AndAgain), Token::AndAgain => self.semicolon_terminated(Stmt::AndAgain),
Token::Finally => self.get_block().map(Stmt::Finally),
Token::Rlyeh => self.semicolon_terminated(Stmt::Rlyeh), Token::Rlyeh => self.semicolon_terminated(Stmt::Rlyeh),
Token::Rickroll => self.semicolon_terminated(Stmt::Rickroll), Token::Rickroll => self.semicolon_terminated(Stmt::Rickroll),
@ -149,7 +150,7 @@ impl<'source> Parser<'source> {
let next = self.checked_next()?; let next = self.checked_next()?;
Ok(Expr::Aint(Box::new(self.parse_expr(next, buf)?))) Ok(Expr::Aint(Box::new(self.parse_expr(next, buf)?)))
} }
Token::Plus Token::Plus
| Token::Minus | Token::Minus
| Token::Star | Token::Star
@ -558,15 +559,6 @@ impl<'source> Parser<'source> {
self.semicolon_terminated(Stmt::Melo(ident)) self.semicolon_terminated(Stmt::Melo(ident))
} }
/// Parse loop flow
///
/// `loop` is an infinite loop, no condition, only body
fn loop_flow(&mut self) -> Result<Stmt, Error> {
Ok(Stmt::Loop {
body: self.get_block()?,
})
}
/// Perform lang -> script substitution if in T-Dark block /// Perform lang -> script substitution if in T-Dark block
fn tdark_subst(&self, mut string: String) -> String { fn tdark_subst(&self, mut string: String) -> String {
if self.tdark { if self.tdark {

View File

@ -18,8 +18,9 @@ use std::{
pub type Cart = HashMap<Value, ValueRef>; pub type Cart = HashMap<Value, ValueRef>;
/// AbleScript Value /// AbleScript Value
#[derive(Debug, Clone)] #[derive(Debug, Default, Clone)]
pub enum Value { pub enum Value {
#[default]
Nul, Nul,
Undefined, Undefined,
Str(String), Str(String),
@ -29,12 +30,6 @@ pub enum Value {
Cart(Cart), Cart(Cart),
} }
impl Default for Value {
fn default() -> Self {
Self::Nul
}
}
impl Hash for Value { impl Hash for Value {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
discriminant(self).hash(state); discriminant(self).hash(state);