1use crate::lcnf::*;
6use std::collections::HashMap;
7
8use super::functions::*;
9use super::functions::{FromImports, PYTHON_KEYWORDS};
10
11#[derive(Debug, Clone, PartialEq)]
13pub struct PythonClassVar {
14 pub name: String,
16 pub annotation: PythonType,
18 pub default: Option<PythonExpr>,
20}
21#[derive(Debug, Clone, PartialEq)]
23pub struct PythonFunction {
24 pub name: String,
26 pub params: Vec<PythonParam>,
28 pub return_type: Option<PythonType>,
30 pub body: Vec<PythonStmt>,
32 pub decorators: Vec<String>,
34 pub is_async: bool,
36 pub is_classmethod: bool,
38 pub is_staticmethod: bool,
40}
41impl PythonFunction {
42 pub fn new(name: impl Into<String>) -> Self {
44 PythonFunction {
45 name: name.into(),
46 params: Vec::new(),
47 return_type: None,
48 body: Vec::new(),
49 decorators: Vec::new(),
50 is_async: false,
51 is_classmethod: false,
52 is_staticmethod: false,
53 }
54 }
55}
56#[derive(Debug, Clone, PartialEq)]
58pub struct PythonClass {
59 pub name: String,
61 pub bases: Vec<String>,
63 pub methods: Vec<PythonFunction>,
65 pub class_vars: Vec<PythonClassVar>,
67 pub is_dataclass: bool,
69 pub is_abstract: bool,
71 pub decorators: Vec<String>,
73 pub docstring: Option<String>,
75}
76impl PythonClass {
77 pub fn new(name: impl Into<String>) -> Self {
79 PythonClass {
80 name: name.into(),
81 bases: Vec::new(),
82 methods: Vec::new(),
83 class_vars: Vec::new(),
84 is_dataclass: false,
85 is_abstract: false,
86 decorators: Vec::new(),
87 docstring: None,
88 }
89 }
90}
91#[derive(Debug, Clone, PartialEq)]
93pub struct PythonParam {
94 pub name: String,
96 pub annotation: Option<PythonType>,
98 pub default: Option<PythonExpr>,
100 pub is_vararg: bool,
102 pub is_kwarg: bool,
104 pub is_keyword_only: bool,
106}
107impl PythonParam {
108 pub fn simple(name: impl Into<String>) -> Self {
110 PythonParam {
111 name: name.into(),
112 annotation: None,
113 default: None,
114 is_vararg: false,
115 is_kwarg: false,
116 is_keyword_only: false,
117 }
118 }
119 pub fn typed(name: impl Into<String>, ty: PythonType) -> Self {
121 PythonParam {
122 name: name.into(),
123 annotation: Some(ty),
124 default: None,
125 is_vararg: false,
126 is_kwarg: false,
127 is_keyword_only: false,
128 }
129 }
130}
131#[derive(Debug, Clone, PartialEq)]
133pub struct MatchArm {
134 pub pattern: String,
136 pub guard: Option<PythonExpr>,
138 pub body: Vec<PythonStmt>,
140}
141#[derive(Debug, Clone, PartialEq)]
143pub enum PythonLit {
144 Int(i64),
146 Float(f64),
148 Str(String),
150 Bool(bool),
152 None,
154 Bytes(Vec<u8>),
156 Ellipsis,
158}
159pub struct PythonBackend {
164 pub module: PythonModule,
166 pub fn_map: HashMap<String, String>,
168 pub fresh_counter: usize,
170}
171impl PythonBackend {
172 pub fn new() -> Self {
174 PythonBackend {
175 module: PythonModule::new(),
176 fn_map: HashMap::new(),
177 fresh_counter: 0,
178 }
179 }
180 pub fn fresh_var(&mut self) -> String {
182 let n = self.fresh_counter;
183 self.fresh_counter += 1;
184 format!("_t{}", n)
185 }
186 pub fn mangle_name(&self, name: &str) -> String {
194 let mangled: String = name
195 .chars()
196 .map(|c| match c {
197 '.' | '\'' | '-' | ' ' => '_',
198 c if c.is_alphanumeric() || c == '_' => c,
199 _ => '_',
200 })
201 .collect();
202 if PYTHON_KEYWORDS.contains(&mangled.as_str())
203 || mangled.starts_with(|c: char| c.is_ascii_digit())
204 {
205 format!("_{}", mangled)
206 } else if mangled.is_empty() {
207 "_anon".to_string()
208 } else {
209 mangled
210 }
211 }
212 pub fn compile_module(decls: &[LcnfFunDecl]) -> Result<String, String> {
215 let mut backend = PythonBackend::new();
216 backend.module.add_from_import(
217 "typing",
218 vec![
219 ("Any".to_string(), None),
220 ("Optional".to_string(), None),
221 ("Union".to_string(), None),
222 ("List".to_string(), None),
223 ("Dict".to_string(), None),
224 ("Tuple".to_string(), None),
225 ("Callable".to_string(), None),
226 ],
227 );
228 for decl in decls {
229 let py_name = backend.mangle_name(&decl.name);
230 backend.fn_map.insert(decl.name.clone(), py_name);
231 }
232 for decl in decls {
233 let func = backend.compile_decl(decl)?;
234 backend.module.add_function(func);
235 }
236 for decl in decls {
237 if let Some(py_name) = backend.fn_map.get(&decl.name) {
238 backend.module.all_exports.push(py_name.clone());
239 }
240 }
241 Ok(backend.module.emit())
242 }
243 pub fn compile_decl(&mut self, decl: &LcnfFunDecl) -> Result<PythonFunction, String> {
245 let py_name = self.mangle_name(&decl.name);
246 let mut func = PythonFunction::new(py_name);
247 for param in &decl.params {
248 let param_name = format!("_v{}", param.id.0);
249 func.params.push(PythonParam {
250 name: param_name,
251 annotation: Some(PythonType::Any),
252 default: None,
253 is_vararg: false,
254 is_kwarg: false,
255 is_keyword_only: false,
256 });
257 }
258 func.return_type = Some(PythonType::Any);
259 let body_stmts = self.compile_expr_to_stmts(&decl.body)?;
260 func.body = body_stmts;
261 Ok(func)
262 }
263 pub(super) fn compile_expr_to_stmts(
266 &mut self,
267 expr: &LcnfExpr,
268 ) -> Result<Vec<PythonStmt>, String> {
269 self.compile_expr_stmts_inner(expr, &mut Vec::new())
270 }
271 pub(super) fn compile_expr_stmts_inner(
273 &mut self,
274 expr: &LcnfExpr,
275 stmts: &mut Vec<PythonStmt>,
276 ) -> Result<Vec<PythonStmt>, String> {
277 match expr {
278 LcnfExpr::Let {
279 name, value, body, ..
280 } => {
281 let py_name = self.mangle_name(name);
282 let py_val = self.compile_let_value(value)?;
283 stmts.push(PythonStmt::Assign(vec![PythonExpr::Var(py_name)], py_val));
284 self.compile_expr_stmts_inner(body, stmts)
285 }
286 LcnfExpr::Return(arg) => {
287 let py_expr = self.compile_arg(arg);
288 stmts.push(PythonStmt::Return(Some(py_expr)));
289 Ok(stmts.clone())
290 }
291 LcnfExpr::Unreachable => {
292 stmts.push(PythonStmt::Raise(Some(PythonExpr::Call(
293 Box::new(PythonExpr::Var("RuntimeError".to_string())),
294 vec![PythonExpr::Lit(PythonLit::Str("unreachable".to_string()))],
295 vec![],
296 ))));
297 Ok(stmts.clone())
298 }
299 LcnfExpr::TailCall(func, args) => {
300 let py_func = self.compile_arg(func);
301 let py_args: Vec<PythonExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
302 stmts.push(PythonStmt::Return(Some(PythonExpr::Call(
303 Box::new(py_func),
304 py_args,
305 vec![],
306 ))));
307 Ok(stmts.clone())
308 }
309 LcnfExpr::Case {
310 scrutinee,
311 alts,
312 default,
313 ..
314 } => {
315 let scrutinee_name = format!("_v{}", scrutinee.0);
316 let match_arms: Vec<MatchArm> = alts
317 .iter()
318 .map(|alt| {
319 let pattern = if alt.params.is_empty() {
320 alt.ctor_name.clone()
321 } else {
322 let param_names: Vec<String> =
323 alt.params.iter().map(|p| format!("_v{}", p.id.0)).collect();
324 format!("{}({})", alt.ctor_name, param_names.join(", "))
325 };
326 let mut arm_stmts = Vec::new();
327 let _ = self.compile_expr_stmts_inner(&alt.body, &mut arm_stmts);
328 MatchArm {
329 pattern,
330 guard: None,
331 body: arm_stmts,
332 }
333 })
334 .collect();
335 let mut all_arms = match_arms;
336 if let Some(def) = default {
337 let mut def_stmts = Vec::new();
338 let _ = self.compile_expr_stmts_inner(def, &mut def_stmts);
339 all_arms.push(MatchArm {
340 pattern: "_".to_string(),
341 guard: None,
342 body: def_stmts,
343 });
344 }
345 stmts.push(PythonStmt::Match(PythonExpr::Var(scrutinee_name), all_arms));
346 Ok(stmts.clone())
347 }
348 }
349 }
350 pub(super) fn compile_arg(&self, arg: &LcnfArg) -> PythonExpr {
352 match arg {
353 LcnfArg::Var(id) => PythonExpr::Var(format!("_v{}", id.0)),
354 LcnfArg::Lit(lit) => self.compile_lit(lit),
355 LcnfArg::Erased => PythonExpr::Lit(PythonLit::None),
356 LcnfArg::Type(_) => PythonExpr::Lit(PythonLit::None),
357 }
358 }
359 pub(super) fn compile_let_value(&mut self, value: &LcnfLetValue) -> Result<PythonExpr, String> {
361 match value {
362 LcnfLetValue::App(func, args) => {
363 let py_func = self.compile_arg(func);
364 let py_args: Vec<PythonExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
365 Ok(PythonExpr::Call(Box::new(py_func), py_args, vec![]))
366 }
367 LcnfLetValue::Proj(_, idx, var) => {
368 let obj = PythonExpr::Var(format!("_v{}", var.0));
369 Ok(PythonExpr::Subscript(
370 Box::new(obj),
371 Box::new(PythonExpr::Lit(PythonLit::Int(*idx as i64))),
372 ))
373 }
374 LcnfLetValue::Ctor(name, _, args) => {
375 let py_args: Vec<PythonExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
376 Ok(PythonExpr::Call(
377 Box::new(PythonExpr::Var(self.mangle_name(name))),
378 py_args,
379 vec![],
380 ))
381 }
382 LcnfLetValue::Lit(lit) => Ok(self.compile_lit(lit)),
383 LcnfLetValue::Erased => Ok(PythonExpr::Lit(PythonLit::None)),
384 LcnfLetValue::FVar(id) => Ok(PythonExpr::Var(format!("_v{}", id.0))),
385 LcnfLetValue::Reset(id) => Ok(PythonExpr::Var(format!("_v{}", id.0))),
386 LcnfLetValue::Reuse(id, name, _, args) => {
387 let py_args: Vec<PythonExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
388 let _ = id;
389 Ok(PythonExpr::Call(
390 Box::new(PythonExpr::Var(self.mangle_name(name))),
391 py_args,
392 vec![],
393 ))
394 }
395 }
396 }
397 pub(super) fn compile_lit(&self, lit: &LcnfLit) -> PythonExpr {
399 match lit {
400 LcnfLit::Nat(n) => PythonExpr::Lit(PythonLit::Int(*n as i64)),
401 LcnfLit::Str(s) => PythonExpr::Lit(PythonLit::Str(s.clone())),
402 }
403 }
404 pub fn emit_module(&self) -> String {
406 self.module.emit()
407 }
408}
409#[derive(Debug, Clone, PartialEq, Eq, Hash)]
411pub enum PythonType {
412 Int,
414 Float,
416 Str,
418 Bool,
420 None_,
422 List(Box<PythonType>),
424 Dict(Box<PythonType>, Box<PythonType>),
426 Tuple(Vec<PythonType>),
428 Optional(Box<PythonType>),
430 Union(Vec<PythonType>),
432 Custom(String),
434 Any,
436 Callable,
438 Set(Box<PythonType>),
440 FrozenSet(Box<PythonType>),
442 Generator(Box<PythonType>, Box<PythonType>, Box<PythonType>),
444 AsyncGenerator(Box<PythonType>, Box<PythonType>),
446 Iterator(Box<PythonType>),
448 Iterable(Box<PythonType>),
450 Sequence(Box<PythonType>),
452 Mapping(Box<PythonType>, Box<PythonType>),
454 ClassVar(Box<PythonType>),
456 Final(Box<PythonType>),
458 Type(Box<PythonType>),
460}
461#[derive(Debug, Clone, PartialEq)]
463pub enum FStringPart {
464 Literal(String),
466 Expr(PythonExpr),
468 ExprWithFormat(PythonExpr, String),
470}
471#[derive(Debug, Clone, PartialEq)]
473pub enum PythonStmt {
474 Expr(PythonExpr),
476 Assign(Vec<PythonExpr>, PythonExpr),
478 AugAssign(PythonExpr, String, PythonExpr),
480 AnnAssign(String, PythonType, Option<PythonExpr>),
482 If(
484 PythonExpr,
485 Vec<PythonStmt>,
486 Vec<(PythonExpr, Vec<PythonStmt>)>,
487 Vec<PythonStmt>,
488 ),
489 For(String, PythonExpr, Vec<PythonStmt>, Vec<PythonStmt>),
491 While(PythonExpr, Vec<PythonStmt>, Vec<PythonStmt>),
493 With(Vec<(PythonExpr, Option<String>)>, Vec<PythonStmt>),
495 Try(
497 Vec<PythonStmt>,
498 Vec<(Option<PythonExpr>, Option<String>, Vec<PythonStmt>)>,
499 Vec<PythonStmt>,
500 Vec<PythonStmt>,
501 ),
502 Return(Option<PythonExpr>),
504 Raise(Option<PythonExpr>),
506 Del(Vec<PythonExpr>),
508 Pass,
510 Break,
512 Continue,
514 Import(Vec<(String, Option<String>)>),
516 From(String, Vec<(String, Option<String>)>),
518 ClassDef(PythonClass),
520 FuncDef(PythonFunction),
522 AsyncFuncDef(PythonFunction),
524 Docstring(String),
526 Assert(PythonExpr, Option<PythonExpr>),
528 Global(Vec<String>),
530 Nonlocal(Vec<String>),
532 Match(PythonExpr, Vec<MatchArm>),
534 Raw(String),
536}
537#[derive(Debug, Clone)]
539pub struct PythonModule {
540 pub imports: Vec<(String, Option<String>)>,
542 pub from_imports: FromImports,
544 pub classes: Vec<PythonClass>,
546 pub functions: Vec<PythonFunction>,
548 pub statements: Vec<PythonStmt>,
550 pub module_docstring: Option<String>,
552 pub all_exports: Vec<String>,
554}
555impl PythonModule {
556 pub fn new() -> Self {
558 PythonModule {
559 imports: Vec::new(),
560 from_imports: Vec::new(),
561 classes: Vec::new(),
562 functions: Vec::new(),
563 statements: Vec::new(),
564 module_docstring: None,
565 all_exports: Vec::new(),
566 }
567 }
568 pub fn add_import(&mut self, module: impl Into<String>, alias: Option<String>) {
570 self.imports.push((module.into(), alias));
571 }
572 pub fn add_from_import(
574 &mut self,
575 module: impl Into<String>,
576 names: Vec<(String, Option<String>)>,
577 ) {
578 self.from_imports.push((module.into(), names));
579 }
580 pub fn add_class(&mut self, cls: PythonClass) {
582 self.classes.push(cls);
583 }
584 pub fn add_function(&mut self, func: PythonFunction) {
586 self.functions.push(func);
587 }
588 pub fn add_statement(&mut self, stmt: PythonStmt) {
590 self.statements.push(stmt);
591 }
592 pub fn emit(&self) -> String {
594 let mut out = String::new();
595 if let Some(doc) = &self.module_docstring {
596 out.push_str(&format!("\"\"\"{}\"\"\"\n\n", doc));
597 }
598 let future_imports: Vec<_> = self
599 .from_imports
600 .iter()
601 .filter(|(m, _)| m == "__future__")
602 .collect();
603 for (module, names) in &future_imports {
604 out.push_str(&format_from_import(module, names));
605 out.push('\n');
606 }
607 if !future_imports.is_empty() {
608 out.push('\n');
609 }
610 for (module, alias) in &self.imports {
611 match alias {
612 Some(a) => out.push_str(&format!("import {} as {}\n", module, a)),
613 None => out.push_str(&format!("import {}\n", module)),
614 }
615 }
616 if !self.imports.is_empty() {
617 out.push('\n');
618 }
619 let non_future: Vec<_> = self
620 .from_imports
621 .iter()
622 .filter(|(m, _)| m != "__future__")
623 .collect();
624 for (module, names) in &non_future {
625 out.push_str(&format_from_import(module, names));
626 out.push('\n');
627 }
628 if !non_future.is_empty() {
629 out.push('\n');
630 }
631 if !self.all_exports.is_empty() {
632 out.push_str("__all__ = [");
633 for (i, name) in self.all_exports.iter().enumerate() {
634 if i > 0 {
635 out.push_str(", ");
636 }
637 out.push_str(&format!("\"{}\"", name));
638 }
639 out.push_str("]\n\n");
640 }
641 for cls in &self.classes {
642 out.push_str(&emit_class(cls, 0));
643 out.push_str("\n\n");
644 }
645 for func in &self.functions {
646 out.push_str(&emit_function(func, 0));
647 out.push_str("\n\n");
648 }
649 for stmt in &self.statements {
650 out.push_str(&emit_stmt(stmt, 0));
651 out.push('\n');
652 }
653 out
654 }
655}
656#[derive(Debug, Clone, PartialEq)]
658pub enum PythonExpr {
659 Lit(PythonLit),
661 Var(String),
663 BinOp(String, Box<PythonExpr>, Box<PythonExpr>),
665 UnaryOp(String, Box<PythonExpr>),
667 Call(Box<PythonExpr>, Vec<PythonExpr>, Vec<(String, PythonExpr)>),
669 Attr(Box<PythonExpr>, String),
671 Subscript(Box<PythonExpr>, Box<PythonExpr>),
673 Lambda(Vec<String>, Box<PythonExpr>),
675 IfExpr(Box<PythonExpr>, Box<PythonExpr>, Box<PythonExpr>),
677 ListComp(
679 Box<PythonExpr>,
680 String,
681 Box<PythonExpr>,
682 Option<Box<PythonExpr>>,
683 ),
684 DictComp(
686 Box<PythonExpr>,
687 Box<PythonExpr>,
688 String,
689 String,
690 Box<PythonExpr>,
691 ),
692 SetComp(
694 Box<PythonExpr>,
695 String,
696 Box<PythonExpr>,
697 Option<Box<PythonExpr>>,
698 ),
699 GenExpr(
701 Box<PythonExpr>,
702 String,
703 Box<PythonExpr>,
704 Option<Box<PythonExpr>>,
705 ),
706 Tuple(Vec<PythonExpr>),
708 List(Vec<PythonExpr>),
710 Dict(Vec<(PythonExpr, PythonExpr)>),
712 Set(Vec<PythonExpr>),
714 Await(Box<PythonExpr>),
716 Yield(Option<Box<PythonExpr>>),
718 YieldFrom(Box<PythonExpr>),
720 Match(Box<PythonExpr>),
722 FString(Vec<FStringPart>),
724 Walrus(String, Box<PythonExpr>),
726 Star(Box<PythonExpr>),
728 DoubleStar(Box<PythonExpr>),
730 Slice(
732 Option<Box<PythonExpr>>,
733 Option<Box<PythonExpr>>,
734 Option<Box<PythonExpr>>,
735 ),
736}