use netsblox_vm::real_time::*;
use netsblox_vm::std_system::*;
use netsblox_vm::std_util::*;
use netsblox_vm::bytecode::*;
use netsblox_vm::process::*;
use netsblox_vm::runtime::*;
use netsblox_vm::project::*;
use netsblox_vm::gc::*;
use netsblox_vm::ast;
use netsblox_vm::compact_str::CompactString;
use std::io::Read;
use std::time::Duration;
use std::sync::Arc;
use std::rc::Rc;
const BASE_URL: &'static str = "https://cloud.netsblox.org";
const CLOCK_INTERVAL: Duration = Duration::from_millis(10);
const COLLECT_INTERVAL: Duration = Duration::from_secs(60);
const YIELDS_BEFORE_SLEEP: usize = 64;
const IDLE_SLEEP_TIME: Duration = Duration::from_millis(1);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum NativeType {}
#[derive(Debug)]
enum NativeValue {} impl GetType for NativeValue {
type Output = NativeType;
fn get_type(&self) -> Self::Output {
unreachable!() }
}
struct EntityState; impl From<EntityKind<'_, '_, C, StdSystem<C>>> for EntityState {
fn from(_: EntityKind<'_, '_, C, StdSystem<C>>) -> Self {
EntityState
}
}
struct ProcessState; impl From<ProcessKind<'_, '_, C, StdSystem<C>>> for ProcessState {
fn from(_: ProcessKind<'_, '_, C, StdSystem<C>>) -> Self {
ProcessState
}
}
impl Unwindable for ProcessState {
type UnwindPoint = (); fn get_unwind_point(&self) -> Self::UnwindPoint { }
fn unwind_to(&mut self, _: &Self::UnwindPoint) { }
}
struct C; impl CustomTypes<StdSystem<C>> for C {
type NativeValue = NativeValue; type Intermediate = SimpleValue;
type EntityState = EntityState; type ProcessState = ProcessState;
fn from_intermediate<'gc>(mc: &Mutation<'gc>, value: Self::Intermediate) -> Value<'gc, C, StdSystem<C>> {
Value::from_simple(mc, value)
}
}
#[derive(Collect)]
#[collect(no_drop)]
struct Env<'gc> {
proj: Gc<'gc, RefLock<Project<'gc, C, StdSystem<C>>>>,
#[collect(require_static)] locs: Locations, }
type EnvArena = Arena<Rootable![Env<'_>]>;
fn get_running_project(xml: &str, system: Rc<StdSystem<C>>) -> EnvArena {
EnvArena::new(|mc| {
let parser = ast::Parser::default();
let ast = parser.parse(xml).unwrap();
assert_eq!(ast.roles.len(), 1);
let (bytecode, init_info, locs, _) = ByteCode::compile(&ast.roles[0]).unwrap();
let mut proj = Project::from_init(mc, &init_info, Rc::new(bytecode), Settings::default(), system);
proj.input(mc, Input::Start);
Env { proj: Gc::new(mc, RefLock::new(proj)), locs }
})
}
fn main() {
let args = std::env::args().collect::<Vec<_>>();
if args.len() != 2 {
panic!("usage: {} [xml file]", &args[0]);
}
let mut xml = String::new();
std::fs::File::open(&args[1]).expect("failed to open file").read_to_string(&mut xml).expect("failed to read file");
let clock = Arc::new(Clock::new(UtcOffset::UTC, Some(Precision::Medium)));
let clock_clone = clock.clone();
std::thread::spawn(move || loop {
std::thread::sleep(CLOCK_INTERVAL);
clock_clone.update();
});
let config = Config::<C, StdSystem<C>> {
request: None,
command: Some(Rc::new(|_mc, key, command, _proc| match command {
Command::Print { style: _, value } => {
if let Some(value) = value {
println!("{value:?}");
}
key.complete(Ok(())); CommandStatus::Handled
}
_ => CommandStatus::UseDefault { key, command }, })),
};
let system = Rc::new(StdSystem::new_sync(CompactString::new(BASE_URL), None, config, clock.clone()));
let mut env = get_running_project(&xml, system);
let mut idle_sleeper = IdleAction::new(YIELDS_BEFORE_SLEEP, Box::new(|| std::thread::sleep(IDLE_SLEEP_TIME)));
let mut next_collect = clock.read(Precision::Medium) + COLLECT_INTERVAL;
loop {
env.mutate(|mc, env| {
let mut proj = env.proj.borrow_mut(mc);
for _ in 0..1024 {
let res = proj.step(mc);
if let ProjectStep::Error { error, proc } = &res {
let trace = ErrorSummary::extract(error, proc, &env.locs);
println!("error: {error:?}\ntrace: {trace:?}");
}
idle_sleeper.consume(&res);
}
});
if clock.read(Precision::Low) >= next_collect {
env.collect_all();
next_collect = clock.read(Precision::Medium) + COLLECT_INTERVAL;
}
}
}