TypeScript_Rust_Compiler/
compiler.rs1use crate::error::{CompilerError, Result};
4use crate::generator::CodeGenerator;
5use crate::lexer_utf8::Utf8Lexer;
6use crate::parser::Parser;
7use std::fs;
8use std::path::{Path, PathBuf};
9
10pub struct Compiler {
12 optimize: bool,
13 runtime: bool,
14 output_dir: Option<PathBuf>,
15}
16
17impl Compiler {
18 pub fn new() -> Self {
20 Self {
21 optimize: false,
22 runtime: false,
23 output_dir: None,
24 }
25 }
26
27 pub fn with_optimization(mut self, optimize: bool) -> Self {
29 self.optimize = optimize;
30 self
31 }
32
33 pub fn with_runtime(mut self, runtime: bool) -> Self {
35 self.runtime = runtime;
36 self
37 }
38
39 pub fn with_output_dir(mut self, output_dir: PathBuf) -> Self {
41 self.output_dir = Some(output_dir);
42 self
43 }
44
45 pub fn compile(&mut self, input: &Path, output: &Path) -> Result<()> {
47 let input_content = fs::read_to_string(input).map_err(CompilerError::Io)?;
49
50 let mut lexer = Utf8Lexer::new(input_content);
52 let tokens = lexer.tokenize()?;
53
54 let mut parser = Parser::new(tokens);
56 let program = parser.parse()?;
57
58 let mut generator = CodeGenerator::new(self.runtime);
60 let rust_code = generator.generate(&program)?;
61
62 self.write_output(output, &rust_code)?;
64
65 Ok(())
66 }
67
68 fn write_output(&self, output: &Path, rust_code: &str) -> Result<()> {
70 if output.is_dir() {
71 self.write_multiple_files(output, rust_code)?;
73 } else {
74 if let Some(parent) = output.parent() {
76 fs::create_dir_all(parent).map_err(CompilerError::Io)?;
77 }
78 fs::write(output, rust_code).map_err(CompilerError::Io)?;
80 }
81
82 Ok(())
83 }
84
85 fn write_multiple_files(&self, output_dir: &Path, rust_code: &str) -> Result<()> {
87 fs::create_dir_all(output_dir).map_err(CompilerError::Io)?;
89
90 let main_rs_path = output_dir.join("src").join("main.rs");
92 fs::create_dir_all(main_rs_path.parent().unwrap()).map_err(CompilerError::Io)?;
93 fs::write(&main_rs_path, rust_code).map_err(CompilerError::Io)?;
94
95 let cargo_toml = self.generate_cargo_toml();
97 let cargo_toml_path = output_dir.join("Cargo.toml");
98 fs::write(&cargo_toml_path, cargo_toml).map_err(CompilerError::Io)?;
99
100 let lib_rs_path = output_dir.join("src").join("lib.rs");
102 let lib_rs_content = self.generate_lib_rs();
103 fs::write(&lib_rs_path, lib_rs_content).map_err(CompilerError::Io)?;
104
105 Ok(())
106 }
107
108 fn generate_cargo_toml(&self) -> String {
110 let mut dependencies = vec![
111 "serde = { version = \"1.0\", features = [\"derive\"] }".to_string(),
112 "serde_json = \"1.0\"".to_string(),
113 ];
114
115 if self.runtime {
116 dependencies.push("anyhow = \"1.0\"".to_string());
117 dependencies.push("thiserror = \"1.0\"".to_string());
118 }
119
120 format!(
121 r#"[package]
122name = "generated_rust_project"
123version = "0.4.0"
124edition = "2021"
125
126[dependencies]
127{}
128
129[profile.release]
130opt-level = 3
131lto = true
132"#,
133 dependencies.join("\n")
134 )
135 }
136
137 fn generate_lib_rs(&self) -> String {
139 if self.runtime {
140 r#"
141pub mod runtime;
142pub mod types;
143
144use runtime::*;
145use types::*;
146
147// Re-export commonly used types
148pub use runtime::{Any, Unknown, TypeScriptObject};
149"#
150 .to_string()
151 } else {
152 r#"
153// Generated Rust code
154"#
155 .to_string()
156 }
157 }
158
159 pub fn compile_project(&mut self, input_dir: &Path, output_dir: &Path) -> Result<()> {
161 let ts_files = self.find_typescript_files(input_dir)?;
163
164 if ts_files.is_empty() {
165 return Err(CompilerError::internal_error(
166 "No TypeScript files found in input directory",
167 ));
168 }
169
170 fs::create_dir_all(output_dir).map_err(CompilerError::Io)?;
172
173 for ts_file in ts_files {
175 let relative_path = ts_file
176 .strip_prefix(input_dir)
177 .map_err(|_| CompilerError::internal_error("Failed to strip prefix"))?;
178
179 let rust_file = output_dir.join(relative_path).with_extension("rs");
180
181 if let Some(parent) = rust_file.parent() {
183 fs::create_dir_all(parent).map_err(CompilerError::Io)?;
184 }
185
186 self.compile(&ts_file, &rust_file)?;
188 }
189
190 self.generate_project_files(output_dir)?;
192
193 Ok(())
194 }
195
196 fn find_typescript_files(&self, dir: &Path) -> Result<Vec<PathBuf>> {
198 let mut ts_files = Vec::new();
199
200 for entry in fs::read_dir(dir).map_err(CompilerError::Io)? {
201 let entry = entry.map_err(CompilerError::Io)?;
202 let path = entry.path();
203
204 if path.is_dir() {
205 let sub_files = self.find_typescript_files(&path)?;
207 ts_files.extend(sub_files);
208 } else if path.extension().and_then(|s| s.to_str()) == Some("ts") {
209 ts_files.push(path);
210 }
211 }
212
213 Ok(ts_files)
214 }
215
216 fn generate_project_files(&self, output_dir: &Path) -> Result<()> {
218 let cargo_toml = self.generate_cargo_toml();
220 let cargo_toml_path = output_dir.join("Cargo.toml");
221 fs::write(&cargo_toml_path, cargo_toml).map_err(CompilerError::Io)?;
222
223 let readme = self.generate_readme();
225 let readme_path = output_dir.join("README.md");
226 fs::write(&readme_path, readme).map_err(CompilerError::Io)?;
227
228 let gitignore = self.generate_gitignore();
230 let gitignore_path = output_dir.join(".gitignore");
231 fs::write(&gitignore_path, gitignore).map_err(CompilerError::Io)?;
232
233 Ok(())
234 }
235
236 fn generate_readme(&self) -> String {
238 r#"# Generated Rust Project
239
240This project was generated from TypeScript code using the TypeScript-Rust-Compiler.
241
242## Building
243
244```bash
245cargo build
246```
247
248## Running
249
250```bash
251cargo run
252```
253
254## Testing
255
256```bash
257cargo test
258```
259
260## Features
261
262- Generated from TypeScript source code
263- Full Rust type safety
264- Serde serialization support
265"#
266 .to_string()
267 }
268
269 fn generate_gitignore(&self) -> String {
271 r#"# Rust
272/target/
273Cargo.lock
274
275# IDE
276.vscode/
277.idea/
278*.swp
279*.swo
280
281# OS
282.DS_Store
283Thumbs.db
284"#
285 .to_string()
286 }
287
288 pub fn version() -> &'static str {
290 env!("CARGO_PKG_VERSION")
291 }
292
293 pub fn info(&self) -> String {
295 format!(
296 "TypeScript-Rust-Compiler v{}\nOptimization: {}\nRuntime: {}",
297 Self::version(),
298 self.optimize,
299 self.runtime
300 )
301 }
302}
303
304impl Default for Compiler {
305 fn default() -> Self {
306 Self::new()
307 }
308}