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_routine.rs

60 lines
2.3 KiB

use sexp::{Sexp, SourcePosition};
use crate::asm::data::Register;
use crate::asm::error::CrsnError;
use crate::asm::instr::{Flatten, Routine};
use crate::asm::parse::{parse_instructions, ParserContext};
use crate::asm::parse::arg_parser::TokenParser;
use crate::asm::parse::parse_data::parse_reg_alias;
use crate::asm::parse::sexp_expect::expect_string_atom;
use crate::builtin::parse::parse_routine_name;
use crate::asm::patches::NextOrErr;
pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, rt_pos: SourcePosition, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {
let (name, namepos) = expect_string_atom(toki.next_or_err(rt_pos.clone(), "Expected routine name")?)?;
let mut name = parse_routine_name(name, namepos)?;
let arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect(), rt_pos.clone(), pcx);
// If arity is explicitly given, then either no named argument must be provided,
// or their count must match the arity. If no arity is given, then arity is determined
// by the number of named arguments.
if name.arity == 0 && arg_tokens.len() != 0 {
name.arity = arg_tokens.len() as u8;
} else if arg_tokens.len() != 0 && name.arity as usize != arg_tokens.len() {
return Err(CrsnError::Parse(format!("arity mismatch in routine {}", name.name).into(), rt_pos));
}
let toki = toki.skip_while(|e| e.is_atom());
{
let mut pstate = pcx.state.borrow_mut();
let old = std::mem::replace(&mut pstate.reg_aliases, Default::default());
pstate.reg_alias_stack.push(old);
for (n, tok) in arg_tokens.into_iter().enumerate() {
let alias = parse_reg_alias(tok)?;
if pstate.constants.contains_key(&alias.0) {
return Err(CrsnError::Parse(format!("Symbol \"{}\" already used for a constant.", alias.0).into(), alias.1));
}
pstate.reg_aliases.insert(alias.0, Register::Arg(n as u8));
}
}
let body = parse_instructions(toki, rt_pos.clone(), pcx)?;
{
let mut pstate = pcx.state.borrow_mut();
let old = pstate.reg_alias_stack.pop().unwrap();
pstate.reg_aliases = old;
}
return Ok(Box::new(Routine {
name,
pos: rt_pos,
body,
}));
}