Skip to main content

mq_lang/
ast.rs

1use node::Node;
2
3use crate::{Shared, Token, arena::ArenaId};
4
5pub mod code;
6pub mod constants;
7pub mod node;
8pub mod parser;
9
10pub type Program = Vec<Shared<Node>>;
11pub type TokenId = ArenaId<Shared<Token>>;
12
13/// Serializes an AST `Program` to a JSON string.
14///
15/// # Errors
16///
17/// Returns a `miette::Error` if serialization fails.
18#[cfg(feature = "ast-json")]
19pub fn ast_to_json(program: &Program) -> miette::Result<String> {
20    serde_json::to_string(program).map_err(|e| miette::miette!("Failed to serialize AST to JSON: {}", e))
21}
22
23/// Deserializes a JSON string into an AST `Program`.
24///
25/// # Errors
26///
27/// Returns a `miette::Error` if deserialization fails.
28#[cfg(feature = "ast-json")]
29pub fn ast_from_json(json: &str) -> miette::Result<Program> {
30    serde_json::from_str(json).map_err(|e| miette::miette!("Failed to deserialize AST from JSON: {}", e))
31}
32
33#[cfg(test)]
34mod tests {
35    #[cfg(feature = "ast-json")]
36    use super::*;
37
38    #[cfg(feature = "ast-json")]
39    #[test]
40    fn test_ast_to_json_and_from_json_roundtrip() {
41        use crate::{AstExpr, ast::node::IdentWithToken};
42
43        let ident = Shared::new(Node {
44            token_id: TokenId::new(1),
45            expr: Shared::new(AstExpr::Ident(IdentWithToken::new("foo"))),
46        });
47        let program = vec![ident.clone()];
48
49        let json = ast_to_json(&program).expect("Serialization should succeed");
50        let deserialized = ast_from_json(&json).expect("Deserialization should succeed");
51
52        assert_eq!(deserialized.len(), 1);
53        match &*deserialized[0].expr {
54            AstExpr::Ident(name) => assert_eq!(name.name, "foo".into()),
55            _ => panic!("Expected Ident node"),
56        }
57    }
58}