xee_xpath_compiler/
ast_ir.rs

1use xee_interpreter::{context, error, error::Error, function, xml};
2use xee_ir::{ir, ir::AtomS, Binding, Bindings, Variables};
3use xee_schema_type::Xs;
4use xee_xpath_ast::{ast, ast::Span, span::Spanned, FN_NAMESPACE};
5use xot::xmlname::NameStrInfo;
6
7#[derive(Debug)]
8pub struct IrConverter<'a> {
9    variables: &'a mut Variables,
10    static_context: &'a context::StaticContext,
11    fn_position: ast::Name,
12    fn_last: ast::Name,
13}
14
15impl<'a> IrConverter<'a> {
16    pub fn new(variables: &'a mut Variables, static_context: &'a context::StaticContext) -> Self {
17        Self {
18            variables,
19            static_context,
20            fn_position: ast::Name::new(
21                "position".to_string(),
22                FN_NAMESPACE.to_string(),
23                String::new(),
24            ),
25            fn_last: ast::Name::new("last".to_string(), FN_NAMESPACE.to_string(), String::new()),
26        }
27    }
28
29    #[cfg(test)]
30    fn convert_expr_single(&mut self, ast: &ast::ExprSingleS) -> error::SpannedResult<ir::ExprS> {
31        let bindings = self.expr_single(ast)?;
32        Ok(bindings.expr())
33    }
34
35    pub(crate) fn convert_xpath(&mut self, ast: &ast::XPath) -> error::SpannedResult<ir::ExprS> {
36        let bindings = self.xpath(ast)?;
37        Ok(bindings.expr())
38    }
39
40    pub fn xpath(&mut self, ast: &ast::XPath) -> error::SpannedResult<Bindings> {
41        let context_names = self.variables.push_context();
42        // define any external variable names
43        let mut ir_names = Vec::new();
44        for name in self.static_context.variable_names() {
45            ir_names.push(self.variables.new_var_name(name));
46        }
47        let exprs_bindings = self.expr(&ast.0)?;
48        self.variables.pop_context();
49        let mut params = vec![
50            ir::Param {
51                name: context_names.item,
52                type_: None,
53            },
54            ir::Param {
55                name: context_names.position,
56                type_: None,
57            },
58            ir::Param {
59                name: context_names.last,
60                type_: None,
61            },
62        ];
63        // add any variables defined in static context as parameters
64        for ir_name in ir_names {
65            params.push(ir::Param {
66                name: ir_name,
67                type_: None,
68            });
69        }
70        let outer_function_expr = ir::Expr::FunctionDefinition(ir::FunctionDefinition {
71            params,
72            return_type: None,
73            body: Box::new(exprs_bindings.expr()),
74        });
75        let binding = self.variables.new_binding(outer_function_expr, ast.0.span);
76        Ok(Bindings::new(binding))
77    }
78
79    fn expr_single(&mut self, ast: &ast::ExprSingleS) -> error::SpannedResult<Bindings> {
80        let outer_ast = &ast.value;
81        let span = ast.span;
82        match outer_ast {
83            ast::ExprSingle::Path(ast) => self.path_expr(ast),
84            ast::ExprSingle::Apply(ast) => self.apply_expr(ast, span),
85            ast::ExprSingle::Let(ast) => self.let_expr(ast, span),
86            ast::ExprSingle::If(ast) => self.if_expr(ast, span),
87            ast::ExprSingle::Binary(ast) => self.binary_expr(ast, span),
88            ast::ExprSingle::For(ast) => self.for_expr(ast, span),
89            ast::ExprSingle::Quantified(ast) => self.quantified_expr(ast, span),
90        }
91    }
92
93    fn path_expr(&mut self, ast: &ast::PathExpr) -> error::SpannedResult<Bindings> {
94        let first_step = &ast.steps[0];
95        let rest_steps = &ast.steps[1..];
96        let first_step_bindings = Ok(self.step_expr(first_step)?);
97        rest_steps
98            .iter()
99            .fold(first_step_bindings, |acc, step_expr| {
100                let mut step_bindings = acc?;
101                let step_atom = step_bindings.atom();
102                let context_names = self.variables.push_context();
103                let return_bindings = self.step_expr(step_expr)?;
104                self.variables.pop_context();
105                let expr = ir::Expr::Map(ir::Map {
106                    context_names,
107                    var_atom: step_atom,
108                    return_expr: Box::new(return_bindings.expr()),
109                });
110                // wrap this in a deduplicate step
111                let deduplicate_expr =
112                    ir::Expr::Deduplicate(Box::new(Spanned::new(expr, step_expr.span)));
113
114                let binding = self.variables.new_binding(deduplicate_expr, step_expr.span);
115                Ok(step_bindings.bind(binding))
116            })
117    }
118
119    fn step_expr(&mut self, ast: &ast::StepExprS) -> error::SpannedResult<Bindings> {
120        let outer_ast = &ast.value;
121        let span = ast.span;
122        match outer_ast {
123            ast::StepExpr::PrimaryExpr(ast) => self.primary_expr(ast),
124            ast::StepExpr::PostfixExpr { primary, postfixes } => self.postfixes(primary, postfixes),
125            ast::StepExpr::AxisStep(ast) => self.axis_step(ast, span),
126        }
127    }
128
129    fn primary_expr(&mut self, ast: &ast::PrimaryExprS) -> error::SpannedResult<Bindings> {
130        let outer_ast = &ast.value;
131        let span = ast.span;
132        match outer_ast {
133            ast::PrimaryExpr::Literal(ast) => Ok(self.literal(ast, span)?),
134            ast::PrimaryExpr::VarRef(ast) => self.variables.var_ref(ast, span),
135            ast::PrimaryExpr::Expr(expr) => self.expr_or_empty(expr),
136            ast::PrimaryExpr::ContextItem => self.variables.context_item(span),
137            ast::PrimaryExpr::InlineFunction(ast) => self.inline_function(ast, span),
138            ast::PrimaryExpr::FunctionCall(ast) => self.function_call(ast, span),
139            ast::PrimaryExpr::NamedFunctionRef(ast) => self.named_function_ref(ast, span),
140            ast::PrimaryExpr::MapConstructor(ast) => self.map_constructor(ast, span),
141            ast::PrimaryExpr::ArrayConstructor(ast) => self.array_constructor(ast, span),
142            ast::PrimaryExpr::UnaryLookup(ast) => self.unary_lookup(ast, span),
143        }
144    }
145
146    fn postfixes(
147        &mut self,
148        primary: &ast::PrimaryExprS,
149        postfixes: &[ast::Postfix],
150    ) -> error::SpannedResult<Bindings> {
151        let primary_bindings = self.primary_expr(primary);
152        postfixes.iter().fold(primary_bindings, |acc, postfix| {
153            let mut bindings = acc?;
154            match postfix {
155                ast::Postfix::Predicate(exprs) => {
156                    let atom = bindings.atom();
157                    let context_names = self.variables.push_context();
158                    let return_bindings = self.expr(exprs)?;
159                    self.variables.pop_context();
160                    let expr = ir::Expr::Filter(ir::Filter {
161                        context_names,
162                        var_atom: atom,
163                        return_expr: Box::new(return_bindings.expr()),
164                    });
165                    // TODO should use postfix span, not exprs span
166                    let binding = self.variables.new_binding(expr, exprs.span);
167                    Ok(bindings.bind(binding))
168                }
169                ast::Postfix::ArgumentList(exprs) => {
170                    let atom = bindings.atom();
171                    let (arg_bindings, atoms) = self.args(exprs)?;
172                    let expr = ir::Expr::FunctionCall(ir::FunctionCall { atom, args: atoms });
173                    // TODO should be able to get span for postfix
174                    let empty_span = (0..0).into();
175                    let binding = self.variables.new_binding(expr, empty_span);
176                    Ok(bindings.concat(arg_bindings).bind(binding))
177                }
178                ast::Postfix::Lookup(key_specifier) => {
179                    self.postfix_lookup(key_specifier, &mut bindings)
180                }
181            }
182        })
183    }
184
185    fn postfix_lookup(
186        &mut self,
187        key_specifier: &ast::KeySpecifier,
188        bindings: &mut Bindings,
189    ) -> error::SpannedResult<Bindings> {
190        let span = (0..0).into();
191
192        // the thing we loop over is bound
193        let var_atom = bindings.atom();
194
195        // make up an internal name for the loop variable
196        let name = self.variables.new_name();
197        // access the loop variable
198        let mut bindings = bindings.bind(Binding::new(
199            name.clone(),
200            ir::Expr::Atom(Spanned::new(ir::Atom::Variable(name.clone()), span)),
201            span,
202        ));
203
204        let atom = bindings.atom();
205
206        let return_bindings = match key_specifier {
207            ast::KeySpecifier::NcName(ncname) => {
208                let arg_atom =
209                    Spanned::new(ir::Atom::Const(ir::Const::String(ncname.clone())), span);
210                let arg_bindings = self.atom(arg_atom, span);
211                let mut bindings = bindings.concat(arg_bindings);
212                let arg_atom = bindings.atom();
213                let expr = ir::Expr::Lookup(ir::Lookup { atom, arg_atom });
214                let binding = self.variables.new_binding(expr, span);
215                bindings.bind(binding)
216            }
217            ast::KeySpecifier::Integer(integer) => {
218                let arg_atom =
219                    Spanned::new(ir::Atom::Const(ir::Const::Integer(integer.clone())), span);
220                let arg_bindings = self.atom(arg_atom, span);
221                let mut bindings = bindings.concat(arg_bindings);
222                let arg_atom = bindings.atom();
223                let expr = ir::Expr::Lookup(ir::Lookup { atom, arg_atom });
224                let binding = self.variables.new_binding(expr, span);
225                bindings.bind(binding)
226            }
227            ast::KeySpecifier::Expr(expr) => {
228                let arg_bindings = self.expr_or_empty(expr)?;
229                let mut bindings = bindings.concat(arg_bindings);
230                let arg_atom = bindings.atom();
231                let expr = ir::Expr::Lookup(ir::Lookup { atom, arg_atom });
232                let binding = self.variables.new_binding(expr, span);
233                bindings.bind(binding)
234            }
235            ast::KeySpecifier::Star => {
236                let expr = ir::Expr::WildcardLookup(ir::WildcardLookup { atom });
237                let binding = self.variables.new_binding(expr, span);
238                bindings.bind(binding)
239            }
240        };
241        // we wrap the whole thing in a map
242        let context_names = self.variables.explicit_context_names(name);
243        let expr = ir::Expr::Map(ir::Map {
244            context_names,
245            var_atom,
246            return_expr: Box::new(return_bindings.expr()),
247        });
248        let binding = self.variables.new_binding(expr, span);
249        Ok(bindings.bind(binding))
250    }
251
252    fn axis_step(&mut self, ast: &ast::AxisStep, span: Span) -> error::SpannedResult<Bindings> {
253        // get the current context
254        let mut current_context_bindings = self.variables.context_item(span)?;
255
256        if matches!(ast.axis, ast::Axis::Namespace) {
257            return Err(Error::XPST0010.with_ast_span(span));
258        }
259
260        let step = xml::Step {
261            axis: ast.axis.clone(),
262            node_test: ast.node_test.clone(),
263        };
264
265        // given the current context item, apply the step
266        let expr = ir::Expr::Step(ir::Step {
267            step,
268            context: current_context_bindings.atom(),
269        });
270
271        // create a new binding for the step
272        let binding = self.variables.new_binding(expr, span);
273
274        let bindings = Ok(Bindings::new(binding));
275
276        // now apply predicates
277        ast.predicates.iter().fold(bindings, |acc, predicate| {
278            let mut bindings = acc?;
279            let atom = bindings.atom();
280            let context_names = self.variables.push_context();
281            let return_bindings = self.expr(predicate)?;
282            self.variables.pop_context();
283            let expr = ir::Expr::Filter(ir::Filter {
284                context_names,
285                var_atom: atom,
286                return_expr: Box::new(return_bindings.expr()),
287            });
288            let binding = self.variables.new_binding(expr, predicate.span);
289            Ok(bindings.bind(binding))
290        })
291    }
292
293    fn literal(&mut self, ast: &ast::Literal, span: Span) -> error::SpannedResult<Bindings> {
294        let atom = match ast {
295            ast::Literal::Integer(i) => ir::Atom::Const(ir::Const::Integer(i.clone())),
296            ast::Literal::String(s) => ir::Atom::Const(ir::Const::String(s.clone())),
297            ast::Literal::Double(d) => ir::Atom::Const(ir::Const::Double(*d)),
298            ast::Literal::Decimal(d) => ir::Atom::Const(ir::Const::Decimal(*d)),
299        };
300        let expr = ir::Expr::Atom(Spanned::new(atom, span));
301        let binding = self.variables.new_binding(expr, span);
302        Ok(Bindings::new(binding))
303    }
304
305    pub fn expr(&mut self, expr: &ast::ExprS) -> error::SpannedResult<Bindings> {
306        self.expr_with_span(&expr.value, expr.span)
307    }
308
309    fn expr_with_span(&mut self, expr: &ast::Expr, span: Span) -> error::SpannedResult<Bindings> {
310        let expr = &expr.0;
311
312        // XXX could this be reduce?
313        let first_expr = &expr[0];
314        let span_start = span.start;
315        let rest_exprs = &expr[1..];
316        rest_exprs
317            .iter()
318            .fold(self.expr_single(first_expr), |acc, expr_single| {
319                let mut left_bindings = acc?;
320                let mut right_bindings = self.expr_single(expr_single)?;
321                let expr = ir::Expr::Binary(ir::Binary {
322                    left: left_bindings.atom(),
323                    op: ir::BinaryOperator::Comma,
324                    right: right_bindings.atom(),
325                });
326                let span_end = expr_single.span.end;
327                let span = (span_start..span_end).into();
328                let binding = self.variables.new_binding(expr, span);
329                Ok(left_bindings.concat(right_bindings).bind(binding))
330            })
331    }
332
333    fn expr_or_empty(&mut self, expr: &ast::ExprOrEmptyS) -> error::SpannedResult<Bindings> {
334        let span = expr.span;
335        if let Some(expr) = &expr.value {
336            self.expr_with_span(expr, span)
337        } else {
338            let expr = ir::Expr::Atom(Spanned::new(
339                ir::Atom::Const(ir::Const::EmptySequence),
340                span,
341            ));
342            let binding = self.variables.new_binding(expr, span);
343            Ok(Bindings::new(binding))
344        }
345    }
346
347    fn binary_expr(&mut self, ast: &ast::BinaryExpr, span: Span) -> error::SpannedResult<Bindings> {
348        let mut left_bindings = self.path_expr(&ast.left)?;
349        let mut right_bindings = self.path_expr(&ast.right)?;
350        let op = self.binary_op(ast.operator);
351        let expr = ir::Expr::Binary(ir::Binary {
352            left: left_bindings.atom(),
353            op,
354            right: right_bindings.atom(),
355        });
356        let binding = self.variables.new_binding(expr, span);
357
358        Ok(left_bindings.concat(right_bindings).bind(binding))
359    }
360
361    fn binary_op(&mut self, operator: ast::BinaryOperator) -> ir::BinaryOperator {
362        operator
363    }
364
365    fn apply_expr(&mut self, ast: &ast::ApplyExpr, span: Span) -> error::SpannedResult<Bindings> {
366        match &ast.operator {
367            ast::ApplyOperator::SimpleMap(path_exprs) => {
368                let path_bindings = self.path_expr(&ast.path_expr);
369                path_exprs.iter().fold(path_bindings, |acc, path_expr| {
370                    let mut path_bindings = acc?;
371                    let path_atom = path_bindings.atom();
372                    let context_names = self.variables.push_context();
373                    let return_bindings = self.path_expr(path_expr)?;
374                    self.variables.pop_context();
375                    let expr = ir::Expr::Map(ir::Map {
376                        context_names,
377                        var_atom: path_atom,
378                        return_expr: Box::new(return_bindings.expr()),
379                    });
380                    let binding = self.variables.new_binding(expr, span);
381                    Ok(path_bindings.bind(binding))
382                })
383            }
384            ast::ApplyOperator::Unary(ops) => {
385                let bindings = self.path_expr(&ast.path_expr);
386                ops.iter().rev().fold(bindings, |acc, op| {
387                    let mut bindings = acc?;
388                    let expr = ir::Expr::Unary(ir::Unary {
389                        op: op.clone(),
390                        atom: bindings.atom(),
391                    });
392                    let binding = self.variables.new_binding(expr, span);
393                    Ok(bindings.bind(binding))
394                })
395            }
396            ast::ApplyOperator::Cast(single_type) => {
397                let xs = Xs::by_name(
398                    single_type.name.value.namespace(),
399                    single_type.name.value.local_name(),
400                );
401                if let Some(xs) = xs {
402                    if !xs.derives_from(Xs::AnySimpleType) {
403                        return Err(Error::XQST0052.with_ast_span(span));
404                    }
405                    if xs == Xs::Notation || xs == Xs::AnySimpleType || xs == Xs::AnyAtomicType {
406                        return Err(Error::XPST0080.with_ast_span(span));
407                    }
408                    let mut bindings = self.path_expr(&ast.path_expr)?;
409                    let expr = ir::Expr::Cast(ir::Cast {
410                        atom: bindings.atom(),
411                        xs,
412                        empty_sequence_allowed: single_type.optional,
413                    });
414                    let binding = self.variables.new_binding(expr, span);
415                    Ok(bindings.bind(binding))
416                } else {
417                    Err(Error::XQST0052.with_ast_span(span))
418                }
419            }
420            ast::ApplyOperator::Castable(single_type) => {
421                let xs = Xs::by_name(
422                    single_type.name.value.namespace(),
423                    single_type.name.value.local_name(),
424                );
425                if let Some(xs) = xs {
426                    if !xs.derives_from(Xs::AnySimpleType) {
427                        return Err(Error::XQST0052.with_ast_span(span));
428                    }
429                    if xs == Xs::Notation || xs == Xs::AnySimpleType || xs == Xs::AnyAtomicType {
430                        return Err(Error::XPST0080.with_ast_span(span));
431                    }
432                    let mut bindings = self.path_expr(&ast.path_expr)?;
433                    let expr = ir::Expr::Castable(ir::Castable {
434                        atom: bindings.atom(),
435                        xs,
436                        empty_sequence_allowed: single_type.optional,
437                    });
438                    let binding = self.variables.new_binding(expr, span);
439                    Ok(bindings.bind(binding))
440                } else {
441                    Err(Error::XQST0052.with_ast_span(span))
442                }
443            }
444            ast::ApplyOperator::InstanceOf(sequence_type) => {
445                let mut bindings = self.path_expr(&ast.path_expr)?;
446                let expr = ir::Expr::InstanceOf(ir::InstanceOf {
447                    atom: bindings.atom(),
448                    sequence_type: sequence_type.clone(),
449                });
450                let binding = self.variables.new_binding(expr, span);
451                Ok(bindings.bind(binding))
452            }
453            ast::ApplyOperator::Treat(sequence_type) => {
454                let mut bindings = self.path_expr(&ast.path_expr)?;
455                let expr = ir::Expr::Treat(ir::Treat {
456                    atom: bindings.atom(),
457                    sequence_type: sequence_type.clone(),
458                });
459                let binding = self.variables.new_binding(expr, span);
460                Ok(bindings.bind(binding))
461            }
462        }
463    }
464
465    fn if_expr(&mut self, ast: &ast::IfExpr, span: Span) -> error::SpannedResult<Bindings> {
466        let mut condition_bindings = self.expr(&ast.condition)?;
467        let then_bindings = self.expr_single(&ast.then)?;
468        let else_bindings = self.expr_single(&ast.else_)?;
469        let expr = ir::Expr::If(ir::If {
470            condition: condition_bindings.atom(),
471            then: Box::new(then_bindings.expr()),
472            else_: Box::new(else_bindings.expr()),
473        });
474        let binding = self.variables.new_binding(expr, span);
475        Ok(condition_bindings.bind(binding))
476    }
477
478    fn let_expr(&mut self, ast: &ast::LetExpr, span: Span) -> error::SpannedResult<Bindings> {
479        let name = self.variables.new_var_name(&ast.var_name.value);
480        let var_bindings = self.expr_single(&ast.var_expr)?;
481        let return_bindings = self.expr_single(&ast.return_expr)?;
482        let expr = ir::Expr::Let(ir::Let {
483            name,
484            var_expr: Box::new(var_bindings.expr()),
485            return_expr: Box::new(return_bindings.expr()),
486        });
487        Ok(Bindings::new(self.variables.new_binding(expr, span)))
488    }
489
490    fn for_expr(&mut self, ast: &ast::ForExpr, span: Span) -> error::SpannedResult<Bindings> {
491        let name = self.variables.new_var_name(&ast.var_name.value);
492        let mut var_bindings = self.expr_single(&ast.var_expr)?;
493        let var_atom = var_bindings.atom();
494        let context_names = self.variables.explicit_context_names(name);
495        let return_bindings = self.expr_single(&ast.return_expr)?;
496        let expr = ir::Expr::Map(ir::Map {
497            context_names,
498            var_atom,
499            return_expr: Box::new(return_bindings.expr()),
500        });
501
502        let binding = self.variables.new_binding(expr, span);
503        Ok(var_bindings.bind(binding))
504    }
505
506    fn quantified_expr(
507        &mut self,
508        ast: &ast::QuantifiedExpr,
509        span: Span,
510    ) -> error::SpannedResult<Bindings> {
511        let name = self.variables.new_var_name(&ast.var_name.value);
512        let mut var_bindings = self.expr_single(&ast.var_expr)?;
513        let var_atom = var_bindings.atom();
514
515        let context_names = self.variables.explicit_context_names(name);
516        let satisfies_bindings = self.expr_single(&ast.satisfies_expr)?;
517        let expr = ir::Expr::Quantified(ir::Quantified {
518            quantifier: self.quantifier(&ast.quantifier),
519            context_names,
520            var_atom,
521            satisifies_expr: Box::new(satisfies_bindings.expr()),
522        });
523
524        let binding = self.variables.new_binding(expr, span);
525        Ok(var_bindings.bind(binding))
526    }
527
528    fn quantifier(&mut self, quantifier: &ast::Quantifier) -> ir::Quantifier {
529        match quantifier {
530            ast::Quantifier::Some => ir::Quantifier::Some,
531            ast::Quantifier::Every => ir::Quantifier::Every,
532        }
533    }
534
535    fn inline_function(
536        &mut self,
537        inline_function: &ast::InlineFunction,
538        span: Span,
539    ) -> error::SpannedResult<Bindings> {
540        let params = inline_function
541            .params
542            .iter()
543            .map(|param| self.param(param))
544            .collect();
545        // wrapper functions (used to simulate placeholder arguments) do not
546        // have an absent context, but instead share the context of their
547        // environment. Normal inline functions wipe out the context, however.
548        if !inline_function.wrapper {
549            self.variables.push_absent_context();
550        }
551        let body_bindings = self.expr_or_empty(&inline_function.body)?;
552        if !inline_function.wrapper {
553            self.variables.pop_context();
554        }
555        let expr = ir::Expr::FunctionDefinition(ir::FunctionDefinition {
556            params,
557            return_type: inline_function.return_type.clone(),
558            body: Box::new(body_bindings.expr()),
559        });
560        let binding = self.variables.new_binding(expr, span);
561        Ok(Bindings::new(binding))
562    }
563
564    fn param(&mut self, param: &ast::Param) -> ir::Param {
565        ir::Param {
566            name: self.variables.new_var_name(&param.name),
567            type_: param.type_.clone(),
568        }
569    }
570
571    fn function_call(
572        &mut self,
573        ast: &ast::FunctionCall,
574        span: Span,
575    ) -> error::SpannedResult<Bindings> {
576        let arity = ast.arguments.len();
577        if arity > u8::MAX as usize {
578            return Err(Error::XPDY0130.with_ast_span(span));
579        }
580        // hardcoded fn:position and fn:last
581        // These should work without hardcoding them, but this is faster
582        // (until some advanced compiler optimization is implemented)
583        // unfortunately this can generate a type error instead of a 'context absent'
584        // error in some circumstances, but we can live with that for now as it's
585        // much more efficient
586        if ast.name.value == self.fn_position {
587            if arity != 0 {
588                // advice: format!("Either the function name {:?} does not exist, or you are calling it with the wrong number of arguments ({})", ast.name, arity),
589                return Err(Error::XPST0017.with_ast_span(span));
590            }
591            return self.variables.fn_position(span);
592        } else if ast.name.value == self.fn_last {
593            if arity != 0 {
594                // advice: format!("Either the function name {:?} does not exist, or you are calling it with the wrong number of arguments ({})", ast.name, arity),
595                return Err(Error::XPST0017.with_ast_span(span));
596            }
597            return self.variables.fn_last(span);
598        }
599
600        // advice: format!("Either the function name {:?} does not exist, or you are calling it with the wrong number of arguments ({})", ast.name, arity),
601        let static_function_id = self
602            .static_context
603            .function_id_by_name(&ast.name.value, arity as u8)
604            .ok_or(Error::XPST0017.with_ast_span(span))?;
605        // TODO we don't know yet how to get the proper span here
606        let empty_span = (0..0).into();
607        let mut static_function_ref_bindings =
608            self.static_function_ref(static_function_id, empty_span);
609        let atom = static_function_ref_bindings.atom();
610        let (arg_bindings, atoms) = self.args(&ast.arguments)?;
611        let expr = ir::Expr::FunctionCall(ir::FunctionCall { atom, args: atoms });
612        let binding = self.variables.new_binding(expr, span);
613        Ok(static_function_ref_bindings
614            .concat(arg_bindings)
615            .bind(binding))
616    }
617
618    fn named_function_ref(
619        &mut self,
620        ast: &ast::NamedFunctionRef,
621        span: Span,
622    ) -> error::SpannedResult<Bindings> {
623        // advice: format!("Either the function name {:?} does not exist, or you are calling it with the wrong number of arguments ({})", ast.name, ast.arity),
624        let static_function_id = self
625            .static_context
626            .function_id_by_name(&ast.name.value, ast.arity)
627            .ok_or(Error::XPST0017.with_ast_span(span))?;
628        Ok(self.static_function_ref(static_function_id, span))
629    }
630
631    fn static_function_ref(
632        &mut self,
633        static_function_id: function::StaticFunctionId,
634        span: Span,
635    ) -> Bindings {
636        let atom = ir::Atom::Const(ir::Const::StaticFunctionReference(
637            static_function_id,
638            self.variables.current_context_names(),
639        ));
640        let expr = ir::Expr::Atom(Spanned::new(atom, span));
641        let binding = self.variables.new_binding(expr, span);
642        Bindings::new(binding)
643    }
644
645    fn args(&mut self, args: &[ast::ExprSingleS]) -> error::SpannedResult<(Bindings, Vec<AtomS>)> {
646        if args.is_empty() {
647            return Ok((Bindings::empty(), vec![]));
648        }
649        let first = &args[0];
650        let rest = &args[1..];
651        let mut bindings = self.expr_single(first)?;
652        let atoms = vec![bindings.atom()];
653        rest.iter()
654            .try_fold((bindings, atoms), |(bindings, atoms), arg| {
655                let mut arg_bindings = self.expr_single(arg)?;
656                let mut atoms = atoms.clone();
657                atoms.push(arg_bindings.atom());
658                Ok((bindings.concat(arg_bindings), atoms))
659            })
660    }
661
662    fn unary_lookup(
663        &mut self,
664        ast: &ast::KeySpecifier,
665        span: Span,
666    ) -> error::SpannedResult<Bindings> {
667        let mut bindings = self.variables.context_item(span)?;
668        let context_atom = bindings.atom();
669
670        match ast {
671            ast::KeySpecifier::NcName(ncname) => {
672                let arg_atom =
673                    Spanned::new(ir::Atom::Const(ir::Const::String(ncname.clone())), span);
674                let arg_bindings = self.atom(arg_atom, span);
675                let mut bindings = bindings.concat(arg_bindings);
676                let arg_atom = bindings.atom();
677                let expr = ir::Expr::Lookup(ir::Lookup {
678                    atom: context_atom,
679                    arg_atom,
680                });
681                let binding = self.variables.new_binding(expr, span);
682                Ok(bindings.bind(binding))
683            }
684            ast::KeySpecifier::Integer(i) => {
685                let arg_atom = Spanned::new(ir::Atom::Const(ir::Const::Integer(i.clone())), span);
686                let arg_bindings = self.atom(arg_atom, span);
687                let mut bindings = bindings.concat(arg_bindings);
688                let arg_atom = bindings.atom();
689                let expr = ir::Expr::Lookup(ir::Lookup {
690                    atom: context_atom,
691                    arg_atom,
692                });
693                let binding = self.variables.new_binding(expr, span);
694                Ok(bindings.bind(binding))
695            }
696            ast::KeySpecifier::Expr(expr) => {
697                let arg_bindings = self.expr_or_empty(expr)?;
698                let mut bindings = bindings.concat(arg_bindings);
699                let arg_atom = bindings.atom();
700                let expr = ir::Expr::Lookup(ir::Lookup {
701                    atom: context_atom,
702                    arg_atom,
703                });
704                let binding = self.variables.new_binding(expr, span);
705                Ok(bindings.bind(binding))
706            }
707            ast::KeySpecifier::Star => {
708                let mut bindings = self.variables.context_item(span)?;
709                let context_atom = bindings.atom();
710                let expr = ir::Expr::WildcardLookup(ir::WildcardLookup { atom: context_atom });
711                let binding = self.variables.new_binding(expr, span);
712                Ok(bindings.bind(binding))
713            }
714        }
715    }
716
717    fn atom(&mut self, atom: AtomS, span: Span) -> Bindings {
718        let expr = ir::Expr::Atom(atom);
719        let binding = self.variables.new_binding(expr, span);
720        Bindings::new(binding)
721    }
722
723    fn map_constructor(
724        &mut self,
725        ast: &ast::MapConstructor,
726        span: Span,
727    ) -> error::SpannedResult<Bindings> {
728        let keys = ast
729            .entries
730            .iter()
731            .map(|entry| entry.key.clone())
732            .collect::<Vec<_>>();
733        let values = ast
734            .entries
735            .iter()
736            .map(|entry| entry.value.clone())
737            .collect::<Vec<_>>();
738        let (key_bindings, key_atoms) = self.args(&keys)?;
739        let (value_bindings, value_atoms) = self.args(&values)?;
740        let members = key_atoms.into_iter().zip(value_atoms).collect::<Vec<_>>();
741        let expr = ir::Expr::MapConstructor(ir::MapConstructor { members });
742        let expr_binding = self.variables.new_binding(expr, span);
743        let bindings = key_bindings.concat(value_bindings).bind(expr_binding);
744        Ok(bindings)
745    }
746
747    fn array_constructor(
748        &mut self,
749        ast: &ast::ArrayConstructor,
750        span: Span,
751    ) -> error::SpannedResult<Bindings> {
752        match ast {
753            ast::ArrayConstructor::Square(expr) => {
754                let (bindings, atoms) = self.args(&expr.value.0)?;
755                let expr = ir::Expr::ArrayConstructor(ir::ArrayConstructor::Square(atoms));
756                let binding = self.variables.new_binding(expr, span);
757                Ok(bindings.bind(binding))
758            }
759            ast::ArrayConstructor::Curly(expr_or_empty) => {
760                let mut bindings = self.expr_or_empty(expr_or_empty)?;
761                let expr = ir::Expr::ArrayConstructor(ir::ArrayConstructor::Curly(bindings.atom()));
762                let binding = self.variables.new_binding(expr, span);
763                Ok(bindings.bind(binding))
764            }
765        }
766    }
767}
768
769#[cfg(test)]
770mod tests {
771    use super::*;
772    use insta::assert_debug_snapshot;
773
774    fn convert_expr_single(s: &str) -> error::SpannedResult<ir::ExprS> {
775        let ast = ast::ExprSingle::parse(s)?;
776        let static_context = context::StaticContext::default();
777        let mut variables = Variables::new();
778        let mut converter = IrConverter::new(&mut variables, &static_context);
779        converter.convert_expr_single(&ast)
780    }
781
782    pub(crate) fn convert_xpath(s: &str) -> error::SpannedResult<ir::ExprS> {
783        let static_context = context::StaticContext::default();
784        let ast = static_context.parse_xpath(s)?;
785        let mut variables = Variables::new();
786        let mut converter = IrConverter::new(&mut variables, &static_context);
787        converter.convert_xpath(&ast)
788    }
789
790    #[test]
791    fn test_integer() {
792        assert_debug_snapshot!(convert_expr_single("1"));
793    }
794
795    #[test]
796    fn test_add() {
797        assert_debug_snapshot!(convert_expr_single("1 + 2"));
798    }
799
800    #[test]
801    fn test_add2() {
802        assert_debug_snapshot!(convert_expr_single("1 + 2 + 3"));
803    }
804
805    #[test]
806    fn test_if() {
807        assert_debug_snapshot!(convert_expr_single("if (1 gt 2) then 1 + 2 else 3 + 4"));
808    }
809
810    #[test]
811    fn test_comma() {
812        assert_debug_snapshot!(convert_xpath("1, 2"));
813    }
814
815    #[test]
816    fn test_comma2() {
817        assert_debug_snapshot!(convert_xpath("1, 2, 3"));
818    }
819
820    #[test]
821    fn test_empty_sequence() {
822        assert_debug_snapshot!(convert_xpath("()"));
823    }
824
825    #[test]
826    fn test_let_expr() {
827        assert_debug_snapshot!(convert_expr_single("let $x := 1 return 2"));
828    }
829
830    #[test]
831    fn test_let_expr_variable() {
832        assert_debug_snapshot!(convert_expr_single("let $x := 1 return $x"));
833    }
834
835    #[test]
836    fn test_let_expr_with_add() {
837        assert_debug_snapshot!(convert_expr_single("let $x := (1 + 2) return $x"));
838    }
839
840    #[test]
841    fn test_for_expr() {
842        assert_debug_snapshot!(convert_expr_single("for $x in 1 return 2"));
843    }
844
845    #[test]
846    fn test_for_expr2() {
847        assert_debug_snapshot!(convert_expr_single("for $x in (1, 2) return $x + 1"));
848    }
849
850    #[test]
851    fn test_simple_map() {
852        assert_debug_snapshot!(convert_expr_single("(1, 2) ! 1"));
853    }
854
855    #[test]
856    fn test_simple_map_with_context() {
857        assert_debug_snapshot!(convert_expr_single("(1, 2) ! (. + 1)"));
858    }
859
860    #[test]
861    fn test_nested_simple_map_with_context() {
862        assert_debug_snapshot!(convert_expr_single("(1, 2) ! (. + 1) ! (. + 2)"));
863    }
864
865    #[test]
866    fn test_quantified() {
867        assert_debug_snapshot!(convert_expr_single("some $x in (1, 2) satisfies $x gt 1"));
868    }
869
870    #[test]
871    fn test_postfix_filter() {
872        assert_debug_snapshot!(convert_expr_single("(1, 2)[. gt 2]"));
873    }
874
875    #[test]
876    fn test_postfix_filter_nested() {
877        assert_debug_snapshot!(convert_expr_single("(1, 2)[. gt 2][. lt 3]"));
878    }
879
880    #[test]
881    fn test_postfix_index() {
882        assert_debug_snapshot!(convert_expr_single("(1, 2)[1]"));
883    }
884
885    #[test]
886    fn test_function_definition() {
887        assert_debug_snapshot!(convert_expr_single("function($x) { $x + 1 }"));
888    }
889
890    #[test]
891    fn test_function_call() {
892        assert_debug_snapshot!(convert_expr_single("function($x) { $x + 1 }(3)"));
893    }
894
895    #[test]
896    fn test_function_call2() {
897        assert_debug_snapshot!(convert_expr_single("function($x) { $x + 1 }(3 + 5)"));
898    }
899
900    #[test]
901    fn test_static_function_call() {
902        assert_debug_snapshot!(convert_expr_single("my_function(5, 2)"));
903    }
904
905    #[test]
906    fn test_static_function_call2() {
907        assert_debug_snapshot!(convert_expr_single("my_function(1 + 2, 3 + 4)"));
908    }
909
910    #[test]
911    fn test_static_function_call3() {
912        assert_debug_snapshot!(convert_expr_single("my_function(1 + 2 + 3, 4 + 5)"));
913    }
914
915    #[test]
916    fn test_named_function_ref() {
917        assert_debug_snapshot!(convert_expr_single("my_function#2"));
918    }
919
920    #[test]
921    fn test_named_function_ref2() {
922        assert_debug_snapshot!(convert_xpath("my_function#2"));
923    }
924
925    #[test]
926    fn test_path_expr() {
927        assert_debug_snapshot!(convert_expr_single("(1, 2) / (. + 1)"));
928    }
929
930    #[test]
931    fn test_nested_path_expr() {
932        assert_debug_snapshot!(convert_expr_single("(1, 2) / (. + 1) / (. + 2)"));
933    }
934
935    #[test]
936    fn test_single_axis_step() {
937        assert_debug_snapshot!(convert_xpath("child::a"));
938    }
939
940    #[test]
941    fn test_multiple_axis_steps() {
942        assert_debug_snapshot!(convert_xpath("child::a/child::b"));
943    }
944
945    #[test]
946    fn test_axis_step_with_predicates() {
947        assert_debug_snapshot!(convert_xpath("child::a[. gt 1]"));
948    }
949
950    #[test]
951    fn test_absent_context_in_function() {
952        assert_debug_snapshot!(convert_xpath("function() { . }"));
953    }
954
955    #[test]
956    fn test_unknown_static_function_name() {
957        assert_debug_snapshot!(convert_expr_single("unknown_function()"));
958    }
959
960    #[test]
961    fn test_wrong_amount_of_arguments() {
962        assert_debug_snapshot!(convert_expr_single("fn:string(1, 2, 3)"));
963    }
964
965    #[test]
966    fn test_unknown_variable_name() {
967        assert_debug_snapshot!(convert_expr_single("$unknown"));
968    }
969
970    #[test]
971    fn test_unknown_named_function_ref() {
972        assert_debug_snapshot!(convert_expr_single("unknown_function#2"));
973    }
974
975    #[test]
976    fn test_unary() {
977        assert_debug_snapshot!(convert_expr_single("-1"));
978    }
979
980    #[test]
981    fn test_unary_plus() {
982        assert_debug_snapshot!(convert_expr_single("+1"));
983    }
984
985    #[test]
986    fn test_unary_combo() {
987        assert_debug_snapshot!(convert_expr_single("-+1"));
988    }
989
990    #[test]
991    fn test_cast() {
992        assert_debug_snapshot!(convert_expr_single("1 cast as xs:string"));
993    }
994
995    #[test]
996    fn test_cast_question_mark() {
997        assert_debug_snapshot!(convert_expr_single("1 cast as xs:string?"));
998    }
999
1000    #[test]
1001    fn test_castable() {
1002        assert_debug_snapshot!(convert_expr_single("1 castable as xs:string"));
1003    }
1004
1005    #[test]
1006    fn test_castable_question_mark() {
1007        assert_debug_snapshot!(convert_expr_single("1 castable as xs:string?"));
1008    }
1009
1010    #[test]
1011    fn test_cast_unknown_schema_type() {
1012        assert_debug_snapshot!(convert_expr_single("1 cast as unknown"));
1013    }
1014
1015    #[test]
1016    fn test_cast_non_simple_schema_type() {
1017        assert_debug_snapshot!(convert_expr_single("1 cast as xs:untyped"));
1018    }
1019
1020    #[test]
1021    fn test_cast_illegal_simple_type() {
1022        assert_debug_snapshot!(convert_expr_single("1 cast as xs:NOTATION"));
1023    }
1024
1025    #[test]
1026    fn test_instance_of_atomic() {
1027        assert_debug_snapshot!(convert_expr_single("1 instance of xs:string"));
1028    }
1029
1030    #[test]
1031    fn test_instance_of_kind_test() {
1032        assert_debug_snapshot!(convert_expr_single("1 instance of node()"));
1033    }
1034
1035    #[test]
1036    fn test_function_call_with_sequence() {
1037        assert_debug_snapshot!(
1038            convert_expr_single(
1039                "compare('a', 'b', ((), 'http://www.w3.org/2005/xpath-functions/collation/codepoint', ()))"));
1040    }
1041
1042    #[test]
1043    fn test_ncname_key_specifier() {
1044        assert_debug_snapshot!(convert_xpath("? foo"));
1045    }
1046
1047    #[test]
1048    fn test_integer_key_specifier() {
1049        assert_debug_snapshot!(convert_xpath("? 1"));
1050    }
1051
1052    #[test]
1053    fn test_postfix_lookup() {
1054        assert_debug_snapshot!(convert_xpath("1 ? foo"));
1055    }
1056}