Want to contribute? Fork me on Codeberg.org!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

237 lines
8.0 KiB

use debug_cell::RefCell;
use std::{collections::HashMap, rc::Rc};
use super::{
command::{parse_command, AssignType, Command},
control::{parse_control, Control},
event::Event,
token::Token,
Pair, Rule,
};
pub struct CommandBlock {
parent: Option<Rc<RefCell<CommandBlock>>>,
control: Option<Control>,
elements: Vec<BlockElement>,
next: Option<usize>,
pub variables: Rc<RefCell<HashMap<String, Token>>>,
}
pub struct CommandContext {
pub context: Rc<RefCell<CommandBlock>>,
pub command: Command,
}
impl CommandContext {
pub fn execute(&self) -> Option<Event> {
use AssignType::*;
use Command::*;
Some(
match &self.command {
Say { name, text } => Event::Say {
name: name.clone(),
text: text.clone(),
},
Command::Assign {
assign_type,
variable,
value,
} => match assign_type {
Define => panic!("define command should not be executed at runtime!"),
GlobalAssign => {
if let Token::Keyword(_) = value {
todo!("assignment variable interpolation isn't implemented");
}
let root = self.context.borrow().get_root(&self.context);
// Don't want to re-borrow if root is self
let root = if Rc::ptr_eq(&self.context, &root) {
&self.context
} else {
&root
};
root.borrow_mut()
.variables
.as_ref()
.borrow_mut()
.insert(variable.clone(), value.clone());
return None;
}
Let => {
if let Token::Keyword(_) = value {
todo!("assignment variable interpolation isn't implemented");
}
self.context
.borrow()
.variables
.borrow_mut()
.insert(variable.clone(), value.clone());
return None;
}
Assign => {
if let Token::Keyword(_) = value {
todo!("assignment variable interpolation isn't implemented");
}
todo!("local variable assignment isn't implemented")
}
},
Eat { .. } => return None,
}
.process(&self.context),
)
}
}
impl CommandBlock {
pub fn next(&mut self, self_rc: &Rc<RefCell<Self>>) -> Option<CommandContext> {
let mut next = match self.next {
Some(next) => next,
None => return None,
};
if !self.evaluate_control() {
return None;
}
let mut result = None;
let count = self.elements.len();
for element in &mut self.elements[next..] {
match element {
BlockElement::Command(command) => {
result = Some(CommandContext {
context: self_rc.clone(),
command: command.clone(),
});
next += 1;
break;
}
BlockElement::Block(block) => match block.borrow_mut().next(block) {
Some(context_command) => {
result = Some(context_command);
break;
}
None => {
next += 1;
}
},
};
}
self.next = if count >= next { Some(next) } else { None };
result
}
fn evaluate_control(&self) -> bool {
use Control::*;
self.control.as_ref().map_or(true, |control| match control {
If { condition } => *condition,
})
}
pub fn get_variables(&self) -> HashMap<String, Token> {
let variables = self.variables.borrow().clone();
if let Some(parent) = &self.parent {
let mut parent_variables = parent.borrow().get_variables();
parent_variables.extend(variables.into_iter());
parent_variables
} else {
variables
}
}
pub fn get_root(&self, self_rc: &Rc<RefCell<Self>>) -> Rc<RefCell<Self>> {
if let Some(parent) = &self.parent {
parent.borrow().get_root(parent)
} else {
self_rc.clone()
}
}
}
impl Default for CommandBlock {
fn default() -> Self {
Self {
parent: None,
control: None,
elements: Vec::new(),
next: Some(0),
variables: Rc::new(RefCell::new(HashMap::new())),
}
}
}
enum BlockElement {
Command(Command),
Block(Rc<RefCell<CommandBlock>>),
}
pub fn parse_block(
pair: Pair,
definitions: Option<Rc<RefCell<HashMap<String, Token>>>>,
) -> Rc<RefCell<CommandBlock>> {
//let variables: HashMap<String, Token> = HashMap::new();
let is_root = definitions.is_none();
let definitions = definitions.unwrap_or(Rc::new(RefCell::new(HashMap::new())));
let block_rc = Rc::new(RefCell::new(CommandBlock {
variables: if is_root {
definitions.clone()
} else {
Default::default()
},
..Default::default()
}));
{
let mut block = block_rc.borrow_mut();
block.elements = {
let mut control = None;
let mut elements = Vec::new();
for pair in pair.into_inner() {
elements.push(match pair.as_rule() {
Rule::Control => {
if control.is_some() {
panic!("control statement should not be empty");
}
control = Some(parse_control(pair));
continue;
}
Rule::Line => BlockElement::Command(match parse_command(pair) {
Command::Assign {
variable,
value,
assign_type: AssignType::Define,
} => {
let mut value = value;
if let Token::Keyword(keyword) = value {
value = definitions
.borrow()
.get(&keyword)
.unwrap_or_else(|| panic!("undefined variable `{keyword}`"))
.clone();
}
definitions.borrow_mut().insert(variable, value);
continue;
}
command => command,
}),
Rule::Block => BlockElement::Block({
let subblock_rc = parse_block(pair, Some(definitions.clone()));
{
let mut subblock = subblock_rc.borrow_mut();
if control.is_none() {
panic!("block should have control");
}
subblock.parent = Some(block_rc.clone());
subblock.control = control;
control = None;
}
subblock_rc
}),
Rule::EOI => break, // end
_ => unreachable!(),
});
}
elements
};
if is_root {
block.variables = definitions;
}
}
block_rc
}