use crate::prelude::*;
use std::collections::HashMap;
impl Runtime {
fn param_type_to_cart_dimension_obj(&self, pt: &ParamType) -> Result<Obj, RuntimeError> {
match pt {
ParamType::Obj(o) => match o {
Obj::FamilyObj(family_ty) => {
let family_name = family_ty.name.to_string();
let def = self
.get_cloned_family_definition_by_name(&family_name)
.ok_or_else(|| {
RuntimeError::new_unknown_error_with_msg_position_optional_fact_previous_error(
format!("family `{}` is not defined", family_name),
default_line_file(),
None,
None,
)
})?;
let map = ParamGroupWithParamType::param_defs_and_args_to_param_to_arg_map(
&def.params_def_with_type,
&family_ty.params,
);
self.inst_obj(&def.equal_to, &map)
}
_ => Ok(o.clone()),
},
ParamType::Struct(_)
| ParamType::Set(_)
| ParamType::NonemptySet(_)
| ParamType::FiniteSet(_) => Err(
RuntimeError::new_unknown_error_with_msg_position_optional_fact_previous_error(
"by struct: this field parameter kind cannot be used as a cart dimension yet"
.to_string(),
default_line_file(),
None,
None,
),
),
}
}
pub fn exec_by_struct_stmt(
&mut self,
stmt: &ByStructStmt,
) -> Result<StmtResult, RuntimeError> {
let stmt_exec = stmt.clone().into();
let struct_ty = match &stmt.struct_obj {
Obj::StructObj(s) => s.clone(),
_ => {
return Err(RuntimeError::from(RuntimeErrorStruct::exec_stmt_with_message_and_cause(
stmt_exec,
"by struct: expected `struct name(...)` object".to_string(),
None,
vec![],
)));
}
};
let struct_name = struct_ty.name.to_string();
let def = match self.get_cloned_definition_of_struct(&struct_name) {
Some(d) => d,
None => {
return Err(RuntimeError::from(RuntimeErrorStruct::exec_stmt_with_message_and_cause(
stmt_exec.clone(),
format!("by struct: struct `{}` is not defined", struct_name),
None,
vec![],
)));
}
};
let expected_count = ParamGroupWithStructFieldType::number_of_params(&def.param_defs);
if struct_ty.args.len() != expected_count {
return Err(RuntimeError::from(RuntimeErrorStruct::exec_stmt_with_message_and_cause(
stmt_exec,
format!(
"by struct: struct `{}` expects {} type argument(s), got {}",
struct_name,
expected_count,
struct_ty.args.len()
),
None,
vec![],
)));
}
let param_to_arg_map =
ParamGroupWithStructFieldType::param_defs_and_args_to_param_to_arg_map(
&def.param_defs,
&struct_ty.args,
);
let mut cart_dims: Vec<Obj> = Vec::with_capacity(def.fields.len());
for (_, field_st) in def.fields.iter() {
let pt = self.inst_param_type(&field_st.to_param_type(), ¶m_to_arg_map)?;
cart_dims.push(self.param_type_to_cart_dimension_obj(&pt)?);
}
let cart_obj = Obj::Cart(Cart::new(cart_dims));
let verify_state = VerifyState::new(0, false);
self.verify_obj_well_defined_and_store_cache(&stmt.struct_obj, &verify_state)
.map_err(|e| {
RuntimeError::from(RuntimeErrorStruct::exec_stmt_with_message_and_cause(
stmt_exec.clone(),
format!(
"by struct: struct type object `{}` is not well-defined",
stmt.struct_obj
),
Some(e.into()),
vec![],
))
})?;
self.verify_obj_well_defined_and_store_cache(&cart_obj, &verify_state)
.map_err(|e| {
RuntimeError::from(RuntimeErrorStruct::exec_stmt_with_message_and_cause(
stmt_exec.clone(),
format!("by struct: cart `{}` is not well-defined", cart_obj),
Some(e.into()),
vec![],
))
})?;
let random_names = self.generate_random_unused_names(2);
let forall_param = random_names[0].clone();
let set_builder_param = random_names[1].clone();
let forall_param_obj = Obj::Identifier(Identifier::new(forall_param.clone()));
let mut then_facts: Vec<ExistOrAndChainAtomicFact> = Vec::new();
then_facts.push(ExistOrAndChainAtomicFact::AtomicFact(AtomicFact::InFact(
InFact::new(
forall_param_obj.clone(),
cart_obj.clone(),
stmt.line_file.clone(),
),
)));
for (i, (field_name, _)) in def.fields.iter().enumerate() {
let idx = i + 1;
let lhs = Obj::ObjAtIndex(ObjAtIndex::new(
forall_param_obj.clone(),
Obj::Number(Number::new(idx.to_string())),
));
let rhs = Obj::FieldAccess(FieldAccess::new(forall_param.clone(), field_name.clone()));
then_facts.push(ExistOrAndChainAtomicFact::AtomicFact(
AtomicFact::EqualFact(EqualFact::new(lhs, rhs, stmt.line_file.clone())),
));
}
let forall_fact = Fact::ForallFact(ForallFact::new(
vec![ParamGroupWithParamType::new(
vec![forall_param],
ParamType::Struct(struct_ty.clone()),
)],
vec![],
then_facts,
stmt.line_file.clone(),
));
let x_obj = Obj::Identifier(Identifier::new(set_builder_param.clone()));
let mut tuple_components: Vec<Obj> =
Vec::with_capacity(def.number_of_params() + def.fields.len());
for a in struct_ty.args.iter() {
tuple_components.push(a.clone());
}
for i in 0..def.fields.len() {
tuple_components.push(Obj::ObjAtIndex(ObjAtIndex::new(
x_obj.clone(),
Obj::Number(Number::new((i + 1).to_string())),
)));
}
let self_as_tuple = Obj::Tuple(Tuple::new(tuple_components));
let mut extended_for_sb: HashMap<String, Obj> = param_to_arg_map.clone();
extended_for_sb.insert(SELF.to_string(), self_as_tuple);
self.register_param_as_struct_instance(SELF, struct_ty.clone());
let mut inst_body_facts: Vec<OrAndChainAtomicFact> = Vec::with_capacity(def.facts.len());
for fact in def.facts.iter() {
inst_body_facts.push(self.inst_or_and_chain_atomic_fact(fact, &extended_for_sb)?);
}
let set_builder = SetBuilder::new_with_mangled_name(
set_builder_param,
cart_obj.clone(),
inst_body_facts,
);
let rhs_sb_obj = Obj::SetBuilder(set_builder.clone());
self.verify_obj_well_defined_and_store_cache(&rhs_sb_obj, &verify_state)
.map_err(|e| {
RuntimeError::from(RuntimeErrorStruct::exec_stmt_with_message_and_cause(
stmt_exec.clone(),
"by struct: set-builder (right-hand side) is not well-defined".to_string(),
Some(e.into()),
vec![],
))
})?;
let definitional_eq = AtomicFact::EqualFact(EqualFact::new(
Obj::StructObj(struct_ty.clone()),
rhs_sb_obj,
stmt.line_file.clone(),
));
let mut infer_result = InferResult::new();
infer_result.push_atomic_fact(&definitional_eq);
infer_result.new_infer_result_inside(
self.store_atomic_fact_without_well_defined_verified_and_infer(definitional_eq)
.map_err(RuntimeError::from)?,
);
infer_result.new_fact(&forall_fact);
infer_result.new_infer_result_inside(
self.store_fact_without_well_defined_verified_and_infer(forall_fact)
.map_err(RuntimeError::from)?,
);
Ok((NonFactualStmtSuccess::new(stmt_exec, infer_result, vec![])).into())
}
}