1use std::any::Any;
9use std::cell::RefCell;
10use std::ops::Deref;
11use std::rc::Rc;
12
13use crate::ast::{IXamlAstNode, IXamlPropertySetter, IXamlWrappedMethod};
14use crate::exceptions::{XamlError, XamlResult};
15use crate::extensions::{
16 query_node_interface, query_property_setter_interface, query_wrapped_method_interface,
17};
18use crate::transform::{TransformerConfiguration, XamlContextBase};
19use crate::type_system::{IFileSource, IXamlLocal, IXamlMethod, IXamlType, IXamlTypeBuilder};
20
21use super::{
22 IHasLocalsPool, IXamlAstLocalsNodeEmitter, IXamlWrappedMethodEmitterWithLocals,
23 XamlLanguageEmitMappings, XamlRuntimeContext,
24};
25
26pub trait IXamlEmitResult {
27 fn return_type(&self) -> Option<Rc<dyn IXamlType>>;
28 fn valid(&self) -> bool;
29}
30
31pub trait IXamlEmitter<TBackendEmitter, TEmitResult: IXamlEmitResult>: 'static {
34 fn as_node_emitter(&self) -> Option<&dyn IXamlAstNodeEmitter<TBackendEmitter, TEmitResult>> {
36 None
37 }
38 fn as_property_setter_emitter(
40 &self,
41 ) -> Option<&dyn IXamlPropertySetterEmitter<TBackendEmitter>> {
42 None
43 }
44 fn as_wrapped_method_emitter(
46 &self,
47 ) -> Option<&dyn IXamlWrappedMethodEmitter<TBackendEmitter, TEmitResult>> {
48 None
49 }
50 fn as_locals_node_emitter(
52 &self,
53 ) -> Option<&dyn IXamlAstLocalsNodeEmitter<TBackendEmitter, TEmitResult>>
54 where
55 TBackendEmitter: IHasLocalsPool,
56 {
57 None
58 }
59 fn as_wrapped_method_emitter_with_locals(
61 &self,
62 ) -> Option<&dyn IXamlWrappedMethodEmitterWithLocals<TBackendEmitter, TEmitResult>>
63 where
64 TBackendEmitter: IHasLocalsPool,
65 {
66 None
67 }
68 fn as_any(&self) -> &dyn Any;
69}
70
71pub trait IXamlAstNodeEmitter<TBackendEmitter, TEmitResult: IXamlEmitResult> {
72 fn emit(
74 &self,
75 node: &Rc<dyn IXamlAstNode>,
76 context: &dyn XamlEmitContext<TBackendEmitter, TEmitResult>,
77 code_gen: &TBackendEmitter,
78 ) -> XamlResult<Option<TEmitResult>>;
79}
80
81pub trait IXamlAstEmitableNode<TBackendEmitter, TEmitResult: IXamlEmitResult> {
84 fn emit(
85 &self,
86 context: &dyn XamlEmitContext<TBackendEmitter, TEmitResult>,
87 code_gen: &TBackendEmitter,
88 ) -> XamlResult<TEmitResult>;
89}
90
91pub trait IXamlCustomEmitMethod<TBackendEmitter>: IXamlMethod {
92 fn emit_call(&self, emitter: &TBackendEmitter) -> XamlResult<()>;
93}
94
95pub trait IXamlCustomEmitMethodWithContext<TBackendEmitter, TEmitResult: IXamlEmitResult>:
96 IXamlMethod
97{
98 fn emit_call(
99 &self,
100 context: &dyn XamlEmitContext<TBackendEmitter, TEmitResult>,
101 emitter: &TBackendEmitter,
102 ) -> XamlResult<()>;
103}
104
105pub trait IXamlPropertySetterEmitter<TBackendEmitter> {
106 fn emit_call(
107 &self,
108 setter: &Rc<dyn IXamlPropertySetter>,
109 emitter: &TBackendEmitter,
110 ) -> XamlResult<bool>;
111}
112
113pub trait IXamlEmitablePropertySetter<TBackendEmitter>: IXamlPropertySetter {
116 fn emit(&self, emitter: &TBackendEmitter) -> XamlResult<()>;
117}
118
119pub trait IXamlWrappedMethodEmitter<TBackendEmitter, TEmitResult: IXamlEmitResult> {
120 fn emit_call(
121 &self,
122 context: &dyn XamlEmitContext<TBackendEmitter, TEmitResult>,
123 method: &Rc<dyn IXamlWrappedMethod>,
124 emitter: &TBackendEmitter,
125 swallow_result: bool,
126 ) -> XamlResult<bool>;
127}
128
129pub trait IXamlEmitableWrappedMethod<TBackendEmitter, TEmitResult: IXamlEmitResult>:
132 IXamlWrappedMethod
133{
134 fn emit(
135 &self,
136 context: &dyn XamlEmitContext<TBackendEmitter, TEmitResult>,
137 emitter: &TBackendEmitter,
138 swallow_result: bool,
139 ) -> XamlResult<()>;
140}
141
142type AfterEmitCallback = Box<dyn FnOnce() -> XamlResult<()>>;
143
144pub struct XamlEmitContextBase<TBackendEmitter, TEmitResult: IXamlEmitResult> {
146 base: XamlContextBase,
147 context_local: Option<Rc<dyn IXamlLocal>>,
148 pub file: Option<Rc<dyn IFileSource>>,
149 pub emitters: Vec<Rc<dyn IXamlEmitter<TBackendEmitter, TEmitResult>>>,
150 after_emit_callbacks: RefCell<Vec<AfterEmitCallback>>,
151 current_node: RefCell<Option<Rc<dyn IXamlAstNode>>>,
152 pub configuration: Rc<TransformerConfiguration>,
153 pub emit_mappings: Rc<XamlLanguageEmitMappings<TBackendEmitter, TEmitResult>>,
154 pub runtime_context: Rc<XamlRuntimeContext<TBackendEmitter, TEmitResult>>,
155 pub declaring_type: Rc<dyn IXamlTypeBuilder<TBackendEmitter>>,
156 pub emitter: TBackendEmitter,
157}
158
159impl<TBackendEmitter, TEmitResult: IXamlEmitResult> Deref
161 for XamlEmitContextBase<TBackendEmitter, TEmitResult>
162{
163 type Target = XamlContextBase;
164
165 fn deref(&self) -> &XamlContextBase {
166 &self.base
167 }
168}
169
170impl<TBackendEmitter, TEmitResult: IXamlEmitResult>
171 XamlEmitContextBase<TBackendEmitter, TEmitResult>
172{
173 #[allow(clippy::too_many_arguments)]
174 pub fn new(
175 emitter: TBackendEmitter,
176 configuration: Rc<TransformerConfiguration>,
177 emit_mappings: Rc<XamlLanguageEmitMappings<TBackendEmitter, TEmitResult>>,
178 runtime_context: Rc<XamlRuntimeContext<TBackendEmitter, TEmitResult>>,
179 context_local: Option<Rc<dyn IXamlLocal>>,
180 declaring_type: Rc<dyn IXamlTypeBuilder<TBackendEmitter>>,
181 file: Option<Rc<dyn IFileSource>>,
182 emitters: Vec<Rc<dyn IXamlEmitter<TBackendEmitter, TEmitResult>>>,
183 ) -> Self {
184 Self {
185 base: XamlContextBase::new(),
186 context_local,
187 file,
188 emitters,
189 after_emit_callbacks: RefCell::new(Vec::new()),
190 current_node: RefCell::new(None),
191 configuration,
192 emit_mappings,
193 runtime_context,
194 declaring_type,
195 emitter,
196 }
197 }
198
199 pub fn context_local(&self) -> XamlResult<Rc<dyn IXamlLocal>> {
200 self.context_local.clone().ok_or_else(|| {
201 XamlError::invalid_operation(
202 "The current emit context doesn't supply a runtime context",
203 )
204 })
205 }
206
207 pub fn add_after_emit_callbacks(&self, callback: impl FnOnce() -> XamlResult<()> + 'static) {
208 self.after_emit_callbacks
209 .borrow_mut()
210 .push(Box::new(callback));
211 }
212
213 pub fn execute_after_emit_callbacks(&self) -> XamlResult<()> {
214 let callbacks = std::mem::take(&mut *self.after_emit_callbacks.borrow_mut());
215 for callback in callbacks {
216 callback()?;
217 }
218 Ok(())
219 }
220}
221
222pub trait XamlEmitContext<TBackendEmitter: 'static, TEmitResult: IXamlEmitResult + 'static>:
229 'static
230{
231 fn base(&self) -> &XamlEmitContextBase<TBackendEmitter, TEmitResult>;
233
234 fn as_emit_context(&self) -> &dyn XamlEmitContext<TBackendEmitter, TEmitResult>;
236
237 fn as_any(&self) -> &dyn Any;
238
239 fn emit_convert(
241 &self,
242 value: &Rc<dyn IXamlAstNode>,
243 code_gen: &TBackendEmitter,
244 expected_type: &Rc<dyn IXamlType>,
245 returned_type: &Rc<dyn IXamlType>,
246 ) -> XamlResult<()>;
247
248 fn emit_core_property_setter(
250 &self,
251 setter: &Rc<dyn IXamlPropertySetter>,
252 code_gen: &TBackendEmitter,
253 ) -> XamlResult<bool> {
254 default_emit_core_property_setter(self.as_emit_context(), setter, code_gen)
255 }
256
257 fn emit_core_wrapped_method(
259 &self,
260 wrapped: &Rc<dyn IXamlWrappedMethod>,
261 code_gen: &TBackendEmitter,
262 swallow_result: bool,
263 ) -> XamlResult<bool> {
264 default_emit_core_wrapped_method(self.as_emit_context(), wrapped, code_gen, swallow_result)
265 }
266
267 fn emit_node(
269 &self,
270 value: &Rc<dyn IXamlAstNode>,
271 code_gen: &TBackendEmitter,
272 ) -> XamlResult<TEmitResult> {
273 default_emit_node(self.as_emit_context(), value, code_gen)
274 }
275
276 fn emit_node_core(
279 &self,
280 value: &Rc<dyn IXamlAstNode>,
281 code_gen: &TBackendEmitter,
282 ) -> XamlResult<(Option<TEmitResult>, bool)> {
283 default_emit_node_core(self.as_emit_context(), value, code_gen)
284 }
285}
286
287pub fn default_emit_core_property_setter<B: 'static, R: IXamlEmitResult + 'static>(
289 context: &dyn XamlEmitContext<B, R>,
290 setter: &Rc<dyn IXamlPropertySetter>,
291 code_gen: &B,
292) -> XamlResult<bool> {
293 let mut found_emitter = false;
294 for e in &context.base().emitters {
295 if let Some(pse) = e.as_property_setter_emitter() {
296 found_emitter = pse.emit_call(setter, code_gen)?;
297 if found_emitter {
298 break;
299 }
300 }
301 }
302
303 if !found_emitter {
304 if let Some(eps) =
305 query_property_setter_interface::<dyn IXamlEmitablePropertySetter<B>>(setter)
306 {
307 found_emitter = true;
308 eps.emit(code_gen)?;
309 }
310 }
311
312 Ok(found_emitter)
313}
314
315pub fn default_emit_core_wrapped_method<B: 'static, R: IXamlEmitResult + 'static>(
317 context: &dyn XamlEmitContext<B, R>,
318 wrapped: &Rc<dyn IXamlWrappedMethod>,
319 code_gen: &B,
320 swallow_result: bool,
321) -> XamlResult<bool> {
322 let mut found_emitter = false;
323 for e in &context.base().emitters {
324 if let Some(wme) = e.as_wrapped_method_emitter() {
325 found_emitter = wme.emit_call(context, wrapped, code_gen, swallow_result)?;
326 if found_emitter {
327 break;
328 }
329 }
330 }
331
332 if !found_emitter {
333 if let Some(ewm) =
334 query_wrapped_method_interface::<dyn IXamlEmitableWrappedMethod<B, R>>(wrapped)
335 {
336 found_emitter = true;
337 ewm.emit(context, code_gen, swallow_result)?;
338 }
339 }
340
341 Ok(found_emitter)
342}
343
344pub fn default_emit_node<B: 'static, R: IXamlEmitResult + 'static>(
346 context: &dyn XamlEmitContext<B, R>,
347 value: &Rc<dyn IXamlAstNode>,
348 code_gen: &B,
349) -> XamlResult<R> {
350 let result = context
351 .emit_node_core(value, code_gen)
352 .and_then(|(res, found_emitter)| {
353 if !found_emitter {
354 return Err(XamlError::load_exception(
355 format!(
356 "Unable to find emitter for node type: {}",
357 value.type_name()
358 ),
359 Some(&**value),
360 ));
361 }
362 res.ok_or_else(|| {
363 XamlError::internal(
364 "NullReferenceException",
365 "The node emitter didn't produce an emit result",
366 )
367 })
368 });
369
370 match result {
371 Ok(res) => Ok(res),
372 Err(e) if e.is_xml_exception() => Err(e),
373 Err(e) => Err(XamlError::load_exception(
374 format!(
375 "Internal compiler error while emitting node {}:\n{}",
376 value.to_node_string(),
377 e
378 ),
379 Some(&**value),
380 )),
381 }
382}
383
384pub fn default_emit_node_core<B: 'static, R: IXamlEmitResult + 'static>(
386 context: &dyn XamlEmitContext<B, R>,
387 value: &Rc<dyn IXamlAstNode>,
388 code_gen: &B,
389) -> XamlResult<(Option<R>, bool)> {
390 let mut res: Option<R> = None;
391 for e in &context.base().emitters {
392 if let Some(ve) = e.as_node_emitter() {
393 res = ve.emit(value, context, code_gen)?;
394 if res.as_ref().is_some_and(|r| r.valid()) {
395 return Ok((res, true));
396 }
397 }
398 }
399
400 if let Some(en) = query_node_interface::<dyn IXamlAstEmitableNode<B, R>>(value) {
401 return Ok((Some(en.emit(context, code_gen)?), true));
402 }
403
404 Ok((res, false))
405}
406
407impl<B: 'static, R: IXamlEmitResult + 'static> dyn XamlEmitContext<B, R> {
409 pub fn emit(
411 &self,
412 value: &Rc<dyn IXamlAstNode>,
413 code_gen: &B,
414 expected_type: Option<&Rc<dyn IXamlType>>,
415 ) -> XamlResult<R> {
416 let base = self.base();
417 let previous = base.current_node.borrow().clone();
418 match previous {
419 Some(current) => {
420 base.push_parent(current);
421 *base.current_node.borrow_mut() = Some(value.clone());
422 let res = self.emit_core(value, code_gen, expected_type);
423 *base.current_node.borrow_mut() = base.pop_parent();
424 res
425 }
426 None => {
427 *base.current_node.borrow_mut() = Some(value.clone());
428 let res = self.emit_core(value, code_gen, expected_type);
429 *base.current_node.borrow_mut() = None;
430 res
431 }
432 }
433 }
434
435 pub fn emit_property_setter(
437 &self,
438 setter: &Rc<dyn IXamlPropertySetter>,
439 code_gen: &B,
440 ) -> XamlResult<()> {
441 if !self.emit_core_property_setter(setter, code_gen)? {
442 return Err(XamlError::invalid_operation(format!(
443 "Unable to find emitter for property setter type: {}",
444 setter.type_name()
445 )));
446 }
447 Ok(())
448 }
449
450 pub fn emit_wrapped_method(
452 &self,
453 wrapped: &Rc<dyn IXamlWrappedMethod>,
454 code_gen: &B,
455 swallow_result: bool,
456 ) -> XamlResult<()> {
457 if !self.emit_core_wrapped_method(wrapped, code_gen, swallow_result)? {
458 return Err(XamlError::invalid_operation(format!(
459 "Unable to find emitter for wrapped method type: {}",
460 wrapped.type_name()
461 )));
462 }
463 Ok(())
464 }
465
466 fn emit_core(
467 &self,
468 value: &Rc<dyn IXamlAstNode>,
469 code_gen: &B,
470 expected_type: Option<&Rc<dyn IXamlType>>,
471 ) -> XamlResult<R> {
472 let res = self.emit_node(value, code_gen)?;
473 let returned_type = res.return_type();
474
475 match (&returned_type, expected_type) {
476 (None, None) => {}
477 (Some(returned_type), None) => {
478 return Err(XamlError::load_exception(
479 format!(
480 "Emit of node {} resulted in {} while caller expected void",
481 value.to_node_string(),
482 returned_type.get_fqn()
483 ),
484 Some(&**value),
485 ));
486 }
487 (None, Some(expected_type)) => {
488 return Err(XamlError::load_exception(
489 format!(
490 "Emit of node {} resulted in void while caller expected {}",
491 value.to_node_string(),
492 expected_type.get_fqn()
493 ),
494 Some(&**value),
495 ));
496 }
497 (Some(returned_type), Some(expected_type)) => {
498 if !returned_type.equals(&**expected_type) {
499 self.emit_convert(value, code_gen, expected_type, returned_type)?;
500 }
501 }
502 }
503
504 Ok(res)
505 }
506
507 pub fn context_local(&self) -> XamlResult<Rc<dyn IXamlLocal>> {
508 self.base().context_local()
509 }
510
511 pub fn add_after_emit_callbacks(&self, callback: impl FnOnce() -> XamlResult<()> + 'static) {
512 self.base().add_after_emit_callbacks(callback)
513 }
514
515 pub fn execute_after_emit_callbacks(&self) -> XamlResult<()> {
516 self.base().execute_after_emit_callbacks()
517 }
518}