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::asm::patches::NextOrErr; use crate::builtin::parse::parse_routine_name; pub fn parse_routine(mut toki: impl Iterator + Clone, rt_pos: &SourcePosition, pcx: &ParserContext) -> Result, 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, 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.clone())); } 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, 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.clone(), body, })); }