1use crate::data::core::ExpressionParseException;
5use crate::utilities::character_reader::CharacterReader;
6use crate::utilities::span_helpers::{try_parse_int, NumberStyles};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub enum SourceMode {
11 Data,
12 Control,
13}
14
15#[derive(Clone, Debug, PartialEq)]
17pub enum Node {
18 EmptyExpression,
20 PropertyName {
22 accepts_null: bool,
23 property_name: String,
24 },
25 AttachedPropertyName {
27 accepts_null: bool,
28 namespace: String,
29 type_name: String,
30 property_name: String,
31 },
32 Indexer { arguments: Vec<String> },
34 Not,
36 Stream,
38 SelfNode,
40 Name { name: String },
42 Ancestor {
44 namespace: Option<String>,
45 type_name: Option<String>,
46 level: i32,
47 },
48 TypeCast { namespace: String, type_name: String },
50}
51
52impl Node {
53 pub fn is_transform_node(&self) -> bool {
56 matches!(self, Node::Not)
57 }
58}
59
60pub struct BindingExpressionGrammar;
62
63impl BindingExpressionGrammar {
64 pub fn parse(text: &str) -> Result<(Vec<Node>, SourceMode), ExpressionParseException> {
66 let mut r = CharacterReader::new(text);
67 Self::parse_reader(&mut r)
68 }
69
70 pub fn parse_reader(
72 r: &mut CharacterReader<'_>,
73 ) -> Result<(Vec<Node>, SourceMode), ExpressionParseException> {
74 let mut result = Vec::new();
75 let mode = parse(r, &mut result)?;
76 Ok((result, mode))
77 }
78}
79
80type ParseResult<T> = Result<T, ExpressionParseException>;
81
82#[derive(Clone, Copy, Debug, PartialEq, Eq)]
83enum State {
84 Start,
85 RelativeSource,
86 ElementName,
87 AfterMember,
88 BeforeMember,
89 BeforeMemberNullable,
90 AttachedProperty,
91 AttachedPropertyNullable,
92 Indexer,
93 TypeCast,
94 End,
95}
96
97struct TypeName<'a> {
98 namespace: &'a str,
99 type_name: &'a str,
100}
101
102fn parse(r: &mut CharacterReader<'_>, nodes: &mut Vec<Node>) -> ParseResult<SourceMode> {
103 let mut state = State::Start;
104 let mut mode = SourceMode::Data;
105
106 while !r.end() && state != State::End {
107 match state {
108 State::Start => state = parse_start(r, nodes),
109 State::AfterMember => state = parse_after_member(r, nodes),
110 State::BeforeMember => state = parse_before_member(r, nodes, false),
111 State::BeforeMemberNullable => state = parse_before_member(r, nodes, true),
112 State::AttachedProperty => state = parse_attached_property(r, nodes, false)?,
113 State::AttachedPropertyNullable => state = parse_attached_property(r, nodes, true)?,
114 State::Indexer => state = parse_indexer(r, nodes)?,
115 State::TypeCast => state = parse_type_cast(r, nodes)?,
116 State::ElementName => {
117 state = parse_element_name(r, nodes)?;
118 mode = SourceMode::Control;
119 }
120 State::RelativeSource => {
121 state = parse_relative_source(r, nodes)?;
122 mode = SourceMode::Control;
123 }
124 State::End => {}
125 }
126 }
127
128 if !r.end() {
129 return Err(ExpressionParseException::new(
130 r.position(),
131 "Expected end of expression.",
132 ));
133 }
134
135 if matches!(state, State::BeforeMember | State::BeforeMemberNullable) {
136 return Err(ExpressionParseException::new(
137 r.position(),
138 "Unexpected end of expression.",
139 ));
140 }
141
142 Ok(mode)
143}
144
145fn parse_start(r: &mut CharacterReader<'_>, nodes: &mut Vec<Node>) -> State {
146 if parse_not(r) {
147 nodes.push(Node::Not);
148 return State::Start;
149 } else if parse_sharp(r) {
150 return State::ElementName;
151 } else if parse_dollar_sign(r) {
152 return State::RelativeSource;
153 } else if parse_open_brace(r) {
154 if peek_open_brace(r) {
155 return State::TypeCast;
156 }
157
158 return State::AttachedProperty;
159 } else if peek_open_bracket(r) {
160 return State::Indexer;
161 } else if parse_dot(r) {
162 nodes.push(Node::EmptyExpression);
163 return State::AfterMember;
164 } else if parse_stream_operator(r) {
165 nodes.push(Node::EmptyExpression);
166 nodes.push(Node::Stream);
167 return State::AfterMember;
168 } else {
169 let identifier = r.parse_identifier();
170
171 if !identifier.is_empty() {
172 nodes.push(Node::PropertyName {
173 accepts_null: false,
174 property_name: identifier.to_string(),
175 });
176 return State::AfterMember;
177 }
178 }
179
180 State::End
181}
182
183fn parse_after_member(r: &mut CharacterReader<'_>, nodes: &mut Vec<Node>) -> State {
184 if let Some(accepts_null) = parse_member_accessor(r) {
185 return if accepts_null {
186 State::BeforeMemberNullable
187 } else {
188 State::BeforeMember
189 };
190 } else if parse_stream_operator(r) {
191 nodes.push(Node::Stream);
192 return State::AfterMember;
193 } else if peek_open_bracket(r) {
194 return State::Indexer;
195 } else if parse_open_brace(r) {
196 return State::TypeCast;
197 }
198
199 State::End
200}
201
202fn parse_before_member(
203 r: &mut CharacterReader<'_>,
204 nodes: &mut Vec<Node>,
205 accepts_null: bool,
206) -> State {
207 if parse_open_brace(r) {
208 if peek_open_brace(r) {
209 return State::TypeCast;
210 }
211
212 if accepts_null {
213 State::AttachedPropertyNullable
214 } else {
215 State::AttachedProperty
216 }
217 } else {
218 let identifier = r.parse_identifier();
219
220 if !identifier.is_empty() {
221 nodes.push(Node::PropertyName {
222 accepts_null,
223 property_name: identifier.to_string(),
224 });
225 return State::AfterMember;
226 }
227
228 State::End
229 }
230}
231
232fn parse_attached_property(
233 r: &mut CharacterReader<'_>,
234 nodes: &mut Vec<Node>,
235 accepts_null: bool,
236) -> ParseResult<State> {
237 let TypeName {
238 namespace: ns,
239 type_name: owner,
240 } = parse_type_name(r);
241
242 if !r.end() && r.take_if(')') {
243 nodes.push(Node::TypeCast {
244 namespace: ns.to_string(),
245 type_name: owner.to_string(),
246 });
247 return Ok(State::AfterMember);
248 }
249
250 if r.end() || !r.take_if('.') {
251 return Err(ExpressionParseException::new(
252 r.position(),
253 "Invalid attached property name.",
254 ));
255 }
256
257 let name = r.parse_identifier();
258
259 if name.is_empty() {
260 return Err(ExpressionParseException::new(
261 r.position(),
262 "Attached Property name expected after '.'.",
263 ));
264 }
265
266 if r.end() || !r.take_if(')') {
267 return Err(ExpressionParseException::new(r.position(), "Expected ')'."));
268 }
269
270 nodes.push(Node::AttachedPropertyName {
271 accepts_null,
272 namespace: ns.to_string(),
273 type_name: owner.to_string(),
274 property_name: name.to_string(),
275 });
276 Ok(State::AfterMember)
277}
278
279fn parse_indexer(r: &mut CharacterReader<'_>, nodes: &mut Vec<Node>) -> ParseResult<State> {
280 let args = r.parse_arguments('[', ']')?;
281
282 if args.is_empty() {
283 return Err(ExpressionParseException::new(
284 r.position(),
285 "Indexer may not be empty.",
286 ));
287 }
288
289 nodes.push(Node::Indexer { arguments: args });
290 Ok(State::AfterMember)
291}
292
293fn parse_type_cast(r: &mut CharacterReader<'_>, nodes: &mut Vec<Node>) -> ParseResult<State> {
294 let parse_member_before_add_cast = parse_open_brace(r);
295
296 let TypeName {
297 namespace: ns,
298 type_name,
299 } = parse_type_name(r);
300
301 let mut result = State::AfterMember;
302
303 if parse_member_before_add_cast {
304 if !parse_close_brace(r) {
305 return Err(ExpressionParseException::new(r.position(), "Expected ')'."));
306 }
307
308 result = parse_before_member(r, nodes, false);
309 if result == State::AttachedProperty {
310 result = parse_attached_property(r, nodes, false)?;
311 }
312
313 if r.peek() == Some('[') {
314 result = parse_indexer(r, nodes)?;
315 }
316 }
317
318 nodes.push(Node::TypeCast {
319 namespace: ns.to_string(),
320 type_name: type_name.to_string(),
321 });
322
323 if r.end() || !r.take_if(')') {
324 return Err(ExpressionParseException::new(r.position(), "Expected ')'."));
325 }
326
327 Ok(result)
328}
329
330fn parse_element_name(r: &mut CharacterReader<'_>, nodes: &mut Vec<Node>) -> ParseResult<State> {
331 let name = r.parse_identifier();
332
333 if name.is_empty() {
334 return Err(ExpressionParseException::new(
335 r.position(),
336 "Element name expected after '#'.",
337 ));
338 }
339
340 nodes.push(Node::Name {
341 name: name.to_string(),
342 });
343 Ok(State::AfterMember)
344}
345
346fn parse_relative_source(
347 r: &mut CharacterReader<'_>,
348 nodes: &mut Vec<Node>,
349) -> ParseResult<State> {
350 let mode = r.parse_identifier();
351
352 if mode == "self" {
353 nodes.push(Node::SelfNode);
354 } else if mode == "parent" {
355 let mut ancestor_namespace: Option<String> = None;
356 let mut ancestor_type: Option<String> = None;
357 let mut ancestor_level = 0;
358 if peek_open_bracket(r) {
359 let args = r.parse_arguments_with_delimiter('[', ']', ';')?;
360 if args.len() > 2 || args.is_empty() {
361 return Err(ExpressionParseException::new(
362 r.position(),
363 "Too many arguments in RelativeSource syntax sugar",
364 ));
365 } else if args.len() == 1 {
366 if let Some(level) = try_parse_int(&args[0], NumberStyles::INTEGER) {
367 ancestor_type = None;
368 ancestor_level = level;
369 } else {
370 let mut reader = CharacterReader::new(&args[0]);
371 let name = parse_type_name(&mut reader);
372 ancestor_namespace = Some(name.namespace.to_string());
373 ancestor_type = Some(name.type_name.to_string());
374 }
375 } else {
376 let mut reader = CharacterReader::new(&args[0]);
377 let name = parse_type_name(&mut reader);
378 ancestor_namespace = Some(name.namespace.to_string());
379 ancestor_type = Some(name.type_name.to_string());
380 ancestor_level = match try_parse_int(&args[1], NumberStyles::INTEGER) {
381 Some(level) => level,
382 None => {
383 return Err(ExpressionParseException::new(
384 r.position(),
385 format!(
386 "The input string '{}' was not in a correct format.",
387 args[1]
388 ),
389 ));
390 }
391 };
392 }
393 }
394 nodes.push(Node::Ancestor {
395 namespace: ancestor_namespace,
396 type_name: ancestor_type,
397 level: ancestor_level,
398 });
399 } else {
400 return Err(ExpressionParseException::new(
401 r.position(),
402 "Unknown RelativeSource mode.",
403 ));
404 }
405
406 Ok(State::AfterMember)
407}
408
409fn parse_type_name<'a>(r: &mut CharacterReader<'a>) -> TypeName<'a> {
410 let type_name_or_namespace = r.parse_type_identifier();
411
412 if !r.end() && r.take_if(':') {
413 TypeName {
414 namespace: type_name_or_namespace,
415 type_name: r.parse_type_identifier(),
416 }
417 } else {
418 TypeName {
419 namespace: "",
420 type_name: type_name_or_namespace,
421 }
422 }
423}
424
425fn parse_not(r: &mut CharacterReader<'_>) -> bool {
426 !r.end() && r.take_if('!')
427}
428
429fn parse_member_accessor(r: &mut CharacterReader<'_>) -> Option<bool> {
431 if r.end() {
432 return None;
433 }
434
435 if r.take_if('.') {
436 return Some(false);
437 }
438
439 if r.take_if_str("?.") {
440 return Some(true);
441 }
442
443 None
444}
445
446fn parse_open_brace(r: &mut CharacterReader<'_>) -> bool {
447 !r.end() && r.take_if('(')
448}
449
450fn parse_close_brace(r: &mut CharacterReader<'_>) -> bool {
451 !r.end() && r.take_if(')')
452}
453
454fn peek_open_bracket(r: &CharacterReader<'_>) -> bool {
455 !r.end() && r.peek() == Some('[')
456}
457
458fn peek_open_brace(r: &CharacterReader<'_>) -> bool {
459 !r.end() && r.peek() == Some('(')
460}
461
462fn parse_stream_operator(r: &mut CharacterReader<'_>) -> bool {
463 !r.end() && r.take_if('^')
464}
465
466fn parse_dollar_sign(r: &mut CharacterReader<'_>) -> bool {
467 !r.end() && r.take_if('$')
468}
469
470fn parse_sharp(r: &mut CharacterReader<'_>) -> bool {
471 !r.end() && r.take_if('#')
472}
473
474fn parse_dot(r: &mut CharacterReader<'_>) -> bool {
475 !r.end() && r.take_if('.')
476}
477
478#[cfg(test)]
479mod tests {
480 use super::*;
481
482 fn parse(s: &str) -> Vec<Node> {
483 let mut r = CharacterReader::new(s);
484 BindingExpressionGrammar::parse_reader(&mut r).unwrap().0
485 }
486
487 fn parse_err(s: &str) -> ExpressionParseException {
488 BindingExpressionGrammar::parse(s).unwrap_err()
489 }
490
491 fn assert_error(s: &str, column: i32, message: &str) {
492 let e = parse_err(s);
493 assert_eq!((e.column(), e.message()), (column, message), "input: {s}");
494 }
495
496 fn assert_is_property(node: &Node, name: &str) {
497 assert_is_property_nullable(node, name, false);
498 }
499
500 fn assert_is_property_nullable(node: &Node, name: &str, accepts_null: bool) {
501 assert_eq!(
502 node,
503 &Node::PropertyName {
504 accepts_null,
505 property_name: name.to_string()
506 }
507 );
508 }
509
510 fn assert_is_attached_property(node: &Node, type_name: &str, name: &str) {
511 assert_is_attached_property_nullable(node, type_name, name, false);
512 }
513
514 fn assert_is_attached_property_nullable(
515 node: &Node,
516 expected_type_name: &str,
517 name: &str,
518 expected_accepts_null: bool,
519 ) {
520 match node {
521 Node::AttachedPropertyName {
522 accepts_null,
523 type_name,
524 property_name,
525 ..
526 } => {
527 assert_eq!(type_name, expected_type_name);
528 assert_eq!(property_name, name);
529 assert_eq!(*accepts_null, expected_accepts_null);
530 }
531 other => panic!("expected an attached property, got {other:?}"),
532 }
533 }
534
535 fn assert_is_indexer(node: &Node, args: &[&str]) {
536 match node {
537 Node::Indexer { arguments } => assert_eq!(arguments, args),
538 other => panic!("expected an indexer, got {other:?}"),
539 }
540 }
541
542 fn type_cast(namespace: &str, type_name: &str) -> Node {
543 Node::TypeCast {
544 namespace: namespace.to_string(),
545 type_name: type_name.to_string(),
546 }
547 }
548
549 #[test]
552 fn should_parse_single_property() {
553 let result = parse("Foo");
554 assert_eq!(result.len(), 1);
555 assert_is_property(&result[0], "Foo");
556 }
557
558 #[test]
559 fn should_parse_underscored_property() {
560 let result = parse("_Foo");
561 assert_eq!(result.len(), 1);
562 assert_is_property(&result[0], "_Foo");
563 }
564
565 #[test]
566 fn should_parse_property_with_digits() {
567 let result = parse("F0o");
568 assert_eq!(result.len(), 1);
569 assert_is_property(&result[0], "F0o");
570 }
571
572 #[test]
573 fn should_parse_dot() {
574 let result = parse(".");
575 assert_eq!(result, [Node::EmptyExpression]);
576 }
577
578 #[test]
579 fn should_parse_single_attached_property() {
580 let result = parse("(Foo.Bar)");
581 assert_eq!(result.len(), 1);
582 assert_is_attached_property(&result[0], "Foo", "Bar");
583 }
584
585 #[test]
586 fn should_parse_property_chain() {
587 let result = parse("Foo.Bar.Baz");
588
589 assert_eq!(result.len(), 3);
590 assert_is_property(&result[0], "Foo");
591 assert_is_property(&result[1], "Bar");
592 assert_is_property(&result[2], "Baz");
593 }
594
595 #[test]
596 fn should_parse_property_chain_with_attached_property_1() {
597 let result = parse("(Foo.Bar).Baz");
598
599 assert_eq!(result.len(), 2);
600 assert_is_attached_property(&result[0], "Foo", "Bar");
601 assert_is_property(&result[1], "Baz");
602 }
603
604 #[test]
605 fn should_parse_property_chain_with_attached_property_2() {
606 let result = parse("Foo.(Bar.Baz)");
607
608 assert_eq!(result.len(), 2);
609 assert_is_property(&result[0], "Foo");
610 assert_is_attached_property(&result[1], "Bar", "Baz");
611 }
612
613 #[test]
614 fn should_parse_property_chain_with_attached_property_3() {
615 let result = parse("Foo.(Bar.Baz).Last");
616
617 assert_eq!(result.len(), 3);
618 assert_is_property(&result[0], "Foo");
619 assert_is_attached_property(&result[1], "Bar", "Baz");
620 assert_is_property(&result[2], "Last");
621 }
622
623 #[test]
624 fn should_parse_null_conditional_in_property_chain_1() {
625 let result = parse("Foo?.Bar.Baz");
626
627 assert_eq!(result.len(), 3);
628 assert_is_property(&result[0], "Foo");
629 assert_is_property_nullable(&result[1], "Bar", true);
630 assert_is_property(&result[2], "Baz");
631 }
632
633 #[test]
634 fn should_parse_null_conditional_in_property_chain_2() {
635 let result = parse("Foo.Bar?.Baz");
636
637 assert_eq!(result.len(), 3);
638 assert_is_property(&result[0], "Foo");
639 assert_is_property(&result[1], "Bar");
640 assert_is_property_nullable(&result[2], "Baz", true);
641 }
642
643 #[test]
644 fn should_parse_null_conditional_in_property_chain_3() {
645 let result = parse("Foo?.(Bar.Baz)");
646
647 assert_eq!(result.len(), 2);
648 assert_is_property(&result[0], "Foo");
649 assert_is_attached_property_nullable(&result[1], "Bar", "Baz", true);
650 }
651
652 #[test]
653 fn should_parse_negated_property_chain() {
654 let result = parse("!Foo.Bar.Baz");
655
656 assert_eq!(result.len(), 4);
657 assert_eq!(result[0], Node::Not);
658 assert_is_property(&result[1], "Foo");
659 assert_is_property(&result[2], "Bar");
660 assert_is_property(&result[3], "Baz");
661 }
662
663 #[test]
664 fn should_parse_double_negated_property_chain() {
665 let result = parse("!!Foo.Bar.Baz");
666
667 assert_eq!(result.len(), 5);
668 assert_eq!(result[0], Node::Not);
669 assert_eq!(result[1], Node::Not);
670 assert_is_property(&result[2], "Foo");
671 assert_is_property(&result[3], "Bar");
672 assert_is_property(&result[4], "Baz");
673 }
674
675 #[test]
676 fn should_parse_indexed_property() {
677 let result = parse("Foo[15]");
678
679 assert_eq!(result.len(), 2);
680 assert_is_property(&result[0], "Foo");
681 assert_is_indexer(&result[1], &["15"]);
682 }
683
684 #[test]
685 fn should_parse_indexed_property_string_index() {
686 let result = parse("Foo[Key]");
687
688 assert_eq!(result.len(), 2);
689 assert_is_property(&result[0], "Foo");
690 assert_is_indexer(&result[1], &["Key"]);
691 }
692
693 #[test]
694 fn should_parse_multiple_indexed_property() {
695 let result = parse("Foo[15,6]");
696
697 assert_eq!(result.len(), 2);
698 assert_is_property(&result[0], "Foo");
699 assert_is_indexer(&result[1], &["15", "6"]);
700 }
701
702 #[test]
703 fn should_parse_multiple_indexed_property_with_space() {
704 let result = parse("Foo[5, 16]");
705
706 assert_eq!(result.len(), 2);
707 assert_is_property(&result[0], "Foo");
708 assert_is_indexer(&result[1], &["5", "16"]);
709 }
710
711 #[test]
712 fn should_parse_consecutive_indexers() {
713 let result = parse("Foo[15][16]");
714
715 assert_eq!(result.len(), 3);
716 assert_is_property(&result[0], "Foo");
717 assert_is_indexer(&result[1], &["15"]);
718 assert_is_indexer(&result[2], &["16"]);
719 }
720
721 #[test]
722 fn should_parse_indexed_property_in_chain() {
723 let result = parse("Foo.Bar[5, 6].Baz");
724
725 assert_eq!(result.len(), 4);
726 assert_is_property(&result[0], "Foo");
727 assert_is_property(&result[1], "Bar");
728 assert_is_indexer(&result[2], &["5", "6"]);
729 assert_is_property(&result[3], "Baz");
730 }
731
732 #[test]
733 fn should_parse_stream_node() {
734 let result = parse("Foo^");
735
736 assert_eq!(result.len(), 2);
737 assert_eq!(result[1], Node::Stream);
738 }
739
740 #[test]
741 fn should_parse_stream_node_on_empty_expression() {
742 let result = parse("^");
743
744 assert_eq!(result, [Node::EmptyExpression, Node::Stream]);
745 }
746
747 #[test]
748 fn should_parse_stream_node_after_dot() {
749 let result = parse(".^");
750
751 assert_eq!(result, [Node::EmptyExpression, Node::Stream]);
752 }
753
754 #[test]
755 fn should_parse_cast_to_nested_type() {
756 let result = parse("((ns:Outer+Inner)Foo).Bar");
757
758 assert_eq!(result[1], type_cast("ns", "Outer+Inner"));
759 }
760
761 #[test]
762 fn should_parse_cast_to_non_nested_type() {
763 let result = parse("((ns:Outer)Foo).Bar");
764
765 assert_eq!(result[1], type_cast("ns", "Outer"));
766 }
767
768 #[test]
771 fn identifier_cannot_start_with_digit() {
772 assert_error("1Foo", 0, "Expected end of expression.");
773 }
774
775 #[test]
776 fn identifier_cannot_start_with_symbol() {
777 assert_error("Foo.%Bar", 4, "Expected end of expression.");
778 }
779
780 #[test]
781 fn identifier_cannot_start_with_question_mark() {
782 assert_error("?Foo", 0, "Expected end of expression.");
783 }
784
785 #[test]
786 fn identifier_cannot_start_with_null_conditional() {
787 assert_error("?.Foo", 0, "Expected end of expression.");
788 }
789
790 #[test]
791 fn expression_cannot_end_with_period() {
792 assert_error("Foo.Bar.", 8, "Unexpected end of expression.");
793 }
794
795 #[test]
796 fn expression_cannot_end_with_question_mark() {
797 assert_error("Foo.Bar?", 7, "Expected end of expression.");
798 }
799
800 #[test]
801 fn expression_cannot_end_with_null_conditional() {
802 assert_error("Foo.Bar?.", 9, "Unexpected end of expression.");
803 }
804
805 #[test]
806 fn expression_cannot_start_with_period_then_token() {
807 assert_error(".Bar", 1, "Expected end of expression.");
808 }
809
810 #[test]
811 fn expression_cannot_have_empty_indexer() {
812 assert_error("Foo.Bar[]", 8, "Expected indexer argument.");
813 }
814
815 #[test]
816 fn expression_cannot_have_extra_comma_at_start_of_indexer() {
817 assert_error("Foo.Bar[,3,4]", 8, "Expected indexer argument.");
818 }
819
820 #[test]
821 fn expression_cannot_have_extra_comma_in_indexer() {
822 assert_error("Foo.Bar[3,,4]", 10, "Expected indexer argument.");
823 }
824
825 #[test]
826 fn expression_cannot_have_extra_comma_at_end_of_indexer() {
827 assert_error("Foo.Bar[3,4,]", 12, "Expected indexer argument.");
828 }
829
830 #[test]
831 fn expression_cannot_have_digit_after_indexer() {
832 assert_error("Foo.Bar[3,4]5", 12, "Expected end of expression.");
833 }
834
835 #[test]
836 fn expression_cannot_have_letter_after_indexer() {
837 assert_error("Foo.Bar[3,4]A", 12, "Expected end of expression.");
838 }
839
840 fn parse_with_mode(s: &str) -> (Vec<Node>, SourceMode) {
844 BindingExpressionGrammar::parse(s).unwrap()
845 }
846
847 fn property(name: &str) -> Node {
848 Node::PropertyName {
849 accepts_null: false,
850 property_name: name.to_string(),
851 }
852 }
853
854 #[test]
855 fn empty_string_parses_to_no_nodes() {
856 assert_eq!(parse_with_mode(""), (vec![], SourceMode::Data));
857 }
858
859 #[test]
860 fn data_source_mode_for_property_paths() {
861 assert_eq!(parse_with_mode("Foo.Bar").1, SourceMode::Data);
862 }
863
864 #[test]
865 fn should_parse_element_name() {
866 assert_eq!(
867 parse_with_mode("#foo.Bar"),
868 (
869 vec![
870 Node::Name {
871 name: "foo".to_string()
872 },
873 property("Bar")
874 ],
875 SourceMode::Control
876 )
877 );
878 }
879
880 #[test]
881 fn should_parse_negated_element_name() {
882 let (nodes, mode) = parse_with_mode("!#foo");
883 assert_eq!(
884 nodes,
885 [
886 Node::Not,
887 Node::Name {
888 name: "foo".to_string()
889 }
890 ]
891 );
892 assert_eq!(mode, SourceMode::Control);
893 assert!(nodes[0].is_transform_node());
894 assert!(!nodes[1].is_transform_node());
895 }
896
897 #[test]
898 fn should_parse_self() {
899 assert_eq!(
900 parse_with_mode("$self.Foo"),
901 (vec![Node::SelfNode, property("Foo")], SourceMode::Control)
902 );
903 }
904
905 #[test]
906 fn should_parse_parent() {
907 assert_eq!(
908 parse_with_mode("$parent.Foo"),
909 (
910 vec![
911 Node::Ancestor {
912 namespace: None,
913 type_name: None,
914 level: 0
915 },
916 property("Foo")
917 ],
918 SourceMode::Control
919 )
920 );
921 }
922
923 #[test]
924 fn should_parse_parent_with_level() {
925 assert_eq!(
926 parse("$parent[2]"),
927 [Node::Ancestor {
928 namespace: None,
929 type_name: None,
930 level: 2
931 }]
932 );
933 }
934
935 #[test]
936 fn should_parse_parent_with_type() {
937 assert_eq!(
938 parse("$parent[Border].Tag"),
939 [
940 Node::Ancestor {
941 namespace: Some(String::new()),
942 type_name: Some("Border".to_string()),
943 level: 0
944 },
945 property("Tag")
946 ]
947 );
948 }
949
950 #[test]
951 fn should_parse_parent_with_namespaced_type_and_level() {
952 assert_eq!(
953 parse("$parent[local:Border; 1]"),
954 [Node::Ancestor {
955 namespace: Some("local".to_string()),
956 type_name: Some("Border".to_string()),
957 level: 1
958 }]
959 );
960 }
961
962 #[test]
963 fn should_parse_namespaced_attached_property() {
964 assert_eq!(
965 parse("(local:Foo.Bar)"),
966 [Node::AttachedPropertyName {
967 accepts_null: false,
968 namespace: "local".to_string(),
969 type_name: "Foo".to_string(),
970 property_name: "Bar".to_string()
971 }]
972 );
973 }
974
975 #[test]
976 fn should_parse_type_cast_of_source() {
977 assert_eq!(parse("(ns:Foo)"), [type_cast("ns", "Foo")]);
978 assert_eq!(
979 parse("(Foo).Bar"),
980 [type_cast("", "Foo"), property("Bar")]
981 );
982 }
983
984 #[test]
985 fn should_parse_type_cast_after_member() {
986 assert_eq!(
987 parse("Foo(ns:Bar).Baz"),
988 [property("Foo"), type_cast("ns", "Bar"), property("Baz")]
989 );
990 assert_eq!(
991 parse("Foo.Bar((Baz)Qux)"),
992 [
993 property("Foo"),
994 property("Bar"),
995 property("Qux"),
996 type_cast("", "Baz")
997 ]
998 );
999 }
1000
1001 #[test]
1002 fn should_parse_type_cast_of_member_in_chain() {
1003 assert_eq!(
1004 parse("Foo.((ns:Type)Bar).Baz"),
1005 [
1006 property("Foo"),
1007 property("Bar"),
1008 type_cast("ns", "Type"),
1009 property("Baz")
1010 ]
1011 );
1012 }
1013
1014 #[test]
1015 fn should_parse_type_cast_of_attached_property_and_indexer() {
1016 assert_eq!(
1017 parse("((Type)(Owner.Prop))"),
1018 [
1019 Node::AttachedPropertyName {
1020 accepts_null: false,
1021 namespace: String::new(),
1022 type_name: "Owner".to_string(),
1023 property_name: "Prop".to_string()
1024 },
1025 type_cast("", "Type")
1026 ]
1027 );
1028 assert_eq!(
1029 parse("((Type)Foo[1])"),
1030 [
1031 property("Foo"),
1032 Node::Indexer {
1033 arguments: vec!["1".to_string()]
1034 },
1035 type_cast("", "Type")
1036 ]
1037 );
1038 }
1039
1040 #[test]
1041 fn should_parse_leading_indexer() {
1042 let result = parse("[0].Foo");
1043 assert_is_indexer(&result[0], &["0"]);
1044 assert_is_property(&result[1], "Foo");
1045 }
1046
1047 #[test]
1048 fn should_parse_stream_in_chain() {
1049 assert_eq!(
1050 parse("Foo^.Bar^"),
1051 [property("Foo"), Node::Stream, property("Bar"), Node::Stream]
1052 );
1053 }
1054
1055 #[test]
1056 fn should_parse_unicode_identifiers() {
1057 assert_eq!(parse("Żółw.Imię"), [property("Żółw"), property("Imię")]);
1058 }
1059
1060 #[test]
1061 fn unterminated_prefixes_parse_to_no_nodes() {
1062 assert_eq!(parse_with_mode("#"), (vec![], SourceMode::Data));
1065 assert_eq!(parse_with_mode("$"), (vec![], SourceMode::Data));
1066 assert_eq!(parse_with_mode("("), (vec![], SourceMode::Data));
1067 assert_eq!(parse_with_mode("!"), (vec![Node::Not], SourceMode::Data));
1068 }
1069
1070 #[test]
1071 fn element_name_errors() {
1072 assert_error("#1", 1, "Element name expected after '#'.");
1073 }
1074
1075 #[test]
1076 fn relative_source_errors() {
1077 assert_error("$foo", 4, "Unknown RelativeSource mode.");
1078 assert_error("$1", 1, "Unknown RelativeSource mode.");
1079 assert_error(
1080 "$parent[A;1;2]",
1081 14,
1082 "Too many arguments in RelativeSource syntax sugar",
1083 );
1084 assert_error(
1085 "$parent[A;B]",
1086 12,
1087 "The input string 'B' was not in a correct format.",
1088 );
1089 assert_error("$parent[A 1]", 11, "Expected ';'.");
1090 assert_error("$parent[]", 8, "Expected indexer argument.");
1091 }
1092
1093 #[test]
1094 fn attached_property_errors() {
1095 assert_error("(Foo", 4, "Invalid attached property name.");
1096 assert_error("(Foo:", 5, "Invalid attached property name.");
1097 assert_error("(Foo-Bar)", 4, "Invalid attached property name.");
1098 assert_error("(Foo.)", 5, "Attached Property name expected after '.'.");
1099 assert_error("(Foo.", 5, "Attached Property name expected after '.'.");
1100 assert_error("(Foo.Bar", 8, "Expected ')'.");
1101 assert_error("(Foo.Bar.Baz)", 8, "Expected ')'.");
1102 assert_error("Foo?.(Bar", 9, "Invalid attached property name.");
1103 }
1104
1105 #[test]
1106 fn type_cast_errors() {
1107 assert_error("((Foo", 5, "Expected ')'.");
1108 assert_error("((Foo)", 6, "Expected ')'.");
1109 assert_error("((Foo)Bar", 9, "Expected ')'.");
1110 assert_error("((Foo)Bar]", 9, "Expected ')'.");
1111 assert_error("Foo(Bar", 7, "Expected ')'.");
1112 assert_error("((Foo)Bar[])", 10, "Expected indexer argument.");
1113 }
1114
1115 #[test]
1116 fn indexer_errors() {
1117 assert_error("Foo[1", 5, "Expected ','.");
1118 assert_error("Foo[1,", 6, "Expected ']'.");
1119 assert_error("Foo[1 2]", 7, "Expected ','.");
1120 }
1121
1122 #[test]
1123 fn trailing_garbage_is_an_error() {
1124 assert_error("Foo Bar", 3, "Expected end of expression.");
1125 assert_error("Foo)", 3, "Expected end of expression.");
1126 assert_error("Foo!", 3, "Expected end of expression.");
1127 }
1128}