1#![cfg(not(test))]
2#![cfg(feature = "python")]
3mod py_lang;
4mod py_node;
5mod range;
6mod unicode_position;
7use py_lang::register_dynamic_language;
8use py_node::{Edit, SgNode};
9use range::{Pos, Range};
10
11use ast_grep_core::{AstGrep, Language, NodeMatch, StrDoc};
12use py_lang::PyLang;
13use pyo3::prelude::*;
14
15use unicode_position::UnicodePosition;
16
17#[pymodule]
19fn ast_grep_py(_py: Python, m: &Bound<PyModule>) -> PyResult<()> {
20 m.add_class::<SgRoot>()?;
21 m.add_class::<SgNode>()?;
22 m.add_class::<Range>()?;
23 m.add_class::<Pos>()?;
24 m.add_class::<Edit>()?;
25 m.add_function(wrap_pyfunction!(register_dynamic_language, m)?)?;
26 Ok(())
27}
28
29#[pyclass]
30struct SgRoot {
31 inner: AstGrep<StrDoc<PyLang>>,
32 filename: String,
33 pub(crate) position: UnicodePosition,
34}
35
36#[pymethods]
37impl SgRoot {
38 #[new]
39 fn new(src: &str, lang: &str) -> Self {
40 let position = UnicodePosition::new(src);
41 let lang: PyLang = lang.parse().unwrap();
42 let inner = lang.ast_grep(src);
43 Self {
44 inner,
45 filename: "anonymous".into(),
46 position,
47 }
48 }
49
50 fn root(slf: PyRef<Self>) -> SgNode {
51 let tree = unsafe { &*(&slf.inner as *const AstGrep<_>) } as &'static AstGrep<_>;
52 let inner = NodeMatch::from(tree.root());
53 SgNode {
54 inner,
55 root: slf.into(),
56 }
57 }
58
59 fn filename(&self) -> &str {
60 &self.filename
61 }
62}