use pyo3::prelude::*;
use pyo3::wrap_pyfunction;
mod lexer;
mod parser;
mod resolve;
mod env;
mod eval;
mod interp;
mod arena;
mod rust_jit;
mod graph_ir;
mod checkpoint;
mod trace;
mod type_check;
mod effect_check;
mod kg;
use eval::Evaluator;
use interp::{make_env, run_code, print_repr};
fn on_big_stack<R: Send>(f: impl FnOnce() -> R + Send) -> R {
let stack = eval::interp_stack_bytes();
std::thread::scope(|s| {
std::thread::Builder::new()
.stack_size(stack)
.spawn_scoped(s, || { eval::set_interp_stack(stack); f() })
.expect("failed to spawn interpreter thread")
.join()
.expect("interpreter thread panicked")
})
}
#[pyclass(name = "Rusty")]
pub struct RustyInterp;
#[pymethods]
impl RustyInterp {
#[new]
fn new() -> Self { RustyInterp }
fn eval(&self, code: &str) -> PyResult<String> {
on_big_stack(|| {
let env = make_env();
run_code(code, &env, &Evaluator::new()).map(|v| print_repr(&v))
}).map_err(pyo3::exceptions::PyRuntimeError::new_err)
}
fn eval_repr(&self, code: &str) -> PyResult<String> {
on_big_stack(|| {
let env = make_env();
run_code(code, &env, &Evaluator::new()).map(|v| format!("{}", v))
}).map_err(pyo3::exceptions::PyRuntimeError::new_err)
}
fn check(&self, code: &str) -> bool {
on_big_stack(|| {
let tokens = lexer::Lexer::new(code).tokenize();
match parser::Parser::new(tokens).parse_checked() {
Ok(ast) => !ast.is_empty(),
Err(_) => false,
}
})
}
fn __repr__(&self) -> &str { "<Rusty interpreter>" }
}
#[pyclass]
pub struct RustySession {
history: Vec<String>,
}
#[pymethods]
impl RustySession {
#[new]
fn new() -> Self { RustySession { history: Vec::new() } }
fn eval(&mut self, code: &str) -> PyResult<String> {
let history = &self.history;
let result = on_big_stack(|| {
let env = make_env();
let eval = Evaluator::new();
for prev in history {
let _ = run_code(prev, &env, &eval);
}
run_code(code, &env, &eval).map(|v| print_repr(&v))
});
match result {
Ok(s) => { self.history.push(code.to_string()); Ok(s) }
Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(e)),
}
}
fn reset(&mut self) { self.history.clear(); }
fn history_len(&self) -> usize { self.history.len() }
fn __repr__(&self) -> String {
format!("<RustySession history={}>", self.history.len())
}
}
#[pymodule]
fn rusty(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<RustyInterp>()?;
m.add_class::<RustySession>()?;
m.add_function(wrap_pyfunction!(eval_fn, m)?)?;
Ok(())
}
#[pyfunction]
#[pyo3(name = "eval")]
fn eval_fn(code: &str) -> PyResult<String> {
on_big_stack(|| {
let env = make_env();
run_code(code, &env, &Evaluator::new()).map(|v| print_repr(&v))
}).map_err(pyo3::exceptions::PyRuntimeError::new_err)
}