diff --git a/src/sb2/mod.rs b/src/sb2/mod.rs index 5a42e26..0355cfe 100644 --- a/src/sb2/mod.rs +++ b/src/sb2/mod.rs @@ -213,61 +213,239 @@ pub struct Info { pub struct TopLevelScript { pub x: f64, pub y: f64, - pub script: Script, + pub script: Vec, } -type Script = Vec; +#[derive(Debug)] +#[derive(Deserialize, Serialize)] +#[serde(untagged)] +pub enum Block { + DefineProcedure(DefineProcedure), + EBlock(EBlock), + CBlock(CBlock), + BasicBlock(BasicBlock), +} #[derive(Debug)] -pub struct Block { +pub struct BasicBlock { pub opcode: String, pub args: Vec, } -type BlockArgument = serde_json::Value; -/* +#[derive(Debug)] +pub struct CBlock { + pub opcode: String, + pub args: Vec, + pub branch: Vec, +} + +#[derive(Debug)] +pub struct EBlock { + pub opcode: String, + pub args: Vec, + pub branch0: Vec, + pub branch1: Vec, +} + +#[derive(Debug)] +#[derive(Deserialize, Serialize)] +pub struct DefineProcedure { + pub opcode: String, // always "procDef" + pub spec: String, + pub parameter_names: Vec, + pub default_arg_values: Vec, + pub run_without_screen_refresh: bool, +} + #[derive(Debug)] #[derive(Deserialize, Serialize)] #[serde(untagged)] pub enum BlockArgument { - Literal(serde_json::Value), + Boolean(bool), + Number(f64), + String(String), + Reporter(BasicBlock), } -*/ -impl<'de> Deserialize<'de> for Block { +#[derive(Debug)] +#[derive(Deserialize, Serialize)] +#[serde(untagged)] +pub enum LiteralValue { + Boolean(bool), + Number(f64), + String(String), +} + +impl From<&str> for BlockArgument { + fn from(value: &str) -> Self { + BlockArgument::String(value.to_string()) + } +} + +impl<'de> Deserialize<'de> for EBlock { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { - struct BlockVisitor; + struct EBlockVisitor; - impl<'de> Visitor<'de> for BlockVisitor { - type Value = Block; + impl<'de> Visitor<'de> for EBlockVisitor { + type Value = EBlock; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("an array containing an opcode optionally followed by inputs") + formatter.write_str("a script block with two branches (an 'E block')") } fn visit_seq(self, mut seq: A) -> Result where A: serde::de::SeqAccess<'de>, { - let opcode = seq.next_element()?.ok_or_else(|| { - de::Error::custom("could not read opcode for script block") - })?; + let opcode = seq.next_element()?.ok_or_else(|| + de::Error::custom("could not read opcode for E block") + )?; - let mut args = Vec::::with_capacity(seq.size_hint().unwrap_or(0)); - while let Some(arg) = seq.next_element::()? { + let mut args = vec![]; + let mut branches: [serde_json::Value; 2] = [ + seq.next_element()?.ok_or_else(|| + de::Error::custom("could not find first branch for E block") + )?, + seq.next_element()?.ok_or_else(|| + de::Error::custom("could not find second branch for E block") + )?, + ]; + while let Some(next_element) = seq.next_element::()? { + let arg = serde_json::from_value::(branches[0].take()).map_err(|_| + de::Error::custom("could not interpret argument for E block") + )?; args.push(arg); + branches[0] = branches[1].take(); + branches[1] = next_element; } - - Ok(Block { opcode, args }) + Ok(EBlock { + opcode, + args, + branch0: serde_json::from_value(branches[0].take()).map_err(|_| + de::Error::custom("could not interpret first branch for E block") + )?, + branch1: serde_json::from_value(branches[1].take()).map_err(|_| + de::Error::custom("could not interpret second branch for E block") + )?, + }) } } - deserializer.deserialize_seq(BlockVisitor) + deserializer.deserialize_seq(EBlockVisitor) } } -impl Serialize for Block { +impl Serialize for EBlock { + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer + { + let mut state = serializer.serialize_seq(Some(3 + self.args.len()))?; + state.serialize_element(&self.opcode)?; + for arg in &self.args { + state.serialize_element(arg)?; + } + state.serialize_element(&self.branch0)?; + state.serialize_element(&self.branch1)?; + state.end() + } +} + +impl<'de> Deserialize<'de> for CBlock { + fn deserialize(deserializer: D) -> Result + where D: serde::Deserializer<'de>, + { + struct CBlockVisitor; + + impl<'de> Visitor<'de> for CBlockVisitor { + type Value = CBlock; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a script block with one branch (a 'C block')") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de>, + { + let opcode = seq.next_element()?.ok_or_else(|| + de::Error::custom("could not read opcode for C block") + )?; + + let mut args = vec![]; + let mut branch = seq.next_element()?.ok_or_else(|| + de::Error::custom("could not find branch for C block") + )?; + while let Some(next_element) = seq.next_element::()? { + let arg = serde_json::from_value::(branch).map_err(|_| + de::Error::custom("could not interpret argument for C block") + )?; + args.push(arg); + branch = next_element; + } + Ok(CBlock { + opcode, + args, + branch: serde_json::from_value(branch).map_err(|_| + de::Error::custom("could not interpret first branch for C block") + )?, + }) + } + } + + deserializer.deserialize_seq(CBlockVisitor) + } +} + +impl Serialize for CBlock { + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer + { + let mut state = serializer.serialize_seq(Some(2 + self.args.len()))?; + state.serialize_element(&self.opcode)?; + for arg in &self.args { + state.serialize_element(arg)?; + } + state.serialize_element(&self.branch)?; + state.end() + } +} + +impl<'de> Deserialize<'de> for BasicBlock { + fn deserialize(deserializer: D) -> Result + where D: serde::Deserializer<'de>, + { + struct BasicBlockVisitor; + + impl<'de> Visitor<'de> for BasicBlockVisitor { + type Value = BasicBlock; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a script block with no branches") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de>, + { + let opcode = seq.next_element()?.ok_or_else(|| + de::Error::custom("could not read opcode for block") + )?; + + let mut args = vec![]; + while let Some(next_argument) = seq.next_element()? { + args.push(next_argument); + } + Ok(BasicBlock { + opcode, + args, + }) + } + } + + deserializer.deserialize_seq(BasicBlockVisitor) + } +} + +impl Serialize for BasicBlock { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer {