xee_xslt_compiler/
ast_ir.rs

1use ahash::HashSetExt;
2use xee_name::{Name, Namespaces, FN_NAMESPACE};
3
4use xee_interpreter::{context::StaticContext, error, interpreter};
5use xee_ir::{compile_xslt, ir, Bindings, Variables};
6use xee_xpath_ast::{ast as xpath_ast, pattern::transform_pattern, span::Spanned};
7use xee_xslt_ast::{ast, parse_transform};
8use xot::xmlname::NameStrInfo;
9
10use crate::{default_declarations::text_only_copy_declarations, priority::default_priority};
11
12struct IrConverter<'a> {
13    variables: Variables,
14    static_context: &'a StaticContext,
15}
16
17pub fn compile(
18    transform: ast::Transform,
19    static_context: StaticContext,
20) -> error::SpannedResult<interpreter::Program> {
21    let mut ir_converter = IrConverter::new(&static_context);
22    let declarations = ir_converter.transform(&transform)?;
23    compile_xslt(declarations, static_context)
24}
25
26pub fn parse(
27    static_context: StaticContext,
28    xslt: &str,
29) -> error::SpannedResult<interpreter::Program> {
30    let transform = parse_transform(xslt);
31    // TODO: better error handling
32    let mut transform = match transform {
33        Ok(transform) => transform,
34        Err(_e) => {
35            return Err(error::Error::Unsupported.into());
36        }
37    };
38    // insert default rules early on in precedence order
39    let mut declarations = text_only_copy_declarations().unwrap();
40    declarations.extend(transform.declarations);
41    transform.declarations = declarations;
42    compile(transform, static_context)
43}
44
45impl<'a> IrConverter<'a> {
46    fn new(static_context: &'a StaticContext) -> Self {
47        IrConverter {
48            variables: Variables::new(),
49            static_context,
50        }
51    }
52
53    fn main_sequence_constructor(&mut self) -> ast::SequenceConstructor {
54        vec![ast::SequenceConstructorItem::Instruction(
55            ast::SequenceConstructorInstruction::ApplyTemplates(Box::new(ast::ApplyTemplates {
56                // TODO: mode should be configurable from the outside somehow,
57                // the XSTL test suite I think requires this.
58                mode: ast::ApplyTemplatesModeValue::Unnamed,
59                select: ast::Expression {
60                    xpath: xee_xpath_ast::ast::XPath::parse(
61                        "/",
62                        &Namespaces::default(),
63                        &xee_name::VariableNames::new(),
64                    )
65                    .unwrap(),
66                    span: xee_xslt_ast::ast::Span::new(0, 0),
67                },
68                content: vec![],
69                span: xee_xslt_ast::ast::Span::new(0, 0),
70            })),
71        )]
72    }
73
74    fn simple_content_atom(&mut self) -> ir::Atom {
75        self.static_function_atom("simple-content", FN_NAMESPACE, 2)
76    }
77
78    fn concat_atom(&mut self, arity: u8) -> ir::Atom {
79        self.static_function_atom("concat", FN_NAMESPACE, arity)
80    }
81
82    // fn error_atom(&mut self) -> ir::Atom {
83    //     self.static_function_atom("error", Some(FN_NAMESPACE), 0)
84    // }
85
86    fn static_function_atom(&mut self, name: &str, namespace: &str, arity: u8) -> ir::Atom {
87        ir::Atom::Const(ir::Const::StaticFunctionReference(
88            self.static_context
89                .function_id_by_name(
90                    &Name::new(name.to_string(), namespace.to_string(), String::new()),
91                    arity,
92                )
93                .unwrap(),
94            None,
95        ))
96    }
97
98    fn simple_content_expr(
99        &mut self,
100        select_atom: ir::AtomS,
101        separator_atom: ir::AtomS,
102    ) -> ir::Expr {
103        ir::Expr::FunctionCall(ir::FunctionCall {
104            atom: Spanned::new(self.simple_content_atom(), (0..0).into()),
105            args: vec![select_atom, separator_atom],
106        })
107    }
108
109    fn transform(&mut self, transform: &ast::Transform) -> error::SpannedResult<ir::Declarations> {
110        let main_sequence_constructor = self.main_sequence_constructor();
111        let main = self.sequence_constructor_function(&main_sequence_constructor)?;
112        let mut declarations = ir::Declarations::new(main);
113
114        for declaration in &transform.declarations {
115            self.declaration(&mut declarations, declaration)?;
116        }
117        Ok(declarations)
118    }
119
120    fn declaration(
121        &mut self,
122        declarations: &mut ir::Declarations,
123        declaration: &ast::Declaration,
124    ) -> error::SpannedResult<()> {
125        use ast::Declaration::*;
126        match declaration {
127            Template(template) => self.template(declarations, template),
128            Mode(mode) => self.mode(declarations, mode),
129            _ => Err(error::Error::Unsupported.into()),
130        }
131    }
132
133    fn template(
134        &mut self,
135        declarations: &mut ir::Declarations,
136        template: &ast::Template,
137    ) -> error::SpannedResult<()> {
138        if let Some(pattern) = &template.match_ {
139            let priority = if let Some(priority) = &template.priority {
140                *priority
141            } else {
142                let default_priorities = default_priority(&pattern.pattern).collect::<Vec<_>>();
143                if default_priorities.len() > 1 {
144                    // for now, we can't deal with multiple registration yet
145                    return Err(error::Error::Unsupported.into());
146                } else {
147                    default_priorities.first().unwrap().1
148                }
149            };
150            let function_definition =
151                self.sequence_constructor_function(&template.sequence_constructor)?;
152
153            let modes = template
154                .mode
155                .iter()
156                .map(Self::ast_mode_value_to_ir_mode_value)
157                .collect();
158
159            declarations.rules.push(ir::Rule {
160                priority,
161                modes,
162                pattern: transform_pattern(&pattern.pattern, |expr| self.pattern_predicate(expr))?,
163                function_definition,
164            });
165            Ok(())
166        } else {
167            Err(error::Error::Unsupported.into())
168        }
169    }
170
171    fn mode(
172        &mut self,
173        declarations: &mut ir::Declarations,
174        mode: &ast::Mode,
175    ) -> error::SpannedResult<()> {
176        declarations.modes.insert(mode.name.clone(), ir::Mode {});
177        Ok(())
178    }
179
180    fn ast_mode_value_to_ir_mode_value(mode: &ast::ModeValue) -> ir::ModeValue {
181        match mode {
182            ast::ModeValue::EqName(name) => ir::ModeValue::Named(name.clone()),
183            ast::ModeValue::Unnamed => ir::ModeValue::Unnamed,
184            ast::ModeValue::All => ir::ModeValue::All,
185        }
186    }
187
188    fn sequence_constructor_function(
189        &mut self,
190        sequence_constructor: &ast::SequenceConstructor,
191    ) -> error::SpannedResult<ir::FunctionDefinition> {
192        let context_names = self.variables.push_context();
193        let bindings = self.sequence_constructor(sequence_constructor)?;
194        self.variables.pop_context();
195        let params = vec![
196            ir::Param {
197                name: context_names.item,
198                type_: None,
199            },
200            ir::Param {
201                name: context_names.position,
202                type_: None,
203            },
204            ir::Param {
205                name: context_names.last,
206                type_: None,
207            },
208        ];
209        Ok(ir::FunctionDefinition {
210            params,
211            return_type: None,
212            body: Box::new(bindings.expr()),
213        })
214    }
215
216    fn sequence_constructor(
217        &mut self,
218        sequence_constructor: &[ast::SequenceConstructorItem],
219    ) -> error::SpannedResult<Bindings> {
220        let mut items = sequence_constructor.iter();
221        let left = items.next();
222        if let Some(left) = left {
223            if let Some((name, var_bindings)) = self.variable(left)? {
224                let expr = ir::Expr::Let(ir::Let {
225                    name,
226                    var_expr: Box::new(var_bindings.expr()),
227                    return_expr: Box::new(self.sequence_constructor(items.as_slice())?.expr()),
228                });
229                return Ok(Bindings::new(
230                    self.variables.new_binding(expr, (0..0).into()),
231                ));
232            }
233            self.sequence_constructor_concat(left, items)
234        } else {
235            let empty_sequence = self.empty_sequence();
236            Ok(Bindings::new(
237                self.variables
238                    .new_binding(empty_sequence.value, empty_sequence.span),
239            ))
240        }
241    }
242
243    fn sequence_constructor_concat<'b>(
244        &mut self,
245        left: &ast::SequenceConstructorItem,
246        items: impl Iterator<Item = &'b ast::SequenceConstructorItem>,
247    ) -> error::SpannedResult<Bindings> {
248        let left_bindings = Ok(self.sequence_constructor_item(left)?);
249        items.fold(left_bindings, |left, right| {
250            let mut left_bindings = left?;
251            let mut right_bindings = self.sequence_constructor_item(right)?;
252            let expr = ir::Expr::Binary(ir::Binary {
253                left: left_bindings.atom(),
254                op: ir::BinaryOperator::Comma,
255                right: right_bindings.atom(),
256            });
257            let binding = self.variables.new_binding_no_span(expr);
258            Ok(left_bindings.concat(right_bindings).bind(binding))
259        })
260    }
261
262    fn sequence_constructor_item(
263        &mut self,
264        item: &ast::SequenceConstructorItem,
265    ) -> error::SpannedResult<Bindings> {
266        match item {
267            ast::SequenceConstructorItem::Instruction(instruction) => {
268                self.sequence_constructor_instruction(instruction)
269            }
270            ast::SequenceConstructorItem::Content(content) => {
271                self.sequence_constructor_content(content)
272            }
273        }
274    }
275
276    fn sequence_constructor_instruction(
277        &mut self,
278        instruction: &ast::SequenceConstructorInstruction,
279    ) -> error::SpannedResult<Bindings> {
280        use ast::SequenceConstructorInstruction::*;
281        match instruction {
282            ApplyTemplates(apply_templates) => self.apply_templates(apply_templates),
283            ValueOf(value_of) => self.value_of(value_of),
284            If(if_) => self.if_(if_),
285            Choose(choose) => self.choose(choose),
286            ForEach(for_each) => self.for_each(for_each),
287            Copy(copy) => self.copy(copy),
288            CopyOf(copy_of) => self.copy_of(copy_of),
289            Sequence(sequence) => self.sequence(sequence),
290            Element(element) => self.element(element),
291            Text(text) => self.text(text),
292            Attribute(attribute) => self.attribute(attribute),
293            Namespace(namespace) => self.namespace(namespace),
294            Comment(comment) => self.comment(comment),
295            ProcessingInstruction(pi) => self.processing_instruction(pi),
296            // TODO: xsl:variable does not produce content and is handled
297            // earlier already should be unreachable!() but at this point this
298            // can be reached so return unsupported
299            Variable(_variable) => Err(error::Error::Unsupported.into()),
300            _ => Err(error::Error::Unsupported.into()),
301        }
302    }
303
304    fn sequence_constructor_content(
305        &mut self,
306        content: &ast::Content,
307    ) -> error::SpannedResult<Bindings> {
308        match content {
309            ast::Content::Element(element_node) => {
310                self.sequence_constructor_content_element(element_node)
311            }
312            ast::Content::Text(text) => {
313                let text_atom = Spanned::new(
314                    ir::Atom::Const(ir::Const::String(text.clone())),
315                    (0..0).into(),
316                );
317                let bindings = Bindings::empty();
318                Ok(bindings.bind_expr_no_span(
319                    &mut self.variables,
320                    ir::Expr::XmlText(ir::XmlText { value: text_atom }),
321                ))
322            }
323            ast::Content::Value(expression) => {
324                let (atom, bindings) = self.expression(expression)?.atom_bindings();
325                let expr = self.simple_content_expr(atom, self.space_separator_atom());
326                let (text_atom, bindings) = bindings
327                    .bind_expr_no_span(&mut self.variables, expr)
328                    .atom_bindings();
329                Ok(bindings.bind_expr_no_span(
330                    &mut self.variables,
331                    ir::Expr::XmlText(ir::XmlText { value: text_atom }),
332                ))
333            }
334        }
335    }
336
337    fn sequence_constructor_content_element(
338        &mut self,
339        element_node: &ast::ElementNode,
340    ) -> error::SpannedResult<Bindings> {
341        let (name_atom, bindings) = self.xml_name(&element_node.name)?.atom_bindings();
342        let name_expr = ir::Expr::XmlElement(ir::XmlElement { name: name_atom });
343        let (element_atom, mut bindings) = bindings
344            .bind_expr_no_span(&mut self.variables, name_expr)
345            .atom_bindings();
346        for (name, value) in &element_node.attributes {
347            let (value_atom, value_bindings) =
348                self.attribute_value_template(value)?.atom_bindings();
349            let (attribute_name_atom, attribute_bindings) = self.xml_name(name)?.atom_bindings();
350            let value_bindings = value_bindings.concat(attribute_bindings);
351            let attribute_expr = ir::Expr::XmlAttribute(ir::XmlAttribute {
352                name: attribute_name_atom,
353                value: value_atom,
354            });
355            let (attribute_atom, attribute_bindings) = value_bindings
356                .bind_expr_no_span(&mut self.variables, attribute_expr)
357                .atom_bindings();
358            let append_expr = ir::Expr::XmlAppend(ir::XmlAppend {
359                parent: element_atom.clone(),
360                child: attribute_atom,
361            });
362            let append_bindings =
363                attribute_bindings.bind_expr_no_span(&mut self.variables, append_expr);
364            bindings = bindings.concat(append_bindings);
365        }
366        let sequence_constructor_bindings = self.sequence_constructor_append(
367            element_atom.clone(),
368            &element_node.sequence_constructor,
369        )?;
370        let bindings = bindings.concat(sequence_constructor_bindings);
371        Ok(bindings)
372    }
373
374    fn sequence_constructor_append(
375        &mut self,
376        element_atom: ir::AtomS,
377        sequence_constructor: &ast::SequenceConstructor,
378    ) -> error::SpannedResult<Bindings> {
379        if !sequence_constructor.is_empty() {
380            let (atom, bindings) = self
381                .sequence_constructor(sequence_constructor)?
382                .atom_bindings();
383            let append = ir::Expr::XmlAppend(ir::XmlAppend {
384                parent: element_atom,
385                child: atom,
386            });
387            let bindings = bindings.bind_expr_no_span(&mut self.variables, append);
388            Ok(bindings)
389        } else {
390            Ok(Bindings::empty())
391        }
392    }
393
394    fn space_separator_atom(&self) -> ir::AtomS {
395        Spanned::new(
396            ir::Atom::Const(ir::Const::String(" ".to_string())),
397            (0..0).into(),
398        )
399    }
400
401    fn apply_templates(
402        &mut self,
403        apply_templates: &ast::ApplyTemplates,
404    ) -> error::SpannedResult<Bindings> {
405        let (select_atom, bindings) = self.expression(&apply_templates.select)?.atom_bindings();
406        let mode = match &apply_templates.mode {
407            ast::ApplyTemplatesModeValue::EqName(name) => {
408                ir::ApplyTemplatesModeValue::Named(name.clone())
409            }
410            ast::ApplyTemplatesModeValue::Unnamed => ir::ApplyTemplatesModeValue::Unnamed,
411            ast::ApplyTemplatesModeValue::Current => ir::ApplyTemplatesModeValue::Current,
412        };
413
414        Ok(bindings.bind_expr_no_span(
415            &mut self.variables,
416            ir::Expr::ApplyTemplates(ir::ApplyTemplates {
417                mode,
418                select: select_atom,
419            }),
420        ))
421    }
422
423    fn select_or_sequence_constructor(
424        &mut self,
425        instruction: &impl ast::SelectOrSequenceConstructor,
426    ) -> error::SpannedResult<Bindings> {
427        if let Some(select) = instruction.select() {
428            self.expression(select)
429        } else {
430            self.sequence_constructor(instruction.sequence_constructor())
431        }
432    }
433
434    fn select_or_sequence_constructor_simple_content(
435        &mut self,
436        instruction: &impl ast::SelectOrSequenceConstructor,
437    ) -> error::SpannedResult<Bindings> {
438        let (select_atom, bindings) = self
439            .select_or_sequence_constructor(instruction)?
440            .atom_bindings();
441
442        let separator_atom = self.space_separator_atom();
443        let expr = self.simple_content_expr(select_atom, separator_atom);
444        Ok(bindings.bind_expr_no_span(&mut self.variables, expr))
445    }
446
447    fn select_or_sequence_constructor_simple_content_with_separator(
448        &mut self,
449        instruction: &impl ast::SelectOrSequenceConstructor,
450        separator: &Option<ast::ValueTemplate<String>>,
451    ) -> error::SpannedResult<Bindings> {
452        let (select_atom, select_bindings) = self
453            .select_or_sequence_constructor(instruction)?
454            .atom_bindings();
455
456        let (separator_atom, separator_bindings) = if let Some(separator) = separator {
457            self.attribute_value_template(separator)?
458        } else {
459            Bindings::new(
460                self.variables
461                    .new_binding_no_span(ir::Expr::Atom(self.space_separator_atom())),
462            )
463        }
464        .atom_bindings();
465        let bindings = select_bindings.concat(separator_bindings);
466        let expr = self.simple_content_expr(select_atom, separator_atom);
467        Ok(bindings.bind_expr_no_span(&mut self.variables, expr))
468    }
469
470    fn value_of(&mut self, value_of: &ast::ValueOf) -> error::SpannedResult<Bindings> {
471        let (text_atom, bindings) = self
472            .select_or_sequence_constructor_simple_content_with_separator(
473                value_of,
474                &value_of.separator,
475            )?
476            .atom_bindings();
477
478        Ok(bindings.bind_expr_no_span(
479            &mut self.variables,
480            ir::Expr::XmlText(ir::XmlText { value: text_atom }),
481        ))
482    }
483
484    fn attribute_value_template(
485        &mut self,
486        value_template: &ast::ValueTemplate<String>,
487    ) -> error::SpannedResult<Bindings> {
488        let mut all_bindings = Vec::new();
489        for item in &value_template.template {
490            let bindings = match item {
491                ast::ValueTemplateItem::String { text, span: _span } => {
492                    let text_atom = Spanned::new(
493                        ir::Atom::Const(ir::Const::String(text.clone())),
494                        (0..0).into(),
495                    );
496                    let bindings = Bindings::empty();
497                    bindings.bind_expr_no_span(&mut self.variables, ir::Expr::Atom(text_atom))
498                }
499                ast::ValueTemplateItem::Curly { c } => {
500                    let text_atom = Spanned::new(
501                        ir::Atom::Const(ir::Const::String(c.to_string())),
502                        (0..0).into(),
503                    );
504                    let bindings = Bindings::empty();
505                    bindings.bind_expr_no_span(&mut self.variables, ir::Expr::Atom(text_atom))
506                }
507                ast::ValueTemplateItem::Value { xpath, span: _ } => {
508                    let (atom, bindings) = self.xpath(&xpath.0)?.atom_bindings();
509                    let expr = self.simple_content_expr(atom, self.space_separator_atom());
510                    bindings.bind_expr_no_span(&mut self.variables, expr)
511                }
512            };
513            all_bindings.push(bindings);
514        }
515        Ok(if all_bindings.is_empty() {
516            // empty attribute value template is a string
517            let bindings = Bindings::empty();
518            let empty_string = ir::Expr::Atom(self.empty_string());
519            bindings.bind_expr_no_span(&mut self.variables, empty_string)
520        } else if all_bindings.len() == 1 {
521            // a single binding is just that binding
522            all_bindings.pop().unwrap()
523        } else {
524            // TODO: speculative code, needs tests
525            // if we have multiple bindings, concatenate each result into
526            // a single string
527            let mut combined_bindings = Bindings::empty();
528            let mut atoms = Vec::new();
529            for binding in all_bindings {
530                let (atom, binding) = binding.atom_bindings();
531                combined_bindings = combined_bindings.concat(binding);
532                atoms.push(atom);
533            }
534            // concatenate all the pieces of content into a single string
535            // TODO: this may create more than we have arities for, so we may want to use more
536            // generic concat function that takes a sequence at some point
537            let concat_atom = self.concat_atom(atoms.len() as u8);
538            let expr = ir::Expr::FunctionCall(ir::FunctionCall {
539                atom: Spanned::new(concat_atom, (0..0).into()),
540                args: atoms,
541            });
542            combined_bindings.bind_expr_no_span(&mut self.variables, expr)
543        })
544    }
545
546    fn variable(
547        &mut self,
548        item: &ast::SequenceConstructorItem,
549    ) -> error::SpannedResult<Option<(ir::Name, Bindings)>> {
550        if let ast::SequenceConstructorItem::Instruction(
551            ast::SequenceConstructorInstruction::Variable(variable),
552        ) = item
553        {
554            let name = self.variables.new_var_name(&variable.name);
555            let var_bindings = if let Some(select) = &variable.select {
556                self.expression(select)?
557            } else {
558                self.sequence_constructor(&variable.sequence_constructor)?
559            };
560            Ok(Some((name, var_bindings)))
561        } else {
562            Ok(None)
563        }
564    }
565
566    fn empty_sequence(&mut self) -> ir::ExprS {
567        Spanned::new(
568            ir::Expr::Atom(Spanned::new(
569                ir::Atom::Const(ir::Const::EmptySequence),
570                (0..0).into(),
571            )),
572            (0..0).into(),
573        )
574    }
575
576    fn empty_string(&self) -> ir::AtomS {
577        Spanned::new(
578            ir::Atom::Const(ir::Const::String("".to_string())),
579            (0..0).into(),
580        )
581    }
582
583    fn if_(&mut self, if_: &ast::If) -> error::SpannedResult<Bindings> {
584        let (condition, bindings) = self.expression(&if_.test)?.atom_bindings();
585        let expr = ir::Expr::If(ir::If {
586            condition,
587            then: Box::new(self.sequence_constructor(&if_.sequence_constructor)?.expr()),
588            else_: Box::new(self.empty_sequence()),
589        });
590        Ok(bindings.bind_expr_no_span(&mut self.variables, expr))
591    }
592
593    fn choose(&mut self, choose: &ast::Choose) -> error::SpannedResult<Bindings> {
594        self.choose_when_otherwise(&choose.when, choose.otherwise.as_ref())
595    }
596
597    fn choose_when_otherwise(
598        &mut self,
599        when: &[ast::When],
600        otherwise: Option<&ast::Otherwise>,
601    ) -> error::SpannedResult<Bindings> {
602        let first = &when.first().unwrap();
603        let rest = &when[1..];
604
605        let (condition, bindings) = self.expression(&first.test)?.atom_bindings();
606        let else_expr = if !rest.is_empty() {
607            self.choose_when_otherwise(rest, otherwise)?.expr()
608        } else if let Some(otherwise) = otherwise {
609            self.sequence_constructor(&otherwise.sequence_constructor)?
610                .expr()
611        } else {
612            self.empty_sequence()
613        };
614
615        let expr = ir::Expr::If(ir::If {
616            condition,
617            then: Box::new(
618                self.sequence_constructor(&first.sequence_constructor)?
619                    .expr(),
620            ),
621            else_: Box::new(else_expr),
622        });
623        Ok(bindings.bind_expr_no_span(&mut self.variables, expr))
624    }
625
626    fn for_each(&mut self, for_each: &ast::ForEach) -> error::SpannedResult<Bindings> {
627        let (var_atom, bindings) = self.expression(&for_each.select)?.atom_bindings();
628
629        let context_names = self.variables.push_context();
630        let return_bindings = self.sequence_constructor(&for_each.sequence_constructor)?;
631        self.variables.pop_context();
632        let expr = ir::Expr::Map(ir::Map {
633            context_names,
634            var_atom,
635            return_expr: Box::new(return_bindings.expr()),
636        });
637
638        Ok(bindings.bind_expr_no_span(&mut self.variables, expr))
639    }
640
641    fn copy(&mut self, copy: &ast::Copy) -> error::SpannedResult<Bindings> {
642        let (context_atom, bindings) = if let Some(select) = &copy.select {
643            self.expression(select)?.atom_bindings()
644        } else {
645            self.variables.context_item((0..0).into())?.atom_bindings()
646        };
647        // copy shallow this item
648        let expr = ir::Expr::CopyShallow(ir::CopyShallow {
649            select: context_atom,
650        });
651        let (copy_atom, bindings) = bindings
652            .bind_expr_no_span(&mut self.variables, expr)
653            .atom_bindings();
654
655        // if it is an element or document,
656        // execute sequence constructor
657        // TODO: work on document check
658        // let _is_document_expr = self.is_document_expr(context_atom.clone());
659        let is_element_expr = self.is_element_expr(copy_atom.clone());
660        let (is_element_atom, bindings) = bindings
661            .bind_expr_no_span(&mut self.variables, is_element_expr)
662            .atom_bindings();
663
664        let copy_expr = ir::Expr::Atom(copy_atom.clone());
665
666        let (sequence_constructor_atom, sequence_constructor_bindings) = self
667            .sequence_constructor(&copy.sequence_constructor)?
668            .atom_bindings();
669
670        let bindings = bindings.concat(sequence_constructor_bindings);
671
672        let append = ir::Expr::XmlAppend(ir::XmlAppend {
673            parent: copy_atom,
674            child: sequence_constructor_atom,
675        });
676
677        let if_expr = ir::Expr::If(ir::If {
678            condition: is_element_atom,
679            then: Box::new(Spanned::new(append, (0..0).into())),
680            else_: Box::new(Spanned::new(copy_expr, (0..0).into())),
681        });
682
683        Ok(bindings.bind_expr_no_span(&mut self.variables, if_expr))
684    }
685
686    // fn is_document_expr(&self, atom: ir::AtomS) -> ir::Expr {
687    //     ir::Expr::InstanceOf(ir::InstanceOf {
688    //         atom,
689    //         sequence_type: xpath_ast::SequenceType::Item(xpath_ast::Item {
690    //             item_type: xpath_ast::ItemType::KindTest(xpath_ast::KindTest::Document(None)),
691    //             occurrence: xpath_ast::Occurrence::One,
692    //         }),
693    //     })
694    // }
695
696    fn is_element_expr(&self, atom: ir::AtomS) -> ir::Expr {
697        ir::Expr::InstanceOf(ir::InstanceOf {
698            atom,
699            sequence_type: xpath_ast::SequenceType::Item(xpath_ast::Item {
700                item_type: xpath_ast::ItemType::KindTest(xpath_ast::KindTest::Element(None)),
701                occurrence: xpath_ast::Occurrence::One,
702            }),
703        })
704    }
705
706    fn copy_of(&mut self, copy_of: &ast::CopyOf) -> error::SpannedResult<Bindings> {
707        let (atom, bindings) = self.expression(&copy_of.select)?.atom_bindings();
708        let copy_deep_expr = ir::Expr::CopyDeep(ir::CopyDeep { select: atom });
709        Ok(bindings.bind_expr_no_span(&mut self.variables, copy_deep_expr))
710    }
711
712    fn sequence(&mut self, sequence: &ast::Sequence) -> error::SpannedResult<Bindings> {
713        self.select_or_sequence_constructor(sequence)
714    }
715
716    fn xml_name(&mut self, name: &ast::Name) -> error::SpannedResult<Bindings> {
717        let local_name = Spanned::new(
718            ir::Atom::Const(ir::Const::String(name.local_name().to_string())),
719            (0..0).into(),
720        );
721        let namespace = self.empty_string();
722
723        let binding = self
724            .variables
725            .new_binding_no_span(ir::Expr::XmlName(ir::XmlName {
726                local_name,
727                namespace,
728            }));
729        Ok(Bindings::new(binding))
730    }
731
732    fn xml_name_dynamic(
733        &mut self,
734        name: &ast::ValueTemplate<String>,
735        namespace: &Option<ast::ValueTemplate<String>>,
736    ) -> error::SpannedResult<Bindings> {
737        let (localname_atom, bindings) = self.attribute_value_template(name)?.atom_bindings();
738        let (namespace_atom, namespace_bindings) = if let Some(namespace) = namespace {
739            self.attribute_value_template(namespace)?.atom_bindings()
740        } else {
741            let namespace_atom = self.empty_string();
742            (namespace_atom, Bindings::empty())
743        };
744        let bindings = bindings.concat(namespace_bindings);
745        let name = ir::Expr::XmlName(ir::XmlName {
746            local_name: localname_atom,
747            namespace: namespace_atom,
748        });
749        Ok(bindings.bind_expr_no_span(&mut self.variables, name))
750    }
751
752    fn ncname_dynamic(
753        &mut self,
754        name: &ast::ValueTemplate<String>,
755    ) -> error::SpannedResult<Bindings> {
756        self.attribute_value_template(name)
757    }
758
759    fn element(&mut self, element: &ast::Element) -> error::SpannedResult<Bindings> {
760        let (name_atom, bindings) = self
761            .xml_name_dynamic(&element.name, &element.namespace)?
762            .atom_bindings();
763
764        let expr = ir::Expr::XmlElement(ir::XmlElement { name: name_atom });
765        let (element_atom, bindings) = bindings
766            .bind_expr_no_span(&mut self.variables, expr)
767            .atom_bindings();
768        let sequence_constructor_bindings =
769            self.sequence_constructor_append(element_atom, &element.sequence_constructor)?;
770        Ok(bindings.concat(sequence_constructor_bindings))
771    }
772
773    fn text(&mut self, text: &ast::Text) -> error::SpannedResult<Bindings> {
774        let (atom, bindings) = self
775            .attribute_value_template(&text.content)?
776            .atom_bindings();
777        Ok(bindings.bind_expr_no_span(
778            &mut self.variables,
779            ir::Expr::XmlText(ir::XmlText { value: atom }),
780        ))
781    }
782
783    fn attribute(&mut self, attribute: &ast::Attribute) -> error::SpannedResult<Bindings> {
784        let (name_atom, name_bindings) = self
785            .xml_name_dynamic(&attribute.name, &attribute.namespace)?
786            .atom_bindings();
787        let (text_atom, text_bindings) = self
788            .select_or_sequence_constructor_simple_content_with_separator(
789                attribute,
790                &attribute.separator,
791            )?
792            .atom_bindings();
793        let bindings = name_bindings.concat(text_bindings);
794        Ok(bindings.bind_expr_no_span(
795            &mut self.variables,
796            ir::Expr::XmlAttribute(ir::XmlAttribute {
797                name: name_atom,
798                value: text_atom,
799            }),
800        ))
801    }
802
803    fn namespace(&mut self, namespace: &ast::Namespace) -> error::SpannedResult<Bindings> {
804        let (ncname_atom, ncname_bindings) = self.ncname_dynamic(&namespace.name)?.atom_bindings();
805        let (text_atom, text_bindings) = self
806            .select_or_sequence_constructor_simple_content(namespace)?
807            .atom_bindings();
808        let bindings = ncname_bindings.concat(text_bindings);
809        Ok(bindings.bind_expr_no_span(
810            &mut self.variables,
811            ir::Expr::XmlNamespace(ir::XmlNamespace {
812                prefix: ncname_atom,
813                namespace: text_atom,
814            }),
815        ))
816    }
817
818    fn comment(&mut self, comment: &ast::Comment) -> error::SpannedResult<Bindings> {
819        let (atom, bindings) = self
820            .select_or_sequence_constructor_simple_content(comment)?
821            .atom_bindings();
822        Ok(bindings.bind_expr_no_span(
823            &mut self.variables,
824            ir::Expr::XmlComment(ir::XmlComment { value: atom }),
825        ))
826    }
827
828    fn processing_instruction(
829        &mut self,
830        pi: &ast::ProcessingInstruction,
831    ) -> error::SpannedResult<Bindings> {
832        let (ncname_atom, ncname_bindings) = self.ncname_dynamic(&pi.name)?.atom_bindings();
833        let (content_atom, content_bindings) = self
834            .select_or_sequence_constructor_simple_content(pi)?
835            .atom_bindings();
836        let bindings = ncname_bindings.concat(content_bindings);
837        Ok(bindings.bind_expr_no_span(
838            &mut self.variables,
839            ir::Expr::XmlProcessingInstruction(ir::XmlProcessingInstruction {
840                target: ncname_atom,
841                content: content_atom,
842            }),
843        ))
844    }
845
846    // fn throw_error(&mut self) -> error::SpannedResult<Bindings> {
847    //     let error_atom = self.error_atom();
848    //     let expr = ir::Expr::FunctionCall(ir::FunctionCall {
849    //         atom: Spanned::new(error_atom, (0..0).into()),
850    //         args: vec![],
851    //     });
852    //     Ok(Bindings::new(self.variables.new_binding_no_span(expr)))
853    // }
854
855    fn expression(&mut self, expression: &ast::Expression) -> error::SpannedResult<Bindings> {
856        self.xpath(&expression.xpath.0)
857    }
858
859    fn xpath(&mut self, xpath: &xee_xpath_ast::ast::ExprS) -> error::SpannedResult<Bindings> {
860        let mut ir_converter =
861            xee_xpath_compiler::IrConverter::new(&mut self.variables, self.static_context);
862        ir_converter.expr(xpath)
863    }
864
865    fn pattern_predicate(
866        &mut self,
867        expr: &xpath_ast::ExprS,
868    ) -> error::SpannedResult<ir::FunctionDefinition> {
869        let context_names = self.variables.push_context();
870        let bindings = self.xpath(expr)?;
871        self.variables.pop_context();
872        // a predicate is a function that takes a sequence as an argument and returns
873        // a boolean that is true if the sequence matches the predicate
874        let name = self.variables.new_name();
875        let var_atom = Spanned::new(ir::Atom::Variable(name.clone()), (0..0).into());
876        let filter = ir::Expr::PatternPredicate(ir::PatternPredicate {
877            context_names: context_names.clone(),
878            var_atom,
879            expr: Box::new(bindings.expr()),
880        });
881        let bindings = bindings.bind_expr(&mut self.variables, Spanned::new(filter, (0..0).into()));
882
883        let params = vec![
884            ir::Param {
885                name: context_names.item,
886                type_: None,
887            },
888            ir::Param {
889                name: context_names.position,
890                type_: None,
891            },
892            ir::Param {
893                name: context_names.last,
894                type_: None,
895            },
896        ];
897
898        Ok(ir::FunctionDefinition {
899            params,
900            return_type: None,
901            body: Box::new(bindings.expr()),
902        })
903    }
904}