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