Skip to main content

typr_core/
lib.rs

1//! # TypR Core
2//!
3//! Pure logic for TypR - a typed superset of R.
4//!
5//! This crate contains the core functionality that can be compiled to WebAssembly:
6//! - Parsing TypR source code
7//! - Type checking
8//! - Transpilation to R
9//!
10//! ## Architecture
11//!
12//! The crate is designed to be platform-agnostic by using trait abstractions
13//! for all I/O operations:
14//!
15//! - [`SourceProvider`]: Provides source code content (replaces `std::fs::read_to_string`)
16//! - [`OutputHandler`]: Handles transpilation output (replaces file writes)
17//! - [`PackageChecker`]: Checks/installs R packages (replaces `Command` execution)
18//!
19//! ## Usage
20//!
21//! ```rust,ignore
22//! use typr_core::{Compiler, InMemorySourceProvider};
23//!
24//! let mut sources = InMemorySourceProvider::new();
25//! sources.add_source("main.ty", "let x: Number = 42;");
26//!
27//! let compiler = Compiler::new(sources);
28//! let result = compiler.compile("main.ty")?;
29//! println!("R code: {}", result.r_code);
30//! ```
31
32pub mod abstractions;
33pub mod components;
34pub mod processes;
35pub mod utils;
36
37// Re-export main types
38pub use abstractions::*;
39pub use components::context::config::Environment;
40pub use components::context::Context;
41pub use components::error_message::typr_error::TypRError;
42pub use components::language::Lang;
43pub use components::r#type::Type;
44
45// Re-export main functions
46pub use processes::parsing;
47pub use processes::transpiling;
48pub use processes::type_checking::{typing, typing_with_errors, TypingResult};
49
50/// Main compiler interface for TypR
51pub struct Compiler<S: SourceProvider> {
52    source_provider: S,
53    context: Context,
54}
55
56impl<S: SourceProvider> Compiler<S> {
57    /// Create a new compiler with the given source provider
58    pub fn new(source_provider: S) -> Self {
59        Self {
60            source_provider,
61            context: Context::default(),
62        }
63    }
64
65    /// Create a compiler configured for WASM environment
66    ///
67    /// In WASM mode:
68    /// - All external modules are inlined
69    /// - No source() calls are generated
70    /// - Generated files are collected and can be retrieved
71    pub fn new_wasm(source_provider: S) -> Self {
72        use components::context::config::Config;
73
74        let config = Config::default().set_environment(Environment::Wasm);
75        Self {
76            source_provider,
77            context: config.to_context(),
78        }
79    }
80
81    /// Create a compiler with a custom context
82    pub fn with_context(source_provider: S, context: Context) -> Self {
83        Self {
84            source_provider,
85            context,
86        }
87    }
88
89    /// Get the current context
90    pub fn get_context(&self) -> Context {
91        self.context.clone()
92    }
93
94    /// Parse source code and return the AST
95    pub fn parse(&self, filename: &str) -> Result<Lang, CompileError> {
96        let source = self
97            .source_provider
98            .get_source(filename)
99            .ok_or_else(|| CompileError::FileNotFound(filename.to_string()))?;
100
101        Ok(parsing::parse_from_string(&source, filename))
102    }
103
104    /// Type check the given AST
105    pub fn type_check(&self, ast: &Lang) -> TypingResult {
106        typing_with_errors(&self.context, ast)
107    }
108
109    /// Transpile AST to R code
110    pub fn transpile(&self, ast: &Lang) -> TranspileResult {
111        use processes::type_checking::type_checker::TypeChecker;
112
113        let type_checker = TypeChecker::new(self.context.clone()).typing(ast);
114        let r_code = type_checker.clone().transpile();
115        let context = type_checker.get_context();
116
117        TranspileResult {
118            r_code,
119            type_annotations: context.get_type_anotations(),
120            generic_functions: context
121                .get_all_generic_functions()
122                .iter()
123                .map(|(var, _)| var.get_name())
124                .filter(|x| !x.contains("<-"))
125                .collect(),
126        }
127    }
128
129    /// Full compilation: parse, type check, and transpile
130    pub fn compile(&self, filename: &str) -> Result<CompileOutput, CompileError> {
131        let ast = self.parse(filename)?;
132        let typing_result = self.type_check(&ast);
133
134        if typing_result.has_errors() {
135            return Err(CompileError::TypeErrors(typing_result.get_errors().clone()));
136        }
137
138        let transpile_result = self.transpile(&ast);
139
140        Ok(CompileOutput {
141            ast,
142            r_code: transpile_result.r_code,
143            type_annotations: transpile_result.type_annotations,
144            generic_functions: transpile_result.generic_functions,
145        })
146    }
147
148    /// Get completions at a position (for LSP support)
149    pub fn get_completions(&self, _source: &str, _position: usize) -> Vec<String> {
150        // TODO: Implement completion logic
151        vec![]
152    }
153
154    /// Get hover information at a position (for LSP support)
155    pub fn get_hover(&self, _source: &str, _position: usize) -> Option<String> {
156        // TODO: Implement hover logic
157        None
158    }
159}
160
161/// Result of transpilation
162#[derive(Debug, Clone)]
163pub struct TranspileResult {
164    pub r_code: String,
165    pub type_annotations: String,
166    pub generic_functions: Vec<String>,
167}
168
169/// Full compilation output
170#[derive(Debug, Clone)]
171pub struct CompileOutput {
172    pub ast: Lang,
173    pub r_code: String,
174    pub type_annotations: String,
175    pub generic_functions: Vec<String>,
176}
177
178/// Compilation errors
179#[derive(Debug, Clone)]
180pub enum CompileError {
181    FileNotFound(String),
182    ParseError(String),
183    TypeErrors(Vec<TypRError>),
184}
185
186impl std::fmt::Display for CompileError {
187    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188        match self {
189            CompileError::FileNotFound(name) => write!(f, "File not found: {}", name),
190            CompileError::ParseError(msg) => write!(f, "Parse error: {}", msg),
191            CompileError::TypeErrors(errors) => {
192                write!(f, "Type errors:\n")?;
193                for err in errors {
194                    write!(f, "  - {:?}\n", err)?;
195                }
196                Ok(())
197            }
198        }
199    }
200}
201
202impl std::error::Error for CompileError {}