Skip to content

Commit

Permalink
Implement Blueprint structural representation
Browse files Browse the repository at this point in the history
  • Loading branch information
tifv committed Jul 10, 2024
1 parent f3c803f commit b2f6a5d
Show file tree
Hide file tree
Showing 7 changed files with 578 additions and 67 deletions.
42 changes: 21 additions & 21 deletions src/blueprint/behavior.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
value::{Key, Value, Table, ArrayBuilder as TableArrayBuilder},
};

use super::instruction::Instruction;
use super::Instruction;

#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct Behavior {
Expand Down Expand Up @@ -113,45 +113,45 @@ impl BehaviorBuilder {
fn err_unexpected_key(key: Key) -> LoadError { LoadError::from(format!(
"behavior representation should not have {key:?} key" )) }

fn set_name(&mut self, name: Value) -> Result<(), LoadError> {
let Value::String(name) = name else {
fn set_name(&mut self, value: Value) -> Result<(), LoadError> {
let Value::String(value) = value else {
return Err(LoadError::from(
"behavor's name should be a string" ));
};
self.name = Some(name); Ok(())
self.name = Some(value); Ok(())
}

fn set_description(&mut self, description: Value) -> Result<(), LoadError> {
let Value::String(description) = description else {
fn set_description(&mut self, value: Value) -> Result<(), LoadError> {
let Value::String(value) = value else {
return Err(LoadError::from(
"behavor's description should be a string" ));
};
self.description = Some(description); Ok(())
self.description = Some(value); Ok(())
}

fn set_parameters(&mut self, parameters: Value) -> Result<(), LoadError> {
let Value::Table(parameters) = parameters else {
fn set_parameters(&mut self, value: Value) -> Result<(), LoadError> {
let Value::Table(table) = value else {
return Err(Self::err_parameters());
};
for value in parameters.into_continuous_iter() {
let value = value.map_err(|_error| Self::err_parameters())?;
let Value::Boolean(value) = value else {
for item in table.into_continuous_iter() {
let item = item.map_err(|_error| Self::err_parameters())?;
let Value::Boolean(is_output) = item else {
return Err(Self::err_parameters());
};
self.parameters.push(Parameter { is_output: value, name: None });
self.parameters.push(Parameter { is_output, name: None });
}
Ok(())
}
fn err_parameters() -> LoadError { LoadError::from(
"behavior's parameters should be \
a continuous array of booleans" ) }

fn set_parameter_names(&mut self, parameter_names: Value)
fn set_parameter_names(&mut self, value: Value)
-> Result<(), LoadError> {
let Value::Table(parameter_names) = parameter_names else {
let Value::Table(table) = value else {
return Err(Self::err_param_names());
};
self.parameter_names = Some(parameter_names);
self.parameter_names = Some(table);
Ok(())
}

Expand Down Expand Up @@ -183,14 +183,14 @@ impl BehaviorBuilder {
"behavior's parameter names should be \
an array of strings or nils" ) }

fn set_subroutines(&mut self, subroutines: Value)
fn set_subroutines(&mut self, value: Value)
-> Result<(), LoadError> {
let Value::Table(subroutines) = subroutines else {
let Value::Table(table) = value else {
return Err(Self::err_subroutines());
};
for value in subroutines.into_continuous_iter() {
let value = value.map_err(|_error| Self::err_subroutines())?;
self.subroutines.push(Behavior::try_from(value)?);
for item in table.into_continuous_iter() {
let item = item.map_err(|_error| Self::err_subroutines())?;
self.subroutines.push(Behavior::try_from(item)?);
}
Ok(())
}
Expand Down
26 changes: 12 additions & 14 deletions src/blueprint/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
value::{Key, Value, Table, ArrayBuilder as TableArrayBuilder},
};

use super::operand::{Operand, Jump};
use super::{Operand, Jump};

#[derive(Debug, Clone)]
pub struct Instruction {
Expand Down Expand Up @@ -62,23 +62,26 @@ impl InstructionBuilder {
// of arguments, and all of them can be None. But if
// we do not limit the number of arguments somehow, we can be
// tricked out of memory by a very large index.
let max_index = i32::try_from(table.len() * 2 + 256)
.unwrap_or(i32::MAX);
let max_index = i32::try_from(
table.len().saturating_mul(2).saturating_add(256)
).unwrap_or(i32::MAX);
for (key, value) in table {
match key {
Key::Index(index) if (1 ..= max_index).contains(&index)
=> {
Key::Index(index) if index > max_index => {
return Err(LoadError::from(
"unrealistically large number \
of instruction arguments" ))
},
Key::Index(index) if index < 1 =>
return Err(Self::err_unexpected_key(key)),
Key::Index(index) => {
let Ok(index) = usize::try_from(index - 1)
else { unreachable!(); };
if array.len() <= index {
array.resize_with(index + 1, || None);
}
array[index] = Some(value);
},
Key::Index(index) if index <= 0 =>
return Err(Self::err_unexpected_key(key)),
Key::Index(index) =>
return Err(Self::err_non_continuous(index)),
Key::Name(name) => match name.as_ref() {
"op" => this.set_operation (value)?,
"next" => this.set_next (value)?,
Expand All @@ -100,11 +103,6 @@ impl InstructionBuilder {
this.build()
}

fn err_non_continuous(index: i32) -> LoadError { LoadError::from(format!(
"instruction representation should have \
argument indices in a range `1..N` (for a resonable N), \
not {index:?}" )) }

fn err_unexpected_key(key: Key) -> LoadError { LoadError::from(format!(
"instruction representation should not have {key:?} key" )) }

Expand Down
Loading

0 comments on commit b2f6a5d

Please sign in to comment.