1use pyo3::prelude::*;
18use pyo3::wrap_pyfunction;
19
20mod lexer;
21mod parser;
22mod resolve;
23mod env;
24mod eval;
25mod interp;
26mod arena;
27mod rust_jit;
28mod graph_ir;
29mod checkpoint;
30mod trace;
31mod type_check;
32mod effect_check;
33mod kg;
34
35use eval::Evaluator;
36use interp::{make_env, run_code, print_repr};
37
38fn on_big_stack<R: Send>(f: impl FnOnce() -> R + Send) -> R {
45 let stack = eval::interp_stack_bytes();
46 std::thread::scope(|s| {
47 std::thread::Builder::new()
48 .stack_size(stack)
49 .spawn_scoped(s, || { eval::set_interp_stack(stack); f() })
50 .expect("failed to spawn interpreter thread")
51 .join()
52 .expect("interpreter thread panicked")
53 })
54}
55
56#[pyclass(name = "Rusty")]
61pub struct RustyInterp;
62
63#[pymethods]
64impl RustyInterp {
65 #[new]
66 fn new() -> Self { RustyInterp }
67
68 fn eval(&self, code: &str) -> PyResult<String> {
70 on_big_stack(|| {
71 let env = make_env();
72 run_code(code, &env, &Evaluator::new()).map(|v| print_repr(&v))
73 }).map_err(pyo3::exceptions::PyRuntimeError::new_err)
74 }
75
76 fn eval_repr(&self, code: &str) -> PyResult<String> {
78 on_big_stack(|| {
79 let env = make_env();
80 run_code(code, &env, &Evaluator::new()).map(|v| format!("{}", v))
81 }).map_err(pyo3::exceptions::PyRuntimeError::new_err)
82 }
83
84 fn check(&self, code: &str) -> bool {
86 on_big_stack(|| {
87 let tokens = lexer::Lexer::new(code).tokenize();
88 match parser::Parser::new(tokens).parse_checked() {
91 Ok(ast) => !ast.is_empty(),
92 Err(_) => false,
93 }
94 })
95 }
96
97 fn __repr__(&self) -> &str { "<Rusty interpreter>" }
98}
99
100#[pyclass]
108pub struct RustySession {
109 history: Vec<String>,
110}
111
112#[pymethods]
113impl RustySession {
114 #[new]
115 fn new() -> Self { RustySession { history: Vec::new() } }
116
117 fn eval(&mut self, code: &str) -> PyResult<String> {
119 let history = &self.history;
120 let result = on_big_stack(|| {
121 let env = make_env();
122 let eval = Evaluator::new();
123 for (i, prev) in history.iter().enumerate() {
124 if let Err(e) = run_code(prev, &env, &eval) {
125 return Err(format!(
126 "session history replay failed at form {} ({}): {}",
127 i + 1,
128 prev.chars().take(40).collect::<String>(),
129 e));
130 }
131 }
132 run_code(code, &env, &eval).map(|v| print_repr(&v))
133 });
134 match result {
135 Ok(s) => { self.history.push(code.to_string()); Ok(s) }
136 Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(e)),
137 }
138 }
139
140 fn reset(&mut self) { self.history.clear(); }
142
143 fn history_len(&self) -> usize { self.history.len() }
145
146 fn __repr__(&self) -> String {
147 format!("<RustySession history={}>", self.history.len())
148 }
149}
150
151#[pymodule]
154fn rusty(m: &Bound<'_, PyModule>) -> PyResult<()> {
155 m.add_class::<RustyInterp>()?;
156 m.add_class::<RustySession>()?;
157 m.add_function(wrap_pyfunction!(eval_fn, m)?)?;
158 Ok(())
159}
160
161#[pyfunction]
163#[pyo3(name = "eval")]
164fn eval_fn(code: &str) -> PyResult<String> {
165 on_big_stack(|| {
166 let env = make_env();
167 run_code(code, &env, &Evaluator::new()).map(|v| print_repr(&v))
168 }).map_err(pyo3::exceptions::PyRuntimeError::new_err)
169}