feat: parse scripts structurally, change Block to enum of block shapes

This commit is contained in:
Christopher Willis-Ford 2023-03-18 00:38:14 -07:00
parent 15b2fb6084
commit bbd9cce395

View file

@ -213,61 +213,239 @@ pub struct Info {
pub struct TopLevelScript {
pub x: f64,
pub y: f64,
pub script: Script,
pub script: Vec<Block>,
}
type Script = Vec<Block>;
#[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<BlockArgument>,
}
type BlockArgument = serde_json::Value;
/*
#[derive(Debug)]
pub struct CBlock {
pub opcode: String,
pub args: Vec<BlockArgument>,
pub branch: Vec<Block>,
}
#[derive(Debug)]
pub struct EBlock {
pub opcode: String,
pub args: Vec<BlockArgument>,
pub branch0: Vec<Block>,
pub branch1: Vec<Block>,
}
#[derive(Debug)]
#[derive(Deserialize, Serialize)]
pub struct DefineProcedure {
pub opcode: String, // always "procDef"
pub spec: String,
pub parameter_names: Vec<String>,
pub default_arg_values: Vec<LiteralValue>,
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<D>(deserializer: D) -> Result<Self, D::Error>
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<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
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::<BlockArgument>::with_capacity(seq.size_hint().unwrap_or(0));
while let Some(arg) = seq.next_element::<serde_json::Value>()? {
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::<serde_json::Value>()? {
let arg = serde_json::from_value::<BlockArgument>(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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<D>(deserializer: D) -> Result<Self, D::Error>
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<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
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::<serde_json::Value>()? {
let arg = serde_json::from_value::<BlockArgument>(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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<D>(deserializer: D) -> Result<Self, D::Error>
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<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer
{