muss/mps-interpreter/src/lang/vocabulary/variable_assign.rs

225 lines
7.3 KiB
Rust

use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator;
use crate::tokens::MpsToken;
use crate::MpsContext;
use crate::lang::utility::{assert_token, assert_token_raw, assert_type, check_is_type};
use crate::lang::MpsLanguageDictionary;
use crate::lang::{
BoxedMpsOpFactory, MpsIteratorItem, MpsOp, MpsOpFactory, MpsTypePrimitive, PseudoOp,
};
use crate::lang::{RuntimeError, RuntimeOp, SyntaxError};
use crate::processing::general::MpsType;
#[derive(Debug)]
pub struct AssignStatement {
variable_name: String,
inner_statement: Option<PseudoOp>,
assign_type: Option<MpsTypePrimitive>,
context: Option<MpsContext>,
is_declaration: bool,
is_simple: bool,
}
impl Display for AssignStatement {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
if let Some(inner_statement) = &self.inner_statement {
write!(f, "{} = {}", self.variable_name, inner_statement)
} else {
write!(f, "{} = ???", self.variable_name)
}
}
}
impl std::clone::Clone for AssignStatement {
fn clone(&self) -> Self {
Self {
variable_name: self.variable_name.clone(),
inner_statement: self.inner_statement.clone(),
assign_type: self.assign_type.clone(),
context: None,
is_declaration: self.is_declaration,
is_simple: self.is_simple,
}
}
}
impl Iterator for AssignStatement {
type Item = MpsIteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if let Some(inner_statement) = &mut self.inner_statement {
if inner_statement.is_fake() {
Some(Err(RuntimeError {
line: 0,
op: (Box::new(self.clone()) as Box<dyn MpsOp>).into(),
msg: format!(
"Variable {} already assigned, cannot redo assignment",
self.variable_name
),
}))
} else {
let mut inner = inner_statement.clone();
std::mem::swap(inner_statement, &mut inner);
let real = match inner.unwrap_real() {
Ok(real) => real,
Err(e) => return Some(Err(e)),
};
let result;
if self.is_declaration {
result = self
.context
.as_mut()
.unwrap()
.variables
.declare(&self.variable_name, MpsType::Op(real));
} else {
result = self
.context
.as_mut()
.unwrap()
.variables
.assign(&self.variable_name, MpsType::Op(real));
}
match result {
Ok(_) => None,
Err(e) => Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))),
}
}
} else if !self.is_simple {
panic!(
"Assignee statement for {} is None but assignment is not simple type",
self.variable_name
)
/*Some(Err(RuntimeError {
line: 0,
op: (Box::new(self.clone()) as Box<dyn MpsOp>).into(),
msg: format!("(BUG) Assignee statement for {} is None but assignment is not simple type", self.variable_name),
}))*/
} else {
let assign_type = self.assign_type.clone().unwrap();
let result;
if self.is_declaration {
result = self
.context
.as_mut()
.unwrap()
.variables
.declare(&self.variable_name, MpsType::Primitive(assign_type));
} else {
result = self
.context
.as_mut()
.unwrap()
.variables
.assign(&self.variable_name, MpsType::Primitive(assign_type));
}
match result {
Ok(_) => None,
Err(e) => Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))),
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(1))
}
}
impl MpsOp for AssignStatement {
fn enter(&mut self, ctx: MpsContext) {
self.context = Some(ctx)
}
fn escape(&mut self) -> MpsContext {
self.context.take().unwrap()
}
fn dup(&self) -> Box<dyn MpsOp> {
Box::new(Self {
variable_name: self.variable_name.clone(),
inner_statement: self
.inner_statement
.as_ref()
.map(|x| PseudoOp::from(x.try_real_ref().unwrap().dup())),
assign_type: self.assign_type.clone(),
context: None,
is_declaration: self.is_declaration,
is_simple: self.is_simple,
})
}
}
pub struct AssignStatementFactory;
impl MpsOpFactory<AssignStatement> for AssignStatementFactory {
fn is_op(&self, tokens: &VecDeque<MpsToken>) -> bool {
(tokens.len() >= 3
&&tokens[0].is_name() // can be any (valid) variable name
&& tokens[1].is_equals())
|| (tokens.len() >= 4
&& tokens[0].is_let()
&& tokens[1].is_name() // any name
&& tokens[2].is_equals())
}
fn build_op(
&self,
tokens: &mut VecDeque<MpsToken>,
dict: &MpsLanguageDictionary,
) -> Result<AssignStatement, SyntaxError> {
// [let] variable_name = inner_statement
let is_decl = tokens[0].is_let();
if is_decl {
// variable declarations start with let, assignments do not
assert_token_raw(MpsToken::Let, tokens)?;
}
let name = assert_token(
|t| match t {
MpsToken::Name(s) => Some(s),
_ => None,
},
MpsToken::Name("variable_name".into()),
tokens,
)?;
assert_token_raw(MpsToken::Equals, tokens)?;
let is_simple_assign = check_is_type(&tokens[0]);
if is_simple_assign {
let simple_type = assert_type(tokens)?;
Ok(AssignStatement {
variable_name: name,
inner_statement: None,
assign_type: Some(simple_type),
context: None,
is_declaration: is_decl,
is_simple: true,
})
} else {
let inner_statement = dict.try_build_statement(tokens)?;
Ok(AssignStatement {
variable_name: name,
inner_statement: Some(inner_statement.into()),
assign_type: None,
context: None,
is_declaration: is_decl,
is_simple: false,
})
}
}
}
impl BoxedMpsOpFactory for AssignStatementFactory {
fn build_op_boxed(
&self,
tokens: &mut VecDeque<MpsToken>,
dict: &MpsLanguageDictionary,
) -> Result<Box<dyn MpsOp>, SyntaxError> {
self.build_box(tokens, dict)
}
fn is_op_boxed(&self, tokens: &VecDeque<MpsToken>) -> bool {
self.is_op(tokens)
}
}