drone-micropython-core 0.1.1

MicroPython for Drone.
//! The module for parse, compile, execute.

use core::mem;
#[cfg(feature = "io")]
use drone_core::ffi::CStr;
#[cfg(feature = "io")]
use drone_micropython_raw::mp_lexer_new_from_file;
use drone_micropython_raw::{
  mp_call_function_0, mp_compile, mp_lexer_new_from_str_len, mp_lexer_t,
  mp_obj_print_exception, mp_obj_t, mp_parse, mp_parse_input_kind_t,
  mp_plat_print, nlr_pop, nlr_push, MP_QSTR__lt_stdin_gt_, MP_EMIT_OPT_NONE,
};

/// MicroPython Uncaught Exception.
#[derive(Debug, Fail)]
#[fail(display = "MicroPython uncaught exception.")]
pub struct UncaughtException;

pub(crate) unsafe fn exec_source(
  source: &str,
) -> Result<(), UncaughtException> {
  exec(|| {
    mp_lexer_new_from_str_len(
      MP_QSTR__lt_stdin_gt_ as _,
      source.as_ptr(),
      source.len(),
      0,
    )
  })
}

#[cfg(feature = "io")]
pub(crate) unsafe fn exec_path(path: &CStr) -> Result<(), UncaughtException> {
  exec(|| mp_lexer_new_from_file(path.as_ptr()))
}

unsafe fn exec<F>(f: F) -> Result<(), UncaughtException>
where
  F: FnOnce() -> *mut mp_lexer_t,
{
  exec_raw_fun(|| {
    let lex = f();
    let source_name = (*lex).source_name;
    let mut parse_tree =
      mp_parse(lex, mp_parse_input_kind_t::MP_PARSE_FILE_INPUT);
    mp_compile(&mut parse_tree, source_name, MP_EMIT_OPT_NONE, false)
  })
}

unsafe fn exec_raw_fun<F>(f: F) -> Result<(), UncaughtException>
where
  F: FnOnce() -> mp_obj_t,
{
  let mut nlr = mem::uninitialized();
  if nlr_push(&mut nlr) == 0 {
    mp_call_function_0(f());
    nlr_pop();
    Ok(())
  } else {
    mp_obj_print_exception(&mp_plat_print, nlr.ret_val);
    Err(UncaughtException)
  }
}