cursython/backend/
stmt.rs

1use super::expr::*;
2use super::*;
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Debug, Serialize, Deserialize)]
6#[serde(tag = "type")]
7pub enum IfBranch {
8    If { condition: Value, content: Block },
9    Elif { condition: Value, content: Block },
10    Else { content: Block },
11}
12
13#[derive(Clone, Debug, Serialize, Deserialize)]
14#[serde(tag = "type")]
15pub struct SetStmt {
16    name: Ident,
17    value: Value,
18}
19
20#[derive(Clone, Debug, Serialize, Deserialize)]
21#[serde(tag = "type")]
22pub struct ImportStmt {
23    mod_name: Value,
24}
25
26#[derive(Clone, Debug, Serialize, Deserialize)]
27#[serde(tag = "type")]
28pub struct ImportAsStmt {
29    mod_name: Value,
30    import_as: Ident,
31}
32
33#[derive(Clone, Debug, Serialize, Deserialize)]
34#[serde(tag = "type")]
35pub struct FromImportStmt {
36    mod_name: Value,
37    import_from: Value,
38}
39
40#[derive(Clone, Debug, Serialize, Deserialize)]
41#[serde(tag = "type")]
42pub struct CallStmt {
43    base: Value,
44    args: Box<[Value]>,
45    kw_args: Box<[Kwarg]>,
46}
47
48#[derive(Clone, Debug, Serialize, Deserialize)]
49#[serde(tag = "type")]
50pub struct ReturnStmt {
51    value: Value,
52}
53
54#[derive(Clone, Debug, Serialize, Deserialize)]
55#[serde(tag = "type")]
56pub struct YieldStmt {
57    value: Value,
58}
59
60#[derive(Clone, Debug, Serialize, Deserialize)]
61#[serde(tag = "type")]
62pub struct PropertyStmt {
63    base: Value,
64    props: Box<[Ident]>,
65}
66
67#[derive(Clone, Debug, Serialize, Deserialize)]
68#[serde(tag = "type")]
69pub struct IfStmt {
70    branches: Box<[IfBranch]>,
71    block_indents: Option<usize>,
72}
73
74#[derive(Clone, Debug, Serialize, Deserialize)]
75#[serde(tag = "type")]
76pub struct ForStmt {
77    iter_subj: Value,
78    iter_vals: Box<[Ident]>,
79    content: Block,
80    block_indents: Option<usize>,
81}
82
83#[derive(Clone, Debug, Serialize, Deserialize)]
84#[serde(tag = "type")]
85pub struct WhileStmt {
86    cond: Value,
87    content: Block,
88    block_indents: Option<usize>,
89}
90
91#[derive(Clone, Debug, Serialize, Deserialize)]
92#[serde(tag = "type")]
93pub struct DefStmt {
94    name: Ident,
95    args: Box<[Ident]>,
96    kw_args: Box<[Kwarg]>,
97    content: Block,
98    decorator: Option<Value>,
99    block_indents: Option<usize>,
100}
101
102#[derive(Clone, Debug, Serialize, Deserialize)]
103#[serde(tag = "type")]
104pub struct ClassStmt {
105    name: Ident,
106    parents: Box<[Value]>,
107    methods: Box<[DefStmt]>,
108    block_indents: Option<usize>,
109}
110
111#[typetag::serde]
112impl Codegen for SetStmt {
113    fn code_gen(&self) -> String {
114        format!("{} = {}", self.name.code_gen(), self.value.code_gen())
115    }
116}
117
118#[typetag::serde]
119impl Codegen for CallStmt {
120    fn code_gen(&self) -> String {
121        let mut args = self
122            .args
123            .iter()
124            .map(|expr| expr.code_gen())
125            .collect::<Vec<String>>()
126            .join(", ");
127
128        let kwargs_vec = self
129            .kw_args
130            .iter()
131            .map(|kwarg| kwarg.code_gen())
132            .collect::<Vec<String>>();
133
134        let kwargs = if !kwargs_vec.is_empty() {
135            if !self.args.is_empty() {
136                args += ", "
137            }
138            kwargs_vec.join(", ")
139        } else {
140            "".to_owned()
141        };
142
143        format!("{}({}{})", self.base.code_gen(), args, kwargs)
144    }
145}
146
147#[typetag::serde]
148impl Codegen for ReturnStmt {
149    fn code_gen(&self) -> String {
150        format!("return {}", self.value.code_gen())
151    }
152}
153
154#[typetag::serde]
155impl Codegen for YieldStmt {
156    fn code_gen(&self) -> String {
157        format!("yield {}", self.value.code_gen())
158    }
159}
160
161#[typetag::serde]
162impl Codegen for PropertyStmt {
163    fn code_gen(&self) -> String {
164        let mut prop_items = self
165            .props
166            .iter()
167            .map(|ident| ident.code_gen())
168            .collect::<Vec<String>>();
169
170        let mut res = Vec::new();
171        res.push(self.base.code_gen());
172        res.append(&mut prop_items);
173
174        res.join(".")
175    }
176}
177
178#[typetag::serde]
179impl Codegen for ImportStmt {
180    fn code_gen(&self) -> String {
181        format!("import {}", self.mod_name.code_gen())
182    }
183}
184
185#[typetag::serde]
186impl Codegen for ImportAsStmt {
187    fn code_gen(&self) -> String {
188        format!(
189            "import {} as {}",
190            self.mod_name.code_gen(),
191            self.import_as.code_gen()
192        )
193    }
194}
195
196#[typetag::serde]
197impl Codegen for FromImportStmt {
198    fn code_gen(&self) -> String {
199        format!(
200            "from {} import {}",
201            self.import_from.code_gen(),
202            self.mod_name.code_gen()
203        )
204    }
205}
206
207#[typetag::serde]
208impl Codegen for IfStmt {
209    fn code_gen(&self) -> String {
210        let gen_branch = |branch: &IfBranch| {
211            use IfBranch::*;
212
213            match branch {
214                If { condition, content } => {
215                    format!("if {}{}", condition.code_gen(), content.code_gen())
216                }
217                Elif { condition, content } => {
218                    format!("elif {}{}", condition.code_gen(), content.code_gen())
219                }
220                Else { content } => format!("else{}", content.code_gen()),
221            }
222        };
223
224        self.branches
225            .iter()
226            .map(gen_branch)
227            .collect::<Vec<String>>()
228            .join("")
229    }
230
231    fn get_indents(&self) -> Option<usize> {
232        Some(self.block_indents.unwrap_or(1))
233    }
234
235    fn set_indents(&mut self, n: usize) {
236        self.block_indents = Some(n);
237
238        self.branches = self
239            .branches
240            .iter()
241            .map(|branch| match branch {
242                IfBranch::If { condition, content } => {
243                    let mut content = content.clone();
244                    content.set_indents(n);
245                    IfBranch::If {
246                        condition: condition.clone(),
247                        content,
248                    }
249                }
250                IfBranch::Elif { condition, content } => {
251                    let mut content = content.clone();
252                    content.set_indents(n);
253                    IfBranch::Elif {
254                        condition: condition.clone(),
255                        content,
256                    }
257                }
258                IfBranch::Else { content } => {
259                    let mut content = content.clone();
260                    content.set_indents(n);
261                    IfBranch::Else { content }
262                }
263            })
264            .collect::<Vec<IfBranch>>()
265            .into_boxed_slice();
266    }
267}
268
269#[typetag::serde]
270impl Codegen for ForStmt {
271    fn code_gen(&self) -> String {
272        let iter_vals = {
273            let res = self
274                .iter_vals
275                .iter()
276                .map(|ident| ident.code_gen())
277                .collect::<Vec<String>>()
278                .join(",");
279            format!("{}", res)
280        };
281
282        format!(
283            "for {} in {}{}",
284            iter_vals,
285            self.iter_subj.code_gen(),
286            self.content.code_gen()
287        )
288    }
289
290    fn get_indents(&self) -> Option<usize> {
291        Some(self.block_indents.unwrap_or(1))
292    }
293
294    fn set_indents(&mut self, n: usize) {
295        (self.block_indents, self.content.indents) = (Some(n), Some(n));
296    }
297}
298
299#[typetag::serde]
300impl Codegen for WhileStmt {
301    fn code_gen(&self) -> String {
302        format!("while {}{}", self.cond.code_gen(), self.content.code_gen())
303    }
304
305    fn get_indents(&self) -> Option<usize> {
306        Some(self.block_indents.unwrap_or(1))
307    }
308
309    fn set_indents(&mut self, n: usize) {
310        (self.block_indents, self.content.indents) = (Some(n), Some(n));
311    }
312}
313
314#[typetag::serde]
315impl Codegen for DefStmt {
316    fn code_gen(&self) -> String {
317        let indents_stmt = "    ".repeat(self.get_indents().unwrap() - 1);
318        let args = self
319            .args
320            .iter()
321            .map(|expr| expr.code_gen())
322            .collect::<Vec<String>>()
323            .join(", ");
324
325        let mut kwargs = self
326            .kw_args
327            .iter()
328            .map(|expr| expr.code_gen())
329            .collect::<Vec<String>>()
330            .join(", ");
331
332        if self.kw_args.is_empty() {
333            kwargs = "".to_owned()
334        }
335
336        let decorator = if let Some(deco) = &self.decorator {
337            format!("@{}\n{}", deco.code_gen(), indents_stmt)
338        } else {
339            "".to_owned()
340        };
341
342        format!(
343            "{}def {}({}{}){}",
344            decorator,
345            self.name.code_gen(),
346            args,
347            kwargs,
348            self.content.code_gen()
349        )
350    }
351
352    fn get_indents(&self) -> Option<usize> {
353        Some(self.block_indents.unwrap_or(1))
354    }
355
356    fn set_indents(&mut self, n: usize) {
357        (self.block_indents, self.content.indents) = (Some(n), Some(n));
358    }
359}
360
361#[typetag::serde]
362impl Codegen for ClassStmt {
363    fn code_gen(&self) -> String {
364        let indents = "    ".repeat(self.get_indents().unwrap());
365
366        let methods = self
367            .methods
368            .iter()
369            .map(|blk| {
370                let mut res = blk.clone();
371                res.set_indents(self.get_indents().unwrap() + 1);
372                format!("{}{}", indents, res.code_gen())
373            })
374            .collect::<Vec<String>>();
375
376        let methods_string = methods.join("\n");
377        let mut methods = String::from(":\n");
378        methods += methods_string.as_str();
379
380        let parents = self
381            .parents
382            .iter()
383            .map(|expr| expr.code_gen())
384            .collect::<Vec<String>>()
385            .join(", ");
386
387        format!("class {}({}){}", self.name.code_gen(), parents, methods)
388    }
389
390    fn get_indents(&self) -> Option<usize> {
391        Some(self.block_indents.unwrap_or(1))
392    }
393
394    fn set_indents(&mut self, n: usize) {
395        self.block_indents = Some(n);
396        self.methods = self
397            .methods
398            .iter()
399            .map(|stmt| {
400                let mut s = stmt.clone();
401                s.set_indents(n);
402                s
403            })
404            .collect::<Vec<DefStmt>>()
405            .into_boxed_slice();
406    }
407}