1use std::fs::File;
2use std::io::Write;
3
4use erg_common::error::{ErrorDisplay, ErrorKind, MultiErrorDisplay};
5use erg_common::log;
6use erg_common::set::Set as HashSet;
7use erg_common::traits::BlockKind;
8use erg_common::traits::{ExitStatus, Locational, New, Runnable, Stream};
9use erg_common::Str;
10use erg_common::{config::ErgConfig, dict};
11use erg_common::{config::TranspileTarget, dict::Dict as HashMap};
12
13use erg_parser::ast::{ParamPattern, TypeSpec, VarName, AST};
14use erg_parser::token::TokenKind;
15use erg_parser::ParserRunner;
16
17use crate::artifact::{
18 BuildRunnable, Buildable, CompleteArtifact, ErrorArtifact, IncompleteArtifact,
19};
20use crate::build_package::PackageBuilder;
21use crate::codegen::PyCodeGenerator;
22use crate::context::{Context, ContextProvider, ModuleContext};
23use crate::desugar_hir::HIRDesugarer;
24use crate::error::{CompileError, CompileErrors, CompileResult};
25use crate::hir::{
26 Accessor, Args, BinOp, Block, Call, ClassDef, Def, Dict, Expr, Identifier, Lambda, List,
27 Literal, Params, PatchDef, ReDef, Record, Set, Signature, Tuple, UnaryOp, HIR,
28};
29use crate::link_hir::HIRLinker;
30use crate::module::SharedCompilerResource;
31use crate::ty::typaram::OpKind;
32use crate::ty::value::ValueObj;
33use crate::ty::{Field, HasType, Type, VisibilityModifier};
34use crate::varinfo::{AbsLocation, VarInfo};
35
36fn debind(ident: &Identifier) -> Option<Str> {
39 match ident.vi.py_name.as_ref().map(|s| &s[..]) {
40 Some(name) if name.starts_with("Function::") => {
41 Some(Str::from(name.replace("Function::", "")))
42 }
43 Some(patch_method) if patch_method.contains("::") || patch_method.contains('.') => {
44 if ident.vis().is_private() {
45 Some(Str::from(format!("{patch_method}__")))
46 } else {
47 Some(Str::rc(patch_method))
48 }
49 }
50 _ => None,
51 }
52}
53
54fn demangle(name: &str) -> String {
55 name.trim_start_matches("::<module>")
56 .replace("::", "__")
57 .replace('.', "_")
58}
59
60fn replace_non_symbolic(name: &str) -> String {
62 name.replace('\'', "__single_quote__")
63 .replace(' ', "__space__")
64 .replace('+', "__plus__")
65 .replace('-', "__minus__")
66 .replace('*', "__star__")
67 .replace('/', "__slash__")
68 .replace('%', "__percent__")
69 .replace('!', "__erg_proc__")
70 .replace('$', "erg_shared__")
71}
72
73pub enum Enclosure {
74 Paren,
76 Bracket,
78 Brace,
80 None,
81}
82
83impl Enclosure {
84 pub const fn open(&self) -> char {
85 match self {
86 Enclosure::Paren => '(',
87 Enclosure::Bracket => '[',
88 Enclosure::Brace => '{',
89 Enclosure::None => ' ',
90 }
91 }
92
93 pub const fn close(&self) -> char {
94 match self {
95 Enclosure::Paren => ')',
96 Enclosure::Bracket => ']',
97 Enclosure::Brace => '}',
98 Enclosure::None => ' ',
99 }
100 }
101}
102
103#[derive(Debug)]
104pub enum LastLineOperation {
105 Discard,
106 Return,
107 StoreTmp(Str),
108}
109
110use LastLineOperation::*;
111
112impl LastLineOperation {
113 pub const fn is_return(&self) -> bool {
114 matches!(self, LastLineOperation::Return)
115 }
116
117 pub const fn is_store_tmp(&self) -> bool {
118 matches!(self, LastLineOperation::StoreTmp(_))
119 }
120}
121
122#[derive(Debug)]
123pub enum TranspiledFile {
124 PyScript(PyScript),
125 Json(Json),
126}
127
128impl TranspiledFile {
129 pub fn code(&self) -> &str {
130 match self {
131 Self::PyScript(script) => &script.code,
132 Self::Json(json) => &json.code,
133 }
134 }
135
136 pub fn into_code(self) -> String {
137 match self {
138 Self::PyScript(script) => script.code,
139 Self::Json(json) => json.code,
140 }
141 }
142
143 pub fn filename(&self) -> &str {
144 match self {
145 Self::PyScript(script) => &script.filename,
146 Self::Json(json) => &json.filename,
147 }
148 }
149
150 pub fn extension(&self) -> &str {
151 match self {
152 Self::PyScript(_) => "py",
153 Self::Json(_) => "json",
154 }
155 }
156}
157
158#[derive(Debug, Clone)]
159pub struct PyScript {
160 pub filename: Str,
161 pub code: String,
162}
163
164#[derive(Debug, Clone)]
165pub struct Json {
166 pub filename: Str,
167 pub code: String,
168}
169
170#[derive(Debug)]
172pub struct Transpiler {
173 pub cfg: ErgConfig,
174 builder: PackageBuilder,
175 shared: SharedCompilerResource,
176 script_generator: PyScriptGenerator,
177}
178
179impl Default for Transpiler {
180 fn default() -> Self {
181 Self::new(ErgConfig::default())
182 }
183}
184
185impl New for Transpiler {
186 fn new(cfg: ErgConfig) -> Self {
187 let shared = SharedCompilerResource::new(cfg.copy());
188 Self {
189 shared: shared.clone(),
190 builder: PackageBuilder::new_with_cache(cfg.copy(), "<module>".into(), shared),
191 script_generator: PyScriptGenerator::new(),
192 cfg,
193 }
194 }
195}
196
197impl Runnable for Transpiler {
198 type Err = CompileError;
199 type Errs = CompileErrors;
200 const NAME: &'static str = "Erg transpiler";
201
202 #[inline]
203 fn cfg(&self) -> &ErgConfig {
204 &self.cfg
205 }
206 #[inline]
207 fn cfg_mut(&mut self) -> &mut ErgConfig {
208 &mut self.cfg
209 }
210
211 #[inline]
212 fn finish(&mut self) {}
213
214 fn initialize(&mut self) {
215 self.builder.initialize();
216 }
219
220 fn clear(&mut self) {
221 self.builder.clear();
222 }
223
224 fn exec(&mut self) -> Result<ExitStatus, Self::Errs> {
225 let mut path = self.cfg.dump_path();
226 let src = self.cfg.input.read();
227 let artifact = self.transpile(src, "exec").map_err(|eart| {
228 eart.warns.write_all_stderr();
229 eart.errors
230 })?;
231 artifact.warns.write_all_stderr();
232 path.set_extension(artifact.object.extension());
233 let mut f = File::create(path).unwrap();
234 f.write_all(artifact.object.code().as_bytes()).unwrap();
235 Ok(ExitStatus::compile_passed(artifact.warns.len()))
236 }
237
238 fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
239 let artifact = self.transpile(src, "eval").map_err(|eart| {
240 eart.warns.write_all_stderr();
241 eart.errors
242 })?;
243 artifact.warns.write_all_stderr();
244 Ok(artifact.object.into_code())
245 }
246
247 fn expect_block(&self, src: &str) -> BlockKind {
248 let mut parser = ParserRunner::new(self.cfg().clone());
249 match parser.eval(src.to_string()) {
250 Err(errs) => {
251 let kind = errs
252 .iter()
253 .filter(|e| e.core().kind == ErrorKind::ExpectNextLine)
254 .map(|e| {
255 let msg = e.core().sub_messages.last().unwrap();
256 msg.get_msg().first().unwrap().to_owned()
258 })
259 .next();
260 if let Some(kind) = kind {
261 return BlockKind::from(kind.as_str());
262 }
263 if errs
264 .iter()
265 .any(|err| err.core.main_message.contains("\"\"\""))
266 {
267 return BlockKind::MultiLineStr;
268 }
269 BlockKind::Error
270 }
271 Ok(_) => {
272 if src.contains("Class") {
273 return BlockKind::ClassDef;
274 }
275 BlockKind::None
276 }
277 }
278 }
279}
280
281impl ContextProvider for Transpiler {
282 fn dir(&self) -> HashMap<&VarName, &VarInfo> {
283 self.builder.dir()
284 }
285
286 fn get_receiver_ctx(&self, receiver_name: &str) -> Option<&Context> {
287 self.builder.get_receiver_ctx(receiver_name)
288 }
289
290 fn get_var_info(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
291 self.builder.get_var_info(name)
292 }
293}
294
295impl Buildable<TranspiledFile> for Transpiler {
296 fn inherit(cfg: ErgConfig, shared: SharedCompilerResource) -> Self {
297 let mod_name = Str::from(cfg.input.file_stem());
298 Self::new_with_cache(cfg, mod_name, shared)
299 }
300 fn inherit_with_name(cfg: ErgConfig, mod_name: Str, shared: SharedCompilerResource) -> Self {
301 Self::new_with_cache(cfg, mod_name, shared)
302 }
303 fn build(
304 &mut self,
305 src: String,
306 mode: &str,
307 ) -> Result<CompleteArtifact<TranspiledFile>, IncompleteArtifact<TranspiledFile>> {
308 self.transpile(src, mode)
309 .map_err(|err| IncompleteArtifact::new(None, err.errors, err.warns))
310 }
311 fn build_from_ast(
312 &mut self,
313 ast: AST,
314 mode: &str,
315 ) -> Result<CompleteArtifact<TranspiledFile>, IncompleteArtifact<TranspiledFile>> {
316 self.transpile_from_ast(ast, mode)
317 .map_err(|err| IncompleteArtifact::new(None, err.errors, err.warns))
318 }
319 fn pop_context(&mut self) -> Option<ModuleContext> {
320 self.builder.pop_context()
321 }
322 fn get_context(&self) -> Option<&ModuleContext> {
323 self.builder.get_context()
324 }
325}
326
327impl BuildRunnable<TranspiledFile> for Transpiler {}
328
329impl Transpiler {
330 pub fn new(cfg: ErgConfig) -> Self {
331 New::new(cfg)
332 }
333
334 pub fn new_with_cache(cfg: ErgConfig, mod_name: Str, shared: SharedCompilerResource) -> Self {
335 Self {
336 shared: shared.clone(),
337 builder: PackageBuilder::new_with_cache(cfg.copy(), mod_name, shared),
338 script_generator: PyScriptGenerator::new(),
339 cfg,
340 }
341 }
342
343 pub fn transpile(
344 &mut self,
345 src: String,
346 mode: &str,
347 ) -> Result<CompleteArtifact<TranspiledFile>, ErrorArtifact> {
348 log!(info "the transpiling process has started.");
349 let artifact = self.build_link_desugar(src, mode)?;
350 let file = self.lower(artifact.object)?;
351 log!(info "code:\n{}", file.code());
352 log!(info "the transpiling process has completed");
353 Ok(CompleteArtifact::new(file, artifact.warns))
354 }
355
356 pub fn transpile_from_ast(
357 &mut self,
358 ast: AST,
359 mode: &str,
360 ) -> Result<CompleteArtifact<TranspiledFile>, ErrorArtifact> {
361 log!(info "the transpiling process has started.");
362 let artifact = self.builder.build_from_ast(ast, mode)?;
363 let file = self.lower(artifact.object)?;
364 log!(info "code:\n{}", file.code());
365 log!(info "the transpiling process has completed");
366 Ok(CompleteArtifact::new(file, artifact.warns))
367 }
368
369 fn lower(&mut self, hir: HIR) -> CompileResult<TranspiledFile> {
370 match self.cfg.transpile_target {
371 Some(TranspileTarget::Json) => {
372 let mut gen = JsonGenerator::new(self.cfg.copy());
373 Ok(TranspiledFile::Json(gen.transpile(hir)?))
374 }
375 _ => Ok(TranspiledFile::PyScript(
376 self.script_generator.transpile(hir),
377 )),
378 }
379 }
380
381 pub fn transpile_module(&mut self) -> Result<CompleteArtifact<TranspiledFile>, ErrorArtifact> {
382 let src = self.cfg.input.read();
383 self.transpile(src, "exec")
384 }
385
386 fn build_link_desugar(
387 &mut self,
388 src: String,
389 mode: &str,
390 ) -> Result<CompleteArtifact, ErrorArtifact> {
391 let artifact = self.builder.build(src, mode)?;
392 self.link_desugar(artifact)
393 }
394
395 fn link_desugar(
396 &mut self,
397 artifact: CompleteArtifact,
398 ) -> Result<CompleteArtifact, ErrorArtifact> {
399 let linker = HIRLinker::new(&self.cfg, &self.shared.mod_cache);
400 let hir = linker.link(artifact.object);
401 let desugared = HIRDesugarer::desugar(hir);
402 Ok(CompleteArtifact::new(desugared, artifact.warns))
403 }
404
405 pub fn pop_mod_ctx(&mut self) -> Option<ModuleContext> {
406 self.builder.pop_context()
407 }
408
409 pub fn dir(&mut self) -> HashMap<&VarName, &VarInfo> {
410 ContextProvider::dir(self)
411 }
412
413 pub fn get_receiver_ctx(&self, receiver_name: &str) -> Option<&Context> {
414 ContextProvider::get_receiver_ctx(self, receiver_name)
415 }
416
417 pub fn get_var_info(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
418 ContextProvider::get_var_info(self, name)
419 }
420}
421
422#[derive(Debug, Default)]
423pub struct PyScriptGenerator {
424 globals: HashSet<String>,
425 level: usize,
426 fresh_var_n: usize,
427 namedtuple_loaded: bool,
428 mutate_op_loaded: bool,
429 contains_op_loaded: bool,
430 range_ops_loaded: bool,
431 builtin_types_loaded: bool,
432 builtin_control_loaded: bool,
433 convertors_loaded: bool,
434 prelude: String,
435}
436
437impl PyScriptGenerator {
438 pub fn new() -> Self {
439 Self {
440 globals: HashSet::new(),
441 level: 0,
442 fresh_var_n: 0,
443 namedtuple_loaded: false,
444 mutate_op_loaded: false,
445 contains_op_loaded: false,
446 range_ops_loaded: false,
447 builtin_types_loaded: false,
448 builtin_control_loaded: false,
449 convertors_loaded: false,
450 prelude: String::new(),
451 }
452 }
453
454 pub fn transpile(&mut self, hir: HIR) -> PyScript {
455 let mut code = String::new();
456 for chunk in hir.module.into_iter() {
457 let expr = self.transpile_expr(chunk);
458 if !expr.is_empty() {
459 code += &expr;
460 code.push('\n');
461 }
462 }
463 code = std::mem::take(&mut self.prelude) + &code;
464 PyScript {
465 filename: hir.name,
466 code,
467 }
468 }
469
470 fn replace_import(src: &str) -> String {
472 src.replace("from _erg_nat import NatMut", "")
473 .replace("from _erg_nat import Nat", "")
474 .replace("from _erg_int import IntMut", "")
475 .replace("from _erg_int import Int", "")
476 .replace("from _erg_bool import BoolMut", "")
477 .replace("from _erg_bool import Bool", "")
478 .replace("from _erg_str import StrMut", "")
479 .replace("from _erg_str import Str", "")
480 .replace("from _erg_float import FloatMut", "")
481 .replace("from _erg_float import Float", "")
482 .replace("from _erg_list import List", "")
483 .replace("from _erg_range import Range", "")
484 .replace("from _erg_result import Error", "")
485 .replace("from _erg_result import is_ok", "")
486 .replace("from _erg_control import then__", "")
487 .replace("from _erg_contains_operator import contains_operator", "")
488 .replace("from _erg_type import is_type", "")
489 .replace("from _erg_type import _isinstance", "")
490 .replace("from _erg_type import UnionType", "")
491 .replace("from _erg_type import MutType", "")
492 }
493
494 fn load_namedtuple_if_not(&mut self) {
495 if !self.namedtuple_loaded {
496 self.prelude += "from collections import namedtuple as NamedTuple__\n";
497 self.namedtuple_loaded = true;
498 }
499 }
500
501 fn load_range_ops_if_not(&mut self) {
503 if !self.range_ops_loaded {
504 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_result.py"));
505 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_int.py"));
506 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_nat.py"));
507 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_str.py"));
508 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_range.py"));
509 self.range_ops_loaded = true;
510 }
511 }
512
513 fn load_contains_op_if_not(&mut self) {
514 if !self.contains_op_loaded {
515 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_result.py"));
516 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_range.py"));
517 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_type.py"));
518 self.prelude +=
519 &Self::replace_import(include_str!("lib/core/_erg_contains_operator.py"));
520 self.contains_op_loaded = true;
521 }
522 }
523
524 fn load_mutate_op_if_not(&mut self) {
525 if !self.mutate_op_loaded {
526 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_mutate_operator.py"));
527 self.mutate_op_loaded = true;
528 }
529 }
530
531 fn load_builtin_types_if_not(&mut self) {
532 if !self.builtin_types_loaded {
533 self.load_builtin_controls_if_not();
534 self.load_contains_op_if_not();
535 if self.range_ops_loaded {
536 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_float.py"));
537 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_list.py"));
538 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_dict.py"));
539 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_set.py"));
540 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_bytes.py"));
541 } else {
542 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_int.py"));
543 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_nat.py"));
544 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_bool.py"));
545 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_str.py"));
546 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_float.py"));
547 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_list.py"));
548 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_dict.py"));
549 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_set.py"));
550 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_bytes.py"));
551 }
552 self.builtin_types_loaded = true;
553 }
554 }
555
556 fn load_builtin_controls_if_not(&mut self) {
557 if !self.builtin_control_loaded {
558 self.prelude += include_str!("lib/core/_erg_control.py");
559 self.builtin_control_loaded = true;
560 }
561 }
562
563 fn load_convertors_if_not(&mut self) {
564 if !self.convertors_loaded {
565 self.prelude += &Self::replace_import(include_str!("lib/core/_erg_convertors.py"));
566 self.convertors_loaded = true;
567 }
568 }
569
570 fn escape_str(s: &str) -> String {
571 s.replace('\n', "\\n")
572 .replace('\r', "\\r")
573 .replace('\t', "\\t")
574 .replace('\0', "\\0")
576 }
577
578 fn transpile_expr(&mut self, expr: Expr) -> String {
579 match expr {
580 Expr::Literal(lit) => self.transpile_lit(lit),
581 Expr::Call(call) => self.transpile_call(call),
582 Expr::BinOp(bin) => self.transpile_binop(bin),
583 Expr::UnaryOp(unary) => self.transpile_unaryop(unary),
584 Expr::List(list) => match list {
585 List::Normal(lis) => {
586 self.load_builtin_types_if_not();
587 let mut code = "List([".to_string();
588 for elem in lis.elems.pos_args {
589 code += &format!("{},", self.transpile_expr(elem.expr));
590 }
591 code += "])";
592 code
593 }
594 other => todo!("transpiling {other}"),
595 },
596 Expr::Set(set) => match set {
597 Set::Normal(st) => {
598 self.load_builtin_types_if_not();
599 let mut code = "Set({".to_string();
600 for elem in st.elems.pos_args {
601 code += &format!("{},", self.transpile_expr(elem.expr));
602 }
603 code += "})";
604 code
605 }
606 other => todo!("transpiling {other}"),
607 },
608 Expr::Record(rec) => self.transpile_record(rec),
609 Expr::Tuple(tuple) => match tuple {
610 Tuple::Normal(tup) => {
611 let mut code = "(".to_string();
612 for elem in tup.elems.pos_args {
613 code += &format!("{},", self.transpile_expr(elem.expr));
614 }
615 code += ")";
616 code
617 }
618 },
619 Expr::Dict(dict) => match dict {
620 Dict::Normal(dic) => {
621 self.load_builtin_types_if_not();
622 let mut code = "Dict({".to_string();
623 for kv in dic.kvs {
624 code += &format!(
625 "({}): ({}),",
626 self.transpile_expr(kv.key),
627 self.transpile_expr(kv.value)
628 );
629 }
630 code += "})";
631 code
632 }
633 other => todo!("transpiling {other}"),
634 },
635 Expr::Accessor(acc) => self.transpile_acc(acc),
636 Expr::Def(def) => self.transpile_def(def),
637 Expr::Lambda(lambda) => self.transpile_lambda(lambda),
638 Expr::ClassDef(classdef) => self.transpile_classdef(classdef),
639 Expr::PatchDef(patchdef) => self.transpile_patchdef(patchdef),
640 Expr::ReDef(redef) => self.transpile_attrdef(redef),
641 Expr::Compound(comp) => {
643 let mut code = "".to_string();
644 for expr in comp.into_iter() {
645 let expr = self.transpile_expr(expr);
646 if !expr.is_empty() {
647 code += &expr;
648 code += &format!("\n{}", " ".repeat(self.level));
649 }
650 }
651 code
652 }
653 Expr::Import(acc) => {
654 let full_name = acc
655 .qual_name()
656 .map_or(acc.show(), |s| s.replace(".__init__", ""));
657 let root = PyCodeGenerator::get_root(&acc);
658 self.prelude += &format!(
659 "{} = __import__(\"{full_name}\")\n",
660 Self::transpile_ident(root)
661 );
662 String::new()
663 }
664 Expr::TypeAsc(tasc) => self.transpile_expr(*tasc.expr),
665 Expr::Code(_) => todo!("transpiling importing user-defined code"),
666 Expr::Dummy(_) => "".to_string(),
667 }
668 }
669
670 fn transpile_lit(&mut self, lit: Literal) -> String {
671 let escaped = Self::escape_str(&lit.token.content);
672 if matches!(
673 &lit.value,
674 ValueObj::Bool(_)
675 | ValueObj::Int(_)
676 | ValueObj::Nat(_)
677 | ValueObj::Str(_)
678 | ValueObj::Float(_)
679 ) {
680 self.load_builtin_types_if_not();
681 format!("{}({escaped})", lit.value.class())
682 } else {
683 escaped
684 }
685 }
686
687 fn transpile_record(&mut self, rec: Record) -> String {
688 self.load_namedtuple_if_not();
689 let mut attrs = "[".to_string();
690 let mut values = "(".to_string();
691 for mut attr in rec.attrs.into_iter() {
692 attrs += &format!("'{}',", Self::transpile_ident(attr.sig.into_ident()));
693 if attr.body.block.len() > 1 {
694 let name = format!("instant_block_{}__", self.fresh_var_n);
695 self.fresh_var_n += 1;
696 let mut instant = format!("def {name}():\n");
697 instant += &self.transpile_block(attr.body.block, Return);
698 self.prelude += &instant;
699 values += &format!("{name}(),");
700 } else {
701 let expr = attr.body.block.remove(0);
702 values += &format!("{},", self.transpile_expr(expr));
703 }
704 }
705 attrs += "]";
706 values += ")";
707 format!("NamedTuple__('Record', {attrs}){values}")
708 }
709
710 fn transpile_binop(&mut self, bin: BinOp) -> String {
711 match bin.op.kind {
712 TokenKind::Closed | TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Open => {
713 self.load_range_ops_if_not();
714 let mut code = match bin.op.kind {
715 TokenKind::Closed => "ClosedRange(",
716 TokenKind::LeftOpen => "LeftOpenRange(",
717 TokenKind::RightOpen => "RightOpenRange(",
718 TokenKind::Open => "OpenRange(",
719 _ => unreachable!(),
720 }
721 .to_string();
722 code += &self.transpile_expr(*bin.lhs);
723 code.push(',');
724 code += &self.transpile_expr(*bin.rhs);
725 code.push(')');
726 code
727 }
728 TokenKind::ContainsOp => {
729 self.load_contains_op_if_not();
730 let mut code = "contains_operator(".to_string();
731 code += &self.transpile_expr(*bin.lhs);
732 code.push(',');
733 code += &self.transpile_expr(*bin.rhs);
734 code.push(')');
735 code
736 }
737 _ => {
738 let mut code = "(".to_string();
739 code += &self.transpile_expr(*bin.lhs);
740 code.push(' ');
741 code += &bin.op.content;
742 code.push(' ');
743 code += &self.transpile_expr(*bin.rhs);
744 code += ")";
745 code
746 }
747 }
748 }
749
750 fn transpile_unaryop(&mut self, unary: UnaryOp) -> String {
751 let mut code = "".to_string();
752 if unary.op.kind == TokenKind::Mutate {
753 self.load_mutate_op_if_not();
754 code += "mutate_operator(";
755 } else {
756 code += "(";
757 code += &unary.op.content;
758 }
759 code += &self.transpile_expr(*unary.expr);
760 code += ")";
761 code
762 }
763
764 fn transpile_acc(&mut self, acc: Accessor) -> String {
765 let mut prefix = "".to_string();
766 match acc.ref_t().derefine() {
767 v @ (Type::Bool | Type::Nat | Type::Int | Type::Float | Type::Str) => {
768 self.load_builtin_types_if_not();
769 prefix.push_str(&v.qual_name());
770 prefix.push('(');
771 }
772 other => {
773 if let t @ ("Bytes" | "List" | "Dict" | "Set") = &other.qual_name()[..] {
774 self.load_builtin_types_if_not();
775 prefix.push_str(t);
776 prefix.push('(');
777 }
778 }
779 }
780 let postfix = if prefix.is_empty() { "" } else { ")" };
781 match acc {
782 Accessor::Ident(ident) => {
783 match &ident.inspect()[..] {
784 "Str" | "Bytes" | "Bool" | "Nat" | "Int" | "Float" | "List" | "Dict"
785 | "Set" | "Str!" | "Bytes!" | "Bool!" | "Nat!" | "Int!" | "Float!"
786 | "List!" => {
787 self.load_builtin_types_if_not();
788 }
789 "if" | "if!" | "for!" | "while" | "discard" => {
790 self.load_builtin_controls_if_not();
791 }
792 "int" | "nat" | "float" | "str" => {
793 self.load_convertors_if_not();
794 }
795 _ => {}
796 }
797 prefix + &Self::transpile_ident(ident) + postfix
798 }
799 Accessor::Attr(attr) => {
800 if let Some(name) = debind(&attr.ident) {
801 demangle(&name)
802 } else {
803 format!(
804 "{prefix}({}).{}{postfix}",
805 self.transpile_expr(*attr.obj),
806 Self::transpile_ident(attr.ident),
807 )
808 }
809 }
810 }
811 }
812
813 fn transpile_call(&mut self, mut call: Call) -> String {
814 match call.obj.local_name() {
815 Some("assert") => {
816 let mut code = format!("assert {}", self.transpile_expr(call.args.remove(0)));
817 if let Some(msg) = call.args.try_remove(0) {
818 code += &format!(", {}", self.transpile_expr(msg));
819 }
820 code
821 }
822 Some("not") => format!("(not ({}))", self.transpile_expr(call.args.remove(0))),
823 Some("if" | "if!") => self.transpile_if(call),
824 Some("for" | "for!") => {
825 let mut code = "for ".to_string();
826 let iter = call.args.remove(0);
827 let Expr::Lambda(block) = call.args.remove(0) else {
828 todo!()
829 };
830 let non_default = block.params.non_defaults.first().unwrap();
831 let param_token = match &non_default.raw.pat {
832 ParamPattern::VarName(name) => name.token(),
833 ParamPattern::Discard(token) => token,
834 _ => unreachable!(),
835 };
836 code += &Self::transpile_name(
837 &VisibilityModifier::Private,
838 param_token.inspect(),
839 &non_default.vi,
840 );
841 code += &format!(" in {}:\n", self.transpile_expr(iter));
842 code += &self.transpile_block(block.body, Discard);
843 code
844 }
845 Some("while" | "while!") => {
846 let mut code = "while ".to_string();
847 let Expr::Lambda(mut cond) = call.args.remove(0) else {
848 todo!()
849 };
850 let Expr::Lambda(block) = call.args.remove(0) else {
851 todo!()
852 };
853 code += &format!("{}:\n", self.transpile_expr(cond.body.remove(0)));
854 code += &self.transpile_block(block.body, Discard);
855 code
856 }
857 Some("match" | "match!") => self.transpile_match(call),
858 _ => self.transpile_simple_call(call),
859 }
860 }
861
862 fn transpile_if(&mut self, mut call: Call) -> String {
863 let cond = self.transpile_expr(call.args.remove(0));
864 let Expr::Lambda(mut then_block) = call.args.remove(0) else {
865 todo!()
866 };
867 let else_block = call.args.try_remove(0).map(|ex| {
868 if let Expr::Lambda(blk) = ex {
869 blk
870 } else {
871 todo!()
872 }
873 });
874 if then_block.body.len() == 1
875 && else_block
876 .as_ref()
877 .map(|blk| blk.body.len() == 1)
878 .unwrap_or(true)
879 {
880 let then = self.transpile_expr(then_block.body.remove(0));
881 if let Some(mut else_block) = else_block {
882 let els = self.transpile_expr(else_block.body.remove(0));
883 return format!("{then} if {cond} else {els}");
884 } else {
885 return format!("{then} if {cond} else None");
886 }
887 }
888 let tmp = Str::from(format!("if_tmp_{}__", self.fresh_var_n));
889 self.fresh_var_n += 1;
890 let tmp_func = Str::from(format!("if_tmp_func_{}__", self.fresh_var_n));
891 self.fresh_var_n += 1;
892 let mut code = format!("def {tmp_func}():\n");
893 code += &format!(" if {cond}:\n");
894 let level = self.level;
895 self.level = 1;
896 code += &self.transpile_block(then_block.body, StoreTmp(tmp.clone()));
897 self.level = level;
898 if let Some(else_block) = else_block {
899 code += " else:\n";
900 let level = self.level;
901 self.level = 1;
902 code += &self.transpile_block(else_block.body, StoreTmp(tmp.clone()));
903 self.level = level;
904 } else {
905 code += " else:\n";
906 code += &format!(" {tmp} = None\n");
907 }
908 code += &format!(" return {tmp}\n");
909 self.prelude += &code;
910 format!("{tmp_func}()")
914 }
915
916 fn transpile_match(&mut self, mut call: Call) -> String {
917 let tmp = Str::from(format!("match_tmp_{}__", self.fresh_var_n));
918 self.fresh_var_n += 1;
919 let tmp_func = Str::from(format!("match_tmp_func_{}__", self.fresh_var_n));
920 self.fresh_var_n += 1;
921 let mut code = format!("def {tmp_func}():\n");
922 self.level += 1;
923 code += &" ".repeat(self.level);
924 code += "match ";
925 let cond = call.args.remove(0);
926 code += &format!("{}:\n", self.transpile_expr(cond));
927 while let Some(Expr::Lambda(arm)) = call.args.try_remove(0) {
928 self.level += 1;
929 code += &" ".repeat(self.level);
930 let target = arm.params.non_defaults.first().unwrap();
931 match &target.raw.pat {
932 ParamPattern::VarName(param) => {
933 let param = Self::transpile_name(
934 &VisibilityModifier::Private,
935 param.inspect(),
936 &target.vi,
937 );
938 match target.raw.t_spec.as_ref().map(|t| &t.t_spec) {
939 Some(TypeSpec::Enum(enum_t)) => {
940 let values = ValueObj::vec_from_const_args(enum_t.clone());
941 let patterns = values
942 .iter()
943 .map(|v| v.to_string())
944 .collect::<Vec<_>>()
945 .join(" | ");
946 code += &format!("case ({patterns}) as {param}:\n");
947 }
948 Some(other) => {
949 if let Some(Expr::Set(Set::Normal(set))) = &target.t_spec_as_expr {
950 let patterns = set
951 .elems
952 .pos_args
953 .iter()
954 .map(|elem| self.transpile_expr(elem.expr.clone()))
955 .collect::<Vec<_>>()
956 .join(" | ");
957 code += &format!("case ({patterns}) as {param}:\n");
958 } else {
959 todo!("{other}")
960 }
961 }
962 None => {
963 code += &format!("case {param}:\n");
964 }
965 }
966 code += &self.transpile_block(arm.body, StoreTmp(tmp.clone()));
967 self.level -= 1;
968 }
969 ParamPattern::Discard(_) => {
970 match target.raw.t_spec.as_ref().map(|t| &t.t_spec) {
971 Some(TypeSpec::Enum(enum_t)) => {
972 let values = ValueObj::vec_from_const_args(enum_t.clone());
973 let patterns = values
974 .iter()
975 .map(|v| v.to_string())
976 .collect::<Vec<_>>()
977 .join(" | ");
978 code += &format!("case {patterns}:\n");
979 }
980 Some(_) => todo!(),
981 None => {
982 code += "case _:\n";
983 }
984 }
985 code += &self.transpile_block(arm.body, StoreTmp(tmp.clone()));
986 self.level -= 1;
987 }
988 _ => todo!(),
989 }
990 }
991 code += &" ".repeat(self.level);
992 code += &format!("return {tmp}\n");
993 self.prelude += &code;
994 self.level -= 1;
995 format!("{tmp_func}()")
996 }
997
998 fn transpile_simple_call(&mut self, call: Call) -> String {
999 let enc = if call.obj.ref_t().is_poly_meta_type() {
1000 Enclosure::Bracket
1001 } else {
1002 Enclosure::Paren
1003 };
1004 let is_py_api = if let Some(attr) = &call.attr_name {
1005 let is_py_api = attr.is_py_api();
1006 if let Some(name) = debind(attr) {
1007 let name = demangle(&name);
1008 return format!(
1009 "{name}({}, {})",
1010 self.transpile_expr(*call.obj),
1011 self.transpile_args(call.args, is_py_api, enc)
1012 );
1013 }
1014 is_py_api
1015 } else {
1016 call.obj.is_py_api()
1017 };
1018 let mut code = format!("({})", self.transpile_expr(*call.obj));
1019 if let Some(attr) = call.attr_name {
1020 code += &format!(".{}", Self::transpile_ident(attr));
1021 }
1022 code += &self.transpile_args(call.args, is_py_api, enc);
1023 code
1024 }
1025
1026 fn transpile_args(&mut self, mut args: Args, is_py_api: bool, enc: Enclosure) -> String {
1027 let mut code = String::new();
1028 code.push(enc.open());
1029 while let Some(arg) = args.try_remove_pos(0) {
1030 code += &self.transpile_expr(arg.expr);
1031 code.push(',');
1032 }
1033 while let Some(arg) = args.try_remove_kw(0) {
1034 let escape = if is_py_api { "" } else { "__" };
1035 code += &format!(
1036 "{}{escape}={},",
1037 arg.keyword.content,
1038 self.transpile_expr(arg.expr)
1039 );
1040 }
1041 code.push(enc.close());
1042 code
1043 }
1044
1045 fn transpile_ident(ident: Identifier) -> String {
1046 Self::transpile_name(ident.vis(), ident.inspect(), &ident.vi)
1047 }
1048
1049 fn transpile_name(vis: &VisibilityModifier, name: &Str, vi: &VarInfo) -> String {
1050 if let Some(py_name) = &vi.py_name {
1051 return demangle(py_name);
1052 }
1053 let name = replace_non_symbolic(name);
1054 if vis.is_public() || &name == "_" {
1055 name.to_string()
1056 } else {
1057 let def_line = vi.def_loc.loc.ln_begin().unwrap_or(0);
1058 let def_col = vi.def_loc.loc.col_begin().unwrap_or(0);
1059 let line_mangling = match (def_line, def_col) {
1060 (0, 0) => "".to_string(),
1061 (0, _) => format!("_C{def_col}"),
1062 (_, 0) => format!("_L{def_line}"),
1063 (_, _) => format!("_L{def_line}_C{def_col}"),
1064 };
1065 format!("{name}{line_mangling}")
1066 }
1067 }
1068
1069 fn transpile_params(&mut self, params: Params) -> String {
1070 let mut code = String::new();
1071 for non_default in params.non_defaults {
1072 match non_default.raw.pat {
1073 ParamPattern::VarName(param) => {
1074 code += &Self::transpile_name(
1075 &VisibilityModifier::Private,
1076 param.inspect(),
1077 &non_default.vi,
1078 );
1079 code += ",";
1080 }
1081 ParamPattern::Discard(_) => {
1082 code += &format!("_{},", self.fresh_var_n);
1083 self.fresh_var_n += 1;
1084 }
1085 _ => unreachable!(),
1086 }
1087 }
1088 for default in params.defaults {
1089 match default.sig.raw.pat {
1090 ParamPattern::VarName(param) => {
1091 code += &format!(
1092 "{} = {},",
1093 Self::transpile_name(
1094 &VisibilityModifier::Private,
1095 param.inspect(),
1096 &default.sig.vi
1097 ),
1098 self.transpile_expr(default.default_val),
1099 );
1100 }
1101 ParamPattern::Discard(_) => {
1102 let n = self.fresh_var_n;
1103 code += &format!("_{n} = {},", self.transpile_expr(default.default_val),);
1104 self.fresh_var_n += 1;
1105 }
1106 _ => unreachable!(),
1107 }
1108 }
1109 code
1110 }
1111
1112 fn transpile_block(&mut self, block: Block, last_op: LastLineOperation) -> String {
1113 self.level += 1;
1114 let mut code = String::new();
1115 let last = block.len().saturating_sub(1);
1116 for (i, chunk) in block.into_iter().enumerate() {
1117 code += &" ".repeat(self.level);
1118 if i == last {
1119 match last_op {
1120 Return => {
1121 code += "return ";
1122 }
1123 Discard => {}
1124 StoreTmp(ref tmp) => {
1125 code += &format!("{tmp} = ");
1126 }
1127 }
1128 }
1129 let expr = self.transpile_expr(chunk);
1130 if !expr.is_empty() {
1131 code += &expr;
1132 code.push('\n');
1133 }
1134 }
1135 self.level -= 1;
1136 code
1137 }
1138
1139 fn transpile_lambda(&mut self, lambda: Lambda) -> String {
1140 if lambda.body.len() > 1 {
1141 let name = format!("lambda_{}__", self.fresh_var_n);
1142 self.fresh_var_n += 1;
1143 let mut code = format!("def {name}({}):\n", self.transpile_params(lambda.params));
1144 code += &self.transpile_block(lambda.body, Return);
1145 self.prelude += &code;
1146 name
1147 } else {
1148 let mut code = format!("(lambda {}:", self.transpile_params(lambda.params));
1149 code += &self.transpile_block(lambda.body, Discard);
1150 code.pop(); code.push(')');
1152 code
1153 }
1154 }
1155
1156 fn transpile_def(&mut self, mut def: Def) -> String {
1158 let mut code = if self.level == 0 {
1160 "".to_string()
1161 } else {
1162 let name = Self::transpile_ident(def.sig.ident().clone());
1163 if self.globals.contains(&name) {
1164 "".to_string()
1165 } else {
1166 self.globals.insert(name.clone());
1167 format!("global {name}\n{}", " ".repeat(self.level))
1168 }
1169 };
1170 match def.sig {
1171 Signature::Var(var) => {
1172 code += &format!("{} = ", Self::transpile_ident(var.ident));
1173 if def.body.block.len() > 1 {
1174 let name = format!("instant_block_{}__", self.fresh_var_n);
1175 self.fresh_var_n += 1;
1176 let mut instant = format!("def {name}():\n");
1177 instant += &self.transpile_block(def.body.block, Return);
1178 self.prelude += &instant;
1179 code + &format!("{name}()")
1180 } else {
1181 let expr = def.body.block.remove(0);
1182 code += &self.transpile_expr(expr);
1183 code
1184 }
1185 }
1186 Signature::Subr(subr) => {
1187 code += &format!(
1188 "def {}({}):\n",
1189 Self::transpile_ident(subr.ident),
1190 self.transpile_params(subr.params)
1191 );
1192 code += &self.transpile_block(def.body.block, Return);
1193 code
1194 }
1195 Signature::Glob(_) => todo!(),
1196 }
1197 }
1198
1199 fn transpile_classdef(&mut self, classdef: ClassDef) -> String {
1200 let class_name = Self::transpile_ident(classdef.sig.into_ident());
1201 let mut code = format!("class {class_name}():\n");
1202 let mut init_method = format!(
1203 "{}def __init__(self, param__):\n",
1204 " ".repeat(self.level + 1)
1205 );
1206 match classdef.constructor.non_default_params().unwrap()[0].typ() {
1207 Type::Record(rec) => {
1208 for field in rec.keys() {
1209 let vis = if field.vis.is_private() { "__" } else { "" };
1210 init_method += &format!(
1211 "{}self.{}{vis} = param__.{}{vis}\n",
1212 " ".repeat(self.level + 2),
1213 field.symbol,
1214 field.symbol,
1215 );
1216 }
1217 }
1218 other => todo!("{other}"),
1219 }
1220 code += &init_method;
1221 if classdef.need_to_gen_new {
1222 code += &" ".repeat(self.level + 1);
1223 code += &format!("def new(x): return {class_name}.__call__(x)\n");
1224 }
1225 let methods = ClassDef::take_all_methods(classdef.methods_list);
1226 code += &self.transpile_block(methods, Discard);
1227 code
1228 }
1229
1230 fn transpile_patchdef(&mut self, patch_def: PatchDef) -> String {
1231 let mut code = String::new();
1232 for chunk in patch_def.methods.into_iter() {
1233 let Expr::Def(mut def) = chunk else { todo!() };
1234 let name = format!(
1235 "{}{}",
1236 demangle(&patch_def.sig.ident().to_string_notype()),
1237 demangle(&def.sig.ident().to_string_notype()),
1238 );
1239 def.sig.ident_mut().raw.name = VarName::from_str(Str::from(name));
1240 code += &" ".repeat(self.level);
1241 code += &self.transpile_def(def);
1242 code.push('\n');
1243 }
1244 code
1245 }
1246
1247 fn transpile_attrdef(&mut self, mut redef: ReDef) -> String {
1248 let mut code = format!("{} = ", self.transpile_expr(Expr::Accessor(redef.attr)));
1249 if redef.block.len() > 1 {
1250 let name = format!("instant_block_{}__", self.fresh_var_n);
1251 self.fresh_var_n += 1;
1252 let mut instant = format!("def {name}():\n");
1253 instant += &self.transpile_block(redef.block, Return);
1254 self.prelude += &instant;
1255 code + &format!("{name}()")
1256 } else {
1257 let expr = redef.block.remove(0);
1258 code += &self.transpile_expr(expr);
1259 code
1260 }
1261 }
1262}
1263
1264#[derive(Debug, Default)]
1265pub struct JsonGenerator {
1266 cfg: ErgConfig,
1267 binds: HashMap<AbsLocation, ValueObj>,
1268 errors: CompileErrors,
1269}
1270
1271impl JsonGenerator {
1272 pub fn new(cfg: ErgConfig) -> Self {
1273 Self {
1274 cfg,
1275 binds: HashMap::new(),
1276 errors: CompileErrors::empty(),
1277 }
1278 }
1279
1280 pub fn transpile(&mut self, hir: HIR) -> CompileResult<Json> {
1281 let mut code = "".to_string();
1282 let mut len = 0;
1283 for (i, chunk) in hir.module.into_iter().enumerate() {
1284 if i > 0 && len > 0 {
1285 code += ",\n";
1286 }
1287 let expr = self.transpile_expr(chunk);
1288 len = expr.len();
1289 code += &expr;
1290 }
1291 if self.errors.is_empty() {
1292 Ok(Json {
1293 filename: hir.name,
1294 code: format!("{{\n{code}\n}}"),
1295 })
1296 } else {
1297 Err(self.errors.take_all().into())
1298 }
1299 }
1300
1301 fn expr_into_value(&self, expr: Expr) -> Option<ValueObj> {
1302 match expr {
1303 Expr::List(List::Normal(lis)) => {
1304 let mut vals = vec![];
1305 for elem in lis.elems.pos_args {
1306 if let Some(val) = self.expr_into_value(elem.expr) {
1307 vals.push(val);
1308 } else {
1309 return None;
1310 }
1311 }
1312 Some(ValueObj::List(vals.into()))
1313 }
1314 Expr::List(List::WithLength(lis)) => {
1315 let len = lis
1316 .len
1317 .and_then(|len| self.expr_into_value(*len))
1318 .and_then(|v| usize::try_from(&v).ok())?;
1319 let vals = vec![self.expr_into_value(*lis.elem)?; len];
1320 Some(ValueObj::List(vals.into()))
1321 }
1322 Expr::Tuple(Tuple::Normal(tup)) => {
1323 let mut vals = vec![];
1324 for elem in tup.elems.pos_args {
1325 if let Some(val) = self.expr_into_value(elem.expr) {
1326 vals.push(val);
1327 } else {
1328 return None;
1329 }
1330 }
1331 Some(ValueObj::Tuple(vals.into()))
1332 }
1333 Expr::Dict(Dict::Normal(dic)) => {
1334 let mut kvs = dict! {};
1335 for kv in dic.kvs {
1336 let key = self.expr_into_value(kv.key)?;
1337 let val = self.expr_into_value(kv.value)?;
1338 kvs.insert(key, val);
1339 }
1340 Some(ValueObj::Dict(kvs))
1341 }
1342 Expr::Record(rec) => {
1343 let mut attrs = dict! {};
1344 for mut attr in rec.attrs {
1345 let field = Field::from(attr.sig.ident());
1346 let val = self.expr_into_value(attr.body.block.remove(0))?;
1347 attrs.insert(field, val);
1348 }
1349 Some(ValueObj::Record(attrs))
1350 }
1351 Expr::Literal(lit) => Some(lit.value),
1352 Expr::Accessor(acc) => self.binds.get(&acc.var_info().def_loc).cloned(),
1353 Expr::BinOp(bin) => {
1354 let lhs = self.expr_into_value(*bin.lhs)?;
1355 let rhs = self.expr_into_value(*bin.rhs)?;
1356 lhs.try_binary(rhs, OpKind::try_from(bin.op.kind).ok()?)
1357 }
1358 _ => None,
1359 }
1360 }
1361
1362 fn transpile_def(&mut self, mut def: Def) -> String {
1363 self.register_def(&def);
1364 if def.sig.vis().is_public() {
1365 let expr = self.transpile_expr(def.body.block.remove(0));
1366 format!("\"{}\": {expr}", def.sig.inspect())
1367 } else {
1368 "".to_string()
1369 }
1370 }
1371
1372 fn register_def(&mut self, def: &Def) {
1373 if let Some(val) = def
1374 .body
1375 .block
1376 .first()
1377 .cloned()
1378 .and_then(|expr| self.expr_into_value(expr))
1379 {
1380 self.binds.insert(def.sig.ident().vi.def_loc.clone(), val);
1381 }
1382 }
1383
1384 fn transpile_expr(&mut self, expr: Expr) -> String {
1385 match expr {
1386 Expr::Literal(lit) => lit.token.content.to_string(),
1387 Expr::Accessor(acc) => {
1388 if let Some(val) = self.binds.get(&acc.var_info().def_loc) {
1389 val.to_string()
1390 } else {
1391 replace_non_symbolic(&acc.to_string())
1392 }
1393 }
1394 Expr::List(list) => match list {
1395 List::Normal(lis) => {
1396 let mut code = "[".to_string();
1397 for (i, elem) in lis.elems.pos_args.into_iter().enumerate() {
1398 if i > 0 {
1399 code += ", ";
1400 }
1401 code += &self.transpile_expr(elem.expr);
1402 }
1403 code += "]";
1404 code
1405 }
1406 other => todo!("{other}"),
1407 },
1408 Expr::Tuple(tup) => match tup {
1409 Tuple::Normal(tup) => {
1410 let mut code = "[".to_string();
1411 for (i, elem) in tup.elems.pos_args.into_iter().enumerate() {
1412 if i > 0 {
1413 code += ", ";
1414 }
1415 code += &self.transpile_expr(elem.expr);
1416 }
1417 code += "]";
1418 code
1419 }
1420 },
1421 Expr::Record(rec) => {
1422 let mut code = "".to_string();
1423 for (i, mut attr) in rec.attrs.into_iter().enumerate() {
1424 if i > 0 {
1425 code += ", ";
1426 }
1427 let expr = self.transpile_expr(attr.body.block.remove(0));
1428 code += &format!("\"{}\": {expr}", attr.sig.inspect());
1429 }
1430 format!("{{{code}}}")
1431 }
1432 Expr::Dict(dic) => match dic {
1433 Dict::Normal(dic) => {
1434 let mut code = "".to_string();
1435 for (i, kv) in dic.kvs.into_iter().enumerate() {
1436 if i > 0 {
1437 code += ", ";
1438 }
1439 code += &format!(
1440 "{}: {}",
1441 self.transpile_expr(kv.key),
1442 self.transpile_expr(kv.value)
1443 );
1444 }
1445 format!("{{{code}}}")
1446 }
1447 Dict::Comprehension(other) => todo!("{other}"),
1448 },
1449 Expr::Def(def) => self.transpile_def(def),
1450 other => {
1451 let loc = other.loc();
1452 if let Some(val) = self.expr_into_value(other) {
1453 val.to_string()
1454 } else {
1455 self.errors.push(CompileError::not_const_expr(
1456 self.cfg.input.clone(),
1457 line!() as usize,
1458 loc,
1459 "".into(),
1460 ));
1461 "".to_string()
1462 }
1463 }
1464 }
1465 }
1466}