1use std::fmt;
6
7use html5ever::{LocalName, Namespace, Prefix, QualName, local_name, namespace_prefix, ns};
8use script_bindings::script_runtime::CanGc;
9
10use super::parser::{
11 AdditiveOp, Axis, EqualityOp, Expr, FilterExpr, KindTest, Literal, MultiplicativeOp, NodeTest,
12 NumericLiteral, PathExpr, PredicateExpr, PredicateListExpr, PrimaryExpr,
13 QName as ParserQualName, RelationalOp, StepExpr, UnaryOp,
14};
15use super::{EvaluationCtx, Value};
16use crate::dom::attr::Attr;
17use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
18use crate::dom::bindings::domname::namespace_from_domstring;
19use crate::dom::bindings::error::Error as JsError;
20use crate::dom::bindings::inheritance::{Castable, CharacterDataTypeId, NodeTypeId};
21use crate::dom::bindings::root::DomRoot;
22use crate::dom::bindings::str::DOMString;
23use crate::dom::bindings::xmlname;
24use crate::dom::element::Element;
25use crate::dom::node::{Node, ShadowIncluding};
26use crate::dom::processinginstruction::ProcessingInstruction;
27use crate::xpath::context::PredicateCtx;
28
29#[derive(Clone, Debug)]
30pub(crate) enum Error {
31 NotANodeset,
32 InvalidPath,
33 UnknownFunction {
34 name: QualName,
35 },
36 CannotUseVariables,
42 UnknownNamespace {
43 prefix: String,
44 },
45 InvalidQName {
46 qname: ParserQualName,
47 },
48 FunctionEvaluation {
49 fname: String,
50 },
51 Internal {
52 msg: String,
53 },
54 JsException(JsError),
56}
57
58impl std::fmt::Display for Error {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 match self {
61 Error::NotANodeset => write!(f, "expression did not evaluate to a nodeset"),
62 Error::InvalidPath => write!(f, "invalid path expression"),
63 Error::UnknownFunction { name } => write!(f, "unknown function {:?}", name),
64 Error::CannotUseVariables => write!(f, "cannot use variables"),
65 Error::UnknownNamespace { prefix } => {
66 write!(f, "unknown namespace prefix {:?}", prefix)
67 },
68 Error::InvalidQName { qname } => {
69 write!(f, "invalid QName {:?}", qname)
70 },
71 Error::FunctionEvaluation { fname } => {
72 write!(f, "error while evaluating function: {}", fname)
73 },
74 Error::Internal { msg } => {
75 write!(f, "internal error: {}", msg)
76 },
77 Error::JsException(exception) => {
78 write!(f, "JS exception: {:?}", exception)
79 },
80 }
81 }
82}
83
84impl std::error::Error for Error {}
85
86pub(crate) fn try_extract_nodeset(v: Value) -> Result<Vec<DomRoot<Node>>, Error> {
87 match v {
88 Value::Nodeset(ns) => Ok(ns),
89 _ => Err(Error::NotANodeset),
90 }
91}
92
93pub(crate) trait Evaluatable: fmt::Debug {
94 fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error>;
95 fn is_primitive(&self) -> bool;
97}
98
99impl<T: ?Sized> Evaluatable for Box<T>
100where
101 T: Evaluatable,
102{
103 fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> {
104 (**self).evaluate(context)
105 }
106
107 fn is_primitive(&self) -> bool {
108 (**self).is_primitive()
109 }
110}
111
112impl<T> Evaluatable for Option<T>
113where
114 T: Evaluatable,
115{
116 fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> {
117 match self {
118 Some(expr) => expr.evaluate(context),
119 None => Ok(Value::Nodeset(vec![])),
120 }
121 }
122
123 fn is_primitive(&self) -> bool {
124 self.as_ref().is_some_and(|t| T::is_primitive(t))
125 }
126}
127
128impl Evaluatable for Expr {
129 fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> {
130 match self {
131 Expr::And(left, right) => {
132 let left_bool = left.evaluate(context)?.boolean();
133 let v = left_bool && right.evaluate(context)?.boolean();
134 Ok(Value::Boolean(v))
135 },
136 Expr::Or(left, right) => {
137 let left_bool = left.evaluate(context)?.boolean();
138 let v = left_bool || right.evaluate(context)?.boolean();
139 Ok(Value::Boolean(v))
140 },
141 Expr::Equality(left, equality_op, right) => {
142 let left_val = left.evaluate(context)?;
143 let right_val = right.evaluate(context)?;
144
145 let v = match equality_op {
146 EqualityOp::Eq => left_val == right_val,
147 EqualityOp::NotEq => left_val != right_val,
148 };
149
150 Ok(Value::Boolean(v))
151 },
152 Expr::Relational(left, relational_op, right) => {
153 let left_val = left.evaluate(context)?.number();
154 let right_val = right.evaluate(context)?.number();
155
156 let v = match relational_op {
157 RelationalOp::Lt => left_val < right_val,
158 RelationalOp::Gt => left_val > right_val,
159 RelationalOp::LtEq => left_val <= right_val,
160 RelationalOp::GtEq => left_val >= right_val,
161 };
162 Ok(Value::Boolean(v))
163 },
164 Expr::Additive(left, additive_op, right) => {
165 let left_val = left.evaluate(context)?.number();
166 let right_val = right.evaluate(context)?.number();
167
168 let v = match additive_op {
169 AdditiveOp::Add => left_val + right_val,
170 AdditiveOp::Sub => left_val - right_val,
171 };
172 Ok(Value::Number(v))
173 },
174 Expr::Multiplicative(left, multiplicative_op, right) => {
175 let left_val = left.evaluate(context)?.number();
176 let right_val = right.evaluate(context)?.number();
177
178 let v = match multiplicative_op {
179 MultiplicativeOp::Mul => left_val * right_val,
180 MultiplicativeOp::Div => left_val / right_val,
181 MultiplicativeOp::Mod => left_val % right_val,
182 };
183 Ok(Value::Number(v))
184 },
185 Expr::Unary(unary_op, expr) => {
186 let v = expr.evaluate(context)?.number();
187
188 match unary_op {
189 UnaryOp::Minus => Ok(Value::Number(-v)),
190 }
191 },
192 Expr::Union(left, right) => {
193 let as_nodes = |e: &Expr| e.evaluate(context).and_then(try_extract_nodeset);
194
195 let mut left_nodes = as_nodes(left)?;
196 let right_nodes = as_nodes(right)?;
197
198 left_nodes.extend(right_nodes);
199 Ok(Value::Nodeset(left_nodes))
200 },
201 Expr::Path(path_expr) => path_expr.evaluate(context),
202 }
203 }
204
205 fn is_primitive(&self) -> bool {
206 match self {
207 Expr::Or(left, right) => left.is_primitive() && right.is_primitive(),
208 Expr::And(left, right) => left.is_primitive() && right.is_primitive(),
209 Expr::Equality(left, _, right) => left.is_primitive() && right.is_primitive(),
210 Expr::Relational(left, _, right) => left.is_primitive() && right.is_primitive(),
211 Expr::Additive(left, _, right) => left.is_primitive() && right.is_primitive(),
212 Expr::Multiplicative(left, _, right) => left.is_primitive() && right.is_primitive(),
213 Expr::Unary(_, expr) => expr.is_primitive(),
214 Expr::Union(_, _) => false,
215 Expr::Path(path_expr) => path_expr.is_primitive(),
216 }
217 }
218}
219
220impl Evaluatable for PathExpr {
221 fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> {
222 let mut current_nodes = if self.is_absolute || self.is_descendant {
224 vec![context.starting_node.clone()]
225 } else {
226 vec![context.context_node.clone()]
227 };
228
229 if self.is_descendant {
231 current_nodes = current_nodes
232 .iter()
233 .flat_map(|n| n.traverse_preorder(ShadowIncluding::No))
234 .collect();
235 }
236
237 trace!("[PathExpr] Evaluating path expr: {:?}", self);
238
239 let have_multiple_steps = self.steps.len() > 1;
240
241 for step in &self.steps {
242 let mut next_nodes = Vec::new();
243 for node in current_nodes {
244 let step_context = context.subcontext_for_node(&node);
245 let step_result = step.evaluate(&step_context)?;
246 match (have_multiple_steps, step_result) {
247 (_, Value::Nodeset(mut nodes)) => {
248 next_nodes.append(&mut nodes);
250 },
251 (false, value) => {
252 trace!("[PathExpr] Got single primitive value: {:?}", value);
253 return Ok(value);
254 },
255 (true, value) => {
256 error!(
257 "Expected nodeset from step evaluation, got: {:?} node: {:?}, step: {:?}",
258 value, node, step
259 );
260 return Ok(value);
261 },
262 }
263 }
264 current_nodes = next_nodes;
265 }
266
267 trace!("[PathExpr] Got nodes: {:?}", current_nodes);
268
269 Ok(Value::Nodeset(current_nodes))
270 }
271
272 fn is_primitive(&self) -> bool {
273 !self.is_absolute &&
274 !self.is_descendant &&
275 self.steps.len() == 1 &&
276 self.steps[0].is_primitive()
277 }
278}
279
280#[derive(Debug)]
283enum ValidationError {
284 InvalidCharacter,
285 Namespace,
286}
287
288fn validate_and_extract_qualified_name(
292 qualified_name: &str,
293) -> Result<(Option<&str>, &str), ValidationError> {
294 if qualified_name.is_empty() {
295 return Err(ValidationError::InvalidCharacter);
297 }
298 let mut colon_offset = None;
299 let mut at_start_of_name = true;
300
301 for (byte_position, c) in qualified_name.char_indices() {
302 if c == ':' {
303 if colon_offset.is_some() {
304 return Err(ValidationError::InvalidCharacter);
306 }
307 colon_offset = Some(byte_position);
308 at_start_of_name = true;
309 continue;
310 }
311
312 if at_start_of_name {
313 if !xmlname::is_valid_start(c) {
314 return Err(ValidationError::InvalidCharacter);
316 }
317 at_start_of_name = false;
318 } else if !xmlname::is_valid_continuation(c) {
319 return Err(ValidationError::InvalidCharacter);
321 }
322 }
323
324 let Some(colon_offset) = colon_offset else {
325 return Ok((None, qualified_name));
327 };
328
329 let (prefix, local_name) = qualified_name.split_at(colon_offset);
330 let local_name = &local_name[1..]; if prefix.is_empty() || local_name.is_empty() {
333 return Err(ValidationError::InvalidCharacter);
335 }
336
337 Ok((Some(prefix), local_name))
338}
339
340fn validate_and_extract(
343 namespace: Option<DOMString>,
344 qualified_name: &str,
345) -> Result<(Namespace, Option<Prefix>, LocalName), ValidationError> {
346 let namespace = namespace_from_domstring(namespace);
348
349 let (prefix, local_name) = validate_and_extract_qualified_name(qualified_name)?;
356 debug_assert!(!local_name.contains(':'));
357
358 match (namespace, prefix) {
359 (ns!(), Some(_)) => {
360 Err(ValidationError::Namespace)
362 },
363 (ref ns, Some("xml")) if ns != &ns!(xml) => {
364 Err(ValidationError::Namespace)
367 },
368 (ref ns, p) if ns != &ns!(xmlns) && (qualified_name == "xmlns" || p == Some("xmlns")) => {
369 Err(ValidationError::Namespace)
372 },
373 (ns!(xmlns), p) if qualified_name != "xmlns" && p != Some("xmlns") => {
374 Err(ValidationError::Namespace)
377 },
378 (ns, p) => {
379 Ok((ns, p.map(Prefix::from), LocalName::from(local_name)))
381 },
382 }
383}
384
385pub(crate) fn convert_parsed_qname_to_qualified_name(
386 qname: &ParserQualName,
387 context: &EvaluationCtx,
388 can_gc: CanGc,
389) -> Result<QualName, Error> {
390 let qname_as_str = qname.to_string();
391 let namespace = context
392 .resolve_namespace(qname.prefix.as_deref(), can_gc)
393 .map_err(Error::JsException)?;
394
395 if let Ok((ns, prefix, local)) = validate_and_extract(namespace, &qname_as_str) {
396 Ok(QualName { prefix, ns, local })
397 } else {
398 Err(Error::InvalidQName {
399 qname: qname.clone(),
400 })
401 }
402}
403
404#[derive(Debug)]
405pub(crate) enum NameTestComparisonMode {
406 XHtml,
408 Html,
410}
411
412pub(crate) fn element_name_test(
413 expected_name: QualName,
414 element_qualname: QualName,
415 comparison_mode: NameTestComparisonMode,
416) -> bool {
417 let is_wildcard = expected_name.local == local_name!("*");
418
419 let test_prefix = expected_name
420 .prefix
421 .clone()
422 .unwrap_or(namespace_prefix!(""));
423 let test_ns_uri = match test_prefix {
424 namespace_prefix!("*") => ns!(*),
425 namespace_prefix!("html") => ns!(html),
426 namespace_prefix!("xml") => ns!(xml),
427 namespace_prefix!("xlink") => ns!(xlink),
428 namespace_prefix!("svg") => ns!(svg),
429 namespace_prefix!("mathml") => ns!(mathml),
430 namespace_prefix!("") => {
431 if matches!(comparison_mode, NameTestComparisonMode::XHtml) {
432 ns!()
433 } else {
434 ns!(html)
435 }
436 },
437 _ => {
438 if matches!(comparison_mode, NameTestComparisonMode::XHtml) {
440 panic!("Unrecognized namespace prefix: {}", test_prefix)
441 } else {
442 ns!(html)
443 }
444 },
445 };
446
447 if is_wildcard {
448 test_ns_uri == element_qualname.ns
449 } else {
450 test_ns_uri == element_qualname.ns && expected_name.local == element_qualname.local
451 }
452}
453
454fn apply_node_test(
455 context: &EvaluationCtx,
456 test: &NodeTest,
457 node: &Node,
458 can_gc: CanGc,
459) -> Result<bool, Error> {
460 let result = match test {
461 NodeTest::Name(qname) => {
462 let wanted_name = convert_parsed_qname_to_qualified_name(qname, context, can_gc)?;
464 match node.type_id() {
465 NodeTypeId::Element(_) => {
466 let element = node.downcast::<Element>().unwrap();
467 let comparison_mode = if node.owner_doc().is_html_document() {
468 NameTestComparisonMode::Html
469 } else {
470 NameTestComparisonMode::XHtml
471 };
472 let element_qualname = QualName::new(
473 element.prefix().as_ref().cloned(),
474 element.namespace().clone(),
475 element.local_name().clone(),
476 );
477 element_name_test(wanted_name, element_qualname, comparison_mode)
478 },
479 NodeTypeId::Attr => {
480 let attr = node.downcast::<Attr>().unwrap();
481 let attr_qualname = QualName::new(
482 attr.prefix().cloned(),
483 attr.namespace().clone(),
484 attr.local_name().clone(),
485 );
486 let comparison_mode = NameTestComparisonMode::XHtml;
488 element_name_test(wanted_name, attr_qualname, comparison_mode)
489 },
490 _ => false,
491 }
492 },
493 NodeTest::Wildcard => matches!(node.type_id(), NodeTypeId::Element(_)),
494 NodeTest::Kind(kind) => match kind {
495 KindTest::PI(target) => {
496 if NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) ==
497 node.type_id()
498 {
499 let pi = node.downcast::<ProcessingInstruction>().unwrap();
500 match (target, pi.target()) {
501 (Some(target_name), node_target_name)
502 if target_name == &node_target_name.to_string() =>
503 {
504 true
505 },
506 (Some(_), _) => false,
507 (None, _) => true,
508 }
509 } else {
510 false
511 }
512 },
513 KindTest::Comment => matches!(
514 node.type_id(),
515 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
516 ),
517 KindTest::Text => matches!(
518 node.type_id(),
519 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_))
520 ),
521 KindTest::Node => true,
522 },
523 };
524 Ok(result)
525}
526
527impl Evaluatable for StepExpr {
528 fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> {
529 match self {
530 StepExpr::Filter(filter_expr) => filter_expr.evaluate(context),
531 StepExpr::Axis(axis_step) => {
532 let nodes: Vec<DomRoot<Node>> = match axis_step.axis {
533 Axis::Child => context.context_node.children().collect(),
534 Axis::Descendant => context
535 .context_node
536 .traverse_preorder(ShadowIncluding::No)
537 .skip(1)
538 .collect(),
539 Axis::Parent => vec![context.context_node.GetParentNode()]
540 .into_iter()
541 .flatten()
542 .collect(),
543 Axis::Ancestor => context.context_node.ancestors().collect(),
544 Axis::Following => context
545 .context_node
546 .following_nodes(&context.context_node)
547 .skip(1)
548 .collect(),
549 Axis::Preceding => context
550 .context_node
551 .preceding_nodes(&context.context_node)
552 .skip(1)
553 .collect(),
554 Axis::FollowingSibling => context.context_node.following_siblings().collect(),
555 Axis::PrecedingSibling => context.context_node.preceding_siblings().collect(),
556 Axis::Attribute => {
557 if matches!(Node::type_id(&context.context_node), NodeTypeId::Element(_)) {
558 let element = context.context_node.downcast::<Element>().unwrap();
559 element
560 .attrs()
561 .iter()
562 .map(|attr| attr.upcast::<Node>())
563 .map(DomRoot::from_ref)
564 .collect()
565 } else {
566 vec![]
567 }
568 },
569 Axis::Self_ => vec![context.context_node.clone()],
570 Axis::DescendantOrSelf => context
571 .context_node
572 .traverse_preorder(ShadowIncluding::No)
573 .collect(),
574 Axis::AncestorOrSelf => context
575 .context_node
576 .inclusive_ancestors(ShadowIncluding::No)
577 .collect(),
578 Axis::Namespace => Vec::new(), };
580
581 trace!("[StepExpr] Axis {:?} got nodes {:?}", axis_step.axis, nodes);
582
583 let filtered_nodes: Vec<DomRoot<Node>> = nodes
586 .into_iter()
587 .map(|node| {
588 apply_node_test(context, &axis_step.node_test, &node, CanGc::note())
591 .map(|matches| matches.then_some(node))
592 })
593 .collect::<Result<Vec<_>, _>>()?
594 .into_iter()
595 .flatten()
596 .collect();
597
598 trace!("[StepExpr] Filtering got nodes {:?}", filtered_nodes);
599
600 if axis_step.predicates.predicates.is_empty() {
601 trace!(
602 "[StepExpr] No predicates, returning nodes {:?}",
603 filtered_nodes
604 );
605 Ok(Value::Nodeset(filtered_nodes))
606 } else {
607 let predicate_list_subcontext = context
609 .update_predicate_nodes(filtered_nodes.iter().map(|n| &**n).collect());
610 axis_step.predicates.evaluate(&predicate_list_subcontext)
611 }
612 },
613 }
614 }
615
616 fn is_primitive(&self) -> bool {
617 match self {
618 StepExpr::Filter(filter_expr) => filter_expr.is_primitive(),
619 StepExpr::Axis(_) => false,
620 }
621 }
622}
623
624impl Evaluatable for PredicateListExpr {
625 fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> {
626 if let Some(ref predicate_nodes) = context.predicate_nodes {
627 let mut matched_nodes: Vec<DomRoot<Node>> = predicate_nodes.clone();
628
629 for predicate_expr in &self.predicates {
630 let size = matched_nodes.len();
631 let mut new_matched = Vec::new();
632
633 for (i, node) in matched_nodes.iter().enumerate() {
634 let predicate_ctx = EvaluationCtx {
636 starting_node: context.starting_node.clone(),
637 context_node: node.clone(),
638 predicate_nodes: context.predicate_nodes.clone(),
639 predicate_ctx: Some(PredicateCtx { index: i + 1, size }),
640 resolver: context.resolver.clone(),
641 };
642
643 let eval_result = predicate_expr.expr.evaluate(&predicate_ctx);
644
645 let keep = match eval_result {
646 Ok(Value::Number(n)) => (i + 1) as f64 == n,
647 Ok(Value::Boolean(b)) => b,
648 Ok(v) => v.boolean(),
649 Err(_) => false,
650 };
651
652 if keep {
653 new_matched.push(node.clone());
654 }
655 }
656
657 matched_nodes = new_matched;
658 trace!(
659 "[PredicateListExpr] Predicate {:?} matched nodes {:?}",
660 predicate_expr, matched_nodes
661 );
662 }
663 Ok(Value::Nodeset(matched_nodes))
664 } else {
665 Err(Error::Internal {
666 msg: "[PredicateListExpr] No nodes on stack for predicate to operate on"
667 .to_string(),
668 })
669 }
670 }
671
672 fn is_primitive(&self) -> bool {
673 self.predicates.len() == 1 && self.predicates[0].is_primitive()
674 }
675}
676
677impl Evaluatable for PredicateExpr {
678 fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> {
679 let narrowed_nodes: Result<Vec<DomRoot<Node>>, Error> = context
680 .subcontext_iter_for_nodes()
681 .filter_map(|ctx| {
682 if let Some(predicate_ctx) = ctx.predicate_ctx {
683 let eval_result = self.expr.evaluate(&ctx);
684
685 let v = match eval_result {
686 Ok(Value::Number(v)) => Ok(predicate_ctx.index == v as usize),
687 Ok(Value::Boolean(v)) => Ok(v),
688 Ok(v) => Ok(v.boolean()),
689 Err(e) => Err(e),
690 };
691
692 match v {
693 Ok(true) => Some(Ok(ctx.context_node)),
694 Ok(false) => None,
695 Err(e) => Some(Err(e)),
696 }
697 } else {
698 Some(Err(Error::Internal {
699 msg: "[PredicateExpr] No predicate context set".to_string(),
700 }))
701 }
702 })
703 .collect();
704
705 Ok(Value::Nodeset(narrowed_nodes?))
706 }
707
708 fn is_primitive(&self) -> bool {
709 self.expr.is_primitive()
710 }
711}
712
713impl Evaluatable for FilterExpr {
714 fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> {
715 let primary_result = self.primary.evaluate(context)?;
716 let have_predicates = !self.predicates.predicates.is_empty();
717
718 match (have_predicates, &primary_result) {
719 (false, _) => {
720 trace!(
721 "[FilterExpr] No predicates, returning primary result: {:?}",
722 primary_result
723 );
724 Ok(primary_result)
725 },
726 (true, Value::Nodeset(vec)) => {
727 let predicate_list_subcontext =
728 context.update_predicate_nodes(vec.iter().map(|n| &**n).collect());
729 let result_filtered_by_predicates =
730 self.predicates.evaluate(&predicate_list_subcontext);
731 trace!(
732 "[FilterExpr] Result filtered by predicates: {:?}",
733 result_filtered_by_predicates
734 );
735 result_filtered_by_predicates
736 },
737 (true, _) => Err(Error::NotANodeset),
739 }
740 }
741
742 fn is_primitive(&self) -> bool {
743 self.predicates.predicates.is_empty() && self.primary.is_primitive()
744 }
745}
746
747impl Evaluatable for PrimaryExpr {
748 fn evaluate(&self, context: &EvaluationCtx) -> Result<Value, Error> {
749 match self {
750 PrimaryExpr::Literal(literal) => literal.evaluate(context),
751 PrimaryExpr::Variable(_qname) => Err(Error::CannotUseVariables),
752 PrimaryExpr::Parenthesized(expr) => expr.evaluate(context),
753 PrimaryExpr::ContextItem => Ok(Value::Nodeset(vec![context.context_node.clone()])),
754 PrimaryExpr::Function(core_function) => core_function.evaluate(context),
755 }
756 }
757
758 fn is_primitive(&self) -> bool {
759 match self {
760 PrimaryExpr::Literal(_) => true,
761 PrimaryExpr::Variable(_qname) => false,
762 PrimaryExpr::Parenthesized(expr) => expr.is_primitive(),
763 PrimaryExpr::ContextItem => false,
764 PrimaryExpr::Function(_) => false,
765 }
766 }
767}
768
769impl Evaluatable for Literal {
770 fn evaluate(&self, _context: &EvaluationCtx) -> Result<Value, Error> {
771 match self {
772 Literal::Numeric(numeric_literal) => match numeric_literal {
773 NumericLiteral::Integer(v) => Ok(Value::Number(*v as f64)),
775 NumericLiteral::Decimal(v) => Ok(Value::Number(*v)),
776 },
777 Literal::String(s) => Ok(Value::String(s.into())),
778 }
779 }
780
781 fn is_primitive(&self) -> bool {
782 true
783 }
784}