(len: usize)
| 301 | |
| 302 | #[unsafe(no_mangle)] |
| 303 | pub unsafe extern "C" fn run(len: usize) -> usize { |
| 304 | let src = match read_src(len) { |
| 305 | Ok(s) => s, |
| 306 | Err(e) => return unsafe { |
| 307 | write_out(&s!("input rejected: invalid utf-8 at byte ", int e.valid_up_to())) |
| 308 | }, |
| 309 | }; |
| 310 | |
| 311 | let (tokens, lex_errs) = lex(&src); |
| 312 | let resolver = Box::new(WasmHostResolver { dir: String::new() }); |
| 313 | let mut p = Parser::with_resolver(&src, tokens.into_iter(), resolver); |
| 314 | for e in lex_errs { |
| 315 | p.errors.push(Diagnostic { start: e.start, end: e.end, msg: e.msg.into() }); |
| 316 | } |
| 317 | let (mut chunk, errs) = p.parse(); |
| 318 | |
| 319 | let out: String = if !errs.is_empty() { |
| 320 | let mut s = String::new(); |
| 321 | for (i, e) in errs.iter().enumerate() { |
| 322 | if i > 0 { s.push('\n'); } |
| 323 | s.push_str(&e.render(&src, None)); |
| 324 | } |
| 325 | s |
| 326 | } else { |
| 327 | crate::modules::vm::optimizer::constant_fold(&mut chunk); |
| 328 | let mut vm = VM::with_limits(&chunk, Limits::sandbox()); |
| 329 | vm.print_hook = Some(stream_print); |
| 330 | vm.set_time_hook(now_ns_host); |
| 331 | vm.strict_input = true; |
| 332 | // Drain any host-supplied input bytes; `UTF-8` invalid bytes degrade to an empty input rather than UB. |
| 333 | let inp_text = with_runtime(|rt| { |
| 334 | if rt.inp_len == 0 { return String::new(); } |
| 335 | let bytes = &rt.inp[..rt.inp_len]; |
| 336 | let inp = core::str::from_utf8(bytes).unwrap_or("").to_string(); |
| 337 | rt.inp_len = 0; |
| 338 | inp |
| 339 | }); |
| 340 | if !inp_text.is_empty() { |
| 341 | vm.input_buffer = inp_text.split('\n').map(alloc::string::String::from).collect(); |
| 342 | } |
| 343 | |
| 344 | // Publish VM for re-entrant host_edge_op via RAII guard so a panic or early return cannot leave a stale pointer in the runtime. |
| 345 | let _guard = VmGuard::new(&mut vm); |
| 346 | let result = vm.run(); |
| 347 | |
| 348 | match result { |
| 349 | Ok(_) => String::new(), |
| 350 | // Legacy `run` cannot suspend; embedders that need `sleep(n>0)` / `frame()` / `receive()` must drive `run_start` + `run_resume`. |
| 351 | Err(VmErr::HostYield(_)) => String::from( |
| 352 | "RuntimeError: scheduler suspended; this build's legacy `run` entry has no resume, drive `run_start` / `run_resume` instead.", |
| 353 | ), |
| 354 | Err(e) => e.render_traceback( |
| 355 | &src, vm.error_pos(), None, |
| 356 | vm.call_stack_frames(), vm.function_names_ref(), |
| 357 | ), |
| 358 | } |
| 359 | }; |
| 360 |
nothing calls this directly
no test coverage detected