use core::mem;
use alloc::{string::String, vec::Vec};
use ellie_core::defs::CursorPosition;
use crate::{
heap_memory,
raw_type::{RawType, StaticRawType, TypeId},
stack::Stack,
stack_memory,
};
#[derive(Clone, Debug)]
pub enum VmNativeCallParameters {
Static(StaticRawType),
Dynamic(RawType),
}
#[derive(Clone, Debug)]
pub struct VmNativeCall {
pub hash: usize,
pub params: Vec<VmNativeCallParameters>,
pub return_heap_position: usize,
}
#[derive(Clone, Debug)]
pub enum VmNativeAnswer {
Ok(VmNativeCallParameters),
RuntimeError(String),
}
#[derive(Debug, Clone)]
pub struct ThreadInfo {
pub id: usize,
pub stack_id: usize,
pub frame_pos: usize,
pub pos: usize,
pub stack_caller: Option<usize>,
}
impl ThreadInfo {
pub fn get_real_pos(&self) -> usize {
self.frame_pos + self.pos
}
pub fn get_real_pos_with_location(&self, pos: usize) -> usize {
self.frame_pos + pos
}
}
#[derive(Debug, Clone)]
pub enum ThreadPanicReason {
IntegerOverflow,
ByteOverflow,
PlatformOverflow,
FloatOverflow,
DoubleOverflow,
UnmergebleTypes(String, String),
UncomparableTypes(u8, u8),
StackOverflow,
BrokenStackTree(u8),
UnexpectedType(u8),
NullReference(usize),
OutOfInstructions,
RuntimeError(String),
InvalidRegisterAccess(u8),
IndexAccessViolation(u8),
IndexOutOfBounds(usize, usize),
WrongEntryLength(usize, usize),
CannotIndexWithNegative(isize),
ParameterMemoryAccessViolation(usize),
MemoryAccessViolation(usize, usize),
ImmediateUseViolation(u8),
InvalidType(u8),
IllegalAddressingValue,
CannotConvertToType(u8, u8),
CallToUnknown((String, usize)),
MissingModule(usize),
MissingTrace(usize),
ArraySizeCorruption,
ReferenceError(usize),
}
#[derive(Debug, Clone)]
pub struct StackNode {
pub stack_name: String,
pub location: CursorPosition,
pub program_counter: usize,
}
#[derive(Debug, Clone)]
pub struct ThreadPanic {
pub reason: ThreadPanicReason,
pub stack_trace: Vec<Stack>,
pub code_location: String,
}
#[derive(Debug, Clone)]
pub enum ThreadExit {
Panic(ThreadPanic),
ExitGracefully,
}
#[derive(Debug, Clone)]
pub enum StepResult {
Step,
ThreadExit(ThreadExit),
}
#[derive(Debug, Clone)]
pub struct ThreadStep {
pub instruction: crate::program::ReadInstruction,
pub stack_pos: usize,
pub stack_id: usize,
pub info: ThreadStepInfo,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ThreadStepInfo {
StepNext,
CALL(usize),
JMP(usize),
EndOfStacks,
DropStack,
}
pub enum ExitCode {
Success,
StackOverflow,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Types {
Integer,
Float,
Double,
Byte,
Bool,
String,
Char,
Array,
Void,
}
impl Types {
pub fn display(&self) -> String {
match self {
Types::Integer => String::from("Integer"),
Types::Float => String::from("Float"),
Types::Double => String::from("Double"),
Types::Byte => String::from("Byte"),
Types::Bool => String::from("Bool"),
Types::String => String::from("String"),
Types::Char => String::from("Char"),
Types::Array => String::from("Array"),
Types::Void => String::from("Void"),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum AddressingModes {
Implicit,
Immediate,
Absolute,
AbsoluteIndex,
AbsoluteProperty,
AbsoluteStatic,
IndirectA,
IndirectB,
IndirectC,
IndirectX,
IndirectY,
}
#[derive(Clone, Copy, Debug)]
pub enum AddressingValues {
Implicit,
Immediate(StaticRawType),
Absolute(usize),
AbsoluteIndex(usize, usize),
AbsoluteProperty(usize, usize),
AbsoluteStatic(usize),
IndirectA,
IndirectB,
IndirectC,
IndirectX,
IndirectY,
}
pub trait Reader {
fn read(&mut self) -> Option<u8>;
}
pub struct ProgramReader<'a> {
reader: &'a mut dyn Reader,
}
impl ProgramReader<'_> {
pub fn new(vreader: &mut dyn Reader) -> ProgramReader<'_> {
ProgramReader { reader: vreader }
}
pub fn read_usize(&mut self, arch_size: u8) -> Option<usize> {
let mut array = [0; mem::size_of::<usize>()];
for i in 0..mem::size_of::<usize>() {
if arch_size > i as u8 {
match self.reader.read() {
Some(byte) => {
array[i] = byte;
}
None => return None,
}
} else {
array[i] = 0
}
}
Some(usize::from_le_bytes(array))
}
pub fn read_string(&mut self, string_length: usize) -> Option<String> {
let mut string = String::new();
for _ in 0..string_length {
match self.reader.read() {
Some(byte) => {
string.push(byte as char);
}
None => return None,
}
}
Some(string)
}
pub fn read_isize(&mut self, arch_size: u8) -> Option<isize> {
let mut array = [0; mem::size_of::<isize>()];
for i in 0..mem::size_of::<isize>() {
if arch_size > i as u8 {
match self.reader.read() {
Some(byte) => {
array[i] = byte;
}
None => return None,
}
} else {
array[i] = 0
}
}
Some(isize::from_le_bytes(array))
}
pub fn read_u8(&mut self) -> Option<u8> {
self.reader.read()
}
}
pub enum ResolvedReference {
StaticRawType((StaticRawType, usize)),
RawType((RawType, usize)),
}
impl ResolvedReference {
pub fn type_id(&self) -> TypeId {
match self {
ResolvedReference::StaticRawType(e) => e.0.type_id,
ResolvedReference::RawType(e) => e.0.type_id,
}
}
pub fn data(&self) -> Option<&Vec<u8>> {
match self {
ResolvedReference::RawType(e) => Some(&e.0.data),
_ => None,
}
}
pub fn as_static_raw_type(&self) -> Option<&StaticRawType> {
match self {
ResolvedReference::StaticRawType(e) => Some(&e.0),
_ => None,
}
}
pub fn as_raw_type(&self) -> Option<&RawType> {
match self {
ResolvedReference::RawType(e) => Some(&e.0),
_ => None,
}
}
}
pub enum ReferenceType {
Heap,
Stack,
}
impl ReferenceType {
pub fn from(ref_type: usize) -> ReferenceType {
match ref_type {
13 => ReferenceType::Stack,
14 => ReferenceType::Heap,
_ => panic!("Invalid reference type"),
}
}
}
pub fn resolve_reference(
reference_type: ReferenceType,
reference_data: usize,
heap_memory: &heap_memory::HeapMemory,
stack_memory: &stack_memory::StackMemory,
) -> Result<ResolvedReference, usize> {
match reference_type {
ReferenceType::Heap => match heap_memory.get(&reference_data) {
Some(data) => {
if data.type_id.id == 13 {
resolve_reference(
ReferenceType::Stack,
usize::from_le_bytes(data.data.try_into().unwrap()),
heap_memory,
stack_memory,
)
} else if data.type_id.id == 14 {
resolve_reference(
ReferenceType::Heap,
usize::from_le_bytes(data.data.try_into().unwrap()),
heap_memory,
stack_memory,
)
} else {
Ok(ResolvedReference::RawType((data, reference_data)))
}
}
None => Err(reference_data),
},
ReferenceType::Stack => match stack_memory.get(&reference_data) {
Some(data) => {
if data.type_id.id == 13 {
resolve_reference(
ReferenceType::Stack,
data.to_int() as usize,
heap_memory,
stack_memory,
)
} else if data.type_id.id == 14 {
resolve_reference(
ReferenceType::Heap,
data.to_int() as usize,
heap_memory,
stack_memory,
)
} else {
Ok(ResolvedReference::StaticRawType((data, reference_data)))
}
}
None => Err(reference_data),
},
}
}