Skip to main content

typr_cli/
engine.rs

1//! Build engine utilities for TypR CLI
2//!
3//! Provides functions for:
4//! - Parsing code files
5//! - Compiling with error collection
6//! - Writing standard library files
7
8#![allow(dead_code)]
9
10use crate::io::{get_os_file, read_file};
11use crate::metaprogramming::metaprogrammation;
12use nom_locate::LocatedSpan;
13use std::fs::File;
14use std::io::Write;
15use std::path::PathBuf;
16use typr_core::components::context::config::Environment;
17use typr_core::components::context::Context;
18use typr_core::components::error_message::syntax_error::SyntaxError;
19use typr_core::components::error_message::typr_error::TypRError;
20use typr_core::components::language::Lang;
21use typr_core::components::r#type::Type;
22use typr_core::processes::parsing::{parse, ParseResult};
23use typr_core::typing_with_errors;
24
25pub fn write_std_for_type_checking(output_dir: &PathBuf) {
26    let rstd = include_str!("../configs/std/std_R.ty");
27    let std_path = output_dir.join("std.ty");
28    let mut rstd_file = File::create(std_path).unwrap();
29    rstd_file.write_all(rstd.as_bytes()).unwrap();
30}
31
32pub struct TypRFile<'a> {
33    content: &'a str,
34    name: String,
35}
36
37impl<'a> TypRFile<'a> {
38    pub fn new(content: &'a str, name: String) -> TypRFile<'a> {
39        TypRFile {
40            content: content,
41            name: name,
42        }
43    }
44
45    /// Parse and return the full ParseResult with AST and collected errors
46    pub fn parse_with_errors(self) -> ParseResult {
47        parse(LocatedSpan::new_extra(self.content, self.name))
48    }
49
50    /// Parse and return just the AST (legacy behavior)
51    pub fn parse(self) -> Lang {
52        self.parse_with_errors().ast
53    }
54}
55
56/// Result of parsing a code file, containing the AST and any syntax errors
57pub struct ParseCodeResult {
58    pub ast: Lang,
59    pub errors: Vec<SyntaxError>,
60}
61
62impl ParseCodeResult {
63    pub fn has_errors(&self) -> bool {
64        !self.errors.is_empty()
65    }
66}
67
68/// Parse code and return the AST along with any syntax errors collected
69pub fn parse_code_with_errors(path: &PathBuf, environment: Environment) -> ParseCodeResult {
70    let file = get_os_file(path.to_str().unwrap());
71    let file_content = read_file(path).expect(&format!("Path {:?} not found", path));
72    let base_file = TypRFile::new(&file_content, file);
73
74    let parse_result = base_file.parse_with_errors();
75    let ast = metaprogrammation(parse_result.ast, environment);
76
77    ParseCodeResult {
78        ast,
79        errors: parse_result.errors,
80    }
81}
82
83/// Parse code and return the AST (legacy behavior, ignores syntax errors)
84pub fn parse_code(path: &PathBuf, environment: Environment) -> Lang {
85    parse_code_with_errors(path, environment).ast
86}
87
88/// Complete result of compiling a TypR file (parsing + type checking)
89pub struct CompileResult {
90    /// The parsed and type-checked AST
91    pub ast: Lang,
92    /// The inferred type of the program
93    pub inferred_type: Type,
94    /// The final typing context
95    pub context: Context,
96    /// All errors (syntax + type) collected during compilation
97    pub errors: Vec<TypRError>,
98}
99
100impl CompileResult {
101    /// Check if compilation produced any errors
102    pub fn has_errors(&self) -> bool {
103        !self.errors.is_empty()
104    }
105
106    /// Get only syntax errors
107    pub fn syntax_errors(&self) -> Vec<&SyntaxError> {
108        self.errors
109            .iter()
110            .filter_map(|e| match e {
111                TypRError::Syntax(s) => Some(s),
112                _ => None,
113            })
114            .collect()
115    }
116
117    /// Get only type errors
118    pub fn type_errors(&self) -> Vec<&typr_core::components::error_message::type_error::TypeError> {
119        self.errors
120            .iter()
121            .filter_map(|e| match e {
122                TypRError::Type(t) => Some(t),
123                _ => None,
124            })
125            .collect()
126    }
127}
128
129/// Parse and type-check code, returning all errors collected
130///
131/// This is the main entry point for compiling TypR code with error collection.
132pub fn compile_code_with_errors(path: &PathBuf, environment: Environment) -> CompileResult {
133    let file = get_os_file(path.to_str().unwrap());
134    let file_content = read_file(path).expect(&format!("Path {:?} not found", path));
135    let base_file = TypRFile::new(&file_content, file);
136
137    // Parse with error collection
138    let parse_result = base_file.parse_with_errors();
139    let ast = metaprogrammation(parse_result.ast, environment);
140
141    // Convert syntax errors to TypRErrors
142    let mut all_errors: Vec<TypRError> = parse_result
143        .errors
144        .into_iter()
145        .map(TypRError::Syntax)
146        .collect();
147
148    // Type check with error collection
149    let context = Context::default();
150    let typing_result = typing_with_errors(&context, &ast);
151
152    // Collect type errors
153    all_errors.extend(typing_result.errors);
154
155    CompileResult {
156        ast: typing_result.type_context.lang,
157        inferred_type: typing_result.type_context.value,
158        context: typing_result.type_context.context,
159        errors: all_errors,
160    }
161}
162
163/// Compile code from a string (useful for REPL and testing)
164pub fn compile_string_with_errors(
165    code: &str,
166    file_name: &str,
167    environment: Environment,
168) -> CompileResult {
169    let base_file = TypRFile::new(code, file_name.to_string());
170
171    // Parse with error collection
172    let parse_result = base_file.parse_with_errors();
173    let ast = metaprogrammation(parse_result.ast, environment);
174
175    // Convert syntax errors to TypRErrors
176    let mut all_errors: Vec<TypRError> = parse_result
177        .errors
178        .into_iter()
179        .map(TypRError::Syntax)
180        .collect();
181
182    // Type check with error collection
183    let context = Context::default();
184    let typing_result = typing_with_errors(&context, &ast);
185
186    // Collect type errors
187    all_errors.extend(typing_result.errors);
188
189    CompileResult {
190        ast: typing_result.type_context.lang,
191        inferred_type: typing_result.type_context.value,
192        context: typing_result.type_context.context,
193        errors: all_errors,
194    }
195}