use std::{collections::HashMap, fmt::Display};
use super::{ParserError, Tokens, Val as InternalVal};
use crate::{
NEWLINE,
parser::{StreamMessage, value::PsString},
};
#[derive(Debug, Clone, PartialEq)]
pub enum PsValue {
Null,
Bool(bool),
Int(i64),
Float(f64),
Char(u32),
String(String),
Array(Vec<PsValue>),
HashTable(HashMap<String, PsValue>),
}
impl core::fmt::Display for PsString {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl PsValue {
pub fn is_true(&self) -> bool {
match self {
PsValue::Bool(b) => *b,
PsValue::Int(i) => *i != 0,
PsValue::Float(f) => *f != 0.0,
PsValue::Char(c) => *c != 0,
PsValue::String(s) => !s.is_empty(),
PsValue::Array(arr) => !arr.is_empty(),
PsValue::HashTable(hash) => !hash.is_empty(),
PsValue::Null => false,
}
}
}
impl From<char> for PsValue {
fn from(c: char) -> Self {
PsValue::Char(c as u32)
}
}
impl From<String> for PsValue {
fn from(s: String) -> Self {
PsValue::String(s)
}
}
impl Display for PsValue {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let val: InternalVal = self.clone().into();
write!(f, "{}", val)
}
}
impl From<PsValue> for InternalVal {
fn from(val: PsValue) -> Self {
match val {
PsValue::Null => InternalVal::Null,
PsValue::Bool(b) => InternalVal::Bool(b),
PsValue::Int(i) => InternalVal::Int(i),
PsValue::Float(f) => InternalVal::Float(f),
PsValue::Char(c) => InternalVal::Char(c),
PsValue::String(s) => InternalVal::String(PsString(s)),
PsValue::Array(arr) => {
InternalVal::Array(arr.iter().map(|v| v.clone().into()).collect())
}
PsValue::HashTable(hash) => InternalVal::HashTable(
hash.iter()
.map(|(k, v)| (k.clone(), v.clone().into()))
.collect(),
),
}
}
}
impl From<InternalVal> for PsValue {
fn from(val: InternalVal) -> Self {
match val {
InternalVal::Null => PsValue::Null,
InternalVal::Bool(b) => PsValue::Bool(b),
InternalVal::Int(i) => PsValue::Int(i),
InternalVal::Float(f) => PsValue::Float(f),
InternalVal::Char(c) => PsValue::Char(c),
InternalVal::String(PsString(s)) => PsValue::String(s),
InternalVal::Array(arr) => {
PsValue::Array(arr.iter().map(|v| v.clone().into()).collect())
}
InternalVal::HashTable(hash) => PsValue::HashTable(
hash.iter()
.map(|(k, v)| (k.clone(), v.clone().into()))
.collect(),
),
InternalVal::RuntimeObject(obj) => PsValue::String(obj.to_string()),
InternalVal::RuntimeType(obj) => PsValue::String(obj.describe()),
InternalVal::ScriptBlock(sb) => PsValue::String(sb.raw_text),
InternalVal::ScriptText(st) => PsValue::String(st.clone()),
InternalVal::NonDisplayed(box_val) => (*box_val).into(),
}
}
}
#[derive(Debug)]
pub struct ScriptResult {
result: PsValue,
stream: Vec<String>,
evaluated_statements: Vec<String>,
tokens: Tokens,
errors: Vec<ParserError>,
script_values: HashMap<String, PsValue>,
}
impl ScriptResult {
pub(crate) fn new(
result: InternalVal,
stream: Vec<StreamMessage>,
evaluated_statements: Vec<String>,
tokens: Tokens,
errors: Vec<ParserError>,
script_values: HashMap<String, PsValue>,
) -> Self {
Self {
result: result.into(),
stream: stream
.iter()
.map(|msg| msg.to_string())
.collect::<Vec<String>>(),
evaluated_statements,
tokens,
errors,
script_values,
}
}
pub fn result(&self) -> PsValue {
self.result.clone()
}
pub fn deobfuscated_lines(&self) -> Vec<String> {
self.evaluated_statements.clone()
}
pub fn deobfuscated(&self) -> String {
self.evaluated_statements.join(NEWLINE)
}
pub fn tokens(&self) -> Tokens {
self.tokens.clone()
}
pub fn errors(&self) -> Vec<ParserError> {
self.errors.clone()
}
pub fn output(&self) -> String {
self.stream.join(NEWLINE)
}
pub fn output_lines(&self) -> Vec<String> {
self.stream.clone()
}
pub fn script_variables(&self) -> HashMap<String, PsValue> {
self.script_values.clone()
}
}