You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
5.5 KiB
150 lines
5.5 KiB
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<dyn CrsnExtension> {
|
|
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<ParseRes<'a, OpKind>, 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<Value> {
|
|
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<ParseRes<'a, Box<dyn Flatten>>, 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<Box<dyn Flatten>> = 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<Box<dyn Flatten>> = 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))
|
|
}
|
|
}
|
|
|