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]
105pub struct RustySession {
106 history: Vec<String>,
107}
108
109#[pymethods]
110impl RustySession {
111 #[new]
112 fn new() -> Self { RustySession { history: Vec::new() } }
113
114 fn eval(&mut self, code: &str) -> PyResult<String> {
116 let history = &self.history;
117 let result = on_big_stack(|| {
118 let env = make_env();
119 let eval = Evaluator::new();
120 for prev in history {
121 let _ = run_code(prev, &env, &eval);
122 }
123 run_code(code, &env, &eval).map(|v| print_repr(&v))
124 });
125 match result {
126 Ok(s) => { self.history.push(code.to_string()); Ok(s) }
127 Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(e)),
128 }
129 }
130
131 fn reset(&mut self) { self.history.clear(); }
133
134 fn history_len(&self) -> usize { self.history.len() }
136
137 fn __repr__(&self) -> String {
138 format!("<RustySession history={}>", self.history.len())
139 }
140}
141
142#[pymodule]
145fn rusty(m: &Bound<'_, PyModule>) -> PyResult<()> {
146 m.add_class::<RustyInterp>()?;
147 m.add_class::<RustySession>()?;
148 m.add_function(wrap_pyfunction!(eval_fn, m)?)?;
149 Ok(())
150}
151
152#[pyfunction]
154#[pyo3(name = "eval")]
155fn eval_fn(code: &str) -> PyResult<String> {
156 on_big_stack(|| {
157 let env = make_env();
158 run_code(code, &env, &Evaluator::new()).map(|v| print_repr(&v))
159 }).map_err(pyo3::exceptions::PyRuntimeError::new_err)
160}