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

176 lines
6.2 KiB

use std::borrow::Cow;
use std::convert::TryFrom;
use sexp::{Atom, Sexp, SourcePosition};
use crate::asm::data::{DataDisp, Rd, RdData, reg, Wr, WrData};
use crate::asm::data::literal::{ConstantName, Label, RegisterAlias, Value};
use crate::asm::error::CrsnError;
use crate::asm::parse::ParserContext;
use crate::asm::parse::sexp_expect::expect_string_atom;
use std::num::TryFromIntError;
use crate::asm::patches::ErrWithPos;
fn is_valid_identifier(name: &str) -> bool {
name.starts_with(|c: char| c.is_ascii_alphabetic() || c == '_')
&& name.chars().find(|c| !c.is_ascii_alphanumeric() && *c != '_').is_none()
}
/// Parse register alias
pub fn parse_reg_alias(name: Sexp) -> Result<(RegisterAlias, SourcePosition), CrsnError> {
// trace!("parse reg alias: {:?}", name);
let (name, namepos) = expect_string_atom(name)?;
if !is_valid_identifier(&name) {
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed register alias.", name).into(), namepos));
}
Ok((name, namepos))
}
/// Parse constant name
pub fn parse_constant_name(name: Sexp) -> Result<(ConstantName, SourcePosition), CrsnError> {
// trace!("parse const name: {:?}", name);
let (name, namepos) = expect_string_atom(name)?;
if !is_valid_identifier(&name) {
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed constant name.", name).into(), namepos));
}
Ok((name, namepos))
}
/// Parse a label
pub fn parse_label(name: Sexp) -> Result<Label, CrsnError> {
// trace!("parse label: {:?}", name);
let (name, namepos) = expect_string_atom(name)?;
Ok(parse_label_str(&name, namepos)?)
}
pub fn parse_label_str(name: &str, pos: SourcePosition) -> Result<Label, CrsnError> {
let label = name.trim_start_matches(':');
Ok(if label.starts_with('#') {
let val = parse_u64(&label[1..], pos.clone())?;
Label::Numbered(u32::try_from(val).err_pos(pos)?)
} else {
Label::Named(label.to_string())
})
}
/// Parse data disposition (address/value, without the read/write restriction)
pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnError> {
// trace!("parse data: {:?}", tok);
// TODO implement masks
match tok {
Sexp::Atom(Atom::I(val), pos) => {
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(val) }))
}
Sexp::Atom(Atom::S(s), pos) => {
if s == "_" {
return Ok(DataDisp::Discard);
}
// check if we have an alias defined
{
let pstate = pcx.state.borrow();
if let Some(val) = pstate.constants.get(&s) {
return Ok(DataDisp::Immediate(*val));
}
if let Some(val) = pstate.reg_aliases.get(&s) {
return Ok(DataDisp::Register(*val));
}
}
if let Some(reference) = s.strip_prefix('@') {
let pstate = pcx.state.borrow();
if let Some(val) = pstate.reg_aliases.get(reference) {
Ok(DataDisp::ObjectPtr(*val))
} else {
let reg = reg::parse_reg(reference, pos.clone())?;
if pstate.reg_aliases.values().find(|v| **v == reg).is_some() {
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos))
} else {
Ok(DataDisp::ObjectPtr(reg))
}
}
} else if s.starts_with(|c: char| c.is_ascii_digit()) {
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(parse_i64(&s, pos)?) }))
} else {
let reg = reg::parse_reg(&s, pos.clone())?;
let pstate = pcx.state.borrow();
if pstate.reg_aliases.values().find(|v| **v == reg).is_some() {
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos))
} else {
Ok(DataDisp::Register(reg))
}
}
}
other => {
Err(CrsnError::Parse(format!("bad data disp: {:?}", other).into(), other.pos().clone()))
}
}
}
/// Parse immediate value
pub fn parse_value(tok: Sexp, pcx: &ParserContext) -> Result<Value, CrsnError> {
match tok {
Sexp::Atom(Atom::I(val), pos) => {
Ok(unsafe { std::mem::transmute(val) })
}
Sexp::Atom(Atom::S(s), pos) => {
let pstate = pcx.state.borrow();
if let Some(val) = pstate.constants.get(&s) {
return Ok(*val);
}
Ok(unsafe { std::mem::transmute(parse_i64(&s, pos)?) })
}
other => {
Err(CrsnError::Parse(format!("bad value format: {:?}", other).into(), other.pos().clone()))
}
}
}
pub fn parse_u64(literal: &str, pos: SourcePosition) -> Result<u64, CrsnError> {
// trace!("parse u64 from {}", literal);
let mut without_underscores = Cow::Borrowed(literal);
if without_underscores.contains('_') {
without_underscores = without_underscores.replace('_', "").into();
}
if let Some(hex) = without_underscores.strip_prefix("0x") {
Ok(u64::from_str_radix(hex, 16).err_pos(pos)?)
} else if let Some(hex) = without_underscores.strip_prefix("0b") {
Ok(u64::from_str_radix(hex, 2).err_pos(pos)?)
} else {
Ok(u64::from_str_radix(&without_underscores, 10).err_pos(pos)?)
}
}
pub fn parse_i64(literal: &str, pos: SourcePosition) -> Result<i64, CrsnError> {
// trace!("parse i64 from {}", literal);
if let Some(_value) = literal.strip_prefix("-") {
Ok(-1 * i64::try_from(parse_u64(literal, pos.clone())?).err_pos(pos)?)
} else {
Ok(i64::try_from(parse_u64(literal, pos.clone())?).err_pos(pos)?)
}
}
pub fn parse_rd(tok: Sexp, pcx: &ParserContext) -> Result<Rd, CrsnError> {
let pos = tok.pos().clone();
Ok(Rd::new(RdData::try_from(parse_data_disp(tok, pcx)?).err_pos(pos)?))
}
pub fn parse_wr(tok: Sexp, pcx: &ParserContext) -> Result<Wr, CrsnError> {
let pos = tok.pos().clone();
Ok(Wr::new(WrData::try_from(parse_data_disp(tok, pcx)?).err_pos(pos)?))
}