Skip to main content

glint/
compiler.rs

1use crate::ast::*;
2use crate::opcodes::*;
3
4pub struct Compiler<'a> {
5    module: &'a ModuleSoA,
6    buf: Vec<u8>,
7}
8
9impl<'a> Compiler<'a> {
10    pub fn new(module: &'a ModuleSoA) -> Self {
11        Self {
12            module,
13            buf: Vec::new(),
14        }
15    }
16
17    pub fn compile(mut self, root_nodes: &[NodeId]) -> Vec<u8> {
18        self.buf.extend_from_slice(&MAGIC_HEADER);
19
20        self.compile_span(root_nodes);
21
22        self.buf
23    }
24
25    fn compile_span(&mut self, nodes: &[NodeId]) {
26        for node in nodes {
27            match node {
28                NodeId::Element(id) => self.compile_element(*id),
29                NodeId::Directive(id) => self.compile_directive(*id),
30            }
31        }
32    }
33
34    fn compile_block(&mut self, span: (u32, u32)) {
35        let start = span.0 as usize;
36        let len = span.1 as usize;
37        let nodes = &self.module.hierarchy[start..start + len];
38        self.compile_span(nodes);
39        self.buf.push(OP_END_BLOCK);
40    }
41
42    fn compile_element(&mut self, id: u32) {
43        let idx = id as usize;
44        let typ = &self.module.elem_types[idx];
45
46        self.buf.push(OP_ELEM_PUSH);
47        self.write_string(typ);
48
49        let (p_start, p_len) = self.module.elem_prop_spans[idx];
50        for i in p_start..(p_start + p_len) {
51            let key = &self.module.prop_keys[i as usize];
52            let val = &self.module.prop_values[i as usize];
53            self.compile_property(key, val);
54        }
55
56        if let Some(content) = &self.module.elem_content[idx] {
57            self.buf.push(OP_CONTENT);
58            self.compile_value(content);
59        }
60
61        let child_span = self.module.elem_child_spans[idx];
62        if child_span.1 > 0 {
63            self.compile_block(child_span);
64        }
65
66        self.buf.push(OP_ELEM_POP);
67    }
68
69    fn compile_directive(&mut self, id: u32) {
70        let dir = &self.module.directives[id as usize];
71        match dir {
72            Directive::Version(v) => {
73                self.buf.push(OP_VERSION);
74                self.write_i64(*v);
75            }
76            Directive::Style(s) => {
77                self.buf.push(OP_STYLE);
78                self.write_string(s);
79            }
80            Directive::Global { name, value } => {
81                self.buf.push(OP_GLOBAL);
82                self.write_string(name);
83                self.compile_value(value);
84            }
85            Directive::Singleton { name, prop_span } => {
86                self.buf.push(OP_SINGLETON);
87                self.write_string(name);
88                self.write_u32(prop_span.1);
89
90                let (start, len) = *prop_span;
91                for i in start..(start + len) {
92                    let key = &self.module.prop_keys[i as usize];
93                    let val = &self.module.prop_values[i as usize];
94                    self.write_string(key);
95                    self.compile_value(val);
96                }
97            }
98            Directive::Component {
99                name,
100                params,
101                child_span,
102            } => {
103                self.buf.push(OP_COMPONENT);
104                self.write_string(name);
105                self.write_u32(params.len() as u32);
106                for (pname, ptype) in params {
107                    self.write_string(pname);
108                    self.write_string(ptype);
109                }
110                self.compile_block(*child_span);
111            }
112            Directive::Let { name, value } => {
113                self.buf.push(OP_LET);
114                self.write_string(name);
115                self.compile_value(value);
116            }
117            Directive::If {
118                condition,
119                child_span,
120                else_span,
121            } => {
122                self.buf.push(OP_IF);
123                self.compile_value(condition);
124                self.compile_block(*child_span);
125                if let Some(es) = else_span {
126                    self.buf.push(1); // Has else
127                    self.compile_block(*es);
128                } else {
129                    self.buf.push(0); // No else
130                }
131            }
132            Directive::Each {
133                item,
134                collection,
135                child_span,
136            } => {
137                self.buf.push(OP_EACH);
138                self.write_string(item);
139                self.compile_value(collection);
140                self.compile_block(*child_span);
141            }
142            Directive::On {
143                event,
144                args,
145                child_span,
146            } => {
147                self.buf.push(OP_ON);
148                self.write_string(event);
149                self.write_u32(args.len() as u32);
150                for (k, v) in args {
151                    self.write_string(k);
152                    self.compile_value(v);
153                }
154                self.compile_block(*child_span);
155            }
156            Directive::RheiBlock(code) => {
157                self.buf.push(OP_RHEI_BLK);
158                self.write_string(code);
159            }
160        }
161    }
162
163    fn compile_property(&mut self, key: &str, val: &Value) {
164        match val {
165            Value::String(s) => {
166                self.buf.push(OP_PROP_STR);
167                self.write_string(key);
168                self.write_string(s);
169            }
170            Value::Int(i) => {
171                self.buf.push(OP_PROP_INT);
172                self.write_string(key);
173                self.write_i64(*i);
174            }
175            Value::Float(f) => {
176                self.buf.push(OP_PROP_FLOAT);
177                self.write_string(key);
178                self.write_f64(*f);
179            }
180            Value::Bool(b) => {
181                self.buf.push(OP_PROP_BOOL);
182                self.write_string(key);
183                self.buf.push(if *b { 1 } else { 0 });
184            }
185            Value::Color(c) => {
186                self.buf.push(OP_PROP_COLOR);
187                self.write_string(key);
188                self.write_string(c);
189            }
190            Value::FsPath(p) => {
191                self.buf.push(OP_PROP_FSPATH);
192                self.write_string(key);
193                self.write_string(p);
194            }
195            Value::Variable(v) => {
196                self.buf.push(OP_PROP_VAR);
197                self.write_string(key);
198                self.write_string(v);
199            }
200            Value::Rhei(r) => {
201                self.buf.push(OP_PROP_RHEI);
202                self.write_string(key);
203                self.write_string(r);
204            }
205        }
206    }
207
208    fn compile_value(&mut self, val: &Value) {
209        match val {
210            Value::String(s) => {
211                self.buf.push(OP_PROP_STR);
212                self.write_string(s);
213            }
214            Value::Int(i) => {
215                self.buf.push(OP_PROP_INT);
216                self.write_i64(*i);
217            }
218            Value::Float(f) => {
219                self.buf.push(OP_PROP_FLOAT);
220                self.write_f64(*f);
221            }
222            Value::Bool(b) => {
223                self.buf.push(OP_PROP_BOOL);
224                self.buf.push(if *b { 1 } else { 0 });
225            }
226            Value::Color(c) => {
227                self.buf.push(OP_PROP_COLOR);
228                self.write_string(c);
229            }
230            Value::FsPath(p) => {
231                self.buf.push(OP_PROP_FSPATH);
232                self.write_string(p);
233            }
234            Value::Variable(v) => {
235                self.buf.push(OP_PROP_VAR);
236                self.write_string(v);
237            }
238            Value::Rhei(r) => {
239                self.buf.push(OP_PROP_RHEI);
240                self.write_string(r);
241            }
242        }
243    }
244
245    fn write_string(&mut self, s: &str) {
246        let bytes = s.as_bytes();
247        self.write_u32(bytes.len() as u32);
248        self.buf.extend_from_slice(bytes);
249    }
250
251    fn write_u32(&mut self, v: u32) {
252        self.buf.extend_from_slice(&v.to_le_bytes());
253    }
254
255    fn write_i64(&mut self, v: i64) {
256        self.buf.extend_from_slice(&v.to_le_bytes());
257    }
258
259    fn write_f64(&mut self, v: f64) {
260        self.buf.extend_from_slice(&v.to_le_bytes());
261    }
262}