|
|
|
@ -1,4 +1,4 @@ |
|
|
|
|
use sexp::{Atom, Sexp, SourcePosition, atom_qs, atom_s}; |
|
|
|
|
use sexp::{Atom, Sexp, SourcePosition, atom_qs}; |
|
|
|
|
|
|
|
|
|
use crate::asm::data::literal::{RoutineName}; |
|
|
|
|
use crate::asm::data::reg::parse_reg; |
|
|
|
@ -452,7 +452,7 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { |
|
|
|
|
if args.is_empty() { |
|
|
|
|
sexp::list(&[A("spawn"), A(handle), A(proc)]) |
|
|
|
|
} else { |
|
|
|
|
let mut v = vec![A("spawn"), A(handle), A(proc)]; |
|
|
|
|
let mut v = vec![A("spawn"), A(handle), A(&proc.name)]; |
|
|
|
|
v.extend(args.iter().map(|r| A(r))); |
|
|
|
|
sexp::list(&v) |
|
|
|
|
} |
|
|
|
@ -473,10 +473,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() { |
|
|
|
@ -562,13 +567,42 @@ mod test { |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
}, |
|
|
|
|
const_eval_ti: ti.clone(), |
|
|
|
|
parsing_expr: false |
|
|
|
|
}), |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
for (sample, expected) in samples { |
|
|
|
|
let pcx = ParserContext { |
|
|
|
|
parsers, |
|
|
|
|
state: Default::default(), |
|
|
|
|
}; |
|
|
|
|
pcx.state.borrow_mut().reset(); |
|
|
|
|
|
|
|
|
|
println!("Parse: {}", sample); |
|
|
|
|
|
|
|
|
@ -587,10 +621,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)) |
|
|
|
|