1pub use crypt_macro::Cryptic;
17
18use std::{
19 cell::LazyCell,
20 collections::HashMap,
21 ffi::OsString,
22 iter::Peekable,
23 path::{Path, PathBuf},
24 vec::IntoIter
25};
26
27use indexmap::IndexMap;
28use oaken::{
29 Lexer, Registry,
30 TokenPosition, TracedToken,
31 TracedTokenStream,
32 util::{
33 numeric_state::{DecimalState, numeric_entry_rule},
34 string_state::StringState
35 }
36};
37
38#[derive(Debug, Clone)]
43enum Token {
45 Identifier(String),
46 String(String),
47 Integer(i64),
48 Float(f64),
49 Boolean(bool), Null, Import, Assign, SingleTag, TagOpen, TagClose, BodyOpen, BodyClose, ListOpen, ListClose, Break, }
64
65impl std::fmt::Display for Token {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 match self {
68 Self::Identifier(ident) => write!(f, "'{}'", ident),
69 Self::String(str) => write!(f, "\"{}\"", str),
70 Self::Integer(int) => write!(f, "{}", int),
71 Self::Float(fl) => write!(f, "{}", fl),
72 Self::Boolean(bool) => write!(f, "{}", bool),
73 Self::Null => write!(f, "null"),
74 Self::Import => write!(f, "!import"),
75 Self::Assign => write!(f, ": | ="),
76 Self::SingleTag => write!(f, "#"),
77 Self::TagOpen => write!(f, "("),
78 Self::TagClose => write!(f, ")"),
79 Self::ListOpen => write!(f, "["),
80 Self::ListClose => write!(f, "]"),
81 Self::BodyOpen => write!(f, "{{"),
82 Self::BodyClose => write!(f, "}}"),
83 Self::Break => write!(f, ","),
84 }
85 }
86}
87
88impl Token {
89 fn get_binding_power(&self) -> isize {
90 match self {
91 Self::Break => 1,
92 Self::Assign => 2,
93
94 _ => 0,
95 }
96 }
97}
98
99impl From<String> for Token {
100 fn from(value: String) -> Self {
101 Self::String(value)
102 }
103}
104
105macro_rules! from_int {
106 ($($ty:ty)+) => {
107 $(
108 impl From<$ty> for Token {
109 fn from(value: $ty) -> Self {
110 Self::Integer(value as _)
111 }
112 }
113 )+
114 };
115}
116from_int!(i8 u8 i16 u16 i32 u32 i64 u64);
117
118impl From<f32> for Token {
119 fn from(value: f32) -> Self {
120 Self::Float(value as _)
121 }
122}
123impl From<f64> for Token {
124 fn from(value: f64) -> Self {
125 Self::Float(value)
126 }
127}
128
129const TOKENS: LazyCell<Vec<(&'static str, Token, bool)>> =
130LazyCell::new(||vec![
131 ("true", Token::Boolean(true), false),
132 ("false", Token::Boolean(false), false),
133 ("null", Token::Null, false),
134 ("!import", Token::Import, false),
135 ("#", Token::SingleTag, true),
136 ("(", Token::TagOpen, true),
137 (")", Token::TagClose, true),
138 ("{", Token::BodyOpen, true),
139 ("}", Token::BodyClose, true),
140 ("[", Token::ListOpen, true),
141 ("]", Token::ListClose, true),
142 (",", Token::Break, true),
143 ("=", Token::Assign, true),
144 (":", Token::Assign, true),
145]);
146
147fn identifier_fallback(str: &String) -> Token {
148 Token::Identifier(str.clone())
149}
150
151
152pub struct CryptParserServer {
176 register: Registry<Token>,
178 opened_files: HashMap<OsString, TracedObject>,
180}
181
182impl CryptParserServer {
183 pub fn new() -> Self {
185 let mut reg= Registry::new(identifier_fallback);
186
187 for (kw, tk, br) in &*TOKENS {
188 reg = reg.new_keyword(kw, tk.clone(), *br).unwrap();
189 }
190
191 Self {
192 register: reg
193 .new_special_state('"', StringState::new('"'))
194 .add_new_entry_rule(numeric_entry_rule, DecimalState::default()),
195 opened_files: HashMap::new(),
196 }
197 }
198
199 pub fn open<P, T>(&mut self, path: P) -> Result<T, CryptError>
202 where
203 P: AsRef<Path>,
204 T: Cryptic,
205 {
206 let path_str = path.as_ref().canonicalize()?.as_os_str().to_os_string();
207
208 if let Some(built) = self.opened_files.get(&path_str) {
209 return T::cryptic(built.clone())
210 }
211
212 let tokens = self.tokenize(path)?;
213 let mut iter = tokens.into_iter().peekable();
214 let ast = parse_body(&mut iter)?;
215 let object = resolve(ast, self)?;
216
217 self.opened_files.insert(path_str, object.clone());
218
219 if let CryptObject::ObjectList(body) = &object.object
221 && body.len() == 1 && matches!(&body.iter().next().unwrap().object, &CryptObject::ObjectBody(_))
222 {
223 let CryptObject::ObjectList(body) = object.object else { unreachable!() };
224 let object = body.into_iter().next().unwrap();
225 T::cryptic(object)
226 } else {
227 T::cryptic(object)
228 }
229 }
230
231 fn tokenize<P>(&self, path: P) -> std::io::Result<TracedTokenStream<Token>>
233 where
234 P: AsRef<Path>,
235 {
236 let mut lexer = Lexer::from(&self.register);
237 lexer.traced();
238 lexer.lex_file(path, None)?;
239 Ok(lexer.finish_as_trace())
240 }
241}
242
243
244#[derive(Debug)]
249struct TracedNode {
252 position: TokenPosition,
253 node: Node,
254}
255
256#[derive(Debug)]
257enum Node {
259 Identifier(String),
260 String(String),
261 Integer(i64),
262 Float(f64),
263 Boolean(bool),
264 Null,
265
266 Import(String),
267 Assignment(String, Box<TracedNode>),
268 Tag(Vec<TracedNode>, Box<TracedNode>),
269 Body(Vec<TracedNode>),
270 List(Vec<TracedNode>),
271}
272
273type TokenIterator = Peekable<IntoIter<TracedToken<Token>>>;
274
275fn parse_body(iter: &mut TokenIterator) -> Result<TracedNode, CryptError> {
277 let mut items = Vec::new();
278 while let Some(_) = iter.peek() {
279 let item = parse(iter, 1)?;
280 items.push(item);
281
282 if let Some(t) = iter.peek() && matches!(t.get_type(), Token::Break) {
283 iter.next();
284 } else {
285 break;
286 }
287 }
288 if let Some(t) = iter.next() {
289 return Err(CryptError(Some(t.get_position().clone()), CryptErrorType::UnexpectedToken(t.into_type())))
290 }
291
292 Ok(TracedNode { position: TokenPosition { line: 0, column_start: 0, column_end: 0, path: None }, node: Node::List(items) })
293}
294
295fn parse(iter: &mut TokenIterator, current_binding_power: isize, ) -> Result<TracedNode, CryptError> {
296 let Some(current) = iter.next() else {
297 return Err(CryptError(None, CryptErrorType::UnexpectedEOF))
298 };
299
300 let mut left = parse_nud(iter, current)?;
301
302 while let Some(t) = iter.peek() && t.get_type().get_binding_power() > current_binding_power {
303 let current = iter.next().unwrap();
304 left = parse_led(iter, left, current)?;
305 }
306
307 Ok(left)
308}
309
310fn parse_nud(iter: &mut TokenIterator, current: TracedToken<Token>) -> Result<TracedNode, CryptError> {
311 let pos = current.get_position().clone();
312 let token = current.into_type();
313 let node = match token.clone() {
314 Token::Identifier(ident) => Node::Identifier(ident),
315 Token::String(str) => Node::String(str),
316 Token::Integer(int) => Node::Integer(int),
317 Token::Float(fl) => Node::Float(fl),
318 Token::Boolean(bool) => Node::Boolean(bool),
319 Token::Null => Node::Null,
320
321 Token::Import => {
322 let Some(t) = iter.next() else {
323 return Err(CryptError(None, CryptErrorType::UnexpectedEOF))
324 };
325
326 let path_token_pos = t.get_position().clone();
327 let t = t.into_type();
328 let Token::String(str) = t.clone() else {
329 return Err(CryptError(Some(path_token_pos), CryptErrorType::ExpectedOther("path string", t)))
330 };
331
332 Node::Import(str)
333 },
334
335 Token::SingleTag => {
336 if let Some(t) = iter.peek() && matches!(t.get_type(), Token::TagOpen) {
337 iter.next();
338 let mut tags = Vec::new();
339 while let Some(t) = iter.peek() && !matches!(t.get_type(), Token::TagClose) {
340 let tag = parse(iter, 1)?;
341 tags.push(tag);
342
343 if let Some(t) = iter.peek() && matches!(t.get_type(), Token::Break) {
344 iter.next();
345 } else {
346 break;
347 }
348 }
349 if let Some(t) = iter.next() && !matches!(t.get_type(), Token::TagClose) {
350 return Err(CryptError(Some(t.get_position().clone()), CryptErrorType::ExpectedOther("closing ')'", t.into_type())))
351 }
352 Node::Tag(tags, Box::new(parse(iter, 1)?))
353 } else {
354 let tag = parse(iter, 1)?;
355 Node::Tag(vec![tag], Box::new(parse(iter, 1)?))
356 }
357 }
358
359 Token::BodyOpen => {
360 let mut items = Vec::new();
361 while let Some(t) = iter.peek() && !matches!(t.get_type(), Token::BodyClose) {
362 let item = parse(iter, 1)?;
363 items.push(item);
364
365 if let Some(t) = iter.peek() && matches!(t.get_type(), Token::Break) {
366 iter.next();
367 } else {
368 break;
369 }
370 }
371 if let Some(t) = iter.next() && !matches!(t.get_type(), Token::BodyClose) {
372 return Err(CryptError(Some(t.get_position().clone()), CryptErrorType::ExpectedOther("closing '}'", t.into_type())))
373 }
374 Node::Body(items)
375 }
376
377 Token::ListOpen => {
378 let mut items = Vec::new();
379 while let Some(t) = iter.peek() && !matches!(t.get_type(), Token::ListClose) {
380 let item = parse(iter, 1)?;
381 items.push(item);
382
383 if let Some(t) = iter.peek() && matches!(t.get_type(), Token::Break) {
384 iter.next();
385 } else {
386 break;
387 }
388 }
389 if let Some(t) = iter.next() && !matches!(t.get_type(), Token::ListClose) {
390 return Err(CryptError(Some(t.get_position().clone()), CryptErrorType::ExpectedOther("closing ']'", t.into_type())))
391 }
392 Node::List(items)
393 }
394
395 _ => return Err(CryptError(Some(pos), CryptErrorType::UnexpectedToken(token)))
396 };
397
398 Ok(TracedNode { position: pos, node, })
399}
400
401fn parse_led(iter: &mut TokenIterator, left: TracedNode, current: TracedToken<Token>) -> Result<TracedNode, CryptError> {
402 let pos = current.get_position().clone();
403 let token = current.into_type();
404 let node = match token.clone() {
405 Token::Assign => {
406 let ident = match left.node {
407 Node::Identifier(ident) => ident,
408 Node::String(str) => str,
409 _ => return Err(CryptError(Some(left.position), CryptErrorType::ExpectedIdentifier))
410 };
411
412 let object = parse(iter, 1)?;
413 Node::Assignment(ident, Box::new(object))
414 }
415
416 _ => return Err(CryptError(Some(pos), CryptErrorType::UnexpectedToken(token)))
417 };
418
419 Ok(TracedNode { position: pos, node, })
420}
421
422
423
424
425fn resolve(node: TracedNode, server: &mut CryptParserServer) -> Result<TracedObject, CryptError> {
426 let pos = node.position;
427
428 let obj = match node.node {
429 Node::Identifier(ident) => CryptObject::FloatingIdentifier(ident),
430 Node::String(str) => CryptObject::ConstantString(str),
431 Node::Integer(int) => CryptObject::ConstantInteger(int),
432 Node::Float(fl) => CryptObject::ConstantFloat(fl),
433 Node::Boolean(bool) => CryptObject::ConstantBoolean(bool),
434 Node::Null => CryptObject::Null,
435 Node::Assignment(ident, item) => CryptObject::IdentifiedObject(ident, Box::new(resolve(*item, server)?)),
436 Node::Body(items) => {
437 let mut body = IndexMap::new();
438 for item in items {
439 let item = resolve(item, server)?;
440 match item.object {
441 CryptObject::IdentifiedObject(ident, item) => {
442 body.insert(ident, *item);
443 }
444 CryptObject::TaggedObject(tags, tagged_item) =>
445 if let CryptObject::IdentifiedObject(ident, tagged_item) = tagged_item.object {
446 body.insert(ident, TracedObject { position: item.position, object: CryptObject::TaggedObject(tags, tagged_item) });
447 } else {
448 return Err(CryptError(Some(item.position), CryptErrorType::ExpectedIdentifier))
449 },
450 _ => return Err(CryptError(Some(item.position), CryptErrorType::ExpectedIdentifier))
451 }
452 }
453 CryptObject::ObjectBody(body)
454 }
455 Node::List(items) => {
456 let mut resolved_items = Vec::new();
457 for item in items {
458 let item = resolve(item, server)?;
459 resolved_items.push(item);
460 }
461 CryptObject::ObjectList(resolved_items)
462 }
463 Node::Tag(tags, object) => {
464 let mut resolved_tags = Vec::new();
465 for tag in tags {
466 let tag = resolve(tag, server)?;
467 resolved_tags.push(tag);
468 }
469 CryptObject::TaggedObject(resolved_tags, Box::new(resolve(*object, server)?))
470 }
471 Node::Import(path) => {
472 let Some(current_path) = pos.path else {
473 return Err(CryptError(Some(pos), CryptErrorType::CannotImport))
474 };
475
476 let path_buf =
477 PathBuf::from(current_path.as_ref())
478 .canonicalize().unwrap(); let final_path = path_buf.parent().unwrap().join(path);
480
481 return server.open(final_path)
482 }
483 };
484
485 Ok(TracedObject { position: pos, object: obj })
486}
487
488
489
490
491#[derive(Debug, Clone)]
496pub struct TracedObject {
504 position: TokenPosition,
505 object: CryptObject,
506}
507
508#[derive(Debug, Clone)]
509enum CryptObject {
511 ConstantString(String),
512 ConstantInteger(i64),
513 ConstantFloat(f64),
514 ConstantBoolean(bool),
515 Null,
516 FloatingIdentifier(String),
517 IdentifiedObject(String, Box<TracedObject>),
518
519 TaggedObject (Vec<TracedObject>, Box<TracedObject>),
520
521 ObjectBody(IndexMap<String, TracedObject>),
522 ObjectList(Vec<TracedObject>),
523}
524
525#[derive(Debug, Clone)]
526pub enum CrypticObject {
532 ConstantString(String),
533 ConstantInteger(i64),
534 ConstantFloat(f64),
535 ConstantBoolean(bool),
536 Null,
537 FloatingIdentifier(String),
538 IdentifiedObject(String, Box<CrypticObject>),
539
540 TaggedObject (Vec<CrypticObject>, Box<CrypticObject>),
541
542 ObjectBody(HashMap<String, CrypticObject>),
543 ObjectList(Vec<CrypticObject>),
544}
545
546#[derive(Debug, Clone)]
547pub struct Tagged<T, O> {
549 pub tag: T,
550 pub object: O
551}
552
553#[derive(Debug, Clone)]
554pub struct HashTagged<T, O> {
556 pub tags: HashMap<String, T>,
557 pub object: O
558}
559
560#[derive(Debug, Clone)]
561pub struct ListTagged<T, O> {
563 pub tags: Vec<T>,
564 pub object: O
565}
566
567
568
569pub trait Cryptic: Sized {
578 fn cryptic(object: TracedObject) -> Result<Self, CryptError>;
583}
584
585impl TryInto<String> for TracedObject {
586 type Error = CryptError;
587
588 fn try_into(self) -> Result<String, Self::Error> {
589 match self.object {
590 CryptObject::ConstantString(str) => Ok(str),
591 CryptObject::FloatingIdentifier(ident) => Ok(ident),
592 CryptObject::ConstantInteger(int) => Ok(int.to_string()),
593 CryptObject::ConstantFloat(fl) => Ok(fl.to_string()),
594 CryptObject::ConstantBoolean(b) => Ok(b.to_string()),
595 CryptObject::Null => Ok(String::new()),
596 CryptObject::IdentifiedObject(_, obj) => (*obj).try_into(),
597 CryptObject::TaggedObject(_, obj) => (*obj).try_into(),
598 _ => Err(CryptError(Some(self.position), CryptErrorType::UnexpectedType))
599 }
600 }
601}
602
603impl TryInto<bool> for TracedObject {
604 type Error = CryptError;
605
606 fn try_into(self) -> Result<bool, Self::Error> {
607 match self.object {
608 CryptObject::ConstantString(str) => Ok(str != ""),
609 CryptObject::FloatingIdentifier(_) => Ok(true),
610 CryptObject::ConstantInteger(int) => Ok(int != 0),
611 CryptObject::ConstantFloat(fl) => Ok(fl != 0.0),
612 CryptObject::ConstantBoolean(b) => Ok(b),
613 CryptObject::Null => Ok(false),
614 CryptObject::IdentifiedObject(_, obj) => (*obj).try_into(),
615 CryptObject::TaggedObject(_, obj) => (*obj).try_into(),
616 _ => Err(CryptError(Some(self.position), CryptErrorType::UnexpectedType))
617 }
618 }
619}
620
621macro_rules! try_into_int {
622 ($($ty:ty)+) => {
623 $(
624 impl TryInto<$ty> for TracedObject {
625 type Error = CryptError;
626
627 fn try_into(self) -> Result<$ty, Self::Error> {
628 match self.object {
629 CryptObject::ConstantInteger(int) => Ok(int as _),
630 CryptObject::ConstantFloat(fl) => Ok(fl as _),
631 CryptObject::ConstantBoolean(b) => Ok(if b {1 as _} else {0 as _}),
632 CryptObject::ConstantString(str) => match str.parse() {
633 Ok(i) => Ok(i),
634 Err(_) => Err(CryptError(Some(self.position), CryptErrorType::ParseError))
635 },
636 CryptObject::IdentifiedObject(_, item) => (*item).try_into(),
637 CryptObject::TaggedObject(_, obj) => (*obj).try_into(),
638 _ => Err(CryptError(Some(self.position), CryptErrorType::UnexpectedType))
639 }
640 }
641 }
642 )+
643 };
644}
645try_into_int!(i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64);
646
647impl<T> TryInto<Vec<T>> for TracedObject
648where
649 T: Cryptic
650{
651 type Error = CryptError;
652
653 fn try_into(self) -> Result<Vec<T>, Self::Error> {
654 match self.object {
655 CryptObject::ObjectList(list) =>
656 list
657 .into_iter()
658 .map(|i| T::cryptic(i))
659 .collect(),
660 CryptObject::ObjectBody(body) =>
661 body
662 .into_values()
663 .into_iter()
664 .map(|i| T::cryptic(i))
665 .collect(),
666
667 CryptObject::IdentifiedObject(_, obj) => (*obj).try_into(),
668 CryptObject::TaggedObject(_, obj) => (*obj).try_into(),
669
670 _ => Ok(vec![T::cryptic(self)?])
671 }
672 }
673}
674
675impl<T> TryInto<HashMap<String, T>> for TracedObject
676where
677 T: Cryptic
678{
679 type Error = CryptError;
680
681 fn try_into(self) -> Result<HashMap<String, T>, Self::Error> {
682 match self.object {
683 CryptObject::ObjectBody(body) =>
684 body
685 .into_iter()
686 .map(|(k, i)| T::cryptic(i).map(|i| (k, i)))
687 .collect(),
688 CryptObject::ObjectList(list) => {
689 let mut body = HashMap::new();
690 let mut idx: usize = 0;
691 for item in list {
692 if let CryptObject::IdentifiedObject(ident, item) = item.object {
693 body.insert(ident, T::cryptic(*item)?);
694 } else {
695 body.insert(idx.to_string(), T::cryptic(item)?);
696 idx += 1;
697 }
698 }
699 Ok(body)
700 },
701
702 CryptObject::IdentifiedObject(ident, item) => Ok(vec![(ident, T::cryptic(*item)?)].into_iter().collect()),
703 CryptObject::TaggedObject(_, item) => (*item).try_into(),
704
705 _ => Err(CryptError(Some(self.position), CryptErrorType::UnexpectedType))
706 }
707 }
708}
709
710
711impl<T, O> TryInto<Tagged<T, O>> for TracedObject
712where
713 T: Cryptic,
714 O: Cryptic
715{
716 type Error = CryptError;
717
718 fn try_into(self) -> Result<Tagged<T, O>, Self::Error> {
719 match self.object {
720 CryptObject::TaggedObject(tags, obj) => {
721 let Some(tag) = tags.into_iter().next() else {
722 return Err(CryptError(Some(self.position), CryptErrorType::ExpectedTag))
723 };
724 let tag = T::cryptic(tag)?;
725
726 Ok(Tagged { tag: tag, object: O::cryptic(*obj)? })
727 }
728
729 _ => Err(CryptError(Some(self.position), CryptErrorType::UnexpectedType))
730
731 }
732 }
733}
734
735impl<T, O> TryInto<ListTagged<T, O>> for TracedObject
736where
737 T: Cryptic,
738 O: Cryptic
739{
740 type Error = CryptError;
741
742 fn try_into(self) -> Result<ListTagged<T, O>, Self::Error> {
743 match self.object {
744 CryptObject::TaggedObject(tags, obj) => {
745 let tags = tags.into_iter().map(|i| T::cryptic(i)).collect::<Result<Vec<T>, CryptError>>()?;
746 Ok(ListTagged { tags, object: O::cryptic(*obj)? })
747 }
748
749 _ => Ok(ListTagged { tags: Vec::new(), object: O::cryptic(self)? })
750 }
751 }
752}
753
754impl<T, O> TryInto<HashTagged<T, O>> for TracedObject
755where
756 T: Cryptic,
757 O: Cryptic
758{
759 type Error = CryptError;
760
761 fn try_into(self) -> Result<HashTagged<T, O>, Self::Error> {
762 match self.object {
763 CryptObject::TaggedObject(tags, item) => {
764 let mut built_tags = HashMap::new();
765 let mut idx: usize = 0;
766 for tag in tags {
767 if let CryptObject::IdentifiedObject(ident, item) = tag.object {
768 built_tags.insert(ident, T::cryptic(*item)?);
769 } else {
770 built_tags.insert(idx.to_string(), T::cryptic(tag)?);
771 idx += 1;
772 }
773 }
774 Ok(HashTagged { tags: built_tags, object: O::cryptic(*item)? })
775 }
776
777 _ => Ok(HashTagged { tags: HashMap::new(), object: O::cryptic(self)? })
778 }
779 }
780}
781
782impl<T> Cryptic for T
783where
784 TracedObject: TryInto<T, Error = CryptError>,
785{
786 fn cryptic(object: TracedObject) -> Result<Self, CryptError> {
787 object.try_into()
788 }
789}
790
791impl Cryptic for CryptObject {
792 fn cryptic(object: TracedObject) -> Result<Self, CryptError> {
793 Ok(object.object)
794 }
795}
796
797impl Cryptic for CrypticObject {
798 fn cryptic(object: TracedObject) -> Result<Self, CryptError> {
799 Ok(match object.object {
800 CryptObject::ConstantString(str) => CrypticObject::ConstantString(str),
801 CryptObject::ConstantInteger(int) => CrypticObject::ConstantInteger(int),
802 CryptObject::ConstantFloat(fl) => CrypticObject::ConstantFloat(fl),
803 CryptObject::ConstantBoolean(b) => CrypticObject::ConstantBoolean(b),
804 CryptObject::Null => CrypticObject::Null,
805 CryptObject::FloatingIdentifier(ident) => CrypticObject::FloatingIdentifier(ident),
806 CryptObject::IdentifiedObject(ident, item) => CrypticObject::IdentifiedObject(ident, Box::new(CrypticObject::cryptic(*item).unwrap())),
807 CryptObject::TaggedObject (tags, item) => CrypticObject::TaggedObject(tags.into_iter().map(|i| CrypticObject::cryptic(i).unwrap()).collect(), Box::new(CrypticObject::cryptic(*item).unwrap())),
808 CryptObject::ObjectBody(body) => CrypticObject::ObjectBody(body.into_iter().map(|(ident, item)| (ident, CrypticObject::cryptic(item).unwrap())).collect()),
809 CryptObject::ObjectList(list) => CrypticObject::ObjectList(list.into_iter().map(|i| CrypticObject::cryptic(i).unwrap()).collect()),
810 })
811 }
812}
813
814impl<T> Cryptic for Option<T>
815where
816 T: Cryptic
817{
818 fn cryptic(object: TracedObject) -> Result<Self, CryptError> {
819 match object.object {
820 CryptObject::Null => Ok(None),
821 _ => Ok(Some(Cryptic::cryptic(object)?))
822 }
823 }
824}
825
826impl Cryptic for TracedObject {
827 fn cryptic(object: TracedObject) -> Result<Self, CryptError> {
828 Ok(object)
829 }
830}
831
832#[derive(Debug)]
833pub struct CryptError(Option<TokenPosition>, CryptErrorType);
835
836impl CryptError {
837 pub const fn cannot_find_ident(name: &'static str) -> Self {
838 Self(None, CryptErrorType::NoItemOfIdentifier(name))
839 }
840 pub const fn not_enough_items() -> Self {
841 Self(None, CryptErrorType::NotEnoughItems)
842 }
843 pub fn invalid_enum_variant(variant: String) -> Self {
844 Self(None, CryptErrorType::InvalidEnumVariant(variant))
845 }
846}
847
848#[derive(Debug)]
849enum CryptErrorType {
850 UnexpectedToken(Token),
851 ExpectedOther(&'static str, Token),
852 UnexpectedEOF,
853 ExpectedIdentifier,
854 CannotImport,
855 UnexpectedType,
856 ParseError,
857 ExpectedTag,
858
859 NoItemOfIdentifier(&'static str),
860 NotEnoughItems,
861 InvalidEnumVariant(String),
862
863 OsError(std::io::Error),
864}
865
866impl std::fmt::Display for CryptError {
867 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
868 match &self.1 {
869 CryptErrorType::UnexpectedToken(t) => writeln!(f, "Unexpected token: {}", t),
870 CryptErrorType::ExpectedOther(desc, t) => writeln!(f, "Unexpected token: {}, expected {}", t, desc),
871 CryptErrorType::UnexpectedEOF => writeln!(f, "Unexpected end of file"),
872 CryptErrorType::ExpectedIdentifier => writeln!(f, "Expected an identifier"),
873 CryptErrorType::CannotImport => writeln!(f, "Cannot import here"),
874 CryptErrorType::UnexpectedType => writeln!(f, "Unexpected type"),
875 CryptErrorType::ParseError => writeln!(f, "Failed to parse"),
876 CryptErrorType::ExpectedTag => writeln!(f, "Expected a tag"),
877 CryptErrorType::OsError(e) => writeln!(f, "{}", e),
878 CryptErrorType::NoItemOfIdentifier(ident) => write!(f, "Couldn't find item: {}", ident),
879 CryptErrorType::NotEnoughItems => write!(f, "Not enough items found"),
880 CryptErrorType::InvalidEnumVariant(v) => write!(f, "Invalid enum variant: {}", v),
881 }?;
882
883 if let Some(pos) = &self.0 {
884 writeln!(f, "at: {:?}", pos)?;
885 }
886
887 Ok(())
888 }
889}
890
891impl std::error::Error for CryptError {}
892
893impl From<std::io::Error> for CryptError {
894 fn from(value: std::io::Error) -> Self {
895 CryptError(None, CryptErrorType::OsError(value))
896 }
897}