Croissant Runtime
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.
 
 
crsn/crsn/src/builtin/mod.rs

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))
}
}