1pub use crypt_macro::Cryptic;
17use oaken::{
18 lexer::{IntoLexer, LexerFileLexingExt, TokenTraceData, TracedToken}, numeric_build_methods, standard::{
19 LexerRegistry, StandardLexerToken
20 }, standard_fallback, util::{
21 comments::OakenCommentStateRegistryExt,
22 numbers::{AttachNumericStateExt, NumericState, NumericStateBuildType},
23 strings::OakenDelimitedStateRegistryExt
24 }
25};
26
27use std::{
28 cell::LazyCell,
29 collections::HashMap,
30 ffi::OsString,
31 iter::Peekable,
32 path::{Path, PathBuf},
33 vec::IntoIter
34};
35
36use indexmap::IndexMap;
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 StandardLexerToken for Token {}
100
101standard_fallback!(identifier_fallback -> Token for Token::Identifier, use u8);
102standard_fallback!(string_method -> Token for Token::String, use u8);
103
104const TOKENS: LazyCell<Vec<(&'static str, Token, bool)>> =
105LazyCell::new(||vec![
106 ("true", Token::Boolean(true), false),
107 ("false", Token::Boolean(false), false),
108 ("null", Token::Null, false),
109 ("!import", Token::Import, false),
110 ("#", Token::SingleTag, true),
111 ("(", Token::TagOpen, true),
112 (")", Token::TagClose, true),
113 ("{", Token::BodyOpen, true),
114 ("}", Token::BodyClose, true),
115 ("[", Token::ListOpen, true),
116 ("]", Token::ListClose, true),
117 (",", Token::Break, true),
118 ("=", Token::Assign, true),
119 (":", Token::Assign, true),
120]);
121
122
123pub struct CryptParserServer {
147 register: LexerRegistry<Token>,
149 opened_files: HashMap<OsString, TracedObject>,
151}
152
153impl CryptParserServer {
154 pub fn new() -> Self {
156 let mut reg = LexerRegistry::new(identifier_fallback);
157
158 for (kw, tk, br) in &*TOKENS {
159 reg.new_keyword(kw, *br, tk.clone()).unwrap();
160 }
161
162 reg.add_delimiting_state(b'"', b'"', string_method).unwrap();
163 reg.add_comment_state(b"--").unwrap();
164
165 numeric_build_methods! {
166 build_methods::Token {
167 NumericStateBuildType::CustomInteger => |str|{
168 Token::Integer(str.parse().unwrap())
169 },
170
171 NumericStateBuildType::CustomFloat => |str| {
172 Token::Float(str.parse().unwrap())
173 }
174 }
175 }
176
177 NumericState::new(HashMap::new()).extend_reg(&mut reg);
178
179 Self {
180 register: reg,
181 opened_files: HashMap::new(),
182 }
183 }
184
185 pub fn open<P, T>(&mut self, path: P) -> Result<T, CryptError>
188 where
189 P: AsRef<Path>,
190 T: Cryptic,
191 {
192 let path_str = path.as_ref().canonicalize()?.as_os_str().to_os_string();
193
194 if let Some(built) = self.opened_files.get(&path_str) {
195 return T::cryptic(built.clone())
196 }
197
198 let tokens = self.tokenize(path)?;
199 let mut iter = tokens.into_iter().peekable();
200 let ast = parse_body(&mut iter)?;
201 let object = resolve(ast, self)?;
202
203 self.opened_files.insert(path_str, object.clone());
204
205 if let CryptObject::ObjectList(body) = &object.object
207 && body.len() == 1 && matches!(&body.iter().next().unwrap().object, &CryptObject::ObjectBody(_))
208 {
209 let CryptObject::ObjectList(body) = object.object else { unreachable!() };
210 let object = body.into_iter().next().unwrap();
211 T::cryptic(object)
212 } else {
213 T::cryptic(object)
214 }
215 }
216
217 fn tokenize<P>(&self, path: P) -> std::io::Result<Vec<TracedToken<Token>>>
219 where
220 P: AsRef<Path>,
221 {
222 let mut lexer = self.register.into_lexer();
223 lexer.lex_file(path)?;
224 Ok(lexer.finish())
225 }
226}
227
228
229#[derive(Debug)]
234struct TracedNode {
237 position: TokenTraceData,
238 node: Node,
239}
240
241#[derive(Debug)]
242enum Node {
244 Identifier(String),
245 String(String),
246 Integer(i64),
247 Float(f64),
248 Boolean(bool),
249 Null,
250
251 Import(String),
252 Assignment(String, Box<TracedNode>),
253 Tag(Vec<TracedNode>, Box<TracedNode>),
254 Body(Vec<TracedNode>),
255 List(Vec<TracedNode>),
256}
257
258type TokenIterator = Peekable<IntoIter<TracedToken<Token>>>;
259
260fn parse_body(iter: &mut TokenIterator) -> Result<TracedNode, CryptError> {
262 let mut items = Vec::new();
263 while let Some(_) = iter.peek() {
264 let item = parse(iter, 1)?;
265 items.push(item);
266
267 if let Some(t) = iter.peek() && matches!(t.token, Token::Break) {
268 iter.next();
269 } else {
270 break;
271 }
272 }
273 if let Some(t) = iter.next() {
274 return Err(CryptError(Some(t.trace), CryptErrorType::UnexpectedToken(t.token)))
275 }
276
277 Ok(TracedNode { position: TokenTraceData { line: None, column_start: 0, column_end: 0, src_file_path: None }, node: Node::List(items) })
278}
279
280fn parse(iter: &mut TokenIterator, current_binding_power: isize, ) -> Result<TracedNode, CryptError> {
281 let Some(current) = iter.next() else {
282 return Err(CryptError(None, CryptErrorType::UnexpectedEOF))
283 };
284
285 let mut left = parse_nud(iter, current)?;
286
287 while let Some(t) = iter.peek() && t.token.get_binding_power() > current_binding_power {
288 let current = iter.next().unwrap();
289 left = parse_led(iter, left, current)?;
290 }
291
292 Ok(left)
293}
294
295fn parse_nud(iter: &mut TokenIterator, current: TracedToken<Token>) -> Result<TracedNode, CryptError> {
296 let pos = current.trace.clone();
297 let token = current.token;
298 let node = match token.clone() {
299 Token::Identifier(ident) => Node::Identifier(ident),
300 Token::String(str) => Node::String(str),
301 Token::Integer(int) => Node::Integer(int),
302 Token::Float(fl) => Node::Float(fl),
303 Token::Boolean(bool) => Node::Boolean(bool),
304 Token::Null => Node::Null,
305
306 Token::Import => {
307 let Some(t) = iter.next() else {
308 return Err(CryptError(None, CryptErrorType::UnexpectedEOF))
309 };
310
311 let path_token_pos = t.trace;
312 let t = t.token;
313 let Token::String(str) = t.clone() else {
314 return Err(CryptError(Some(path_token_pos), CryptErrorType::ExpectedOther("path string", t)))
315 };
316
317 Node::Import(str)
318 },
319
320 Token::SingleTag => {
321 if let Some(t) = iter.peek() && matches!(t.token, Token::TagOpen) {
322 iter.next();
323 let mut tags = Vec::new();
324 while let Some(t) = iter.peek() && !matches!(t.token, Token::TagClose) {
325 let tag = parse(iter, 1)?;
326 tags.push(tag);
327
328 if let Some(t) = iter.peek() && matches!(t.token, Token::Break) {
329 iter.next();
330 } else {
331 break;
332 }
333 }
334 if let Some(t) = iter.next() && !matches!(t.token, Token::TagClose) {
335 return Err(CryptError(Some(t.trace.clone()), CryptErrorType::ExpectedOther("closing ')'", t.token)))
336 }
337 Node::Tag(tags, Box::new(parse(iter, 1)?))
338 } else {
339 let tag = parse(iter, 1)?;
340 Node::Tag(vec![tag], Box::new(parse(iter, 1)?))
341 }
342 }
343
344 Token::BodyOpen => {
345 let mut items = Vec::new();
346 while let Some(t) = iter.peek() && !matches!(t.token, Token::BodyClose) {
347 let item = parse(iter, 1)?;
348 items.push(item);
349
350 if let Some(t) = iter.peek() && matches!(t.token, Token::Break) {
351 iter.next();
352 } else {
353 break;
354 }
355 }
356 if let Some(t) = iter.next() && !matches!(t.token, Token::BodyClose) {
357 return Err(CryptError(Some(t.trace.clone()), CryptErrorType::ExpectedOther("closing '}'", t.token)))
358 }
359 Node::Body(items)
360 }
361
362 Token::ListOpen => {
363 let mut items = Vec::new();
364 while let Some(t) = iter.peek() && !matches!(t.token, Token::ListClose) {
365 let item = parse(iter, 1)?;
366 items.push(item);
367
368 if let Some(t) = iter.peek() && matches!(t.token, Token::Break) {
369 iter.next();
370 } else {
371 break;
372 }
373 }
374 if let Some(t) = iter.next() && !matches!(t.token, Token::ListClose) {
375 return Err(CryptError(Some(t.trace.clone()), CryptErrorType::ExpectedOther("closing ']'", t.token)))
376 }
377 Node::List(items)
378 }
379
380 _ => return Err(CryptError(Some(pos), CryptErrorType::UnexpectedToken(token)))
381 };
382
383 Ok(TracedNode { position: pos, node, })
384}
385
386fn parse_led(iter: &mut TokenIterator, left: TracedNode, current: TracedToken<Token>) -> Result<TracedNode, CryptError> {
387 let pos = current.trace.clone();
388 let token = current.token;
389 let node = match token.clone() {
390 Token::Assign => {
391 let ident = match left.node {
392 Node::Identifier(ident) => ident,
393 Node::String(str) => str,
394 _ => return Err(CryptError(Some(left.position), CryptErrorType::ExpectedIdentifier))
395 };
396
397 let object = parse(iter, 1)?;
398 Node::Assignment(ident, Box::new(object))
399 }
400
401 _ => return Err(CryptError(Some(pos), CryptErrorType::UnexpectedToken(token)))
402 };
403
404 Ok(TracedNode { position: pos, node, })
405}
406
407
408
409
410fn resolve(node: TracedNode, server: &mut CryptParserServer) -> Result<TracedObject, CryptError> {
411 let pos = node.position;
412
413 let obj = match node.node {
414 Node::Identifier(ident) => CryptObject::FloatingIdentifier(ident),
415 Node::String(str) => CryptObject::ConstantString(str),
416 Node::Integer(int) => CryptObject::ConstantInteger(int),
417 Node::Float(fl) => CryptObject::ConstantFloat(fl),
418 Node::Boolean(bool) => CryptObject::ConstantBoolean(bool),
419 Node::Null => CryptObject::Null,
420 Node::Assignment(ident, item) => CryptObject::IdentifiedObject(ident, Box::new(resolve(*item, server)?)),
421 Node::Body(items) => {
422 let mut body = IndexMap::new();
423 for item in items {
424 let item = resolve(item, server)?;
425 match item.object {
426 CryptObject::IdentifiedObject(ident, item) => {
427 body.insert(ident, *item);
428 }
429 CryptObject::TaggedObject(tags, tagged_item) =>
430 if let CryptObject::IdentifiedObject(ident, tagged_item) = tagged_item.object {
431 body.insert(ident, TracedObject { position: item.position, object: CryptObject::TaggedObject(tags, tagged_item) });
432 } else {
433 return Err(CryptError(Some(item.position), CryptErrorType::ExpectedIdentifier))
434 },
435 _ => return Err(CryptError(Some(item.position), CryptErrorType::ExpectedIdentifier))
436 }
437 }
438 CryptObject::ObjectBody(body)
439 }
440 Node::List(items) => {
441 let mut resolved_items = Vec::new();
442 for item in items {
443 let item = resolve(item, server)?;
444 resolved_items.push(item);
445 }
446 CryptObject::ObjectList(resolved_items)
447 }
448 Node::Tag(tags, object) => {
449 let mut resolved_tags = Vec::new();
450 for tag in tags {
451 let tag = resolve(tag, server)?;
452 resolved_tags.push(tag);
453 }
454 CryptObject::TaggedObject(resolved_tags, Box::new(resolve(*object, server)?))
455 }
456 Node::Import(path) => {
457 let Some(current_path) = pos.src_file_path else {
458 return Err(CryptError(Some(pos), CryptErrorType::CannotImport))
459 };
460
461 let path_buf =
462 PathBuf::from(current_path.as_ref())
463 .canonicalize().unwrap(); let final_path = path_buf.parent().unwrap().join(path);
465
466 return server.open(final_path)
467 }
468 };
469
470 Ok(TracedObject { position: pos, object: obj })
471}
472
473
474
475
476#[derive(Debug, Clone)]
481pub struct TracedObject {
489 position: TokenTraceData,
490 object: CryptObject,
491}
492
493#[derive(Debug, Clone)]
494enum CryptObject {
496 ConstantString(String),
497 ConstantInteger(i64),
498 ConstantFloat(f64),
499 ConstantBoolean(bool),
500 Null,
501 FloatingIdentifier(String),
502 IdentifiedObject(String, Box<TracedObject>),
503
504 TaggedObject (Vec<TracedObject>, Box<TracedObject>),
505
506 ObjectBody(IndexMap<String, TracedObject>),
507 ObjectList(Vec<TracedObject>),
508}
509
510#[derive(Debug, Clone)]
511pub enum CrypticObject {
517 ConstantString(String),
518 ConstantInteger(i64),
519 ConstantFloat(f64),
520 ConstantBoolean(bool),
521 Null,
522 FloatingIdentifier(String),
523 IdentifiedObject(String, Box<CrypticObject>),
524
525 TaggedObject (Vec<CrypticObject>, Box<CrypticObject>),
526
527 ObjectBody(HashMap<String, CrypticObject>),
528 ObjectList(Vec<CrypticObject>),
529}
530
531#[derive(Debug, Clone)]
532pub struct Tagged<T, O> {
534 pub tag: T,
535 pub object: O
536}
537
538#[derive(Debug, Clone)]
539pub struct HashTagged<T, O> {
541 pub tags: HashMap<String, T>,
542 pub object: O
543}
544
545#[derive(Debug, Clone)]
546pub struct ListTagged<T, O> {
548 pub tags: Vec<T>,
549 pub object: O
550}
551
552
553
554pub trait Cryptic: Sized {
563 fn cryptic(object: TracedObject) -> Result<Self, CryptError>;
568}
569
570impl TryInto<String> for TracedObject {
571 type Error = CryptError;
572
573 fn try_into(self) -> Result<String, Self::Error> {
574 match self.object {
575 CryptObject::ConstantString(str) => Ok(str),
576 CryptObject::FloatingIdentifier(ident) => Ok(ident),
577 CryptObject::ConstantInteger(int) => Ok(int.to_string()),
578 CryptObject::ConstantFloat(fl) => Ok(fl.to_string()),
579 CryptObject::ConstantBoolean(b) => Ok(b.to_string()),
580 CryptObject::Null => Ok(String::new()),
581 CryptObject::IdentifiedObject(_, obj) => (*obj).try_into(),
582 CryptObject::TaggedObject(_, obj) => (*obj).try_into(),
583 _ => Err(CryptError(Some(self.position), CryptErrorType::UnexpectedType))
584 }
585 }
586}
587
588impl TryInto<bool> for TracedObject {
589 type Error = CryptError;
590
591 fn try_into(self) -> Result<bool, Self::Error> {
592 match self.object {
593 CryptObject::ConstantString(str) => Ok(str != ""),
594 CryptObject::FloatingIdentifier(_) => Ok(true),
595 CryptObject::ConstantInteger(int) => Ok(int != 0),
596 CryptObject::ConstantFloat(fl) => Ok(fl != 0.0),
597 CryptObject::ConstantBoolean(b) => Ok(b),
598 CryptObject::Null => Ok(false),
599 CryptObject::IdentifiedObject(_, obj) => (*obj).try_into(),
600 CryptObject::TaggedObject(_, obj) => (*obj).try_into(),
601 _ => Err(CryptError(Some(self.position), CryptErrorType::UnexpectedType))
602 }
603 }
604}
605
606macro_rules! try_into_int {
607 ($($ty:ty)+) => {
608 $(
609 impl TryInto<$ty> for TracedObject {
610 type Error = CryptError;
611
612 fn try_into(self) -> Result<$ty, Self::Error> {
613 match self.object {
614 CryptObject::ConstantInteger(int) => Ok(int as _),
615 CryptObject::ConstantFloat(fl) => Ok(fl as _),
616 CryptObject::ConstantBoolean(b) => Ok(if b {1 as _} else {0 as _}),
617 CryptObject::ConstantString(str) => match str.parse() {
618 Ok(i) => Ok(i),
619 Err(_) => Err(CryptError(Some(self.position), CryptErrorType::ParseError))
620 },
621 CryptObject::IdentifiedObject(_, item) => (*item).try_into(),
622 CryptObject::TaggedObject(_, obj) => (*obj).try_into(),
623 _ => Err(CryptError(Some(self.position), CryptErrorType::UnexpectedType))
624 }
625 }
626 }
627 )+
628 };
629}
630try_into_int!(i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64);
631
632impl<T> TryInto<Vec<T>> for TracedObject
633where
634 T: Cryptic
635{
636 type Error = CryptError;
637
638 fn try_into(self) -> Result<Vec<T>, Self::Error> {
639 match self.object {
640 CryptObject::ObjectList(list) =>
641 list
642 .into_iter()
643 .map(|i| T::cryptic(i))
644 .collect(),
645 CryptObject::ObjectBody(body) =>
646 body
647 .into_values()
648 .into_iter()
649 .map(|i| T::cryptic(i))
650 .collect(),
651
652 CryptObject::IdentifiedObject(_, obj) => (*obj).try_into(),
653 CryptObject::TaggedObject(_, obj) => (*obj).try_into(),
654
655 _ => Ok(vec![T::cryptic(self)?])
656 }
657 }
658}
659
660impl<T> TryInto<HashMap<String, T>> for TracedObject
661where
662 T: Cryptic
663{
664 type Error = CryptError;
665
666 fn try_into(self) -> Result<HashMap<String, T>, Self::Error> {
667 match self.object {
668 CryptObject::ObjectBody(body) =>
669 body
670 .into_iter()
671 .map(|(k, i)| T::cryptic(i).map(|i| (k, i)))
672 .collect(),
673 CryptObject::ObjectList(list) => {
674 let mut body = HashMap::new();
675 let mut idx: usize = 0;
676 for item in list {
677 if let CryptObject::IdentifiedObject(ident, item) = item.object {
678 body.insert(ident, T::cryptic(*item)?);
679 } else {
680 body.insert(idx.to_string(), T::cryptic(item)?);
681 idx += 1;
682 }
683 }
684 Ok(body)
685 },
686
687 CryptObject::IdentifiedObject(ident, item) => Ok(vec![(ident, T::cryptic(*item)?)].into_iter().collect()),
688 CryptObject::TaggedObject(_, item) => (*item).try_into(),
689
690 _ => Err(CryptError(Some(self.position), CryptErrorType::UnexpectedType))
691 }
692 }
693}
694
695
696impl<T, O> TryInto<Tagged<T, O>> for TracedObject
697where
698 T: Cryptic,
699 O: Cryptic
700{
701 type Error = CryptError;
702
703 fn try_into(self) -> Result<Tagged<T, O>, Self::Error> {
704 match self.object {
705 CryptObject::TaggedObject(tags, obj) => {
706 let Some(tag) = tags.into_iter().next() else {
707 return Err(CryptError(Some(self.position), CryptErrorType::ExpectedTag))
708 };
709 let tag = T::cryptic(tag)?;
710
711 Ok(Tagged { tag: tag, object: O::cryptic(*obj)? })
712 }
713
714 _ => Err(CryptError(Some(self.position), CryptErrorType::UnexpectedType))
715
716 }
717 }
718}
719
720impl<T, O> TryInto<ListTagged<T, O>> for TracedObject
721where
722 T: Cryptic,
723 O: Cryptic
724{
725 type Error = CryptError;
726
727 fn try_into(self) -> Result<ListTagged<T, O>, Self::Error> {
728 match self.object {
729 CryptObject::TaggedObject(tags, obj) => {
730 let tags = tags.into_iter().map(|i| T::cryptic(i)).collect::<Result<Vec<T>, CryptError>>()?;
731 Ok(ListTagged { tags, object: O::cryptic(*obj)? })
732 }
733
734 _ => Ok(ListTagged { tags: Vec::new(), object: O::cryptic(self)? })
735 }
736 }
737}
738
739impl<T, O> TryInto<HashTagged<T, O>> for TracedObject
740where
741 T: Cryptic,
742 O: Cryptic
743{
744 type Error = CryptError;
745
746 fn try_into(self) -> Result<HashTagged<T, O>, Self::Error> {
747 match self.object {
748 CryptObject::TaggedObject(tags, item) => {
749 let mut built_tags = HashMap::new();
750 let mut idx: usize = 0;
751 for tag in tags {
752 if let CryptObject::IdentifiedObject(ident, item) = tag.object {
753 built_tags.insert(ident, T::cryptic(*item)?);
754 } else {
755 built_tags.insert(idx.to_string(), T::cryptic(tag)?);
756 idx += 1;
757 }
758 }
759 Ok(HashTagged { tags: built_tags, object: O::cryptic(*item)? })
760 }
761
762 _ => Ok(HashTagged { tags: HashMap::new(), object: O::cryptic(self)? })
763 }
764 }
765}
766
767impl<T> Cryptic for T
768where
769 TracedObject: TryInto<T, Error = CryptError>,
770{
771 fn cryptic(object: TracedObject) -> Result<Self, CryptError> {
772 object.try_into()
773 }
774}
775
776impl Cryptic for CryptObject {
777 fn cryptic(object: TracedObject) -> Result<Self, CryptError> {
778 Ok(object.object)
779 }
780}
781
782impl Cryptic for CrypticObject {
783 fn cryptic(object: TracedObject) -> Result<Self, CryptError> {
784 Ok(match object.object {
785 CryptObject::ConstantString(str) => CrypticObject::ConstantString(str),
786 CryptObject::ConstantInteger(int) => CrypticObject::ConstantInteger(int),
787 CryptObject::ConstantFloat(fl) => CrypticObject::ConstantFloat(fl),
788 CryptObject::ConstantBoolean(b) => CrypticObject::ConstantBoolean(b),
789 CryptObject::Null => CrypticObject::Null,
790 CryptObject::FloatingIdentifier(ident) => CrypticObject::FloatingIdentifier(ident),
791 CryptObject::IdentifiedObject(ident, item) => CrypticObject::IdentifiedObject(ident, Box::new(CrypticObject::cryptic(*item).unwrap())),
792 CryptObject::TaggedObject (tags, item) => CrypticObject::TaggedObject(tags.into_iter().map(|i| CrypticObject::cryptic(i).unwrap()).collect(), Box::new(CrypticObject::cryptic(*item).unwrap())),
793 CryptObject::ObjectBody(body) => CrypticObject::ObjectBody(body.into_iter().map(|(ident, item)| (ident, CrypticObject::cryptic(item).unwrap())).collect()),
794 CryptObject::ObjectList(list) => CrypticObject::ObjectList(list.into_iter().map(|i| CrypticObject::cryptic(i).unwrap()).collect()),
795 })
796 }
797}
798
799impl<T> Cryptic for Option<T>
800where
801 T: Cryptic
802{
803 fn cryptic(object: TracedObject) -> Result<Self, CryptError> {
804 match object.object {
805 CryptObject::Null => Ok(None),
806 _ => Ok(Some(Cryptic::cryptic(object)?))
807 }
808 }
809}
810
811impl Cryptic for TracedObject {
812 fn cryptic(object: TracedObject) -> Result<Self, CryptError> {
813 Ok(object)
814 }
815}
816
817#[derive(Debug)]
818pub struct CryptError(Option<TokenTraceData>, CryptErrorType);
820
821impl CryptError {
822 pub const fn cannot_find_ident(name: &'static str) -> Self {
823 Self(None, CryptErrorType::NoItemOfIdentifier(name))
824 }
825 pub const fn not_enough_items() -> Self {
826 Self(None, CryptErrorType::NotEnoughItems)
827 }
828 pub fn invalid_enum_variant(variant: String) -> Self {
829 Self(None, CryptErrorType::InvalidEnumVariant(variant))
830 }
831}
832
833#[derive(Debug)]
834enum CryptErrorType {
835 UnexpectedToken(Token),
836 ExpectedOther(&'static str, Token),
837 UnexpectedEOF,
838 ExpectedIdentifier,
839 CannotImport,
840 UnexpectedType,
841 ParseError,
842 ExpectedTag,
843
844 NoItemOfIdentifier(&'static str),
845 NotEnoughItems,
846 InvalidEnumVariant(String),
847
848 OsError(std::io::Error),
849}
850
851impl std::fmt::Display for CryptError {
852 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
853 match &self.1 {
854 CryptErrorType::UnexpectedToken(t) => writeln!(f, "Unexpected token: {}", t),
855 CryptErrorType::ExpectedOther(desc, t) => writeln!(f, "Unexpected token: {}, expected {}", t, desc),
856 CryptErrorType::UnexpectedEOF => writeln!(f, "Unexpected end of file"),
857 CryptErrorType::ExpectedIdentifier => writeln!(f, "Expected an identifier"),
858 CryptErrorType::CannotImport => writeln!(f, "Cannot import here"),
859 CryptErrorType::UnexpectedType => writeln!(f, "Unexpected type"),
860 CryptErrorType::ParseError => writeln!(f, "Failed to parse"),
861 CryptErrorType::ExpectedTag => writeln!(f, "Expected a tag"),
862 CryptErrorType::OsError(e) => writeln!(f, "{}", e),
863 CryptErrorType::NoItemOfIdentifier(ident) => write!(f, "Couldn't find item: {}", ident),
864 CryptErrorType::NotEnoughItems => write!(f, "Not enough items found"),
865 CryptErrorType::InvalidEnumVariant(v) => write!(f, "Invalid enum variant: {}", v),
866 }?;
867
868 if let Some(pos) = &self.0 {
869 writeln!(f, "at: {:?}", pos)?;
870 }
871
872 Ok(())
873 }
874}
875
876impl std::error::Error for CryptError {}
877
878impl From<std::io::Error> for CryptError {
879 fn from(value: std::io::Error) -> Self {
880 CryptError(None, CryptErrorType::OsError(value))
881 }
882}