1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use std::default::Default;

use crate::codegen::CodeGenContext;

use proc_macro2::TokenStream;
use quote::{quote, format_ident};
use pyo3::{PyAny, FromPyObject, PyResult};

pub mod statement;
pub use statement::*;

pub mod function_def;
pub use function_def::*;

pub mod arguments;
pub use arguments::*;

pub mod call;
pub use call::*;

pub mod class_def;
pub use class_def::*;

pub mod constant;
pub use constant::*;

pub mod expression;
pub use expression::*;

pub mod import;
pub use import::*;

pub mod parameters;
pub use parameters::*;

pub mod name;
pub use name::*;

use crate::codegen::{CodeGen, PythonOptions};

use log::info;

#[derive(Clone, Debug)]
pub enum Type {
    Unimplemented,
}

impl<'a> FromPyObject<'a> for Type {
    fn extract(ob: &'a PyAny) -> PyResult<Self> {
        info!("Type: {:?}", ob);
        Ok(Type::Unimplemented)
    }
}

/// Represents a module as imported from an ast.
#[derive(Clone, Debug, Default, FromPyObject)]
pub struct Module {
    pub body: Vec<Statement>,
    pub type_ignores: Vec<Type>,
}

impl<'a> CodeGen for Module {
    type Context = CodeGenContext;
    type Options = PythonOptions;

    fn to_rust(self, ctx: Self::Context, options: Self::Options) -> Result<TokenStream, Box<dyn std::error::Error>> {
        let mut stream = TokenStream::new();
        let stdpython = format_ident!("{}", options.stdpython);
        if options.with_std_python {
            stream.extend(quote!(use #stdpython::*;));
        }
        for s in self.body {
            let statement = s.clone().to_rust(ctx, options.clone())
                .expect(format!("parsing statement {:?} in module", s).as_str());
            if statement.to_string() != "" {
                stream.extend(statement);
            }
        }
        Ok(stream)
    }
}

#[cfg(test)]
mod tests {
    use super::*;


    #[test]
    fn does_module_compile() {
        let options = PythonOptions::default();
        let result = crate::parse("#test comment
def foo():
    continue
    pass
", "test_case").unwrap();
        info!("{:?}", result);
        let code = result.to_rust(CodeGenContext::Module, options);
        info!("module: {:?}", code);
    }

    #[test]
    fn can_we_print() {
        let options = PythonOptions::default();
        let result = crate::parse("#test comment
def foo():
    print(\"Test print.\")
", "test_case").unwrap();
        info!("Python tree: {:?}", result);
        //info!("{}", result);

        let code = result.to_rust(CodeGenContext::Module, options);
        info!("module: {:?}", code);
    }


    #[test]
    fn can_we_import() {
        let result = crate::parse("import ast", "ast").unwrap();
        let options = PythonOptions::default();
        info!("{:?}", result);

        let code = result.to_rust(CodeGenContext::Module, options);
        info!("module: {:?}", code);
    }

    #[test]
    fn can_we_import2() {
        let result = crate::parse("import ast.test as test", "ast").unwrap();
        let options = PythonOptions::default();
        info!("{:?}", result);

        let code = result.to_rust(CodeGenContext::Module, options);
        info!("module: {:?}", code);
    }

}