1#![warn(clippy::all)]
7#![allow(clippy::module_name_repetitions)]
10#![allow(clippy::must_use_candidate)]
11#![allow(clippy::case_sensitive_file_extension_comparisons)]
13#![allow(clippy::match_same_arms)]
14#![allow(clippy::struct_excessive_bools)]
15#![allow(clippy::cast_precision_loss)]
16#![allow(clippy::cast_possible_truncation)]
17#![allow(clippy::unused_self)]
18#![allow(clippy::expect_used)]
19#![allow(clippy::missing_errors_doc)]
20#![allow(clippy::missing_panics_doc)]
21#![allow(clippy::too_many_arguments)]
22#![allow(clippy::trivially_copy_pass_by_ref)]
23#![allow(clippy::unnecessary_wraps)]
24#![allow(clippy::only_used_in_recursion)]
25#![allow(clippy::print_stdout)]
26#![allow(clippy::print_stderr)]
27#![allow(clippy::format_push_string)]
28#![allow(clippy::field_reassign_with_default)]
29#![allow(clippy::return_self_not_must_use)]
30#![allow(clippy::unwrap_used)]
31#![allow(clippy::needless_pass_by_value)]
32#![allow(clippy::manual_clamp)]
33#![allow(clippy::should_implement_trait)]
34#![allow(clippy::unnecessary_to_owned)]
35#![allow(clippy::cast_possible_wrap)]
36#![allow(clippy::if_same_then_else)]
37
38pub mod actors;
39pub mod backend;
40pub mod frontend;
41pub mod lints;
42pub mod lsp;
43pub mod mcp;
44pub mod middleend;
45pub mod optimization;
46pub mod parser;
47pub mod proving;
48pub mod quality;
49pub mod runtime;
50#[cfg(any(test, feature = "testing"))]
51pub mod testing;
52pub mod transpiler;
53pub mod wasm;
54
55pub use actors::{
56 Actor, ActorHandle, McpActor, McpMessage, McpResponse, SupervisionStrategy, Supervisor,
57};
58pub use backend::transpiler::Transpiler;
59pub use frontend::ast::{BinaryOp, Expr, ExprKind, Literal, Pattern, UnaryOp};
60pub use frontend::lexer::{Token, TokenStream};
61pub use frontend::parser::Parser;
62pub use lsp::{start_server, start_tcp_server, Formatter, RuchyLanguageServer, SemanticAnalyzer};
63pub use quality::{
64 CiQualityEnforcer, CoverageCollector, CoverageReport, CoverageTool, FileCoverage,
65 HtmlReportGenerator, QualityGates, QualityMetrics, QualityReport, QualityThresholds,
66};
67pub use quality::gates::{QualityGateEnforcer, QualityGateConfig, GateResult};
68
69use anyhow::Result;
70
71pub fn compile(source: &str) -> Result<String> {
88 let mut parser = Parser::new(source);
89 let ast = parser.parse()?;
90 let transpiler = Transpiler::new();
91 let rust_code = transpiler.transpile_to_program(&ast)?;
93 Ok(rust_code.to_string())
94}
95
96#[must_use]
98pub fn is_valid_syntax(source: &str) -> bool {
99 let mut parser = Parser::new(source);
100 parser.parse().is_ok()
101}
102
103#[must_use]
105pub fn get_parse_error(source: &str) -> Option<String> {
106 let mut parser = Parser::new(source);
107 parser.parse().err().map(|e| e.to_string())
108}
109
110pub fn run_repl() -> Result<()> {
126 let mut repl = runtime::repl::Repl::new()?;
127 repl.run()
128}
129
130#[cfg(test)]
131mod test_config {
132 use std::sync::Once;
133
134 static INIT: Once = Once::new();
135
136 pub fn init() {
138 INIT.call_once(|| {
139 if std::env::var("CI").is_err() {
141 std::env::set_var("PROPTEST_CASES", "10");
142 std::env::set_var("PROPTEST_MAX_SHRINK_ITERS", "50");
143 }
144 if std::env::var("RUST_TEST_THREADS").is_err() {
146 std::env::set_var("RUST_TEST_THREADS", "4");
147 }
148 });
149 }
150}
151
152#[cfg(test)]
153#[allow(clippy::unwrap_used)]
154#[allow(clippy::single_char_pattern)]
155mod tests {
156 use super::test_config;
157 use super::*;
158
159 #[test]
160 fn test_compile_simple() {
161 test_config::init();
162 let result = compile("42").unwrap();
163 assert!(result.contains("42"));
164 }
165
166 #[test]
167 fn test_compile_let() {
168 let result = compile("let x = 10 in x + 1").unwrap();
169 assert!(result.contains("let"));
170 assert!(result.contains("10"));
171 }
172
173 #[test]
174 fn test_compile_function() {
175 let result = compile("fun add(x: i32, y: i32) -> i32 { x + y }").unwrap();
176 assert!(result.contains("fn"));
177 assert!(result.contains("add"));
178 assert!(result.contains("i32"));
179 }
180
181 #[test]
182 fn test_compile_if() {
183 let result = compile("if true { 1 } else { 0 }").unwrap();
184 assert!(result.contains("if"));
185 assert!(result.contains("else"));
186 }
187
188 #[test]
189 fn test_compile_match() {
190 let result = compile("match x { 0 => \"zero\", _ => \"other\" }").unwrap();
191 assert!(result.contains("match"));
192 }
193
194 #[test]
195 fn test_compile_list() {
196 let result = compile("[1, 2, 3]").unwrap();
197 assert!(result.contains("vec") && result.contains("!"));
198 }
199
200 #[test]
201 fn test_compile_lambda() {
202 let result = compile("|x| x * 2").unwrap();
203 assert!(result.contains("|"));
204 }
205
206 #[test]
207 fn test_compile_struct() {
208 let result = compile("struct Point { x: f64, y: f64 }").unwrap();
209 assert!(result.contains("struct"));
210 assert!(result.contains("Point"));
211 }
212
213 #[test]
214 fn test_compile_impl() {
215 let result =
216 compile("impl Point { fun new() -> Point { Point { x: 0.0, y: 0.0 } } }").unwrap();
217 assert!(result.contains("impl"));
218 }
219
220 #[test]
221 fn test_compile_trait() {
222 let result = compile("trait Show { fun show(&self) -> String }").unwrap();
223 assert!(result.contains("trait"));
224 }
225
226 #[test]
227 fn test_compile_for_loop() {
228 let result = compile("for x in [1, 2, 3] { print(x) }").unwrap();
229 assert!(result.contains("for"));
230 }
231
232 #[test]
233 fn test_compile_binary_ops() {
234 let result = compile("1 + 2 * 3 - 4 / 2").unwrap();
235 assert!(result.contains("+"));
236 assert!(result.contains("*"));
237 assert!(result.contains("-"));
238 assert!(result.contains("/"));
239 }
240
241 #[test]
242 fn test_compile_comparison_ops() {
243 let result = compile("x < y && y <= z").unwrap();
244 assert!(result.contains("<"));
245 assert!(result.contains("<="));
246 assert!(result.contains("&&"));
247 }
248
249 #[test]
250 fn test_compile_unary_ops() {
251 let result = compile("-x").unwrap();
252 assert!(result.contains("-"));
253
254 let result = compile("!flag").unwrap();
255 assert!(result.contains("!"));
256 }
257
258 #[test]
259 fn test_compile_call() {
260 let result = compile("func(1, 2, 3)").unwrap();
261 assert!(result.contains("func"));
262 assert!(result.contains("("));
263 assert!(result.contains(")"));
264 }
265
266 #[test]
267 fn test_compile_method_call() {
268 let result = compile("obj.method()").unwrap();
269 assert!(result.contains("."));
270 assert!(result.contains("method"));
271 }
272
273 #[test]
274 fn test_compile_block() {
275 let result = compile("{ let x = 1; x + 1 }").unwrap();
276 assert!(result.contains("{"));
277 assert!(result.contains("}"));
278 }
279
280 #[test]
281 fn test_compile_string() {
282 let result = compile("\"hello world\"").unwrap();
283 assert!(result.contains("hello world"));
284 }
285
286 #[test]
287 fn test_compile_bool() {
288 let result = compile("true && false").unwrap();
289 assert!(result.contains("true"));
290 assert!(result.contains("false"));
291 }
292
293 #[test]
294 fn test_compile_unit() {
295 let result = compile("()").unwrap();
296 assert!(result.contains("()"));
297 }
298
299 #[test]
300 fn test_compile_nested_let() {
301 let result = compile("let x = 1 in let y = 2 in x + y").unwrap();
302 assert!(result.contains("let"));
303 }
304
305 #[test]
306 fn test_compile_nested_if() {
307 let result = compile("if x { if y { 1 } else { 2 } } else { 3 }").unwrap();
308 assert!(result.contains("if"));
309 }
310
311 #[test]
312 fn test_compile_empty_list() {
313 let result = compile("[]").unwrap();
314 assert!(result.contains("vec") && result.contains("!"));
315 }
316
317 #[test]
318 fn test_compile_empty_block() {
319 let result = compile("{ }").unwrap();
320 assert!(result.contains("()"));
321 }
322
323 #[test]
324 fn test_compile_float() {
325 let result = compile("3.14159").unwrap();
326 assert!(result.contains("3.14159"));
327 }
328
329 #[test]
330 fn test_compile_large_int() {
331 let result = compile("999999999").unwrap();
332 assert!(result.contains("999999999"));
333 }
334
335 #[test]
336 fn test_compile_string_escape() {
337 let result = compile(r#""hello\nworld""#).unwrap();
338 assert!(result.contains("hello"));
339 }
340
341 #[test]
342 fn test_compile_power_op() {
343 let result = compile("2 ** 8").unwrap();
344 assert!(result.contains("pow"));
345 }
346
347 #[test]
348 fn test_compile_modulo() {
349 let result = compile("10 % 3").unwrap();
350 assert!(result.contains("%"));
351 }
352
353 #[test]
354 fn test_compile_bitwise_ops() {
355 let result = compile("a & b | c ^ d").unwrap();
356 assert!(result.contains("&"));
357 assert!(result.contains("|"));
358 assert!(result.contains("^"));
359 }
360
361 #[test]
362 fn test_compile_left_shift() {
363 let result = compile("x << 2").unwrap();
364 assert!(result.contains("<<"));
365 }
366
367 #[test]
368 fn test_compile_not_equal() {
369 let result = compile("x != y").unwrap();
370 assert!(result.contains("!="));
371 }
372
373 #[test]
374 fn test_compile_greater_ops() {
375 let result = compile("x > y && x >= z").unwrap();
376 assert!(result.contains(">"));
377 assert!(result.contains(">="));
378 }
379
380 #[test]
381 fn test_compile_or_op() {
382 let result = compile("x || y").unwrap();
383 assert!(result.contains("||"));
384 }
385
386 #[test]
387 fn test_compile_complex_expression() {
388 let result = compile("(x + y) * (z - w) / 2").unwrap();
389 assert!(result.contains("+"));
390 assert!(result.contains("-"));
391 assert!(result.contains("*"));
392 assert!(result.contains("/"));
393 }
394
395 #[test]
396 fn test_compile_errors() {
397 assert!(compile("").is_err());
398 assert!(compile(" ").is_err());
399 assert!(compile("let x =").is_err());
400 assert!(compile("if").is_err());
401 assert!(compile("match").is_err());
402 }
403
404 #[test]
405 fn test_is_valid_syntax_valid_cases() {
406 assert!(is_valid_syntax("42"));
407 assert!(is_valid_syntax("3.14"));
408 assert!(is_valid_syntax("true"));
409 assert!(is_valid_syntax("false"));
410 assert!(is_valid_syntax("\"hello\""));
411 assert!(is_valid_syntax("x + y"));
412 assert!(is_valid_syntax("[1, 2, 3]"));
413 assert!(is_valid_syntax("if true { 1 } else { 2 }"));
414 }
415
416 #[test]
417 fn test_is_valid_syntax_invalid_cases() {
418 assert!(!is_valid_syntax(""));
419 assert!(!is_valid_syntax(" "));
420 assert!(!is_valid_syntax("let x ="));
421 assert!(!is_valid_syntax("if { }"));
422 assert!(!is_valid_syntax("[1, 2,"));
423 assert!(!is_valid_syntax("match"));
424 assert!(!is_valid_syntax("struct"));
425 }
426
427 #[test]
428 fn test_get_parse_error_with_errors() {
429 let error = get_parse_error("fun (");
430 assert!(error.is_some());
431 assert!(!error.unwrap().is_empty());
433 }
434
435 #[test]
436 fn test_get_parse_error_without_errors() {
437 let error = get_parse_error("42");
438 assert!(error.is_none());
439 }
440
441 #[test]
442 fn test_get_parse_error_detailed() {
443 let error = get_parse_error("if");
444 assert!(error.is_some());
445
446 let error = get_parse_error("match");
447 assert!(error.is_some());
448
449 let error = get_parse_error("[1, 2,");
450 assert!(error.is_some());
451 }
452
453 #[test]
454 fn test_compile_generic_function() {
455 let result = compile("fun id<T>(x: T) -> T { x }").unwrap();
456 assert!(result.contains("fn"));
457 assert!(result.contains("id"));
458 }
459
460 #[test]
461 fn test_compile_generic_struct() {
462 let result = compile("struct Box<T> { value: T }").unwrap();
463 assert!(result.contains("struct"));
464 assert!(result.contains("Box"));
465 }
466
467 #[test]
468 fn test_compile_multiple_statements() {
469 let result = compile("let x = 1 in let y = 2 in x + y").unwrap();
470 assert!(result.contains("let"));
471 }
472
473 #[test]
474 fn test_compile_pattern_matching() {
475 let result = compile("match x { 0 => \"zero\", _ => \"other\" }").unwrap();
476 assert!(result.contains("match"));
477 }
478
479 #[test]
480 fn test_compile_struct_literal() {
481 let result = compile("Point { x: 10, y: 20 }").unwrap();
482 assert!(result.contains("Point"));
483 }
484
485 #[test]
493 fn test_compile_await_expression() {
494 let result = compile("async_func().await").unwrap();
495 assert!(result.contains("await"));
496 }
497
498 #[test]
499 fn test_compile_import() {
500 let result = compile("import std.collections.HashMap").unwrap();
501 assert!(result.contains("use"));
502 }
503
504 #[test]
505 fn test_compile_while_loop() {
506 let result = compile("while x < 10 { x + 1 }").unwrap();
507 assert!(result.contains("while"));
508 }
509
510 #[test]
511 fn test_compile_range() {
512 let result = compile("1..10").unwrap();
513 assert!(result.contains(".."));
514 }
515
516 #[test]
517 fn test_compile_pipeline() {
518 let result = compile("data >> filter >> map").unwrap();
519 assert!(result.contains("("));
520 }
521
522 #[test]
523 fn test_compile_send_operation() {
524 let result = compile("myactor <- message").unwrap();
525 assert!(result.contains(". send (")); assert!(result.contains(". await")); }
528
529 #[test]
530 fn test_compile_ask_operation() {
531 let result = compile("myactor <? request").unwrap();
532 assert!(result.contains(". ask (")); assert!(result.contains(". await")); }
535
536 #[test]
537 fn test_compile_list_comprehension() {
538 let result = compile("[x * 2 for x in range(10)]").unwrap();
539 assert!(result.contains("map"));
540 }
541
542 #[test]
543 fn test_compile_actor() {
544 let result = compile(
545 r"
546 actor Counter {
547 count: i32,
548
549 receive {
550 Inc => 1,
551 Get => 0
552 }
553 }
554 ",
555 )
556 .unwrap();
557 assert!(result.contains("struct Counter"));
558 assert!(result.contains("enum CounterMessage"));
559 }
560}