use serde::{Deserialize, Serialize};
use std::hash::{Hash, Hasher};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Op {
Nop,
LoadInt(i64),
LoadFloat(f64),
LoadConst(u16), LoadTrue,
LoadFalse,
LoadUndef,
Pop,
Dup,
Dup2,
Swap,
Rot,
GetVar(u16),
SetVar(u16),
DeclareVar(u16),
GetSlot(u16),
SetSlot(u16),
GetArray(u16),
SetArray(u16),
DeclareArray(u16),
ArrayGet(u16), ArraySet(u16), ArrayPush(u16), ArrayPop(u16), ArrayShift(u16), ArrayLen(u16), MakeArray(u16),
GetHash(u16),
SetHash(u16),
DeclareHash(u16),
HashGet(u16), HashSet(u16), HashDelete(u16), HashExists(u16), HashKeys(u16), HashValues(u16), MakeHash(u16),
Add,
Sub,
Mul,
Div,
Mod,
Pow,
Negate,
Inc,
Dec,
Concat,
StringRepeat,
StringLen,
NumEq,
NumNe,
NumLt,
NumGt,
NumLe,
NumGe,
Spaceship,
StrEq,
StrNe,
StrLt,
StrGt,
StrLe,
StrGe,
StrCmp,
LogNot,
LogAnd, LogOr,
BitAnd,
BitOr,
BitXor,
BitNot,
Shl,
Shr,
Jump(usize),
JumpIfTrue(usize),
JumpIfFalse(usize),
JumpIfTrueKeep(usize), JumpIfFalseKeep(usize),
Call(u16, u8),
Return,
ReturnValue,
PushFrame,
PopFrame,
Print(u8),
PrintLn(u8),
ReadLine,
Range,
RangeStep,
MapBlock(u16),
GrepBlock(u16),
SortBlock(u16),
SortDefault, ForEachBlock(u16),
PreIncSlot(u16),
SlotLtIntJumpIfFalse(u16, i32, usize),
SlotIncLtIntJumpBack(u16, i32, usize),
AccumSumLoop(u16, u16, i32),
ConcatConstLoop(u16, u16, u16, i32),
PushIntRangeLoop(u16, u16, i32),
AddAssignSlotVoid(u16, u16),
PreIncSlotVoid(u16),
CallBuiltin(u16, u8),
Extended(u16, u8),
ExtendedWide(u16, usize),
Exec(u8),
ExecBg(u8),
PipelineBegin(u8),
PipelineStage,
PipelineEnd,
Redirect(u8, u8),
HereDoc(u16),
HereString,
CmdSubst(u16), SubshellBegin,
SubshellEnd,
ProcessSubIn(u16),
ProcessSubOut(u16),
Glob,
GlobRecursive,
TestFile(u8),
SetStatus,
GetStatus,
TrapSet(u16),
TrapCheck,
ExpandParam(u8),
WordSplit,
BraceExpand,
TildeExpand,
}
pub mod file_test {
pub const IS_FILE: u8 = 0;
pub const IS_DIR: u8 = 1;
pub const IS_READABLE: u8 = 2;
pub const IS_WRITABLE: u8 = 3;
pub const IS_EXECUTABLE: u8 = 4;
pub const EXISTS: u8 = 5;
pub const IS_NONEMPTY: u8 = 6;
pub const IS_SYMLINK: u8 = 7;
pub const IS_SOCKET: u8 = 8;
pub const IS_FIFO: u8 = 9;
pub const IS_BLOCK_DEV: u8 = 10;
pub const IS_CHAR_DEV: u8 = 11;
}
pub mod redirect_op {
pub const WRITE: u8 = 0;
pub const APPEND: u8 = 1;
pub const READ: u8 = 2;
pub const READ_WRITE: u8 = 3;
pub const CLOBBER: u8 = 4;
pub const DUP_READ: u8 = 5;
pub const DUP_WRITE: u8 = 6;
pub const WRITE_BOTH: u8 = 7;
pub const APPEND_BOTH: u8 = 8;
}
pub mod param_mod {
pub const DEFAULT: u8 = 0; pub const ASSIGN: u8 = 1; pub const ERROR: u8 = 2; pub const ALTERNATE: u8 = 3; pub const LENGTH: u8 = 4; pub const STRIP_SHORT: u8 = 5; pub const STRIP_LONG: u8 = 6; pub const RSTRIP_SHORT: u8 = 7; pub const RSTRIP_LONG: u8 = 8; pub const SUBST_FIRST: u8 = 9; pub const SUBST_ALL: u8 = 10; pub const UPPER: u8 = 11; pub const LOWER: u8 = 12; pub const UPPER_FIRST: u8 = 13; pub const LOWER_FIRST: u8 = 14; pub const INDIRECT: u8 = 15; pub const KEYS: u8 = 16; pub const SLICE: u8 = 17; }
impl Hash for Op {
fn hash<H: Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {
Op::LoadInt(n) => n.hash(state),
Op::LoadFloat(f) => f.to_bits().hash(state),
Op::LoadConst(idx) => idx.hash(state),
Op::GetVar(idx)
| Op::SetVar(idx)
| Op::DeclareVar(idx)
| Op::GetSlot(idx)
| Op::SetSlot(idx)
| Op::GetArray(idx)
| Op::SetArray(idx)
| Op::DeclareArray(idx)
| Op::ArrayGet(idx)
| Op::ArraySet(idx)
| Op::ArrayPush(idx)
| Op::ArrayPop(idx)
| Op::ArrayShift(idx)
| Op::ArrayLen(idx)
| Op::MakeArray(idx)
| Op::GetHash(idx)
| Op::SetHash(idx)
| Op::DeclareHash(idx)
| Op::HashGet(idx)
| Op::HashSet(idx)
| Op::HashDelete(idx)
| Op::HashExists(idx)
| Op::HashKeys(idx)
| Op::HashValues(idx)
| Op::MakeHash(idx)
| Op::PreIncSlot(idx)
| Op::PreIncSlotVoid(idx)
| Op::HereDoc(idx)
| Op::CmdSubst(idx)
| Op::ProcessSubIn(idx)
| Op::ProcessSubOut(idx)
| Op::TrapSet(idx)
| Op::MapBlock(idx)
| Op::GrepBlock(idx)
| Op::SortBlock(idx)
| Op::ForEachBlock(idx) => idx.hash(state),
Op::Jump(t)
| Op::JumpIfTrue(t)
| Op::JumpIfFalse(t)
| Op::JumpIfTrueKeep(t)
| Op::JumpIfFalseKeep(t) => t.hash(state),
Op::Call(name, argc) => {
name.hash(state);
argc.hash(state);
}
Op::CallBuiltin(id, argc) => {
id.hash(state);
argc.hash(state);
}
Op::Extended(id, arg) => {
id.hash(state);
arg.hash(state);
}
Op::ExtendedWide(id, payload) => {
id.hash(state);
payload.hash(state);
}
Op::Print(n) | Op::PrintLn(n) | Op::Exec(n) | Op::ExecBg(n) | Op::PipelineBegin(n) => {
n.hash(state)
}
Op::Redirect(fd, op) => {
fd.hash(state);
op.hash(state);
}
Op::TestFile(t) | Op::ExpandParam(t) => t.hash(state),
Op::SlotLtIntJumpIfFalse(slot, limit, target) => {
slot.hash(state);
limit.hash(state);
target.hash(state);
}
Op::SlotIncLtIntJumpBack(slot, limit, target) => {
slot.hash(state);
limit.hash(state);
target.hash(state);
}
Op::AccumSumLoop(sum, i, limit) => {
sum.hash(state);
i.hash(state);
limit.hash(state);
}
Op::ConcatConstLoop(c, s, i, limit) => {
c.hash(state);
s.hash(state);
i.hash(state);
limit.hash(state);
}
Op::PushIntRangeLoop(arr, i, limit) => {
arr.hash(state);
i.hash(state);
limit.hash(state);
}
Op::AddAssignSlotVoid(a, b) => {
a.hash(state);
b.hash(state);
}
Op::Nop
| Op::LoadTrue
| Op::LoadFalse
| Op::LoadUndef
| Op::Pop
| Op::Dup
| Op::Dup2
| Op::Swap
| Op::Rot
| Op::Add
| Op::Sub
| Op::Mul
| Op::Div
| Op::Mod
| Op::Pow
| Op::Negate
| Op::Inc
| Op::Dec
| Op::Concat
| Op::StringRepeat
| Op::StringLen
| Op::NumEq
| Op::NumNe
| Op::NumLt
| Op::NumGt
| Op::NumLe
| Op::NumGe
| Op::Spaceship
| Op::StrEq
| Op::StrNe
| Op::StrLt
| Op::StrGt
| Op::StrLe
| Op::StrGe
| Op::StrCmp
| Op::LogNot
| Op::LogAnd
| Op::LogOr
| Op::BitAnd
| Op::BitOr
| Op::BitXor
| Op::BitNot
| Op::Shl
| Op::Shr
| Op::Return
| Op::ReturnValue
| Op::PushFrame
| Op::PopFrame
| Op::ReadLine
| Op::Range
| Op::RangeStep
| Op::SortDefault
| Op::SetStatus
| Op::GetStatus
| Op::PipelineStage
| Op::PipelineEnd
| Op::HereString
| Op::SubshellBegin
| Op::SubshellEnd
| Op::Glob
| Op::GlobRecursive
| Op::TrapCheck
| Op::WordSplit
| Op::BraceExpand
| Op::TildeExpand => {}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_op_size() {
assert!(
std::mem::size_of::<Op>() <= 24,
"Op too large: {} bytes",
std::mem::size_of::<Op>()
);
}
}