1use core::fmt;
2use std::path::Path;
3
4use erg_common::config::ErgConfig;
5use erg_common::dict::Dict as HashMap;
6use erg_common::error::Location as ErgLocation;
7use erg_common::fresh::FRESH_GEN;
8use erg_common::set::Set as HashSet;
9use erg_common::traits::{Locational, Stream, Traversable};
10use erg_common::{fmt_vec, log, set};
11use erg_compiler::artifact::IncompleteArtifact;
12use erg_compiler::erg_parser::ast::{
13 Accessor, Args, BinOp, Block, ClassAttr, ClassAttrs, ClassDef, Compound, ConstAccessor,
14 ConstApp, ConstArgs, ConstAttribute, ConstBinOp, ConstBlock, ConstDict, ConstExpr,
15 ConstKeyValue, ConstLambda, ConstList, ConstListWithLength, ConstNormalList, ConstNormalSet,
16 ConstPosArg, ConstSet, Decorator, Def, DefBody, DefId, DefaultParamSignature, Dict,
17 DictComprehension, Dummy, Expr, Identifier, KeyValue, KwArg, Lambda, LambdaSignature, List,
18 ListComprehension, Literal, Methods, Module, NonDefaultParamSignature, NormalDict, NormalList,
19 NormalRecord, NormalSet, NormalTuple, ParamPattern, ParamTySpec, Params, PosArg,
20 PreDeclTypeSpec, ReDef, Record, RecordAttrs, Set, SetComprehension, Signature, SubrSignature,
21 SubrTypeSpec, Tuple, TupleTypeSpec, TypeAppArgs, TypeAppArgsKind, TypeAscription,
22 TypeBoundSpec, TypeBoundSpecs, TypeSpec, TypeSpecWithOp, UnaryOp, VarName, VarPattern,
23 VarRecordAttr, VarRecordAttrs, VarRecordPattern, VarSignature, VisModifierSpec,
24};
25use erg_compiler::erg_parser::desugar::Desugarer;
26use erg_compiler::erg_parser::token::{Token, TokenKind, AS, COLON, DOT, EQUAL};
27use erg_compiler::erg_parser::Parser;
28use erg_compiler::error::{CompileError, CompileErrors};
29use rustpython_ast::located::LocatedMut;
30use rustpython_ast::source_code::RandomLocator;
31use rustpython_parser::ast::located::{
32 self as py_ast, Alias, Arg, Arguments, BoolOp, CmpOp, ExprConstant, Keyword, Located,
33 ModModule, Operator, Stmt, String, Suite, TypeParam, UnaryOp as UnOp,
34};
35use rustpython_parser::ast::Fold;
36use rustpython_parser::source_code::{
37 OneIndexed, SourceLocation as PyLocation, SourceRange as PySourceRange,
38};
39use rustpython_parser::Parse;
40
41use crate::ast_util::accessor_name;
42use crate::error::*;
43
44macro_rules! global_unary_collections {
45 () => {
46 "Collection" | "Container" | "Generator" | "Iterable" | "Iterator" | "Sequence" | "Set"
47 };
48}
49
50macro_rules! global_mutable_unary_collections {
51 () => {
52 "MutableSequence" | "MutableSet" | "MutableMapping"
53 };
54}
55
56macro_rules! global_binary_collections {
57 () => {
58 "Mapping"
59 };
60}
61
62pub const ARROW: Token = Token::dummy(TokenKind::FuncArrow, "->");
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
65pub enum RenameKind {
66 Let,
67 Phi,
68 Redef,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Hash)]
72pub enum NameKind {
73 Variable,
74 Class,
75 Function,
76}
77
78impl NameKind {
79 pub const fn is_variable(&self) -> bool {
80 matches!(self, Self::Variable)
81 }
82 pub const fn is_class(&self) -> bool {
83 matches!(self, Self::Class)
84 }
85 pub const fn is_function(&self) -> bool {
86 matches!(self, Self::Function)
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
91pub enum BlockKind {
92 If,
93 Else {
95 if_block_id: usize,
96 },
97 For,
98 While,
99 Try,
100 With,
101 Function,
102 AsyncFunction,
103 Class,
104 Module,
105}
106
107impl BlockKind {
108 pub const fn is_if(&self) -> bool {
109 matches!(self, Self::If)
110 }
111 pub const fn is_function(&self) -> bool {
112 matches!(self, Self::Function | Self::AsyncFunction)
113 }
114 pub const fn makes_scope(&self) -> bool {
115 matches!(self, Self::Function | Self::AsyncFunction | Self::Class)
116 }
117 pub const fn is_else(&self) -> bool {
118 matches!(self, Self::Else { .. })
119 }
120 pub const fn if_block_id(&self) -> Option<usize> {
121 match self {
122 Self::Else { if_block_id } => Some(*if_block_id),
123 _ => None,
124 }
125 }
126}
127
128fn escape_name(name: String) -> String {
131 match &name[..] {
132 "object" => "Obj".into(),
133 "int" => "Int".into(),
134 "float" => "Float".into(),
135 "complex" => "Complex".into(),
136 "str" => "Str".into(),
137 "bool" => "Bool".into(),
138 "list" => "GenericList".into(),
139 "bytes" => "Bytes".into(),
140 "bytearray" => "ByteArray!".into(),
141 "dict" => "GenericDict".into(),
143 "set" => "GenericSet".into(),
144 "tuple" => "GenericTuple".into(),
145 "type" => "Type".into(),
146 "ModuleType" => "GeneticModule".into(),
147 _ => name,
148 }
149}
150
151fn is_global_poly_type(name: &str) -> bool {
152 matches!(
153 name,
154 "list"
155 | "dict"
156 | "set"
157 | "tuple"
158 | "List"
159 | "Dict"
160 | "Tuple"
161 | global_unary_collections!()
162 | global_mutable_unary_collections!()
163 | global_binary_collections!()
164 )
165}
166
167fn quoted_symbol(sym: &str, lineno: u32, col_begin: u32) -> Token {
168 let col_end = col_begin + sym.chars().count() as u32;
169 Token {
170 kind: TokenKind::StrLit,
171 content: format!("\"{sym}\"").into(),
172 lineno,
173 col_begin,
174 col_end,
175 }
176}
177
178fn op_to_token(op: Operator) -> Token {
179 let (kind, cont) = match op {
180 Operator::Add => (TokenKind::Plus, "+"),
181 Operator::Sub => (TokenKind::Minus, "-"),
182 Operator::Mult => (TokenKind::Star, "*"),
183 Operator::Div => (TokenKind::Slash, "/"),
184 Operator::Mod => (TokenKind::Mod, "%"),
185 Operator::Pow => (TokenKind::Pow, "**"),
186 Operator::LShift => (TokenKind::Shl, "<<"),
187 Operator::RShift => (TokenKind::Shr, ">>"),
188 Operator::BitOr => (TokenKind::BitOr, "||"),
189 Operator::BitXor => (TokenKind::BitXor, "^^"),
190 Operator::BitAnd => (TokenKind::BitAnd, "&&"),
191 Operator::FloorDiv => (TokenKind::FloorDiv, "//"),
192 Operator::MatMult => (TokenKind::AtSign, "@"),
193 };
194 Token::from_str(kind, cont)
195}
196
197pub fn pyloc_to_ergloc(range: PySourceRange) -> erg_common::error::Location {
198 erg_common::error::Location::range(
199 range.start.row.get(),
200 range.start.column.to_zero_indexed(),
201 range.end.unwrap().row.get(),
202 range.end.unwrap().column.to_zero_indexed(),
203 )
204}
205
206pub fn ergloc_to_pyloc(loc: erg_common::error::Location) -> PySourceRange {
207 PySourceRange::new(
208 PyLocation {
209 row: OneIndexed::from_zero_indexed(loc.ln_begin().unwrap_or(0)),
210 column: OneIndexed::from_zero_indexed(loc.col_begin().unwrap_or(0)),
211 },
212 PyLocation {
213 row: OneIndexed::from_zero_indexed(loc.ln_end().unwrap_or(0)),
214 column: OneIndexed::from_zero_indexed(loc.col_end().unwrap_or(0)),
215 },
216 )
217}
218
219fn attr_name_loc(value: &Expr) -> PyLocation {
220 PyLocation {
221 row: OneIndexed::from_zero_indexed(value.ln_end().unwrap_or(0)).saturating_sub(1),
222 column: OneIndexed::from_zero_indexed(value.col_end().unwrap_or(0)).saturating_add(1),
223 }
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227pub enum DefinedPlace {
228 Known(String),
229 Unknown,
230}
231
232impl PartialEq<str> for DefinedPlace {
233 fn eq(&self, other: &str) -> bool {
234 match self {
235 Self::Known(s) => s == other,
236 Self::Unknown => false,
237 }
238 }
239}
240
241impl PartialEq<String> for DefinedPlace {
242 fn eq(&self, other: &String) -> bool {
243 match self {
244 Self::Known(s) => s == other,
245 Self::Unknown => false,
246 }
247 }
248}
249
250impl DefinedPlace {
251 pub const fn is_unknown(&self) -> bool {
252 matches!(self, Self::Unknown)
253 }
254}
255
256#[derive(Debug, Clone, PartialEq, Eq, Hash)]
257pub struct NameInfo {
258 kind: NameKind,
259 rename: Option<String>,
260 defined_in: DefinedPlace,
261 defined_block_id: usize,
262 defined_times: usize,
263 referenced: HashSet<String>,
264}
265
266impl NameInfo {
267 pub fn new(
268 kind: NameKind,
269 rename: Option<String>,
270 defined_in: DefinedPlace,
271 defined_block_id: usize,
272 defined_times: usize,
273 ) -> Self {
274 Self {
275 kind,
276 rename,
277 defined_in,
278 defined_block_id,
279 defined_times,
280 referenced: HashSet::new(),
281 }
282 }
283
284 pub fn add_referrer(&mut self, referrer: String) {
286 self.referenced.insert(referrer);
287 }
288}
289
290#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
291pub enum ShadowingMode {
292 Invisible,
293 Visible,
294}
295
296#[derive(Debug, Clone, PartialEq, Eq, Hash)]
297pub struct TypeVarInfo {
298 name: String,
299 constraints: Vec<Expr>,
300 bound: Option<Expr>,
301}
302
303impl fmt::Display for TypeVarInfo {
304 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305 if let Some(bound) = &self.bound {
306 write!(
307 f,
308 "TypeVarInfo({}, [{}], bound={})",
309 self.name,
310 fmt_vec(&self.constraints),
311 bound
312 )
313 } else {
314 write!(
315 f,
316 "TypeVarInfo({}, [{}])",
317 self.name,
318 fmt_vec(&self.constraints)
319 )
320 }
321 }
322}
323
324impl TypeVarInfo {
325 pub const fn new(name: String, constraints: Vec<Expr>, bound: Option<Expr>) -> Self {
326 Self {
327 name,
328 constraints,
329 bound,
330 }
331 }
332}
333
334#[derive(Debug)]
335pub struct BlockInfo {
336 pub id: usize,
337 pub kind: BlockKind,
338}
339
340#[derive(Debug)]
341pub enum ReturnKind {
342 None,
343 Return,
344 Yield,
345}
346
347impl ReturnKind {
348 pub const fn is_none(&self) -> bool {
349 matches!(self, Self::None)
350 }
351}
352
353#[derive(Debug)]
354pub struct LocalContext {
355 pub name: String,
356 pub kind: BlockKind,
357 names: HashMap<String, NameInfo>,
359 type_vars: HashMap<String, TypeVarInfo>,
360 appeared_type_names: HashSet<String>,
362 return_kind: ReturnKind,
363}
364
365impl LocalContext {
366 pub fn new(name: String, kind: BlockKind) -> Self {
367 Self {
368 name,
369 kind,
370 names: HashMap::new(),
371 type_vars: HashMap::new(),
372 appeared_type_names: HashSet::new(),
373 return_kind: ReturnKind::None,
374 }
375 }
376}
377
378#[derive(Debug, Default)]
379pub struct CommentStorage {
380 comments: HashMap<u32, (String, Option<py_ast::Expr>)>,
381}
382
383impl fmt::Display for CommentStorage {
384 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
385 for (i, (comment, expr)) in &self.comments {
386 writeln!(f, "line {i}: \"{comment}\" (expr: {})", expr.is_some())?;
387 }
388 Ok(())
389 }
390}
391
392impl CommentStorage {
393 pub fn new() -> Self {
394 Self {
395 comments: HashMap::new(),
396 }
397 }
398
399 pub fn read(&mut self, code: &str) {
400 let mut locater = RandomLocator::new(code);
402 for (i, line) in code.lines().enumerate() {
403 let mut split = line.split('#');
404 let _code = split.next().unwrap();
405 if let Some(comment) = split.next() {
406 let comment = comment.to_string();
407 let trimmed = comment.trim_start();
408 let expr = if trimmed.starts_with("type:") {
409 let typ = trimmed.trim_start_matches("type:").trim();
410 let typ = if typ == "ignore" { "Any" } else { typ };
411 rustpython_ast::Expr::parse(typ, "<module>")
412 .ok()
413 .and_then(|expr| locater.fold(expr).ok())
414 } else {
415 None
416 };
417 self.comments.insert(i as u32, (comment, expr));
418 }
419 }
420 }
421
422 pub fn get_code(&self, line: u32) -> Option<&String> {
424 self.comments.get(&line).map(|(code, _)| code)
425 }
426
427 pub fn get_type(&self, line: u32) -> Option<&py_ast::Expr> {
429 self.comments.get(&line).and_then(|(_, ty)| ty.as_ref())
430 }
431}
432
433#[derive(Debug, Clone)]
434pub struct PyFuncTypeSpec {
435 type_params: Vec<py_ast::TypeParam>,
436 args: py_ast::Arguments,
437 returns: Option<py_ast::Expr>,
438}
439
440#[derive(Debug, Clone)]
441pub enum PyTypeSpec {
442 Var(py_ast::Expr),
443 Func(PyFuncTypeSpec),
444}
445
446#[derive(Debug, Default)]
447pub struct PyiTypeStorage {
448 decls: HashMap<String, PyTypeSpec>,
449 classes: HashMap<String, HashMap<String, PyTypeSpec>>,
450}
451
452impl fmt::Display for PyiTypeStorage {
453 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
454 for (name, t_spec) in &self.decls {
455 writeln!(f, "{name}: {t_spec:?}")?;
456 }
457 for (class, methods) in &self.classes {
458 writeln!(f, "class {class}:")?;
459 for (name, t_spec) in methods {
460 writeln!(f, " {name}: {t_spec:?}")?;
461 }
462 }
463 Ok(())
464 }
465}
466
467impl PyiTypeStorage {
468 pub fn new() -> Self {
469 Self {
470 decls: HashMap::new(),
471 classes: HashMap::new(),
472 }
473 }
474
475 pub fn parse(&mut self, filename: &str) {
476 let Ok(code) = std::fs::read_to_string(filename) else {
477 return;
478 };
479 let Ok(py_program) = rustpython_ast::ModModule::parse(&code, filename) else {
480 return;
481 };
482 let mut locator = RandomLocator::new(&code);
483 let Ok(py_program) = locator.fold(py_program);
484 for stmt in py_program.body {
485 match stmt {
486 py_ast::Stmt::AnnAssign(assign) => {
487 let py_ast::Expr::Name(name) = *assign.target else {
488 continue;
489 };
490 self.decls
491 .insert(name.id.to_string(), PyTypeSpec::Var(*assign.annotation));
492 }
493 py_ast::Stmt::FunctionDef(def) => {
494 let returns = def.returns.map(|anot| *anot);
495 self.decls.insert(
496 def.name.to_string(),
497 PyTypeSpec::Func(PyFuncTypeSpec {
498 type_params: def.type_params,
499 args: *def.args,
500 returns,
501 }),
502 );
503 }
504 py_ast::Stmt::AsyncFunctionDef(def) => {
505 let returns = def.returns.map(|anot| *anot);
506 self.decls.insert(
507 def.name.to_string(),
508 PyTypeSpec::Func(PyFuncTypeSpec {
509 type_params: def.type_params,
510 args: *def.args,
511 returns,
512 }),
513 );
514 }
515 py_ast::Stmt::ClassDef(class) => {
516 let mut methods = HashMap::new();
517 for stmt in class.body {
518 match stmt {
519 py_ast::Stmt::AnnAssign(assign) => {
520 let py_ast::Expr::Name(name) = *assign.target else {
521 continue;
522 };
523 methods.insert(
524 name.id.to_string(),
525 PyTypeSpec::Var(*assign.annotation),
526 );
527 }
528 py_ast::Stmt::FunctionDef(def) => {
529 let returns = def.returns.map(|anot| *anot);
530 methods.insert(
531 def.name.to_string(),
532 PyTypeSpec::Func(PyFuncTypeSpec {
533 type_params: def.type_params,
534 args: *def.args,
535 returns,
536 }),
537 );
538 }
539 py_ast::Stmt::AsyncFunctionDef(def) => {
540 let returns = def.returns.map(|anot| *anot);
541 methods.insert(
542 def.name.to_string(),
543 PyTypeSpec::Func(PyFuncTypeSpec {
544 type_params: def.type_params,
545 args: *def.args,
546 returns,
547 }),
548 );
549 }
550 _ => {}
551 }
552 }
553 self.classes.insert(class.name.to_string(), methods);
554 }
555 _ => {}
556 }
557 }
558 }
559
560 pub fn get_type(&self, name: &str) -> Option<&PyTypeSpec> {
561 self.decls.get(name)
562 }
563
564 pub fn get_class_member_type(&self, class: &str, name: &str) -> Option<&PyTypeSpec> {
565 self.classes
566 .get(class)
567 .and_then(|methods| methods.get(name))
568 }
569}
570
571#[derive(Debug)]
596pub struct ASTConverter {
597 cfg: ErgConfig,
598 shadowing: ShadowingMode,
599 comments: CommentStorage,
600 pyi_types: PyiTypeStorage,
601 block_id_counter: usize,
602 blocks: Vec<BlockInfo>,
604 contexts: Vec<LocalContext>,
605 warns: CompileErrors,
606 errs: CompileErrors,
607}
608
609impl ASTConverter {
610 pub fn new(cfg: ErgConfig, shadowing: ShadowingMode, comments: CommentStorage) -> Self {
611 let mut pyi_types = PyiTypeStorage::new();
612 pyi_types.parse(&cfg.input.path().with_extension("pyi").to_string_lossy());
613 Self {
614 shadowing,
615 pyi_types,
616 cfg,
617 comments,
618 block_id_counter: 0,
619 blocks: vec![BlockInfo {
620 id: 0,
621 kind: BlockKind::Module,
622 }],
623 contexts: vec![LocalContext::new("<module>".into(), BlockKind::Module)],
624 warns: CompileErrors::empty(),
625 errs: CompileErrors::empty(),
626 }
627 }
628
629 fn get_name(&self, name: &str) -> Option<&NameInfo> {
630 for ctx in self.contexts.iter().rev() {
631 if let Some(ni) = ctx.names.get(name) {
632 return Some(ni);
633 }
634 }
635 None
636 }
637
638 fn get_mut_name(&mut self, name: &str) -> Option<&mut NameInfo> {
639 for ctx in self.contexts.iter_mut().rev() {
640 if let Some(ni) = ctx.names.get_mut(name) {
641 return Some(ni);
642 }
643 }
644 None
645 }
646
647 fn get_type_var(&self, name: &str) -> Option<&TypeVarInfo> {
648 for ctx in self.contexts.iter().rev() {
649 if let Some(tv) = ctx.type_vars.get(name) {
650 return Some(tv);
651 }
652 }
653 None
654 }
655
656 fn is_type_name(&self, name: &str) -> bool {
657 is_global_poly_type(name)
658 || self
659 .contexts
660 .iter()
661 .rev()
662 .any(|ctx| ctx.names.get(name).is_some_and(|ni| ni.kind.is_class()))
663 }
664
665 fn define_name(&mut self, name: String, info: NameInfo) {
666 self.contexts.last_mut().unwrap().names.insert(name, info);
667 }
668
669 fn declare_name(&mut self, name: String, info: NameInfo) {
670 self.contexts.first_mut().unwrap().names.insert(name, info);
671 }
672
673 fn define_type_var(&mut self, name: String, info: TypeVarInfo) {
674 self.contexts
675 .last_mut()
676 .unwrap()
677 .type_vars
678 .insert(name, info);
679 }
680
681 fn grow(&mut self, namespace: String, kind: BlockKind) {
682 self.contexts.push(LocalContext::new(namespace, kind));
683 }
684
685 fn pop(&mut self) {
686 self.contexts.pop();
687 }
688
689 fn cur_block_kind(&self) -> BlockKind {
690 self.blocks.last().unwrap().kind
691 }
692
693 fn cur_block_id(&self) -> usize {
694 self.blocks.last().unwrap().id
695 }
696
697 fn cur_namespace(&self) -> String {
699 self.contexts
700 .iter()
701 .map(|ctx| &ctx.name[..])
702 .collect::<Vec<_>>()
703 .join(".")
704 }
705
706 fn cur_name(&self) -> &str {
708 &self.contexts.last().unwrap().name
709 }
710
711 fn cur_context(&self) -> &LocalContext {
712 self.contexts.last().unwrap()
713 }
714
715 fn cur_context_mut(&mut self) -> &mut LocalContext {
716 self.contexts.last_mut().unwrap()
717 }
718
719 fn parent_name(&self) -> &str {
720 &self.contexts[self.contexts.len().saturating_sub(2)].name
721 }
722
723 fn cur_appeared_type_names(&self) -> &HashSet<String> {
724 &self.contexts.last().unwrap().appeared_type_names
725 }
726
727 fn register_name_info(&mut self, name: &str, kind: NameKind) -> RenameKind {
728 let cur_namespace = self.cur_namespace();
729 let cur_block_id = self.cur_block_id();
730 let cur_block_kind = self.cur_block_kind();
731 if let Some(name_info) = self.get_mut_name(name) {
732 if name_info.defined_in == cur_namespace && name_info.defined_block_id == cur_block_id {
733 name_info.defined_times += 1;
734 }
735 if name_info.defined_in.is_unknown() {
736 name_info.defined_in = DefinedPlace::Known(cur_namespace);
737 name_info.defined_times += 1; }
739 if cur_block_kind
740 .if_block_id()
741 .is_some_and(|id| id == name_info.defined_block_id)
742 {
743 RenameKind::Phi
744 } else if cur_block_kind.makes_scope()
745 || name_info.defined_block_id == cur_block_id
746 || name_info.defined_times == 0
747 {
748 RenameKind::Let
749 } else {
750 RenameKind::Redef
751 }
752 } else {
753 let rename = if kind.is_class() && !name.starts_with(char::is_uppercase) {
756 Some(format!("Type_{name}"))
757 } else {
758 None
759 };
760 let defined_in = DefinedPlace::Known(self.cur_namespace());
761 let info = NameInfo::new(kind, rename, defined_in, self.cur_block_id(), 1);
762 self.define_name(String::from(name), info);
763 RenameKind::Let
764 }
765 }
766
767 fn convert_ident(&mut self, name: String, loc: PyLocation) -> Identifier {
768 let shadowing = self.shadowing;
769 let name = escape_name(name);
770 let cur_namespace = self.cur_namespace();
771 let cur_block_id = self.cur_block_id();
772 let cont = if let Some(name_info) = self.get_mut_name(&name) {
773 let different_namespace = name_info.defined_in != cur_namespace;
774 if cur_block_id != 0 {
775 name_info.add_referrer(cur_namespace);
777 }
778 if different_namespace {
779 name
780 } else {
781 let name = name_info
782 .rename
783 .as_ref()
784 .map_or_else(|| &name, |renamed| renamed);
785 if name_info.defined_times > 1 {
786 if shadowing == ShadowingMode::Invisible {
787 format!("{name}{}", "\0".repeat(name_info.defined_times))
789 } else {
790 format!("{name}__{}", name_info.defined_times)
791 }
792 } else {
793 name.clone()
794 }
795 }
796 } else {
797 let defined_in = if self.cur_namespace() == "<module>" {
798 DefinedPlace::Known(self.cur_namespace())
799 } else {
800 DefinedPlace::Unknown
801 };
802 let mut info = NameInfo::new(NameKind::Variable, None, defined_in, cur_block_id, 0);
803 info.add_referrer(cur_namespace);
804 self.declare_name(name.clone(), info);
805 name
806 };
807 let token = Token::new(
808 TokenKind::Symbol,
809 cont,
810 loc.row.get(),
811 loc.column.to_zero_indexed(),
812 );
813 let name = VarName::new(token);
814 let dot = Token::new(
815 TokenKind::Dot,
816 ".",
817 loc.row.get(),
818 loc.column.to_zero_indexed(),
819 );
820 Identifier::new(VisModifierSpec::Public(dot.loc()), name)
821 }
822
823 fn convert_attr_ident(&mut self, name: String, loc: PyLocation) -> Identifier {
825 let token = Token::new(
826 TokenKind::Symbol,
827 name,
828 loc.row.get(),
829 loc.column.to_zero_indexed(),
830 );
831 let name = VarName::new(token);
832 let dot = Token::new(
833 TokenKind::Dot,
834 ".",
835 loc.row.get(),
836 loc.column.to_zero_indexed(),
837 );
838 Identifier::new(VisModifierSpec::Public(dot.loc()), name)
839 }
840
841 fn convert_param_pattern(&mut self, arg: String, loc: PyLocation) -> ParamPattern {
843 self.register_name_info(&arg, NameKind::Variable);
844 let ident = self.convert_ident(arg, loc);
845 ParamPattern::VarName(ident.name)
846 }
847
848 fn get_cur_scope_t_spec(&self) -> Option<&PyTypeSpec> {
849 if self.contexts.len() == 2 {
850 let func_name = self.cur_name();
851 self.pyi_types.get_type(func_name)
852 } else {
853 let class = self.parent_name();
854 let func_name = self.cur_name();
855 self.pyi_types.get_class_member_type(class, func_name)
856 }
857 }
858
859 fn convert_nd_param(&mut self, param: Arg) -> NonDefaultParamSignature {
860 let pat = self.convert_param_pattern(param.arg.to_string(), param.location());
861 let t_spec = param
862 .annotation
863 .or_else(|| {
864 let PyTypeSpec::Func(func) = self.get_cur_scope_t_spec()? else {
865 return None;
866 };
867 func.args
868 .args
869 .iter()
870 .chain(&func.args.kwonlyargs)
871 .find(|arg| arg.def.arg == param.arg)
872 .and_then(|arg| arg.def.annotation.clone())
873 })
874 .map(|anot| {
875 (
876 self.convert_type_spec(*anot.clone()),
877 self.convert_expr(*anot),
878 )
879 })
880 .map(|(t_spec, expr)| {
881 let as_op = Token::new(
882 TokenKind::As,
883 "as",
884 t_spec.ln_begin().unwrap_or(0),
885 t_spec.col_begin().unwrap_or(0),
886 );
887 TypeSpecWithOp::new(as_op, t_spec, expr)
888 });
889 NonDefaultParamSignature::new(pat, t_spec)
890 }
891
892 fn convert_default_param(&mut self, kw: Arg, default: py_ast::Expr) -> DefaultParamSignature {
893 let sig = self.convert_nd_param(kw);
894 let default = self.convert_expr(default);
895 DefaultParamSignature::new(sig, default)
896 }
897
898 fn convert_params(&mut self, params: Arguments) -> Params {
899 #[allow(clippy::type_complexity)]
900 fn split_args(
901 params: Arguments,
902 ) -> (Vec<Arg>, Option<Arg>, Vec<(Arg, py_ast::Expr)>, Option<Arg>) {
903 let mut args = Vec::new();
904 let mut with_defaults = Vec::new();
905 let var_args = params.vararg.map(|x| *x);
906 let kw_args = params.kwarg.map(|x| *x);
907 for arg in params
908 .posonlyargs
909 .into_iter()
910 .chain(params.args.into_iter())
911 .chain(params.kwonlyargs.into_iter())
912 {
913 if let Some(default) = arg.default {
914 with_defaults.push((arg.def, *default));
915 } else {
916 args.push(arg.def);
917 }
918 }
919 (args, var_args, with_defaults, kw_args)
920 }
921 let (non_defaults, var_args, defaults, kw_args) = split_args(params);
922 let non_defaults = non_defaults
923 .into_iter()
924 .map(|p| self.convert_nd_param(p))
925 .collect();
926 let var_params = var_args.map(|p| self.convert_nd_param(p));
927 let defaults = defaults
928 .into_iter()
929 .map(|(kw, default)| self.convert_default_param(kw, default))
930 .collect();
931 let kw_var_params = kw_args.map(|p| self.convert_nd_param(p));
932 Params::new(non_defaults, var_params, defaults, kw_var_params, None)
933 }
934
935 fn convert_for_param(&mut self, name: String, loc: PyLocation) -> NonDefaultParamSignature {
936 let pat = self.convert_param_pattern(name, loc);
937 let t_spec = None;
938 NonDefaultParamSignature::new(pat, t_spec)
939 }
940
941 fn param_pattern_to_var(pat: ParamPattern) -> VarPattern {
942 match pat {
943 ParamPattern::VarName(name) => VarPattern::Ident(Identifier::new(
944 VisModifierSpec::Public(ErgLocation::Unknown),
945 name,
946 )),
947 ParamPattern::Discard(token) => VarPattern::Discard(token),
948 other => todo!("{other}"),
949 }
950 }
951
952 fn convert_opt_expr_to_param(
954 &mut self,
955 expr: Option<py_ast::Expr>,
956 ) -> (NonDefaultParamSignature, Vec<Expr>) {
957 if let Some(expr) = expr {
958 self.convert_expr_to_param(expr)
959 } else {
960 let token = Token::new(TokenKind::UBar, "_", 0, 0);
961 (
962 NonDefaultParamSignature::new(ParamPattern::Discard(token), None),
963 vec![],
964 )
965 }
966 }
967
968 fn convert_expr_to_param(
969 &mut self,
970 expr: py_ast::Expr,
971 ) -> (NonDefaultParamSignature, Vec<Expr>) {
972 match expr {
973 py_ast::Expr::Name(expr) => (
974 self.convert_for_param(expr.id.to_string(), expr.location()),
975 vec![],
976 ),
977 py_ast::Expr::Tuple(expr) => {
978 let loc = expr.location();
979 let tmp = FRESH_GEN.fresh_varname();
980 let tmp_name = VarName::from_str_and_line(tmp, expr.location().row.get());
981 let tmp_expr = Expr::Accessor(Accessor::Ident(Identifier::new(
982 VisModifierSpec::Public(ErgLocation::Unknown),
983 tmp_name.clone(),
984 )));
985 let mut block = vec![];
986 for (i, elem) in expr.elts.into_iter().enumerate() {
987 let index = Literal::new(Token::new(
988 TokenKind::NatLit,
989 i.to_string(),
990 elem.location().row.get(),
991 elem.location().column.to_zero_indexed(),
992 ));
993 let (param, mut blocks) = self.convert_expr_to_param(elem);
994 let sig = Signature::Var(VarSignature::new(
995 Self::param_pattern_to_var(param.pat),
996 param.t_spec,
997 ));
998 let method = tmp_expr
999 .clone()
1000 .attr_expr(self.convert_ident("__getitem__".to_string(), loc));
1001 let tuple_acc = method.call1(Expr::Literal(index));
1002 let body = DefBody::new(EQUAL, Block::new(vec![tuple_acc]), DefId(0));
1003 let def = Expr::Def(Def::new(sig, body));
1004 block.push(def);
1005 block.append(&mut blocks);
1006 }
1007 let pat = ParamPattern::VarName(tmp_name);
1008 (NonDefaultParamSignature::new(pat, None), block)
1009 }
1010 other => {
1011 let token = Token::new(
1012 TokenKind::UBar,
1013 "_",
1014 other.location().row.get(),
1015 other.location().column.to_zero_indexed(),
1016 );
1017 (
1018 NonDefaultParamSignature::new(ParamPattern::Discard(token), None),
1019 vec![],
1020 )
1021 }
1022 }
1023 }
1024
1025 fn convert_for_body(&mut self, lhs: Option<py_ast::Expr>, body: Suite) -> Lambda {
1026 let (param, block) = self.convert_opt_expr_to_param(lhs);
1027 let params = Params::new(vec![param], None, vec![], None, None);
1028 self.block_id_counter += 1;
1029 self.blocks.push(BlockInfo {
1030 id: self.block_id_counter,
1031 kind: BlockKind::For,
1032 });
1033 let body = body
1034 .into_iter()
1035 .map(|stmt| self.convert_statement(stmt, true))
1036 .collect::<Vec<_>>();
1037 self.blocks.pop();
1038 let body = block.into_iter().chain(body).collect();
1039 let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
1040 let op = Token::from_str(TokenKind::FuncArrow, "->");
1041 Lambda::new(sig, op, Block::new(body), DefId(0))
1042 }
1043
1044 fn convert_ident_type_spec(&mut self, name: String, range: PySourceRange) -> TypeSpec {
1045 let loc = pyloc_to_ergloc(range);
1046 let global = ConstExpr::Accessor(ConstAccessor::Local(Identifier::private_with_loc(
1047 "global".into(),
1048 loc,
1049 )));
1050 let obj = ConstExpr::Accessor(ConstAccessor::Local(Identifier::private_with_loc(
1051 "Obj".into(),
1052 loc,
1053 )));
1054 match &name[..] {
1055 "dict" => {
1056 let kv = ConstKeyValue::new(obj.clone(), obj.clone());
1057 let (l, r) = Self::gen_enclosure_tokens(TokenKind::LSqBr, range);
1058 let dict = ConstDict::new(l, r, vec![kv]);
1059 TypeSpec::poly(
1060 global.attr(Identifier::private_with_loc("Dict!".into(), loc)),
1061 ConstArgs::single(ConstExpr::Dict(dict)),
1062 )
1063 }
1064 "set" => TypeSpec::poly(
1065 global.attr(Identifier::private_with_loc("Set!".into(), loc)),
1066 ConstArgs::single(obj),
1067 ),
1068 "tuple" => TypeSpec::poly(
1069 global.attr(Identifier::private_with_loc("HomogenousTuple".into(), loc)),
1070 ConstArgs::single(obj),
1071 ),
1072 global_unary_collections!() => TypeSpec::poly(
1074 global.attr(Identifier::private_with_loc(name.into(), loc)),
1075 ConstArgs::single(obj),
1076 ),
1077 global_mutable_unary_collections!() => TypeSpec::poly(
1079 global.attr(Identifier::private_with_loc(
1080 format!("{}!", name.trim_start_matches("Mutable")).into(),
1081 loc,
1082 )),
1083 ConstArgs::single(obj),
1084 ),
1085 global_binary_collections!() => TypeSpec::poly(
1087 global.attr(Identifier::private_with_loc(name.into(), loc)),
1088 ConstArgs::pos_only(
1089 vec![ConstPosArg::new(obj.clone()), ConstPosArg::new(obj)],
1090 None,
1091 ),
1092 ),
1093 _ => TypeSpec::mono(self.convert_ident(name, range.start)),
1094 }
1095 }
1096
1097 fn gen_dummy_type_spec(loc: PyLocation) -> TypeSpec {
1098 TypeSpec::Infer(Token::new(
1099 TokenKind::UBar,
1100 "_",
1101 loc.row.get(),
1102 loc.column.to_zero_indexed(),
1103 ))
1104 }
1105
1106 fn convert_const_expr(&mut self, expr: ConstExpr) -> ConstExpr {
1107 match expr {
1108 ConstExpr::UnaryOp(un) if un.op.is(TokenKind::Mutate) => *un.expr,
1109 ConstExpr::App(app)
1110 if app
1111 .attr_name
1112 .as_ref()
1113 .is_some_and(|n| n.inspect() == "__getitem__") =>
1114 {
1115 let obj = self.convert_const_expr(*app.obj);
1116 let mut args = app.args.map(&mut |arg| self.convert_const_expr(arg));
1117 if args.pos_args.is_empty() {
1118 return ConstExpr::App(ConstApp::new(obj, app.attr_name, args));
1119 }
1120 let mut args = match args.pos_args.remove(0).expr {
1121 ConstExpr::Tuple(tuple) => tuple.elems,
1122 other => {
1123 args.pos_args.insert(0, ConstPosArg::new(other));
1124 args
1125 }
1126 };
1127 match obj.local_name() {
1128 Some("Union") => {
1129 if args.pos_args.len() >= 2 {
1130 let first = args.pos_args.remove(0).expr;
1131 let or_op = Token::dummy(TokenKind::OrOp, "or");
1132 args.pos_args.into_iter().fold(first, |acc, expr| {
1133 ConstExpr::BinOp(ConstBinOp::new(or_op.clone(), acc, expr.expr))
1134 })
1135 } else if args.pos_args.len() == 1 {
1136 args.pos_args.remove(0).expr
1137 } else {
1138 ConstExpr::App(ConstApp::new(obj, app.attr_name, args))
1139 }
1140 }
1141 Some("GenericDict" | "Dict") => {
1142 if args.pos_args.len() == 2 {
1143 let key = args.pos_args.remove(0).expr;
1144 let value = args.pos_args.remove(0).expr;
1145 let key_value = ConstKeyValue::new(key, value);
1146 ConstExpr::Dict(ConstDict::new(
1147 Token::DUMMY,
1148 Token::DUMMY,
1149 vec![key_value],
1150 ))
1151 } else {
1152 ConstExpr::App(ConstApp::new(obj, app.attr_name, args))
1153 }
1154 }
1155 Some("GenericList" | "List") => {
1156 if args.pos_args.len() == 2 {
1157 let elem = args.pos_args.remove(0).expr;
1158 let len = args.pos_args.remove(0).expr;
1159 let l_brace = Token::dummy(TokenKind::LSqBr, "[");
1160 let r_brace = Token::dummy(TokenKind::RSqBr, "]");
1161 ConstExpr::List(ConstList::WithLength(ConstListWithLength::new(
1162 l_brace, r_brace, elem, len,
1163 )))
1164 } else {
1165 let obj = ConstExpr::Accessor(ConstAccessor::Local(
1166 Identifier::private("List".into()),
1167 ));
1168 ConstExpr::App(ConstApp::new(obj, None, args))
1169 }
1170 }
1171 Some("GenericTuple" | "Tuple") => {
1172 if args.pos_args.get(1).is_some_and(|arg| matches!(&arg.expr, ConstExpr::Lit(l) if l.is(TokenKind::EllipsisLit))) {
1173 let ty = args.pos_args.remove(0).expr;
1174 let obj = ConstExpr::Accessor(ConstAccessor::Local(
1175 Identifier::private("HomogenousTuple".into()),
1176 ));
1177 let args = ConstArgs::single(ty);
1178 ConstExpr::App(ConstApp::new(obj, None, args))
1179 } else {
1180 let obj = ConstExpr::Accessor(ConstAccessor::Local(
1181 Identifier::private("Tuple".into()),
1182 ));
1183 let range = ergloc_to_pyloc(args.loc());
1184 let (l, r) = Self::gen_enclosure_tokens(TokenKind::LSqBr, range);
1185 let list = ConstList::Normal(ConstNormalList::new(l, r, args, None));
1186 let args = ConstArgs::single(ConstExpr::List(list));
1187 ConstExpr::App(ConstApp::new(obj, None, args))
1188 }
1189 }
1190 Some("Optional") => {
1191 let arg = args.pos_args.remove(0).expr;
1192 let none = ConstExpr::Accessor(ConstAccessor::Local(Identifier::private(
1193 "NoneType".into(),
1194 )));
1195 let or_op = Token::dummy(TokenKind::OrOp, "or");
1196 ConstExpr::BinOp(ConstBinOp::new(or_op, arg, none))
1197 }
1198 Some("Literal") => {
1199 let set = ConstNormalSet::new(Token::DUMMY, Token::DUMMY, args);
1200 ConstExpr::Set(ConstSet::Normal(set))
1201 }
1202 Some("Callable") => {
1203 let params = if args.pos_args.is_empty() {
1204 self.errs.push(CompileError::syntax_error(
1205 self.cfg.input.clone(),
1206 line!() as usize,
1207 args.loc(),
1208 self.cur_namespace(),
1209 "`Callable` takes an input type list and a return type".into(),
1210 None,
1211 ));
1212 ConstArgs::empty()
1213 } else {
1214 match args.pos_args.remove(0).expr {
1215 ConstExpr::List(ConstList::Normal(list)) => list.elems,
1216 other => {
1217 args.pos_args.insert(0, ConstPosArg::new(other));
1218 args.clone()
1219 }
1220 }
1221 };
1222 let non_defaults = params
1223 .pos_args
1224 .into_iter()
1225 .map(|param| {
1226 let expr = match param.expr.downgrade() {
1227 Expr::Literal(lit) if lit.is(TokenKind::NoneLit) => {
1228 Expr::Accessor(Accessor::Ident(Identifier::private(
1229 "NoneType".into(),
1230 )))
1231 }
1232 other => other,
1233 };
1234 let ty = Parser::expr_to_type_spec(expr.clone())
1235 .unwrap_or(TypeSpec::mono(Identifier::private("Any".into())));
1236 let discard = Token::dummy(TokenKind::UBar, "_");
1237 let t_spec = TypeSpecWithOp::new(
1238 Token::dummy(TokenKind::Colon, ":"),
1239 ty,
1240 expr,
1241 );
1242 NonDefaultParamSignature::new(
1243 ParamPattern::Discard(discard),
1244 Some(t_spec),
1245 )
1246 })
1247 .collect();
1248 let params = Params::new(non_defaults, None, vec![], None, None);
1249 let ret = if args.pos_args.is_empty() {
1250 self.errs.push(CompileError::syntax_error(
1251 self.cfg.input.clone(),
1252 line!() as usize,
1253 args.loc(),
1254 self.cur_namespace(),
1255 "Expected a return type".into(),
1256 None,
1257 ));
1258 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Any".into())))
1259 } else {
1260 match args.pos_args.remove(0).expr {
1261 ConstExpr::Lit(lit) if lit.is(TokenKind::NoneLit) => {
1262 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private(
1263 "NoneType".into(),
1264 )))
1265 }
1266 other => other,
1267 }
1268 };
1269 let op = Token::dummy(TokenKind::ProcArrow, "=>");
1270 let body = ConstBlock::new(vec![ret]);
1271 let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
1272 ConstExpr::Lambda(ConstLambda::new(sig, op, body, DefId(0)))
1273 }
1274 _ => ConstExpr::App(ConstApp::new(obj, app.attr_name, args)),
1275 }
1276 }
1277 _ => expr.map(&mut |expr| self.convert_const_expr(expr)),
1278 }
1279 }
1280
1281 fn convert_expr_to_const(&mut self, expr: py_ast::Expr) -> Option<ConstExpr> {
1282 let expr = self.convert_expr(expr);
1283 match Parser::validate_const_expr(expr) {
1284 Ok(expr) => Some(self.convert_const_expr(expr)),
1285 Err(err) => {
1286 let err =
1287 CompileError::new(err.into(), self.cfg.input.clone(), self.cur_namespace());
1288 self.errs.push(err);
1289 None
1290 }
1291 }
1292 }
1293
1294 fn convert_compound_type_spec(&mut self, name: String, args: py_ast::Expr) -> TypeSpec {
1296 match &name[..] {
1297 "Union" => {
1298 let py_ast::Expr::Tuple(mut tuple) = args else {
1299 let err = CompileError::syntax_error(
1300 self.cfg.input.clone(),
1301 line!() as usize,
1302 pyloc_to_ergloc(args.range()),
1303 self.cur_namespace(),
1304 "`Union` takes at least 2 types".into(),
1305 None,
1306 );
1307 self.errs.push(err);
1308 return Self::gen_dummy_type_spec(args.location());
1309 };
1310 let lhs = self.convert_type_spec(tuple.elts.remove(0));
1311 if tuple.elts.is_empty() {
1312 return lhs;
1313 }
1314 let rhs = self.convert_type_spec(tuple.elts.remove(0));
1315 let mut union = TypeSpec::or(lhs, rhs);
1316 for elem in tuple.elts {
1317 let t = self.convert_type_spec(elem);
1318 union = TypeSpec::or(union, t);
1319 }
1320 union
1321 }
1322 "Optional" => {
1323 let loc = args.location();
1324 let t = self.convert_type_spec(args);
1325 let ident = Identifier::private_with_line("NoneType".into(), loc.row.get());
1326 let none = TypeSpec::mono(ident);
1327 TypeSpec::or(t, none)
1328 }
1329 "Literal" => {
1330 let py_ast::Expr::Tuple(tuple) = args else {
1331 return Self::gen_dummy_type_spec(args.location());
1332 };
1333 let mut elems = vec![];
1334 for elem in tuple.elts {
1335 if let Some(expr) = self.convert_expr_to_const(elem) {
1336 elems.push(ConstPosArg::new(expr));
1337 }
1338 }
1339 let elems = ConstArgs::new(elems, None, vec![], None, None);
1340 TypeSpec::Enum(elems)
1341 }
1342 "Final" | "Required" | "NotRequired" | "ReadOnly" => self.convert_type_spec(args),
1344 "Callable" => {
1346 let mut tuple = match args {
1347 py_ast::Expr::Tuple(tuple) if tuple.elts.len() == 2 => tuple,
1348 _ => {
1349 let err = CompileError::syntax_error(
1350 self.cfg.input.clone(),
1351 line!() as usize,
1352 pyloc_to_ergloc(args.range()),
1353 self.cur_namespace(),
1354 "`Callable` takes an input type list and a return type".into(),
1355 None,
1356 );
1357 self.errs.push(err);
1358 return Self::gen_dummy_type_spec(args.location());
1359 }
1360 };
1361 let params = tuple.elts.remove(0);
1362 let mut non_defaults = vec![];
1363 match params {
1364 py_ast::Expr::List(list) => {
1365 for param in list.elts.into_iter() {
1366 let t_spec = self.convert_type_spec(param);
1367 non_defaults.push(ParamTySpec::anonymous(t_spec));
1368 }
1369 }
1370 other => {
1371 let err = CompileError::syntax_error(
1372 self.cfg.input.clone(),
1373 line!() as usize,
1374 pyloc_to_ergloc(other.range()),
1375 self.cur_namespace(),
1376 "Expected a list of parameters".into(),
1377 None,
1378 );
1379 self.errs.push(err);
1380 }
1381 }
1382 let ret = self.convert_type_spec(tuple.elts.remove(0));
1383 TypeSpec::Subr(SubrTypeSpec::new(
1384 TypeBoundSpecs::empty(),
1385 None,
1386 non_defaults,
1387 None,
1388 vec![],
1389 None,
1390 ARROW,
1391 ret,
1392 ))
1393 }
1394 "Iterable" | "Iterator" | "Collection" | "Container" | "Sequence"
1395 | "MutableSequence" => {
1396 let elem_t = match self.convert_expr_to_const(args) {
1397 Some(elem_t) => elem_t,
1398 None => {
1399 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1400 }
1401 };
1402 let elem_t = ConstPosArg::new(elem_t);
1403 let global =
1404 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
1405 let acc = ConstAccessor::Attr(ConstAttribute::new(
1406 global,
1407 Identifier::private(escape_name(name).into()),
1408 ));
1409 TypeSpec::poly(acc, ConstArgs::pos_only(vec![elem_t], None))
1410 }
1411 "Mapping" | "MutableMapping" => {
1412 let mut tuple = match args {
1413 py_ast::Expr::Tuple(tuple) if tuple.elts.len() == 2 => tuple,
1414 _ => {
1415 let err = CompileError::syntax_error(
1416 self.cfg.input.clone(),
1417 line!() as usize,
1418 pyloc_to_ergloc(args.range()),
1419 self.cur_namespace(),
1420 "`Mapping` takes 2 types".into(),
1421 None,
1422 );
1423 self.errs.push(err);
1424 return Self::gen_dummy_type_spec(args.location());
1425 }
1426 };
1427 let key_t = match self.convert_expr_to_const(tuple.elts.remove(0)) {
1428 Some(key_t) => key_t,
1429 None => {
1430 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1431 }
1432 };
1433 let key_t = ConstPosArg::new(key_t);
1434 let value_t = match self.convert_expr_to_const(tuple.elts.remove(0)) {
1435 Some(value_t) => value_t,
1436 None => {
1437 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1438 }
1439 };
1440 let value_t = ConstPosArg::new(value_t);
1441 let global =
1442 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
1443 let acc = ConstAccessor::Attr(ConstAttribute::new(
1444 global,
1445 Identifier::private(escape_name(name).into()),
1446 ));
1447 TypeSpec::poly(acc, ConstArgs::pos_only(vec![key_t, value_t], None))
1448 }
1449 "List" | "list" => {
1450 let len = ConstExpr::Accessor(ConstAccessor::Local(Identifier::private_with_loc(
1451 "_".into(),
1452 pyloc_to_ergloc(args.range()),
1453 )));
1454 let elem_t = match self.convert_expr_to_const(args) {
1455 Some(elem_t) => elem_t,
1456 None => {
1457 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1458 }
1459 };
1460 let elem_t = ConstPosArg::new(elem_t);
1461 let len = ConstPosArg::new(len);
1462 let global =
1463 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
1464 let acc = ConstAccessor::Attr(ConstAttribute::new(
1465 global,
1466 Identifier::private("List!".into()),
1467 ));
1468 TypeSpec::poly(
1469 acc,
1470 ConstArgs::new(vec![elem_t, len], None, vec![], None, None),
1471 )
1472 }
1473 "Dict" | "dict" => {
1474 let mut tuple = match args {
1475 py_ast::Expr::Tuple(tuple) if tuple.elts.len() == 2 => tuple,
1476 _ => {
1477 let err = CompileError::syntax_error(
1478 self.cfg.input.clone(),
1479 line!() as usize,
1480 pyloc_to_ergloc(args.range()),
1481 self.cur_namespace(),
1482 "`dict` takes 2 types".into(),
1483 None,
1484 );
1485 self.errs.push(err);
1486 return Self::gen_dummy_type_spec(args.location());
1487 }
1488 };
1489 let (l_brace, r_brace) = Self::gen_enclosure_tokens(TokenKind::LBrace, tuple.range);
1490 let key_t = match self.convert_expr_to_const(tuple.elts.remove(0)) {
1491 Some(key_t) => key_t,
1492 None => {
1493 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1494 }
1495 };
1496 let val_t = match self.convert_expr_to_const(tuple.elts.remove(0)) {
1497 Some(val_t) => val_t,
1498 None => {
1499 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1500 }
1501 };
1502 let dict = ConstPosArg::new(ConstExpr::Dict(ConstDict::new(
1503 l_brace,
1504 r_brace,
1505 vec![ConstKeyValue::new(key_t, val_t)],
1506 )));
1507 let global =
1508 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
1509 let acc = ConstAccessor::Attr(ConstAttribute::new(
1510 global,
1511 Identifier::private("Dict!".into()),
1512 ));
1513 TypeSpec::poly(acc, ConstArgs::new(vec![dict], None, vec![], None, None))
1514 }
1515 "Tuple" | "tuple" => {
1516 let py_ast::Expr::Tuple(mut tuple) = args else {
1517 return Self::gen_dummy_type_spec(args.location());
1518 };
1519 if tuple.elts.get(1).is_some_and(|ex| matches!(ex, py_ast::Expr::Constant(c) if matches!(c.value, py_ast::Constant::Ellipsis))) {
1521 let acc = ConstAccessor::local(Token::symbol("HomogenousTuple"));
1522 let ty = tuple.elts.remove(0);
1523 let args = ConstArgs::single(self.convert_expr_to_const(ty).unwrap());
1524 return TypeSpec::poly(acc, args);
1525 }
1526 let tys = tuple
1527 .elts
1528 .into_iter()
1529 .map(|elem| self.convert_type_spec(elem))
1530 .collect();
1531 let (l, r) = Self::gen_enclosure_tokens(TokenKind::LParen, tuple.range);
1532 let tuple = TupleTypeSpec::new(Some((l.loc(), r.loc())), tys);
1533 TypeSpec::Tuple(tuple)
1534 }
1535 "Set" | "set" => {
1536 let elem_t = match self.convert_expr_to_const(args) {
1537 Some(elem_t) => elem_t,
1538 None => {
1539 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1540 }
1541 };
1542 let elem_t = ConstPosArg::new(elem_t);
1543 let global =
1544 ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
1545 let acc = ConstAccessor::Attr(ConstAttribute::new(
1546 global,
1547 Identifier::private("Set!".into()),
1548 ));
1549 TypeSpec::poly(acc, ConstArgs::pos_only(vec![elem_t], None))
1550 }
1551 _ => Self::gen_dummy_type_spec(args.location()),
1552 }
1553 }
1554
1555 fn convert_type_spec(&mut self, expr: py_ast::Expr) -> TypeSpec {
1556 match expr {
1557 py_ast::Expr::Name(name) => {
1558 self.contexts
1559 .last_mut()
1560 .unwrap()
1561 .appeared_type_names
1562 .insert(name.id.to_string());
1563 self.convert_ident_type_spec(name.id.to_string(), name.range)
1564 }
1565 py_ast::Expr::Constant(cons) => {
1566 if cons.value.is_none() {
1567 self.convert_ident_type_spec("NoneType".into(), cons.range)
1568 } else if let Some(name) = cons.value.as_str() {
1569 self.convert_ident_type_spec(name.into(), cons.range)
1570 } else {
1571 let err = CompileError::syntax_error(
1572 self.cfg.input.clone(),
1573 line!() as usize,
1574 pyloc_to_ergloc(cons.range()),
1575 self.cur_namespace(),
1576 format!("{:?} is not a type", cons.value),
1577 None,
1578 );
1579 self.errs.push(err);
1580 Self::gen_dummy_type_spec(cons.location())
1581 }
1582 }
1583 py_ast::Expr::Attribute(attr) => {
1584 let namespace = Box::new(self.convert_expr(*attr.value));
1585 let t = self.convert_ident(attr.attr.to_string(), attr_name_loc(&namespace));
1586 if namespace
1587 .full_name()
1588 .is_some_and(|n| n == "typing" || n == "collections.abc")
1589 {
1590 match &t.inspect()[..] {
1591 global_unary_collections!()
1592 | global_mutable_unary_collections!()
1593 | global_binary_collections!() => {
1594 return self.convert_ident_type_spec(attr.attr.to_string(), attr.range)
1595 }
1596 "Any" => return TypeSpec::PreDeclTy(PreDeclTypeSpec::Mono(t)),
1597 _ => {}
1598 }
1599 }
1600 let predecl = PreDeclTypeSpec::Attr { namespace, t };
1601 TypeSpec::PreDeclTy(predecl)
1602 }
1603 py_ast::Expr::Subscript(subs) => match *subs.value {
1605 py_ast::Expr::Name(name) => {
1606 self.convert_compound_type_spec(name.id.to_string(), *subs.slice)
1607 }
1608 py_ast::Expr::Attribute(attr) => {
1609 let loc = attr.location();
1610 match accessor_name(*attr.value).as_ref().map(|s| &s[..]) {
1611 Some("typing" | "collections.abc") => {
1612 self.convert_compound_type_spec(attr.attr.to_string(), *subs.slice)
1613 }
1614 other => {
1615 log!(err "unknown: {other:?}");
1616 Self::gen_dummy_type_spec(loc)
1617 }
1618 }
1619 }
1620 other => {
1621 log!(err "unknown: {other:?}");
1622 Self::gen_dummy_type_spec(other.location())
1623 }
1624 },
1625 py_ast::Expr::BinOp(bin) => {
1626 let loc = bin.location();
1627 match bin.op {
1628 Operator::BitOr => {
1630 let lhs = self.convert_type_spec(*bin.left);
1631 let rhs = self.convert_type_spec(*bin.right);
1632 TypeSpec::or(lhs, rhs)
1633 }
1634 _ => Self::gen_dummy_type_spec(loc),
1635 }
1636 }
1637 other => {
1638 log!(err "unknown: {other:?}");
1639 Self::gen_dummy_type_spec(other.location())
1640 }
1641 }
1642 }
1643
1644 fn gen_enclosure_tokens(l_kind: TokenKind, expr_range: PySourceRange) -> (Token, Token) {
1645 let (l_cont, r_cont, r_kind) = match l_kind {
1646 TokenKind::LBrace => ("{", "}", TokenKind::RBrace),
1647 TokenKind::LParen => ("(", ")", TokenKind::RParen),
1648 TokenKind::LSqBr => ("[", "]", TokenKind::RSqBr),
1649 _ => unreachable!(),
1650 };
1651 let (line_end, c_end) = (
1652 expr_range.end.unwrap_or(expr_range.start).row.get(),
1653 expr_range
1654 .end
1655 .unwrap_or(expr_range.start)
1656 .column
1657 .to_zero_indexed(),
1658 );
1659 let l_brace = Token::new(
1660 l_kind,
1661 l_cont,
1662 expr_range.start.row.get(),
1663 expr_range.start.column.to_zero_indexed(),
1664 );
1665 let r_brace = Token::new(r_kind, r_cont, line_end, c_end);
1666 (l_brace, r_brace)
1667 }
1668
1669 fn mutate_expr(expr: Expr) -> Expr {
1670 let mut_op = Token::new(
1671 TokenKind::Mutate,
1672 "!",
1673 expr.ln_begin().unwrap_or(0),
1674 expr.col_begin().unwrap_or(0),
1675 );
1676 Expr::UnaryOp(UnaryOp::new(mut_op, expr))
1677 }
1678
1679 fn convert_const(&mut self, const_: ExprConstant) -> Expr {
1680 let loc = const_.location();
1681 match const_.value {
1682 py_ast::Constant::Int(i) => {
1683 let kind = if i >= 0.into() {
1684 TokenKind::NatLit
1685 } else {
1686 TokenKind::IntLit
1687 };
1688 let token = Token::new(
1689 kind,
1690 i.to_string(),
1691 loc.row.get(),
1692 loc.column.to_zero_indexed(),
1693 );
1694 Expr::Literal(Literal::new(token))
1695 }
1696 py_ast::Constant::Float(f) => {
1697 let token = Token::new(
1698 TokenKind::RatioLit,
1699 f.to_string(),
1700 const_.location().row.get(),
1701 const_.location().column.to_zero_indexed(),
1702 );
1703 Expr::Literal(Literal::new(token))
1704 }
1705 py_ast::Constant::Complex { real: _, imag: _ } => Expr::Dummy(Dummy::new(None, vec![])),
1706 py_ast::Constant::Str(value) => {
1707 let kind = if const_
1708 .range
1709 .end
1710 .is_some_and(|end| end.row != const_.range.start.row)
1711 {
1712 TokenKind::DocComment
1713 } else {
1714 TokenKind::StrLit
1715 };
1716 let value = format!("\"{value}\"");
1717 let token = Token::new(kind, value, loc.row.get(), loc.column.to_zero_indexed());
1719 Expr::Literal(Literal::new(token))
1720 }
1721 py_ast::Constant::Bool(b) => {
1722 let cont = if b { "True" } else { "False" };
1723 Expr::Literal(Literal::new(Token::new(
1724 TokenKind::BoolLit,
1725 cont,
1726 loc.row.get(),
1727 loc.column.to_zero_indexed(),
1728 )))
1729 }
1730 py_ast::Constant::None => Expr::Literal(Literal::new(Token::new(
1731 TokenKind::NoneLit,
1732 "None",
1733 const_.location().row.get(),
1734 const_.location().column.to_zero_indexed(),
1735 ))),
1736 py_ast::Constant::Ellipsis => Expr::Literal(Literal::new(Token::new(
1737 TokenKind::EllipsisLit,
1738 "...",
1739 const_.location().row.get(),
1740 const_.location().column.to_zero_indexed(),
1741 ))),
1742 other => {
1744 log!(err "unknown: {other:?}");
1745 Expr::Dummy(Dummy::new(None, vec![]))
1746 }
1747 }
1748 }
1749
1750 fn convert_expr(&mut self, expr: py_ast::Expr) -> Expr {
1751 match expr {
1752 py_ast::Expr::Constant(const_) => self.convert_const(const_),
1753 py_ast::Expr::Name(name) => {
1754 let ident = self.convert_ident(name.id.to_string(), name.location());
1755 Expr::Accessor(Accessor::Ident(ident))
1756 }
1757 py_ast::Expr::Attribute(attr) => {
1758 let value = self.convert_expr(*attr.value);
1759 let name = self.convert_attr_ident(attr.attr.to_string(), attr_name_loc(&value));
1760 value.attr_expr(name)
1761 }
1762 py_ast::Expr::IfExp(if_) => {
1763 let loc = if_.location();
1764 let block = self.convert_expr(*if_.body);
1765 let params = Params::new(vec![], None, vec![], None, None);
1766 let sig = LambdaSignature::new(params.clone(), None, TypeBoundSpecs::empty());
1767 let body = Lambda::new(sig, Token::DUMMY, Block::new(vec![block]), DefId(0));
1768 let test = self.convert_expr(*if_.test);
1769 let if_ident = self.convert_ident("if".to_string(), loc);
1770 let if_acc = Expr::Accessor(Accessor::Ident(if_ident));
1771 let else_block = self.convert_expr(*if_.orelse);
1772 let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
1773 let else_body =
1774 Lambda::new(sig, Token::DUMMY, Block::new(vec![else_block]), DefId(0));
1775 let args = Args::pos_only(
1776 vec![
1777 PosArg::new(test),
1778 PosArg::new(Expr::Lambda(body)),
1779 PosArg::new(Expr::Lambda(else_body)),
1780 ],
1781 None,
1782 );
1783 if_acc.call_expr(args)
1784 }
1785 py_ast::Expr::Call(call) => {
1786 let loc = call.location();
1787 let end_loc = call.end_location();
1788 let function = self.convert_expr(*call.func);
1789 let (pos_args, var_args): (Vec<_>, _) = call
1790 .args
1791 .into_iter()
1792 .partition(|arg| !arg.is_starred_expr());
1793 let pos_args = pos_args
1794 .into_iter()
1795 .map(|ex| PosArg::new(self.convert_expr(ex)))
1796 .collect::<Vec<_>>();
1797 let var_args = var_args
1798 .into_iter()
1799 .map(|ex| {
1800 let py_ast::Expr::Starred(star) = ex else {
1801 unreachable!()
1802 };
1803 PosArg::new(self.convert_expr(*star.value))
1804 })
1805 .next();
1806 let (kw_args, kw_var): (Vec<_>, _) =
1807 call.keywords.into_iter().partition(|kw| kw.arg.is_some());
1808 let kw_args = kw_args
1809 .into_iter()
1810 .map(|Keyword { arg, value, range }| {
1811 let name = Token::symbol_with_loc(
1812 arg.unwrap().to_string(),
1813 pyloc_to_ergloc(range),
1814 );
1815 let ex = self.convert_expr(value);
1816 KwArg::new(name, None, ex)
1817 })
1818 .collect();
1819 let kw_var = kw_var
1820 .into_iter()
1821 .map(|Keyword { value, .. }| PosArg::new(self.convert_expr(value)))
1822 .next();
1823 let last_col = end_loc.map_or_else(
1824 || {
1825 pos_args
1826 .last()
1827 .and_then(|last| last.col_end())
1828 .unwrap_or(function.col_end().unwrap_or(0) + 1)
1829 },
1830 |loc| loc.column.to_zero_indexed().saturating_sub(1),
1831 );
1832 let paren = {
1833 let lp = Token::new(
1834 TokenKind::LParen,
1835 "(",
1836 loc.row.get(),
1837 function.col_end().unwrap_or(0),
1838 );
1839 let rp = Token::new(TokenKind::RParen, ")", loc.row.get(), last_col);
1840 (lp.loc(), rp.loc())
1841 };
1842 let args = Args::new(pos_args, var_args, kw_args, kw_var, Some(paren));
1843 function.call_expr(args)
1844 }
1845 py_ast::Expr::BinOp(bin) => {
1846 let lhs = self.convert_expr(*bin.left);
1847 let rhs = self.convert_expr(*bin.right);
1848 let op = op_to_token(bin.op);
1849 Expr::BinOp(BinOp::new(op, lhs, rhs))
1850 }
1851 py_ast::Expr::UnaryOp(un) => {
1852 let rhs = self.convert_expr(*un.operand);
1853 let (kind, cont) = match un.op {
1854 UnOp::UAdd => (TokenKind::PrePlus, "+"),
1855 UnOp::USub => (TokenKind::PreMinus, "-"),
1856 UnOp::Invert => (TokenKind::PreBitNot, "~"),
1857 UnOp::Not => return Expr::Call(Identifier::public("not".into()).call1(rhs)),
1858 };
1859 let op = Token::from_str(kind, cont);
1860 Expr::UnaryOp(UnaryOp::new(op, rhs))
1861 }
1862 py_ast::Expr::BoolOp(mut boole) => {
1864 let lhs = self.convert_expr(boole.values.remove(0));
1865 let rhs = self.convert_expr(boole.values.remove(0));
1866 let (kind, cont) = match boole.op {
1867 BoolOp::And => (TokenKind::AndOp, "and"),
1868 BoolOp::Or => (TokenKind::OrOp, "or"),
1869 };
1870 let op = Token::from_str(kind, cont);
1871 Expr::BinOp(BinOp::new(op, lhs, rhs))
1872 }
1873 py_ast::Expr::Compare(mut cmp) => {
1875 let lhs = self.convert_expr(*cmp.left);
1876 let rhs = self.convert_expr(cmp.comparators.remove(0));
1877 let (kind, cont) = match cmp.ops.remove(0) {
1878 CmpOp::Eq => (TokenKind::DblEq, "=="),
1879 CmpOp::NotEq => (TokenKind::NotEq, "!="),
1880 CmpOp::Lt => (TokenKind::Less, "<"),
1881 CmpOp::LtE => (TokenKind::LessEq, "<="),
1882 CmpOp::Gt => (TokenKind::Gre, ">"),
1883 CmpOp::GtE => (TokenKind::GreEq, ">="),
1884 CmpOp::Is => (TokenKind::IsOp, "is!"),
1885 CmpOp::IsNot => (TokenKind::IsNotOp, "isnot!"),
1886 CmpOp::In => (TokenKind::InOp, "in"),
1887 CmpOp::NotIn => (TokenKind::NotInOp, "notin"),
1888 };
1889 let op = Token::from_str(kind, cont);
1890 Expr::BinOp(BinOp::new(op, lhs, rhs))
1891 }
1892 py_ast::Expr::Lambda(lambda) => {
1893 self.grow("<lambda>".to_string(), BlockKind::Function);
1894 let params = self.convert_params(*lambda.args);
1895 let body = vec![self.convert_expr(*lambda.body)];
1896 self.pop();
1897 let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
1898 let op = Token::from_str(TokenKind::FuncArrow, "->");
1899 Expr::Lambda(Lambda::new(sig, op, Block::new(body), DefId(0)))
1900 }
1901 py_ast::Expr::List(list) => {
1902 let (l_sqbr, r_sqbr) = Self::gen_enclosure_tokens(TokenKind::LSqBr, list.range);
1903 let elements = list
1904 .elts
1905 .into_iter()
1906 .map(|ex| PosArg::new(self.convert_expr(ex)))
1907 .collect::<Vec<_>>();
1908 let elems = Args::pos_only(elements, None);
1909 let arr = Expr::List(List::Normal(NormalList::new(l_sqbr, r_sqbr, elems)));
1910 Self::mutate_expr(arr)
1911 }
1912 py_ast::Expr::ListComp(comp) => {
1913 let (l_sqbr, r_sqbr) = Self::gen_enclosure_tokens(TokenKind::LSqBr, comp.range);
1914 let layout = self.convert_expr(*comp.elt);
1915 let generator = comp.generators.into_iter().next().unwrap();
1916 let target = self.convert_expr(generator.target);
1917 let Expr::Accessor(Accessor::Ident(ident)) = target else {
1918 log!(err "unimplemented: {target}");
1919 let loc = pyloc_to_ergloc(comp.range);
1920 return Expr::Dummy(Dummy::new(Some(loc), vec![]));
1921 };
1922 let iter = self.convert_expr(generator.iter);
1923 let guard = generator
1924 .ifs
1925 .into_iter()
1926 .next()
1927 .map(|ex| self.convert_expr(ex));
1928 let generators = vec![(ident, iter)];
1929 let arr = Expr::List(List::Comprehension(ListComprehension::new(
1930 l_sqbr,
1931 r_sqbr,
1932 Some(layout),
1933 generators,
1934 guard,
1935 )));
1936 Self::mutate_expr(arr)
1937 }
1938 py_ast::Expr::Set(set) => {
1939 let (l_brace, r_brace) = Self::gen_enclosure_tokens(TokenKind::LBrace, set.range);
1940 let elements = set
1941 .elts
1942 .into_iter()
1943 .map(|ex| PosArg::new(self.convert_expr(ex)))
1944 .collect::<Vec<_>>();
1945 let elems = Args::pos_only(elements, None);
1946 let set = Expr::Set(Set::Normal(NormalSet::new(l_brace, r_brace, elems)));
1947 Self::mutate_expr(set)
1948 }
1949 py_ast::Expr::SetComp(comp) => {
1950 let (l_brace, r_brace) = Self::gen_enclosure_tokens(TokenKind::LBrace, comp.range);
1951 let layout = self.convert_expr(*comp.elt);
1952 let generator = comp.generators.into_iter().next().unwrap();
1953 let target = self.convert_expr(generator.target);
1954 let Expr::Accessor(Accessor::Ident(ident)) = target else {
1955 log!(err "unimplemented: {target}");
1956 let loc = pyloc_to_ergloc(comp.range);
1957 return Expr::Dummy(Dummy::new(Some(loc), vec![]));
1958 };
1959 let iter = self.convert_expr(generator.iter);
1960 let guard = generator
1961 .ifs
1962 .into_iter()
1963 .next()
1964 .map(|ex| self.convert_expr(ex));
1965 let generators = vec![(ident, iter)];
1966 let set = Expr::Set(Set::Comprehension(SetComprehension::new(
1967 l_brace,
1968 r_brace,
1969 Some(layout),
1970 generators,
1971 guard,
1972 )));
1973 Self::mutate_expr(set)
1974 }
1975 py_ast::Expr::Dict(dict) => {
1976 let (l_brace, r_brace) = Self::gen_enclosure_tokens(TokenKind::LBrace, dict.range);
1977 let kvs = dict
1978 .keys
1979 .into_iter()
1980 .zip(dict.values)
1981 .map(|(k, v)| {
1982 KeyValue::new(
1983 k.map(|k| self.convert_expr(k))
1984 .unwrap_or(Expr::Dummy(Dummy::new(None, vec![]))),
1985 self.convert_expr(v),
1986 )
1987 })
1988 .collect::<Vec<_>>();
1989 let dict = Expr::Dict(Dict::Normal(NormalDict::new(l_brace, r_brace, kvs)));
1990 Self::mutate_expr(dict)
1991 }
1992 py_ast::Expr::DictComp(comp) => {
1993 let (l_brace, r_brace) = Self::gen_enclosure_tokens(TokenKind::LBrace, comp.range);
1994 let key = self.convert_expr(*comp.key);
1995 let value = self.convert_expr(*comp.value);
1996 let kv = KeyValue::new(key, value);
1997 let generator = comp.generators.into_iter().next().unwrap();
1998 let target = self.convert_expr(generator.target);
1999 let Expr::Accessor(Accessor::Ident(ident)) = target else {
2000 log!(err "unimplemented: {target}");
2001 let loc = pyloc_to_ergloc(comp.range);
2002 return Expr::Dummy(Dummy::new(Some(loc), vec![]));
2003 };
2004 let iter = self.convert_expr(generator.iter);
2005 let guard = generator
2006 .ifs
2007 .into_iter()
2008 .next()
2009 .map(|ex| self.convert_expr(ex));
2010 let generators = vec![(ident, iter)];
2011 let dict = Expr::Dict(Dict::Comprehension(DictComprehension::new(
2012 l_brace, r_brace, kv, generators, guard,
2013 )));
2014 Self::mutate_expr(dict)
2015 }
2016 py_ast::Expr::Tuple(tuple) => {
2017 let (l, r) = Self::gen_enclosure_tokens(TokenKind::LParen, tuple.range);
2018 let elements = tuple
2019 .elts
2020 .into_iter()
2021 .map(|ex| PosArg::new(self.convert_expr(ex)))
2022 .collect::<Vec<_>>();
2023 let elems = Args::pos_only(elements, Some((l.loc(), r.loc())));
2024 Expr::Tuple(Tuple::Normal(NormalTuple::new(elems)))
2025 }
2026 py_ast::Expr::Subscript(subs) => {
2027 let obj = self.convert_expr(*subs.value);
2028 if obj.get_name().is_some_and(|n| self.is_type_name(n)) {
2030 let obj = if obj.get_name().is_some_and(|n| n == "List") {
2031 let global = self.convert_ident("global".to_string(), subs.range.start);
2032 Expr::from(global).attr_expr(Identifier::private("List!".into()))
2033 } else if obj.get_name().is_some_and(|n| n == "Set") {
2034 let global = self.convert_ident("global".to_string(), subs.range.start);
2035 Expr::from(global).attr_expr(Identifier::private("Set!".into()))
2036 } else {
2037 obj
2038 };
2039 return obj.call1(self.convert_expr(*subs.slice));
2040 }
2041 let method = obj.attr_expr(
2042 self.convert_ident("__getitem__".to_string(), subs.slice.location()),
2043 );
2044 method.call1(self.convert_expr(*subs.slice))
2045 }
2046 py_ast::Expr::Slice(slice) => {
2052 let loc = slice.location();
2053 let start = slice.lower.map(|ex| self.convert_expr(*ex));
2054 let stop = slice.upper.map(|ex| self.convert_expr(*ex));
2055 let step = slice.step.map(|ex| self.convert_expr(*ex));
2056 let mut args = Args::empty();
2057 if let Some(start) = start {
2058 args.push_pos(PosArg::new(start));
2059 }
2060 if let Some(stop) = stop {
2061 args.push_pos(PosArg::new(stop));
2062 }
2063 if let Some(step) = step {
2064 args.push_pos(PosArg::new(step));
2065 }
2066 if args.is_empty() {
2067 args.push_pos(PosArg::new(Expr::Literal(Literal::new(Token::new(
2068 TokenKind::NoneLit,
2069 "None",
2070 loc.row.get(),
2071 loc.column.to_zero_indexed(),
2072 )))));
2073 }
2074 let slice = self.convert_ident("slice".to_string(), loc);
2075 slice.call(args).into()
2076 }
2077 py_ast::Expr::JoinedStr(string) => {
2078 if string.values.is_empty() {
2079 let loc = string.location();
2080 let stringify = self.convert_ident("str".to_string(), loc);
2081 return stringify.call(Args::empty()).into();
2082 } else if string.values.len() == 1 {
2083 let loc = string.location();
2084 let mut values = string.values;
2085 let expr = self.convert_expr(values.remove(0));
2086 let stringify = self.convert_ident("str".to_string(), loc);
2087 return stringify.call1(expr).into();
2088 }
2089 let mut values = vec![];
2090 for value in string.values {
2091 match value {
2092 py_ast::Expr::Constant(cons) => {
2093 let cons = self.convert_const(cons);
2094 values.push(cons);
2095 }
2096 py_ast::Expr::FormattedValue(form) => {
2097 let loc = form.location();
2098 let expr = self.convert_expr(*form.value);
2099 let stringify = self.convert_ident("str".to_string(), loc);
2100 values.push(stringify.call1(expr).into());
2101 }
2102 _ => {}
2103 }
2104 }
2105 let fst = values.remove(0);
2106 values.into_iter().fold(fst, |acc, expr| {
2107 let plus = Token::dummy(TokenKind::Plus, "+");
2108 Expr::BinOp(BinOp::new(plus, acc, expr))
2109 })
2110 }
2111 py_ast::Expr::FormattedValue(form) => {
2112 let loc = form.location();
2113 let expr = self.convert_expr(*form.value);
2114 let stringify = self.convert_ident("str".to_string(), loc);
2115 stringify.call1(expr).into()
2116 }
2117 py_ast::Expr::NamedExpr(named) => {
2118 let loc = named.location();
2119 let target = self.convert_expr(*named.target);
2120 let target_pat = match &target {
2121 Expr::Accessor(Accessor::Ident(ident)) => VarPattern::Ident(ident.clone()),
2122 _ => {
2123 log!(err "unimplemented: {:?}", target);
2124 VarPattern::Ident(Identifier::private("_".into()))
2125 }
2126 };
2127 let value = self.convert_expr(*named.value);
2128 let assign = Token::new(
2129 TokenKind::Assign,
2130 "=",
2131 loc.row.get(),
2132 loc.column.to_zero_indexed(),
2133 );
2134 let def = Def::new(
2135 Signature::Var(VarSignature::new(target_pat, None)),
2136 DefBody::new(assign, Block::new(vec![value]), DefId(0)),
2137 );
2138 Expr::Compound(Compound::new(vec![Expr::Def(def), target]))
2139 }
2140 py_ast::Expr::Yield(_) => {
2141 self.cur_context_mut().return_kind = ReturnKind::Yield;
2142 log!(err "unimplemented: {:?}", expr);
2143 Expr::Dummy(Dummy::new(None, vec![]))
2144 }
2145 _other => {
2146 log!(err "unimplemented: {:?}", _other);
2147 Expr::Dummy(Dummy::new(None, vec![]))
2148 }
2149 }
2150 }
2151
2152 fn convert_block(&mut self, block: Suite, kind: BlockKind) -> Block {
2153 let mut new_block = Vec::new();
2154 let len = block.len();
2155 self.block_id_counter += 1;
2156 self.blocks.push(BlockInfo {
2157 id: self.block_id_counter,
2158 kind,
2159 });
2160 for (i, stmt) in block.into_iter().enumerate() {
2161 let is_last = i == len - 1;
2162 new_block.push(self.convert_statement(stmt, is_last && kind.is_function()));
2163 }
2164 self.blocks.pop();
2165 Block::new(new_block)
2166 }
2167
2168 #[allow(clippy::result_large_err)]
2169 fn check_init_sig(&self, sig: &Signature) -> Result<(), (bool, CompileError)> {
2170 match sig {
2171 Signature::Subr(subr) => {
2172 if let Some(first) = subr.params.non_defaults.first() {
2173 if first.inspect().map(|s| &s[..]) == Some("self") {
2174 return Ok(());
2175 }
2176 }
2177 Err((
2178 true,
2179 self_not_found_error(self.cfg.input.clone(), subr.loc(), self.cur_namespace()),
2180 ))
2181 }
2182 Signature::Var(var) => Err((
2183 false,
2184 init_var_error(self.cfg.input.clone(), var.loc(), self.cur_namespace()),
2185 )),
2186 }
2187 }
2188
2189 #[allow(clippy::only_used_in_recursion)]
2202 fn collect_called_methods(&self, expr: &Expr, methods: &mut HashSet<String>) {
2203 expr.traverse(&mut |ex| {
2204 if let Expr::Call(call) = ex {
2205 match call.obj.as_ref() {
2206 Expr::Accessor(Accessor::Ident(ident)) if ident.inspect() == "self" => {
2207 if let Some(method_ident) = &call.attr_name {
2208 methods.insert(method_ident.inspect().to_string());
2209 } else {
2210 self.collect_called_methods(&call.obj, methods);
2211 }
2212 }
2213 _ => self.collect_called_methods(ex, methods),
2214 }
2215 } else {
2216 self.collect_called_methods(ex, methods);
2217 }
2218 });
2219 }
2220
2221 fn extract_init(
2229 &mut self,
2230 base_type: &mut Option<Expr>,
2231 init_def: Def,
2232 attrs: &[ClassAttr],
2233 pre_check: bool,
2234 ) -> Option<Def> {
2235 if let Err((continuable, err)) = self.check_init_sig(&init_def.sig) {
2236 if pre_check {
2237 self.errs.push(err);
2238 }
2239 if !continuable {
2240 return None;
2241 }
2242 }
2243 let l_brace = Token::new(
2244 TokenKind::LBrace,
2245 "{",
2246 init_def.ln_begin().unwrap_or(0),
2247 init_def.col_begin().unwrap_or(0),
2248 );
2249 let r_brace = Token::new(
2250 TokenKind::RBrace,
2251 "}",
2252 init_def.ln_end().unwrap_or(0),
2253 init_def.col_end().unwrap_or(0),
2254 );
2255 let expr = Expr::Def(init_def.clone());
2256 let Signature::Subr(sig) = init_def.sig else {
2257 unreachable!()
2258 };
2259 let mut fields = vec![];
2260 self.extract_instance_attrs(&sig, &init_def.body.block, &mut fields);
2261 let mut method_names = HashSet::new();
2262 self.collect_called_methods(&expr, &mut method_names);
2263 for class_attr in attrs {
2264 if let ClassAttr::Def(def) = class_attr {
2265 if let Signature::Subr(sig) = &def.sig {
2266 if method_names.contains(&sig.ident.inspect()[..]) {
2267 self.extract_instance_attrs(sig, &def.body.block, &mut fields);
2268 }
2269 }
2270 }
2271 }
2272 if let Some(Expr::Record(Record::Normal(rec))) = base_type.as_mut() {
2273 let no_exist_fields = fields
2274 .into_iter()
2275 .filter(|field| {
2276 rec.attrs
2277 .iter()
2278 .all(|rec_field| rec_field.sig.ident() != field.sig.ident())
2279 })
2280 .collect::<Vec<_>>();
2281 rec.attrs.extend(no_exist_fields);
2282 } else {
2283 let record = Record::Normal(NormalRecord::new(
2284 l_brace,
2285 r_brace,
2286 RecordAttrs::new(fields),
2287 ));
2288 *base_type = Some(Expr::Record(record));
2289 }
2290 let call_ident = Identifier::new(
2291 VisModifierSpec::Public(ErgLocation::Unknown),
2292 VarName::from_static("__call__"),
2293 );
2294 let class_ident = Identifier::public_with_line(
2295 DOT,
2296 self.cur_name().to_string().into(),
2297 sig.ln_begin().unwrap_or(0),
2298 );
2299 let class_ident_expr = Expr::Accessor(Accessor::Ident(class_ident.clone()));
2300 let class_spec = TypeSpecWithOp::new(COLON, TypeSpec::mono(class_ident), class_ident_expr);
2301 let mut params = sig.params.clone();
2302 if params
2303 .non_defaults
2304 .first()
2305 .is_some_and(|param| param.inspect().map(|s| &s[..]) == Some("self"))
2306 {
2307 params.non_defaults.remove(0);
2308 }
2309 let sig = Signature::Subr(SubrSignature::new(
2310 set! { Decorator(Expr::static_local("Override")) },
2311 call_ident,
2312 TypeBoundSpecs::empty(),
2313 params,
2314 Some(class_spec),
2315 ));
2316 let unreachable_acc = Identifier::new(
2317 VisModifierSpec::Public(ErgLocation::Unknown),
2318 VarName::from_static("exit"),
2319 );
2320 let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty());
2321 let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0));
2322 let def = Def::new(sig, body);
2323 Some(def)
2324 }
2325
2326 fn extract_instance_attrs(&self, sig: &SubrSignature, block: &Block, fields: &mut Vec<Def>) {
2327 for chunk in block.iter() {
2328 if let Expr::ReDef(redef) = chunk {
2329 let Accessor::Attr(attr) = &redef.attr else {
2330 continue;
2331 };
2332 if attr.obj.get_name().map(|s| &s[..]) == Some("self")
2334 && fields
2335 .iter()
2336 .all(|field| field.sig.ident().unwrap() != &attr.ident)
2337 {
2338 let typ = if let Some(t_spec_op) = sig
2340 .params
2341 .non_defaults
2342 .iter()
2343 .find(|¶m| param.inspect() == Some(attr.ident.inspect()))
2344 .and_then(|param| param.t_spec.as_ref())
2345 .or_else(|| {
2346 sig.params
2347 .defaults
2348 .iter()
2349 .find(|¶m| param.inspect() == Some(attr.ident.inspect()))
2350 .and_then(|param| param.sig.t_spec.as_ref())
2351 }) {
2352 *t_spec_op.t_spec_as_expr.clone()
2353 } else if let Some(typ) =
2354 redef.t_spec.clone().map(|t_spec| t_spec.t_spec_as_expr)
2355 {
2356 *typ
2357 } else {
2358 Expr::from(Accessor::Ident(Identifier::private_with_line(
2359 "Any".into(),
2360 attr.obj.ln_begin().unwrap_or(0),
2361 )))
2362 };
2363 let sig = Signature::Var(VarSignature::new(
2364 VarPattern::Ident(attr.ident.clone()),
2365 None,
2366 ));
2367 let body = DefBody::new(EQUAL, Block::new(vec![typ]), DefId(0));
2368 let field_type_def = Def::new(sig, body);
2369 fields.push(field_type_def);
2370 }
2371 }
2372 }
2373 }
2374
2375 fn gen_default_init(&self, line: usize) -> Def {
2376 let call_ident = Identifier::new(
2377 VisModifierSpec::Public(ErgLocation::Unknown),
2378 VarName::from_static("__call__"),
2379 );
2380 let params = Params::empty();
2381 let class_ident =
2382 Identifier::public_with_line(DOT, self.cur_name().to_string().into(), line as u32);
2383 let class_ident_expr = Expr::Accessor(Accessor::Ident(class_ident.clone()));
2384 let class_spec = TypeSpecWithOp::new(COLON, TypeSpec::mono(class_ident), class_ident_expr);
2385 let sig = Signature::Subr(SubrSignature::new(
2386 set! { Decorator(Expr::static_local("Override")) },
2387 call_ident,
2388 TypeBoundSpecs::empty(),
2389 params,
2390 Some(class_spec),
2391 ));
2392 let unreachable_acc = Identifier::new(
2393 VisModifierSpec::Public(ErgLocation::Unknown),
2394 VarName::from_static("exit"),
2395 );
2396 let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty());
2397 let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0));
2398 Def::new(sig, body)
2399 }
2400
2401 fn extract_method(
2402 &mut self,
2403 body: Vec<py_ast::Stmt>,
2404 inherit: bool,
2405 class_name: Expr,
2406 ) -> (Option<Expr>, ClassAttrs) {
2407 let mut base_type = None;
2408 let mut attrs = vec![];
2409 let mut call_params_len = None;
2410 for stmt in body {
2411 match self.convert_statement(stmt, true) {
2412 Expr::Def(mut def) => {
2413 if inherit {
2414 if let Signature::Subr(subr) = &mut def.sig {
2415 subr.decorators
2416 .insert(Decorator(Expr::static_local("Override")));
2417 }
2418 }
2419 if def.sig.decorators().is_some_and(|decos| {
2420 decos.iter().any(|deco| {
2421 deco.expr()
2422 .get_name()
2423 .is_some_and(|name| name == "property")
2424 })
2425 }) {
2426 let mut args = Args::empty();
2434 if call_params_len.as_ref().is_some_and(|&len| len >= 1) {
2435 args.set_var_args(PosArg::new(Expr::List(List::Normal(
2436 NormalList::new(
2437 Token::dummy(TokenKind::LSqBr, "["),
2438 Token::dummy(TokenKind::RSqBr, "]"),
2439 Args::empty(),
2440 ),
2441 ))));
2442 }
2443 let instance = class_name.clone().call(args);
2444 let name = def.sig.ident().unwrap().clone();
2445 def.sig
2446 .ident_mut()
2447 .unwrap()
2448 .name
2449 .rename(format!("{} ", name.inspect()).into());
2450 let escaped = def.sig.ident().unwrap().clone();
2451 let call = Expr::Call(instance).method_call_expr(escaped, Args::empty());
2452 let t_spec = def.sig.t_spec_op_mut().cloned();
2453 let sig =
2454 Signature::Var(VarSignature::new(VarPattern::Ident(name), t_spec));
2455 let var_def =
2456 Def::new(sig, DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)));
2457 attrs.push(ClassAttr::Def(def));
2458 attrs.push(ClassAttr::Def(var_def));
2459 } else if def
2460 .sig
2461 .ident()
2462 .is_some_and(|id| &id.inspect()[..] == "__init__")
2463 {
2464 if let Some(call_def) =
2467 self.extract_init(&mut base_type, def.clone(), &attrs, true)
2468 {
2469 if let Some(params) = call_def.sig.params() {
2470 call_params_len = Some(params.len());
2471 }
2472 attrs.push(ClassAttr::Def(def));
2473 }
2474 } else {
2475 attrs.push(ClassAttr::Def(def));
2476 }
2477 }
2478 Expr::TypeAscription(type_asc) => {
2479 let sig = match type_asc.expr.as_ref() {
2480 Expr::Accessor(Accessor::Ident(ident)) => Signature::Var(
2481 VarSignature::new(VarPattern::Ident(ident.clone()), None),
2482 ),
2483 other => {
2484 log!(err "{other}");
2485 continue;
2486 }
2487 };
2488 let expr = *type_asc.t_spec.t_spec_as_expr;
2489 let body = DefBody::new(EQUAL, Block::new(vec![expr]), DefId(0));
2490 let def = Def::new(sig, body);
2491 match &mut base_type {
2492 Some(Expr::Record(Record::Normal(NormalRecord { attrs, .. }))) => {
2493 attrs.push(def);
2494 }
2495 None => {
2496 let l_brace = Token::new(
2497 TokenKind::LBrace,
2498 "{",
2499 def.ln_begin().unwrap_or(0),
2500 def.col_begin().unwrap_or(0),
2501 );
2502 let r_brace = Token::new(
2503 TokenKind::RBrace,
2504 "}",
2505 def.ln_end().unwrap_or(0),
2506 def.col_end().unwrap_or(0),
2507 );
2508 let rec = Expr::Record(Record::Normal(NormalRecord::new(
2509 l_brace,
2510 r_brace,
2511 RecordAttrs::new(vec![def]),
2512 )));
2513 base_type = Some(rec);
2514 }
2515 _ => {}
2516 }
2517 }
2519 _other => {} }
2521 }
2522 let mut init = None;
2523 for (i, attr) in attrs.iter().enumerate() {
2524 if let ClassAttr::Def(def) = attr {
2525 if def
2526 .sig
2527 .ident()
2528 .is_some_and(|id| &id.inspect()[..] == "__init__")
2529 {
2530 if let Some(def) = self.extract_init(&mut base_type, def.clone(), &attrs, false)
2531 {
2532 init = Some((i, def));
2533 }
2534 }
2535 }
2536 }
2537 if let Some((i, def)) = init {
2538 attrs.remove(i);
2539 attrs.insert(0, ClassAttr::Def(def));
2540 } else if !inherit {
2541 attrs.insert(0, ClassAttr::Def(self.gen_default_init(0)));
2542 }
2543 (base_type, ClassAttrs::new(attrs))
2544 }
2545
2546 fn extract_method_list(
2547 &mut self,
2548 ident: Identifier,
2549 body: Vec<py_ast::Stmt>,
2550 base: Option<py_ast::Expr>,
2551 ) -> (Option<Expr>, Vec<Methods>) {
2552 let inherit = base.is_some();
2553 let class = if let Some(base) = base {
2554 let base_spec = self.convert_type_spec(base.clone());
2555 let expr = self.convert_expr(base);
2556 let loc = expr.loc();
2557 let base = TypeSpecWithOp::new(COLON, base_spec, expr);
2558 let args = TypeAppArgs::new(loc, TypeAppArgsKind::SubtypeOf(Box::new(base)), loc);
2559 TypeSpec::type_app(TypeSpec::mono(ident.clone()), args)
2560 } else {
2561 TypeSpec::mono(ident.clone())
2562 };
2563 let class_as_expr = Expr::Accessor(Accessor::Ident(ident));
2564 let (base_type, attrs) = self.extract_method(body, inherit, class_as_expr.clone());
2565 self.block_id_counter += 1;
2566 let methods = Methods::new(
2567 DefId(self.block_id_counter),
2568 class,
2569 class_as_expr,
2570 VisModifierSpec::Public(ErgLocation::Unknown),
2571 attrs,
2572 );
2573 (base_type, vec![methods])
2574 }
2575
2576 fn get_type_bounds(&mut self, type_params: Vec<TypeParam>) -> TypeBoundSpecs {
2577 let mut bounds = TypeBoundSpecs::empty();
2578 if type_params.is_empty() {
2579 for ty in self.cur_appeared_type_names() {
2580 let name = VarName::from_str(ty.clone().into());
2581 let op = Token::dummy(TokenKind::SubtypeOf, "<:");
2582 if let Some(tv_info) = self.get_type_var(ty) {
2583 let bound = if let Some(bound) = &tv_info.bound {
2584 let t_spec = Parser::expr_to_type_spec(bound.clone())
2585 .unwrap_or(TypeSpec::Infer(name.token().clone()));
2586 let spec = TypeSpecWithOp::new(op, t_spec, bound.clone());
2587 TypeBoundSpec::non_default(name, spec)
2588 } else if !tv_info.constraints.is_empty() {
2589 let op = Token::dummy(TokenKind::Colon, ":");
2590 let mut elems = vec![];
2591 for constraint in tv_info.constraints.iter() {
2592 if let Ok(expr) = Parser::validate_const_expr(constraint.clone()) {
2593 elems.push(ConstPosArg::new(expr));
2594 }
2595 }
2596 let t_spec = TypeSpec::Enum(ConstArgs::pos_only(elems, None));
2597 let elems = Args::pos_only(
2598 tv_info
2599 .constraints
2600 .iter()
2601 .cloned()
2602 .map(PosArg::new)
2603 .collect(),
2604 None,
2605 );
2606 let expr = Expr::Set(Set::Normal(NormalSet::new(
2607 Token::DUMMY,
2608 Token::DUMMY,
2609 elems,
2610 )));
2611 let spec = TypeSpecWithOp::new(op, t_spec, expr);
2612 TypeBoundSpec::non_default(name, spec)
2613 } else {
2614 TypeBoundSpec::Omitted(name)
2615 };
2616 bounds.push(bound);
2617 }
2618 }
2619 }
2620 for tp in type_params {
2621 let Some(tv) = tp.as_type_var() else {
2623 continue;
2624 };
2625 let name = VarName::from_str(tv.name.to_string().into());
2626 let spec = if let Some(bound) = &tv.bound {
2627 let op = Token::dummy(TokenKind::SubtypeOf, "<:");
2628 let spec = self.convert_type_spec(*bound.clone());
2629 let expr = self.convert_expr(*bound.clone());
2630 let spec = TypeSpecWithOp::new(op, spec, expr);
2631 TypeBoundSpec::non_default(name, spec)
2632 } else {
2633 TypeBoundSpec::Omitted(name)
2634 };
2635 bounds.push(spec);
2636 }
2637 bounds
2638 }
2639
2640 fn convert_funcdef(&mut self, func_def: py_ast::StmtFunctionDef, is_async: bool) -> Expr {
2641 let name = func_def.name.to_string();
2642 let params = *func_def.args;
2643 let returns = func_def.returns.map(|x| *x);
2644 if self.get_name(&name).is_some_and(|info| {
2646 info.defined_times > 0
2647 && info.defined_in == DefinedPlace::Known(self.cur_namespace())
2648 && !info.referenced.difference(&set! {name.clone()}).is_empty()
2649 }) {
2650 let err = reassign_func_error(
2651 self.cfg.input.clone(),
2652 pyloc_to_ergloc(func_def.range),
2653 self.cur_namespace(),
2654 &name,
2655 );
2656 self.errs.push(err);
2657 Expr::Dummy(Dummy::new(None, vec![]))
2658 } else {
2659 let loc = func_def.range.start;
2660 let decos = func_def
2661 .decorator_list
2662 .into_iter()
2663 .map(|ex| Decorator(self.convert_expr(ex)))
2664 .collect::<HashSet<_>>();
2665 self.register_name_info(&name, NameKind::Function);
2666 let func_name_loc = PyLocation {
2667 row: loc.row,
2668 column: loc.column.saturating_add(4),
2669 };
2670 let ident = self.convert_ident(name, func_name_loc);
2671 let kind = if is_async {
2672 BlockKind::AsyncFunction
2673 } else {
2674 BlockKind::Function
2675 };
2676 self.grow(ident.inspect().to_string(), kind);
2677 let params = self.convert_params(params);
2678 let return_t = returns
2679 .or_else(|| {
2680 let PyTypeSpec::Func(func) = self.get_cur_scope_t_spec()? else {
2681 return None;
2682 };
2683 func.returns.clone()
2684 })
2685 .map(|ret| {
2686 let t_spec = self.convert_type_spec(ret.clone());
2687 let colon = Token::new(
2688 TokenKind::Colon,
2689 ":",
2690 t_spec.ln_begin().unwrap_or(0),
2691 t_spec.col_begin().unwrap_or(0),
2692 );
2693 TypeSpecWithOp::new(colon, t_spec, self.convert_expr(ret))
2694 });
2695 let type_params = if !func_def.type_params.is_empty() {
2696 func_def.type_params
2697 } else {
2698 self.get_cur_scope_t_spec()
2699 .and_then(|ty| {
2700 if let PyTypeSpec::Func(func) = ty {
2701 (!func.type_params.is_empty()).then(|| func.type_params.clone())
2702 } else {
2703 None
2704 }
2705 })
2706 .unwrap_or(func_def.type_params)
2707 };
2708 let bounds = self.get_type_bounds(type_params);
2709 let mut sig =
2710 Signature::Subr(SubrSignature::new(decos, ident, bounds, params, return_t));
2711 let block = self.convert_block(func_def.body, BlockKind::Function);
2712 if self.cur_context().return_kind.is_none() {
2713 let Signature::Subr(subr) = &mut sig else {
2714 unreachable!()
2715 };
2716 if subr.return_t_spec.is_none() {
2717 let none = TypeSpecWithOp::new(
2718 Token::dummy(TokenKind::Colon, ":"),
2719 TypeSpec::mono(Identifier::private("NoneType".into())),
2720 Expr::static_local("NoneType"),
2721 );
2722 subr.return_t_spec = Some(Box::new(none));
2723 }
2724 }
2725 let body = DefBody::new(EQUAL, block, DefId(0));
2726 let def = Def::new(sig, body);
2727 self.pop();
2728 Expr::Def(def)
2729 }
2730 }
2731
2732 fn convert_classdef(&mut self, class_def: py_ast::StmtClassDef) -> Expr {
2747 let loc = class_def.location();
2748 let name = class_def.name.to_string();
2749 let _decos = class_def
2750 .decorator_list
2751 .into_iter()
2752 .map(|deco| self.convert_expr(deco))
2753 .collect::<Vec<_>>();
2754 let inherit = class_def.bases.first().cloned();
2755 let is_inherit = inherit.is_some();
2756 let mut bases = class_def
2757 .bases
2758 .into_iter()
2759 .map(|base| self.convert_expr(base))
2760 .collect::<Vec<_>>();
2761 self.register_name_info(&name, NameKind::Class);
2762 let class_name_loc = PyLocation {
2763 row: loc.row,
2764 column: loc.column.saturating_add(6),
2765 };
2766 let ident = self.convert_ident(name, class_name_loc);
2767 let sig = Signature::Var(VarSignature::new(VarPattern::Ident(ident.clone()), None));
2768 self.grow(ident.inspect().to_string(), BlockKind::Class);
2769 let (base_type, methods) = self.extract_method_list(ident, class_def.body, inherit);
2770 let classdef = if is_inherit {
2771 let pos_args = vec![PosArg::new(bases.remove(0))];
2773 let mut args = Args::pos_only(pos_args, None);
2774 if let Some(rec @ Expr::Record(_)) = base_type {
2775 args.push_kw(KwArg::new(Token::symbol("Additional"), None, rec));
2776 }
2777 let inherit_acc = Expr::Accessor(Accessor::Ident(
2778 self.convert_ident("Inherit".to_string(), loc),
2779 ));
2780 let inherit_call = inherit_acc.call_expr(args);
2781 let body = DefBody::new(EQUAL, Block::new(vec![inherit_call]), DefId(0));
2782 let def = Def::new(sig, body);
2783 ClassDef::new(def, methods)
2784 } else {
2785 let pos_args = if let Some(base) = base_type {
2786 vec![PosArg::new(base)]
2787 } else {
2788 vec![]
2789 };
2790 let args = Args::pos_only(pos_args, None);
2791 let class_acc = Expr::Accessor(Accessor::Ident(
2792 self.convert_ident("Class".to_string(), loc),
2793 ));
2794 let class_call = class_acc.call_expr(args);
2795 let inheritable_acc = Expr::Accessor(Accessor::Ident(
2796 self.convert_ident("Inheritable".to_string(), loc),
2797 ));
2798 let inheritable_call = inheritable_acc.call1(class_call);
2799 let body = DefBody::new(EQUAL, Block::new(vec![inheritable_call]), DefId(0));
2800 let def = Def::new(sig, body);
2801 ClassDef::new(def, methods)
2802 };
2803 self.pop();
2804 Expr::ClassDef(classdef)
2805 }
2806
2807 fn convert_for(&mut self, for_: py_ast::StmtFor) -> Expr {
2808 let loc = for_.location();
2809 let iter = self.convert_expr(*for_.iter);
2810 let if_block_id = self.block_id_counter + 1;
2811 let block = self.convert_for_body(Some(*for_.target), for_.body);
2812 let for_ident = self.convert_ident("for".to_string(), loc);
2813 let for_acc = Expr::Accessor(Accessor::Ident(for_ident));
2814 if for_.orelse.is_empty() {
2815 for_acc.call2(iter, Expr::Lambda(block))
2816 } else {
2817 let else_block = self.convert_block(for_.orelse, BlockKind::Else { if_block_id });
2818 let params = Params::empty();
2819 let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
2820 let op = Token::from_str(TokenKind::FuncArrow, "->");
2821 let else_block = Lambda::new(sig, op, else_block, DefId(0));
2822 let args = Args::pos_only(
2823 vec![
2824 PosArg::new(iter),
2825 PosArg::new(Expr::Lambda(block)),
2826 PosArg::new(Expr::Lambda(else_block)),
2827 ],
2828 None,
2829 );
2830 for_acc.call_expr(args)
2831 }
2832 }
2833
2834 fn get_t_spec(&self, name: &str) -> Option<&PyTypeSpec> {
2835 if self.contexts.len() == 1 {
2836 self.pyi_types.get_type(name)
2837 } else {
2838 let class = self.cur_name();
2839 self.pyi_types.get_class_member_type(class, name)
2840 }
2841 }
2842
2843 fn get_assign_t_spec(
2844 &mut self,
2845 name: &py_ast::ExprName,
2846 expr: &Expr,
2847 ) -> Option<TypeSpecWithOp> {
2848 expr.ln_end()
2849 .and_then(|i| {
2850 i.checked_sub(1)
2851 .and_then(|line| self.comments.get_type(line))
2852 })
2853 .cloned()
2854 .or_else(|| {
2855 let type_spec = self.get_t_spec(&name.id)?;
2856 let PyTypeSpec::Var(expr) = type_spec else {
2857 return None;
2858 };
2859 Some(expr.clone())
2860 })
2861 .map(|mut expr| {
2862 if let py_ast::Expr::Subscript(sub) = &mut expr {
2864 sub.range = name.range;
2865 *sub.slice.range_mut() = name.range;
2866 *sub.value.range_mut() = name.range;
2867 } else {
2868 *expr.range_mut() = name.range;
2869 }
2870 let t_as_expr = self.convert_expr(expr.clone());
2871 TypeSpecWithOp::new(AS, self.convert_type_spec(expr), t_as_expr)
2872 })
2873 }
2874
2875 fn convert_statement(&mut self, stmt: Stmt, dont_call_return: bool) -> Expr {
2876 match stmt {
2877 py_ast::Stmt::Expr(stmt) => self.convert_expr(*stmt.value),
2878 py_ast::Stmt::AnnAssign(ann_assign) => {
2880 let anot = self.convert_expr(*ann_assign.annotation.clone());
2881 let t_spec = self.convert_type_spec(*ann_assign.annotation);
2882 let as_op = Token::new(
2883 TokenKind::As,
2884 "as",
2885 t_spec.ln_begin().unwrap_or(0),
2886 t_spec.col_begin().unwrap_or(0),
2887 );
2888 let t_spec = TypeSpecWithOp::new(as_op, t_spec, anot);
2889 match *ann_assign.target {
2890 py_ast::Expr::Name(name) => {
2891 if let Some(value) = ann_assign.value {
2892 let expr = self.convert_expr(*value);
2893 let rename =
2895 self.register_name_info(name.id.as_str(), NameKind::Variable);
2896 let ident = self.convert_ident(name.id.to_string(), name.location());
2897 match rename {
2898 RenameKind::Let => {
2899 let block = Block::new(vec![expr]);
2900 let body = DefBody::new(EQUAL, block, DefId(0));
2901 let sig = Signature::Var(VarSignature::new(
2902 VarPattern::Ident(ident),
2903 Some(t_spec),
2904 ));
2905 let def = Def::new(sig, body);
2906 Expr::Def(def)
2907 }
2908 RenameKind::Phi => {
2909 let block = Block::new(vec![expr]);
2910 let body = DefBody::new(EQUAL, block, DefId(0));
2911 let sig = Signature::Var(VarSignature::new(
2912 VarPattern::Phi(ident),
2913 Some(t_spec),
2914 ));
2915 let def = Def::new(sig, body);
2916 Expr::Def(def)
2917 }
2918 RenameKind::Redef => {
2919 let redef =
2920 ReDef::new(Accessor::Ident(ident), Some(t_spec), expr);
2921 Expr::ReDef(redef)
2922 }
2923 }
2924 } else {
2925 let ident = self.convert_ident(name.id.to_string(), name.location());
2927 let tasc =
2928 TypeAscription::new(Expr::Accessor(Accessor::Ident(ident)), t_spec);
2929 Expr::TypeAscription(tasc)
2930 }
2931 }
2932 py_ast::Expr::Attribute(attr) => {
2933 let value = self.convert_expr(*attr.value);
2934 let ident =
2935 self.convert_attr_ident(attr.attr.to_string(), attr_name_loc(&value));
2936 let attr = value.attr(ident);
2937 if let Some(value) = ann_assign.value {
2938 let expr = self.convert_expr(*value);
2939 let redef = ReDef::new(attr, Some(t_spec), expr);
2940 Expr::ReDef(redef)
2941 } else {
2942 let tasc = TypeAscription::new(Expr::Accessor(attr), t_spec);
2943 Expr::TypeAscription(tasc)
2944 }
2945 }
2946 _other => Expr::Dummy(Dummy::new(None, vec![])),
2947 }
2948 }
2949 py_ast::Stmt::Assign(mut assign) => {
2950 if assign.targets.len() == 1 {
2951 let lhs = assign.targets.remove(0);
2952 match lhs {
2953 py_ast::Expr::Name(name) => {
2954 let expr = self.convert_expr(*assign.value);
2955 if let Expr::Call(call) = &expr {
2956 if let Some("TypeVar") = call.obj.get_name().map(|s| &s[..]) {
2957 let arg = if let Some(Expr::Literal(lit)) =
2958 call.args.get_left_or_key("arg")
2959 {
2960 lit.token.content.trim_matches('\"').to_string()
2961 } else {
2962 name.id.to_string()
2963 };
2964 let mut constraints = vec![];
2965 let mut nth = 1;
2966 while let Some(constr) = call.args.get_nth(nth) {
2967 constraints.push(constr.clone());
2968 nth += 1;
2969 }
2970 if constraints.len() == 1 {
2971 let err = CompileError::syntax_error(
2972 self.cfg.input.clone(),
2973 line!() as usize,
2974 call.args.get_nth(1).unwrap().loc(),
2975 self.cur_namespace(),
2976 "TypeVar must have at least two constrained types"
2977 .into(),
2978 None,
2979 );
2980 self.errs.push(err);
2981 }
2982 let bound = call.args.get_with_key("bound").cloned();
2983 let info = TypeVarInfo::new(arg, constraints, bound);
2984 self.define_type_var(name.id.to_string(), info);
2985 }
2986 }
2987 let rename = self.register_name_info(&name.id, NameKind::Variable);
2988 let ident = self.convert_ident(name.id.to_string(), name.location());
2989 let t_spec = self.get_assign_t_spec(&name, &expr);
2990 match rename {
2991 RenameKind::Let => {
2992 let block = Block::new(vec![expr]);
2993 let body = DefBody::new(EQUAL, block, DefId(0));
2994 let sig = Signature::Var(VarSignature::new(
2995 VarPattern::Ident(ident),
2996 t_spec,
2997 ));
2998 let def = Def::new(sig, body);
2999 Expr::Def(def)
3000 }
3001 RenameKind::Phi => {
3002 let block = Block::new(vec![expr]);
3003 let body = DefBody::new(EQUAL, block, DefId(0));
3004 let sig = Signature::Var(VarSignature::new(
3005 VarPattern::Phi(ident),
3006 t_spec,
3007 ));
3008 let def = Def::new(sig, body);
3009 Expr::Def(def)
3010 }
3011 RenameKind::Redef => {
3012 let redef = ReDef::new(Accessor::Ident(ident), t_spec, expr);
3013 Expr::ReDef(redef)
3014 }
3015 }
3016 }
3017 py_ast::Expr::Attribute(attr) => {
3018 let value = self.convert_expr(*attr.value);
3019 let ident = self
3020 .convert_attr_ident(attr.attr.to_string(), attr_name_loc(&value));
3021 let attr = value.attr(ident);
3022 let expr = self.convert_expr(*assign.value);
3023 let adef = ReDef::new(attr, None, expr);
3024 Expr::ReDef(adef)
3025 }
3026 py_ast::Expr::Tuple(tuple) => {
3027 let tmp = FRESH_GEN.fresh_varname();
3028 let tmp_name =
3029 VarName::from_str_and_line(tmp, tuple.location().row.get());
3030 let tmp_ident = Identifier::new(
3031 VisModifierSpec::Public(ErgLocation::Unknown),
3032 tmp_name,
3033 );
3034 let tmp_expr = Expr::Accessor(Accessor::Ident(tmp_ident.clone()));
3035 let sig = Signature::Var(VarSignature::new(
3036 VarPattern::Ident(tmp_ident),
3037 None,
3038 ));
3039 let body = DefBody::new(
3040 EQUAL,
3041 Block::new(vec![self.convert_expr(*assign.value)]),
3042 DefId(0),
3043 );
3044 let tmp_def = Expr::Def(Def::new(sig, body));
3045 let mut defs = vec![tmp_def];
3046 for (i, elem) in tuple.elts.into_iter().enumerate() {
3047 let loc = elem.location();
3048 let index = Literal::new(Token::new(
3049 TokenKind::NatLit,
3050 i.to_string(),
3051 loc.row.get(),
3052 loc.column.to_zero_indexed(),
3053 ));
3054 let (param, mut blocks) =
3055 self.convert_opt_expr_to_param(Some(elem));
3056 let sig = Signature::Var(VarSignature::new(
3057 Self::param_pattern_to_var(param.pat),
3058 param.t_spec,
3059 ));
3060 let method = tmp_expr
3061 .clone()
3062 .attr_expr(self.convert_ident("__getitem__".to_string(), loc));
3063 let tuple_acc = method.call1(Expr::Literal(index));
3064 let body =
3065 DefBody::new(EQUAL, Block::new(vec![tuple_acc]), DefId(0));
3066 let def = Expr::Def(Def::new(sig, body));
3067 defs.push(def);
3068 defs.append(&mut blocks);
3069 }
3070 Expr::Dummy(Dummy::new(None, defs))
3071 }
3072 py_ast::Expr::Subscript(subs) => {
3075 let a = self.convert_expr(*subs.value);
3076 let slice_loc = subs.slice.location();
3077 let b = self.convert_expr(*subs.slice);
3078 let x = self.convert_expr(*assign.value);
3079 let method = a.attr_expr(
3080 self.convert_ident("__setitem__".to_string(), slice_loc),
3081 );
3082 method.call2(b, x)
3083 }
3084 other => {
3085 log!(err "{other:?} as LHS");
3086 Expr::Dummy(Dummy::new(None, vec![]))
3087 }
3088 }
3089 } else {
3090 let value = self.convert_expr(*assign.value);
3091 let mut defs = vec![];
3092 for target in assign.targets {
3093 match target {
3094 py_ast::Expr::Name(name) => {
3095 let body =
3096 DefBody::new(EQUAL, Block::new(vec![value.clone()]), DefId(0));
3097 let rename = self.register_name_info(&name.id, NameKind::Variable);
3098 let ident =
3099 self.convert_ident(name.id.to_string(), name.location());
3100 match rename {
3101 RenameKind::Let => {
3102 let sig = Signature::Var(VarSignature::new(
3103 VarPattern::Ident(ident),
3104 None,
3105 ));
3106 let def = Def::new(sig, body);
3107 defs.push(Expr::Def(def));
3108 }
3109 RenameKind::Phi => {
3110 let sig = Signature::Var(VarSignature::new(
3111 VarPattern::Phi(ident),
3112 None,
3113 ));
3114 let def = Def::new(sig, body);
3115 defs.push(Expr::Def(def));
3116 }
3117 RenameKind::Redef => {
3118 let redef =
3119 ReDef::new(Accessor::Ident(ident), None, value.clone());
3120 defs.push(Expr::ReDef(redef));
3121 }
3122 }
3123 }
3124 _other => {
3125 defs.push(Expr::Dummy(Dummy::new(None, vec![])));
3126 }
3127 }
3128 }
3129 Expr::Dummy(Dummy::new(None, defs))
3130 }
3131 }
3132 py_ast::Stmt::AugAssign(aug_assign) => {
3133 let op = op_to_token(aug_assign.op);
3134 match *aug_assign.target {
3135 py_ast::Expr::Name(name) => {
3136 let val = self.convert_expr(*aug_assign.value);
3137 let prev_ident = self.convert_ident(name.id.to_string(), name.location());
3138 if self
3139 .get_name(name.id.as_str())
3140 .is_some_and(|info| info.defined_block_id == self.cur_block_id())
3141 {
3142 self.register_name_info(&name.id, NameKind::Variable);
3143 let ident = self.convert_ident(name.id.to_string(), name.location());
3144 let bin =
3145 BinOp::new(op, Expr::Accessor(Accessor::Ident(prev_ident)), val);
3146 let sig =
3147 Signature::Var(VarSignature::new(VarPattern::Ident(ident), None));
3148 let block = Block::new(vec![Expr::BinOp(bin)]);
3149 let body = DefBody::new(EQUAL, block, DefId(0));
3150 let def = Def::new(sig, body);
3151 Expr::Def(def)
3152 } else {
3153 let ident = self.convert_ident(name.id.to_string(), name.location());
3154 let bin =
3155 BinOp::new(op, Expr::Accessor(Accessor::Ident(prev_ident)), val);
3156 let redef = ReDef::new(Accessor::Ident(ident), None, Expr::BinOp(bin));
3157 Expr::ReDef(redef)
3158 }
3159 }
3160 py_ast::Expr::Attribute(attr) => {
3161 let assign_value = self.convert_expr(*aug_assign.value);
3162 let attr_value = self.convert_expr(*attr.value);
3163 let ident = self
3164 .convert_attr_ident(attr.attr.to_string(), attr_name_loc(&attr_value));
3165 let attr = attr_value.attr(ident);
3166 let bin = BinOp::new(op, Expr::Accessor(attr.clone()), assign_value);
3167 let redef = ReDef::new(attr, None, Expr::BinOp(bin));
3168 Expr::ReDef(redef)
3169 }
3170 other => {
3171 log!(err "{other:?} as LHS");
3172 Expr::Dummy(Dummy::new(None, vec![]))
3173 }
3174 }
3175 }
3176 py_ast::Stmt::FunctionDef(func_def) => self.convert_funcdef(func_def, false),
3177 py_ast::Stmt::AsyncFunctionDef(func_def) => {
3178 let py_ast::StmtAsyncFunctionDef {
3179 name,
3180 args,
3181 body,
3182 decorator_list,
3183 returns,
3184 type_params,
3185 range,
3186 type_comment,
3187 } = func_def;
3188 let func_def = py_ast::StmtFunctionDef {
3189 name,
3190 args,
3191 body,
3192 decorator_list,
3193 returns,
3194 type_params,
3195 range,
3196 type_comment,
3197 };
3198 self.convert_funcdef(func_def, true)
3199 }
3200 py_ast::Stmt::ClassDef(class_def) => self.convert_classdef(class_def),
3201 py_ast::Stmt::For(for_) => self.convert_for(for_),
3202 py_ast::Stmt::AsyncFor(for_) => {
3203 let py_ast::StmtAsyncFor {
3204 target,
3205 iter,
3206 body,
3207 orelse,
3208 range,
3209 type_comment,
3210 } = for_;
3211 let for_ = py_ast::StmtFor {
3212 target,
3213 iter,
3214 body,
3215 orelse,
3216 range,
3217 type_comment,
3218 };
3219 self.convert_for(for_)
3220 }
3221 py_ast::Stmt::While(while_) => {
3222 let loc = while_.location();
3223 let test = self.convert_expr(*while_.test);
3224 let params = Params::empty();
3225 let empty_sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
3226 let if_block_id = self.block_id_counter + 1;
3227 let block = self.convert_block(while_.body, BlockKind::While);
3228 let body = Lambda::new(empty_sig, Token::DUMMY, block, DefId(0));
3229 let while_ident = self.convert_ident("while".to_string(), loc);
3230 let while_acc = Expr::Accessor(Accessor::Ident(while_ident));
3231 if while_.orelse.is_empty() {
3232 while_acc.call2(test, Expr::Lambda(body))
3233 } else {
3234 let else_block =
3235 self.convert_block(while_.orelse, BlockKind::Else { if_block_id });
3236 let params = Params::empty();
3237 let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
3238 let op = Token::from_str(TokenKind::FuncArrow, "->");
3239 let else_body = Lambda::new(sig, op, else_block, DefId(0));
3240 let args = Args::pos_only(
3241 vec![
3242 PosArg::new(test),
3243 PosArg::new(Expr::Lambda(body)),
3244 PosArg::new(Expr::Lambda(else_body)),
3245 ],
3246 None,
3247 );
3248 while_acc.call_expr(args)
3249 }
3250 }
3251 py_ast::Stmt::If(if_) => {
3252 let loc = if_.location();
3253 let if_block_id = self.block_id_counter + 1;
3254 let block = self.convert_block(if_.body, BlockKind::If);
3255 let params = Params::empty();
3256 let sig = LambdaSignature::new(params.clone(), None, TypeBoundSpecs::empty());
3257 let body = Lambda::new(sig, Token::DUMMY, block, DefId(0));
3258 let test = self.convert_expr(*if_.test);
3259 let if_ident = self.convert_ident("if".to_string(), loc);
3260 let if_acc = Expr::Accessor(Accessor::Ident(if_ident));
3261 if !if_.orelse.is_empty() {
3262 let else_block =
3263 self.convert_block(if_.orelse, BlockKind::Else { if_block_id });
3264 let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
3265 let else_body = Lambda::new(sig, Token::DUMMY, else_block, DefId(0));
3266 let args = Args::pos_only(
3267 vec![
3268 PosArg::new(test),
3269 PosArg::new(Expr::Lambda(body)),
3270 PosArg::new(Expr::Lambda(else_body)),
3271 ],
3272 None,
3273 );
3274 if_acc.call_expr(args)
3275 } else {
3276 if_acc.call2(test, Expr::Lambda(body))
3277 }
3278 }
3279 py_ast::Stmt::Return(return_) => {
3280 self.cur_context_mut().return_kind = ReturnKind::Return;
3281 let loc = return_.location();
3282 let value = return_
3283 .value
3284 .map(|val| self.convert_expr(*val))
3285 .unwrap_or_else(|| Expr::Tuple(Tuple::Normal(NormalTuple::new(Args::empty()))));
3286 if dont_call_return {
3287 value
3288 } else {
3289 let func_acc = Expr::Accessor(Accessor::Ident(
3290 self.convert_ident(self.cur_name().to_string(), loc),
3291 ));
3292 let return_acc = self.convert_ident("return".to_string(), loc);
3293 let return_acc = Expr::Accessor(Accessor::attr(func_acc, return_acc));
3294 return_acc.call1(value)
3295 }
3296 }
3297 py_ast::Stmt::Assert(assert) => {
3298 let loc = assert.location();
3299 let test = self.convert_expr(*assert.test);
3300 let args = if let Some(msg) = assert.msg {
3301 let msg = self.convert_expr(*msg);
3302 Args::pos_only(vec![PosArg::new(test), PosArg::new(msg)], None)
3303 } else {
3304 Args::pos_only(vec![PosArg::new(test)], None)
3305 };
3306 let assert_acc = Expr::Accessor(Accessor::Ident(
3307 self.convert_ident("assert".to_string(), loc),
3308 ));
3309 assert_acc.call_expr(args)
3310 }
3311 py_ast::Stmt::Import(import) => {
3312 let import_loc = import.location();
3313 let mut imports = vec![];
3314 for name in import.names {
3315 let import_acc = Expr::Accessor(Accessor::Ident(
3316 self.convert_ident("__import__".to_string(), import_loc),
3317 ));
3318 let sym = if name.asname.is_some() {
3319 name.name.replace('.', "/")
3320 } else {
3321 name.name.split('.').next().unwrap().to_string()
3322 };
3323 let mod_name = Expr::Literal(Literal::new(quoted_symbol(
3324 &sym,
3325 name.location().row.get(),
3326 name.location().column.to_zero_indexed(),
3327 )));
3328 let call = import_acc.call1(mod_name);
3329 let name_loc = name.location();
3330 let def = if let Some(alias) = name.asname {
3331 self.register_name_info(&alias, NameKind::Variable);
3332 let var = VarSignature::new(
3333 VarPattern::Ident(self.convert_ident(alias.to_string(), name_loc)),
3334 None,
3335 );
3336 Def::new(
3337 Signature::Var(var),
3338 DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)),
3339 )
3340 } else {
3341 let top_module = name.name.split('.').next().unwrap();
3342 self.register_name_info(top_module, NameKind::Variable);
3343 let var = VarSignature::new(
3344 VarPattern::Ident(
3345 self.convert_ident(top_module.to_string(), name.location()),
3346 ),
3347 None,
3348 );
3349 Def::new(
3350 Signature::Var(var),
3351 DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)),
3352 )
3353 };
3354 imports.push(Expr::Def(def));
3355 }
3356 Expr::Dummy(Dummy::new(None, imports))
3357 }
3358 py_ast::Stmt::ImportFrom(import_from) => {
3360 let mut loc = import_from.location();
3361 loc.column = loc.column.saturating_add(5);
3362 self.convert_from_import(import_from.module, import_from.names, loc)
3363 }
3364 py_ast::Stmt::Try(try_) => {
3365 let if_block_id = self.block_id_counter + 1;
3366 let mut chunks = self.convert_block(try_.body, BlockKind::Try);
3367 for py_ast::ExceptHandler::ExceptHandler(handler) in try_.handlers {
3368 let mut block =
3369 self.convert_block(handler.body, BlockKind::Else { if_block_id });
3370 if let Some(name) = handler.name {
3371 let ident = self.convert_ident(name.to_string(), handler.range.start);
3372 let t_spec = if let Some(type_) = handler.type_ {
3373 let t_spec = self.convert_type_spec(*type_.clone());
3374 let as_expr = self.convert_expr(*type_.clone());
3375 let as_op = Token::new(
3376 TokenKind::As,
3377 "as",
3378 t_spec.ln_begin().unwrap_or(0),
3379 t_spec.col_begin().unwrap_or(0),
3380 );
3381 let t_spec = TypeSpecWithOp::new(as_op, t_spec, as_expr);
3382 Some(t_spec)
3383 } else {
3384 None
3385 };
3386 let var = VarSignature::new(VarPattern::Ident(ident), t_spec);
3387 let unreachable_acc = Identifier::new(
3388 VisModifierSpec::Public(ErgLocation::Unknown),
3389 VarName::from_static("exit"),
3390 );
3391 let body = Expr::Accessor(Accessor::Ident(unreachable_acc))
3392 .call_expr(Args::empty());
3393 let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0));
3394 let def = Def::new(Signature::Var(var), body);
3395 block.insert(0, Expr::Def(def));
3396 }
3397 chunks.extend(block);
3398 }
3399 let dummy = chunks
3400 .into_iter()
3401 .chain(self.convert_block(try_.orelse, BlockKind::Else { if_block_id }))
3402 .chain(self.convert_block(try_.finalbody, BlockKind::Else { if_block_id }))
3403 .collect();
3404 Expr::Dummy(Dummy::new(None, dummy))
3405 }
3406 py_ast::Stmt::With(mut with) => {
3407 let loc = with.location();
3408 let item = with.items.remove(0);
3409 let context_expr = self.convert_expr(item.context_expr);
3410 let body = self.convert_for_body(item.optional_vars.map(|x| *x), with.body);
3411 let with_ident = self.convert_ident("with".to_string(), loc);
3412 let with_acc = Expr::Accessor(Accessor::Ident(with_ident));
3413 with_acc.call2(context_expr, Expr::Lambda(body))
3414 }
3415 py_ast::Stmt::AsyncWith(mut with) => {
3416 let loc = with.location();
3417 let item = with.items.remove(0);
3418 let context_expr = self.convert_expr(item.context_expr);
3419 let body = self.convert_for_body(item.optional_vars.map(|x| *x), with.body);
3420 let with_ident = self.convert_ident("with".to_string(), loc);
3421 let with_acc = Expr::Accessor(Accessor::Ident(with_ident));
3422 with_acc.call2(context_expr, Expr::Lambda(body))
3423 }
3424 _other => {
3425 log!(err "unimplemented: {:?}", _other);
3426 Expr::Dummy(Dummy::new(None, vec![]))
3427 }
3428 }
3429 }
3430
3431 fn convert_glob_import(&mut self, location: PyLocation, module: String) -> Expr {
3432 let import_acc = Expr::Accessor(Accessor::Ident(
3433 self.convert_ident("__import__".to_string(), location),
3434 ));
3435 let sym = if module == "." { "__init__" } else { &module };
3436 let mod_name = Expr::Literal(Literal::new(quoted_symbol(
3437 sym,
3438 location.row.get(),
3439 location.column.to_zero_indexed(),
3440 )));
3441 let call = import_acc.clone().call1(mod_name);
3442 let var = VarSignature::new(VarPattern::Glob(Token::DUMMY), None);
3443 Expr::Def(Def::new(
3444 Signature::Var(var),
3445 DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)),
3446 ))
3447 }
3448
3449 fn convert_from_import(
3472 &mut self,
3473 module: Option<py_ast::Identifier>,
3474 names: Vec<Alias>,
3475 location: PyLocation,
3476 ) -> Expr {
3477 let import_acc = Expr::Accessor(Accessor::Ident(
3478 self.convert_ident("__import__".to_string(), location),
3479 ));
3480 let module = module
3481 .map(|s| s.replace('.', "/"))
3482 .unwrap_or_else(|| ".".to_string());
3483 let module_path = Path::new(&module);
3484 let sym = if module == "." { "__init__" } else { &module };
3485 let mod_name = Expr::Literal(Literal::new(quoted_symbol(
3486 sym,
3487 location.row.get(),
3488 location.column.to_zero_indexed(),
3489 )));
3490 let call = import_acc.clone().call1(mod_name);
3491 let mut exprs = vec![];
3492 let mut imports = vec![];
3493 if names.len() == 1 && names[0].name.as_str() == "*" {
3494 return self.convert_glob_import(location, module);
3495 }
3496 let names_range = PySourceRange {
3497 start: names[0].location(),
3498 end: names[names.len() - 1].end_location(),
3499 };
3500 for name in names {
3501 let name_path = self
3502 .cfg
3503 .input
3504 .resolve_py(&module_path.join(name.name.as_str()));
3505 let true_name = self.convert_ident(name.name.to_string(), name.location());
3506 let as_loc = name.location();
3507 let alias = if let Some(alias) = name.asname {
3508 self.register_name_info(&alias, NameKind::Variable);
3509 let ident = self.convert_ident(alias.to_string(), as_loc);
3510 VarSignature::new(VarPattern::Ident(ident), None)
3511 } else {
3512 self.register_name_info(&name.name, NameKind::Variable);
3513 let ident = self.convert_ident(name.name.to_string(), name.location());
3514 VarSignature::new(VarPattern::Ident(ident), None)
3515 };
3516 if let Ok(mut path) = name_path {
3518 if path.ends_with("__init__.py") {
3519 path.pop();
3520 }
3521 let mod_name = path.file_name().unwrap_or_default();
3522 if name.name.as_str() == mod_name.to_string_lossy().trim_end_matches(".py") {
3523 let sym = format!("{module}/{}", name.name);
3524 let mod_name = Expr::Literal(Literal::new(quoted_symbol(
3525 &sym,
3526 location.row.get(),
3527 location.column.to_zero_indexed(),
3528 )));
3529 let call = import_acc.clone().call1(mod_name);
3530 let def = Def::new(
3531 Signature::Var(alias),
3532 DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)),
3533 );
3534 exprs.push(Expr::Def(def));
3535 } else {
3536 imports.push(VarRecordAttr::new(true_name, alias));
3538 }
3539 } else {
3540 imports.push(VarRecordAttr::new(true_name, alias));
3541 }
3542 }
3543 let no_import = imports.is_empty();
3544 let attrs = VarRecordAttrs::new(imports);
3545 let braces = pyloc_to_ergloc(names_range);
3546 let pat = VarRecordPattern::new(braces, attrs);
3547 let var = VarSignature::new(VarPattern::Record(pat), None);
3548 let def = Expr::Def(Def::new(
3549 Signature::Var(var),
3550 DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)),
3551 ));
3552 if no_import {
3553 Expr::Dummy(Dummy::new(None, exprs))
3554 } else if exprs.is_empty() {
3555 def
3556 } else {
3557 exprs.push(def);
3558 Expr::Dummy(Dummy::new(None, exprs))
3559 }
3560 }
3561
3562 pub fn convert_program(mut self, program: ModModule) -> IncompleteArtifact<Module> {
3563 let program = program
3564 .body
3565 .into_iter()
3566 .map(|stmt| self.convert_statement(stmt, true))
3567 .collect();
3568 let module = Desugarer::new().desugar(Module::new(program));
3569 IncompleteArtifact::new(Some(module), self.errs, self.warns)
3570 }
3571}