|  |  | @ -5,224 +5,205 @@ use crate::asm::data::reg::parse_reg; | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::asm::error::CrsnError; |  |  |  | use crate::asm::error::CrsnError; | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::asm::instr::op::OpKind; |  |  |  | use crate::asm::instr::op::OpKind; | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::asm::parse::arg_parser::TokenParser; |  |  |  | use crate::asm::parse::arg_parser::TokenParser; | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::asm::parse::parse_data::{parse_constant_name, parse_label, parse_rd, parse_reg_alias, parse_value, parse_u64, parse_label_str}; |  |  |  | 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::asm::parse::sexp_expect::expect_string_atom; | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::builtin::defs::{Barrier, BuiltinOp}; |  |  |  | use crate::builtin::defs::{Barrier, BuiltinOp}; | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::module::{CrsnExtension, ParseRes}; |  |  |  | use crate::module::{CrsnExtension, ParseRes}; | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::utils::A; |  |  |  | use crate::utils::A; | 
			
		
	
		
		
			
				
					
					|  |  |  | use std::convert::TryFrom; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #[derive(Debug, Clone)] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | pub struct BuiltinOps { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     _internal: () |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | impl BuiltinOps { |  |  |  | pub(crate) fn parse_op<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn new() -> Box<dyn CrsnExtension> { |  |  |  |     let pcx = args.pcx; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         Box::new(Self { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             _internal: () |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         }) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | impl CrsnExtension for BuiltinOps { |  |  |  |     Ok(ParseRes::Parsed(OpKind::BuiltIn(match keyword { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     fn name(&self) -> &'static str { |  |  |  |         "nop" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         "builtin" |  |  |  |             BuiltinOp::Nop | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |         } | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     fn parse_op<'a>(&self, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> { |  |  |  |         "halt" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         let pcx = args.pcx; |  |  |  |             BuiltinOp::Halt | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         Ok(ParseRes::Parsed(OpKind::BuiltIn(match keyword { |  |  |  |         "sleep" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             "nop" => { |  |  |  |             BuiltinOp::Sleep { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Nop |  |  |  |                 micros: args.next_rd()?, | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "halt" => { |  |  |  |         "sym" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Halt |  |  |  |             let alias = parse_reg_alias(args.next())?; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             trace!("alias={:?}", alias); | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             let register = parse_reg(&args.next_string()?)?; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             trace!("register={:?}", alias); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "sleep" => { |  |  |  |             let mut pstate = pcx.state.borrow_mut(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Sleep { |  |  |  |             if pstate.reg_aliases.contains_key(&alias) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     micros: args.next_rd()?, |  |  |  |                 return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined!", alias).into())); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "sym" => { |  |  |  |             if pstate.constants.contains_key(&alias) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let alias = parse_reg_alias(args.next())?; |  |  |  |                 return Err(CrsnError::Parse(format!("Name \"{}\" already used for a constant!", alias).into())); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 trace!("alias={:?}", alias); |  |  |  |             } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let register = parse_reg(&args.next_string()?)?; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 trace!("register={:?}", alias); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 let mut pstate = pcx.state.borrow_mut(); |  |  |  |             if pstate.reg_aliases.iter().find(|x| x.1 == ®ister).is_some() { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 if pstate.reg_aliases.contains_key(&alias) { |  |  |  |                 return Err(CrsnError::Parse(format!("Register \"{}\" already aliased!", register).into())); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined!", alias).into())); |  |  |  |             } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 if pstate.constants.contains_key(&alias) { |  |  |  |             pstate.reg_aliases.insert(alias, register); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     return Err(CrsnError::Parse(format!("Name \"{}\" already used for a constant!", alias).into())); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 if pstate.reg_aliases.iter().find(|x| x.1 == ®ister).is_some() { |  |  |  |             return Ok(ParseRes::ParsedNone); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     return Err(CrsnError::Parse(format!("Register \"{}\" already aliased!", register).into())); |  |  |  |         } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 pstate.reg_aliases.insert(alias, register); |  |  |  |         "unsym" => { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             let alias = parse_reg_alias(args.next())?; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 return Ok(ParseRes::ParsedNone); |  |  |  |             let mut pstate = pcx.state.borrow_mut(); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             if pstate.reg_aliases.remove(&alias).is_none() { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 return Err(CrsnError::Parse(format!("Register alias \"{}\" not defined!", alias).into())); | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return Ok(ParseRes::ParsedNone); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "unsym" => { |  |  |  |         "def" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let alias = parse_reg_alias(args.next())?; |  |  |  |             let name = parse_constant_name(args.next())?; | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             let value = parse_value(args.next(), pcx)?; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 let mut pstate = pcx.state.borrow_mut(); |  |  |  |             let mut pstate = pcx.state.borrow_mut(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 if pstate.reg_aliases.remove(&alias).is_none() { |  |  |  |             if pstate.constants.contains_key(&name) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     return Err(CrsnError::Parse(format!("Register alias \"{}\" not defined!", alias).into())); |  |  |  |                 return Err(CrsnError::Parse(format!("Constant \"{}\" already defined!", name).into())); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 return Ok(ParseRes::ParsedNone); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "def" => { |  |  |  |             if pstate.reg_aliases.contains_key(&name) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let name = parse_constant_name(args.next())?; |  |  |  |                 return Err(CrsnError::Parse(format!("Name \"{}\" already used for a register alias!", name).into())); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let value = parse_value(args.next(), pcx)?; |  |  |  |             } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 let mut pstate = pcx.state.borrow_mut(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 if pstate.constants.contains_key(&name) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     return Err(CrsnError::Parse(format!("Constant \"{}\" already defined!", name).into())); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 if pstate.reg_aliases.contains_key(&name) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     return Err(CrsnError::Parse(format!("Name \"{}\" already used for a register alias!", name).into())); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 pstate.constants.insert(name, value); |  |  |  |             pstate.constants.insert(name, value); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 return Ok(ParseRes::ParsedNone); |  |  |  |             return Ok(ParseRes::ParsedNone); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |         } | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "undef" => { |  |  |  |         "undef" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let name = parse_constant_name(args.next())?; |  |  |  |             let name = parse_constant_name(args.next())?; | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 let mut pstate = pcx.state.borrow_mut(); |  |  |  |             let mut pstate = pcx.state.borrow_mut(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 if pstate.constants.remove(&name).is_none() { |  |  |  |             if pstate.constants.remove(&name).is_none() { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     return Err(CrsnError::Parse(format!("Constant \"{}\" not defined!", name).into())); |  |  |  |                 return Err(CrsnError::Parse(format!("Constant \"{}\" not defined!", name).into())); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 return Ok(ParseRes::ParsedNone); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return Ok(ParseRes::ParsedNone); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "j" => { |  |  |  |         "j" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let dest = parse_label(args.next())?; |  |  |  |             let dest = parse_label(args.next())?; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Jump(dest) |  |  |  |             BuiltinOp::Jump(dest) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |         } | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "fj" => { |  |  |  |         "fj" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let dest = parse_label(args.next())?; |  |  |  |             let dest = parse_label(args.next())?; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::FarJump(dest) |  |  |  |             BuiltinOp::FarJump(dest) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |         } | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "call" => { |  |  |  |         "call" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let dest = RoutineName { name: args.next_string()?, arity: args.len() as u8 }; |  |  |  |             let dest = RoutineName { name: args.next_string()?, arity: args.len() as u8 }; | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 let mut call_args = vec![]; |  |  |  |             let mut call_args = vec![]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 for t in args { |  |  |  |             for t in args { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     call_args.push(parse_rd(Some(t), pcx)?); |  |  |  |                 call_args.push(parse_rd(Some(t), pcx)?); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Call(dest, call_args) |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             BuiltinOp::Call(dest, call_args) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "ret" => { |  |  |  |         "ret" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let mut ret_vals = vec![]; |  |  |  |             let mut ret_vals = vec![]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 for t in args { |  |  |  |             for t in args { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     ret_vals.push(parse_rd(Some(t), pcx)?); |  |  |  |                 ret_vals.push(parse_rd(Some(t), pcx)?); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Ret(ret_vals) |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             BuiltinOp::Ret(ret_vals) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "routine" => { |  |  |  |         "routine" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 let name = args.next_string()?; |  |  |  |             let name = args.next_string()?; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Routine(parse_routine_name(name)?) |  |  |  |             BuiltinOp::Routine(parse_routine_name(name)?) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |         } | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "skip" => { |  |  |  |         "skip" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Skip(args.next_rd()?) |  |  |  |             BuiltinOp::Skip(args.next_rd()?) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |         } | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "barrier" => { |  |  |  |         "barrier" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Barrier { |  |  |  |             BuiltinOp::Barrier { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     kind: Barrier::Standalone, |  |  |  |                 kind: Barrier::Standalone, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     msg: match args.next() { |  |  |  |                 msg: match args.next() { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         None => None, |  |  |  |                     None => None, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         Some(s) => Some(expect_string_atom(Some(s))?.into()), |  |  |  |                     Some(s) => Some(expect_string_atom(Some(s))?.into()), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     }, |  |  |  |                 }, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "barrier-open" => { |  |  |  |         "barrier-open" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Barrier { |  |  |  |             BuiltinOp::Barrier { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     kind: Barrier::Open(parse_label(args.next())?), |  |  |  |                 kind: Barrier::Open(parse_label(args.next())?), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     msg: None, |  |  |  |                 msg: None, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "barrier-close" => { |  |  |  |         "barrier-close" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Barrier { |  |  |  |             BuiltinOp::Barrier { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     kind: Barrier::Close(parse_label(args.next())?), |  |  |  |                 kind: Barrier::Close(parse_label(args.next())?), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     msg: None, |  |  |  |                 msg: None, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "fault" => { |  |  |  |         "fault" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Fault(match args.next() { |  |  |  |             BuiltinOp::Fault(match args.next() { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     None => None, |  |  |  |                 None => None, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     Some(s) => Some(expect_string_atom(Some(s))?.into()), |  |  |  |                 Some(s) => Some(expect_string_atom(Some(s))?.into()), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 }) |  |  |  |             }) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |         } | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "ld" => { |  |  |  |         "ld" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Move { |  |  |  |             BuiltinOp::Move { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     dst: args.next_wr()?, |  |  |  |                 dst: args.next_wr()?, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     src: args.next_rd()?, |  |  |  |                 src: args.next_rd()?, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "sst" => { |  |  |  |         "sst" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::StoreStatus { |  |  |  |             BuiltinOp::StoreStatus { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     dst: args.next_wr()?, |  |  |  |                 dst: args.next_wr()?, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "sld" => { |  |  |  |         "sld" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::LoadStatus { |  |  |  |             BuiltinOp::LoadStatus { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     src: args.next_rd()?, |  |  |  |                 src: args.next_rd()?, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "drop" => { |  |  |  |         "drop" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 BuiltinOp::Drop(args.next_rdobj()?) |  |  |  |             BuiltinOp::Drop(args.next_rdobj()?) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |         } | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             "far" => { |  |  |  |         "far" => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 if let Some(Sexp::Atom(Atom::S(ref label))) = args.peek() { |  |  |  |             if let Some(Sexp::Atom(Atom::S(ref label))) = args.peek() { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     if let Some(label) = label.strip_prefix(':') { |  |  |  |                 if let Some(label) = label.strip_prefix(':') { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         let label = Label::Named(label.to_string()); |  |  |  |                     let label = Label::Named(label.to_string()); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         BuiltinOp::FarLabel(label) |  |  |  |                     BuiltinOp::FarLabel(label) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     } else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         return Ok(ParseRes::Unknown(args)); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 } else { |  |  |  |                 } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |                     return Ok(ParseRes::Unknown(args)); |  |  |  |                     return Ok(ParseRes::Unknown(args)); | 
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 return Ok(ParseRes::Unknown(args)); | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             other => { |  |  |  |         other => { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 if let Some(label) = other.strip_prefix(':') { |  |  |  |             if let Some(label) = other.strip_prefix(':') { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     BuiltinOp::Label(parse_label_str(label)?) |  |  |  |                 BuiltinOp::Label(parse_label_str(label)?) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } else { |  |  |  |             } else { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     return Ok(ParseRes::Unknown(args)); |  |  |  |                 return Ok(ParseRes::Unknown(args)); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |         }))) |  |  |  |         } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     }))) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | pub(crate) fn parse_routine_name(name: String) -> Result<RoutineName, CrsnError> { |  |  |  | pub(crate) fn parse_routine_name(name: String) -> Result<RoutineName, CrsnError> { | 
			
		
	
	
		
		
			
				
					|  |  | @ -304,16 +285,16 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #[cfg(test)] |  |  |  | #[cfg(test)] | 
			
		
	
		
		
			
				
					
					|  |  |  | mod test { |  |  |  | mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  |     use std::any::Any; |  |  |  |     
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     use std::cell::RefCell; |  |  |  |     
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     use std::sync::atomic::AtomicU32; |  |  |  |     use std::sync::atomic::AtomicU32; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     use crate::asm::instr::{Flatten, InstrWithBranches}; |  |  |  |     use crate::asm::instr::{Flatten}; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     use crate::asm::parse::{parse_instructions, ParserContext}; |  |  |  |     use crate::asm::parse::{parse_instructions, ParserContext}; | 
			
		
	
		
		
			
				
					
					|  |  |  |     use crate::asm::parse::sexp_expect::expect_list; |  |  |  |     use crate::asm::parse::sexp_expect::expect_list; | 
			
		
	
		
		
			
				
					
					|  |  |  |     use crate::builtin::defs::BuiltinOp; |  |  |  |     
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     use crate::builtin::parse::BuiltinOps; |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     use crate::module::OpTrait; |  |  |  |     use crate::module::OpTrait; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     use crate::builtin::BuiltinOps; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     #[test] |  |  |  |     #[test] | 
			
		
	
		
		
			
				
					
					|  |  |  |     fn roundtrip() { |  |  |  |     fn roundtrip() { | 
			
		
	
	
		
		
			
				
					|  |  | @ -374,7 +355,7 @@ mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  |         let parsers = &[parser]; |  |  |  |         let parsers = &[parser]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         for (sample, expected) in samples { |  |  |  |         for (sample, expected) in samples { | 
			
		
	
		
		
			
				
					
					|  |  |  |             let mut pcx = ParserContext { |  |  |  |             let pcx = ParserContext { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 parsers, |  |  |  |                 parsers, | 
			
		
	
		
		
			
				
					
					|  |  |  |                 state: Default::default(), |  |  |  |                 state: Default::default(), | 
			
		
	
		
		
			
				
					
					|  |  |  |             }; |  |  |  |             }; | 
			
		
	
	
		
		
			
				
					|  |  | @ -386,7 +367,7 @@ mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .expect("parse sexp"); |  |  |  |                 .expect("parse sexp"); | 
			
		
	
		
		
			
				
					
					|  |  |  |             let list = expect_list(Some(s), false).unwrap(); |  |  |  |             let list = expect_list(Some(s), false).unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             let num = AtomicU32::new(0); |  |  |  |             let num = AtomicU32::new(0); | 
			
		
	
		
		
			
				
					
					|  |  |  |             let mut parsed = parse_instructions(list.into_iter(), &pcx) |  |  |  |             let parsed = parse_instructions(list.into_iter(), &pcx) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 .expect("parse instr").flatten(&num) |  |  |  |                 .expect("parse instr").flatten(&num) | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .expect("flatten").remove(0); |  |  |  |                 .expect("flatten").remove(0); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -402,7 +383,7 @@ mod test { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .expect("parse sexp (2c)"); |  |  |  |                 .expect("parse sexp (2c)"); | 
			
		
	
		
		
			
				
					
					|  |  |  |             let list = expect_list(Some(s), false).unwrap(); |  |  |  |             let list = expect_list(Some(s), false).unwrap(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             let num = AtomicU32::new(0); |  |  |  |             let num = AtomicU32::new(0); | 
			
		
	
		
		
			
				
					
					|  |  |  |             let mut parsed = parse_instructions(list.into_iter(), &pcx) |  |  |  |             let parsed = parse_instructions(list.into_iter(), &pcx) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 .expect("parse instr (2c)").flatten(&num) |  |  |  |                 .expect("parse instr (2c)").flatten(&num) | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .expect("flatten (2c)").remove(0); |  |  |  |                 .expect("flatten (2c)").remove(0); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | 
 |