use std::fmt::Debug; use dyn_clonable::*; use sexp::Sexp; use crate::asm::data::{ literal::DebugMsg, literal::Label, literal::RoutineName, Rd, Wr, }; use crate::asm::error::Error; use crate::asm::instr::Cond; use crate::runtime::fault::Fault; use crate::runtime::frame::{CallStack, StackFrame}; use crate::runtime::program::Program; use crate::asm::parse::arg_parser::ArgParser; /// A higher level simple opration #[derive(Clone, Debug)] pub enum OpWrapper { /// Mark a jump target. Label(Label), /// Jump to a label Jump(Label), /// Jump to a label if a flag is set JumpIf(Cond, Label), /// Low level op Op(Op), } /// A low level instruction #[derive(Clone, Debug)] pub enum Op { /// Do nothing Nop, /// Mark a far jump target (can be jumped to from another routine). /// This label is preserved in optimized code. FarLabel(Label), /// Jump to a label that can be in another function FarJump(Label), /// Call a routine with arguments. /// The arguments are passed as argX. Return values are stored in resX registers. Call(RoutineName, Vec), /// Exit the current routine with return values Ret(Vec), /// Mark a routine entry point (call target). /// Kept in the low level instruction file for position-independent code Routine(RoutineName), /// Skip backward or forward Skip(Rd), /// Skip if a flag is set SkipIf(Cond, Rd), /// Deny jumps, skips and run across this address, producing a run-time fault with a message. Barrier(Option), /// Generate a run-time fault with a debugger message Fault(Option), /// Copy value Move { dst: Wr, src: Rd }, /// Store runtime status to a register StoreStatus { dst: Wr }, /// Load runtime status from a register LoadStatus { src: Rd }, Extension(Box), } /// Make "into" work impl From for OpWrapper { fn from(op: Op) -> Self { OpWrapper::Op(op) } } #[clonable] pub trait OpTrait: Clone + Debug + Send + 'static { fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<(), Fault>; } pub enum ParseOpResult { Parsed(Box), Unknown(ArgParser), } #[clonable] pub trait AsmModule: Clone + Debug + Send + 'static { /// Get name of the module fn name(&self) -> &'static str; /// Parse an op. /// If the keyword matches and the function decides to parse the instruction, it must consume /// the argument list and either return Ok or Err. /// /// If the instruction keyword is not recognized, return Unknown with the unchanged argument list. fn parse_op(&self, keyword: &str, arg_tokens: ArgParser) -> Result; }