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::Int(i) => PythonExpr::Lit(PythonLit::Int(*i)),
402 LcnfLit::Str(s) => PythonExpr::Lit(PythonLit::Str(s.clone())),
403 }
404 }
405 pub fn emit_module(&self) -> String {
407 self.module.emit()
408 }
409}
410#[derive(Debug, Clone, PartialEq, Eq, Hash)]
412pub enum PythonType {
413 Int,
415 Float,
417 Str,
419 Bool,
421 None_,
423 List(Box<PythonType>),
425 Dict(Box<PythonType>, Box<PythonType>),
427 Tuple(Vec<PythonType>),
429 Optional(Box<PythonType>),
431 Union(Vec<PythonType>),
433 Custom(String),
435 Any,
437 Callable,
439 Set(Box<PythonType>),
441 FrozenSet(Box<PythonType>),
443 Generator(Box<PythonType>, Box<PythonType>, Box<PythonType>),
445 AsyncGenerator(Box<PythonType>, Box<PythonType>),
447 Iterator(Box<PythonType>),
449 Iterable(Box<PythonType>),
451 Sequence(Box<PythonType>),
453 Mapping(Box<PythonType>, Box<PythonType>),
455 ClassVar(Box<PythonType>),
457 Final(Box<PythonType>),
459 Type(Box<PythonType>),
461}
462#[derive(Debug, Clone, PartialEq)]
464pub enum FStringPart {
465 Literal(String),
467 Expr(PythonExpr),
469 ExprWithFormat(PythonExpr, String),
471}
472#[derive(Debug, Clone, PartialEq)]
474pub enum PythonStmt {
475 Expr(PythonExpr),
477 Assign(Vec<PythonExpr>, PythonExpr),
479 AugAssign(PythonExpr, String, PythonExpr),
481 AnnAssign(String, PythonType, Option<PythonExpr>),
483 If(
485 PythonExpr,
486 Vec<PythonStmt>,
487 Vec<(PythonExpr, Vec<PythonStmt>)>,
488 Vec<PythonStmt>,
489 ),
490 For(String, PythonExpr, Vec<PythonStmt>, Vec<PythonStmt>),
492 While(PythonExpr, Vec<PythonStmt>, Vec<PythonStmt>),
494 With(Vec<(PythonExpr, Option<String>)>, Vec<PythonStmt>),
496 Try(
498 Vec<PythonStmt>,
499 Vec<(Option<PythonExpr>, Option<String>, Vec<PythonStmt>)>,
500 Vec<PythonStmt>,
501 Vec<PythonStmt>,
502 ),
503 Return(Option<PythonExpr>),
505 Raise(Option<PythonExpr>),
507 Del(Vec<PythonExpr>),
509 Pass,
511 Break,
513 Continue,
515 Import(Vec<(String, Option<String>)>),
517 From(String, Vec<(String, Option<String>)>),
519 ClassDef(PythonClass),
521 FuncDef(PythonFunction),
523 AsyncFuncDef(PythonFunction),
525 Docstring(String),
527 Assert(PythonExpr, Option<PythonExpr>),
529 Global(Vec<String>),
531 Nonlocal(Vec<String>),
533 Match(PythonExpr, Vec<MatchArm>),
535 Raw(String),
537}
538#[derive(Debug, Clone)]
540pub struct PythonModule {
541 pub imports: Vec<(String, Option<String>)>,
543 pub from_imports: FromImports,
545 pub classes: Vec<PythonClass>,
547 pub functions: Vec<PythonFunction>,
549 pub statements: Vec<PythonStmt>,
551 pub module_docstring: Option<String>,
553 pub all_exports: Vec<String>,
555}
556impl PythonModule {
557 pub fn new() -> Self {
559 PythonModule {
560 imports: Vec::new(),
561 from_imports: Vec::new(),
562 classes: Vec::new(),
563 functions: Vec::new(),
564 statements: Vec::new(),
565 module_docstring: None,
566 all_exports: Vec::new(),
567 }
568 }
569 pub fn add_import(&mut self, module: impl Into<String>, alias: Option<String>) {
571 self.imports.push((module.into(), alias));
572 }
573 pub fn add_from_import(
575 &mut self,
576 module: impl Into<String>,
577 names: Vec<(String, Option<String>)>,
578 ) {
579 self.from_imports.push((module.into(), names));
580 }
581 pub fn add_class(&mut self, cls: PythonClass) {
583 self.classes.push(cls);
584 }
585 pub fn add_function(&mut self, func: PythonFunction) {
587 self.functions.push(func);
588 }
589 pub fn add_statement(&mut self, stmt: PythonStmt) {
591 self.statements.push(stmt);
592 }
593 pub fn emit(&self) -> String {
595 let mut out = String::new();
596 if let Some(doc) = &self.module_docstring {
597 out.push_str(&format!("\"\"\"{}\"\"\"\n\n", doc));
598 }
599 let future_imports: Vec<_> = self
600 .from_imports
601 .iter()
602 .filter(|(m, _)| m == "__future__")
603 .collect();
604 for (module, names) in &future_imports {
605 out.push_str(&format_from_import(module, names));
606 out.push('\n');
607 }
608 if !future_imports.is_empty() {
609 out.push('\n');
610 }
611 for (module, alias) in &self.imports {
612 match alias {
613 Some(a) => out.push_str(&format!("import {} as {}\n", module, a)),
614 None => out.push_str(&format!("import {}\n", module)),
615 }
616 }
617 if !self.imports.is_empty() {
618 out.push('\n');
619 }
620 let non_future: Vec<_> = self
621 .from_imports
622 .iter()
623 .filter(|(m, _)| m != "__future__")
624 .collect();
625 for (module, names) in &non_future {
626 out.push_str(&format_from_import(module, names));
627 out.push('\n');
628 }
629 if !non_future.is_empty() {
630 out.push('\n');
631 }
632 if !self.all_exports.is_empty() {
633 out.push_str("__all__ = [");
634 for (i, name) in self.all_exports.iter().enumerate() {
635 if i > 0 {
636 out.push_str(", ");
637 }
638 out.push_str(&format!("\"{}\"", name));
639 }
640 out.push_str("]\n\n");
641 }
642 for cls in &self.classes {
643 out.push_str(&emit_class(cls, 0));
644 out.push_str("\n\n");
645 }
646 for func in &self.functions {
647 out.push_str(&emit_function(func, 0));
648 out.push_str("\n\n");
649 }
650 for stmt in &self.statements {
651 out.push_str(&emit_stmt(stmt, 0));
652 out.push('\n');
653 }
654 out
655 }
656}
657#[derive(Debug, Clone, PartialEq)]
659pub enum PythonExpr {
660 Lit(PythonLit),
662 Var(String),
664 BinOp(String, Box<PythonExpr>, Box<PythonExpr>),
666 UnaryOp(String, Box<PythonExpr>),
668 Call(Box<PythonExpr>, Vec<PythonExpr>, Vec<(String, PythonExpr)>),
670 Attr(Box<PythonExpr>, String),
672 Subscript(Box<PythonExpr>, Box<PythonExpr>),
674 Lambda(Vec<String>, Box<PythonExpr>),
676 IfExpr(Box<PythonExpr>, Box<PythonExpr>, Box<PythonExpr>),
678 ListComp(
680 Box<PythonExpr>,
681 String,
682 Box<PythonExpr>,
683 Option<Box<PythonExpr>>,
684 ),
685 DictComp(
687 Box<PythonExpr>,
688 Box<PythonExpr>,
689 String,
690 String,
691 Box<PythonExpr>,
692 ),
693 SetComp(
695 Box<PythonExpr>,
696 String,
697 Box<PythonExpr>,
698 Option<Box<PythonExpr>>,
699 ),
700 GenExpr(
702 Box<PythonExpr>,
703 String,
704 Box<PythonExpr>,
705 Option<Box<PythonExpr>>,
706 ),
707 Tuple(Vec<PythonExpr>),
709 List(Vec<PythonExpr>),
711 Dict(Vec<(PythonExpr, PythonExpr)>),
713 Set(Vec<PythonExpr>),
715 Await(Box<PythonExpr>),
717 Yield(Option<Box<PythonExpr>>),
719 YieldFrom(Box<PythonExpr>),
721 Match(Box<PythonExpr>),
723 FString(Vec<FStringPart>),
725 Walrus(String, Box<PythonExpr>),
727 Star(Box<PythonExpr>),
729 DoubleStar(Box<PythonExpr>),
731 Slice(
733 Option<Box<PythonExpr>>,
734 Option<Box<PythonExpr>>,
735 Option<Box<PythonExpr>>,
736 ),
737}