1#![no_std]
2extern crate alloc;
3
4#[cfg(feature = "std")]
5extern crate std;
6
7pub use text::Text;
9
10pub mod tree;
12
13pub mod identifier;
15
16pub mod text;
18
19pub mod value;
21
22pub mod document;
24
25pub mod path;
27
28pub mod data_model;
30
31pub mod parse;
33
34#[cfg(feature = "std")]
35pub use ahash::AHashMap as Map;
36#[cfg(not(feature = "std"))]
37pub type Map<K, V> = alloc::collections::BTreeMap<K, V>;
38
39pub(crate) mod prelude_internal {
40 #![allow(unused_imports)]
41 #![allow(deprecated)]
42 pub use crate::Map;
43 pub use crate::data_model::*;
44 pub use crate::document::constructor::DocumentConstructor;
45 pub use crate::document::node::{Node, NodeMut, NodeValue};
46 pub use crate::document::{EureDocument, InsertError, InsertErrorKind, NodeId};
47 pub use crate::identifier::Identifier;
48 pub use crate::path::{EurePath, PathSegment};
49 pub use crate::text::{Language, SyntaxHint, Text, TextParseError};
50 pub use crate::value::PrimitiveValue;
51 pub use crate::value::{ObjectKey, Value};
52 pub use alloc::boxed::Box;
53 pub use alloc::{string::String, string::ToString, vec, vec::Vec};
54 pub use thisisplural::Plural;
55}
56
57#[macro_export]
128macro_rules! eure {
129 ({}) => {{
135 $crate::document::EureDocument::new_empty()
136 }};
137
138 ({ $($body:tt)* }) => {{
140 let mut c = $crate::document::constructor::DocumentConstructor::new();
141 $crate::eure!(@body c; $($body)*);
142 c.finish()
143 }};
144
145 (@body $c:ident;) => {};
151
152 (@body $c:ident; = $val:expr $(, $($tail:tt)*)?) => {{
154 $c.bind_from($val).unwrap();
155 $($crate::eure!(@body $c; $($tail)*);)?
156 }};
157
158 (@body $c:ident; $($tokens:tt)+) => {{
160 let scope = $c.begin_scope();
161 $crate::eure!(@parse_seg $c scope; $($tokens)+);
162 }};
163
164 (@parse_seg $c:ident $scope:ident; $seg:ident $($rest:tt)*) => {{
170 $c.navigate($crate::path::PathSegment::Ident(
171 $crate::identifier::Identifier::new_unchecked(stringify!($seg))
172 )).unwrap();
173 $crate::eure!(@after_seg $c $scope; $($rest)*);
174 }};
175
176 (@parse_seg $c:ident $scope:ident; % $ext:ident $($rest:tt)*) => {{
178 $c.navigate($crate::path::PathSegment::Extension(
179 $crate::identifier::Identifier::new_unchecked(stringify!($ext))
180 )).unwrap();
181 $crate::eure!(@after_seg $c $scope; $($rest)*);
182 }};
183
184 (@parse_seg $c:ident $scope:ident; % $ext:literal $($rest:tt)*) => {{
186 $c.navigate($crate::path::PathSegment::Extension(
187 $ext.parse().unwrap()
188 )).unwrap();
189 $crate::eure!(@after_seg $c $scope; $($rest)*);
190 }};
191
192 (@parse_seg $c:ident $scope:ident; # $idx:literal $($rest:tt)*) => {{
194 $c.navigate($crate::path::PathSegment::TupleIndex($idx)).unwrap();
195 $crate::eure!(@after_seg $c $scope; $($rest)*);
196 }};
197
198 (@parse_seg $c:ident $scope:ident; ($($tuple:tt)*) $($rest:tt)*) => {{
200 let key = $crate::eure!(@build_tuple_key; $($tuple)*);
201 $c.navigate($crate::path::PathSegment::Value(key)).unwrap();
202 $crate::eure!(@after_seg $c $scope; $($rest)*);
203 }};
204
205 (@parse_seg $c:ident $scope:ident; $key:literal $($rest:tt)*) => {{
207 $c.navigate($crate::path::PathSegment::Value($key.into())).unwrap();
208 $crate::eure!(@after_seg $c $scope; $($rest)*);
209 }};
210
211 (@build_tuple_key;) => {{
217 $crate::value::ObjectKey::Tuple($crate::value::Tuple(Default::default()))
218 }};
219
220 (@build_tuple_key; $($item:expr),+ $(,)?) => {{
222 $crate::value::ObjectKey::Tuple($crate::value::Tuple::from_iter(
223 [$(<_ as Into<$crate::value::ObjectKey>>::into($item)),+]
224 ))
225 }};
226
227 (@after_seg $c:ident $scope:ident; [$($arr:tt)*] $($rest:tt)*) => {{
233 $crate::eure!(@handle_arr $c $scope [$($arr)*]; $($rest)*);
234 }};
235
236 (@after_seg $c:ident $scope:ident; $($rest:tt)*) => {{
238 $crate::eure!(@after_arr $c $scope; $($rest)*);
239 }};
240
241 (@handle_arr $c:ident $scope:ident []; $($rest:tt)*) => {{
247 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
248 $crate::eure!(@after_arr $c $scope; $($rest)*);
249 }};
250
251 (@handle_arr $c:ident $scope:ident [$idx:literal]; $($rest:tt)*) => {{
253 $c.navigate($crate::path::PathSegment::ArrayIndex(Some($idx))).unwrap();
254 $crate::eure!(@after_arr $c $scope; $($rest)*);
255 }};
256
257 (@after_arr $c:ident $scope:ident; . $($rest:tt)+) => {{
263 $crate::eure!(@parse_seg $c $scope; $($rest)+);
264 }};
265
266 (@after_arr $c:ident $scope:ident; = [$($items:expr),* $(,)?] $(, $($tail:tt)*)?) => {{
268 $c.bind_empty_array().unwrap();
269 $(
270 let item_scope = $c.begin_scope();
271 $c.navigate($crate::path::PathSegment::ArrayIndex(None)).unwrap();
272 $c.bind_from($items).unwrap();
273 $c.end_scope(item_scope).unwrap();
274 )*
275 $c.end_scope($scope).unwrap();
276 $($crate::eure!(@body $c; $($tail)*);)?
277 }};
278
279 (@after_arr $c:ident $scope:ident; = ($($items:expr),* $(,)?) $(, $($tail:tt)*)?) => {{
281 $c.bind_empty_tuple().unwrap();
282 #[allow(unused_mut)]
283 let mut _idx: u8 = 0;
284 $(
285 let item_scope = $c.begin_scope();
286 $c.navigate($crate::path::PathSegment::TupleIndex(_idx)).unwrap();
287 $c.bind_from($items).unwrap();
288 $c.end_scope(item_scope).unwrap();
289 _idx += 1;
290 )*
291 $c.end_scope($scope).unwrap();
292 $($crate::eure!(@body $c; $($tail)*);)?
293 }};
294
295 (@after_arr $c:ident $scope:ident; = { $($key:expr => $val:expr),* $(,)? } $(, $($tail:tt)*)?) => {{
297 $c.bind_empty_map().unwrap();
298 $(
299 let item_scope = $c.begin_scope();
300 $c.navigate($crate::path::PathSegment::Value($key.into())).unwrap();
301 $c.bind_from($val).unwrap();
302 $c.end_scope(item_scope).unwrap();
303 )*
304 $c.end_scope($scope).unwrap();
305 $($crate::eure!(@body $c; $($tail)*);)?
306 }};
307
308 (@after_arr $c:ident $scope:ident; = $val:expr $(, $($tail:tt)*)?) => {{
310 $c.bind_from($val).unwrap();
311 $c.end_scope($scope).unwrap();
312 $($crate::eure!(@body $c; $($tail)*);)?
313 }};
314
315 (@after_arr $c:ident $scope:ident; {} $(, $($tail:tt)*)?) => {{
317 $c.bind_empty_map().unwrap();
318 $c.end_scope($scope).unwrap();
319 $($crate::eure!(@body $c; $($tail)*);)?
320 }};
321
322 (@after_arr $c:ident $scope:ident; { $($inner:tt)+ } $(, $($tail:tt)*)?) => {{
324 $crate::eure!(@body $c; $($inner)+);
325 $c.end_scope($scope).unwrap();
326 $($crate::eure!(@body $c; $($tail)*);)?
327 }};
328}
329
330#[cfg(test)]
331mod tests {
332 use crate::document::EureDocument;
333 use crate::text::Text;
334
335 #[test]
336 fn test_eure_empty() {
337 let doc = eure!({});
338 assert_eq!(doc, EureDocument::new_empty());
339 }
340
341 #[test]
342 fn test_eure_simple_assignment() {
343 let doc = eure!({
344 name = "Alice",
345 });
346
347 let root_id = doc.get_root_id();
349 let root = doc.node(root_id);
350 let name_node_id = root.as_map().unwrap().get(&"name".into()).unwrap();
351 let name_node = doc.node(name_node_id);
352 let prim = name_node.as_primitive().unwrap();
353 assert_eq!(prim.as_str(), Some("Alice"));
354 }
355
356 #[test]
357 fn test_eure_nested_path() {
358 let doc = eure!({
359 user.name = "Bob",
360 user.age = 30,
361 });
362
363 let root_id = doc.get_root_id();
365 let root = doc.node(root_id);
366 let user_id = root.as_map().unwrap().get(&"user".into()).unwrap();
367 let user = doc.node(user_id);
368 let name_id = user.as_map().unwrap().get(&"name".into()).unwrap();
369 let name = doc.node(name_id);
370 assert_eq!(name.as_primitive().unwrap().as_str(), Some("Bob"));
371
372 let age_id = user.as_map().unwrap().get(&"age".into()).unwrap();
373 let age = doc.node(age_id);
374 assert!(matches!(
375 age.as_primitive(),
376 Some(crate::value::PrimitiveValue::Integer(_))
377 ));
378 }
379
380 #[test]
381 fn test_eure_block() {
382 let doc = eure!({
383 user {
384 name = "Charlie",
385 active = true,
386 }
387 });
388
389 let root_id = doc.get_root_id();
390 let root = doc.node(root_id);
391 let user_id = root.as_map().unwrap().get(&"user".into()).unwrap();
392 let user = doc.node(user_id);
393 let name_id = user.as_map().unwrap().get(&"name".into()).unwrap();
394 let name = doc.node(name_id);
395 assert_eq!(name.as_primitive().unwrap().as_str(), Some("Charlie"));
396 }
397
398 #[test]
399 fn test_eure_extension() {
400 let doc = eure!({
401 field.%variant = Text::inline_implicit("text"),
402 });
403
404 let root_id = doc.get_root_id();
405 let root = doc.node(root_id);
406 let field_id = root.as_map().unwrap().get(&"field".into()).unwrap();
407 let field = doc.node(field_id);
408
409 let variant_id = field.get_extension(&"variant".parse().unwrap()).unwrap();
411 let variant = doc.node(variant_id);
412 let text = variant.as_primitive().unwrap().as_text().unwrap();
413 assert_eq!(text.as_str(), "text");
414 }
415
416 #[test]
417 fn test_eure_extension_with_child() {
418 let doc = eure!({
420 field.%variant.name = Text::inline_implicit("text"),
421 field.%variant.min_length = 3
422 });
423
424 let root_id = doc.get_root_id();
425 let root = doc.node(root_id);
426 let field_id = root.as_map().unwrap().get(&"field".into()).unwrap();
427 let field = doc.node(field_id);
428
429 let variant_id = field.get_extension(&"variant".parse().unwrap()).unwrap();
431 let variant = doc.node(variant_id);
432
433 let name_id = variant.as_map().unwrap().get(&"name".into()).unwrap();
435 let name = doc.node(name_id);
436 let text = name.as_primitive().unwrap().as_text().unwrap();
437 assert_eq!(text.as_str(), "text");
438
439 let min_length_id = variant.as_map().unwrap().get(&"min_length".into()).unwrap();
440 let min_length = doc.node(min_length_id);
441 assert!(matches!(
442 min_length.as_primitive(),
443 Some(crate::value::PrimitiveValue::Integer(_))
444 ));
445 }
446
447 #[test]
448 fn test_eure_array() {
449 let doc = eure!({
450 tags = [Text::inline_implicit("a"), Text::inline_implicit("b"), Text::inline_implicit("c")],
451 });
452
453 let root_id = doc.get_root_id();
454 let root = doc.node(root_id);
455 let tags_id = root.as_map().unwrap().get(&"tags".into()).unwrap();
456 let tags = doc.node(tags_id);
457 let array = tags.as_array().unwrap();
458 assert_eq!(array.len(), 3);
459 }
460
461 #[test]
462 fn test_eure_tuple() {
463 let doc = eure!({
464 point = (1.5f64, 2.5f64),
465 });
466
467 let root_id = doc.get_root_id();
468 let root = doc.node(root_id);
469 let point_id = root.as_map().unwrap().get(&"point".into()).unwrap();
470 let point = doc.node(point_id);
471 let tuple = point.as_tuple().unwrap();
472 assert_eq!(tuple.len(), 2);
473 }
474
475 #[test]
476 fn test_eure_multiple_assignments() {
477 let doc = eure!({
478 a = 1,
479 b = 2,
480 c = 3,
481 });
482
483 let root_id = doc.get_root_id();
484 let root = doc.node(root_id);
485 let map = root.as_map().unwrap();
486 assert_eq!(map.len(), 3);
487 }
488
489 #[test]
490 fn test_eure_complex() {
491 let doc = eure!({
493 schema {
494 field.%variant = Text::inline_implicit("text"),
495 field.min_length = 3,
496 field.max_length = 20,
497 },
498 tags = [Text::inline_implicit("required")],
499 });
500
501 let root_id = doc.get_root_id();
502 let root = doc.node(root_id);
503
504 let schema_id = root.as_map().unwrap().get(&"schema".into()).unwrap();
506 let schema = doc.node(schema_id);
507
508 let field_id = schema.as_map().unwrap().get(&"field".into()).unwrap();
510 let field = doc.node(field_id);
511 assert!(field.get_extension(&"variant".parse().unwrap()).is_some());
512
513 let tags_id = root.as_map().unwrap().get(&"tags".into()).unwrap();
515 let tags = doc.node(tags_id);
516 assert_eq!(tags.as_array().unwrap().len(), 1);
517 }
518
519 #[test]
520 fn test_eure_array_push() {
521 let doc = eure!({
523 items[] = 1,
524 items[] = 2,
525 items[] = 3,
526 });
527
528 let root_id = doc.get_root_id();
529 let root = doc.node(root_id);
530 let items_id = root.as_map().unwrap().get(&"items".into()).unwrap();
531 let items = doc.node(items_id);
532 let array = items.as_array().unwrap();
533 assert_eq!(array.len(), 3);
534 }
535
536 #[test]
537 fn test_eure_array_push_with_child() {
538 let doc = eure!({
540 items[].name = "first",
541 items[].name = "second",
542 });
543
544 let root_id = doc.get_root_id();
545 let root = doc.node(root_id);
546 let items_id = root.as_map().unwrap().get(&"items".into()).unwrap();
547 let items = doc.node(items_id);
548 let array = items.as_array().unwrap();
549 assert_eq!(array.len(), 2);
550
551 let first_id = array.get(0).unwrap();
553 let first = doc.node(first_id);
554 let name_id = first.as_map().unwrap().get(&"name".into()).unwrap();
555 let name = doc.node(name_id);
556 assert_eq!(name.as_primitive().unwrap().as_str(), Some("first"));
557 }
558
559 #[test]
560 fn test_eure_tuple_index() {
561 let doc = eure!({
563 point.#0 = 1.5f64,
564 point.#1 = 2.5f64,
565 });
566
567 let root_id = doc.get_root_id();
568 let root = doc.node(root_id);
569 let point_id = root.as_map().unwrap().get(&"point".into()).unwrap();
570 let point = doc.node(point_id);
571 let tuple = point.as_tuple().unwrap();
572 assert_eq!(tuple.len(), 2);
573 }
574
575 #[test]
576 fn test_eure_mixed_path_extension_array() {
577 let doc = eure!({
579 field.%items[].name = "item1",
580 field.%items[].name = "item2",
581 });
582
583 let root_id = doc.get_root_id();
584 let root = doc.node(root_id);
585 let field_id = root.as_map().unwrap().get(&"field".into()).unwrap();
586 let field = doc.node(field_id);
587
588 let items_id = field.get_extension(&"items".parse().unwrap()).unwrap();
590 let items = doc.node(items_id);
591 let array = items.as_array().unwrap();
592 assert_eq!(array.len(), 2);
593 }
594
595 #[test]
596 fn test_eure_mixed_path_array_extension() {
597 let doc = eure!({
599 items[].%variant = Text::inline_implicit("text"),
600 items[].%variant = Text::inline_implicit("number"),
601 });
602
603 let root_id = doc.get_root_id();
604 let root = doc.node(root_id);
605 let items_id = root.as_map().unwrap().get(&"items".into()).unwrap();
606 let items = doc.node(items_id);
607 let array = items.as_array().unwrap();
608 assert_eq!(array.len(), 2);
609
610 let first_id = array.get(0).unwrap();
612 let first = doc.node(first_id);
613 let variant_id = first.get_extension(&"variant".parse().unwrap()).unwrap();
614 let variant = doc.node(variant_id);
615 assert_eq!(
616 variant.as_primitive().unwrap().as_text().unwrap().as_str(),
617 "text"
618 );
619 }
620
621 #[test]
622 fn test_eure_tuple_key() {
623 use crate::value::{ObjectKey, Tuple};
624
625 let doc = eure!({
627 map.(1, "key") = "value1",
628 map.(2, "key") = "value2",
629 });
630
631 let root_id = doc.get_root_id();
632 let root = doc.node(root_id);
633 let map_id = root.as_map().unwrap().get(&"map".into()).unwrap();
634 let map_node = doc.node(map_id);
635 let map = map_node.as_map().unwrap();
636 assert_eq!(map.len(), 2);
637
638 let tuple_key = ObjectKey::Tuple(Tuple(alloc::vec![1.into(), "key".into()]));
640 let value_id = map.get(&tuple_key).unwrap();
641 let value = doc.node(value_id);
642 assert_eq!(value.as_primitive().unwrap().as_str(), Some("value1"));
643 }
644
645 #[test]
646 fn test_eure_tuple_key_with_bool() {
647 use crate::value::{ObjectKey, Tuple};
648
649 let doc = eure!({
651 map.(true, 1) = "yes",
652 map.(false, 1) = "no",
653 });
654
655 let root_id = doc.get_root_id();
656 let root = doc.node(root_id);
657 let map_id = root.as_map().unwrap().get(&"map".into()).unwrap();
658 let map_node = doc.node(map_id);
659 let map = map_node.as_map().unwrap();
660 assert_eq!(map.len(), 2);
661
662 let tuple_key = ObjectKey::Tuple(Tuple(alloc::vec![true.into(), 1.into()]));
664 let value_id = map.get(&tuple_key).unwrap();
665 let value = doc.node(value_id);
666 assert_eq!(value.as_primitive().unwrap().as_str(), Some("yes"));
667 }
668
669 #[test]
670 fn test_eure_tuple_key_with_child() {
671 use crate::value::{ObjectKey, Tuple};
672
673 let doc = eure!({
675 map.(1, 2).name = "point_a",
676 map.(1, 2).value = 42,
677 });
678
679 let root_id = doc.get_root_id();
680 let root = doc.node(root_id);
681 let map_id = root.as_map().unwrap().get(&"map".into()).unwrap();
682 let map_node = doc.node(map_id);
683 let map = map_node.as_map().unwrap();
684
685 let tuple_key = ObjectKey::Tuple(Tuple(alloc::vec![1.into(), 2.into()]));
687 let entry_id = map.get(&tuple_key).unwrap();
688 let entry = doc.node(entry_id);
689 let entry_map = entry.as_map().unwrap();
690
691 let name_id = entry_map.get(&"name".into()).unwrap();
692 let name = doc.node(name_id);
693 assert_eq!(name.as_primitive().unwrap().as_str(), Some("point_a"));
694 }
695
696 #[test]
697 fn test_eure_string_key() {
698 let doc = eure!({
700 field."min-length" = 3,
701 field."max-length" = 20,
702 });
703
704 let root_id = doc.get_root_id();
705 let root = doc.node(root_id);
706 let field_id = root.as_map().unwrap().get(&"field".into()).unwrap();
707 let field = doc.node(field_id);
708 let field_map = field.as_map().unwrap();
709
710 let min_id = field_map.get(&"min-length".into()).unwrap();
712 let min_node = doc.node(min_id);
713 assert!(matches!(
714 min_node.as_primitive(),
715 Some(crate::value::PrimitiveValue::Integer(_))
716 ));
717 }
718
719 #[test]
720 fn test_eure_object_literal() {
721 let doc = eure!({
723 variants.click = { "x" => 1.0f64, "y" => 2.0f64 },
724 });
725
726 let root_id = doc.get_root_id();
727 let root = doc.node(root_id);
728 let variants_id = root.as_map().unwrap().get(&"variants".into()).unwrap();
729 let variants = doc.node(variants_id);
730 let click_id = variants.as_map().unwrap().get(&"click".into()).unwrap();
731 let click = doc.node(click_id);
732 let click_map = click.as_map().unwrap();
733
734 assert_eq!(click_map.len(), 2);
735 assert!(click_map.get(&"x".into()).is_some());
736 assert!(click_map.get(&"y".into()).is_some());
737 }
738
739 #[test]
740 fn test_eure_object_literal_with_text() {
741 let doc = eure!({
743 schema.variants.success = { "data" => Text::inline_implicit("any") },
744 });
745
746 let root_id = doc.get_root_id();
747 let root = doc.node(root_id);
748 let schema_id = root.as_map().unwrap().get(&"schema".into()).unwrap();
749 let schema = doc.node(schema_id);
750 let variants_id = schema.as_map().unwrap().get(&"variants".into()).unwrap();
751 let variants = doc.node(variants_id);
752 let success_id = variants.as_map().unwrap().get(&"success".into()).unwrap();
753 let success = doc.node(success_id);
754 let success_map = success.as_map().unwrap();
755
756 let data_id = success_map.get(&"data".into()).unwrap();
757 let data = doc.node(data_id);
758 let text = data.as_primitive().unwrap().as_text().unwrap();
759 assert_eq!(text.as_str(), "any");
760 }
761
762 #[test]
763 fn test_eure_value_binding() {
764 let doc = eure!({
766 = Text::inline_implicit("hello"),
767 });
768
769 let root_id = doc.get_root_id();
770 let root = doc.node(root_id);
771 let text = root.as_primitive().unwrap().as_text().unwrap();
772 assert_eq!(text.as_str(), "hello");
773 }
774
775 #[test]
776 fn test_eure_value_binding_with_extension() {
777 let doc = eure!({
779 = Text::inline_implicit("any"),
780 %variant = "literal",
781 });
782
783 let root_id = doc.get_root_id();
784 let root = doc.node(root_id);
785
786 let text = root.as_primitive().unwrap().as_text().unwrap();
788 assert_eq!(text.as_str(), "any");
789
790 let variant_id = root.get_extension(&"variant".parse().unwrap()).unwrap();
792 let variant = doc.node(variant_id);
793 assert_eq!(variant.as_primitive().unwrap().as_str(), Some("literal"));
794 }
795
796 #[test]
797 fn test_eure_empty_block() {
798 let doc = eure!({
800 config {},
801 });
802
803 let root_id = doc.get_root_id();
804 let root = doc.node(root_id);
805 let config_id = root.as_map().unwrap().get(&"config".into()).unwrap();
806 let config = doc.node(config_id);
807
808 let map = config
810 .as_map()
811 .expect("Empty block should create an empty map");
812 assert!(map.is_empty());
813 }
814}