|  |  |  | @ -25,21 +25,21 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::Halt | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "uslp" => { | 
			
		
	
		
			
				
					|  |  |  |  |         "uslp" | "usleep" => { | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::Sleep { | 
			
		
	
		
			
				
					|  |  |  |  |                 count: args.next_rd()?, | 
			
		
	
		
			
				
					|  |  |  |  |                 unit_us: SleepUnit::Usec, | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "mslp" => { | 
			
		
	
		
			
				
					|  |  |  |  |         "mslp" | "msleep" => { | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::Sleep { | 
			
		
	
		
			
				
					|  |  |  |  |                 count: args.next_rd()?, | 
			
		
	
		
			
				
					|  |  |  |  |                 unit_us: SleepUnit::Msec, | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "sslp" => { | 
			
		
	
		
			
				
					|  |  |  |  |         "sslp" | "ssleep" => { | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::Sleep { | 
			
		
	
		
			
				
					|  |  |  |  |                 count: args.next_rd()?, | 
			
		
	
		
			
				
					|  |  |  |  |                 unit_us: SleepUnit::Sec, | 
			
		
	
	
		
			
				
					|  |  |  | @ -132,7 +132,7 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok | 
			
		
	
		
			
				
					|  |  |  |  |             for t in args { | 
			
		
	
		
			
				
					|  |  |  |  |                 call_args.push(parse_rd(t, pcx)?); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::Call(dest, call_args) | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::Call { proc: dest, args: call_args } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "ret" => { | 
			
		
	
	
		
			
				
					|  |  |  | @ -183,6 +183,21 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok | 
			
		
	
		
			
				
					|  |  |  |  |             }) | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "crit-begin" => { | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::CriticalBegin | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "crit-end" => { | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::CriticalEnd | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "rt-opt" => { | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::RuntimeOpt { | 
			
		
	
		
			
				
					|  |  |  |  |                 opt: args.next_rd()?, | 
			
		
	
		
			
				
					|  |  |  |  |                 value: args.next_rd()?, | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "ld" => { | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::Load { | 
			
		
	
		
			
				
					|  |  |  |  |                 dst: args.next_wr()?, | 
			
		
	
	
		
			
				
					|  |  |  | @ -258,6 +273,38 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "spawn" => { | 
			
		
	
		
			
				
					|  |  |  |  |             let handle = args.next_wr()?; | 
			
		
	
		
			
				
					|  |  |  |  |             let dest = RoutineName { name: args.next_string()?.0, arity: args.len() as u8 }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             let mut call_args = vec![]; | 
			
		
	
		
			
				
					|  |  |  |  |             for t in args { | 
			
		
	
		
			
				
					|  |  |  |  |                 call_args.push(parse_rd(t, pcx)?); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::Spawn { | 
			
		
	
		
			
				
					|  |  |  |  |                 handle, | 
			
		
	
		
			
				
					|  |  |  |  |                 proc: dest, | 
			
		
	
		
			
				
					|  |  |  |  |                 args: call_args | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "join" => { | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::Join(args.next_rdobj()?) | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "yield" => { | 
			
		
	
		
			
				
					|  |  |  |  |             if args.have_more() { | 
			
		
	
		
			
				
					|  |  |  |  |                 BuiltinOp::Yield { | 
			
		
	
		
			
				
					|  |  |  |  |                     value: Some(args.next_rd()?), | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |  |                 BuiltinOp::Yield { | 
			
		
	
		
			
				
					|  |  |  |  |                     value: None, | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         "del" => { | 
			
		
	
		
			
				
					|  |  |  |  |             BuiltinOp::Delete(args.next_rdobj()?) | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
	
		
			
				
					|  |  |  | @ -289,6 +336,10 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok | 
			
		
	
		
			
				
					|  |  |  |  |                 return Ok(ParseRes::builtin(BuiltinOp::Exchange { a, b, mask })); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             if let Some((dst, expected, src, mask)) = args.parse_masked_rdwr_rd_rd(other, "cas")? { | 
			
		
	
		
			
				
					|  |  |  |  |                 return Ok(ParseRes::builtin(BuiltinOp::CompareSwap { dst, expected, src, mask })); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             if other.starts_with(':') { | 
			
		
	
		
			
				
					|  |  |  |  |                 BuiltinOp::Label(parse_label_str(other, &op_pos)?) | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
	
		
			
				
					|  |  |  | @ -313,6 +364,9 @@ pub(crate) fn parse_routine_name(name: String, pos: &SourcePosition) -> Result<R | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { | 
			
		
	
		
			
				
					|  |  |  |  |     match op { | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::CriticalBegin => sexp::list(&[A("crit-begin")]), | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::CriticalEnd => sexp::list(&[A("crit-end")]), | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::RuntimeOpt { opt, value } => sexp::list(&[A("rt-opt"), A(opt), A(value)]), | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::Nop => sexp::list(&[A("nop")]), | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::Halt => sexp::list(&[A("halt")]), | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::Sleep { count: micros, unit_us: SleepUnit::Sec } => sexp::list(&[A("sslp"), A(micros)]), | 
			
		
	
	
		
			
				
					|  |  |  | @ -322,7 +376,7 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { | 
			
		
	
		
			
				
					|  |  |  |  |         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) => { | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::Call { proc: name, args } => { | 
			
		
	
		
			
				
					|  |  |  |  |             if args.is_empty() { | 
			
		
	
		
			
				
					|  |  |  |  |                 sexp::list(&[A("call"), A(&name.name)]) | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
	
		
			
				
					|  |  |  | @ -389,6 +443,13 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { | 
			
		
	
		
			
				
					|  |  |  |  |                 sexp::list(&[A(format!("xch{}", mask.width)), AM(a, mask.dst_pos), AM(b, mask.src_pos)]) | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         }, | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::CompareSwap { dst, expected, src, mask } => { | 
			
		
	
		
			
				
					|  |  |  |  |             if mask.is_full() { | 
			
		
	
		
			
				
					|  |  |  |  |                 sexp::list(&[A("cas"), A(dst), A(expected), A(src)]) | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |  |                 sexp::list(&[A(format!("cas{}", mask.width)), AM(dst, mask.dst_pos), AM(expected, mask.src_pos), AM(src, mask.src2_pos)]) | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         }, | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::StoreFlags { dst } => sexp::list(&[A("stf"), A(dst)]), | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::LoadFlags { src } => sexp::list(&[A("ldf"), A(src)]), | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::LoadSequence { dst, value } => { | 
			
		
	
	
		
			
				
					|  |  |  | @ -405,6 +466,22 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::Spawn { handle, proc, args } => { | 
			
		
	
		
			
				
					|  |  |  |  |             if args.is_empty() { | 
			
		
	
		
			
				
					|  |  |  |  |                 sexp::list(&[A("spawn"), A(handle), A(proc)]) | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |  |                 let mut v = vec![A("spawn"), A(handle), A(&proc.name)]; | 
			
		
	
		
			
				
					|  |  |  |  |                 v.extend(args.iter().map(|r| A(r))); | 
			
		
	
		
			
				
					|  |  |  |  |                 sexp::list(&v) | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::Join(handle) => sexp::list(&[A("join"), A(handle)]), | 
			
		
	
		
			
				
					|  |  |  |  |         BuiltinOp::Yield { value } => { | 
			
		
	
		
			
				
					|  |  |  |  |             match value { | 
			
		
	
		
			
				
					|  |  |  |  |                 None => sexp::list(&[A("yield")]), | 
			
		
	
		
			
				
					|  |  |  |  |                 Some(rd) => sexp::list(&[A("yield"), A(rd)]), | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -414,10 +491,15 @@ mod test { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     use sexp::SourcePosition; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     use crate::asm::parse::{parse_instructions, ParserContext}; | 
			
		
	
		
			
				
					|  |  |  |  |     use crate::asm::parse::{parse_instructions, ParserContext, ParserState}; | 
			
		
	
		
			
				
					|  |  |  |  |     use crate::asm::parse::sexp_expect::expect_list; | 
			
		
	
		
			
				
					|  |  |  |  |     use crate::builtin::BuiltinOps; | 
			
		
	
		
			
				
					|  |  |  |  |     use crate::module::OpTrait; | 
			
		
	
		
			
				
					|  |  |  |  |     use std::cell::RefCell; | 
			
		
	
		
			
				
					|  |  |  |  |     use std::sync::Arc; | 
			
		
	
		
			
				
					|  |  |  |  |     use crate::runtime::run_thread::{ThreadInfo, ThreadToken, RunState}; | 
			
		
	
		
			
				
					|  |  |  |  |     use crate::runtime::program::Program; | 
			
		
	
		
			
				
					|  |  |  |  |     use crate::runtime::frame::REG_COUNT; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     #[test] | 
			
		
	
		
			
				
					|  |  |  |  |     fn roundtrip() { | 
			
		
	
	
		
			
				
					|  |  |  | @ -474,6 +556,8 @@ mod test { | 
			
		
	
		
			
				
					|  |  |  |  |             ("(xch r0 r1)", "(xch r0 r1)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(xch32 r0 r1)", "(xch32 r0 r1)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(xch32 r0:8 r1:16)", "(xch32 r0:8 r1:16)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(cas r0 r1 r2)", "(cas r0 r1 r2)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(cas8 r0:8 r1:16 r2:24)", "(cas8 r0:8 r1:16 r2:24)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(ld r0 r0)", "(ld r0 r0)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(ld8 r0 r1)", "(ld8 r0 r1)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(ld16 r0 r1)", "(ld16 r0 r1)"), | 
			
		
	
	
		
			
				
					|  |  |  | @ -492,17 +576,53 @@ mod test { | 
			
		
	
		
			
				
					|  |  |  |  |             ("(far :label)", "(far :label)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(del @r5)", "(del @r5)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(sym cat r0)(del @cat)", "(del @r0)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(spawn r0 foo 1 2 3)", "(spawn r0 foo 1 2 3)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(yield)", "(yield)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(yield -1)", "(yield -1)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(yield r5)", "(yield r5)"), | 
			
		
	
		
			
				
					|  |  |  |  |             ("(join @r5)", "(join @r5)"), | 
			
		
	
		
			
				
					|  |  |  |  |         ]; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         let parser = BuiltinOps::new(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         let parsers = &[parser]; | 
			
		
	
		
			
				
					|  |  |  |  |         let parsers = Arc::new(vec![parser]); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         let ti = Arc::new(ThreadInfo { | 
			
		
	
		
			
				
					|  |  |  |  |             id: ThreadToken(0), | 
			
		
	
		
			
				
					|  |  |  |  |             uniq: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |             program: Program::new(vec![], parsers.clone()).unwrap(), | 
			
		
	
		
			
				
					|  |  |  |  |             cycle_time: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |             scheduler_interval: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |             extensions: parsers.clone(), | 
			
		
	
		
			
				
					|  |  |  |  |         }); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         let pcx = ParserContext { | 
			
		
	
		
			
				
					|  |  |  |  |             parsers: &parsers, | 
			
		
	
		
			
				
					|  |  |  |  |             state: RefCell::new(ParserState { | 
			
		
	
		
			
				
					|  |  |  |  |                 reg_aliases: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |                 reg_alias_stack: vec![], | 
			
		
	
		
			
				
					|  |  |  |  |                 global_reg_aliases: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |                 constants: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |                 // This is a fake thread to pass to constant expressions when evaluating them.
 | 
			
		
	
		
			
				
					|  |  |  |  |                 // This allows to evaluate nearly all instructions at compile time.
 | 
			
		
	
		
			
				
					|  |  |  |  |                 const_eval: RunState { | 
			
		
	
		
			
				
					|  |  |  |  |                     thread_info: ti.clone(), | 
			
		
	
		
			
				
					|  |  |  |  |                     cr: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |                     parked: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |                     global_regs: [0; REG_COUNT], | 
			
		
	
		
			
				
					|  |  |  |  |                     ext_data: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |                     cr_deadline: None, | 
			
		
	
		
			
				
					|  |  |  |  |                     critical_section: 0, | 
			
		
	
		
			
				
					|  |  |  |  |                 }, | 
			
		
	
		
			
				
					|  |  |  |  |                 const_eval_ti: ti.clone(), | 
			
		
	
		
			
				
					|  |  |  |  |                 parsing_expr: false, | 
			
		
	
		
			
				
					|  |  |  |  |                 label_num: Default::default() | 
			
		
	
		
			
				
					|  |  |  |  |             }), | 
			
		
	
		
			
				
					|  |  |  |  |         }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         for (sample, expected) in samples { | 
			
		
	
		
			
				
					|  |  |  |  |             let pcx = ParserContext { | 
			
		
	
		
			
				
					|  |  |  |  |                 parsers, | 
			
		
	
		
			
				
					|  |  |  |  |                 state: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |             }; | 
			
		
	
		
			
				
					|  |  |  |  |             pcx.state.borrow_mut().reset(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             println!("Parse: {}", sample); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -521,10 +641,7 @@ mod test { | 
			
		
	
		
			
				
					|  |  |  |  |             assert_eq!(expected, exported); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             println!(" - 2nd cycle"); | 
			
		
	
		
			
				
					|  |  |  |  |             let pcx = ParserContext { | 
			
		
	
		
			
				
					|  |  |  |  |                 parsers, | 
			
		
	
		
			
				
					|  |  |  |  |                 state: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |             }; | 
			
		
	
		
			
				
					|  |  |  |  |             pcx.state.borrow_mut().reset(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             /* second cycle, nothing should change */ | 
			
		
	
		
			
				
					|  |  |  |  |             let s = sexp::parse(&format!("({})", exported)) | 
			
		
	
	
		
			
				
					|  |  |  | 
 |