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