use crate::*;
use std::hash::{DefaultHasher, Hash, Hasher};
pub fn program(program: &Program, p: &Interpreter) -> MResult<Value> {
body(&program.body, p)
}
pub fn body(body: &Body, p: &Interpreter) -> MResult<Value> {
let mut result = Ok(Value::Empty);
for sec in &body.sections {
result = Ok(section(&sec, p)?);
}
result
}
pub fn section(section: &Section, p: &Interpreter) -> MResult<Value> {
let mut result = Ok(Value::Empty);
for el in §ion.elements {
result = Ok(section_element(&el, p)?);
}
result
}
pub fn section_element(element: &SectionElement, p: &Interpreter) -> MResult<Value> {
let mut hasher = DefaultHasher::new();
let mut out = Value::Empty;
match element {
SectionElement::Prompt(x) => x.hash(&mut hasher),
SectionElement::InfoBlock(x) => x.hash(&mut hasher),
SectionElement::QuestionBlock(x) => x.hash(&mut hasher),
SectionElement::WarningBlock(x) => x.hash(&mut hasher),
SectionElement::ErrorBlock(x) => x.hash(&mut hasher),
SectionElement::IdeaBlock(x) => x.hash(&mut hasher),
SectionElement::Image(x) => x.hash(&mut hasher),
SectionElement::Float(x) => x.hash(&mut hasher),
SectionElement::Citation(x) => x.hash(&mut hasher),
SectionElement::Equation(x) => x.hash(&mut hasher),
SectionElement::Abstract(x) => x.hash(&mut hasher),
SectionElement::Diagram(x) => x.hash(&mut hasher),
SectionElement::MechCode(code) => {
for (c,cmmnt) in code {
out = mech_code(&c, p)?;
match cmmnt {
Some(cmmnt) => {
let cmmnt_value = comment(cmmnt, p)?;
}
None => {}
}
}
return Ok(out)
},
#[cfg(feature = "functions")]
SectionElement::FencedMechCode(block) => {
if block.config.disabled == true {
return Ok(Value::Empty);
}
let code_id = block.config.namespace;
if code_id == 0 {
for (c,_) in &block.code {
out = mech_code(&c, &p)?;
}
let (last_code, _) = block.code.last().unwrap();
let out_id = hash_str(&format!("{:?}", last_code));
p.out_values.borrow_mut().insert(out_id, out.clone());
} else {
let mut sub_interpreters = p.sub_interpreters.borrow_mut();
let mut new_sub_interpreter = Interpreter::new(code_id);
new_sub_interpreter.set_functions(p.functions().clone());
let mut pp = sub_interpreters
.entry(code_id)
.or_insert(Box::new(new_sub_interpreter))
.as_mut();
for (c,_) in &block.code {
out = mech_code(&c, &pp)?;
}
let (last_code,_) = block.code.last().unwrap();
let out_id = hash_str(&format!("{:?}", last_code));
pp.out_values.borrow_mut().insert(out_id, out.clone());
}
return Ok(out)
},
SectionElement::Subtitle(x) => x.hash(&mut hasher),
SectionElement::CodeBlock(x) => x.hash(&mut hasher),
SectionElement::Comment(par) => {
for el in par.paragraph.elements.iter() {
let (code_id,value) = match paragraph_element(&el, p) {
Ok(val) => val,
_ => continue,
};
p.out_values.borrow_mut().insert(code_id, value.clone());
}
return Ok(Value::Empty);
},
SectionElement::Footnote(x) => x.hash(&mut hasher),
SectionElement::Paragraph(x) => {
for el in x.elements.iter() {
let (code_id,value) = match paragraph_element(&el, p) {
Ok(val) => val,
_ => continue,
};
p.out_values.borrow_mut().insert(code_id, value.clone());
}
},
SectionElement::Grammar(x) => x.hash(&mut hasher),
SectionElement::Table(x) => {
for row in &x.rows {
for cell in row {
for el in &cell.elements {
let (code_id,value) = match paragraph_element(&el, p) {
Ok(val) => val,
_ => continue,
};
p.out_values.borrow_mut().insert(code_id, value.clone());
}
}
}
x.hash(&mut hasher);
},
SectionElement::QuoteBlock(x) => x.hash(&mut hasher),
SectionElement::ThematicBreak => {return Ok(Value::Empty);}
SectionElement::List(x) => x.hash(&mut hasher),
SectionElement::SuccessBlock(x) => x.hash(&mut hasher),
SectionElement::ErrorBlock(x) => x.hash(&mut hasher),
SectionElement::WarningBlock(x) => x.hash(&mut hasher),
SectionElement::InfoBlock(x) => x.hash(&mut hasher),
SectionElement::IdeaBlock(x) => x.hash(&mut hasher),
#[cfg(feature = "mika")]
SectionElement::Mika((m,s)) => {
return Ok(Value::Atom(Ref::new(MechAtom::from_name(&m.to_string()))));
},
x => {return Err(MechError::new(
FeatureNotEnabledError,
Some(format!("Feature not enabled for section element: {:?}", x)),
).with_compiler_loc().with_tokens(x.tokens())
);}
};
let hash = hasher.finish();
Ok(Value::Id(hash))
}
pub fn paragraph_element(element: &ParagraphElement, p: &Interpreter) -> MResult<(u64,Value)> {
let result = match element {
ParagraphElement::EvalInlineMechCode(expr) => {
let code_id = hash_str(&format!("{:?}", expr));
match expression(&expr, None, p) {
Ok(val) => (code_id,val),
Err(e) => (code_id,Value::Empty), _ => todo!(), }
}
_ => {return Err(MechError::new(
NotExecutableError{},
None
).with_compiler_loc().with_tokens(element.tokens())
);}
};
Ok(result)
}
pub fn comment(cmmt: &Comment, p: &Interpreter) -> MResult<Value> {
let par = &cmmt.paragraph;
for el in par.elements.iter() {
let (code_id,value) = match paragraph_element(&el, p) {
Ok(val) => val,
_ => continue,
};
p.out_values.borrow_mut().insert(code_id, value.clone());
}
Ok(Value::Empty)
}
pub fn mech_code(code: &MechCode, p: &Interpreter) -> MResult<Value> {
match &code {
MechCode::Expression(expr) => expression(&expr, None, p),
MechCode::Statement(stmt) => statement(&stmt, None, p),
#[cfg(feature = "functions")]
MechCode::FunctionDefine(fxn_def) => {
function_define(&fxn_def, p)?;
Ok(Value::Empty)
},
MechCode::Comment(cmmt) => comment(&cmmt, p),
x => Err(MechError::new(
FeatureNotEnabledError,
None
).with_compiler_loc().with_tokens(x.tokens())
),
}
}