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/parse.rs

397 lines
13 KiB

use sexp::{Atom, Sexp, SourcePosition};
use crate::asm::data::literal::{Label, RoutineName};
use crate::asm::data::reg::parse_reg;
4 years ago
use crate::asm::error::CrsnError;
use crate::asm::instr::op::OpKind;
use crate::asm::parse::arg_parser::TokenParser;
4 years ago
use crate::asm::parse::parse_data::{parse_constant_name, parse_label, parse_rd, parse_reg_alias, parse_value, parse_label_str};
use crate::asm::parse::sexp_expect::expect_string_atom;
use crate::builtin::defs::{Barrier, BuiltinOp};
use crate::module::{ParseRes};
use crate::utils::A;
use crate::asm::patches::ErrWithPos;
pub(crate) fn parse_op<'a>(op_pos: SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
4 years ago
let pcx = args.pcx;
4 years ago
Ok(ParseRes::Parsed(OpKind::BuiltIn(match keyword {
"nop" => {
BuiltinOp::Nop
}
4 years ago
"halt" => {
BuiltinOp::Halt
}
4 years ago
"sleep" => {
BuiltinOp::Sleep {
micros: args.next_rd()?,
}
4 years ago
}
4 years ago
"sym" => {
let (alias, aliaspos) = parse_reg_alias(args.next_or_err()?)?;
4 years ago
trace!("alias={:?}", alias);
let (rn, rpos) = args.next_string()?;
let register = parse_reg(&rn, rpos.clone())?;
4 years ago
trace!("register={:?}", alias);
4 years ago
let mut pstate = pcx.state.borrow_mut();
if pstate.reg_aliases.contains_key(&alias) {
return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined!", alias).into(), rpos));
}
4 years ago
if pstate.constants.contains_key(&alias) {
return Err(CrsnError::Parse(format!("Name \"{}\" already used for a constant!", alias).into(), aliaspos));
4 years ago
}
4 years ago
if pstate.reg_aliases.iter().find(|x| x.1 == &register).is_some() {
return Err(CrsnError::Parse(format!("Register \"{}\" already aliased!", register).into(), rpos));
4 years ago
}
4 years ago
pstate.reg_aliases.insert(alias, register);
4 years ago
return Ok(ParseRes::ParsedNone);
}
4 years ago
"unsym" => {
let alias = parse_reg_alias(args.next_or_err()?)?;
4 years ago
let mut pstate = pcx.state.borrow_mut();
if pstate.reg_aliases.remove(&alias.0).is_none() {
return Err(CrsnError::Parse(format!("Register alias \"{}\" not defined!", alias.0).into(), alias.1));
}
4 years ago
return Ok(ParseRes::ParsedNone);
}
4 years ago
"def" => {
let (name, namepos) = parse_constant_name(args.next_or_err()?)?;
let value = parse_value(args.next_or_err()?, pcx)?;
4 years ago
let mut pstate = pcx.state.borrow_mut();
if pstate.constants.contains_key(&name) {
return Err(CrsnError::Parse(format!("Constant \"{}\" already defined!", name).into(), namepos));
}
4 years ago
if pstate.reg_aliases.contains_key(&name) {
return Err(CrsnError::Parse(format!("Name \"{}\" already used for a register alias!", name).into(), namepos));
4 years ago
}
4 years ago
pstate.constants.insert(name, value);
4 years ago
return Ok(ParseRes::ParsedNone);
}
4 years ago
"undef" => {
let (name, namepos) = parse_constant_name(args.next_or_err()?)?;
4 years ago
let mut pstate = pcx.state.borrow_mut();
if pstate.constants.remove(&name).is_none() {
return Err(CrsnError::Parse(format!("Constant \"{}\" not defined!", name).into(), namepos));
}
4 years ago
return Ok(ParseRes::ParsedNone);
}
4 years ago
"j" => {
let dest = parse_label(args.next_or_err()?)?;
4 years ago
BuiltinOp::Jump(dest)
}
4 years ago
"fj" => {
let dest = parse_label(args.next_or_err()?)?;
4 years ago
BuiltinOp::FarJump(dest)
}
4 years ago
"call" => {
let dest = RoutineName { name: args.next_string()?.0, arity: args.len() as u8 };
4 years ago
let mut call_args = vec![];
for t in args {
call_args.push(parse_rd(t, pcx)?);
}
4 years ago
BuiltinOp::Call(dest, call_args)
}
4 years ago
"ret" => {
let mut ret_vals = vec![];
for t in args {
ret_vals.push(parse_rd(t, pcx)?);
}
4 years ago
BuiltinOp::Ret(ret_vals)
}
4 years ago
"routine" => {
let name = args.next_string()?;
BuiltinOp::Routine(parse_routine_name(name.0, name.1)?)
4 years ago
}
4 years ago
"skip" => {
BuiltinOp::Skip(args.next_rd()?)
}
4 years ago
"barrier" => {
BuiltinOp::Barrier {
kind: Barrier::Standalone,
msg: match args.next() {
None => None,
Some(s) => Some(expect_string_atom(s)?.0.into()),
4 years ago
},
}
4 years ago
}
4 years ago
"barrier-open" => {
BuiltinOp::Barrier {
kind: Barrier::Open(parse_label(args.next_or_err()?)?),
4 years ago
msg: None,
}
4 years ago
}
4 years ago
"barrier-close" => {
BuiltinOp::Barrier {
kind: Barrier::Close(parse_label(args.next_or_err()?)?),
4 years ago
msg: None,
}
4 years ago
}
4 years ago
"fault" => {
BuiltinOp::Fault(match args.next() {
None => None,
Some(s) => Some(expect_string_atom(s)?.0.into()),
4 years ago
})
}
4 years ago
"ld" => {
BuiltinOp::Move {
dst: args.next_wr()?,
src: args.next_rd()?,
}
4 years ago
}
4 years ago
"sst" => {
BuiltinOp::StoreStatus {
dst: args.next_wr()?,
4 years ago
}
4 years ago
}
4 years ago
4 years ago
"sld" => {
BuiltinOp::LoadStatus {
src: args.next_rd()?,
4 years ago
}
4 years ago
}
4 years ago
4 years ago
"drop" => {
BuiltinOp::Drop(args.next_rdobj()?)
}
4 years ago
"far" => {
if let Some(Sexp::Atom(Atom::S(ref label), _)) = args.peek() {
4 years ago
if let Some(label) = label.strip_prefix(':') {
let label = Label::Named(label.to_string());
BuiltinOp::FarLabel(label)
} else {
return Ok(ParseRes::Unknown(args));
}
4 years ago
} else {
return Ok(ParseRes::Unknown(args));
}
4 years ago
}
4 years ago
other => {
if let Some(label) = other.strip_prefix(':') {
BuiltinOp::Label(parse_label_str(label, op_pos)?)
4 years ago
} else {
return Ok(ParseRes::Unknown(args));
}
4 years ago
}
})))
}
pub(crate) fn parse_routine_name(name: String, pos: SourcePosition) -> Result<RoutineName, CrsnError> {
let (name, arity) = if let Some(n) = name.find('/') {
(
(&name[0..n]).to_string(),
(&name[(n + 1)..]).parse::<u8>().err_pos(pos)?
)
} else {
(name, 0)
};
Ok(RoutineName { name, arity })
}
pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp {
match op {
BuiltinOp::Nop => sexp::list(&[A("nop")]),
BuiltinOp::Halt => sexp::list(&[A("halt")]),
BuiltinOp::Sleep { micros } => sexp::list(&[A("sleep"), A(micros)]),
BuiltinOp::Label(label) => sexp::list(&[A(label)]),
BuiltinOp::Jump(label) => sexp::list(&[A("j"), A(label)]),
BuiltinOp::FarLabel(label) => sexp::list(&[A("far"), A(label)]),
BuiltinOp::FarJump(label) => sexp::list(&[A("fj"), A(label)]),
BuiltinOp::Call(name, args) => {
if args.is_empty() {
sexp::list(&[A("call"), A(&name.name)])
} else {
let mut inner = vec![A("call"), A(&name.name)];
inner.extend(args.iter().map(A));
sexp::list(&inner)
}
},
BuiltinOp::Ret(values) => {
if values.is_empty() {
sexp::list(&[A("ret")])
} else {
let mut inner = vec![A("ret")];
inner.extend(values.iter().map(A));
sexp::list(&inner)
}
}
BuiltinOp::Routine(name) => sexp::list(&[A("routine"), A(name)]),
BuiltinOp::Skip(n) => sexp::list(&[A("skip"), A(n)]),
BuiltinOp::Barrier { kind, msg } => {
let mut inner = vec![];
match kind {
Barrier::Open(label) => {
inner.push(A("barrier-open"));
inner.push(A(label));
}
Barrier::Close(label) => {
inner.push(A("barrier-close"));
inner.push(A(label));
}
Barrier::Standalone => {
inner.push(A("barrier"));
if let Some(msg) = msg {
inner.push(A(msg));
}
}
}
sexp::list(&inner)
}
BuiltinOp::Fault(msg) => {
if let Some(msg) = msg {
sexp::list(&[A("fault"), A(msg)])
} else {
sexp::list(&[A("fault")])
}
}
BuiltinOp::Drop(obj) => sexp::list(&[A("drop"), A(obj)]),
BuiltinOp::Move { dst, src } => sexp::list(&[A("ld"), A(dst), A(src)]),
BuiltinOp::StoreStatus { dst } => sexp::list(&[A("sst"), A(dst)]),
BuiltinOp::LoadStatus { src } => sexp::list(&[A("sld"), A(src)])
}
}
#[cfg(test)]
mod test {
4 years ago
use std::sync::atomic::AtomicU32;
4 years ago
use crate::asm::instr::{Flatten};
use crate::asm::parse::{parse_instructions, ParserContext};
use crate::asm::parse::sexp_expect::expect_list;
4 years ago
use crate::module::OpTrait;
4 years ago
use crate::builtin::BuiltinOps;
#[test]
fn roundtrip() {
let samples = vec![
// sym, unsym, def, undef - pseudo-instructions
// jump is translated to a skip
("(nop)", "(nop)"),
("(halt)", "(halt)"),
("(sleep 1000)", "(sleep 1000)"),
("(:x)\
(j :x)", "(skip 0)"),
("(:#7)\
(j :#7)", "(skip 0)"),
("(fj :x)", "(fj :x)"),
("(skip 0)", "(skip 0)"),
("(skip r0)", "(skip r0)"),
("(sym banana r0)(unsym banana)(sym banana r1)(skip banana)", "(skip r1)"),
("(def foo 123)(skip foo)", "(skip 123)"),
("(def foo 123)(undef foo)(def foo 444)(skip foo)", "(skip 444)"),
("(def foo -777)(def bar foo)(skip bar)", "(skip -777)"),
("(skip -10)", "(skip -10)"),
("(skip -10000)", "(skip -10000)"),
("(call funcname)", "(call funcname)"),
("(call funcname 13)", "(call funcname 13)"),
("(sym haf r0)\
(call štěkej haf haf)", "(call štěkej r0 r0)"),
("(sym foo r0)\
(sym bar r1)\
(call funcname foo bar)", "(call funcname r0 r1)"),
("(ret)", "(ret)"),
("(ret r0)", "(ret r0)"),
("(ret r0 r1 r2 5)", "(ret r0 r1 r2 5)"),
("(routine ěščžřčřýřážíýáéáýúů)", "(routine ěščžřčřýřážíýáéáýúů/0)"),
("(routine ahoj)", "(routine ahoj/0)"),
("(routine ahoj/2)", "(routine ahoj/2)"),
("(barrier)", "(barrier)"),
("(barrier blablabla)", "(barrier blablabla)"),
("(barrier \"s mezerou\")", "(barrier \"s mezerou\")"),
("(barrier-open :xoxo)", "(barrier-open :xoxo)"),
("(barrier-open :#10)", "(barrier-open :#10)"),
("(barrier-close :xoxo)", "(barrier-close :xoxo)"),
("(barrier-close :#10)", "(barrier-close :#10)"),
("(fault)", "(fault)"),
("(fault kur*a)", "(fault kur*a)"),
("(fault \"do pr*ele\")", "(fault \"do pr*ele\")"),
("(ld r0 r0)", "(ld r0 r0)"),
("(ld r0 156)", "(ld r0 156)"),
("(ld _ -32767)", "(ld _ -32767)"),
("(sst r0)", "(sst r0)"),
("(sld r0)", "(sld r0)"),
("(far :label)", "(far :label)"),
("(drop @r5)", "(drop @r5)"),
("(sym cat r0)(drop @cat)", "(drop @r0)"),
];
let parser = BuiltinOps::new();
let parsers = &[parser];
for (sample, expected) in samples {
4 years ago
let pcx = ParserContext {
parsers,
state: Default::default(),
};
println!("Parse: {}", sample);
/* first cycle */
let s = sexp::parse(&format!("({})", sample))
.expect("parse sexp");
let list = expect_list(Some(s), false).unwrap();
let num = AtomicU32::new(0);
4 years ago
let parsed = parse_instructions(list.into_iter(), &pcx)
.expect("parse instr").flatten(&num)
.expect("flatten").remove(0);
let exported = parsed.to_sexp().to_string();
println!("Parsed: {}", exported);
assert_eq!(expected, exported);
println!(" - 2nd cycle");
/* second cycle, nothing should change */
let s = sexp::parse(&format!("({})", exported))
.expect("parse sexp (2c)");
let list = expect_list(Some(s), false).unwrap();
let num = AtomicU32::new(0);
4 years ago
let parsed = parse_instructions(list.into_iter(), &pcx)
.expect("parse instr (2c)").flatten(&num)
.expect("flatten (2c)").remove(0);
let exported2 = parsed.to_sexp().to_string();
assert_eq!(expected, exported2);
}
}
}