Skip to main content

lutra_bin/value/
print_source.rs

1#![cfg(feature = "std")]
2
3use std::collections::HashMap;
4
5use crate::ir;
6use crate::{Result, Value};
7
8use super::fold::ValueVisitor;
9
10impl Value {
11    pub fn print_source(&self, ty: &ir::Ty, ty_defs: &[ir::TyDef]) -> Result<String> {
12        let ty_defs: HashMap<_, _, _> = ty_defs.iter().map(|def| (&def.name, &def.ty)).collect();
13        let mut printer = Printer {
14            indent: 0,
15            ty_defs: &ty_defs,
16        };
17
18        printer.visit_value(self, ty)
19    }
20}
21
22#[derive(Clone)]
23struct Printer<'t> {
24    indent: usize,
25    ty_defs: &'t HashMap<&'t ir::Path, &'t ir::Ty>,
26}
27
28const INDENT: usize = 2;
29
30impl<'t> Printer<'t> {
31    fn indent(&mut self) {
32        self.indent += INDENT;
33    }
34
35    fn deindent(&mut self) {
36        self.indent -= INDENT;
37    }
38
39    fn new_line(&self) -> String {
40        let mut r = "\n".to_string();
41        r += &" ".repeat(self.indent);
42        r
43    }
44}
45
46impl<'t> ValueVisitor<'t> for Printer<'t> {
47    type Res = String;
48
49    fn get_ty(&self, name: &ir::Path) -> &'t ir::Ty {
50        self.ty_defs.get(name).unwrap()
51    }
52
53    fn visit_bool(&mut self, v: bool) -> Result<Self::Res, crate::Error> {
54        Ok(if v {
55            "true".to_string()
56        } else {
57            "false".to_string()
58        })
59    }
60
61    fn visit_int8(&mut self, v: i8) -> Result<Self::Res, crate::Error> {
62        Ok(format!("{v}"))
63    }
64    fn visit_int16(&mut self, v: i16) -> Result<Self::Res, crate::Error> {
65        Ok(format!("{v}"))
66    }
67    fn visit_int32(&mut self, v: i32) -> Result<Self::Res, crate::Error> {
68        Ok(format!("{v}"))
69    }
70    fn visit_int64(&mut self, v: i64) -> Result<Self::Res, crate::Error> {
71        Ok(format!("{v}"))
72    }
73    fn visit_uint8(&mut self, v: u8) -> Result<Self::Res, crate::Error> {
74        Ok(format!("{v}"))
75    }
76    fn visit_uint16(&mut self, v: u16) -> Result<Self::Res, crate::Error> {
77        Ok(format!("{v}"))
78    }
79    fn visit_uint32(&mut self, v: u32) -> Result<Self::Res, crate::Error> {
80        Ok(format!("{v}"))
81    }
82    fn visit_uint64(&mut self, v: u64) -> Result<Self::Res, crate::Error> {
83        Ok(format!("{v}"))
84    }
85    fn visit_float32(&mut self, v: f32) -> Result<Self::Res, crate::Error> {
86        Ok(format!("{v:#?}"))
87    }
88    fn visit_float64(&mut self, v: f64) -> Result<Self::Res, crate::Error> {
89        Ok(format!("{v:#?}"))
90    }
91
92    fn visit_text(&mut self, v: &str) -> Result<Self::Res, crate::Error> {
93        // TODO escape strings
94        Ok(format!("\"{v}\""))
95    }
96
97    fn visit_tuple(
98        &mut self,
99        fields: &[Value],
100        ty_fields: &'t [ir::TyTupleField],
101    ) -> Result<Self::Res, crate::Error> {
102        let mut r = "{".to_string();
103        self.indent();
104        for (field, ty) in fields.iter().zip(ty_fields) {
105            r += &self.new_line();
106
107            if let Some(name) = &ty.name {
108                r += name;
109                r += " = ";
110            }
111
112            r += &self.visit_value(field, &ty.ty)?;
113            r += ",";
114        }
115        self.deindent();
116        r += &self.new_line();
117        r += "}";
118        Ok(r)
119    }
120
121    fn visit_array(
122        &mut self,
123        items: &[Value],
124        ty_items: &'t ir::Ty,
125    ) -> Result<Self::Res, crate::Error> {
126        let mut r = "[".to_string();
127
128        if !items.is_empty() {
129            self.indent();
130            for item in items {
131                r += &self.new_line();
132                r += &self.visit_value(item, ty_items)?;
133                r += ",";
134            }
135            self.deindent();
136            r += &self.new_line();
137        }
138
139        r += "]";
140        Ok(r)
141    }
142
143    fn visit_enum(
144        &mut self,
145        tag: usize,
146        inner: &Value,
147        ty_variants: &'t [ir::TyEnumVariant],
148    ) -> Result<Self::Res, crate::Error> {
149        let variant = ty_variants.get(tag).ok_or(crate::Error::InvalidData)?;
150
151        let mut r = variant.name.to_string();
152
153        let is_unit = variant.ty.kind.as_tuple().is_some_and(|x| x.is_empty());
154        if !is_unit {
155            r += "(";
156            r += &self.visit_value(inner, &variant.ty)?;
157            r += ")";
158        }
159
160        Ok(r)
161    }
162}