summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/assemblage.rs71
-rw-r--r--src/encyclopedia.rs4
-rw-r--r--src/parameterexpression.rs33
3 files changed, 63 insertions, 45 deletions
diff --git a/src/assemblage.rs b/src/assemblage.rs
index fb60463..773ebf0 100644
--- a/src/assemblage.rs
+++ b/src/assemblage.rs
@@ -2,7 +2,7 @@
use std::collections::HashMap;
use serde::{de, Serialize, Deserialize, Deserializer};
use crate::{
- parameterexpression::ParameterExpression,
+ parameterexpression::{ParameterExpression, EvaluationError},
parameter::{Parameter},
componentwrapper::{ComponentWrapper, ComponentType},
components::{Serialise, Clan},
@@ -23,40 +23,42 @@ pub struct Assemblage {
impl Assemblage {
pub fn validate(&self) -> AnyResult<()> {
+
+ let arguments = self.arguments.iter().filter_map(|(k, v)|Some((k.clone(), v.clone()?))).collect::<HashMap<String, Parameter>>();
for (comptype, parameters) in &self.components {
+ let mut is_complete = true;
+ let mut compargs = HashMap::new();
for paramname in comptype.parameters() {
- let _param = parameters.get(paramname).ok_or(aerr!("missing parameter {} for component {:?}", paramname, comptype))?;
- // todo: validate parameter types
+ let param = parameters.get(paramname).ok_or(aerr!("missing parameter {} for component {:?}", paramname, comptype))?;
+ match param.evaluate(&arguments, &Template::empty("")) {
+ Err(EvaluationError::MissingArgument(_)) => {is_complete = false;}
+ Err(EvaluationError::Other(msg)) => {return Err(aerr!("invalid value for {}: {}", paramname, msg))}
+ Ok(p) => {compargs.insert(paramname, p);}
+ }
+ }
+ if is_complete {
+ ComponentWrapper::load_component(*comptype, compargs)?;
}
}
Ok(())
}
- fn prepare_arguments(&self, kwargs: &HashMap<String, Parameter>) -> AnyResult<HashMap<&str, Parameter>> {
- let mut arguments: HashMap<&str, Parameter> = HashMap::new();
- for (name, def) in self.arguments.iter() {
- let param: Parameter= {
- if let Some(val) = kwargs.get(name) {
- val.clone()
- } else if let Some(val) = def {
- val.clone()
- } else {
- return Err(aerr!("argument <{:?}> has no value", (name, def)))
- }
- };
- arguments.insert(name, param);
- }
- Ok(arguments)
- }
pub fn instantiate(&self, template: &Template) -> AnyResult<Vec<ComponentWrapper>>{
- let kwargs = &template.kwargs;
+ let mut args = self.arguments.clone();
+ for (key, param) in template.kwargs.clone() {
+ // todo: warn about unknown keys
+ args.insert(key, Some(param));
+ }
+ let arguments = args.into_iter().map(|(k, v)|Ok((k.clone(), v.ok_or(aerr!("missing argument value for {}", k))?))).collect::<AnyResult<HashMap<String, Parameter>>>()?;
let mut components: Vec<ComponentWrapper> = Vec::new();
- let arguments = self.prepare_arguments(kwargs)?;
for (comptype, compparams) in &self.components {
let mut compargs: HashMap<&str, Parameter> = HashMap::new();
for (name, param) in compparams {
- compargs.insert(name.as_str(), param.evaluate(&arguments, template).ok_or(aerr!("argument not found"))?);
+ compargs.insert(name.as_str(), param.evaluate(&arguments, template).map_err(|e| match e {
+ EvaluationError::MissingArgument(arg) => aerr!("argument {} not found", arg),
+ EvaluationError::Other(msg) => aerr!("{}", msg)
+ })?);
}
components.push(ComponentWrapper::load_component(*comptype, compargs)?);
}
@@ -192,12 +194,11 @@ mod tests {
}]
]
})).unwrap_err();
-// assert_eq!(result, "not a valid componenttype");
}
-// #[test]
+ #[test]
fn invalid_parameter_type(){
Assemblage::deserialize(&json!({
"arguments": {"sprite": "grass1"},
@@ -208,14 +209,13 @@ mod tests {
"name": "grass"
}]
]
- })).unwrap_err();
-// assert_eq!(result, "parameter type incorrect");
+ })).unwrap().validate().unwrap_err();
}
-// #[test]
+ #[test]
fn wrong_argument_default(){
Assemblage::deserialize(&json!({
"arguments": {"sprite": 1},
@@ -226,8 +226,21 @@ mod tests {
"name": "grass"
}]
]
- })).unwrap_err();
-// assert_eq!(result, "invalid argument default");
+ })).unwrap().validate().unwrap_err();
+ }
+
+ #[test]
+ fn missing_argument_default(){
+ Assemblage::deserialize(&json!({
+ "arguments": {"sprite": null},
+ "components": [
+ ["Visible", {
+ "sprite": {"$arg": "sprite"},
+ "height": 0.1,
+ "name": "grass"
+ }]
+ ]
+ })).unwrap().validate().unwrap();
}
diff --git a/src/encyclopedia.rs b/src/encyclopedia.rs
index 2bb2960..76a7d28 100644
--- a/src/encyclopedia.rs
+++ b/src/encyclopedia.rs
@@ -26,8 +26,8 @@ pub struct Encyclopedia {
impl Encyclopedia {
pub fn validate(&self) -> AnyResult<()> {
- for assemblage in self.assemblages.values() {
- assemblage.validate()?;
+ for (name, assemblage) in self.assemblages.iter() {
+ assemblage.validate().map_err(|e| aerr!("invalid assemblage {}: {}", name.0, e))?;
}
Ok(())
}
diff --git a/src/parameterexpression.rs b/src/parameterexpression.rs
index c96bd93..dfba562 100644
--- a/src/parameterexpression.rs
+++ b/src/parameterexpression.rs
@@ -25,38 +25,43 @@ pub enum ParameterExpression {
TemplateName
}
+pub enum EvaluationError {
+ MissingArgument(String),
+ Other(String)
+}
+
impl ParameterExpression {
- pub fn evaluate(&self, arguments: &HashMap<&str, Parameter>, template: &Template) -> Option<Parameter> {
+ pub fn evaluate(&self, arguments: &HashMap<String, Parameter>, template: &Template) -> Result<Parameter, EvaluationError> {
self.evaluate_(arguments, template, 0)
}
- fn evaluate_(&self, arguments: &HashMap<&str, Parameter>, template: &Template, nesting: usize) -> Option<Parameter> {
+ fn evaluate_(&self, arguments: &HashMap<String, Parameter>, template: &Template, nesting: usize) -> Result<Parameter, EvaluationError> {
if nesting > MAX_NESTING {
- return None;
+ return Err(EvaluationError::Other("Maximum nesting reached in parameter evaluation".to_string()));
}
match self {
Self::Constant(val) => {
- Some(val.clone())
+ Ok(val.clone())
}
Self::List(values) => {
- Some(Parameter::List(values.iter().map(|v| v.evaluate_(arguments, template, nesting+1)).collect::<Option<Vec<Parameter>>>()?))
+ Ok(Parameter::List(values.iter().map(|v| v.evaluate_(arguments, template, nesting+1)).collect::<Result<Vec<Parameter>, EvaluationError>>()?))
}
Self::Template{name, kwargs, save, clan} => {
- Some(Parameter::Template(Template{
+ Ok(Parameter::Template(Template{
name: name.clone(),
save: *save,
kwargs: kwargs
.iter()
.map(
|(k, v)|
- Some((k.clone(), v.evaluate_(arguments, template, nesting+1)?)))
- .collect::<Option<HashMap<String, Parameter>>>()?,
+ Ok((k.clone(), v.evaluate_(arguments, template, nesting+1)?)))
+ .collect::<Result<HashMap<String, Parameter>, EvaluationError>>()?,
clan: clan.clone()
}))
}
Self::Argument(argname) => {
- Some(arguments.get(argname.as_str())?.clone())
+ Ok(arguments.get(argname.as_str()).ok_or(EvaluationError::MissingArgument(argname.to_string()))?.clone())
}
Self::Random(options) => {
let r = rand::thread_rng().gen_range(0, options.len());
@@ -68,10 +73,10 @@ impl ParameterExpression {
if let Parameter::String(s) = option.evaluate_(arguments, template, nesting+1)? {
string.push_str(&s);
} else {
- return None;
+ return Err(EvaluationError::Other(format!("string concatenation value not a string: {:?}", option)));
}
}
- Some(Parameter::String(string))
+ Ok(Parameter::String(string))
}
Self::If(condition, thenval, elseval) => {
if let Parameter::Bool(b) = condition.evaluate_(arguments, template, nesting+1)? {
@@ -81,11 +86,11 @@ impl ParameterExpression {
elseval.evaluate_(arguments, template, nesting+1)
}
} else {
- None
+ return Err(EvaluationError::Other(format!("if condition not a bool: {:?}", condition)))
}
}
- Self::TemplateSelf => Some(Parameter::Template(template.clone())),
- Self::TemplateName => Some(Parameter::String(template.name.0.clone())),
+ Self::TemplateSelf => Ok(Parameter::Template(template.clone())),
+ Self::TemplateName => Ok(Parameter::String(template.name.0.clone())),
}
}