1pub mod core_forms;
11pub mod expander;
12pub mod parser;
13
14pub use core_forms::{CoreForm, NodeId};
15pub use expander::Expander;
16pub use parser::Parser;
17
18pub use oxur_smap::{new_node_id, SourceMap, SourcePos};
20
21pub type Result<T> = std::result::Result<T, Error>;
23
24#[derive(Debug, thiserror::Error)]
26pub enum Error {
27 #[error("Parse error at {location}: {message}")]
28 Parse { message: String, location: Location },
29
30 #[error("Expansion error at node {node_id}: {message}")]
31 Expand { message: String, node_id: NodeId },
32
33 #[error("Invalid syntax: {0}")]
34 Syntax(String),
35}
36
37#[derive(Debug, Clone, Copy)]
39pub struct Location {
40 pub line: usize,
41 pub column: usize,
42}
43
44impl std::fmt::Display for Location {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 write!(f, "{}:{}", self.line, self.column)
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn test_location_display() {
56 let loc = Location { line: 10, column: 25 };
57 assert_eq!(format!("{}", loc), "10:25");
58 }
59
60 #[test]
61 fn test_parse_error_display() {
62 let err = Error::Parse {
63 message: "unexpected token".to_string(),
64 location: Location { line: 1, column: 5 },
65 };
66 let msg = format!("{}", err);
67 assert!(msg.contains("Parse error"));
68 assert!(msg.contains("1:5"));
69 assert!(msg.contains("unexpected token"));
70 }
71
72 #[test]
73 fn test_expand_error_display() {
74 let err = Error::Expand {
75 message: "macro expansion failed".to_string(),
76 node_id: NodeId::from_raw(42),
77 };
78 let msg = format!("{}", err);
79 assert!(msg.contains("Expansion error"));
80 assert!(msg.contains("NodeId(42)"));
81 assert!(msg.contains("macro expansion failed"));
82 }
83
84 #[test]
85 fn test_syntax_error_display() {
86 let err = Error::Syntax("invalid syntax".to_string());
87 let msg = format!("{}", err);
88 assert!(msg.contains("Invalid syntax"));
89 assert!(msg.contains("invalid syntax"));
90 }
91}