1#[macro_export]
105macro_rules! eure {
106 ({}) => {{
114 $crate::document::EureDocument::new_empty()
115 }};
116
117 ({ $($body:tt)* }) => {{
119 #[allow(unused_mut)]
120 let mut c = $crate::document::constructor::DocumentConstructor::new();
121 $crate::eure!(@stmt c; $($body)*);
122 c.finish()
123 }};
124
125 ($c:ident; { $($body:tt)* }) => {{
128 $crate::eure!(@stmt $c; $($body)*);
129 }};
130
131 (@value_tt null) => { $crate::value::PrimitiveValue::Null };
144
145 (@value_tt true) => { true };
147 (@value_tt false) => { false };
148
149 (@value_tt $v:literal) => { $v };
151
152 (@value_tt $v:expr) => { $v };
154
155 (@array_items $c:ident;) => {};
164
165 (@array_items $c:ident; , $($rest:tt)*) => {{
167 $crate::eure!(@array_items $c; $($rest)*);
168 }};
169
170 (@array_items $c:ident; @ code ($content:literal) $($rest:tt)*) => {{
172 let scope = $c.begin_scope();
173 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
174 $c.bind_from($crate::text::Text::inline_implicit($content)).unwrap();
175 $c.end_scope(scope).unwrap();
176 $crate::eure!(@array_items $c; $($rest)*);
177 }};
178
179 (@array_items $c:ident; @ code ($lang:literal, $content:literal) $($rest:tt)*) => {{
181 let scope = $c.begin_scope();
182 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
183 $c.bind_from($crate::text::Text::inline($content, $lang)).unwrap();
184 $c.end_scope(scope).unwrap();
185 $crate::eure!(@array_items $c; $($rest)*);
186 }};
187
188 (@array_items $c:ident; [$($inner:tt)*] $($rest:tt)*) => {{
190 let scope = $c.begin_scope();
191 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
192 $c.bind_empty_array().unwrap();
193 $crate::eure!(@array_items $c; $($inner)*);
194 $c.end_scope(scope).unwrap();
195 $crate::eure!(@array_items $c; $($rest)*);
196 }};
197
198 (@array_items $c:ident; ($($inner:tt)*) $($rest:tt)*) => {{
200 let scope = $c.begin_scope();
201 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
202 $c.bind_empty_tuple().unwrap();
203 $crate::eure!(@tuple_items $c 0; $($inner)*);
204 $c.end_scope(scope).unwrap();
205 $crate::eure!(@array_items $c; $($rest)*);
206 }};
207
208 (@array_items $c:ident; $item:tt $($rest:tt)*) => {{
210 let scope = $c.begin_scope();
211 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
212 $c.bind_from($crate::eure!(@value_tt $item)).unwrap();
213 $c.end_scope(scope).unwrap();
214 $crate::eure!(@array_items $c; $($rest)*);
215 }};
216
217 (@tuple_items $c:ident $idx:expr;) => {};
226
227 (@tuple_items $c:ident $idx:expr; , $($rest:tt)*) => {{
229 $crate::eure!(@tuple_items $c $idx; $($rest)*);
230 }};
231
232 (@tuple_items $c:ident $idx:expr; @ code ($content:literal) $($rest:tt)*) => {{
234 let scope = $c.begin_scope();
235 $c.navigate($crate::path::PathSegment::TupleIndex($idx)).unwrap();
236 $c.bind_from($crate::text::Text::inline_implicit($content)).unwrap();
237 $c.end_scope(scope).unwrap();
238 $crate::eure!(@tuple_items $c ($idx + 1); $($rest)*);
239 }};
240
241 (@tuple_items $c:ident $idx:expr; @ code ($lang:literal, $content:literal) $($rest:tt)*) => {{
243 let scope = $c.begin_scope();
244 $c.navigate($crate::path::PathSegment::TupleIndex($idx)).unwrap();
245 $c.bind_from($crate::text::Text::inline($content, $lang)).unwrap();
246 $c.end_scope(scope).unwrap();
247 $crate::eure!(@tuple_items $c ($idx + 1); $($rest)*);
248 }};
249
250 (@tuple_items $c:ident $idx:expr; [$($inner:tt)*] $($rest:tt)*) => {{
252 let scope = $c.begin_scope();
253 $c.navigate($crate::path::PathSegment::TupleIndex($idx)).unwrap();
254 $c.bind_empty_array().unwrap();
255 $crate::eure!(@array_items $c; $($inner)*);
256 $c.end_scope(scope).unwrap();
257 $crate::eure!(@tuple_items $c ($idx + 1); $($rest)*);
258 }};
259
260 (@tuple_items $c:ident $idx:expr; ($($inner:tt)*) $($rest:tt)*) => {{
262 let scope = $c.begin_scope();
263 $c.navigate($crate::path::PathSegment::TupleIndex($idx)).unwrap();
264 $c.bind_empty_tuple().unwrap();
265 $crate::eure!(@tuple_items $c 0; $($inner)*);
266 $c.end_scope(scope).unwrap();
267 $crate::eure!(@tuple_items $c ($idx + 1); $($rest)*);
268 }};
269
270 (@tuple_items $c:ident $idx:expr; $item:tt $($rest:tt)*) => {{
272 let scope = $c.begin_scope();
273 $c.navigate($crate::path::PathSegment::TupleIndex($idx)).unwrap();
274 $c.bind_from($crate::eure!(@value_tt $item)).unwrap();
275 $c.end_scope(scope).unwrap();
276 $crate::eure!(@tuple_items $c ($idx + 1); $($rest)*);
277 }};
278
279 (@object_key $key:ident) => { stringify!($key) };
288
289 (@object_key $key:tt) => { $key };
291
292 (@object_items $c:ident;) => {};
300
301 (@object_items $c:ident; , $($rest:tt)*) => {{
303 $crate::eure!(@object_items $c; $($rest)*);
304 }};
305
306 (@object_items $c:ident; $key:tt => @ code ($content:literal) $($rest:tt)*) => {{
308 let scope = $c.begin_scope();
309 $c.navigate($crate::path::PathSegment::Value($crate::eure!(@object_key $key).into())).unwrap();
310 $c.bind_from($crate::text::Text::inline_implicit($content)).unwrap();
311 $c.end_scope(scope).unwrap();
312 $crate::eure!(@object_items $c; $($rest)*);
313 }};
314
315 (@object_items $c:ident; $key:tt => @ code ($lang:literal, $content:literal) $($rest:tt)*) => {{
317 let scope = $c.begin_scope();
318 $c.navigate($crate::path::PathSegment::Value($crate::eure!(@object_key $key).into())).unwrap();
319 $c.bind_from($crate::text::Text::inline($content, $lang)).unwrap();
320 $c.end_scope(scope).unwrap();
321 $crate::eure!(@object_items $c; $($rest)*);
322 }};
323
324 (@object_items $c:ident; $key:tt => [$($inner:tt)*] $($rest:tt)*) => {{
326 let scope = $c.begin_scope();
327 $c.navigate($crate::path::PathSegment::Value($crate::eure!(@object_key $key).into())).unwrap();
328 $c.bind_empty_array().unwrap();
329 $crate::eure!(@array_items $c; $($inner)*);
330 $c.end_scope(scope).unwrap();
331 $crate::eure!(@object_items $c; $($rest)*);
332 }};
333
334 (@object_items $c:ident; $key:tt => ($($inner:tt)*) $($rest:tt)*) => {{
336 let scope = $c.begin_scope();
337 $c.navigate($crate::path::PathSegment::Value($crate::eure!(@object_key $key).into())).unwrap();
338 $c.bind_empty_tuple().unwrap();
339 $crate::eure!(@tuple_items $c 0; $($inner)*);
340 $c.end_scope(scope).unwrap();
341 $crate::eure!(@object_items $c; $($rest)*);
342 }};
343
344 (@object_items $c:ident; $key:tt => $val:tt $($rest:tt)*) => {{
346 let scope = $c.begin_scope();
347 $c.navigate($crate::path::PathSegment::Value($crate::eure!(@object_key $key).into())).unwrap();
348 $c.bind_from($crate::eure!(@value_tt $val)).unwrap();
349 $c.end_scope(scope).unwrap();
350 $crate::eure!(@object_items $c; $($rest)*);
351 }};
352
353 (@stmt $c:ident;) => {};
367
368 (@stmt $c:ident; , $($rest:tt)*) => {{
370 $crate::eure!(@stmt $c; $($rest)*);
371 }};
372
373 (@stmt $c:ident; = ! $($rest:tt)*) => {{
376 $c.bind_hole(None).unwrap();
377 $crate::eure!(@stmt $c; $($rest)*);
378 }};
379
380 (@stmt $c:ident; = - $v:literal $($rest:tt)*) => {{
383 $c.bind_from(-$v).unwrap();
384 $crate::eure!(@stmt $c; $($rest)*);
385 }};
386
387 (@stmt $c:ident; = @ code ($content:literal) $($rest:tt)*) => {{
389 $c.bind_from($crate::text::Text::inline_implicit($content)).unwrap();
390 $crate::eure!(@stmt $c; $($rest)*);
391 }};
392
393 (@stmt $c:ident; = @ code ($lang:literal, $content:literal) $($rest:tt)*) => {{
395 $c.bind_from($crate::text::Text::inline($content, $lang)).unwrap();
396 $crate::eure!(@stmt $c; $($rest)*);
397 }};
398
399 (@stmt $c:ident; = @ block ($content:literal) $($rest:tt)*) => {{
401 $c.bind_from($crate::text::Text::block_implicit($content)).unwrap();
402 $crate::eure!(@stmt $c; $($rest)*);
403 }};
404
405 (@stmt $c:ident; = @ block ($lang:literal, $content:literal) $($rest:tt)*) => {{
407 $c.bind_from($crate::text::Text::block($content, $lang)).unwrap();
408 $crate::eure!(@stmt $c; $($rest)*);
409 }};
410
411 (@stmt $c:ident; = [] $($rest:tt)*) => {{
413 $c.bind_empty_array().unwrap();
414 $crate::eure!(@stmt $c; $($rest)*);
415 }};
416
417 (@stmt $c:ident; = [$($items:tt)+] $($rest:tt)*) => {{
419 $c.bind_empty_array().unwrap();
420 $crate::eure!(@array_items $c; $($items)+);
421 $crate::eure!(@stmt $c; $($rest)*);
422 }};
423
424 (@stmt $c:ident; = () $($rest:tt)*) => {{
426 $c.bind_empty_tuple().unwrap();
427 $crate::eure!(@stmt $c; $($rest)*);
428 }};
429
430 (@stmt $c:ident; = ($($items:tt)+) $($rest:tt)*) => {{
432 $c.bind_empty_tuple().unwrap();
433 $crate::eure!(@tuple_items $c 0; $($items)+);
434 $crate::eure!(@stmt $c; $($rest)*);
435 }};
436
437 (@stmt $c:ident; = { $key:tt => $($inner:tt)+ } $($rest:tt)*) => {{
439 $c.bind_empty_map().unwrap();
440 $crate::eure!(@object_items $c; $key => $($inner)+);
441 $crate::eure!(@stmt $c; $($rest)*);
442 }};
443
444 (@stmt $c:ident; = $v:tt $($rest:tt)*) => {{
446 $c.bind_from($crate::eure!(@value_tt $v)).unwrap();
447 $crate::eure!(@stmt $c; $($rest)*);
448 }};
449
450 (@stmt $c:ident; @ [] $($rest:tt)*) => {{
453 $c.begin_section();
454 let scope = $c.begin_scope();
455 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
456 $crate::eure!(@section_after_seg $c scope; $($rest)*);
457 }};
458 (@stmt $c:ident; @ [$idx:literal] $($rest:tt)*) => {{
459 $c.begin_section();
460 let scope = $c.begin_scope();
461 $c.navigate($crate::path::PathSegment::ArrayIndex(Some($idx))).unwrap();
462 $crate::eure!(@section_after_seg $c scope; $($rest)*);
463 }};
464
465 (@stmt $c:ident; @ $seg:ident $($rest:tt)*) => {{
467 $c.begin_section();
468 let scope = $c.begin_scope();
469 $c.navigate($crate::path::PathSegment::Ident(
470 $crate::identifier::Identifier::new_unchecked(stringify!($seg))
471 )).unwrap();
472 $crate::eure!(@section_after_seg $c scope; $($rest)*);
473 }};
474
475 (@stmt $c:ident; $($tokens:tt)+) => {{
478 $c.begin_binding();
479 let scope = $c.begin_scope();
480 $crate::eure!(@path $c scope; $($tokens)+);
481 }};
482
483 (@section_after_seg $c:ident $scope:ident; . $seg:ident $($rest:tt)*) => {{
491 $c.navigate($crate::path::PathSegment::Ident(
492 $crate::identifier::Identifier::new_unchecked(stringify!($seg))
493 )).unwrap();
494 $crate::eure!(@section_after_seg $c $scope; $($rest)*);
495 }};
496 (@section_after_seg $c:ident $scope:ident; # [] $($rest:tt)*) => {{
497 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
498 $crate::eure!(@section_after_seg $c $scope; $($rest)*);
499 }};
500 (@section_after_seg $c:ident $scope:ident; # [$idx:literal] $($rest:tt)*) => {{
501 $c.navigate($crate::path::PathSegment::ArrayIndex(Some($idx))).unwrap();
502 $crate::eure!(@section_after_seg $c $scope; $($rest)*);
503 }};
504 (@section_after_seg $c:ident $scope:ident; [$($arr:tt)*] $($rest:tt)*) => {{
505 compile_error!(
506 "in section headers, raw []/[N] is only allowed immediately after `@`; use #[] or #[N] for continuation"
507 );
508 }};
509
510 (@section_after_seg $c:ident $scope:ident; = $v:tt $($rest:tt)*) => {{
512 $c.bind_from($crate::eure!(@value_tt $v)).unwrap();
513 $c.begin_section_items();
514 $crate::eure!(@section_bindings $c $scope; $($rest)*);
516 }};
517
518 (@section_after_seg $c:ident $scope:ident; {} $($rest:tt)*) => {{
520 $c.begin_eure_block();
521 $c.bind_empty_map().unwrap();
522 $c.end_eure_block().unwrap();
523 $c.end_scope($scope).unwrap();
524 $c.end_section_block().unwrap();
525 $crate::eure!(@stmt $c; $($rest)*);
526 }};
527
528 (@section_after_seg $c:ident $scope:ident; { $($inner:tt)+ } $($rest:tt)*) => {{
530 $c.begin_eure_block();
531 $crate::eure!(@stmt $c; $($inner)+);
532 $c.end_eure_block().unwrap();
533 $c.end_scope($scope).unwrap();
534 $c.end_section_block().unwrap();
535 $crate::eure!(@stmt $c; $($rest)*);
536 }};
537
538 (@section_after_seg $c:ident $scope:ident; $($rest:tt)*) => {{
540 $c.begin_section_items();
541 $crate::eure!(@section_bindings $c $scope; $($rest)*);
542 }};
543
544 (@section_bindings $c:ident $scope:ident;) => {{
546 $c.end_section_items().unwrap();
547 $c.end_scope($scope).unwrap();
548 }};
549
550 (@section_bindings $c:ident $scope:ident; , $($rest:tt)*) => {{
552 $crate::eure!(@section_bindings $c $scope; $($rest)*);
553 }};
554
555 (@section_bindings $c:ident $scope:ident; @ [] $($rest:tt)*) => {{
557 $c.end_section_items().unwrap();
558 $c.end_scope($scope).unwrap();
559 $crate::eure!(@stmt $c; @ [] $($rest)*);
560 }};
561 (@section_bindings $c:ident $scope:ident; @ [$idx:literal] $($rest:tt)*) => {{
562 $c.end_section_items().unwrap();
563 $c.end_scope($scope).unwrap();
564 $crate::eure!(@stmt $c; @ [$idx] $($rest)*);
565 }};
566 (@section_bindings $c:ident $scope:ident; @ $seg:ident $($rest:tt)*) => {{
567 $c.end_section_items().unwrap();
568 $c.end_scope($scope).unwrap();
569 $crate::eure!(@stmt $c; @ $seg $($rest)*);
570 }};
571
572 (@section_bindings $c:ident $scope:ident; $($tokens:tt)+) => {{
574 $c.begin_binding();
575 let inner_scope = $c.begin_scope();
576 $crate::eure!(@section_path $c $scope inner_scope; $($tokens)+);
577 }};
578
579 (@section_path $c:ident $section_scope:ident $scope:ident; $seg:ident $($rest:tt)*) => {{
581 $c.navigate($crate::path::PathSegment::Ident(
582 $crate::identifier::Identifier::new_unchecked(stringify!($seg))
583 )).unwrap();
584 $crate::eure!(@section_after_path $c $section_scope $scope; $($rest)*);
585 }};
586
587 (@section_path $c:ident $section_scope:ident $scope:ident; % $ext:ident $($rest:tt)*) => {{
589 $c.navigate($crate::path::PathSegment::Extension(
590 $crate::identifier::Identifier::new_unchecked(stringify!($ext))
591 )).unwrap();
592 $crate::eure!(@section_after_path $c $section_scope $scope; $($rest)*);
593 }};
594
595 (@section_path $c:ident $section_scope:ident $scope:ident; % $ext:literal $($rest:tt)*) => {{
597 $c.navigate($crate::path::PathSegment::Extension(
598 $ext.parse().unwrap()
599 )).unwrap();
600 $crate::eure!(@section_after_path $c $section_scope $scope; $($rest)*);
601 }};
602
603 (@section_path $c:ident $section_scope:ident $scope:ident; # [] $($rest:tt)*) => {{
605 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
606 $crate::eure!(@section_terminal $c $section_scope $scope; $($rest)*);
607 }};
608 (@section_path $c:ident $section_scope:ident $scope:ident; # [$idx:literal] $($rest:tt)*) => {{
609 $c.navigate($crate::path::PathSegment::ArrayIndex(Some($idx))).unwrap();
610 $crate::eure!(@section_terminal $c $section_scope $scope; $($rest)*);
611 }};
612
613 (@section_path $c:ident $section_scope:ident $scope:ident; # $idx:literal $($rest:tt)*) => {{
615 $c.navigate($crate::path::PathSegment::TupleIndex($idx)).unwrap();
616 $crate::eure!(@section_after_path $c $section_scope $scope; $($rest)*);
617 }};
618
619 (@section_path $c:ident $section_scope:ident $scope:ident; ($($tuple:tt)*) $($rest:tt)*) => {{
621 let key = $crate::eure!(@build_tuple_key; $($tuple)*);
622 $c.navigate($crate::path::PathSegment::Value(key)).unwrap();
623 $crate::eure!(@section_after_path $c $section_scope $scope; $($rest)*);
624 }};
625
626 (@section_path $c:ident $section_scope:ident $scope:ident; $key:literal $($rest:tt)*) => {{
628 $c.navigate($crate::path::PathSegment::Value($key.into())).unwrap();
629 $crate::eure!(@section_after_path $c $section_scope $scope; $($rest)*);
630 }};
631 (@section_path $c:ident $section_scope:ident $scope:ident; [$($arr:tt)*] $($rest:tt)*) => {{
632 compile_error!(
633 "in section bindings, raw []/[N] is not allowed; use #[] or #[N] for array segments"
634 );
635 }};
636
637 (@section_after_path $c:ident $section_scope:ident $scope:ident; [$($arr:tt)*] $($rest:tt)*) => {{
639 compile_error!(
640 "in section bindings, raw []/[N] is not allowed; use #[] or #[N] for array segments"
641 );
642 }};
643
644 (@section_after_path $c:ident $section_scope:ident $scope:ident; $($rest:tt)*) => {{
646 $crate::eure!(@section_terminal $c $section_scope $scope; $($rest)*);
647 }};
648
649 (@section_terminal $c:ident $section_scope:ident $scope:ident; . $($rest:tt)+) => {{
651 $crate::eure!(@section_path $c $section_scope $scope; $($rest)+);
652 }};
653 (@section_terminal $c:ident $section_scope:ident $scope:ident; # [] $($rest:tt)*) => {{
654 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
655 $crate::eure!(@section_terminal $c $section_scope $scope; $($rest)*);
656 }};
657 (@section_terminal $c:ident $section_scope:ident $scope:ident; # [$idx:literal] $($rest:tt)*) => {{
658 $c.navigate($crate::path::PathSegment::ArrayIndex(Some($idx))).unwrap();
659 $crate::eure!(@section_terminal $c $section_scope $scope; $($rest)*);
660 }};
661 (@section_terminal $c:ident $section_scope:ident $scope:ident; [$($arr:tt)*] $($rest:tt)*) => {{
662 compile_error!(
663 "in section bindings, raw []/[N] is not allowed; use #[] or #[N] for array segments"
664 );
665 }};
666
667 (@section_terminal $c:ident $section_scope:ident $scope:ident; = ! $($rest:tt)*) => {{
669 $c.bind_hole(None).unwrap();
670 $c.end_scope($scope).unwrap();
671 $c.end_binding_value().unwrap();
672 $crate::eure!(@section_bindings $c $section_scope; $($rest)*);
673 }};
674
675 (@section_terminal $c:ident $section_scope:ident $scope:ident; = @ code ($content:literal) $($rest:tt)*) => {{
677 $c.bind_from($crate::text::Text::inline_implicit($content)).unwrap();
678 $c.end_scope($scope).unwrap();
679 $c.end_binding_value().unwrap();
680 $crate::eure!(@section_bindings $c $section_scope; $($rest)*);
681 }};
682
683 (@section_terminal $c:ident $section_scope:ident $scope:ident; = @ code ($lang:literal, $content:literal) $($rest:tt)*) => {{
685 $c.bind_from($crate::text::Text::inline($content, $lang)).unwrap();
686 $c.end_scope($scope).unwrap();
687 $c.end_binding_value().unwrap();
688 $crate::eure!(@section_bindings $c $section_scope; $($rest)*);
689 }};
690
691 (@section_terminal $c:ident $section_scope:ident $scope:ident; = @ block ($content:literal) $($rest:tt)*) => {{
693 $c.bind_from($crate::text::Text::block_implicit($content)).unwrap();
694 $c.end_scope($scope).unwrap();
695 $c.end_binding_value().unwrap();
696 $crate::eure!(@section_bindings $c $section_scope; $($rest)*);
697 }};
698
699 (@section_terminal $c:ident $section_scope:ident $scope:ident; = @ block ($lang:literal, $content:literal) $($rest:tt)*) => {{
701 $c.bind_from($crate::text::Text::block($content, $lang)).unwrap();
702 $c.end_scope($scope).unwrap();
703 $c.end_binding_value().unwrap();
704 $crate::eure!(@section_bindings $c $section_scope; $($rest)*);
705 }};
706
707 (@section_terminal $c:ident $section_scope:ident $scope:ident; = $v:tt $($rest:tt)*) => {{
709 $c.bind_from($crate::eure!(@value_tt $v)).unwrap();
710 $c.end_scope($scope).unwrap();
711 $c.end_binding_value().unwrap();
712 $crate::eure!(@section_bindings $c $section_scope; $($rest)*);
713 }};
714
715 (@section_terminal $c:ident $section_scope:ident $scope:ident; {} $($rest:tt)*) => {{
717 $c.begin_eure_block();
718 $c.bind_empty_map().unwrap();
719 $c.end_eure_block().unwrap();
720 $c.end_scope($scope).unwrap();
721 $c.end_binding_block().unwrap();
722 $crate::eure!(@section_bindings $c $section_scope; $($rest)*);
723 }};
724
725 (@section_terminal $c:ident $section_scope:ident $scope:ident; { $($inner:tt)+ } $($rest:tt)*) => {{
727 $c.begin_eure_block();
728 $crate::eure!(@stmt $c; $($inner)+);
729 $c.end_eure_block().unwrap();
730 $c.end_scope($scope).unwrap();
731 $c.end_binding_block().unwrap();
732 $crate::eure!(@section_bindings $c $section_scope; $($rest)*);
733 }};
734
735 (@path $c:ident $scope:ident; $seg:ident $($rest:tt)*) => {{
751 $c.navigate($crate::path::PathSegment::Ident(
752 $crate::identifier::Identifier::new_unchecked(stringify!($seg))
753 )).unwrap();
754 $crate::eure!(@after_path $c $scope; $($rest)*);
755 }};
756
757 (@path $c:ident $scope:ident; % $ext:ident $($rest:tt)*) => {{
760 $c.navigate($crate::path::PathSegment::Extension(
761 $crate::identifier::Identifier::new_unchecked(stringify!($ext))
762 )).unwrap();
763 $crate::eure!(@after_path $c $scope; $($rest)*);
764 }};
765
766 (@path $c:ident $scope:ident; % $ext:literal $($rest:tt)*) => {{
769 $c.navigate($crate::path::PathSegment::Extension(
770 $ext.parse().unwrap()
771 )).unwrap();
772 $crate::eure!(@after_path $c $scope; $($rest)*);
773 }};
774
775 (@path $c:ident $scope:ident; # [] $($rest:tt)*) => {{
777 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
778 $crate::eure!(@terminal $c $scope; $($rest)*);
779 }};
780 (@path $c:ident $scope:ident; # [$idx:literal] $($rest:tt)*) => {{
781 $c.navigate($crate::path::PathSegment::ArrayIndex(Some($idx))).unwrap();
782 $crate::eure!(@terminal $c $scope; $($rest)*);
783 }};
784
785 (@path $c:ident $scope:ident; # $idx:literal $($rest:tt)*) => {{
787 $c.navigate($crate::path::PathSegment::TupleIndex($idx)).unwrap();
788 $crate::eure!(@after_path $c $scope; $($rest)*);
789 }};
790
791 (@path $c:ident $scope:ident; ($($tuple:tt)*) $($rest:tt)*) => {{
794 let key = $crate::eure!(@build_tuple_key; $($tuple)*);
795 $c.navigate($crate::path::PathSegment::Value(key)).unwrap();
796 $crate::eure!(@after_path $c $scope; $($rest)*);
797 }};
798
799 (@path $c:ident $scope:ident; $key:literal $($rest:tt)*) => {{
802 $c.navigate($crate::path::PathSegment::Value($key.into())).unwrap();
803 $crate::eure!(@after_path $c $scope; $($rest)*);
804 }};
805
806 (@build_tuple_key;) => {{
815 $crate::value::ObjectKey::Tuple($crate::value::Tuple(Default::default()))
816 }};
817
818 (@build_tuple_key; $($item:expr),+ $(,)?) => {{
820 $crate::value::ObjectKey::Tuple($crate::value::Tuple::from_iter(
821 [$(<_ as Into<$crate::value::ObjectKey>>::into($item)),+]
822 ))
823 }};
824
825 (@after_path $c:ident $scope:ident; [$($arr:tt)*] $($rest:tt)*) => {{
834 $crate::eure!(@array_marker $c $scope [$($arr)*]; $($rest)*);
835 }};
836
837 (@after_path $c:ident $scope:ident; $($rest:tt)*) => {{
839 $crate::eure!(@terminal $c $scope; $($rest)*);
840 }};
841
842 (@array_marker $c:ident $scope:ident []; $($rest:tt)*) => {{
852 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
853 $crate::eure!(@terminal $c $scope; $($rest)*);
854 }};
855
856 (@array_marker $c:ident $scope:ident [$idx:literal]; $($rest:tt)*) => {{
858 $c.navigate($crate::path::PathSegment::ArrayIndex(Some($idx))).unwrap();
859 $crate::eure!(@terminal $c $scope; $($rest)*);
860 }};
861
862 (@terminal $c:ident $scope:ident; . $($rest:tt)+) => {{
880 $crate::eure!(@path $c $scope; $($rest)+);
881 }};
882 (@terminal $c:ident $scope:ident; # [] $($rest:tt)*) => {{
883 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
884 $crate::eure!(@terminal $c $scope; $($rest)*);
885 }};
886 (@terminal $c:ident $scope:ident; # [$idx:literal] $($rest:tt)*) => {{
887 $c.navigate($crate::path::PathSegment::ArrayIndex(Some($idx))).unwrap();
888 $crate::eure!(@terminal $c $scope; $($rest)*);
889 }};
890
891 (@terminal $c:ident $scope:ident; = ! $($rest:tt)*) => {{
893 $c.bind_hole(None).unwrap();
894 $c.end_scope($scope).unwrap();
895 $c.end_binding_value().unwrap();
896 $crate::eure!(@stmt $c; $($rest)*);
897 }};
898
899 (@terminal $c:ident $scope:ident; = - $v:literal $($rest:tt)*) => {{
901 $c.bind_from(-$v).unwrap();
902 $c.end_scope($scope).unwrap();
903 $c.end_binding_value().unwrap();
904 $crate::eure!(@stmt $c; $($rest)*);
905 }};
906
907 (@terminal $c:ident $scope:ident; = @ code ($content:literal) $($rest:tt)*) => {{
909 $c.bind_from($crate::text::Text::inline_implicit($content)).unwrap();
910 $c.end_scope($scope).unwrap();
911 $c.end_binding_value().unwrap();
912 $crate::eure!(@stmt $c; $($rest)*);
913 }};
914
915 (@terminal $c:ident $scope:ident; = @ code ($lang:literal, $content:literal) $($rest:tt)*) => {{
917 $c.bind_from($crate::text::Text::inline($content, $lang)).unwrap();
918 $c.end_scope($scope).unwrap();
919 $c.end_binding_value().unwrap();
920 $crate::eure!(@stmt $c; $($rest)*);
921 }};
922
923 (@terminal $c:ident $scope:ident; = @ block ($content:literal) $($rest:tt)*) => {{
925 $c.bind_from($crate::text::Text::block_implicit($content)).unwrap();
926 $c.end_scope($scope).unwrap();
927 $c.end_binding_value().unwrap();
928 $crate::eure!(@stmt $c; $($rest)*);
929 }};
930
931 (@terminal $c:ident $scope:ident; = @ block ($lang:literal, $content:literal) $($rest:tt)*) => {{
933 $c.bind_from($crate::text::Text::block($content, $lang)).unwrap();
934 $c.end_scope($scope).unwrap();
935 $c.end_binding_value().unwrap();
936 $crate::eure!(@stmt $c; $($rest)*);
937 }};
938
939 (@terminal $c:ident $scope:ident; = [] $($rest:tt)*) => {{
941 $c.bind_empty_array().unwrap();
942 $c.end_scope($scope).unwrap();
943 $c.end_binding_value().unwrap();
944 $crate::eure!(@stmt $c; $($rest)*);
945 }};
946
947 (@terminal $c:ident $scope:ident; = [$($items:tt)+] $($rest:tt)*) => {{
949 $c.bind_empty_array().unwrap();
950 $crate::eure!(@array_items $c; $($items)+);
951 $c.end_scope($scope).unwrap();
952 $c.end_binding_value().unwrap();
953 $crate::eure!(@stmt $c; $($rest)*);
954 }};
955
956 (@terminal $c:ident $scope:ident; = () $($rest:tt)*) => {{
958 $c.bind_empty_tuple().unwrap();
959 $c.end_scope($scope).unwrap();
960 $c.end_binding_value().unwrap();
961 $crate::eure!(@stmt $c; $($rest)*);
962 }};
963
964 (@terminal $c:ident $scope:ident; = ($($items:tt)+) $($rest:tt)*) => {{
966 $c.bind_empty_tuple().unwrap();
967 $crate::eure!(@tuple_items $c 0; $($items)+);
968 $c.end_scope($scope).unwrap();
969 $c.end_binding_value().unwrap();
970 $crate::eure!(@stmt $c; $($rest)*);
971 }};
972
973 (@terminal $c:ident $scope:ident; = { $key:tt => $($inner:tt)+ } $($rest:tt)*) => {{
975 $c.bind_empty_map().unwrap();
976 $crate::eure!(@object_items $c; $key => $($inner)+);
977 $c.end_scope($scope).unwrap();
978 $c.end_binding_value().unwrap();
979 $crate::eure!(@stmt $c; $($rest)*);
980 }};
981
982 (@terminal $c:ident $scope:ident; = $v:tt $($rest:tt)*) => {{
984 $c.bind_from($crate::eure!(@value_tt $v)).unwrap();
985 $c.end_scope($scope).unwrap();
986 $c.end_binding_value().unwrap();
987 $crate::eure!(@stmt $c; $($rest)*);
988 }};
989
990 (@terminal $c:ident $scope:ident; {} $($rest:tt)*) => {{
992 $c.begin_eure_block();
993 $c.bind_empty_map().unwrap();
994 $c.end_eure_block().unwrap();
995 $c.end_scope($scope).unwrap();
996 $c.end_binding_block().unwrap();
997 $crate::eure!(@stmt $c; $($rest)*);
998 }};
999
1000 (@terminal $c:ident $scope:ident; { $($inner:tt)+ } $($rest:tt)*) => {{
1002 $c.begin_eure_block();
1003 $crate::eure!(@stmt $c; $($inner)+);
1004 $c.end_eure_block().unwrap();
1005 $c.end_scope($scope).unwrap();
1006 $c.end_binding_block().unwrap();
1007 $crate::eure!(@stmt $c; $($rest)*);
1008 }};
1009}
1010
1011#[macro_export]
1031macro_rules! eure_source {
1032 ({}) => {{
1034 $crate::source::SourceDocument::empty()
1035 }};
1036
1037 ({ $($body:tt)* }) => {{
1039 #[allow(unused_mut)]
1040 let mut c = $crate::document::source_constructor::SourceConstructor::new();
1041 $crate::eure!(c; { $($body)* });
1042 c.finish()
1043 }};
1044}
1045
1046#[cfg(test)]
1047mod tests {
1048 use crate::document::EureDocument;
1049 use alloc::vec;
1050
1051 #[test]
1052 fn test_eure_empty() {
1053 let doc = eure!({});
1054 assert_eq!(doc, EureDocument::new_empty());
1055 }
1056
1057 #[test]
1058 fn test_eure_simple_assignment() {
1059 let doc = eure!({ name = "Alice" });
1060
1061 let root_id = doc.get_root_id();
1063 let root = doc.node(root_id);
1064 let name_node_id = root.as_map().unwrap().get_node_id(&"name".into()).unwrap();
1065 let name_node = doc.node(name_node_id);
1066 let prim = name_node.as_primitive().unwrap();
1067 assert_eq!(prim.as_str(), Some("Alice"));
1068 }
1069
1070 #[test]
1071 fn test_eure_nested_path() {
1072 let doc = eure!({
1073 user.name = "Bob"
1074 user.age = 30
1075 });
1076
1077 let root_id = doc.get_root_id();
1079 let root = doc.node(root_id);
1080 let user_id = root.as_map().unwrap().get_node_id(&"user".into()).unwrap();
1081 let user = doc.node(user_id);
1082 let name_id = user.as_map().unwrap().get_node_id(&"name".into()).unwrap();
1083 let name = doc.node(name_id);
1084 assert_eq!(name.as_primitive().unwrap().as_str(), Some("Bob"));
1085
1086 let age_id = user.as_map().unwrap().get_node_id(&"age".into()).unwrap();
1087 let age = doc.node(age_id);
1088 assert!(matches!(
1089 age.as_primitive(),
1090 Some(crate::value::PrimitiveValue::Integer(_))
1091 ));
1092 }
1093
1094 #[test]
1095 fn test_eure_block() {
1096 let doc = eure!({
1097 user {
1098 name = "Charlie"
1099 active = true
1100 }
1101 });
1102
1103 let root_id = doc.get_root_id();
1104 let root = doc.node(root_id);
1105 let user_id = root.as_map().unwrap().get_node_id(&"user".into()).unwrap();
1106 let user = doc.node(user_id);
1107 let name_id = user.as_map().unwrap().get_node_id(&"name".into()).unwrap();
1108 let name = doc.node(name_id);
1109 assert_eq!(name.as_primitive().unwrap().as_str(), Some("Charlie"));
1110 }
1111
1112 #[test]
1113 fn test_eure_extension() {
1114 let doc = eure!({
1115 field.%variant = @code("text")
1116 });
1117
1118 let root_id = doc.get_root_id();
1119 let root = doc.node(root_id);
1120 let field_id = root.as_map().unwrap().get_node_id(&"field".into()).unwrap();
1121 let field = doc.node(field_id);
1122
1123 let variant_id = field.get_extension(&"variant".parse().unwrap()).unwrap();
1125 let variant = doc.node(variant_id);
1126 let text = variant.as_primitive().unwrap().as_text().unwrap();
1127 assert_eq!(text.as_str(), "text");
1128 }
1129
1130 #[test]
1131 fn test_eure_extension_with_child() {
1132 let doc = eure!({
1134 field.%variant.name = @code("text")
1135 field.%variant.min_length = 3
1136 });
1137
1138 let root_id = doc.get_root_id();
1139 let root = doc.node(root_id);
1140 let field_id = root.as_map().unwrap().get_node_id(&"field".into()).unwrap();
1141 let field = doc.node(field_id);
1142
1143 let variant_id = field.get_extension(&"variant".parse().unwrap()).unwrap();
1145 let variant = doc.node(variant_id);
1146
1147 let name_id = variant
1149 .as_map()
1150 .unwrap()
1151 .get_node_id(&"name".into())
1152 .unwrap();
1153 let name = doc.node(name_id);
1154 let text = name.as_primitive().unwrap().as_text().unwrap();
1155 assert_eq!(text.as_str(), "text");
1156
1157 let min_length_id = variant
1158 .as_map()
1159 .unwrap()
1160 .get_node_id(&"min_length".into())
1161 .unwrap();
1162 let min_length = doc.node(min_length_id);
1163 assert!(matches!(
1164 min_length.as_primitive(),
1165 Some(crate::value::PrimitiveValue::Integer(_))
1166 ));
1167 }
1168
1169 #[test]
1170 fn test_eure_array() {
1171 let doc = eure!({ tags = ["a", "b", "c"] });
1172
1173 let root_id = doc.get_root_id();
1174 let root = doc.node(root_id);
1175 let tags_id = root.as_map().unwrap().get_node_id(&"tags".into()).unwrap();
1176 let tags = doc.node(tags_id);
1177 let array = tags.as_array().unwrap();
1178 assert_eq!(array.len(), 3);
1179 }
1180
1181 #[test]
1182 fn test_eure_tuple() {
1183 let doc = eure!({ point = (1.5, 2.5) });
1184
1185 let root_id = doc.get_root_id();
1186 let root = doc.node(root_id);
1187 let point_id = root.as_map().unwrap().get_node_id(&"point".into()).unwrap();
1188 let point = doc.node(point_id);
1189 let tuple = point.as_tuple().unwrap();
1190 assert_eq!(tuple.len(), 2);
1191 }
1192
1193 #[test]
1194 fn test_eure_multiple_assignments() {
1195 let doc = eure!({
1196 a = 1
1197 b = 2
1198 c = 3
1199 });
1200
1201 let root_id = doc.get_root_id();
1202 let root = doc.node(root_id);
1203 let map = root.as_map().unwrap();
1204 assert_eq!(map.len(), 3);
1205 }
1206
1207 #[test]
1208 fn test_eure_complex() {
1209 let doc = eure!({
1211 schema {
1212 field.%variant = @code("text")
1213 field.min_length = 3
1214 field.max_length = 20
1215 }
1216 tags = ["required"]
1217 });
1218
1219 let root_id = doc.get_root_id();
1220 let root = doc.node(root_id);
1221
1222 let schema_id = root
1224 .as_map()
1225 .unwrap()
1226 .get_node_id(&"schema".into())
1227 .unwrap();
1228 let schema = doc.node(schema_id);
1229
1230 let field_id = schema
1232 .as_map()
1233 .unwrap()
1234 .get_node_id(&"field".into())
1235 .unwrap();
1236 let field = doc.node(field_id);
1237 assert!(field.get_extension(&"variant".parse().unwrap()).is_some());
1238
1239 let tags_id = root.as_map().unwrap().get_node_id(&"tags".into()).unwrap();
1241 let tags = doc.node(tags_id);
1242 assert_eq!(tags.as_array().unwrap().len(), 1);
1243 }
1244
1245 #[test]
1246 fn test_eure_array_push() {
1247 let doc = eure!({
1249 items[] = 1
1250 items[] = 2
1251 items[] = 3
1252 });
1253
1254 let root_id = doc.get_root_id();
1255 let root = doc.node(root_id);
1256 let items_id = root.as_map().unwrap().get_node_id(&"items".into()).unwrap();
1257 let items = doc.node(items_id);
1258 let array = items.as_array().unwrap();
1259 assert_eq!(array.len(), 3);
1260 }
1261
1262 #[test]
1263 fn test_eure_array_push_with_child() {
1264 let doc = eure!({
1266 items[].name = "first"
1267 items[].name = "second"
1268 });
1269
1270 let root_id = doc.get_root_id();
1271 let root = doc.node(root_id);
1272 let items_id = root.as_map().unwrap().get_node_id(&"items".into()).unwrap();
1273 let items = doc.node(items_id);
1274 let array = items.as_array().unwrap();
1275 assert_eq!(array.len(), 2);
1276
1277 let first_id = array.get(0).unwrap();
1279 let first = doc.node(first_id);
1280 let name_id = first.as_map().unwrap().get_node_id(&"name".into()).unwrap();
1281 let name = doc.node(name_id);
1282 assert_eq!(name.as_primitive().unwrap().as_str(), Some("first"));
1283 }
1284
1285 #[test]
1286 fn test_eure_root_extension_with_explicit_array_entries() {
1287 let doc = eure!({
1288 %meta { speaker = "Alice" }
1289 #[] = "Hello"
1290 #[] = "World"
1291 });
1292
1293 let root_id = doc.get_root_id();
1294 let root = doc.node(root_id);
1295
1296 let meta_id = root.get_extension(&"meta".parse().unwrap()).unwrap();
1297 let meta = doc.node(meta_id);
1298 let speaker_id = meta
1299 .as_map()
1300 .unwrap()
1301 .get_node_id(&"speaker".into())
1302 .unwrap();
1303 let speaker = doc.node(speaker_id);
1304 assert_eq!(speaker.as_primitive().unwrap().as_str(), Some("Alice"));
1305
1306 let array = root.as_array().unwrap();
1307 assert_eq!(array.len(), 2);
1308
1309 let first = doc.node(array.get(0).unwrap());
1310 assert_eq!(first.as_primitive().unwrap().as_str(), Some("Hello"));
1311
1312 let second = doc.node(array.get(1).unwrap());
1313 assert_eq!(second.as_primitive().unwrap().as_str(), Some("World"));
1314 }
1315
1316 #[test]
1317 fn test_eure_tuple_index() {
1318 let doc = eure!({
1320 point.#0 = 1.5
1321 point.#1 = 2.5
1322 });
1323
1324 let root_id = doc.get_root_id();
1325 let root = doc.node(root_id);
1326 let point_id = root.as_map().unwrap().get_node_id(&"point".into()).unwrap();
1327 let point = doc.node(point_id);
1328 let tuple = point.as_tuple().unwrap();
1329 assert_eq!(tuple.len(), 2);
1330 }
1331
1332 #[test]
1333 fn test_eure_mixed_path_extension_array() {
1334 let doc = eure!({
1336 field.%items[].name = "item1"
1337 field.%items[].name = "item2"
1338 });
1339
1340 let root_id = doc.get_root_id();
1341 let root = doc.node(root_id);
1342 let field_id = root.as_map().unwrap().get_node_id(&"field".into()).unwrap();
1343 let field = doc.node(field_id);
1344
1345 let items_id = field.get_extension(&"items".parse().unwrap()).unwrap();
1347 let items = doc.node(items_id);
1348 let array = items.as_array().unwrap();
1349 assert_eq!(array.len(), 2);
1350 }
1351
1352 #[test]
1353 fn test_eure_mixed_path_array_extension() {
1354 let doc = eure!({
1356 items[].%variant = @code("text")
1357 items[].%variant = @code("number")
1358 });
1359
1360 let root_id = doc.get_root_id();
1361 let root = doc.node(root_id);
1362 let items_id = root.as_map().unwrap().get_node_id(&"items".into()).unwrap();
1363 let items = doc.node(items_id);
1364 let array = items.as_array().unwrap();
1365 assert_eq!(array.len(), 2);
1366
1367 let first_id = array.get(0).unwrap();
1369 let first = doc.node(first_id);
1370 let variant_id = first.get_extension(&"variant".parse().unwrap()).unwrap();
1371 let variant = doc.node(variant_id);
1372 assert_eq!(
1373 variant.as_primitive().unwrap().as_text().unwrap().as_str(),
1374 "text"
1375 );
1376 }
1377
1378 #[test]
1379 fn test_eure_tuple_key() {
1380 use crate::value::{ObjectKey, Tuple};
1381
1382 let doc = eure!({
1384 map.(1, "key") = "value1"
1385 map.(2, "key") = "value2"
1386 });
1387
1388 let root_id = doc.get_root_id();
1389 let root = doc.node(root_id);
1390 let map_id = root.as_map().unwrap().get_node_id(&"map".into()).unwrap();
1391 let map_node = doc.node(map_id);
1392 let map = map_node.as_map().unwrap();
1393 assert_eq!(map.len(), 2);
1394
1395 let tuple_key = ObjectKey::Tuple(Tuple(alloc::vec![1.into(), "key".into()]));
1397 let value_id = map.get_node_id(&tuple_key).unwrap();
1398 let value = doc.node(value_id);
1399 assert_eq!(value.as_primitive().unwrap().as_str(), Some("value1"));
1400 }
1401
1402 #[test]
1403 fn test_eure_tuple_key_with_bool() {
1404 use crate::value::{ObjectKey, Tuple};
1405
1406 let doc = eure!({
1408 map.(true, 1) = "yes"
1409 map.(false, 1) = "no"
1410 });
1411
1412 let root_id = doc.get_root_id();
1413 let root = doc.node(root_id);
1414 let map_id = root.as_map().unwrap().get_node_id(&"map".into()).unwrap();
1415 let map_node = doc.node(map_id);
1416 let map = map_node.as_map().unwrap();
1417 assert_eq!(map.len(), 2);
1418
1419 let tuple_key = ObjectKey::Tuple(Tuple(alloc::vec![true.into(), 1.into()]));
1421 let value_id = map.get_node_id(&tuple_key).unwrap();
1422 let value = doc.node(value_id);
1423 assert_eq!(value.as_primitive().unwrap().as_str(), Some("yes"));
1424 }
1425
1426 #[test]
1427 fn test_eure_tuple_key_with_child() {
1428 use crate::value::{ObjectKey, Tuple};
1429
1430 let doc = eure!({
1432 map.(1, 2).name = "point_a"
1433 map.(1, 2).value = 42
1434 });
1435
1436 let root_id = doc.get_root_id();
1437 let root = doc.node(root_id);
1438 let map_id = root.as_map().unwrap().get_node_id(&"map".into()).unwrap();
1439 let map_node = doc.node(map_id);
1440 let map = map_node.as_map().unwrap();
1441
1442 let tuple_key = ObjectKey::Tuple(Tuple(alloc::vec![1.into(), 2.into()]));
1444 let entry_id = map.get_node_id(&tuple_key).unwrap();
1445 let entry = doc.node(entry_id);
1446 let entry_map = entry.as_map().unwrap();
1447
1448 let name_id = entry_map.get_node_id(&"name".into()).unwrap();
1449 let name = doc.node(name_id);
1450 assert_eq!(name.as_primitive().unwrap().as_str(), Some("point_a"));
1451 }
1452
1453 #[test]
1454 fn test_eure_string_key() {
1455 let doc = eure!({
1457 field."min-length" = 3
1458 field."max-length" = 20
1459 });
1460
1461 let root_id = doc.get_root_id();
1462 let root = doc.node(root_id);
1463 let field_id = root.as_map().unwrap().get_node_id(&"field".into()).unwrap();
1464 let field = doc.node(field_id);
1465 let field_map = field.as_map().unwrap();
1466
1467 let min_id = field_map.get_node_id(&"min-length".into()).unwrap();
1469 let min_node = doc.node(min_id);
1470 assert!(matches!(
1471 min_node.as_primitive(),
1472 Some(crate::value::PrimitiveValue::Integer(_))
1473 ));
1474 }
1475
1476 #[test]
1477 fn test_eure_object_literal() {
1478 let doc = eure!({
1480 variants.click = { "x" => 1.0, "y" => 2.0 }
1481 });
1482
1483 let root_id = doc.get_root_id();
1484 let root = doc.node(root_id);
1485 let variants_id = root
1486 .as_map()
1487 .unwrap()
1488 .get_node_id(&"variants".into())
1489 .unwrap();
1490 let variants = doc.node(variants_id);
1491 let click_id = variants
1492 .as_map()
1493 .unwrap()
1494 .get_node_id(&"click".into())
1495 .unwrap();
1496 let click = doc.node(click_id);
1497 let click_map = click.as_map().unwrap();
1498
1499 assert_eq!(click_map.len(), 2);
1500 assert!(click_map.get(&"x".into()).is_some());
1501 assert!(click_map.get(&"y".into()).is_some());
1502 }
1503
1504 #[test]
1505 fn test_eure_object_literal_with_string() {
1506 let doc = eure!({
1508 schema.variants.success = { "data" => "any" }
1509 });
1510
1511 let root_id = doc.get_root_id();
1512 let root = doc.node(root_id);
1513 let schema_id = root
1514 .as_map()
1515 .unwrap()
1516 .get_node_id(&"schema".into())
1517 .unwrap();
1518 let schema = doc.node(schema_id);
1519 let variants_id = schema
1520 .as_map()
1521 .unwrap()
1522 .get_node_id(&"variants".into())
1523 .unwrap();
1524 let variants = doc.node(variants_id);
1525 let success_id = variants
1526 .as_map()
1527 .unwrap()
1528 .get_node_id(&"success".into())
1529 .unwrap();
1530 let success = doc.node(success_id);
1531 let success_map = success.as_map().unwrap();
1532
1533 let data_id = success_map.get_node_id(&"data".into()).unwrap();
1534 let data = doc.node(data_id);
1535 assert_eq!(data.as_primitive().unwrap().as_str(), Some("any"));
1536 }
1537
1538 #[test]
1539 fn test_eure_value_binding() {
1540 let doc = eure!({
1542 = @code("hello")
1543 });
1544
1545 let root_id = doc.get_root_id();
1546 let root = doc.node(root_id);
1547 let text = root.as_primitive().unwrap().as_text().unwrap();
1548 assert_eq!(text.as_str(), "hello");
1549 }
1550
1551 #[test]
1552 fn test_eure_value_binding_with_extension() {
1553 let doc = eure!({
1555 = @code("any")
1556 %variant = "literal"
1557 });
1558
1559 let root_id = doc.get_root_id();
1560 let root = doc.node(root_id);
1561
1562 let text = root.as_primitive().unwrap().as_text().unwrap();
1564 assert_eq!(text.as_str(), "any");
1565
1566 let variant_id = root.get_extension(&"variant".parse().unwrap()).unwrap();
1568 let variant = doc.node(variant_id);
1569 assert_eq!(variant.as_primitive().unwrap().as_str(), Some("literal"));
1570 }
1571
1572 #[test]
1573 fn test_eure_empty_block() {
1574 let doc = eure!({ config {} });
1576
1577 let root_id = doc.get_root_id();
1578 let root = doc.node(root_id);
1579 let config_id = root
1580 .as_map()
1581 .unwrap()
1582 .get_node_id(&"config".into())
1583 .unwrap();
1584 let config = doc.node(config_id);
1585
1586 let map = config
1588 .as_map()
1589 .expect("Empty block should create an empty map");
1590 assert!(map.is_empty());
1591 }
1592
1593 #[test]
1598 fn test_eure_null_literal() {
1599 let doc = eure!({ optional = null });
1601
1602 let root_id = doc.get_root_id();
1603 let root = doc.node(root_id);
1604 let opt_id = root
1605 .as_map()
1606 .unwrap()
1607 .get_node_id(&"optional".into())
1608 .unwrap();
1609 let opt = doc.node(opt_id);
1610 assert!(matches!(
1611 opt.as_primitive(),
1612 Some(crate::value::PrimitiveValue::Null)
1613 ));
1614 }
1615
1616 #[test]
1617 fn test_eure_null_root() {
1618 let doc = eure!({
1620 = null
1621 });
1622
1623 let root_id = doc.get_root_id();
1624 let root = doc.node(root_id);
1625 assert!(matches!(
1626 root.as_primitive(),
1627 Some(crate::value::PrimitiveValue::Null)
1628 ));
1629 }
1630
1631 #[test]
1632 fn test_eure_hole_literal() {
1633 use crate::document::node::NodeValue;
1634
1635 let doc = eure!({
1637 placeholder = !
1638 });
1639
1640 let root_id = doc.get_root_id();
1641 let root = doc.node(root_id);
1642 let placeholder_id = root
1643 .as_map()
1644 .unwrap()
1645 .get_node_id(&"placeholder".into())
1646 .unwrap();
1647 let placeholder = doc.node(placeholder_id);
1648 assert_eq!(placeholder.content, NodeValue::Hole(None));
1649 }
1650
1651 #[test]
1652 fn test_eure_hole_root() {
1653 use crate::document::node::NodeValue;
1654
1655 let doc = eure!({
1657 = !
1658 });
1659
1660 let root_id = doc.get_root_id();
1661 let root = doc.node(root_id);
1662 assert_eq!(root.content, NodeValue::Hole(None));
1663 }
1664
1665 #[test]
1666 fn test_eure_code_inline_implicit() {
1667 let doc = eure!({
1669 snippet = @code("let x = 1")
1670 });
1671
1672 let root_id = doc.get_root_id();
1673 let root = doc.node(root_id);
1674 let snippet_id = root
1675 .as_map()
1676 .unwrap()
1677 .get_node_id(&"snippet".into())
1678 .unwrap();
1679 let snippet = doc.node(snippet_id);
1680 let text = snippet.as_primitive().unwrap().as_text().unwrap();
1681 assert_eq!(text.as_str(), "let x = 1");
1682 assert!(text.language.is_implicit());
1683 }
1684
1685 #[test]
1686 fn test_eure_code_inline_with_language() {
1687 let doc = eure!({
1689 query = @code("sql", "SELECT * FROM users")
1690 });
1691
1692 let root_id = doc.get_root_id();
1693 let root = doc.node(root_id);
1694 let query_id = root.as_map().unwrap().get_node_id(&"query".into()).unwrap();
1695 let query = doc.node(query_id);
1696 let text = query.as_primitive().unwrap().as_text().unwrap();
1697 assert_eq!(text.as_str(), "SELECT * FROM users");
1698 assert_eq!(text.language.as_str(), Some("sql"));
1699 }
1700
1701 #[test]
1702 fn test_eure_block_implicit() {
1703 let doc = eure!({
1705 script = @block("fn main() {}")
1706 });
1707
1708 let root_id = doc.get_root_id();
1709 let root = doc.node(root_id);
1710 let script_id = root
1711 .as_map()
1712 .unwrap()
1713 .get_node_id(&"script".into())
1714 .unwrap();
1715 let script = doc.node(script_id);
1716 let text = script.as_primitive().unwrap().as_text().unwrap();
1717 assert_eq!(text.as_str(), "fn main() {}\n");
1719 assert!(text.language.is_implicit());
1720 }
1721
1722 #[test]
1723 fn test_eure_block_with_language() {
1724 let doc = eure!({
1726 code = @block("rust", "fn main() {\n println!(\"Hello\");\n}")
1727 });
1728
1729 let root_id = doc.get_root_id();
1730 let root = doc.node(root_id);
1731 let code_id = root.as_map().unwrap().get_node_id(&"code".into()).unwrap();
1732 let code = doc.node(code_id);
1733 let text = code.as_primitive().unwrap().as_text().unwrap();
1734 assert_eq!(text.language.as_str(), Some("rust"));
1735 assert!(text.as_str().contains("println!"));
1736 }
1737
1738 #[test]
1739 fn test_eure_code_at_root() {
1740 let doc = eure!({
1742 = @code("hello")
1743 });
1744
1745 let root_id = doc.get_root_id();
1746 let root = doc.node(root_id);
1747 let text = root.as_primitive().unwrap().as_text().unwrap();
1748 assert_eq!(text.as_str(), "hello");
1749 }
1750
1751 #[test]
1752 fn test_eure_code_with_language_at_root() {
1753 let doc = eure!({
1755 = @code("sql", "SELECT 1")
1756 });
1757
1758 let root_id = doc.get_root_id();
1759 let root = doc.node(root_id);
1760 let text = root.as_primitive().unwrap().as_text().unwrap();
1761 assert_eq!(text.as_str(), "SELECT 1");
1762 assert_eq!(text.language.as_str(), Some("sql"));
1763 }
1764
1765 #[test]
1766 fn test_eure_block_at_root() {
1767 let doc = eure!({
1769 = @block("fn main() {}")
1770 });
1771
1772 let root_id = doc.get_root_id();
1773 let root = doc.node(root_id);
1774 let text = root.as_primitive().unwrap().as_text().unwrap();
1775 assert_eq!(text.as_str(), "fn main() {}\n");
1776 assert!(text.language.is_implicit());
1777 }
1778
1779 #[test]
1780 fn test_eure_block_with_language_at_root() {
1781 let doc = eure!({
1783 = @block("rust", "fn main() {}")
1784 });
1785
1786 let root_id = doc.get_root_id();
1787 let root = doc.node(root_id);
1788 let text = root.as_primitive().unwrap().as_text().unwrap();
1789 assert_eq!(text.as_str(), "fn main() {}\n");
1790 assert_eq!(text.language.as_str(), Some("rust"));
1791 }
1792
1793 #[test]
1798 fn test_eure_array_specific_index() {
1799 let doc = eure!({
1801 items[0] = "first"
1802 items[1] = "second"
1803 });
1804
1805 let root_id = doc.get_root_id();
1806 let root = doc.node(root_id);
1807 let items_id = root.as_map().unwrap().get_node_id(&"items".into()).unwrap();
1808 let items = doc.node(items_id);
1809 let array = items.as_array().unwrap();
1810 assert_eq!(array.len(), 2);
1811
1812 let first_id = array.get(0).unwrap();
1814 let first = doc.node(first_id);
1815 assert_eq!(first.as_primitive().unwrap().as_str(), Some("first"));
1816
1817 let second_id = array.get(1).unwrap();
1818 let second = doc.node(second_id);
1819 assert_eq!(second.as_primitive().unwrap().as_str(), Some("second"));
1820 }
1821
1822 #[test]
1823 fn test_eure_array_index_with_child() {
1824 let doc = eure!({
1826 items[0].name = "first"
1827 items[0].value = 1
1828 items[1].name = "second"
1829 });
1830
1831 let root_id = doc.get_root_id();
1832 let root = doc.node(root_id);
1833 let items_id = root.as_map().unwrap().get_node_id(&"items".into()).unwrap();
1834 let items = doc.node(items_id);
1835 let array = items.as_array().unwrap();
1836 assert_eq!(array.len(), 2);
1837
1838 let first_id = array.get(0).unwrap();
1840 let first = doc.node(first_id);
1841 let name_id = first.as_map().unwrap().get_node_id(&"name".into()).unwrap();
1842 let name = doc.node(name_id);
1843 assert_eq!(name.as_primitive().unwrap().as_str(), Some("first"));
1844 }
1845
1846 #[test]
1847 fn test_eure_nested_empty_blocks() {
1848 let doc = eure!({
1850 a {
1851 b {
1852 c {}
1853 }
1854 }
1855 });
1856
1857 let root_id = doc.get_root_id();
1858 let root = doc.node(root_id);
1859
1860 let a_id = root.as_map().unwrap().get_node_id(&"a".into()).unwrap();
1861 let a = doc.node(a_id);
1862
1863 let b_id = a.as_map().unwrap().get_node_id(&"b".into()).unwrap();
1864 let b = doc.node(b_id);
1865
1866 let c_id = b.as_map().unwrap().get_node_id(&"c".into()).unwrap();
1867 let c = doc.node(c_id);
1868
1869 let map = c.as_map().expect("c should be an empty map");
1871 assert!(map.is_empty());
1872 }
1873
1874 #[test]
1875 fn test_eure_multiple_extensions() {
1876 let doc = eure!({
1878 field.%variant = @code("text")
1879 field.%"variant-repr" = "internal"
1880 field.%schema = "custom"
1881 });
1882
1883 let root_id = doc.get_root_id();
1884 let root = doc.node(root_id);
1885 let field_id = root.as_map().unwrap().get_node_id(&"field".into()).unwrap();
1886 let field = doc.node(field_id);
1887
1888 assert!(field.get_extension(&"variant".parse().unwrap()).is_some());
1890 assert!(
1891 field
1892 .get_extension(&"variant-repr".parse().unwrap())
1893 .is_some()
1894 );
1895 assert!(field.get_extension(&"schema".parse().unwrap()).is_some());
1896 }
1897
1898 #[test]
1899 fn test_eure_extension_on_array_element() {
1900 let doc = eure!({
1903 items[0].%variant = @code("text")
1904 items[0].value = "first"
1905 items[1].%variant = @code("number")
1906 items[1].value = 42
1907 });
1908
1909 let root_id = doc.get_root_id();
1910 let root = doc.node(root_id);
1911 let items_id = root.as_map().unwrap().get_node_id(&"items".into()).unwrap();
1912 let items = doc.node(items_id);
1913 let array = items.as_array().unwrap();
1914 assert_eq!(array.len(), 2);
1915
1916 let first_id = array.get(0).unwrap();
1918 let first = doc.node(first_id);
1919 let variant_id = first.get_extension(&"variant".parse().unwrap()).unwrap();
1920 let variant = doc.node(variant_id);
1921 assert_eq!(
1922 variant.as_primitive().unwrap().as_text().unwrap().as_str(),
1923 "text"
1924 );
1925 let value_id = first
1926 .as_map()
1927 .unwrap()
1928 .get_node_id(&"value".into())
1929 .unwrap();
1930 let value = doc.node(value_id);
1931 assert_eq!(value.as_primitive().unwrap().as_str(), Some("first"));
1932
1933 let second_id = array.get(1).unwrap();
1935 let second = doc.node(second_id);
1936 let variant_id = second.get_extension(&"variant".parse().unwrap()).unwrap();
1937 let variant = doc.node(variant_id);
1938 assert_eq!(
1939 variant.as_primitive().unwrap().as_text().unwrap().as_str(),
1940 "number"
1941 );
1942 }
1943
1944 #[test]
1945 fn test_eure_deep_nesting() {
1946 let doc = eure!({ a.b.c.d.e.f = "deep" });
1948
1949 let root_id = doc.get_root_id();
1950 let root = doc.node(root_id);
1951
1952 let a_id = root.as_map().unwrap().get_node_id(&"a".into()).unwrap();
1953 let a = doc.node(a_id);
1954 let b_id = a.as_map().unwrap().get_node_id(&"b".into()).unwrap();
1955 let b = doc.node(b_id);
1956 let c_id = b.as_map().unwrap().get_node_id(&"c".into()).unwrap();
1957 let c = doc.node(c_id);
1958 let d_id = c.as_map().unwrap().get_node_id(&"d".into()).unwrap();
1959 let d = doc.node(d_id);
1960 let e_id = d.as_map().unwrap().get_node_id(&"e".into()).unwrap();
1961 let e = doc.node(e_id);
1962 let f_id = e.as_map().unwrap().get_node_id(&"f".into()).unwrap();
1963 let f = doc.node(f_id);
1964
1965 assert_eq!(f.as_primitive().unwrap().as_str(), Some("deep"));
1966 }
1967
1968 #[test]
1969 fn test_eure_empty_array_literal() {
1970 let doc = eure!({ items = [] });
1972
1973 let root_id = doc.get_root_id();
1974 let root = doc.node(root_id);
1975 let items_id = root.as_map().unwrap().get_node_id(&"items".into()).unwrap();
1976 let items = doc.node(items_id);
1977 let array = items.as_array().unwrap();
1978 assert!(array.is_empty());
1979 }
1980
1981 #[test]
1982 fn test_eure_empty_tuple_literal() {
1983 let doc = eure!({ point = () });
1985
1986 let root_id = doc.get_root_id();
1987 let root = doc.node(root_id);
1988 let point_id = root.as_map().unwrap().get_node_id(&"point".into()).unwrap();
1989 let point = doc.node(point_id);
1990 let tuple = point.as_tuple().unwrap();
1991 assert!(tuple.is_empty());
1992 }
1993
1994 #[test]
1995 fn test_eure_empty_map_literal() {
1996 let doc = eure!({ data {} });
1999
2000 let root_id = doc.get_root_id();
2001 let root = doc.node(root_id);
2002 let data_id = root.as_map().unwrap().get_node_id(&"data".into()).unwrap();
2003 let data = doc.node(data_id);
2004 let map = data.as_map().unwrap();
2005 assert!(map.is_empty());
2006 }
2007
2008 #[test]
2009 fn test_eure_mixed_null_and_values() {
2010 let doc = eure!({
2012 name = "Alice"
2013 age = null
2014 active = true
2015 score = null
2016 });
2017
2018 let root_id = doc.get_root_id();
2019 let root = doc.node(root_id);
2020 let map = root.as_map().unwrap();
2021 assert_eq!(map.len(), 4);
2022
2023 let age_id = map.get_node_id(&"age".into()).unwrap();
2024 let age = doc.node(age_id);
2025 assert!(matches!(
2026 age.as_primitive(),
2027 Some(crate::value::PrimitiveValue::Null)
2028 ));
2029 }
2030
2031 #[test]
2036 fn test_eure_section_basic() {
2037 let doc = eure!({
2039 @user
2040 name = "Alice"
2041 age = 30
2042 });
2043
2044 let root_id = doc.get_root_id();
2045 let root = doc.node(root_id);
2046 let user_id = root.as_map().unwrap().get_node_id(&"user".into()).unwrap();
2047 let user = doc.node(user_id);
2048 let name_id = user.as_map().unwrap().get_node_id(&"name".into()).unwrap();
2049 let name = doc.node(name_id);
2050 assert_eq!(name.as_primitive().unwrap().as_str(), Some("Alice"));
2051 }
2052
2053 #[test]
2054 fn test_eure_section_multiple() {
2055 let doc = eure!({
2057 @user
2058 name = "Alice"
2059
2060 @settings
2061 theme = "dark"
2062 });
2063
2064 let root_id = doc.get_root_id();
2065 let root = doc.node(root_id);
2066
2067 let user_id = root.as_map().unwrap().get_node_id(&"user".into()).unwrap();
2068 let user = doc.node(user_id);
2069 assert!(user.as_map().unwrap().get_node_id(&"name".into()).is_some());
2070
2071 let settings_id = root
2072 .as_map()
2073 .unwrap()
2074 .get_node_id(&"settings".into())
2075 .unwrap();
2076 let settings = doc.node(settings_id);
2077 assert!(
2078 settings
2079 .as_map()
2080 .unwrap()
2081 .get_node_id(&"theme".into())
2082 .is_some()
2083 );
2084 }
2085
2086 #[test]
2087 fn test_eure_section_dotted_path() {
2088 let doc = eure!({
2090 @user.profile
2091 name = "Alice"
2092 });
2093
2094 let root_id = doc.get_root_id();
2095 let root = doc.node(root_id);
2096 let user_id = root.as_map().unwrap().get_node_id(&"user".into()).unwrap();
2097 let user = doc.node(user_id);
2098 let profile_id = user
2099 .as_map()
2100 .unwrap()
2101 .get_node_id(&"profile".into())
2102 .unwrap();
2103 let profile = doc.node(profile_id);
2104 assert!(
2105 profile
2106 .as_map()
2107 .unwrap()
2108 .get_node_id(&"name".into())
2109 .is_some()
2110 );
2111 }
2112
2113 #[test]
2114 fn test_eure_section_root_array_marker() {
2115 let doc = eure!({
2116 @[]
2117 text = "Hello"
2118 @[]
2119 text = "World"
2120 });
2121
2122 let root_id = doc.get_root_id();
2123 let root = doc.node(root_id);
2124 let array = root.as_array().unwrap();
2125 assert_eq!(array.len(), 2);
2126
2127 let first = doc.node(array.get(0).unwrap());
2128 let first_text_id = first.as_map().unwrap().get_node_id(&"text".into()).unwrap();
2129 let first_text = doc.node(first_text_id);
2130 assert_eq!(first_text.as_primitive().unwrap().as_str(), Some("Hello"));
2131
2132 let second = doc.node(array.get(1).unwrap());
2133 let second_text_id = second
2134 .as_map()
2135 .unwrap()
2136 .get_node_id(&"text".into())
2137 .unwrap();
2138 let second_text = doc.node(second_text_id);
2139 assert_eq!(second_text.as_primitive().unwrap().as_str(), Some("World"));
2140 }
2141
2142 #[test]
2143 fn test_eure_section_explicit_array_continuation() {
2144 let doc = eure!({
2145 @dialog #[]
2146 text = "Hello"
2147 @dialog #[]
2148 text = "World"
2149 });
2150
2151 let root_id = doc.get_root_id();
2152 let root = doc.node(root_id);
2153 let dialog_id = root
2154 .as_map()
2155 .unwrap()
2156 .get_node_id(&"dialog".into())
2157 .unwrap();
2158 let dialog = doc.node(dialog_id);
2159 let array = dialog.as_array().unwrap();
2160 assert_eq!(array.len(), 2);
2161
2162 let first = doc.node(array.get(0).unwrap());
2163 let first_text_id = first.as_map().unwrap().get_node_id(&"text".into()).unwrap();
2164 let first_text = doc.node(first_text_id);
2165 assert_eq!(first_text.as_primitive().unwrap().as_str(), Some("Hello"));
2166
2167 let second = doc.node(array.get(1).unwrap());
2168 let second_text_id = second
2169 .as_map()
2170 .unwrap()
2171 .get_node_id(&"text".into())
2172 .unwrap();
2173 let second_text = doc.node(second_text_id);
2174 assert_eq!(second_text.as_primitive().unwrap().as_str(), Some("World"));
2175 }
2176
2177 #[test]
2178 fn test_eure_section_with_block() {
2179 let doc = eure!({
2181 @user {
2182 name = "Alice"
2183 age = 30
2184 }
2185 });
2186
2187 let root_id = doc.get_root_id();
2188 let root = doc.node(root_id);
2189 let user_id = root.as_map().unwrap().get_node_id(&"user".into()).unwrap();
2190 let user = doc.node(user_id);
2191 assert!(user.as_map().unwrap().get_node_id(&"name".into()).is_some());
2192 assert!(user.as_map().unwrap().get_node_id(&"age".into()).is_some());
2193 }
2194
2195 #[test]
2196 fn test_eure_section_block_with_nested() {
2197 let doc = eure!({
2199 @config {
2200 server {
2201 host = "localhost"
2202 port = 8080
2203 }
2204 debug = true
2205 }
2206 });
2207
2208 let root_id = doc.get_root_id();
2209 let root = doc.node(root_id);
2210 let config_id = root
2211 .as_map()
2212 .unwrap()
2213 .get_node_id(&"config".into())
2214 .unwrap();
2215 let config = doc.node(config_id);
2216 assert!(
2217 config
2218 .as_map()
2219 .unwrap()
2220 .get_node_id(&"server".into())
2221 .is_some()
2222 );
2223 assert!(
2224 config
2225 .as_map()
2226 .unwrap()
2227 .get_node_id(&"debug".into())
2228 .is_some()
2229 );
2230
2231 let server_id = config
2232 .as_map()
2233 .unwrap()
2234 .get_node_id(&"server".into())
2235 .unwrap();
2236 let server = doc.node(server_id);
2237 assert!(
2238 server
2239 .as_map()
2240 .unwrap()
2241 .get_node_id(&"host".into())
2242 .is_some()
2243 );
2244 assert!(
2245 server
2246 .as_map()
2247 .unwrap()
2248 .get_node_id(&"port".into())
2249 .is_some()
2250 );
2251 }
2252
2253 #[test]
2254 fn test_eure_section_block_multiple() {
2255 let doc = eure!({
2257 @user {
2258 name = "Alice"
2259 }
2260 @settings {
2261 theme = "dark"
2262 }
2263 });
2264
2265 let root_id = doc.get_root_id();
2266 let root = doc.node(root_id);
2267 assert!(root.as_map().unwrap().get_node_id(&"user".into()).is_some());
2268 assert!(
2269 root.as_map()
2270 .unwrap()
2271 .get_node_id(&"settings".into())
2272 .is_some()
2273 );
2274 }
2275
2276 #[test]
2277 fn test_eure_section_block_dotted_path() {
2278 let doc = eure!({
2280 @server.config {
2281 host = "localhost"
2282 port = 8080
2283 }
2284 });
2285
2286 let root_id = doc.get_root_id();
2287 let root = doc.node(root_id);
2288 let server_id = root
2289 .as_map()
2290 .unwrap()
2291 .get_node_id(&"server".into())
2292 .unwrap();
2293 let server = doc.node(server_id);
2294 let config_id = server
2295 .as_map()
2296 .unwrap()
2297 .get_node_id(&"config".into())
2298 .unwrap();
2299 let config = doc.node(config_id);
2300 assert!(
2301 config
2302 .as_map()
2303 .unwrap()
2304 .get_node_id(&"host".into())
2305 .is_some()
2306 );
2307 assert!(
2308 config
2309 .as_map()
2310 .unwrap()
2311 .get_node_id(&"port".into())
2312 .is_some()
2313 );
2314 }
2315
2316 #[test]
2317 fn test_eure_section_block_empty() {
2318 let doc = eure!({
2320 @empty {}
2321 });
2322
2323 let root_id = doc.get_root_id();
2324 let root = doc.node(root_id);
2325 let empty_id = root.as_map().unwrap().get_node_id(&"empty".into()).unwrap();
2326 let empty = doc.node(empty_id);
2327 assert!(empty.as_map().unwrap().is_empty());
2329 }
2330
2331 #[test]
2332 fn test_eure_section_mixed_styles() {
2333 let doc = eure!({
2335 @user {
2336 name = "Alice"
2337 }
2338
2339 @settings
2340 theme = "dark"
2341 debug = true
2342
2343 @logging {
2344 level = "info"
2345 }
2346 });
2347
2348 let root_id = doc.get_root_id();
2349 let root = doc.node(root_id);
2350
2351 let user_id = root.as_map().unwrap().get_node_id(&"user".into()).unwrap();
2353 let user = doc.node(user_id);
2354 assert!(user.as_map().unwrap().get_node_id(&"name".into()).is_some());
2355
2356 let settings_id = root
2358 .as_map()
2359 .unwrap()
2360 .get_node_id(&"settings".into())
2361 .unwrap();
2362 let settings = doc.node(settings_id);
2363 assert!(
2364 settings
2365 .as_map()
2366 .unwrap()
2367 .get_node_id(&"theme".into())
2368 .is_some()
2369 );
2370 assert!(
2371 settings
2372 .as_map()
2373 .unwrap()
2374 .get_node_id(&"debug".into())
2375 .is_some()
2376 );
2377
2378 let logging_id = root
2380 .as_map()
2381 .unwrap()
2382 .get_node_id(&"logging".into())
2383 .unwrap();
2384 let logging = doc.node(logging_id);
2385 assert!(
2386 logging
2387 .as_map()
2388 .unwrap()
2389 .get_node_id(&"level".into())
2390 .is_some()
2391 );
2392 }
2393
2394 #[test]
2395 fn test_eure_section_in_section_block() {
2396 let doc = eure!({
2398 @ settings {
2399 theme = "dark"
2400 @ logging
2401 level = "info"
2402 }
2403 });
2404
2405 let settings = doc
2406 .parse_context(doc.get_root_id())
2407 .parse_record()
2408 .expect("Failed to parse record")
2409 .field_record("settings")
2410 .expect("Failed to parse settings");
2411 let theme = settings
2412 .parse_field::<&str>("theme")
2413 .expect("Failed to parse theme");
2414 let logging = settings
2415 .field_record("logging")
2416 .expect("Failed to parse logging")
2417 .parse_field::<&str>("level")
2418 .expect("Failed to parse level");
2419 settings
2420 .deny_unknown_fields()
2421 .expect("Failed to deny unknown fields");
2422 assert_eq!(theme, "dark");
2423 assert_eq!(logging, "info");
2424 }
2425
2426 #[test]
2427 fn test_eure_variable_text() {
2428 use crate::text::Text;
2430 let code = Text::inline_implicit("fn main() {}");
2431 let doc = eure!({ snippet = code });
2432
2433 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2434 let snippet_ctx = root.field("snippet").unwrap();
2435 let snippet_node = doc.node(snippet_ctx.node_id());
2436 let text = snippet_node.as_primitive().unwrap().as_text().unwrap();
2437 assert_eq!(text.as_str(), "fn main() {}");
2438 }
2439
2440 #[test]
2441 fn test_eure_variable_in_array() {
2442 use alloc::vec::Vec;
2444 let first = "one";
2445 let second = "two";
2446 let third = "three";
2447 let doc = eure!({ items = [first, second, third] });
2448
2449 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2450 let items = root.parse_field::<Vec<&str>>("items").unwrap();
2451 assert_eq!(items, vec!["one", "two", "three"]);
2452 }
2453
2454 #[test]
2455 fn test_eure_variable_in_tuple() {
2456 let x = 1.5;
2458 let y = 2.5;
2459 let doc = eure!({ point = (x, y) });
2460
2461 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2462 let point = root.parse_field::<(f64, f64)>("point").unwrap();
2463 assert_eq!(point, (1.5, 2.5));
2464 }
2465
2466 #[test]
2467 fn test_eure_variable_in_object_literal() {
2468 let x_val = 10.0;
2470 let y_val = 20.0;
2471 let doc = eure!({
2472 coords = {
2473 "x" => x_val
2474 "y" => y_val
2475 }
2476 });
2477
2478 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2479 let coords = root.field_record("coords").unwrap();
2480 let x = coords.parse_field::<f64>("x").unwrap();
2481 let y = coords.parse_field::<f64>("y").unwrap();
2482 assert_eq!(x, 10.0);
2483 assert_eq!(y, 20.0);
2484 }
2485
2486 #[test]
2487 #[allow(clippy::bool_assert_comparison)] fn test_eure_variable_mixed_with_literals() {
2489 let username = "bob";
2491 let is_active = true;
2492 let doc = eure!({
2493 user.name = username
2494 user.active = is_active
2495 user.role = "admin"
2496 user.level = 5
2497 });
2498
2499 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2500 let user = root.field_record("user").unwrap();
2501 assert_eq!(user.parse_field::<&str>("name").unwrap(), "bob");
2502 assert_eq!(user.parse_field::<bool>("active").unwrap(), true);
2503 assert_eq!(user.parse_field::<&str>("role").unwrap(), "admin");
2504 assert_eq!(user.parse_field::<i32>("level").unwrap(), 5);
2505 }
2506
2507 #[test]
2508 fn test_eure_variable_in_nested_array() {
2509 use alloc::vec::Vec;
2511 let tag1 = "rust";
2512 let tag2 = "macro";
2513 let doc = eure!({
2514 tags[] = tag1
2515 tags[] = tag2
2516 });
2517
2518 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2519 let tags = root.parse_field::<Vec<&str>>("tags").unwrap();
2520 assert_eq!(tags, vec!["rust", "macro"]);
2521 }
2522
2523 #[test]
2524 fn test_eure_variable_at_root() {
2525 let value = 42;
2527 let doc = eure!({
2528 = value
2529 });
2530
2531 let ctx = doc.parse_context(doc.get_root_id());
2532 let root_value = ctx.parse::<i32>().unwrap();
2533 assert_eq!(root_value, 42);
2534 }
2535
2536 #[test]
2537 fn test_eure_variable_in_section() {
2538 let theme_value = "dark";
2540 let lang_value = "en";
2541 let doc = eure!({
2542 @settings
2543 theme = theme_value
2544 language = lang_value
2545 });
2546
2547 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2548 let settings = root.field_record("settings").unwrap();
2549 assert_eq!(settings.parse_field::<&str>("theme").unwrap(), "dark");
2550 assert_eq!(settings.parse_field::<&str>("language").unwrap(), "en");
2551 }
2552
2553 #[test]
2554 fn test_eure_variable_null_and_primitive() {
2555 use crate::value::PrimitiveValue;
2557 let null_value = PrimitiveValue::Null;
2558 let doc = eure!({ optional = null_value });
2559
2560 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2561 let optional_ctx = root.field("optional").unwrap();
2562 let optional_node = doc.node(optional_ctx.node_id());
2563 assert!(matches!(
2564 optional_node.as_primitive().unwrap(),
2565 PrimitiveValue::Null
2566 ));
2567 }
2568
2569 #[test]
2574 fn test_eure_source_empty() {
2575 let source_doc = eure_source!({});
2576 assert_eq!(source_doc.document(), &EureDocument::new_empty());
2577 assert!(source_doc.root_source().bindings.is_empty());
2578 assert!(source_doc.root_source().sections.is_empty());
2579 }
2580
2581 #[test]
2582 fn test_eure_source_simple_bindings() {
2583 let source_doc = eure_source!({
2584 name = "Alice"
2585 age = 30
2586 });
2587
2588 let doc = source_doc.document();
2590 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2591 assert_eq!(root.parse_field::<&str>("name").unwrap(), "Alice");
2592 assert_eq!(root.parse_field::<i64>("age").unwrap(), 30);
2593
2594 let root_source = source_doc.root_source();
2596 assert_eq!(root_source.bindings.len(), 2);
2597 assert!(root_source.sections.is_empty());
2598 }
2599
2600 #[test]
2601 fn test_eure_source_nested() {
2602 use crate::source::BindSource;
2603
2604 let source_doc = eure_source!({
2605 user {
2606 name = "Bob"
2607 active = true
2608 }
2609 });
2610
2611 let doc = source_doc.document();
2612 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2613 let user = root.field_record("user").unwrap();
2614 assert_eq!(user.parse_field::<&str>("name").unwrap(), "Bob");
2615 assert!(user.parse_field::<bool>("active").unwrap());
2616
2617 let root_source = source_doc.root_source();
2619 assert_eq!(root_source.bindings.len(), 1);
2620 match &root_source.bindings[0].bind {
2621 BindSource::Block(source_id) => {
2622 let inner = source_doc.source(*source_id);
2623 assert_eq!(inner.bindings.len(), 2);
2624 }
2625 _ => panic!("Expected BindSource::Block"),
2626 }
2627 }
2628
2629 #[test]
2630 fn test_eure_generic_entry_point() {
2631 use crate::document::constructor::DocumentConstructor;
2633
2634 let mut c = DocumentConstructor::new();
2635 eure!(c; {
2636 x = 1
2637 y = 2
2638 });
2639 let doc = c.finish();
2640
2641 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2642 assert_eq!(root.parse_field::<i64>("x").unwrap(), 1);
2643 assert_eq!(root.parse_field::<i64>("y").unwrap(), 2);
2644 }
2645
2646 #[test]
2647 fn test_eure_source_generic_entry_point() {
2648 use crate::document::source_constructor::SourceConstructor;
2650
2651 let mut c = SourceConstructor::new();
2652 eure!(c; {
2653 message = "hello"
2654 });
2655 let source_doc = c.finish();
2656
2657 let doc = source_doc.document();
2658 let root = doc.parse_context(doc.get_root_id()).parse_record().unwrap();
2659 assert_eq!(root.parse_field::<&str>("message").unwrap(), "hello");
2660 }
2661}