use sexp::{SourcePosition, Sexp, Atom}; use crate::asm::error::CrsnError; use crate::asm::instr::op::OpKind; use crate::asm::parse::arg_parser::TokenParser; use crate::module::{CrsnExtension, ParseRes}; use crate::asm::data::literal::{Value, Label}; use crate::asm::instr::{Flatten, Op}; use crate::asm::parse::parse_instructions; use crate::builtin::defs::BuiltinOp; use crate::asm::instr::flatten::jumps_to_skips; use crate::asm::data::{Rd, RdData}; use crate::asm::parse::parse_data::parse_label; pub mod defs; pub mod exec; pub mod parse; pub(crate) const RT_OPT_TIMESLICE : u64 = 1; #[derive(Debug, Clone)] pub struct BuiltinOps; impl BuiltinOps { pub fn new() -> Box { Box::new(Self) } } impl CrsnExtension for BuiltinOps { fn name(&self) -> &'static str { "builtin" } fn parse_op<'a>(&self, pos: &SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result, CrsnError> { parse::parse_op(pos, keyword, args) } /// Get value of an extension-provided constant. /// This constant may be an object handle, or a constant value used as argument in some other instruction. fn get_constant_value<'a>(&self, name: &str) -> Option { match name { "RT_TIMESLICE" => Some(RT_OPT_TIMESLICE), _ => None, } } /// Parse a generic S-expression (non-op) that started with the given keyword /// /// pcx is available on the arg_tokens parser fn parse_syntax<'a>(&self, pos: &SourcePosition, keyword: &str, mut tokens: TokenParser<'a>) -> Result>, CrsnError> { if keyword == "crit" || keyword == "critical" { let pcx = tokens.pcx; let opts = parse_instructions(tokens.into_iter(), pos, pcx)?; let flattened = jumps_to_skips(opts.flatten(&pcx.state.borrow_mut().label_num)?)?; let len = flattened.len(); for (n, op) in flattened.iter().enumerate() { match op.kind { OpKind::BuiltIn(BuiltinOp::Skip(Rd(RdData::Immediate(skip)))) => { let signed = i64::from_ne_bytes(skip.to_ne_bytes()); let target = n as i64 + signed; if target < 0 || target > len as i64 { return Err(CrsnError::Parse("Cannot jump out of a critical section!".into(), op.pos())); } } /* Non-constant skip cannot be validated */ OpKind::BuiltIn(BuiltinOp::Skip(_)) => { return Err(CrsnError::Parse("Variable skips are not allowed in a critical section".into(), op.pos())); } /* Yield in critical makes zero sense */ OpKind::BuiltIn(BuiltinOp::Yield { .. }) => { return Err(CrsnError::Parse("Yield in a critical section!".into(), op.pos())); } /* This is likely a bug */ OpKind::BuiltIn(BuiltinOp::Ret(_)) => { return Err(CrsnError::Parse("Ret in a critical section!".into(), op.pos())); } /* Probably also a bug. If someone really wants this, they can start and end the critical section manually. */ OpKind::BuiltIn(BuiltinOp::FarJump(_)) => { return Err(CrsnError::Parse("Far jump a critical section!".into(), op.pos())); } _ => {} } } let vec : Vec> = vec![ Box::new(Op { kind: OpKind::BuiltIn(BuiltinOp::CriticalBegin), cond: None, pos: pos.clone(), }), Box::new(flattened), Box::new(Op { kind: OpKind::BuiltIn(BuiltinOp::CriticalEnd), cond: None, pos: pos.clone(), }), ]; return Ok(ParseRes::Parsed(Box::new(vec))); } if keyword == "loop" { let mut end_label = None; let label = if let Some(Sexp::Atom(Atom::S(_), _)) = tokens.peek() { let label = parse_label(tokens.next().unwrap())?; if let Label::Named(n) = &label { end_label = Some(Label::Named(format!("{}-end", n))); } label } else { Label::unique(&tokens.pcx.state.borrow().label_num) }; let pcx = tokens.pcx; let inner = parse_instructions(tokens.into_iter(), pos, pcx)?; let mut vec : Vec> = vec![ Box::new(Op { kind: OpKind::BuiltIn(BuiltinOp::Label(label.clone())), cond: None, pos: pos.clone(), }), inner, Box::new(Op { kind: OpKind::BuiltIn(BuiltinOp::Jump(label)), cond: None, pos: pos.clone(), }), ]; if let Some(el) = end_label { vec.push(Box::new(Op { kind: OpKind::BuiltIn(BuiltinOp::Label(el)), cond: None, pos: pos.clone(), })); } return Ok(ParseRes::Parsed(Box::new(vec))) } Ok(ParseRes::Unknown(tokens)) } }