diff --git a/ablescript/src/ast.rs b/ablescript/src/ast.rs index 3e62941..9ab00fe 100644 --- a/ablescript/src/ast.rs +++ b/ablescript/src/ast.rs @@ -142,6 +142,7 @@ pub enum Stmt { }, Read(Assignable), Melo(Spanned), + Finally(Block), Rlyeh, Rickroll, } diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index b0d7444..aef62ea 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -9,7 +9,7 @@ #![deny(missing_docs)] use crate::{ - ast::{Assignable, AssignableKind, Expr, Spanned, Stmt}, + ast::{Assignable, AssignableKind, Block, Expr, Spanned, Stmt}, consts::ablescript_consts, error::{Error, ErrorKind}, value::{Functio, Value, ValueRef, Variable}, @@ -37,6 +37,9 @@ pub struct ExecEnv { /// (via the `read` statement). We store each of those bits as /// booleans to facilitate easy manipulation. read_buf: VecDeque, + + /// Vector of blocks to be executed at the end of the program + finalisers: Vec, } /// A set of visible variable and function definitions in a single @@ -51,6 +54,7 @@ impl Default for ExecEnv { Self { stack: vec![Default::default()], read_buf: Default::default(), + finalisers: vec![], } } } @@ -99,7 +103,7 @@ impl ExecEnv { Self { stack: vec![scope], - read_buf: Default::default(), + ..Default::default() } } @@ -115,7 +119,13 @@ impl ExecEnv { kind: ErrorKind::TopLevelEnough, 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" @@ -302,6 +312,7 @@ impl ExecEnv { } } }, + Stmt::Finally(block) => self.finalisers.push(block.clone()), Stmt::Rlyeh => { // Maybe print a creepy error message or something // 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(()) } diff --git a/ablescript/src/lexer.rs b/ablescript/src/lexer.rs index cb39439..ca5e67c 100644 --- a/ablescript/src/lexer.rs +++ b/ablescript/src/lexer.rs @@ -101,6 +101,10 @@ pub enum Token { #[token("and again")] AndAgain, + /// Run at the end of the program + #[token("finally")] + Finally, + /// Crash with random error (see discussion #17) #[token("rlyeh")] Rlyeh, diff --git a/ablescript/src/parser.rs b/ablescript/src/parser.rs index 4967275..22003ce 100644 --- a/ablescript/src/parser.rs +++ b/ablescript/src/parser.rs @@ -70,9 +70,10 @@ impl<'source> Parser<'source> { Token::Functio => self.functio_flow(), Token::Bff => self.bff_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::AndAgain => self.semicolon_terminated(Stmt::AndAgain), + Token::Finally => self.get_block().map(Stmt::Finally), Token::Rlyeh => self.semicolon_terminated(Stmt::Rlyeh), Token::Rickroll => self.semicolon_terminated(Stmt::Rickroll), @@ -149,7 +150,7 @@ impl<'source> Parser<'source> { let next = self.checked_next()?; Ok(Expr::Aint(Box::new(self.parse_expr(next, buf)?))) } - + Token::Plus | Token::Minus | Token::Star @@ -558,15 +559,6 @@ impl<'source> Parser<'source> { self.semicolon_terminated(Stmt::Melo(ident)) } - /// Parse loop flow - /// - /// `loop` is an infinite loop, no condition, only body - fn loop_flow(&mut self) -> Result { - Ok(Stmt::Loop { - body: self.get_block()?, - }) - } - /// Perform lang -> script substitution if in T-Dark block fn tdark_subst(&self, mut string: String) -> String { if self.tdark { diff --git a/ablescript/src/value/mod.rs b/ablescript/src/value/mod.rs index c7998a0..3c1dfe7 100644 --- a/ablescript/src/value/mod.rs +++ b/ablescript/src/value/mod.rs @@ -18,8 +18,9 @@ use std::{ pub type Cart = HashMap; /// AbleScript Value -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] pub enum Value { + #[default] Nul, Undefined, Str(String), @@ -29,12 +30,6 @@ pub enum Value { Cart(Cart), } -impl Default for Value { - fn default() -> Self { - Self::Nul - } -} - impl Hash for Value { fn hash(&self, state: &mut H) { discriminant(self).hash(state);