use std::fmt::Display;
use super::*;
use crate::InputString;
use crate::VarName;
impl Default for Card {
fn default() -> Self {
Card::Pass
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Card {
Pass,
Add,
Sub,
Mul,
Div,
CopyLast,
Less,
LessOrEq,
Equals,
NotEquals,
Pop,
ClearStack,
And,
Or,
Xor,
Not,
Return,
ScalarNil,
CreateTable,
Abort,
Len,
SetProperty,
GetProperty,
ScalarInt(IntegerNode),
ScalarFloat(FloatNode),
StringLiteral(StringNode),
CallNative(Box<CallNode>),
IfTrue(Box<Card>),
IfFalse(Box<Card>),
IfElse {
then: Box<Card>,
r#else: Box<Card>,
},
Jump(LaneNode),
SetGlobalVar(VarNode),
SetVar(VarNode),
ReadVar(VarNode),
Repeat(LaneNode),
While(LaneNode),
ForEach {
variable: VarNode,
lane: LaneNode,
},
CompositeCard(Box<CompositeCard>),
Noop,
}
impl Card {
pub fn name(&self) -> &str {
match self {
Card::SetVar(_) => "SetLocalVar",
Card::Pass => "Pass",
Card::Add => "Add",
Card::Sub => "Sub",
Card::CreateTable => "CreateTable",
Card::Mul => "Mul",
Card::Div => "Div",
Card::CopyLast => "CopyLast",
Card::Not => "Not",
Card::Less => "Less",
Card::LessOrEq => "LessOrEq",
Card::Equals => "Equals",
Card::NotEquals => "NotEquals",
Card::Pop => "Pop",
Card::And => "And",
Card::Or => "Either",
Card::Xor => "Exclusive Or",
Card::Abort => "Abort",
Card::Len => "Len",
Card::ScalarInt(_) => "ScalarInt",
Card::ScalarFloat(_) => "ScalarFloat",
Card::StringLiteral(_) => "StringLiteral",
Card::CallNative(_) => "Call",
Card::IfTrue(_) => "IfTrue",
Card::IfFalse(_) => "IfFalse",
Card::Jump(_) => "Jump",
Card::SetGlobalVar(_) => "SetGlobalVar",
Card::ReadVar(_) => "ReadVar",
Card::ClearStack => "ClearStack",
Card::ScalarNil => "ScalarNil",
Card::Return => "Return",
Card::Repeat(_) => "Repeat",
Card::While(_) => "While",
Card::IfElse { .. } => "IfElse",
Card::GetProperty => "GetProperty",
Card::SetProperty => "SetProperty",
Card::ForEach { .. } => "ForEach",
Card::CompositeCard(c) => c.name.as_str(),
Card::Noop => "No-op",
}
}
pub(crate) fn instruction(&self) -> Option<Instruction> {
match self {
Card::IfElse { .. }
| Card::ReadVar(_)
| Card::SetVar(_)
| Card::While(_)
| Card::Repeat(_)
| Card::ForEach { .. }
| Card::CompositeCard { .. }
| Card::Noop => None,
Card::GetProperty => Some(Instruction::GetProperty),
Card::SetProperty => Some(Instruction::SetProperty),
Card::CreateTable => Some(Instruction::InitTable),
Card::And => Some(Instruction::And),
Card::Abort => Some(Instruction::Exit),
Card::Not => Some(Instruction::Not),
Card::Or => Some(Instruction::Or),
Card::Xor => Some(Instruction::Xor),
Card::Pass => Some(Instruction::Pass),
Card::Add => Some(Instruction::Add),
Card::Sub => Some(Instruction::Sub),
Card::Mul => Some(Instruction::Mul),
Card::Div => Some(Instruction::Div),
Card::CopyLast => Some(Instruction::CopyLast),
Card::Less => Some(Instruction::Less),
Card::LessOrEq => Some(Instruction::LessOrEq),
Card::Equals => Some(Instruction::Equals),
Card::NotEquals => Some(Instruction::NotEquals),
Card::Pop => Some(Instruction::Pop),
Card::ScalarInt(_) => Some(Instruction::ScalarInt),
Card::ScalarFloat(_) => Some(Instruction::ScalarFloat),
Card::CallNative(_) => Some(Instruction::Call),
Card::IfTrue(_) => None,
Card::IfFalse(_) => None,
Card::Jump(_) => Some(Instruction::CallLane),
Card::StringLiteral(_) => Some(Instruction::StringLiteral),
Card::SetGlobalVar(_) => Some(Instruction::SetGlobalVar),
Card::ClearStack => Some(Instruction::ClearStack),
Card::ScalarNil => Some(Instruction::ScalarNil),
Card::Return => Some(Instruction::Return),
Card::Len => Some(Instruction::Len),
}
}
#[allow(unused)]
fn __instruction_to_node(instr: Instruction) {
match instr {
Instruction::SetGlobalVar
| Instruction::Len
| Instruction::ReadGlobalVar
| Instruction::GetProperty
| Instruction::SetProperty
| Instruction::Pop
| Instruction::Less
| Instruction::LessOrEq
| Instruction::Equals
| Instruction::NotEquals
| Instruction::Exit
| Instruction::InitTable
| Instruction::StringLiteral
| Instruction::CallLane
| Instruction::CopyLast
| Instruction::Call
| Instruction::Sub
| Instruction::Mul
| Instruction::Div
| Instruction::ClearStack
| Instruction::ScalarFloat
| Instruction::And
| Instruction::Not
| Instruction::Or
| Instruction::Xor
| Instruction::ScalarInt
| Instruction::Add
| Instruction::ScalarNil
| Instruction::Return
| Instruction::SwapLast
| Instruction::ReadLocalVar
| Instruction::SetLocalVar
| Instruction::Goto
| Instruction::GotoIfTrue
| Instruction::GotoIfFalse
| Instruction::Repeat
| Instruction::BeginRepeat
| Instruction::ForEach
| Instruction::BeginForEach
| Instruction::Pass => {}
};
}
pub fn as_card_list(&self) -> Option<smallvec::SmallVec<[&Card; 4]>> {
let mut res = smallvec::smallvec![];
match self {
Self::CompositeCard(c) => {
res.extend(c.cards.iter());
}
Self::IfTrue(c) | Self::IfFalse(c) => res.push(c.as_ref()),
Self::IfElse { then, r#else } => {
res.push(then.as_ref());
res.push(r#else.as_ref());
}
_ => return None,
}
Some(res)
}
pub fn as_card_list_mut(&mut self) -> Option<smallvec::SmallVec<[&mut Card; 4]>> {
let mut res = smallvec::smallvec![];
match self {
Self::CompositeCard(c) => {
res.extend(c.cards.iter_mut());
}
Self::IfTrue(c) | Self::IfFalse(c) => res.push(c.as_mut()),
Self::IfElse { then, r#else } => {
res.push(then.as_mut());
res.push(r#else.as_mut());
}
_ => return None,
}
Some(res)
}
pub fn as_composite_card(&self) -> Option<&CompositeCard> {
if let Self::CompositeCard(v) = self {
Some(v)
} else {
None
}
}
pub fn as_composite_card_mut(&mut self) -> Option<&mut CompositeCard> {
if let Self::CompositeCard(v) = self {
Some(v)
} else {
None
}
}
pub fn composite_card(name: String, ty: String, cards: Vec<Card>) -> Self {
Self::CompositeCard(Box::new(CompositeCard { name, ty, cards }))
}
pub fn string_card(s: impl Into<String>) -> Self {
Self::StringLiteral(StringNode(s.into()))
}
pub fn get_card_by_index_mut(&mut self, i: usize) -> Option<&mut Card> {
let res;
match self {
Card::CompositeCard(c) => res = c.cards.get_mut(i)?,
Card::IfTrue(c) | Card::IfFalse(c) => {
if i != 0 {
return None;
}
res = c;
}
Card::IfElse { then, r#else } => {
if i > 1 {}
match i {
0 => res = then.as_mut(),
1 => res = r#else.as_mut(),
_ => return None,
}
}
_ => return None,
}
Some(res)
}
pub fn get_card_by_index(&self, i: usize) -> Option<&Card> {
let res;
match self {
Card::CompositeCard(c) => res = c.cards.get(i)?,
Card::IfTrue(c) | Card::IfFalse(c) => {
if i != 0 {
return None;
}
res = c;
}
Card::IfElse { then, r#else } => {
if i > 1 {}
match i {
0 => res = then.as_ref(),
1 => res = r#else.as_ref(),
_ => return None,
}
}
_ => return None,
}
Some(res)
}
pub fn remove_child(&mut self, i: usize) -> Option<Card> {
let res;
match self {
Card::CompositeCard(c) => {
if c.cards.len() <= i {
return None;
}
res = c.cards.remove(i);
}
Card::IfTrue(c) | Card::IfFalse(c) => {
if i != 0 {
return None;
}
res = std::mem::replace::<Card>(c.as_mut(), Card::Noop);
}
Card::IfElse { then, r#else } => {
if i > 1 {}
match i {
0 => res = std::mem::replace::<Card>(then.as_mut(), Card::Noop),
1 => res = std::mem::replace::<Card>(r#else.as_mut(), Card::Noop),
_ => return None,
}
}
_ => return None,
}
Some(res)
}
pub fn insert_child(&mut self, i: usize, card: Self) -> Result<(), Self> {
match self {
Card::CompositeCard(c) => {
if c.cards.len() < i {
return Err(card);
}
c.cards.insert(i, card);
}
Card::IfTrue(c) | Card::IfFalse(c) => {
if i != 0 {
return Err(card);
}
*c.as_mut() = card;
}
Card::IfElse { then, r#else } => {
if i > 1 {}
match i {
0 => *then.as_mut() = card,
1 => *r#else.as_mut() = card,
_ => return Err(card),
};
}
_ => return Err(card),
}
Ok(())
}
pub fn replace_child(&mut self, i: usize, card: Self) -> Result<Self, Self> {
let res = match self {
Card::CompositeCard(c) => match c.cards.get_mut(i) {
Some(c) => std::mem::replace(c, card),
None => return Err(card),
},
Card::IfTrue(c) | Card::IfFalse(c) => {
if i != 0 {
return Err(card);
}
std::mem::replace(c.as_mut(), card)
}
Card::IfElse { then, r#else } => match i {
0 => std::mem::replace(then.as_mut(), card),
1 => std::mem::replace(r#else.as_mut(), card),
_ => return Err(card),
},
_ => return Err(card),
};
Ok(res)
}
}
#[derive(Debug, Clone, Default, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IntegerNode(pub i64);
#[derive(Debug, Clone, Default, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FloatNode(pub f64);
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CallNode(pub InputString);
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SubProgramNode(pub InputString);
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StringNode(pub String);
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VarNode(pub Box<VarName>);
impl VarNode {
pub fn from_str_unchecked(s: &str) -> Self {
Self(Box::new(
VarName::from(s).expect("Failed to parse variable name"),
))
}
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LaneNode(pub String);
impl Display for LaneNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<LaneNode> for Handle {
fn from(ln: LaneNode) -> Self {
Self::from(&ln)
}
}
impl<'a> From<&'a LaneNode> for Handle {
fn from(ln: &'a LaneNode) -> Self {
Handle::from_str(ln.0.as_str()).unwrap()
}
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CompositeCard {
pub name: String,
pub ty: String,
pub cards: Vec<Card>,
}