oxur_lang/
lib.rs

1//! Oxur Language Processing
2//!
3//! This crate handles the frontend of the Oxur compilation pipeline:
4//! - Stage 1: Parse (Oxur syntax → Surface Forms)
5//! - Stage 2: Expand (Surface Forms → Core Forms)
6//!
7//! Core Forms are the stable intermediate representation (IR) that serves
8//! as the contract between the frontend (oxur-lang) and backend (oxur-comp).
9
10pub 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
18// Re-export oxur-smap types for convenience
19pub use oxur_smap::{new_node_id, SourceMap, SourcePos};
20
21/// Result type for language operations
22pub type Result<T> = std::result::Result<T, Error>;
23
24/// Error types for language processing
25#[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/// Source location for error reporting
38#[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}