ason/
lib.rs

1// Copyright (c) 2024 Hemashushu <hippospark@gmail.com>, All rights reserved.
2//
3// This Source Code Form is subject to the terms of
4// the Mozilla Public License version 2.0 and additional exceptions,
5// more details in file LICENSE, LICENSE.additional and CONTRIBUTING.
6
7pub mod ast;
8mod charstream;
9mod charwithposition;
10mod errorprinter;
11mod lexer;
12mod location;
13mod normalizer;
14mod parser;
15mod peekableiter;
16mod printer;
17mod serde;
18mod token;
19
20pub use parser::parse_from_reader;
21pub use parser::parse_from_str;
22pub use printer::print_to_string;
23pub use printer::print_to_writer;
24
25pub use serde::de::from_reader;
26pub use serde::de::from_str;
27pub use serde::ser::to_string;
28pub use serde::ser::to_writer;
29pub use serde::serde_date::Date;
30
31use std::fmt::{self, Display};
32
33use crate::location::Location;
34
35#[derive(Debug, PartialEq, Clone)]
36pub enum AsonError {
37    Message(String),
38    UnexpectedEndOfDocument(String),
39
40    // note that the "index" (and the result of "index+length") may exceed
41    // the last index of string, for example, the "char incomplete" error raised by a string `'a`,
42    // which index is 2.
43    MessageWithLocation(String, Location),
44}
45
46impl Display for AsonError {
47    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48        match self {
49            AsonError::Message(msg) => f.write_str(msg),
50            AsonError::UnexpectedEndOfDocument(detail) => {
51                writeln!(f, "Unexpected to reach the end of document.")?;
52                write!(f, "{}", detail)
53            }
54            AsonError::MessageWithLocation(detail, location) => {
55                writeln!(
56                    f,
57                    "Error at line: {}, column: {}",
58                    location.line + 1,
59                    location.column + 1
60                )?;
61                write!(f, "{}", detail)
62            }
63        }
64    }
65}
66
67impl std::error::Error for AsonError {}
68
69// #[cfg(test)]
70// mod tests {
71//     use std::collections::HashMap;
72//
73//     use serde::{Deserialize, Serialize};
74//
75//     use crate::{
76//         ast::{AsonNode, KeyValuePair, Number},
77//         from_str, parse_from_str, print_to_string, to_string,
78//     };
79//     use pretty_assertions::assert_eq;
80//
81//     #[test]
82//     fn test_from_str_and_to_string() {
83//         #[derive(Debug, PartialEq, Serialize, Deserialize)]
84//         struct Package {
85//             name: String,
86//
87//             #[serde(rename = "type")]
88//             type_: Type,
89//
90//             version: String,
91//             dependencies: HashMap<String, Option<String>>,
92//         }
93//
94//         #[derive(Debug, PartialEq, Serialize, Deserialize)]
95//         enum Type {
96//             Application,
97//             Library,
98//         }
99//
100//         let text = r#"{
101//             name: "foo"
102//             type: Type::Application
103//             version: "0.1.0"
104//             dependencies: {
105//                 "random": Option::None
106//                 "regex": Option::Some("1.0.1")
107//             }
108//         }"#;
109//
110//         let package = from_str::<Package>(text).unwrap();
111//         assert_eq!(package.name, "foo");
112//         assert_eq!(package.type_, Type::Application);
113//         assert_eq!(package.version, "0.1.0");
114//         assert_eq!(package.dependencies.get("random").unwrap(), &None);
115//         assert_eq!(
116//             package.dependencies.get("regex").unwrap(),
117//             &Some("1.0.1".to_owned())
118//         );
119//
120//         // test `to_string`
121//
122//         let s = to_string(&package).unwrap();
123//         assert!(s.starts_with("{"));
124//         assert!(s.ends_with("}"));
125//         assert!(s.contains(r#"name: "foo""#));
126//         assert!(s.contains(r#"type: Type::Application"#));
127//         assert!(s.contains(r#"version: "0.1.0""#));
128//         assert!(s.contains(r#"dependencies: {"#));
129//         assert!(s.contains(r#""random": Option::None"#));
130//         assert!(s.contains(r#""regex": Option::Some("1.0.1")"#));
131//     }
132//
133//     #[test]
134//     fn test_parse_from_and_print_to() {
135//         let text = r#"{
136//     id: 123
137//     name: "John"
138//     orders: [
139//         11
140//         13
141//     ]
142// }"#;
143//
144//         let node = parse_from_str(text).unwrap();
145//
146//         assert_eq!(
147//             node,
148//             AsonNode::Object(vec![
149//                 KeyValuePair {
150//                     key: String::from("id"),
151//                     value: Box::new(AsonNode::Number(Number::I32(123)))
152//                 },
153//                 KeyValuePair {
154//                     key: String::from("name"),
155//                     value: Box::new(AsonNode::String(String::from("John")))
156//                 },
157//                 KeyValuePair {
158//                     key: String::from("orders"),
159//                     value: Box::new(AsonNode::List(vec![
160//                         AsonNode::Number(Number::I32(11)),
161//                         AsonNode::Number(Number::I32(13))
162//                     ]))
163//                 }
164//             ])
165//         );
166//
167//         // test `print_to_string`
168//         let s = print_to_string(&node);
169//         assert_eq!(s, text);
170//     }
171// }