1#[cfg(feature = "llvm")]
7pub mod llvm {
8 use inkwell::builder::Builder;
9 use inkwell::context::Context;
10 use inkwell::execution_engine::{ExecutionEngine, JitFunction};
11 use inkwell::module::Module;
12 use inkwell::passes::PassBuilderOptions;
13 use inkwell::targets::{
14 CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine, TargetTriple,
15 };
16 use inkwell::types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum, StructType};
17 use inkwell::values::{
18 BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue,
19 StructValue,
20 };
21 use inkwell::{AddressSpace, IntPredicate, OptimizationLevel};
22
23 use std::collections::HashMap;
24 use std::path::Path;
25
26 use crate::ast::{self, BinOp, Expr, Item, Literal, UnaryOp};
27 use crate::optimize::{OptLevel, Optimizer};
28 use crate::parser::Parser;
29
30 type MainFn = unsafe extern "C" fn() -> i64;
32
33 #[derive(Clone, Copy, PartialEq, Eq)]
35 pub enum CompileMode {
36 Jit,
38 Aot,
40 }
41
42 #[derive(Clone)]
44 pub struct StructInfo<'ctx> {
45 pub llvm_type: StructType<'ctx>,
47 pub field_indices: HashMap<String, u32>,
49 }
50
51 #[derive(Clone)]
53 pub struct EnumInfo {
54 pub variants: HashMap<String, u64>,
56 }
57
58 #[derive(Clone)]
60 pub struct GenericStructDef {
61 pub def: ast::StructDef,
63 pub type_params: Vec<String>,
65 }
66
67 pub struct LlvmCompiler<'ctx> {
69 context: &'ctx Context,
70 module: Module<'ctx>,
71 builder: Builder<'ctx>,
72 execution_engine: Option<ExecutionEngine<'ctx>>,
73 functions: HashMap<String, FunctionValue<'ctx>>,
75 opt_level: OptLevel,
77 compile_mode: CompileMode,
79 current_module: Vec<String>,
81 use_aliases: HashMap<String, String>,
83 struct_types: HashMap<String, StructInfo<'ctx>>,
85 generic_structs: HashMap<String, GenericStructDef>,
87 enum_types: HashMap<String, EnumInfo>,
89 impl_methods: HashMap<(String, String), String>,
91 string_counter: std::cell::Cell<u32>,
93 evidential_types: HashMap<String, StructType<'ctx>>,
95 current_self_type: Option<String>,
97 global_vars: HashMap<String, inkwell::values::GlobalValue<'ctx>>,
99 }
100
101 const EVIDENCE_KNOWN: u8 = 0; const EVIDENCE_UNCERTAIN: u8 = 1; const EVIDENCE_REPORTED: u8 = 2; const EVIDENCE_PREDICTED: u8 = 3; const EVIDENCE_PARADOX: u8 = 4; extern "C" fn sigil_now() -> i64 {
113 use std::time::{SystemTime, UNIX_EPOCH};
114 SystemTime::now()
115 .duration_since(UNIX_EPOCH)
116 .map(|d| d.as_millis() as i64)
117 .unwrap_or(0)
118 }
119
120 extern "C" fn sigil_print_int(value: i64) {
122 println!("{}", value);
123 }
124
125 extern "C" fn sigil_sqrt(x: i64) -> i64 {
127 f64::to_bits(f64::from_bits(x as u64).sqrt()) as i64
128 }
129 extern "C" fn sigil_sin(x: i64) -> i64 {
130 f64::to_bits(f64::from_bits(x as u64).sin()) as i64
131 }
132 extern "C" fn sigil_cos(x: i64) -> i64 {
133 f64::to_bits(f64::from_bits(x as u64).cos()) as i64
134 }
135 extern "C" fn sigil_tan(x: i64) -> i64 {
136 f64::to_bits(f64::from_bits(x as u64).tan()) as i64
137 }
138 extern "C" fn sigil_exp(x: i64) -> i64 {
139 f64::to_bits(f64::from_bits(x as u64).exp()) as i64
140 }
141 extern "C" fn sigil_ln(x: i64) -> i64 {
142 f64::to_bits(f64::from_bits(x as u64).ln()) as i64
143 }
144 extern "C" fn sigil_pow(x: i64, y: i64) -> i64 {
145 f64::to_bits(f64::from_bits(x as u64).powf(f64::from_bits(y as u64))) as i64
146 }
147 extern "C" fn sigil_floor(x: i64) -> i64 {
148 f64::to_bits(f64::from_bits(x as u64).floor()) as i64
149 }
150 extern "C" fn sigil_ceil(x: i64) -> i64 {
151 f64::to_bits(f64::from_bits(x as u64).ceil()) as i64
152 }
153 extern "C" fn sigil_abs(x: i64) -> i64 {
154 x.abs()
155 }
156 extern "C" fn sigil_min(a: i64, b: i64) -> i64 {
157 a.min(b)
158 }
159 extern "C" fn sigil_max(a: i64, b: i64) -> i64 {
160 a.max(b)
161 }
162
163 extern "C" fn sigil_vec_new(capacity: i64) -> *mut Vec<i64> {
165 let vec = if capacity > 0 {
166 Vec::with_capacity(capacity as usize)
167 } else {
168 Vec::new()
169 };
170 Box::into_raw(Box::new(vec))
171 }
172
173 extern "C" fn sigil_vec_push(vec_ptr: *mut Vec<i64>, value: i64) {
174 if !vec_ptr.is_null() {
175 unsafe {
176 (*vec_ptr).push(value);
177 }
178 }
179 }
180
181 extern "C" fn sigil_vec_get(vec_ptr: *mut Vec<i64>, index: i64) -> i64 {
182 if vec_ptr.is_null() {
183 return 0;
184 }
185 unsafe {
186 let vec_ref = &*vec_ptr;
187 vec_ref.get(index as usize).copied().unwrap_or(0)
188 }
189 }
190
191 extern "C" fn sigil_vec_len(vec_ptr: *mut Vec<i64>) -> i64 {
192 if vec_ptr.is_null() {
193 return 0;
194 }
195 unsafe { (*vec_ptr).len() as i64 }
196 }
197
198 extern "C" fn sigil_string_new() -> *mut String {
200 Box::into_raw(Box::new(String::new()))
201 }
202
203 extern "C" fn sigil_string_from(ptr: *const i8) -> *mut String {
204 if ptr.is_null() {
205 return std::ptr::null_mut();
206 }
207 unsafe {
208 let cstr = std::ffi::CStr::from_ptr(ptr);
209 let s = cstr.to_string_lossy().into_owned();
210 Box::into_raw(Box::new(s))
211 }
212 }
213
214 extern "C" fn sigil_string_len(str_ptr: *mut String) -> i64 {
215 if str_ptr.is_null() {
216 return 0;
217 }
218 unsafe {
219 let str_ref = &*str_ptr;
220 str_ref.len() as i64
221 }
222 }
223
224 extern "C" fn sigil_string_print(str_ptr: *mut String) {
225 if !str_ptr.is_null() {
226 unsafe {
227 print!("{}", *str_ptr);
228 }
229 }
230 }
231
232 extern "C" fn sigil_string_concat(a_ptr: *mut String, b_ptr: *mut String) -> *mut String {
233 if a_ptr.is_null() || b_ptr.is_null() {
234 return std::ptr::null_mut();
235 }
236 unsafe {
237 let result = format!("{}{}", *a_ptr, *b_ptr);
238 Box::into_raw(Box::new(result))
239 }
240 }
241
242 extern "C" fn sigil_option_some(value: i64) -> *mut i64 {
244 Box::into_raw(Box::new(value))
245 }
246
247 extern "C" fn sigil_option_none() -> *mut i64 {
248 std::ptr::null_mut()
249 }
250
251 extern "C" fn sigil_option_is_some(opt_ptr: *mut i64) -> i64 {
252 if opt_ptr.is_null() {
253 0
254 } else {
255 1
256 }
257 }
258
259 extern "C" fn sigil_option_is_none(opt_ptr: *mut i64) -> i64 {
260 if opt_ptr.is_null() {
261 1
262 } else {
263 0
264 }
265 }
266
267 extern "C" fn sigil_option_unwrap(opt_ptr: *mut i64) -> i64 {
268 if opt_ptr.is_null() {
269 eprintln!("Error: unwrap called on None");
270 0
271 } else {
272 unsafe { *opt_ptr }
273 }
274 }
275
276 extern "C" fn sigil_option_unwrap_or(opt_ptr: *mut i64, default: i64) -> i64 {
277 if opt_ptr.is_null() {
278 default
279 } else {
280 unsafe { *opt_ptr }
281 }
282 }
283
284 extern "C" fn sigil_file_exists(path_ptr: *const i8) -> i64 {
286 if path_ptr.is_null() {
287 return 0;
288 }
289 unsafe {
290 let cstr = std::ffi::CStr::from_ptr(path_ptr);
291 if let Ok(path) = cstr.to_str() {
292 if std::path::Path::new(path).exists() {
293 1
294 } else {
295 0
296 }
297 } else {
298 0
299 }
300 }
301 }
302
303 extern "C" fn sigil_file_read_all(path_ptr: *const i8) -> *mut String {
304 if path_ptr.is_null() {
305 return std::ptr::null_mut();
306 }
307 unsafe {
308 let cstr = std::ffi::CStr::from_ptr(path_ptr);
309 if let Ok(path) = cstr.to_str() {
310 if let Ok(content) = std::fs::read_to_string(path) {
311 return Box::into_raw(Box::new(content));
312 }
313 }
314 std::ptr::null_mut()
315 }
316 }
317
318 extern "C" fn sigil_file_write_all(path_ptr: *const i8, content_ptr: *mut String) -> i64 {
319 if path_ptr.is_null() || content_ptr.is_null() {
320 return -1;
321 }
322 unsafe {
323 let cstr = std::ffi::CStr::from_ptr(path_ptr);
324 let content_ref = &*content_ptr;
325 if let Ok(path) = cstr.to_str() {
326 if let Ok(_) = std::fs::write(path, content_ref) {
327 return content_ref.len() as i64;
328 }
329 }
330 -1
331 }
332 }
333
334 impl<'ctx> LlvmCompiler<'ctx> {
335 pub fn new(context: &'ctx Context, opt_level: OptLevel) -> Result<Self, String> {
337 Self::with_mode(context, opt_level, CompileMode::Jit)
338 }
339
340 pub fn with_mode(
342 context: &'ctx Context,
343 opt_level: OptLevel,
344 compile_mode: CompileMode,
345 ) -> Result<Self, String> {
346 Target::initialize_all(&InitializationConfig::default());
349
350 let module = context.create_module("sigil_main");
351 let builder = context.create_builder();
352
353 let triple = TargetMachine::get_default_triple();
355 module.set_triple(&triple);
356
357 let target = Target::from_triple(&triple).map_err(|e| e.to_string())?;
359 let cpu = TargetMachine::get_host_cpu_name();
360 let features = TargetMachine::get_host_cpu_features();
361 if let Some(tm) = target.create_target_machine(
362 &triple,
363 cpu.to_str().unwrap_or("native"),
364 features.to_str().unwrap_or(""),
365 OptimizationLevel::Aggressive,
366 RelocMode::Default,
367 CodeModel::Default,
368 ) {
369 module.set_data_layout(&tm.get_target_data().get_data_layout());
370 }
371
372 Ok(Self {
373 context,
374 module,
375 builder,
376 execution_engine: None,
377 functions: HashMap::new(),
378 opt_level,
379 compile_mode,
380 current_module: vec!["crate".to_string()],
381 use_aliases: HashMap::new(),
382 struct_types: HashMap::new(),
383 generic_structs: HashMap::new(),
384 enum_types: HashMap::new(),
385 impl_methods: HashMap::new(),
386 string_counter: std::cell::Cell::new(0),
387 evidential_types: HashMap::new(),
388 current_self_type: None,
389 global_vars: HashMap::new(),
390 })
391 }
392
393 pub fn compile(&mut self, source: &str) -> Result<(), String> {
395 let mut parser = Parser::new(source);
396 let source_file = parser.parse_file().map_err(|e| format!("{:?}", e))?;
397
398 let optimized = source_file; self.declare_runtime_functions();
405
406 for spanned_item in &optimized.items {
408 match &spanned_item.node {
409 Item::Struct(s) => self.register_struct(s)?,
410 Item::Enum(e) => self.register_enum(e)?,
411 _ => {}
412 }
413 }
414
415 for spanned_item in &optimized.items {
417 if let Item::Impl(impl_block) = &spanned_item.node {
418 self.declare_impl_methods(impl_block)?;
419 }
420 }
421
422 for spanned_item in &optimized.items {
424 match &spanned_item.node {
425 Item::Function(func) => {
426 self.declare_function(func)?;
427 }
428 Item::Module(module) => {
429 self.process_module(module)?;
430 }
431 Item::Use(use_decl) => {
432 self.process_use(use_decl)?;
433 }
434 Item::Static(static_decl) => {
435 self.process_static(static_decl)?;
436 }
437 Item::Const(const_decl) => {
438 self.process_const(const_decl)?;
439 }
440 _ => {}
441 }
442 }
443
444 for spanned_item in &optimized.items {
446 match &spanned_item.node {
447 Item::Function(func) => {
448 self.compile_function(func)?;
449 }
450 Item::Module(module) => {
451 self.compile_module_functions(module)?;
452 }
453 Item::Impl(impl_block) => {
454 self.compile_impl_methods(impl_block)?;
455 }
456 _ => {}
457 }
458 }
459
460 self.run_llvm_optimizations()?;
462
463 Ok(())
464 }
465
466 fn declare_runtime_functions(&self) {
468 let i64_type = self.context.i64_type();
469 let void_type = self.context.void_type();
470
471 let now_type = i64_type.fn_type(&[], false);
473 self.module.add_function("sigil_now", now_type, None);
474
475 let print_int_type = void_type.fn_type(&[i64_type.into()], false);
477 self.module
478 .add_function("sigil_print_int", print_int_type, None);
479
480 let ptr_type_generic = self.context.ptr_type(AddressSpace::default());
482 let print_str_type = void_type.fn_type(&[ptr_type_generic.into()], false);
483 self.module
484 .add_function("sigil_print_str", print_str_type, None);
485
486 let f64_type = self.context.f64_type();
488 let print_float_type = void_type.fn_type(&[f64_type.into()], false);
489 self.module
490 .add_function("sigil_print_float", print_float_type, None);
491
492 self.module
495 .add_function("sigil_write_int", print_int_type, None);
496
497 self.module
499 .add_function("sigil_write_str", print_str_type, None);
500
501 self.module.add_function("print", print_str_type, None);
503 self.module.add_function("println", print_str_type, None);
504 self.module.add_function("eprint", print_str_type, None);
505 self.module.add_function("eprintln", print_str_type, None);
506
507 self.module
509 .add_function("sigil_write_float", print_float_type, None);
510
511 let unary_math_type = i64_type.fn_type(&[i64_type.into()], false);
513 for name in [
514 "sigil_sqrt",
515 "sigil_sin",
516 "sigil_cos",
517 "sigil_tan",
518 "sigil_exp",
519 "sigil_ln",
520 "sigil_floor",
521 "sigil_ceil",
522 "sigil_abs",
523 ] {
524 self.module.add_function(name, unary_math_type, None);
525 }
526
527 let binary_math_type = i64_type.fn_type(&[i64_type.into(), i64_type.into()], false);
529 for name in ["sigil_pow", "sigil_min", "sigil_max"] {
530 self.module.add_function(name, binary_math_type, None);
531 }
532
533 let ptr_type = i64_type; let vec_new_type = ptr_type.fn_type(&[i64_type.into()], false);
538 self.module
539 .add_function("sigil_vec_new", vec_new_type, None);
540
541 let vec_push_type = void_type.fn_type(&[ptr_type.into(), i64_type.into()], false);
543 self.module
544 .add_function("sigil_vec_push", vec_push_type, None);
545
546 let vec_get_type = i64_type.fn_type(&[ptr_type.into(), i64_type.into()], false);
548 self.module
549 .add_function("sigil_vec_get", vec_get_type, None);
550
551 let vec_len_type = i64_type.fn_type(&[ptr_type.into()], false);
553 self.module
554 .add_function("sigil_vec_len", vec_len_type, None);
555
556 let string_new_type = ptr_type.fn_type(&[], false);
559 self.module
560 .add_function("sigil_string_new", string_new_type, None);
561
562 let string_from_type = ptr_type.fn_type(&[ptr_type.into()], false);
565 self.module
566 .add_function("sigil_string_from", string_from_type, None);
567
568 let string_len_type = i64_type.fn_type(&[ptr_type.into()], false);
570 self.module
571 .add_function("sigil_string_len", string_len_type, None);
572
573 let string_print_type = void_type.fn_type(&[ptr_type.into()], false);
575 self.module
576 .add_function("sigil_string_print", string_print_type, None);
577
578 let string_concat_type = ptr_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
580 self.module
581 .add_function("sigil_string_concat", string_concat_type, None);
582
583 let option_some_type = ptr_type.fn_type(&[i64_type.into()], false);
586 self.module
587 .add_function("sigil_option_some", option_some_type, None);
588
589 let option_none_type = ptr_type.fn_type(&[], false);
591 self.module
592 .add_function("sigil_option_none", option_none_type, None);
593
594 let option_is_some_type = i64_type.fn_type(&[ptr_type.into()], false);
596 self.module
597 .add_function("sigil_option_is_some", option_is_some_type, None);
598
599 let option_is_none_type = i64_type.fn_type(&[ptr_type.into()], false);
601 self.module
602 .add_function("sigil_option_is_none", option_is_none_type, None);
603
604 let option_unwrap_type = i64_type.fn_type(&[ptr_type.into()], false);
606 self.module
607 .add_function("sigil_option_unwrap", option_unwrap_type, None);
608
609 let option_unwrap_or_type =
611 i64_type.fn_type(&[ptr_type.into(), i64_type.into()], false);
612 self.module
613 .add_function("sigil_option_unwrap_or", option_unwrap_or_type, None);
614
615 let file_exists_type = i64_type.fn_type(&[ptr_type.into()], false);
618 self.module
619 .add_function("sigil_file_exists", file_exists_type, None);
620
621 let file_read_all_type = ptr_type.fn_type(&[ptr_type.into()], false);
623 self.module
624 .add_function("sigil_file_read_all", file_read_all_type, None);
625
626 let file_write_all_type = i64_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
628 self.module
629 .add_function("sigil_file_write_all", file_write_all_type, None);
630
631 let exit_type = void_type.fn_type(&[i64_type.into()], false);
633 self.module.add_function("sigil_exit", exit_type, None);
634
635 let alloc_type = ptr_type.fn_type(&[i64_type.into()], false);
638 self.module.add_function("sigil_alloc", alloc_type, None);
639
640 let realloc_type = ptr_type.fn_type(&[ptr_type.into(), i64_type.into()], false);
642 self.module
643 .add_function("sigil_realloc", realloc_type, None);
644
645 let free_type = void_type.fn_type(&[ptr_type.into()], false);
647 self.module.add_function("sigil_free", free_type, None);
648
649 let f32_type = self.context.f32_type();
651
652 let simd_alloc_type = ptr_type.fn_type(&[i64_type.into()], false);
654 self.module
655 .add_function("sigil_simd_alloc", simd_alloc_type, None);
656
657 let simd_free_type = void_type.fn_type(&[ptr_type.into()], false);
659 self.module
660 .add_function("sigil_simd_free", simd_free_type, None);
661
662 let simd_splat_type = void_type.fn_type(&[ptr_type.into(), f32_type.into()], false);
664 self.module
665 .add_function("sigil_simd_splat_f32x16", simd_splat_type, None);
666
667 let simd_load_type = void_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
669 self.module
670 .add_function("sigil_simd_load_f32x16", simd_load_type, None);
671
672 let simd_store_type = void_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
674 self.module
675 .add_function("sigil_simd_store_f32x16", simd_store_type, None);
676
677 let simd_binop_type =
679 void_type.fn_type(&[ptr_type.into(), ptr_type.into(), ptr_type.into()], false);
680 self.module
681 .add_function("sigil_simd_add_f32x16", simd_binop_type, None);
682
683 self.module
685 .add_function("sigil_simd_sub_f32x16", simd_binop_type, None);
686
687 self.module
689 .add_function("sigil_simd_mul_f32x16", simd_binop_type, None);
690
691 self.module
693 .add_function("sigil_simd_div_f32x16", simd_binop_type, None);
694
695 let simd_fmadd_type = void_type.fn_type(
697 &[
698 ptr_type.into(),
699 ptr_type.into(),
700 ptr_type.into(),
701 ptr_type.into(),
702 ],
703 false,
704 );
705 self.module
706 .add_function("sigil_simd_fmadd_f32x16", simd_fmadd_type, None);
707
708 let simd_reduce_type = f32_type.fn_type(&[ptr_type.into()], false);
710 self.module
711 .add_function("sigil_simd_reduce_add_f32x16", simd_reduce_type, None);
712
713 let simd_extract_type = f32_type.fn_type(&[ptr_type.into(), i64_type.into()], false);
715 self.module
716 .add_function("sigil_simd_extract_f32x16", simd_extract_type, None);
717
718 let simd_dot_type = f32_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
720 self.module
721 .add_function("sigil_simd_dot_f32x16", simd_dot_type, None);
722
723 let cuda_init_type = i64_type.fn_type(&[], false);
726 self.module
727 .add_function("sigil_cuda_init", cuda_init_type, None);
728
729 let cuda_cleanup_type = void_type.fn_type(&[], false);
731 self.module
732 .add_function("sigil_cuda_cleanup", cuda_cleanup_type, None);
733
734 let cuda_device_count_type = i64_type.fn_type(&[], false);
736 self.module
737 .add_function("sigil_cuda_get_device_count", cuda_device_count_type, None);
738
739 let cuda_malloc_type = i64_type.fn_type(&[i64_type.into()], false);
741 self.module
742 .add_function("sigil_cuda_malloc", cuda_malloc_type, None);
743
744 let cuda_free_type = void_type.fn_type(&[i64_type.into()], false);
746 self.module
747 .add_function("sigil_cuda_free", cuda_free_type, None);
748
749 let cuda_h2d_type =
751 i64_type.fn_type(&[i64_type.into(), ptr_type.into(), i64_type.into()], false);
752 self.module
753 .add_function("sigil_cuda_memcpy_h2d", cuda_h2d_type, None);
754
755 let cuda_d2h_type =
757 i64_type.fn_type(&[ptr_type.into(), i64_type.into(), i64_type.into()], false);
758 self.module
759 .add_function("sigil_cuda_memcpy_d2h", cuda_d2h_type, None);
760
761 let cuda_d2d_type =
763 i64_type.fn_type(&[i64_type.into(), i64_type.into(), i64_type.into()], false);
764 self.module
765 .add_function("sigil_cuda_memcpy_d2d", cuda_d2d_type, None);
766
767 let cuda_sync_type = void_type.fn_type(&[], false);
769 self.module
770 .add_function("sigil_cuda_sync", cuda_sync_type, None);
771
772 let cuda_compile_type = i64_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
774 self.module
775 .add_function("sigil_cuda_compile_kernel", cuda_compile_type, None);
776
777 self.module
779 .add_function("sigil_cuda_load_ptx", cuda_compile_type, None);
780
781 let cuda_launch_1d_type = i64_type.fn_type(
783 &[
784 i64_type.into(),
785 i64_type.into(),
786 i64_type.into(),
787 ptr_type.into(),
788 i64_type.into(),
789 ],
790 false,
791 );
792 self.module
793 .add_function("sigil_cuda_launch_kernel_1d", cuda_launch_1d_type, None);
794
795 let cuda_launch_2d_type = i64_type.fn_type(
797 &[
798 i64_type.into(),
799 i64_type.into(),
800 i64_type.into(),
801 i64_type.into(),
802 i64_type.into(),
803 ptr_type.into(),
804 i64_type.into(),
805 ],
806 false,
807 );
808 self.module
809 .add_function("sigil_cuda_launch_kernel_2d", cuda_launch_2d_type, None);
810 }
811
812 fn register_struct(&mut self, struct_def: &ast::StructDef) -> Result<(), String> {
814 let name = &struct_def.name.name;
815
816 if let Some(ref generics) = struct_def.generics {
818 if !generics.params.is_empty() {
819 let type_params: Vec<String> = generics
821 .params
822 .iter()
823 .filter_map(|p| match p {
824 ast::GenericParam::Type { name, .. } => Some(name.name.clone()),
825 ast::GenericParam::Const { name, .. } => Some(name.name.clone()),
826 ast::GenericParam::Lifetime(_) => None,
827 })
828 .collect();
829
830 self.generic_structs.insert(
832 name.clone(),
833 GenericStructDef {
834 def: struct_def.clone(),
835 type_params,
836 },
837 );
838 return Ok(());
839 }
840 }
841
842 self.register_concrete_struct(struct_def, &HashMap::new())
844 }
845
846 fn register_concrete_struct(
848 &mut self,
849 struct_def: &ast::StructDef,
850 type_substitutions: &HashMap<String, String>,
851 ) -> Result<(), String> {
852 let base_name = &struct_def.name.name;
853
854 let mangled_name = if type_substitutions.is_empty() {
856 base_name.clone()
857 } else {
858 let args: Vec<String> = type_substitutions.values().cloned().collect();
859 format!("{}_{}", base_name, args.join("_"))
860 };
861
862 if self.struct_types.contains_key(&mangled_name) {
864 return Ok(());
865 }
866
867 let i64_type = self.context.i64_type();
868 let f64_type = self.context.f64_type();
869
870 let mut field_types: Vec<BasicTypeEnum> = Vec::new();
872 let mut field_indices: HashMap<String, u32> = HashMap::new();
873
874 match &struct_def.fields {
875 ast::StructFields::Named(fields) => {
876 for (idx, field) in fields.iter().enumerate() {
877 let llvm_type = self.type_expr_to_llvm(&field.ty, type_substitutions);
878 field_types.push(llvm_type);
879 field_indices.insert(field.name.name.clone(), idx as u32);
880 }
881 }
882 ast::StructFields::Tuple(types) => {
883 for (idx, ty) in types.iter().enumerate() {
884 let llvm_type = self.type_expr_to_llvm(ty, type_substitutions);
885 field_types.push(llvm_type);
886 field_indices.insert(format!("{}", idx), idx as u32);
887 }
888 }
889 ast::StructFields::Unit => {
890 }
892 }
893
894 let field_types_refs: Vec<_> = field_types.iter().map(|t| *t).collect();
896 let struct_type = self.context.struct_type(&field_types_refs, false);
897
898 self.struct_types.insert(
900 mangled_name,
901 StructInfo {
902 llvm_type: struct_type,
903 field_indices,
904 },
905 );
906
907 Ok(())
908 }
909
910 fn type_expr_to_llvm(
912 &mut self,
913 ty: &ast::TypeExpr,
914 substitutions: &HashMap<String, String>,
915 ) -> BasicTypeEnum<'ctx> {
916 let i64_type = self.context.i64_type();
917 let f64_type = self.context.f64_type();
918 let i32_type = self.context.i32_type();
919 let i8_type = self.context.i8_type();
920 let bool_type = self.context.bool_type();
921
922 match ty {
923 ast::TypeExpr::Path(path) => {
924 if let Some(segment) = path.segments.first() {
925 let name = &segment.ident.name;
926
927 if let Some(concrete) = substitutions.get(name) {
929 return self.primitive_to_llvm(concrete);
930 }
931
932 match name.as_str() {
934 "i8" | "u8" => i8_type.into(),
935 "i16" | "u16" => self.context.i16_type().into(),
936 "i32" | "u32" => i32_type.into(),
937 "i64" | "u64" | "isize" | "usize" => i64_type.into(),
938 "f32" => self.context.f32_type().into(),
939 "f64" => f64_type.into(),
940 "bool" => bool_type.into(),
941 "F32x16" | "__m512" => {
943 self.context.f32_type().vec_type(16).into()
945 }
946 "F64x8" | "__m512d" => {
947 self.context.f64_type().vec_type(8).into()
949 }
950 "I32x16" | "__m512i" => {
951 self.context.i32_type().vec_type(16).into()
953 }
954 "I64x8" => {
955 self.context.i64_type().vec_type(8).into()
957 }
958 "F32x8" | "__m256" => self.context.f32_type().vec_type(8).into(),
960 "F64x4" | "__m256d" => self.context.f64_type().vec_type(4).into(),
961 _ => i64_type.into(), }
963 } else {
964 i64_type.into()
965 }
966 }
967 ast::TypeExpr::Reference { inner, .. } | ast::TypeExpr::Pointer { inner, .. } => {
968 i64_type.into()
970 }
971 ast::TypeExpr::Array { element, .. } => {
972 i64_type.into()
974 }
975 ast::TypeExpr::Tuple(elements) => {
976 i64_type.into()
978 }
979 ast::TypeExpr::Evidential { inner, .. } => {
980 self.type_expr_to_llvm(inner, substitutions)
982 }
983 _ => i64_type.into(),
984 }
985 }
986
987 fn primitive_to_llvm(&self, name: &str) -> BasicTypeEnum<'ctx> {
989 match name {
990 "i8" | "u8" => self.context.i8_type().into(),
991 "i16" | "u16" => self.context.i16_type().into(),
992 "i32" | "u32" => self.context.i32_type().into(),
993 "i64" | "u64" | "isize" | "usize" => self.context.i64_type().into(),
994 "f32" => self.context.f32_type().into(),
995 "f64" => self.context.f64_type().into(),
996 "bool" => self.context.bool_type().into(),
997 _ => self.context.i64_type().into(),
998 }
999 }
1000
1001 fn monomorphize_struct(
1003 &mut self,
1004 base_name: &str,
1005 type_args: &[ast::TypeExpr],
1006 ) -> Result<String, String> {
1007 let generic_def = self
1009 .generic_structs
1010 .get(base_name)
1011 .ok_or_else(|| format!("Unknown generic struct: {}", base_name))?
1012 .clone();
1013
1014 if type_args.len() != generic_def.type_params.len() {
1015 return Err(format!(
1016 "Wrong number of type arguments for {}: expected {}, got {}",
1017 base_name,
1018 generic_def.type_params.len(),
1019 type_args.len()
1020 ));
1021 }
1022
1023 let mut substitutions: HashMap<String, String> = HashMap::new();
1025 for (param, arg) in generic_def.type_params.iter().zip(type_args.iter()) {
1026 let concrete_name = self.type_expr_to_name(arg);
1027 substitutions.insert(param.clone(), concrete_name);
1028 }
1029
1030 let concrete_names: Vec<String> = substitutions.values().cloned().collect();
1032 let mangled_name = format!("{}_{}", base_name, concrete_names.join("_"));
1033
1034 if !self.struct_types.contains_key(&mangled_name) {
1036 self.register_concrete_struct(&generic_def.def, &substitutions)?;
1037 }
1038
1039 Ok(mangled_name)
1040 }
1041
1042 fn type_expr_to_name(&self, ty: &ast::TypeExpr) -> String {
1044 match ty {
1045 ast::TypeExpr::Path(path) => path
1046 .segments
1047 .iter()
1048 .map(|s| s.ident.name.clone())
1049 .collect::<Vec<_>>()
1050 .join("_"),
1051 ast::TypeExpr::Reference { inner, mutable, .. } => {
1052 let prefix = if *mutable { "mut_ref" } else { "ref" };
1053 format!("{}_{}", prefix, self.type_expr_to_name(inner))
1054 }
1055 ast::TypeExpr::Pointer { inner, mutable, .. } => {
1056 let prefix = if *mutable { "mut_ptr" } else { "ptr" };
1057 format!("{}_{}", prefix, self.type_expr_to_name(inner))
1058 }
1059 ast::TypeExpr::Array { element, .. } => {
1060 format!("arr_{}", self.type_expr_to_name(element))
1061 }
1062 ast::TypeExpr::Tuple(elements) => {
1063 let names: Vec<_> =
1064 elements.iter().map(|e| self.type_expr_to_name(e)).collect();
1065 format!("tup_{}", names.join("_"))
1066 }
1067 ast::TypeExpr::Evidential { inner, .. } => self.type_expr_to_name(inner),
1068 _ => "unknown".to_string(),
1069 }
1070 }
1071
1072 fn get_evidential_type(&mut self, base_type_name: &str) -> StructType<'ctx> {
1079 if let Some(existing) = self.evidential_types.get(base_type_name) {
1080 return *existing;
1081 }
1082
1083 let i8_type = self.context.i8_type();
1085 let value_type = self.primitive_to_llvm(base_type_name);
1086
1087 let struct_name = format!("Evidential_{}", base_type_name);
1088 let struct_type = self
1089 .context
1090 .struct_type(&[i8_type.into(), value_type], false);
1091
1092 self.evidential_types
1093 .insert(base_type_name.to_string(), struct_type);
1094 struct_type
1095 }
1096
1097 fn create_evidential_value(
1100 &mut self,
1101 fn_value: FunctionValue<'ctx>,
1102 value: IntValue<'ctx>,
1103 evidence: u8,
1104 type_name: &str,
1105 ) -> Result<StructValue<'ctx>, String> {
1106 let evidential_type = self.get_evidential_type(type_name);
1107 let tag = self.context.i8_type().const_int(evidence as u64, false);
1108
1109 let ptr = self
1111 .builder
1112 .build_alloca(evidential_type, "evidential")
1113 .map_err(|e| e.to_string())?;
1114
1115 let tag_ptr = self
1117 .builder
1118 .build_struct_gep(evidential_type, ptr, 0, "tag_ptr")
1119 .map_err(|e| e.to_string())?;
1120 self.builder
1121 .build_store(tag_ptr, tag)
1122 .map_err(|e| e.to_string())?;
1123
1124 let value_ptr = self
1126 .builder
1127 .build_struct_gep(evidential_type, ptr, 1, "value_ptr")
1128 .map_err(|e| e.to_string())?;
1129 self.builder
1130 .build_store(value_ptr, value)
1131 .map_err(|e| e.to_string())?;
1132
1133 let result = self
1135 .builder
1136 .build_load(evidential_type, ptr, "evidential_val")
1137 .map_err(|e| e.to_string())?;
1138
1139 Ok(result.into_struct_value())
1140 }
1141
1142 fn unwrap_evidential_value(
1145 &mut self,
1146 evidential_struct: StructValue<'ctx>,
1147 ) -> Result<IntValue<'ctx>, String> {
1148 let value = self
1150 .builder
1151 .build_extract_value(evidential_struct, 1, "unwrapped")
1152 .map_err(|e| e.to_string())?;
1153
1154 Ok(value.into_int_value())
1155 }
1156
1157 fn get_evidence_tag(
1159 &mut self,
1160 evidential_struct: StructValue<'ctx>,
1161 ) -> Result<IntValue<'ctx>, String> {
1162 let tag = self
1163 .builder
1164 .build_extract_value(evidential_struct, 0, "tag")
1165 .map_err(|e| e.to_string())?;
1166
1167 Ok(tag.into_int_value())
1168 }
1169
1170 fn evidentiality_to_tag(ev: &ast::Evidentiality) -> u8 {
1172 match ev {
1173 ast::Evidentiality::Known => EVIDENCE_KNOWN,
1174 ast::Evidentiality::Uncertain => EVIDENCE_UNCERTAIN,
1175 ast::Evidentiality::Reported => EVIDENCE_REPORTED,
1176 ast::Evidentiality::Predicted => EVIDENCE_PREDICTED,
1177 ast::Evidentiality::Paradox => EVIDENCE_PARADOX,
1178 }
1179 }
1180
1181 fn combine_evidence(
1185 &mut self,
1186 tag1: IntValue<'ctx>,
1187 tag2: IntValue<'ctx>,
1188 ) -> Result<IntValue<'ctx>, String> {
1189 let cmp = self
1191 .builder
1192 .build_int_compare(IntPredicate::UGT, tag1, tag2, "ev_cmp")
1193 .map_err(|e| e.to_string())?;
1194
1195 let result = self
1196 .builder
1197 .build_select(cmp, tag1, tag2, "ev_combined")
1198 .map_err(|e| e.to_string())?;
1199
1200 Ok(result.into_int_value())
1201 }
1202
1203 fn register_enum(&mut self, enum_def: &ast::EnumDef) -> Result<(), String> {
1205 let name = &enum_def.name.name;
1206 let mut variants: HashMap<String, u64> = HashMap::new();
1207
1208 for (idx, variant) in enum_def.variants.iter().enumerate() {
1209 let discriminant = idx as u64;
1210 variants.insert(variant.name.name.clone(), discriminant);
1211 }
1212
1213 self.enum_types.insert(name.clone(), EnumInfo { variants });
1214 Ok(())
1215 }
1216
1217 fn process_static(&mut self, static_decl: &ast::StaticDef) -> Result<(), String> {
1219 let name = &static_decl.name.name;
1220 let i64_type = self.context.i64_type();
1222 let global = self.module.add_global(i64_type, None, name);
1223 global.set_initializer(&i64_type.const_int(0, false));
1225 self.global_vars.insert(name.clone(), global);
1226 Ok(())
1227 }
1228
1229 fn process_const(&mut self, const_decl: &ast::ConstDef) -> Result<(), String> {
1231 let name = &const_decl.name.name;
1232 let i64_type = self.context.i64_type();
1234 let global = self.module.add_global(i64_type, None, name);
1235 global.set_initializer(&i64_type.const_int(0, false));
1237 global.set_constant(true);
1238 self.global_vars.insert(name.clone(), global);
1239 Ok(())
1240 }
1241
1242 fn extract_impl_type_name(&self, self_ty: &ast::TypeExpr) -> Result<String, String> {
1244 match self_ty {
1245 ast::TypeExpr::Path(path) => path
1246 .segments
1247 .last()
1248 .map(|s| s.ident.name.clone())
1249 .ok_or_else(|| "Empty impl type path".to_string()),
1250 ast::TypeExpr::Evidential {
1251 inner,
1252 evidentiality,
1253 ..
1254 } => {
1255 let inner_name = self.extract_impl_type_name(inner)?;
1257 match evidentiality {
1258 ast::Evidentiality::Uncertain => Ok(format!("Option_{}", inner_name)),
1259 ast::Evidentiality::Known => Ok(format!("Result_{}", inner_name)),
1260 ast::Evidentiality::Reported => Ok(format!("Reported_{}", inner_name)),
1261 ast::Evidentiality::Predicted => Ok(format!("Predicted_{}", inner_name)),
1262 ast::Evidentiality::Paradox => Ok(format!("Paradox_{}", inner_name)),
1263 }
1264 }
1265 ast::TypeExpr::Reference { inner, .. } => {
1266 self.extract_impl_type_name(inner)
1268 }
1269 ast::TypeExpr::Slice(inner) => {
1270 let inner_name = self.extract_impl_type_name(inner)?;
1271 Ok(format!("Slice_{}", inner_name))
1272 }
1273 ast::TypeExpr::Array { element, .. } => {
1274 let inner_name = self.extract_impl_type_name(element)?;
1275 Ok(format!("Array_{}", inner_name))
1276 }
1277 ast::TypeExpr::Tuple(elements) => {
1278 if elements.is_empty() {
1279 Ok("Unit".to_string())
1280 } else {
1281 let names: Result<Vec<_>, _> = elements
1282 .iter()
1283 .map(|e| self.extract_impl_type_name(e))
1284 .collect();
1285 Ok(format!("Tuple_{}", names?.join("_")))
1286 }
1287 }
1288 _ => Ok("UnknownType".to_string()),
1290 }
1291 }
1292
1293 fn declare_impl_methods(&mut self, impl_block: &ast::ImplBlock) -> Result<(), String> {
1295 let type_name = self.extract_impl_type_name(&impl_block.self_ty)?;
1298
1299 for item in &impl_block.items {
1300 if let ast::ImplItem::Function(func) = item {
1301 let method_name = &func.name.name;
1302 let mangled_name = format!("{}_{}", type_name, method_name);
1303
1304 let i64_type = self.context.i64_type();
1306
1307 let has_explicit_self = func.params.first().map_or(false, |p| {
1309 matches!(&p.pattern, ast::Pattern::Ident { name, .. } if name.name == "self" || name.name == "this")
1310 });
1311
1312 let has_self_ref = func.params.first().map_or(false, |p| {
1314 matches!(&p.pattern, ast::Pattern::Ref { pattern, .. } if {
1315 matches!(&**pattern, ast::Pattern::Ident { name, .. } if name.name == "self" || name.name == "this")
1316 }) || matches!(&p.pattern, ast::Pattern::RefBinding { name, .. } if name.name == "self" || name.name == "this")
1317 });
1318
1319 let is_instance_method = has_explicit_self || has_self_ref;
1322
1323 let param_count = func.params.len();
1325 let param_types: Vec<BasicMetadataTypeEnum> =
1326 (0..param_count).map(|_| i64_type.into()).collect();
1327
1328 let fn_type = i64_type.fn_type(¶m_types, false);
1329 let fn_value = self.module.add_function(&mangled_name, fn_type, None);
1330
1331 for (i, param) in func.params.iter().enumerate() {
1333 let param_name = match ¶m.pattern {
1334 ast::Pattern::Ident { name: ident, .. } => ident.name.clone(),
1335 ast::Pattern::RefBinding { name: ident, .. } => ident.name.clone(),
1336 ast::Pattern::Ref { pattern, .. } => {
1337 if let ast::Pattern::Ident { name: ident, .. } = &**pattern {
1338 ident.name.clone()
1339 } else {
1340 format!("param{}", i)
1341 }
1342 }
1343 _ => format!("param{}", i),
1344 };
1345 fn_value
1346 .get_nth_param(i as u32)
1347 .unwrap()
1348 .set_name(¶m_name);
1349 }
1350 let _ = is_instance_method; self.functions.insert(mangled_name.clone(), fn_value);
1353 self.impl_methods
1354 .insert((type_name.clone(), method_name.clone()), mangled_name);
1355 }
1356 }
1357 Ok(())
1358 }
1359
1360 fn compile_impl_methods(&mut self, impl_block: &ast::ImplBlock) -> Result<(), String> {
1362 let type_name = self.extract_impl_type_name(&impl_block.self_ty)?;
1364
1365 self.current_self_type = Some(type_name.clone());
1367
1368 for item in &impl_block.items {
1369 if let ast::ImplItem::Function(func) = item {
1370 let method_name = &func.name.name;
1371 let mangled_name = format!("{}_{}", type_name, method_name);
1372
1373 let fn_value = *self
1374 .functions
1375 .get(&mangled_name)
1376 .ok_or_else(|| format!("Method not declared: {}", mangled_name))?;
1377
1378 let entry = self.context.append_basic_block(fn_value, "entry");
1380 self.builder.position_at_end(entry);
1381
1382 let mut scope = CompileScope::new();
1384
1385 for (i, param) in func.params.iter().enumerate() {
1388 let param_name = match ¶m.pattern {
1389 ast::Pattern::Ident { name: ident, .. } => ident.name.clone(),
1390 ast::Pattern::RefBinding { name: ident, .. } => ident.name.clone(),
1391 ast::Pattern::Ref { pattern, .. } => {
1392 if let ast::Pattern::Ident { name: ident, .. } = &**pattern {
1393 ident.name.clone()
1394 } else {
1395 format!("param{}", i)
1396 }
1397 }
1398 _ => format!("param{}", i),
1399 };
1400 let param_value = fn_value.get_nth_param(i as u32).unwrap();
1401 let alloca = self
1402 .builder
1403 .build_alloca(self.context.i64_type(), ¶m_name)
1404 .map_err(|e| e.to_string())?;
1405 self.builder
1406 .build_store(alloca, param_value)
1407 .map_err(|e| e.to_string())?;
1408 scope.vars.insert(param_name, alloca);
1409 }
1410
1411 if let Some(ref body) = func.body {
1413 let result = self.compile_block(fn_value, &mut scope, body)?;
1414
1415 let current_block = self.builder.get_insert_block().unwrap();
1416 if current_block.get_terminator().is_none() {
1417 if let Some(val) = result {
1418 self.builder
1419 .build_return(Some(&val))
1420 .map_err(|e| e.to_string())?;
1421 } else {
1422 let zero = self.context.i64_type().const_int(0, false);
1423 self.builder
1424 .build_return(Some(&zero))
1425 .map_err(|e| e.to_string())?;
1426 }
1427 }
1428 } else {
1429 let zero = self.context.i64_type().const_int(0, false);
1430 self.builder
1431 .build_return(Some(&zero))
1432 .map_err(|e| e.to_string())?;
1433 }
1434 }
1435 }
1436
1437 self.current_self_type = None;
1439 Ok(())
1440 }
1441
1442 fn declare_function(
1444 &mut self,
1445 func: &ast::Function,
1446 ) -> Result<FunctionValue<'ctx>, String> {
1447 let name = &func.name.name;
1448
1449 let mangled_name = if self.current_module.len() > 1 {
1451 let module_path = self.current_module[1..].join("_");
1452 format!("{}_{}", module_path, name)
1453 } else {
1454 name.clone()
1455 };
1456
1457 let actual_name = if self.compile_mode == CompileMode::Aot
1459 && name == "main"
1460 && self.current_module.len() == 1
1461 {
1462 "main_sigil".to_string()
1463 } else {
1464 mangled_name.clone()
1465 };
1466
1467 let i64_type = self.context.i64_type();
1468
1469 let param_types: Vec<BasicMetadataTypeEnum> =
1471 func.params.iter().map(|_| i64_type.into()).collect();
1472
1473 let fn_type = i64_type.fn_type(¶m_types, false);
1475
1476 let fn_value = self.module.add_function(&actual_name, fn_type, None);
1478
1479 let nounwind_attr = self.context.create_enum_attribute(
1482 inkwell::attributes::Attribute::get_named_enum_kind_id("nounwind"),
1483 0,
1484 );
1485 fn_value.add_attribute(inkwell::attributes::AttributeLoc::Function, nounwind_attr);
1486
1487 for (i, param) in func.params.iter().enumerate() {
1489 if let ast::Pattern::Ident {
1490 name: ref ident, ..
1491 } = param.pattern
1492 {
1493 fn_value
1494 .get_nth_param(i as u32)
1495 .unwrap()
1496 .set_name(&ident.name);
1497 }
1498 }
1499
1500 self.functions.insert(name.clone(), fn_value);
1502 if self.current_module.len() > 1 {
1503 let full_path = format!("{}::{}", self.current_module[1..].join("::"), name);
1504 self.functions.insert(full_path, fn_value);
1505 }
1506 Ok(fn_value)
1507 }
1508
1509 fn compile_function(&mut self, func: &ast::Function) -> Result<(), String> {
1511 let name = &func.name.name;
1512 let fn_value = *self.functions.get(name).ok_or("Function not declared")?;
1514
1515 let entry = self.context.append_basic_block(fn_value, "entry");
1517 self.builder.position_at_end(entry);
1518
1519 let mut scope = CompileScope::new();
1521
1522 for (i, param) in func.params.iter().enumerate() {
1524 let param_name = match ¶m.pattern {
1526 ast::Pattern::Ident { name: ident, .. } => Some(ident.name.clone()),
1527 ast::Pattern::RefBinding { name: ident, .. } => Some(ident.name.clone()),
1528 _ => {
1529 eprintln!("WARNING: Unhandled parameter pattern type in function '{}' param {}: {:?}",
1530 name, i, param.pattern);
1531 None
1532 }
1533 };
1534
1535 if let Some(param_name) = param_name {
1536 let param_value = fn_value.get_nth_param(i as u32).unwrap();
1537 let alloca = self
1539 .builder
1540 .build_alloca(self.context.i64_type(), ¶m_name)
1541 .map_err(|e| e.to_string())?;
1542 self.builder
1543 .build_store(alloca, param_value)
1544 .map_err(|e| e.to_string())?;
1545 scope.vars.insert(param_name, alloca);
1546 }
1547 }
1548
1549 if let Some(ref body) = func.body {
1551 let result = self.compile_block(fn_value, &mut scope, body)?;
1552
1553 let current_block = self.builder.get_insert_block().unwrap();
1555 if current_block.get_terminator().is_none() {
1556 if let Some(val) = result {
1557 self.builder
1558 .build_return(Some(&val))
1559 .map_err(|e| e.to_string())?;
1560 } else {
1561 let zero = self.context.i64_type().const_int(0, false);
1562 self.builder
1563 .build_return(Some(&zero))
1564 .map_err(|e| e.to_string())?;
1565 }
1566 }
1567 } else {
1568 let zero = self.context.i64_type().const_int(0, false);
1570 self.builder
1571 .build_return(Some(&zero))
1572 .map_err(|e| e.to_string())?;
1573 }
1574
1575 Ok(())
1576 }
1577
1578 fn compile_block(
1580 &mut self,
1581 fn_value: FunctionValue<'ctx>,
1582 scope: &mut CompileScope<'ctx>,
1583 block: &ast::Block,
1584 ) -> Result<Option<IntValue<'ctx>>, String> {
1585 let mut result = None;
1586 for stmt in &block.stmts {
1589 result = self.compile_stmt(fn_value, scope, stmt)?;
1590 if self
1592 .builder
1593 .get_insert_block()
1594 .unwrap()
1595 .get_terminator()
1596 .is_some()
1597 {
1598 return Ok(result);
1599 }
1600 }
1601
1602 if let Some(ref expr) = block.expr {
1604 result = Some(self.compile_expr(fn_value, scope, expr)?);
1605 }
1606
1607 Ok(result)
1608 }
1609
1610 fn compile_stmt(
1612 &mut self,
1613 fn_value: FunctionValue<'ctx>,
1614 scope: &mut CompileScope<'ctx>,
1615 stmt: &ast::Stmt,
1616 ) -> Result<Option<IntValue<'ctx>>, String> {
1617 match stmt {
1618 ast::Stmt::Let { pattern, init, .. } => {
1619 if let ast::Pattern::Ident {
1620 name: ref ident, ..
1621 } = pattern
1622 {
1623 let init_val = if let Some(ref expr) = init {
1625 self.compile_expr(fn_value, scope, expr)?
1626 } else {
1627 self.context.i64_type().const_int(0, false)
1628 };
1629
1630 let alloca = self
1632 .builder
1633 .build_alloca(self.context.i64_type(), &ident.name)
1634 .map_err(|e| e.to_string())?;
1635 self.builder
1636 .build_store(alloca, init_val)
1637 .map_err(|e| e.to_string())?;
1638 scope.vars.insert(ident.name.clone(), alloca);
1639 }
1641 Ok(None)
1642 }
1643 ast::Stmt::Expr(expr) => {
1644 let val = self.compile_expr(fn_value, scope, expr)?;
1645 Ok(Some(val))
1646 }
1647 ast::Stmt::Semi(expr) => {
1648 self.compile_expr(fn_value, scope, expr)?;
1649 Ok(None)
1650 }
1651 ast::Stmt::Item(_) => Ok(None),
1652 ast::Stmt::LetElse { pattern, init, .. } => {
1653 if let ast::Pattern::Ident {
1656 name: ref ident, ..
1657 } = pattern
1658 {
1659 let init_val = self.compile_expr(fn_value, scope, init)?;
1660 let alloca = self
1661 .builder
1662 .build_alloca(self.context.i64_type(), &ident.name)
1663 .map_err(|e| e.to_string())?;
1664 self.builder
1665 .build_store(alloca, init_val)
1666 .map_err(|e| e.to_string())?;
1667 scope.vars.insert(ident.name.clone(), alloca);
1668 }
1669 Ok(None)
1670 }
1671 }
1672 }
1673
1674 fn compile_expr(
1676 &mut self,
1677 fn_value: FunctionValue<'ctx>,
1678 scope: &mut CompileScope<'ctx>,
1679 expr: &Expr,
1680 ) -> Result<IntValue<'ctx>, String> {
1681 match expr {
1682 Expr::Literal(lit) => self.compile_literal(lit),
1683 Expr::Path(path) => {
1684 if path.segments.len() >= 2 {
1686 let enum_name = &path.segments[path.segments.len() - 2].ident.name;
1687 let variant_name = &path.segments[path.segments.len() - 1].ident.name;
1688
1689 if let Some(enum_info) = self.enum_types.get(enum_name) {
1690 if let Some(&discriminant) = enum_info.variants.get(variant_name) {
1691 return Ok(self.context.i64_type().const_int(discriminant, false));
1692 }
1693 }
1694 }
1695
1696 let name = path
1698 .segments
1699 .last()
1700 .map(|s| s.ident.name.as_str())
1701 .ok_or("Empty path")?;
1702
1703 let full_path: String = path
1705 .segments
1706 .iter()
1707 .map(|s| s.ident.name.as_str())
1708 .collect::<Vec<_>>()
1709 .join("::");
1710
1711 if let Some(&ptr) = scope.vars.get(name) {
1712 let val = self
1713 .builder
1714 .build_load(self.context.i64_type(), ptr, name)
1715 .map_err(|e| e.to_string())?;
1716 Ok(val.into_int_value())
1717 } else if let Some(global) = self.global_vars.get(name) {
1718 let val = self
1720 .builder
1721 .build_load(self.context.i64_type(), global.as_pointer_value(), name)
1722 .map_err(|e| e.to_string())?;
1723 Ok(val.into_int_value())
1724 } else if path.segments.len() > 1 {
1725 let type_name = path
1728 .segments
1729 .first()
1730 .map(|s| s.ident.name.as_str())
1731 .unwrap_or("");
1732
1733 if let Some(enum_info) = self.enum_types.get(type_name) {
1735 if let Some(&discriminant) = enum_info.variants.get(name) {
1736 return Ok(self.context.i64_type().const_int(discriminant, false));
1737 }
1738 }
1739
1740 let hash = full_path
1743 .bytes()
1744 .fold(0u64, |acc, b| acc.wrapping_mul(31).wrapping_add(b as u64));
1745 Ok(self.context.i64_type().const_int(hash, false))
1746 } else {
1747 for (_, enum_info) in &self.enum_types {
1749 if let Some(&discriminant) = enum_info.variants.get(name) {
1750 return Ok(self.context.i64_type().const_int(discriminant, false));
1751 }
1752 }
1753
1754 if name
1756 .chars()
1757 .all(|c| c.is_uppercase() || c == '_' || c.is_numeric())
1758 {
1759 let hash = name
1761 .bytes()
1762 .fold(0u64, |acc, b| acc.wrapping_mul(31).wrapping_add(b as u64));
1763 return Ok(self.context.i64_type().const_int(hash, false));
1764 }
1765
1766 Ok(self.context.i64_type().const_int(0, false))
1769 }
1770 }
1771 Expr::Binary { op, left, right } => {
1772 let lhs = self.compile_expr(fn_value, scope, left)?;
1773 let rhs = self.compile_expr(fn_value, scope, right)?;
1774 self.compile_binary_op(*op, lhs, rhs)
1775 }
1776 Expr::Unary { op, expr: inner } => {
1777 let val = self.compile_expr(fn_value, scope, inner)?;
1778 self.compile_unary_op(*op, val)
1779 }
1780 Expr::If {
1781 condition,
1782 then_branch,
1783 else_branch,
1784 } => self.compile_if(
1785 fn_value,
1786 scope,
1787 condition,
1788 then_branch,
1789 else_branch.as_deref(),
1790 ),
1791 Expr::While {
1792 label: _,
1793 condition,
1794 body,
1795 } => self.compile_while(fn_value, scope, condition, body),
1796 Expr::Call { func, args } => self.compile_call(fn_value, scope, func, args),
1797 Expr::Return(val) => {
1798 let ret_val = if let Some(ref e) = val {
1799 self.compile_expr(fn_value, scope, e)?
1800 } else {
1801 self.context.i64_type().const_int(0, false)
1802 };
1803 self.builder
1804 .build_return(Some(&ret_val))
1805 .map_err(|e| e.to_string())?;
1806 Ok(ret_val)
1808 }
1809 Expr::Assign { target, value } => {
1810 let val = self.compile_expr(fn_value, scope, value)?;
1811 match target.as_ref() {
1812 Expr::Path(path) => {
1813 let name = path
1814 .segments
1815 .last()
1816 .map(|s| s.ident.name.as_str())
1817 .ok_or("Empty path")?;
1818 if let Some(&ptr) = scope.vars.get(name) {
1819 self.builder
1820 .build_store(ptr, val)
1821 .map_err(|e| e.to_string())?;
1822 Ok(val)
1823 } else if let Some(global) = self.global_vars.get(name) {
1824 self.builder
1826 .build_store(global.as_pointer_value(), val)
1827 .map_err(|e| e.to_string())?;
1828 Ok(val)
1829 } else {
1830 let i64_type = self.context.i64_type();
1832 let global = self.module.add_global(i64_type, None, name);
1833 global.set_initializer(&i64_type.const_int(0, false));
1834 self.builder
1835 .build_store(global.as_pointer_value(), val)
1836 .map_err(|e| e.to_string())?;
1837 Ok(val)
1839 }
1840 }
1841 Expr::Field { expr, field } => {
1842 let struct_ptr_int = self.compile_expr(fn_value, scope, expr)?;
1844 let ptr_type = self.context.ptr_type(inkwell::AddressSpace::default());
1845 let struct_ptr = self
1846 .builder
1847 .build_int_to_ptr(struct_ptr_int, ptr_type, "struct_ptr")
1848 .map_err(|e| e.to_string())?;
1849
1850 let field_name = &field.name;
1851 for (_name, struct_info) in &self.struct_types {
1853 if let Some(&field_idx) = struct_info.field_indices.get(field_name)
1854 {
1855 let field_ptr = self
1856 .builder
1857 .build_struct_gep(
1858 struct_info.llvm_type,
1859 struct_ptr,
1860 field_idx,
1861 &format!("{}_ptr", field_name),
1862 )
1863 .map_err(|e| e.to_string())?;
1864 self.builder
1865 .build_store(field_ptr, val)
1866 .map_err(|e| e.to_string())?;
1867 return Ok(val);
1868 }
1869 }
1870 let offset = match field_name.as_str() {
1872 "0" => 0u64,
1873 "1" => 1,
1874 "2" => 2,
1875 "3" => 3,
1876 "start" | "first" | "x" | "name" | "key" | "id" => 0,
1877 "end" | "second" | "y" | "value" | "ty" => 1,
1878 "z" | "third" | "body" | "args" => 2,
1879 _ => 0, };
1881 let offset_val = self.context.i64_type().const_int(offset * 8, false);
1882 let field_ptr_int = self
1883 .builder
1884 .build_int_add(struct_ptr_int, offset_val, "field_ptr")
1885 .map_err(|e| e.to_string())?;
1886 let ptr_type = self.context.ptr_type(inkwell::AddressSpace::default());
1887 let field_ptr = self
1888 .builder
1889 .build_int_to_ptr(
1890 field_ptr_int,
1891 ptr_type,
1892 &format!("{}_ptr", field_name),
1893 )
1894 .map_err(|e| e.to_string())?;
1895 self.builder
1896 .build_store(field_ptr, val)
1897 .map_err(|e| e.to_string())?;
1898 Ok(val)
1899 }
1900 Expr::Unary { op, expr } if matches!(op, ast::UnaryOp::Deref) => {
1901 let ptr_val = self.compile_expr(fn_value, scope, expr)?;
1903 let ptr_type = self.context.ptr_type(inkwell::AddressSpace::default());
1904 let ptr = self
1905 .builder
1906 .build_int_to_ptr(ptr_val, ptr_type, "deref_ptr")
1907 .map_err(|e| e.to_string())?;
1908 self.builder
1909 .build_store(ptr, val)
1910 .map_err(|e| e.to_string())?;
1911 Ok(val)
1912 }
1913 Expr::Index { expr, index } => {
1914 let base = self.compile_expr(fn_value, scope, expr)?;
1916 let idx = self.compile_expr(fn_value, scope, index)?;
1917 let offset = self
1919 .builder
1920 .build_int_mul(
1921 idx,
1922 self.context.i64_type().const_int(8, false),
1923 "idx_offset",
1924 )
1925 .map_err(|e| e.to_string())?;
1926 let elem_ptr_int = self
1927 .builder
1928 .build_int_add(base, offset, "elem_ptr")
1929 .map_err(|e| e.to_string())?;
1930 let ptr_type = self.context.ptr_type(inkwell::AddressSpace::default());
1931 let elem_ptr = self
1932 .builder
1933 .build_int_to_ptr(elem_ptr_int, ptr_type, "index_ptr")
1934 .map_err(|e| e.to_string())?;
1935 self.builder
1936 .build_store(elem_ptr, val)
1937 .map_err(|e| e.to_string())?;
1938 Ok(val)
1939 }
1940 _ => {
1941 let _ = self.compile_expr(fn_value, scope, target)?;
1944 Ok(val)
1945 }
1946 }
1947 }
1948 Expr::Block(block) => {
1949 let result = self.compile_block(fn_value, scope, block)?;
1950 Ok(result.unwrap_or_else(|| self.context.i64_type().const_int(0, false)))
1951 }
1952 Expr::Struct { path, fields, .. } => {
1953 let last_segment = path.segments.last().ok_or("Empty struct path")?;
1955 let base_name = last_segment.ident.name.as_str();
1956
1957 let base_name: String = if base_name == "Self" || base_name == "This" {
1959 if let Some(ref self_type) = self.current_self_type {
1960 self_type.clone()
1961 } else {
1962 return Err("Self/This used outside of impl block".to_string());
1963 }
1964 } else {
1965 base_name.to_string()
1966 };
1967
1968 let struct_name = if let Some(ref type_args) = last_segment.generics {
1970 self.monomorphize_struct(&base_name, type_args)?
1972 } else if self.generic_structs.contains_key(&base_name) {
1973 format!("{}_i64", base_name)
1976 } else {
1977 base_name
1978 };
1979
1980 let struct_info_opt = self.struct_types.get(&struct_name).cloned();
1982
1983 if let Some(struct_info) = struct_info_opt {
1984 let struct_ptr = self
1986 .builder
1987 .build_alloca(struct_info.llvm_type, &struct_name)
1988 .map_err(|e| e.to_string())?;
1989
1990 for (idx, field_init) in fields.iter().enumerate() {
1992 let field_name = &field_init.name.name;
1993 let field_idx = *struct_info
1995 .field_indices
1996 .get(field_name)
1997 .unwrap_or(&(idx as u32));
1998
1999 let field_value = if let Some(ref val_expr) = field_init.value {
2001 self.compile_expr(fn_value, scope, val_expr)?
2002 } else {
2003 if let Some(&ptr) = scope.vars.get(field_name.as_str()) {
2005 self.builder
2006 .build_load(self.context.i64_type(), ptr, field_name)
2007 .map_err(|e| e.to_string())?
2008 .into_int_value()
2009 } else {
2010 self.context.i64_type().const_int(0, false)
2012 }
2013 };
2014
2015 let field_ptr = self
2017 .builder
2018 .build_struct_gep(
2019 struct_info.llvm_type,
2020 struct_ptr,
2021 field_idx,
2022 &format!("{}_ptr", field_name),
2023 )
2024 .map_err(|e| e.to_string())?;
2025 self.builder
2026 .build_store(field_ptr, field_value)
2027 .map_err(|e| e.to_string())?;
2028 }
2029
2030 let ptr_int = self
2032 .builder
2033 .build_ptr_to_int(struct_ptr, self.context.i64_type(), "struct_ptr")
2034 .map_err(|e| e.to_string())?;
2035 return Ok(ptr_int);
2036 }
2037
2038 let field_types: Vec<BasicTypeEnum> = fields
2041 .iter()
2042 .map(|_| self.context.i64_type().into())
2043 .collect();
2044
2045 let llvm_type = self.context.struct_type(&field_types, false);
2047 let struct_ptr = self
2048 .builder
2049 .build_alloca(llvm_type, &struct_name)
2050 .map_err(|e| e.to_string())?;
2051
2052 for (idx, field_init) in fields.iter().enumerate() {
2054 let field_name = &field_init.name.name;
2055 let field_idx = idx as u32;
2056
2057 let field_value = if let Some(ref val_expr) = field_init.value {
2059 self.compile_expr(fn_value, scope, val_expr)?
2060 } else {
2061 if let Some(&ptr) = scope.vars.get(field_name.as_str()) {
2063 self.builder
2064 .build_load(self.context.i64_type(), ptr, field_name)
2065 .map_err(|e| e.to_string())?
2066 .into_int_value()
2067 } else {
2068 self.context.i64_type().const_int(0, false)
2070 }
2071 };
2072
2073 let field_ptr = self
2075 .builder
2076 .build_struct_gep(
2077 llvm_type,
2078 struct_ptr,
2079 field_idx,
2080 &format!("{}_ptr", field_name),
2081 )
2082 .map_err(|e| e.to_string())?;
2083 self.builder
2084 .build_store(field_ptr, field_value)
2085 .map_err(|e| e.to_string())?;
2086 }
2087
2088 let ptr_int = self
2090 .builder
2091 .build_ptr_to_int(struct_ptr, self.context.i64_type(), "struct_ptr")
2092 .map_err(|e| e.to_string())?;
2093 Ok(ptr_int)
2094 }
2095 Expr::Field { expr, field } => {
2096 let struct_ptr_int = self.compile_expr(fn_value, scope, expr)?;
2098
2099 let ptr_type = self.context.ptr_type(inkwell::AddressSpace::default());
2101 let struct_ptr = self
2102 .builder
2103 .build_int_to_ptr(struct_ptr_int, ptr_type, "struct_ptr")
2104 .map_err(|e| e.to_string())?;
2105
2106 let field_name = &field.name;
2109 for (_name, struct_info) in &self.struct_types {
2110 if let Some(&field_idx) = struct_info.field_indices.get(field_name) {
2111 let field_ptr = self
2112 .builder
2113 .build_struct_gep(
2114 struct_info.llvm_type,
2115 struct_ptr,
2116 field_idx,
2117 &format!("{}_ptr", field_name),
2118 )
2119 .map_err(|e| e.to_string())?;
2120 let field_value = self
2121 .builder
2122 .build_load(self.context.i64_type(), field_ptr, field_name)
2123 .map_err(|e| e.to_string())?;
2124 return Ok(field_value.into_int_value());
2125 }
2126 }
2127
2128 let field_offset = match field_name.as_str() {
2136 "start" | "first" | "x" | "line" | "lo" | "begin" | "name" | "key"
2138 | "id" | "data" | "value" => Some(0u64),
2139 "end" | "second" | "y" | "col" | "hi" | "suffix" | "span" | "ty"
2141 | "type" => Some(1u64),
2142 "z" | "third" | "depth" | "body" | "args" | "params" => Some(2u64),
2144 "w" | "fourth" | "return_type" | "ret" => Some(3u64),
2146 "message" => Some(0u64),
2148 "source" => Some(1u64),
2149 "file" => Some(2u64),
2150 "kind" => Some(0u64),
2151 "ident" => Some(0u64),
2152 "segments" => Some(0u64),
2153 "items" => Some(0u64),
2154 "fields" => Some(0u64),
2155 "variants" => Some(0u64),
2156 "methods" => Some(0u64),
2157 "generics" => Some(1u64),
2158 "vis" | "visibility" => Some(0u64),
2159 "attrs" | "attributes" => Some(1u64),
2160 "node" => Some(0u64),
2161 "path" | "paths" => Some(0u64),
2162 "left" | "lhs" => Some(0u64),
2163 "right" | "rhs" => Some(1u64),
2164 "op" => Some(0u64),
2165 "inner" | "expr" => Some(0u64),
2166 "condition" | "cond" => Some(0u64),
2167 "then_branch" | "then" => Some(1u64),
2168 "else_branch" | "else" => Some(2u64),
2169 "pattern" | "pat" => Some(0u64),
2170 "iter" | "iterator" => Some(1u64),
2171 "guard" => Some(1u64),
2172 "arms" => Some(1u64),
2173 "scrutinee" => Some(0u64),
2174 "init" => Some(0u64),
2175 "receiver" => Some(0u64),
2176 "method" => Some(1u64),
2177 "func" => Some(0u64),
2178 "callee" => Some(0u64),
2179 "target" => Some(0u64),
2180 "module" | "mod" => Some(0u64),
2181 "imports" | "uses" => Some(0u64),
2182 "exports" => Some(1u64),
2183 "decls" | "declarations" => Some(0u64),
2184 "stmts" | "statements" => Some(0u64),
2185 "tree" | "ast" | "root" => Some(0u64),
2187 "content" | "contents" => Some(0u64),
2188 "entries" | "elements" | "children" => Some(0u64),
2189 "parent" => Some(0u64),
2190 "next" => Some(1u64),
2191 "prev" => Some(0u64),
2192 "tokens" => Some(0u64),
2193 "input" => Some(0u64),
2194 "output" => Some(1u64),
2195 "errors" => Some(0u64),
2196 "warnings" => Some(1u64),
2197 "result" => Some(0u64),
2198 "success" => Some(0u64),
2199 "failure" => Some(1u64),
2200 "text" | "string" | "str" => Some(0u64),
2201 "len" | "length" | "count" | "size" => Some(1u64),
2202 "pos" | "position" => Some(0u64),
2203 "offset" => Some(0u64),
2204 "range" => Some(0u64),
2205 "scope" => Some(0u64),
2206 "context" | "ctx" => Some(0u64),
2207 "state" | "status" => Some(0u64),
2208 "index" | "idx" => Some(0u64),
2209 "level" => Some(0u64),
2210 "tomes" | "modules" => Some(0u64),
2211 "functions" | "fns" => Some(0u64),
2212 "structs" | "types" => Some(0u64),
2213 "traits" | "interfaces" => Some(0u64),
2214 "env" | "environment" => Some(0u64),
2215 "bindings" => Some(0u64),
2216 "symbols" => Some(0u64),
2217 "table" => Some(0u64),
2218 "impls" | "implementations" => Some(0u64),
2220 "enums" => Some(0u64),
2221 "consts" | "constants" => Some(0u64),
2222 "statics" => Some(0u64),
2223 "uses" | "use_stmts" => Some(0u64),
2224 "imports" => Some(0u64),
2225 "exports" => Some(0u64),
2226 "type_aliases" | "aliases" => Some(0u64),
2227 "macros" => Some(0u64),
2228 "generics" | "type_params" => Some(1u64),
2229 "where_clause" | "bounds" => Some(2u64),
2230 "receiver" | "self_param" => Some(0u64),
2231 "params" | "parameters" => Some(1u64),
2232 "return_ty" | "ret_ty" => Some(2u64),
2233 "is_pub" | "is_public" => Some(0u64),
2234 "is_mut" | "is_mutable" => Some(0u64),
2235 "is_const" | "is_constant" => Some(0u64),
2236 "is_static" => Some(0u64),
2237 "is_async" => Some(0u64),
2238 "is_unsafe" => Some(0u64),
2239 "declared" | "declarations" => Some(0u64),
2240 "defined" | "definitions" => Some(1u64),
2241 "referenced" | "references" => Some(2u64),
2242 "resolved" => Some(0u64),
2243 "unresolved" => Some(1u64),
2244 "pending" => Some(2u64),
2245 "diagnostics" | "diags" => Some(0u64),
2246 "notes" => Some(1u64),
2247 "hints" => Some(2u64),
2248 "fixes" | "suggestions" => Some(3u64),
2249 "self_ty" | "self_type" | "for_type" => Some(0u64),
2251 "trait_ref" | "trait_name" | "trait_path" => Some(1u64),
2252 "associated_items" | "assoc_items" => Some(2u64),
2253 "inner_ty" | "inner_type" | "elem_ty" | "elem_type" => Some(0u64),
2255 "key_ty" | "key_type" => Some(0u64),
2256 "value_ty" | "value_type" => Some(1u64),
2257 "mutable" | "is_mutable" | "is_mut" => Some(0u64),
2259 "evidence" | "evidential" | "evidentiality" => Some(0u64),
2260 "element" | "elem" | "item" => Some(0u64),
2261 "prefix" => Some(0u64),
2263 "suffix" => Some(1u64),
2264 "base" => Some(0u64),
2265 "index" => Some(0u64),
2266 "slice_from" => Some(0u64),
2267 "slice_to" => Some(1u64),
2268 "callee" | "callable" => Some(0u64),
2269 "arguments" | "args_list" => Some(1u64),
2270 "is_async" | "async" => Some(0u64),
2271 "is_await" | "await" => Some(0u64),
2272 "is_unsafe" | "unsafe" => Some(0u64),
2273 "is_move" | "move" => Some(0u64),
2274 "capture" | "captures" => Some(0u64),
2275 "label" => Some(0u64),
2276 "lifetime" => Some(0u64),
2277 "value" | "val" => Some(0u64),
2278 "default" | "default_value" => Some(1u64),
2279 "modulus" | "mod_val" => Some(0u64),
2281 "no_std" | "nostd" => Some(0u64),
2282 "patterns" | "pats" => Some(0u64),
2283 "pos" | "position" | "cursor" => Some(0u64),
2284 "globals" | "global_vars" => Some(0u64),
2285 "current_fn_has_mut_self" | "has_mut_self" => Some(0u64),
2286 "current_fn" | "current_function" => Some(0u64),
2287 "current_block" | "cur_block" => Some(0u64),
2288 "current_loop" | "loop_info" => Some(0u64),
2289 "break_target" | "break_bb" => Some(0u64),
2290 "continue_target" | "continue_bb" => Some(1u64),
2291 "return_type" | "ret_type" | "fn_ret_type" => Some(0u64),
2292 "locals" | "local_vars" => Some(0u64),
2293 "temps" | "temporaries" => Some(0u64),
2294 "stack" | "stack_ptr" => Some(0u64),
2295 "heap" | "heap_ptr" => Some(0u64),
2296 "output_buffer" | "buf" | "buffer" => Some(0u64),
2297 "indent" | "indent_level" => Some(0u64),
2298 "line_start" | "col_start" => Some(0u64),
2299 "line_end" | "col_end" => Some(1u64),
2300 "filename" | "file_name" | "filepath" | "file_path" => Some(0u64),
2301 "iterable" | "collection" | "sequence" => Some(0u64),
2303 "current" | "curr" => Some(0u64),
2304 "remaining" | "rest" => Some(1u64),
2305 "done" | "finished" | "exhausted" => Some(0u64),
2306 "in_closure_body" | "in_closure" => Some(0u64),
2308 "in_loop" | "in_loop_body" => Some(0u64),
2309 "in_async" | "in_async_fn" => Some(0u64),
2310 "lanes" | "lane_count" => Some(0u64),
2312 "scalar_type" | "element_type" => Some(1u64),
2313 "0" => Some(0u64),
2315 "1" => Some(1u64),
2316 "2" => Some(2u64),
2317 "3" => Some(3u64),
2318 "4" => Some(4u64),
2319 "5" => Some(5u64),
2320 "6" => Some(6u64),
2321 "7" => Some(7u64),
2322 "inclusive" | "is_inclusive" => Some(0u64),
2324 "exclusive" | "is_exclusive" => Some(0u64),
2325 "operator" | "op" | "opcode" => Some(0u64),
2327 "operand" | "operands" => Some(1u64),
2328 "precedence" | "prec" => Some(2u64),
2329 "associativity" | "assoc" => Some(3u64),
2330 "params" | "parameters" | "param_list" => Some(1u64),
2332 "type_params" | "generic_params" => Some(2u64),
2333 "constraints" | "where_clause" => Some(3u64),
2334 "no_std" | "is_no_std" | "crate_type" => Some(0u64),
2336 "function" | "fn" | "fn_def" | "fn_decl" => Some(0u64),
2338 "return_value" | "ret_val" => Some(0u64),
2339 "basic_blocks" | "blocks" | "bbs" => Some(0u64),
2340 "entry_block" | "entry" | "entry_bb" => Some(0u64),
2341 "exit_block" | "exit" | "exit_bb" => Some(1u64),
2342 "alloca_block" => Some(2u64),
2343 "name" => Some(0u64),
2345 "pos" => Some(0u64),
2346 "variant" | "enum_variant" => Some(0u64),
2348 "operations" | "ops" => Some(0u64),
2349 "instructions" | "instrs" => Some(0u64),
2350 _ => {
2352 if field_name.chars().all(|c| c.is_numeric()) {
2354 field_name.parse::<u64>().ok()
2355 } else {
2356 None
2357 }
2358 }
2359 };
2360
2361 if let Some(offset) = field_offset {
2362 let offset_val = self.context.i64_type().const_int(offset * 8, false); let struct_ptr_as_int = self
2365 .builder
2366 .build_ptr_to_int(struct_ptr, self.context.i64_type(), "ptr_as_int")
2367 .map_err(|e| e.to_string())?;
2368 let field_ptr_int = self
2369 .builder
2370 .build_int_add(struct_ptr_as_int, offset_val, "field_ptr_int")
2371 .map_err(|e| e.to_string())?;
2372 let field_ptr = self
2373 .builder
2374 .build_int_to_ptr(
2375 field_ptr_int,
2376 ptr_type,
2377 &format!("{}_ptr", field_name),
2378 )
2379 .map_err(|e| e.to_string())?;
2380 let field_value = self
2381 .builder
2382 .build_load(self.context.i64_type(), field_ptr, field_name)
2383 .map_err(|e| e.to_string())?;
2384 return Ok(field_value.into_int_value());
2385 }
2386
2387 let offset_val = self.context.i64_type().const_int(0, false);
2390 let field_ptr_int = self
2391 .builder
2392 .build_int_add(struct_ptr_int, offset_val, "fallback_field_ptr")
2393 .map_err(|e| e.to_string())?;
2394 let field_ptr = self
2395 .builder
2396 .build_int_to_ptr(field_ptr_int, ptr_type, &format!("{}_ptr", field_name))
2397 .map_err(|e| e.to_string())?;
2398 let field_value = self
2399 .builder
2400 .build_load(self.context.i64_type(), field_ptr, field_name)
2401 .map_err(|e| e.to_string())?;
2402 Ok(field_value.into_int_value())
2403 }
2404 Expr::Match { expr, arms } => {
2405 let scrutinee = self.compile_expr(fn_value, scope, expr)?;
2407
2408 let merge_bb = self.context.append_basic_block(fn_value, "match_merge");
2409 let mut incoming: Vec<(
2410 IntValue<'ctx>,
2411 inkwell::basic_block::BasicBlock<'ctx>,
2412 )> = Vec::new();
2413
2414 for (i, arm) in arms.iter().enumerate() {
2416 let pattern_val = match &arm.pattern {
2418 ast::Pattern::Path(path) => {
2419 if path.segments.len() >= 2 {
2420 let enum_name =
2421 &path.segments[path.segments.len() - 2].ident.name;
2422 let variant_name =
2423 &path.segments[path.segments.len() - 1].ident.name;
2424 if let Some(enum_info) = self.enum_types.get(enum_name) {
2425 enum_info.variants.get(variant_name).copied()
2426 } else {
2427 None
2428 }
2429 } else {
2430 None
2431 }
2432 }
2433 ast::Pattern::Literal(lit) => {
2434 if let Ok(v) = self.compile_literal(lit) {
2435 Some(v.get_zero_extended_constant().unwrap_or(0))
2436 } else {
2437 None
2438 }
2439 }
2440 ast::Pattern::Wildcard => None,
2441 _ => None,
2442 };
2443
2444 let then_bb = self
2445 .context
2446 .append_basic_block(fn_value, &format!("match_then_{}", i));
2447 let else_bb = if i + 1 < arms.len() {
2448 self.context
2449 .append_basic_block(fn_value, &format!("match_else_{}", i))
2450 } else {
2451 merge_bb
2452 };
2453
2454 let is_last_arm = i + 1 >= arms.len();
2456 if let Some(disc) = pattern_val {
2457 if is_last_arm {
2458 self.builder
2460 .build_unconditional_branch(then_bb)
2461 .map_err(|e| e.to_string())?;
2462 } else {
2463 let pattern_const = self.context.i64_type().const_int(disc, false);
2464 let cond = self
2465 .builder
2466 .build_int_compare(
2467 IntPredicate::EQ,
2468 scrutinee,
2469 pattern_const,
2470 "match_cmp",
2471 )
2472 .map_err(|e| e.to_string())?;
2473 self.builder
2474 .build_conditional_branch(cond, then_bb, else_bb)
2475 .map_err(|e| e.to_string())?;
2476 }
2477 } else {
2478 self.builder
2480 .build_unconditional_branch(then_bb)
2481 .map_err(|e| e.to_string())?;
2482 }
2483
2484 self.builder.position_at_end(then_bb);
2486
2487 match &arm.pattern {
2490 ast::Pattern::TupleStruct {
2491 path: _, fields, ..
2492 } => {
2493 for (i, field_pattern) in fields.iter().enumerate() {
2496 if let ast::Pattern::Ident { name, .. } = field_pattern {
2497 let offset = (i as u64 + 1) * 8; let offset_val =
2501 self.context.i64_type().const_int(offset, false);
2502
2503 let ptr_type =
2504 self.context.ptr_type(inkwell::AddressSpace::default());
2505 let scrutinee_ptr = self
2506 .builder
2507 .build_int_to_ptr(scrutinee, ptr_type, "scrutinee_ptr")
2508 .map_err(|e| e.to_string())?;
2509 let scrutinee_int = self
2510 .builder
2511 .build_ptr_to_int(
2512 scrutinee_ptr,
2513 self.context.i64_type(),
2514 "scr_int",
2515 )
2516 .map_err(|e| e.to_string())?;
2517 let field_ptr_int = self
2518 .builder
2519 .build_int_add(
2520 scrutinee_int,
2521 offset_val,
2522 "field_ptr_int",
2523 )
2524 .map_err(|e| e.to_string())?;
2525 let field_ptr = self
2526 .builder
2527 .build_int_to_ptr(
2528 field_ptr_int,
2529 ptr_type,
2530 &format!("{}_ptr", name.name),
2531 )
2532 .map_err(|e| e.to_string())?;
2533 let field_val = self
2534 .builder
2535 .build_load(
2536 self.context.i64_type(),
2537 field_ptr,
2538 &name.name,
2539 )
2540 .map_err(|e| e.to_string())?;
2541
2542 let alloca = self
2543 .builder
2544 .build_alloca(self.context.i64_type(), &name.name)
2545 .map_err(|e| e.to_string())?;
2546 self.builder
2547 .build_store(alloca, field_val)
2548 .map_err(|e| e.to_string())?;
2549 scope.vars.insert(name.name.clone(), alloca);
2550 }
2551 }
2552 }
2553 ast::Pattern::Struct {
2554 path: _, fields, ..
2555 } => {
2556 for (i, field_pattern) in fields.iter().enumerate() {
2558 let binding_name = if let Some(ref pat) = field_pattern.pattern
2560 {
2561 if let ast::Pattern::Ident { name, .. } = pat {
2562 Some(name.name.clone())
2563 } else {
2564 None
2565 }
2566 } else {
2567 Some(field_pattern.name.name.clone())
2569 };
2570
2571 if let Some(name) = binding_name {
2572 let offset = (i as u64 + 1) * 8;
2574 let offset_val =
2575 self.context.i64_type().const_int(offset, false);
2576
2577 let ptr_type =
2578 self.context.ptr_type(inkwell::AddressSpace::default());
2579 let scrutinee_ptr = self
2580 .builder
2581 .build_int_to_ptr(scrutinee, ptr_type, "scrutinee_ptr")
2582 .map_err(|e| e.to_string())?;
2583 let scrutinee_int = self
2584 .builder
2585 .build_ptr_to_int(
2586 scrutinee_ptr,
2587 self.context.i64_type(),
2588 "scr_int",
2589 )
2590 .map_err(|e| e.to_string())?;
2591 let field_ptr_int = self
2592 .builder
2593 .build_int_add(
2594 scrutinee_int,
2595 offset_val,
2596 "field_ptr_int",
2597 )
2598 .map_err(|e| e.to_string())?;
2599 let field_ptr = self
2600 .builder
2601 .build_int_to_ptr(
2602 field_ptr_int,
2603 ptr_type,
2604 &format!("{}_ptr", name),
2605 )
2606 .map_err(|e| e.to_string())?;
2607 let field_val = self
2608 .builder
2609 .build_load(self.context.i64_type(), field_ptr, &name)
2610 .map_err(|e| e.to_string())?;
2611
2612 let alloca = self
2613 .builder
2614 .build_alloca(self.context.i64_type(), &name)
2615 .map_err(|e| e.to_string())?;
2616 self.builder
2617 .build_store(alloca, field_val)
2618 .map_err(|e| e.to_string())?;
2619 scope.vars.insert(name, alloca);
2620 }
2621 }
2622 }
2623 ast::Pattern::Ident { name, .. } => {
2624 let alloca = self
2626 .builder
2627 .build_alloca(self.context.i64_type(), &name.name)
2628 .map_err(|e| e.to_string())?;
2629 self.builder
2630 .build_store(alloca, scrutinee)
2631 .map_err(|e| e.to_string())?;
2632 scope.vars.insert(name.name.clone(), alloca);
2633 }
2634 _ => {}
2635 }
2636
2637 let arm_val = self.compile_expr(fn_value, scope, &arm.body)?;
2638
2639 if self
2640 .builder
2641 .get_insert_block()
2642 .unwrap()
2643 .get_terminator()
2644 .is_none()
2645 {
2646 let current_bb = self.builder.get_insert_block().unwrap();
2647 self.builder
2648 .build_unconditional_branch(merge_bb)
2649 .map_err(|e| e.to_string())?;
2650 incoming.push((arm_val, current_bb));
2651 }
2652
2653 if i + 1 < arms.len() {
2655 self.builder.position_at_end(else_bb);
2656 }
2657 }
2658
2659 self.builder.position_at_end(merge_bb);
2661
2662 if incoming.is_empty() {
2663 unsafe {
2667 merge_bb
2668 .delete()
2669 .map_err(|_| "Failed to delete unreachable merge block")?;
2670 }
2671 return Ok(self.context.i64_type().const_int(0, false));
2672 }
2673
2674 let phi = self
2675 .builder
2676 .build_phi(self.context.i64_type(), "match_result")
2677 .map_err(|e| e.to_string())?;
2678
2679 for (val, bb) in &incoming {
2680 phi.add_incoming(&[(val, *bb)]);
2681 }
2682
2683 Ok(phi.as_basic_value().into_int_value())
2684 }
2685 Expr::MethodCall {
2686 receiver,
2687 method,
2688 args,
2689 ..
2690 } => {
2691 let receiver_val = self.compile_expr(fn_value, scope, receiver)?;
2693 let method_name = method.name.as_str();
2694
2695 match method_name {
2697 "push" => {
2698 if args.is_empty() {
2700 return Err("push requires a value argument".to_string());
2701 }
2702 let value = self.compile_expr(fn_value, scope, &args[0])?;
2703 let push_fn = self
2704 .module
2705 .get_function("sigil_vec_push")
2706 .ok_or("sigil_vec_push not declared")?;
2707 self.builder
2708 .build_call(push_fn, &[receiver_val.into(), value.into()], "")
2709 .map_err(|e| e.to_string())?;
2710 return Ok(self.context.i64_type().const_int(0, false));
2711 }
2712 "len" => {
2713 let len_fn = self
2715 .module
2716 .get_function("sigil_vec_len")
2717 .ok_or("sigil_vec_len not declared")?;
2718 let call = self
2719 .builder
2720 .build_call(len_fn, &[receiver_val.into()], "vec_len")
2721 .map_err(|e| e.to_string())?;
2722 return Ok(call
2723 .try_as_basic_value()
2724 .left()
2725 .map(|v| v.into_int_value())
2726 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
2727 }
2728 "get" => {
2729 if args.is_empty() {
2731 return Err("get requires an index argument".to_string());
2732 }
2733 let index = self.compile_expr(fn_value, scope, &args[0])?;
2734 let get_fn = self
2735 .module
2736 .get_function("sigil_vec_get")
2737 .ok_or("sigil_vec_get not declared")?;
2738 let call = self
2739 .builder
2740 .build_call(get_fn, &[receiver_val.into(), index.into()], "vec_get")
2741 .map_err(|e| e.to_string())?;
2742 return Ok(call
2743 .try_as_basic_value()
2744 .left()
2745 .map(|v| v.into_int_value())
2746 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
2747 }
2748 "iter" => {
2749 return Ok(receiver_val);
2753 }
2754 "clone" => {
2755 return Ok(receiver_val);
2758 }
2759 "is_empty" => {
2760 let len_fn = self
2762 .module
2763 .get_function("sigil_vec_len")
2764 .ok_or("sigil_vec_len not declared")?;
2765 let call = self
2766 .builder
2767 .build_call(len_fn, &[receiver_val.into()], "vec_len")
2768 .map_err(|e| e.to_string())?;
2769 let len = call
2770 .try_as_basic_value()
2771 .left()
2772 .map(|v| v.into_int_value())
2773 .unwrap_or_else(|| self.context.i64_type().const_int(0, false));
2774 let zero = self.context.i64_type().const_int(0, false);
2775 let is_empty = self
2776 .builder
2777 .build_int_compare(IntPredicate::EQ, len, zero, "is_empty")
2778 .map_err(|e| e.to_string())?;
2779 let result = self
2781 .builder
2782 .build_int_z_extend(
2783 is_empty,
2784 self.context.i64_type(),
2785 "is_empty_i64",
2786 )
2787 .map_err(|e| e.to_string())?;
2788 return Ok(result);
2789 }
2790 "starts_with" => {
2792 if args.is_empty() {
2793 return Err("starts_with requires a prefix argument".to_string());
2794 }
2795 let prefix = self.compile_expr(fn_value, scope, &args[0])?;
2796 let fn_name = "sigil_string_starts_with";
2797 if let Some(callee) = self.module.get_function(fn_name) {
2798 let call = self
2799 .builder
2800 .build_call(
2801 callee,
2802 &[receiver_val.into(), prefix.into()],
2803 "starts_with",
2804 )
2805 .map_err(|e| e.to_string())?;
2806 return Ok(call
2807 .try_as_basic_value()
2808 .left()
2809 .map(|v| v.into_int_value())
2810 .unwrap_or_else(|| {
2811 self.context.i64_type().const_int(0, false)
2812 }));
2813 }
2814 return Ok(self.context.i64_type().const_int(0, false));
2816 }
2817 "to_string" => {
2818 return Ok(receiver_val);
2821 }
2822 "as_str" | "as_ref" => {
2823 return Ok(receiver_val);
2825 }
2826 "chars" => {
2827 let fn_name = "sigil_string_chars";
2829 if let Some(callee) = self.module.get_function(fn_name) {
2830 let call = self
2831 .builder
2832 .build_call(callee, &[receiver_val.into()], "chars")
2833 .map_err(|e| e.to_string())?;
2834 return Ok(call
2835 .try_as_basic_value()
2836 .left()
2837 .map(|v| v.into_int_value())
2838 .unwrap_or_else(|| {
2839 self.context.i64_type().const_int(0, false)
2840 }));
2841 }
2842 return Ok(receiver_val);
2843 }
2844 "collect" => {
2845 return Ok(receiver_val);
2847 }
2848 "skip" => {
2849 return Ok(receiver_val);
2852 }
2853 "unwrap" => {
2854 return Ok(receiver_val);
2857 }
2858 "unwrap_or" => {
2859 return Ok(receiver_val);
2861 }
2862 "is_some" | "is_ok" => {
2863 return Ok(self.context.i64_type().const_int(1, false));
2865 }
2866 "is_none" | "is_err" => {
2867 return Ok(self.context.i64_type().const_int(0, false));
2869 }
2870 "push_str" => {
2871 if args.is_empty() {
2873 return Err("push_str requires a string argument".to_string());
2874 }
2875 let other = self.compile_expr(fn_value, scope, &args[0])?;
2876 if let Some(callee) = self.module.get_function("sigil_string_push_str")
2877 {
2878 let call = self
2879 .builder
2880 .build_call(
2881 callee,
2882 &[receiver_val.into(), other.into()],
2883 "push_str",
2884 )
2885 .map_err(|e| e.to_string())?;
2886 return Ok(call
2887 .try_as_basic_value()
2888 .left()
2889 .map(|v| v.into_int_value())
2890 .unwrap_or_else(|| {
2891 self.context.i64_type().const_int(0, false)
2892 }));
2893 }
2894 return Ok(receiver_val);
2896 }
2897 "push" => {
2898 if args.is_empty() {
2900 return Err("push requires an argument".to_string());
2901 }
2902 let item = self.compile_expr(fn_value, scope, &args[0])?;
2903 if let Some(callee) = self.module.get_function("sigil_vec_push") {
2905 self.builder
2906 .build_call(
2907 callee,
2908 &[receiver_val.into(), item.into()],
2909 "vec_push",
2910 )
2911 .map_err(|e| e.to_string())?;
2912 return Ok(receiver_val);
2913 }
2914 return Ok(receiver_val);
2915 }
2916 "contains" => {
2917 if args.is_empty() {
2919 return Err("contains requires an argument".to_string());
2920 }
2921 let needle = self.compile_expr(fn_value, scope, &args[0])?;
2922 if let Some(callee) = self.module.get_function("sigil_string_contains")
2923 {
2924 let call = self
2925 .builder
2926 .build_call(
2927 callee,
2928 &[receiver_val.into(), needle.into()],
2929 "contains",
2930 )
2931 .map_err(|e| e.to_string())?;
2932 return Ok(call
2933 .try_as_basic_value()
2934 .left()
2935 .map(|v| v.into_int_value())
2936 .unwrap_or_else(|| {
2937 self.context.i64_type().const_int(0, false)
2938 }));
2939 }
2940 return Ok(self.context.i64_type().const_int(0, false));
2942 }
2943 "trim" | "trim_start" | "trim_end" => {
2944 return Ok(receiver_val);
2946 }
2947 "split" | "lines" => {
2948 return Ok(receiver_val);
2950 }
2951 "join" => {
2952 if let Some(callee) = self.module.get_function("sigil_string_new") {
2954 let call = self
2955 .builder
2956 .build_call(callee, &[], "join_result")
2957 .map_err(|e| e.to_string())?;
2958 return Ok(call
2959 .try_as_basic_value()
2960 .left()
2961 .map(|v| v.into_int_value())
2962 .unwrap_or_else(|| {
2963 self.context.i64_type().const_int(0, false)
2964 }));
2965 }
2966 return Ok(self.context.i64_type().const_int(0, false));
2967 }
2968 _ => {}
2969 }
2970
2971 for ((_type_name, meth_name), mangled_name) in &self.impl_methods {
2974 if meth_name == method_name {
2975 if let Some(callee) = self.module.get_function(mangled_name) {
2976 let mut compiled_args: Vec<BasicMetadataValueEnum> =
2978 vec![receiver_val.into()];
2979 for arg in args {
2980 let arg_val = self.compile_expr(fn_value, scope, arg)?;
2981 compiled_args.push(arg_val.into());
2982 }
2983
2984 let call = self
2985 .builder
2986 .build_call(callee, &compiled_args, "method_call")
2987 .map_err(|e| e.to_string())?;
2988
2989 return Ok(call
2990 .try_as_basic_value()
2991 .left()
2992 .map(|v| v.into_int_value())
2993 .unwrap_or_else(|| {
2994 self.context.i64_type().const_int(0, false)
2995 }));
2996 }
2997 }
2998 }
2999
3000 let method_lower = method_name.to_lowercase();
3004 if method_lower.starts_with("collect")
3005 || method_lower.starts_with("check")
3006 || method_lower.starts_with("validate")
3007 || method_lower.starts_with("verify")
3008 || method_lower.starts_with("register")
3009 || method_lower.starts_with("add")
3010 || method_lower.starts_with("insert")
3011 || method_lower.starts_with("remove")
3012 || method_lower.starts_with("clear")
3013 || method_lower.starts_with("reset")
3014 || method_lower.starts_with("update")
3015 || method_lower.starts_with("set")
3016 || method_lower.starts_with("process")
3017 || method_lower.starts_with("analyze")
3018 || method_lower.starts_with("visit")
3019 || method_lower.starts_with("emit")
3020 || method_lower.starts_with("write")
3021 || method_lower.starts_with("flush")
3022 || method_lower.starts_with("sync")
3023 || method_lower.starts_with("close")
3024 || method_lower.starts_with("finish")
3025 || method_lower.starts_with("complete")
3026 || method_lower.starts_with("init")
3027 || method_lower.starts_with("setup")
3028 || method_lower.starts_with("configure")
3029 {
3030 return Ok(self.context.i64_type().const_int(0, false));
3032 }
3033
3034 if method_lower.starts_with("with_")
3036 || method_lower.starts_with("and_")
3037 || method_lower == "build"
3038 || method_lower == "done"
3039 {
3040 return Ok(receiver_val);
3041 }
3042
3043 if method_lower.starts_with("is_")
3045 || method_lower.starts_with("has_")
3046 || method_lower.starts_with("can_")
3047 || method_lower.starts_with("should_")
3048 || method_lower == "exists"
3049 || method_lower == "contains"
3050 {
3051 return Ok(self.context.i64_type().const_int(0, false));
3053 }
3054
3055 if method_lower.starts_with("get_")
3057 || method_lower.starts_with("find_")
3058 || method_lower.starts_with("lookup_")
3059 || method_lower == "get"
3060 || method_lower == "take"
3061 || method_lower == "borrow"
3062 {
3063 return Ok(receiver_val);
3065 }
3066
3067 return Ok(self.context.i64_type().const_int(0, false));
3070 }
3071 Expr::Evidential {
3079 expr,
3080 evidentiality,
3081 } => {
3082 let inner_val = self.compile_expr(fn_value, scope, expr)?;
3083
3084 match evidentiality {
3085 ast::Evidentiality::Known => {
3086 Ok(inner_val)
3089 }
3090 _ => {
3091 let tag = Self::evidentiality_to_tag(evidentiality);
3094 let evidential = self.create_evidential_value(
3095 fn_value, inner_val, tag, "i64", )?;
3097
3098 self.unwrap_evidential_value(evidential)
3101 }
3102 }
3103 }
3104
3105 Expr::Pipe { expr, operations } => {
3107 self.compile_pipe(fn_value, scope, expr, operations)
3108 }
3109
3110 Expr::Morpheme { kind: _, body } => {
3112 self.compile_expr(fn_value, scope, body)
3114 }
3115
3116 Expr::Index { expr, index } => self.compile_index(fn_value, scope, expr, index),
3118
3119 Expr::Range {
3121 start,
3122 end,
3123 inclusive: _,
3124 } => {
3125 if let Some(s) = start {
3128 self.compile_expr(fn_value, scope, s)
3129 } else if let Some(e) = end {
3130 self.compile_expr(fn_value, scope, e)
3131 } else {
3132 Ok(self.context.i64_type().const_int(0, false))
3133 }
3134 }
3135
3136 Expr::Closure {
3138 params: _, body, ..
3139 } => {
3140 self.compile_expr(fn_value, scope, body)
3143 }
3144
3145 Expr::Cast { expr, .. } => {
3147 self.compile_expr(fn_value, scope, expr)
3149 }
3150
3151 Expr::AddrOf { expr, .. } => self.compile_expr(fn_value, scope, expr),
3153
3154 Expr::Deref(inner) => {
3156 let ptr_val = self.compile_expr(fn_value, scope, inner)?;
3158 let ptr = self
3159 .builder
3160 .build_int_to_ptr(
3161 ptr_val,
3162 self.context.ptr_type(AddressSpace::default()),
3163 "deref_ptr",
3164 )
3165 .map_err(|e| e.to_string())?;
3166 let loaded = self
3167 .builder
3168 .build_load(self.context.i64_type(), ptr, "deref_val")
3169 .map_err(|e| e.to_string())?;
3170 Ok(loaded.into_int_value())
3171 }
3172
3173 Expr::Macro { path, tokens } => {
3175 let macro_name = path
3176 .segments
3177 .last()
3178 .map(|s| s.ident.name.trim_end_matches('!'))
3179 .unwrap_or("unknown");
3180
3181 match macro_name {
3182 "println" | "print" => {
3183 self.compile_print_macro(
3184 fn_value,
3185 scope,
3186 tokens,
3187 macro_name == "println",
3188 )?;
3189 Ok(self.context.i64_type().const_int(0, false))
3190 }
3191 "format" => {
3192 Ok(self.context.i64_type().const_int(0, false))
3195 }
3196 "vec" => {
3197 Ok(self.context.i64_type().const_int(0, false))
3200 }
3201 "panic" => {
3202 let exit_fn = self.module.get_function("sigil_exit");
3205 if let Some(f) = exit_fn {
3206 let one = self.context.i64_type().const_int(1, false);
3207 self.builder
3208 .build_call(f, &[one.into()], "")
3209 .map_err(|e| e.to_string())?;
3210 }
3211 Ok(self.context.i64_type().const_int(0, false))
3212 }
3213 "assert" | "assert_eq" | "assert_ne" => {
3214 Ok(self.context.i64_type().const_int(0, false))
3216 }
3217 _ => {
3218 if let Some(f) = self.module.get_function(macro_name) {
3220 let call = self
3221 .builder
3222 .build_call(f, &[], "macro_call")
3223 .map_err(|e| e.to_string())?;
3224 Ok(call
3225 .try_as_basic_value()
3226 .left()
3227 .map(|v| v.into_int_value())
3228 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)))
3229 } else {
3230 Ok(self.context.i64_type().const_int(0, false))
3231 }
3232 }
3233 }
3234 }
3235
3236 Expr::Try(inner) => {
3238 self.compile_expr(fn_value, scope, inner)
3240 }
3241
3242 Expr::Let { value, .. } => self.compile_expr(fn_value, scope, value),
3244
3245 Expr::Tuple(elements) => {
3247 if let Some(first) = elements.first() {
3248 self.compile_expr(fn_value, scope, first)
3249 } else {
3250 Ok(self.context.i64_type().const_int(0, false))
3251 }
3252 }
3253
3254 Expr::Array(elements) => self.compile_array_literal(fn_value, scope, elements),
3256
3257 Expr::Loop { body, .. } => {
3259 let result = self.compile_block(fn_value, scope, body)?;
3260 Ok(result.unwrap_or_else(|| self.context.i64_type().const_int(0, false)))
3261 }
3262
3263 Expr::For {
3264 pattern,
3265 iter,
3266 body,
3267 ..
3268 } => self.compile_for_loop(fn_value, scope, pattern, iter, body),
3269
3270 Expr::Break { .. } | Expr::Continue { .. } => {
3272 Ok(self.context.i64_type().const_int(0, false))
3273 }
3274
3275 Expr::Unsafe(block) => {
3277 let result = self.compile_block(fn_value, scope, block)?;
3278 Ok(result.unwrap_or_else(|| self.context.i64_type().const_int(0, false)))
3279 }
3280
3281 Expr::Await { expr, .. } => self.compile_expr(fn_value, scope, expr),
3283
3284 _ => {
3285 Err(format!(
3287 "LLVM codegen: unsupported expression {:?}",
3288 std::mem::discriminant(expr)
3289 ))
3290 }
3291 }
3292 }
3293
3294 fn parse_int_literal(&self, value: &str) -> Result<u64, String> {
3296 let s = value.replace('_', "");
3298
3299 let suffixes = [
3301 "isize", "usize", "i128", "u128", "i64", "u64", "i32", "u32", "i16", "u16", "i8",
3302 "u8",
3303 ];
3304 let s = suffixes.iter().fold(s, |acc, suffix| {
3305 if acc.ends_with(suffix) {
3306 acc[..acc.len() - suffix.len()].to_string()
3307 } else {
3308 acc
3309 }
3310 });
3311
3312 if s.starts_with("0x") || s.starts_with("0X") {
3314 u64::from_str_radix(&s[2..], 16)
3315 .map_err(|_| format!("Invalid hex integer: {}", value))
3316 } else if s.starts_with("0b") || s.starts_with("0B") {
3317 u64::from_str_radix(&s[2..], 2)
3318 .map_err(|_| format!("Invalid binary integer: {}", value))
3319 } else if s.starts_with("0o") || s.starts_with("0O") {
3320 u64::from_str_radix(&s[2..], 8)
3321 .map_err(|_| format!("Invalid octal integer: {}", value))
3322 } else {
3323 s.parse::<u64>()
3324 .or_else(|_| {
3325 s.parse::<i64>().map(|v| v as u64)
3327 })
3328 .map_err(|_| format!("Invalid integer: {}", value))
3329 }
3330 }
3331
3332 fn compile_literal(&mut self, lit: &Literal) -> Result<IntValue<'ctx>, String> {
3334 match lit {
3335 Literal::Int { value, .. } => {
3336 let v = self.parse_int_literal(value)?;
3338 Ok(self.context.i64_type().const_int(v, false))
3339 }
3340 Literal::Bool(b) => Ok(self
3341 .context
3342 .i64_type()
3343 .const_int(if *b { 1 } else { 0 }, false)),
3344 Literal::Float { value, .. } => {
3345 let s = value.replace('_', "");
3348 let s = s.trim_end_matches("f64").trim_end_matches("f32");
3349 let v: f64 = s.parse().map_err(|_| format!("Invalid float: {}", value))?;
3350 Ok(self.context.i64_type().const_int(v.to_bits(), false))
3351 }
3352 Literal::String(s) => {
3353 let counter = self.string_counter.get();
3355 self.string_counter.set(counter + 1);
3356 let global_name = format!(".str.{}", counter);
3357
3358 let string_bytes = s.as_bytes();
3360 let const_array = self.context.const_string(string_bytes, true);
3361
3362 let global = self
3364 .module
3365 .add_global(const_array.get_type(), None, &global_name);
3366 global.set_initializer(&const_array);
3367 global.set_constant(true);
3368 global.set_linkage(inkwell::module::Linkage::Private);
3369
3370 let ptr = global.as_pointer_value();
3372 let ptr_as_int = self
3373 .builder
3374 .build_ptr_to_int(ptr, self.context.i64_type(), "str_ptr")
3375 .map_err(|e| e.to_string())?;
3376 Ok(ptr_as_int)
3377 }
3378 Literal::Char(c) => Ok(self.context.i64_type().const_int(*c as u64, false)),
3379 _ => Ok(self.context.i64_type().const_int(0, false)),
3380 }
3381 }
3382
3383 fn compile_pipe(
3385 &mut self,
3386 fn_value: FunctionValue<'ctx>,
3387 scope: &mut CompileScope<'ctx>,
3388 expr: &Expr,
3389 operations: &[ast::PipeOp],
3390 ) -> Result<IntValue<'ctx>, String> {
3391 use ast::PipeOp;
3392
3393 if let Expr::Array(elements) = expr {
3395 if operations.len() == 1 {
3397 match &operations[0] {
3398 PipeOp::ReduceSum => {
3399 return self.compile_array_sum(fn_value, scope, elements);
3400 }
3401 PipeOp::ReduceProd => {
3402 return self.compile_array_product(fn_value, scope, elements);
3403 }
3404 PipeOp::Transform(closure) => {
3405 return self
3406 .compile_array_transform(fn_value, scope, elements, closure);
3407 }
3408 PipeOp::Filter(predicate) => {
3409 return self.compile_array_filter(fn_value, scope, elements, predicate);
3410 }
3411 PipeOp::First => {
3412 return self.compile_array_first(fn_value, scope, elements);
3413 }
3414 PipeOp::Last => {
3415 return self.compile_array_last(fn_value, scope, elements);
3416 }
3417 PipeOp::Nth(index_expr) => {
3418 return self.compile_array_nth(fn_value, scope, elements, index_expr);
3419 }
3420 PipeOp::Middle => {
3421 return self.compile_array_middle(fn_value, scope, elements);
3422 }
3423 PipeOp::ReduceMin => {
3424 return self.compile_array_min(fn_value, scope, elements);
3425 }
3426 PipeOp::ReduceMax => {
3427 return self.compile_array_max(fn_value, scope, elements);
3428 }
3429 PipeOp::ReduceAll => {
3430 return self.compile_array_all(fn_value, scope, elements);
3431 }
3432 PipeOp::ReduceAny => {
3433 return self.compile_array_any(fn_value, scope, elements);
3434 }
3435 PipeOp::Sort(_) => {
3436 return self.compile_array_sort(fn_value, scope, elements);
3437 }
3438 PipeOp::Choice => {
3439 return self.compile_array_choice(fn_value, scope, elements);
3440 }
3441 PipeOp::Reduce(reduce_fn) => {
3442 return self.compile_array_reduce(fn_value, scope, elements, reduce_fn);
3443 }
3444 PipeOp::Await => {
3445 return self.compile_array_sum(fn_value, scope, elements);
3448 }
3449 _ => {}
3450 }
3451 }
3452 if operations.len() == 2 {
3454 if let PipeOp::Transform(closure) = &operations[0] {
3455 match &operations[1] {
3456 PipeOp::ReduceSum => {
3457 return self.compile_array_transform_then_sum(
3458 fn_value, scope, elements, closure,
3459 );
3460 }
3461 PipeOp::ReduceProd => {
3462 return self.compile_array_transform_then_product(
3463 fn_value, scope, elements, closure,
3464 );
3465 }
3466 _ => {}
3467 }
3468 }
3469 if let PipeOp::Filter(predicate) = &operations[0] {
3470 match &operations[1] {
3471 PipeOp::ReduceSum => {
3472 return self.compile_array_filter_then_sum(
3473 fn_value, scope, elements, predicate,
3474 );
3475 }
3476 PipeOp::ReduceProd => {
3477 return self.compile_array_filter_then_product(
3478 fn_value, scope, elements, predicate,
3479 );
3480 }
3481 _ => {}
3482 }
3483 }
3484 }
3485 }
3486
3487 let mut current = self.compile_expr(fn_value, scope, expr)?;
3489
3490 for op in operations {
3491 current = match op {
3492 PipeOp::Transform(transform_fn) => {
3494 if let Expr::Closure { body, .. } = transform_fn.as_ref() {
3495 self.compile_expr(fn_value, scope, body)?
3497 } else {
3498 self.compile_expr(fn_value, scope, transform_fn)?
3499 }
3500 }
3501
3502 PipeOp::Filter(predicate) => {
3504 let pred_result = self.compile_expr(fn_value, scope, predicate)?;
3505 let zero = self.context.i64_type().const_int(0, false);
3506 let is_true = self
3507 .builder
3508 .build_int_compare(IntPredicate::NE, pred_result, zero, "filter_cond")
3509 .map_err(|e| e.to_string())?;
3510 self.builder
3511 .build_select(is_true, current, zero, "filter_result")
3512 .map_err(|e| e.to_string())?
3513 .into_int_value()
3514 }
3515
3516 PipeOp::ReduceSum | PipeOp::ReduceProd => current,
3518
3519 PipeOp::ReduceMin | PipeOp::ReduceMax => current,
3521
3522 PipeOp::ReduceAll | PipeOp::ReduceAny => {
3524 let zero = self.context.i64_type().const_int(0, false);
3525 let one = self.context.i64_type().const_int(1, false);
3526 let is_true = self
3527 .builder
3528 .build_int_compare(IntPredicate::NE, current, zero, "is_true")
3529 .map_err(|e| e.to_string())?;
3530 self.builder
3531 .build_select(is_true, one, zero, "bool_result")
3532 .map_err(|e| e.to_string())?
3533 .into_int_value()
3534 }
3535
3536 PipeOp::Sort(_) => current,
3538
3539 PipeOp::Choice => current,
3541
3542 PipeOp::First | PipeOp::Last | PipeOp::Middle => current,
3544 PipeOp::Nth(_) => current,
3545
3546 PipeOp::Await => current,
3548
3549 PipeOp::Reduce(_) => current,
3551
3552 _ => current,
3554 };
3555 }
3556
3557 Ok(current)
3558 }
3559
3560 fn compile_array_sum(
3562 &mut self,
3563 fn_value: FunctionValue<'ctx>,
3564 scope: &mut CompileScope<'ctx>,
3565 elements: &[Expr],
3566 ) -> Result<IntValue<'ctx>, String> {
3567 let len = elements.len();
3568 if len == 0 {
3569 return Ok(self.context.i64_type().const_int(0, false));
3570 }
3571
3572 let i64_type = self.context.i64_type();
3573
3574 if len <= 8 {
3576 let mut sum = self.compile_expr(fn_value, scope, &elements[0])?;
3577 for elem in &elements[1..] {
3578 let val = self.compile_expr(fn_value, scope, elem)?;
3579 sum = self
3580 .builder
3581 .build_int_add(sum, val, "sum")
3582 .map_err(|e| e.to_string())?;
3583 }
3584 return Ok(sum);
3585 }
3586
3587 let array_type = i64_type.array_type(len as u32);
3589 let array_ptr = self
3590 .builder
3591 .build_alloca(array_type, "sum_array")
3592 .map_err(|e| e.to_string())?;
3593
3594 for (i, elem) in elements.iter().enumerate() {
3596 let value = self.compile_expr(fn_value, scope, elem)?;
3597 let indices = [
3598 i64_type.const_int(0, false),
3599 i64_type.const_int(i as u64, false),
3600 ];
3601 let elem_ptr = unsafe {
3602 self.builder
3603 .build_gep(array_type, array_ptr, &indices, "elem_ptr")
3604 }
3605 .map_err(|e| e.to_string())?;
3606 self.builder
3607 .build_store(elem_ptr, value)
3608 .map_err(|e| e.to_string())?;
3609 }
3610
3611 let loop_header = self.context.append_basic_block(fn_value, "sum_header");
3613 let loop_body = self.context.append_basic_block(fn_value, "sum_body");
3614 let loop_exit = self.context.append_basic_block(fn_value, "sum_exit");
3615
3616 let sum_ptr = self
3618 .builder
3619 .build_alloca(i64_type, "sum_ptr")
3620 .map_err(|e| e.to_string())?;
3621 let idx_ptr = self
3622 .builder
3623 .build_alloca(i64_type, "idx_ptr")
3624 .map_err(|e| e.to_string())?;
3625 self.builder
3626 .build_store(sum_ptr, i64_type.const_int(0, false))
3627 .map_err(|e| e.to_string())?;
3628 self.builder
3629 .build_store(idx_ptr, i64_type.const_int(0, false))
3630 .map_err(|e| e.to_string())?;
3631
3632 self.builder
3634 .build_unconditional_branch(loop_header)
3635 .map_err(|e| e.to_string())?;
3636
3637 self.builder.position_at_end(loop_header);
3639 let idx = self
3640 .builder
3641 .build_load(i64_type, idx_ptr, "idx")
3642 .map_err(|e| e.to_string())?
3643 .into_int_value();
3644 let len_val = i64_type.const_int(len as u64, false);
3645 let cond = self
3646 .builder
3647 .build_int_compare(IntPredicate::ULT, idx, len_val, "cmp")
3648 .map_err(|e| e.to_string())?;
3649 self.builder
3650 .build_conditional_branch(cond, loop_body, loop_exit)
3651 .map_err(|e| e.to_string())?;
3652
3653 self.builder.position_at_end(loop_body);
3655 let elem_ptr = unsafe {
3656 self.builder.build_gep(
3657 array_type,
3658 array_ptr,
3659 &[i64_type.const_int(0, false), idx],
3660 "elem_ptr",
3661 )
3662 }
3663 .map_err(|e| e.to_string())?;
3664 let elem_val = self
3665 .builder
3666 .build_load(i64_type, elem_ptr, "elem")
3667 .map_err(|e| e.to_string())?
3668 .into_int_value();
3669 let sum = self
3670 .builder
3671 .build_load(i64_type, sum_ptr, "sum")
3672 .map_err(|e| e.to_string())?
3673 .into_int_value();
3674 let new_sum = self
3675 .builder
3676 .build_int_add(sum, elem_val, "new_sum")
3677 .map_err(|e| e.to_string())?;
3678 self.builder
3679 .build_store(sum_ptr, new_sum)
3680 .map_err(|e| e.to_string())?;
3681 let new_idx = self
3682 .builder
3683 .build_int_add(idx, i64_type.const_int(1, false), "new_idx")
3684 .map_err(|e| e.to_string())?;
3685 self.builder
3686 .build_store(idx_ptr, new_idx)
3687 .map_err(|e| e.to_string())?;
3688 self.builder
3689 .build_unconditional_branch(loop_header)
3690 .map_err(|e| e.to_string())?;
3691
3692 self.builder.position_at_end(loop_exit);
3694 let final_sum = self
3695 .builder
3696 .build_load(i64_type, sum_ptr, "final_sum")
3697 .map_err(|e| e.to_string())?
3698 .into_int_value();
3699
3700 Ok(final_sum)
3701 }
3702
3703 fn compile_array_product(
3705 &mut self,
3706 fn_value: FunctionValue<'ctx>,
3707 scope: &mut CompileScope<'ctx>,
3708 elements: &[Expr],
3709 ) -> Result<IntValue<'ctx>, String> {
3710 let len = elements.len();
3711 if len == 0 {
3712 return Ok(self.context.i64_type().const_int(1, false)); }
3714
3715 let mut product = self.compile_expr(fn_value, scope, &elements[0])?;
3717 for elem in &elements[1..] {
3718 let val = self.compile_expr(fn_value, scope, elem)?;
3719 product = self
3720 .builder
3721 .build_int_mul(product, val, "prod")
3722 .map_err(|e| e.to_string())?;
3723 }
3724 Ok(product)
3725 }
3726
3727 fn compile_array_transform(
3730 &mut self,
3731 fn_value: FunctionValue<'ctx>,
3732 scope: &mut CompileScope<'ctx>,
3733 elements: &[Expr],
3734 closure: &Expr,
3735 ) -> Result<IntValue<'ctx>, String> {
3736 let len = elements.len();
3737 if len == 0 {
3738 return Ok(self.context.i64_type().const_int(0, false));
3739 }
3740
3741 let i64_type = self.context.i64_type();
3742 let array_type = i64_type.array_type(len as u32);
3743
3744 let result_ptr = self
3746 .builder
3747 .build_alloca(array_type, "transform_result")
3748 .map_err(|e| e.to_string())?;
3749
3750 let (param_name, body) = if let Expr::Closure { params, body, .. } = closure {
3752 let name = if let Some(p) = params.first() {
3753 if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
3754 ident.name.clone()
3755 } else {
3756 "x".to_string()
3757 }
3758 } else {
3759 "x".to_string()
3760 };
3761 (name, body.as_ref())
3762 } else {
3763 return Err("Transform requires a closure".to_string());
3764 };
3765
3766 for (i, elem) in elements.iter().enumerate() {
3768 let elem_val = self.compile_expr(fn_value, scope, elem)?;
3770
3771 let param_ptr = self
3773 .builder
3774 .build_alloca(i64_type, ¶m_name)
3775 .map_err(|e| e.to_string())?;
3776 self.builder
3777 .build_store(param_ptr, elem_val)
3778 .map_err(|e| e.to_string())?;
3779
3780 let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
3782
3783 let result = self.compile_expr(fn_value, scope, body)?;
3785
3786 if let Some(old) = old_val {
3788 scope.vars.insert(param_name.to_string(), old);
3789 } else {
3790 scope.vars.remove(¶m_name);
3791 }
3792
3793 let indices = [
3795 i64_type.const_int(0, false),
3796 i64_type.const_int(i as u64, false),
3797 ];
3798 let out_ptr = unsafe {
3799 self.builder
3800 .build_gep(array_type, result_ptr, &indices, "out_elem")
3801 }
3802 .map_err(|e| e.to_string())?;
3803 self.builder
3804 .build_store(out_ptr, result)
3805 .map_err(|e| e.to_string())?;
3806 }
3807
3808 self.builder
3810 .build_ptr_to_int(result_ptr, i64_type, "arr_ptr")
3811 .map_err(|e| e.to_string())
3812 }
3813
3814 fn compile_array_transform_then_sum(
3817 &mut self,
3818 fn_value: FunctionValue<'ctx>,
3819 scope: &mut CompileScope<'ctx>,
3820 elements: &[Expr],
3821 closure: &Expr,
3822 ) -> Result<IntValue<'ctx>, String> {
3823 let len = elements.len();
3824 if len == 0 {
3825 return Ok(self.context.i64_type().const_int(0, false));
3826 }
3827
3828 let i64_type = self.context.i64_type();
3829
3830 let (param_name, body) = if let Expr::Closure { params, body, .. } = closure {
3832 let name = if let Some(p) = params.first() {
3833 if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
3834 ident.name.clone()
3835 } else {
3836 "x".to_string()
3837 }
3838 } else {
3839 "x".to_string()
3840 };
3841 (name, body.as_ref())
3842 } else {
3843 return Err("Transform requires a closure".to_string());
3844 };
3845
3846 let mut sum = i64_type.const_int(0, false);
3848
3849 for elem in elements.iter() {
3850 let elem_val = self.compile_expr(fn_value, scope, elem)?;
3852
3853 let param_ptr = self
3855 .builder
3856 .build_alloca(i64_type, ¶m_name)
3857 .map_err(|e| e.to_string())?;
3858 self.builder
3859 .build_store(param_ptr, elem_val)
3860 .map_err(|e| e.to_string())?;
3861
3862 let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
3863
3864 let transformed = self.compile_expr(fn_value, scope, body)?;
3866
3867 if let Some(old) = old_val {
3869 scope.vars.insert(param_name.to_string(), old);
3870 } else {
3871 scope.vars.remove(¶m_name);
3872 }
3873
3874 sum = self
3876 .builder
3877 .build_int_add(sum, transformed, "sum")
3878 .map_err(|e| e.to_string())?;
3879 }
3880
3881 Ok(sum)
3882 }
3883
3884 fn compile_array_transform_then_product(
3886 &mut self,
3887 fn_value: FunctionValue<'ctx>,
3888 scope: &mut CompileScope<'ctx>,
3889 elements: &[Expr],
3890 closure: &Expr,
3891 ) -> Result<IntValue<'ctx>, String> {
3892 let len = elements.len();
3893 if len == 0 {
3894 return Ok(self.context.i64_type().const_int(1, false));
3895 }
3896
3897 let i64_type = self.context.i64_type();
3898
3899 let (param_name, body) = if let Expr::Closure { params, body, .. } = closure {
3901 let name = if let Some(p) = params.first() {
3902 if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
3903 ident.name.clone()
3904 } else {
3905 "x".to_string()
3906 }
3907 } else {
3908 "x".to_string()
3909 };
3910 (name, body.as_ref())
3911 } else {
3912 return Err("Transform requires a closure".to_string());
3913 };
3914
3915 let mut product = i64_type.const_int(1, false);
3917
3918 for elem in elements.iter() {
3919 let elem_val = self.compile_expr(fn_value, scope, elem)?;
3920
3921 let param_ptr = self
3922 .builder
3923 .build_alloca(i64_type, ¶m_name)
3924 .map_err(|e| e.to_string())?;
3925 self.builder
3926 .build_store(param_ptr, elem_val)
3927 .map_err(|e| e.to_string())?;
3928
3929 let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
3930
3931 let transformed = self.compile_expr(fn_value, scope, body)?;
3932
3933 if let Some(old) = old_val {
3934 scope.vars.insert(param_name.to_string(), old);
3935 } else {
3936 scope.vars.remove(¶m_name);
3937 }
3938
3939 product = self
3940 .builder
3941 .build_int_mul(product, transformed, "prod")
3942 .map_err(|e| e.to_string())?;
3943 }
3944
3945 Ok(product)
3946 }
3947
3948 fn compile_array_filter(
3953 &mut self,
3954 fn_value: FunctionValue<'ctx>,
3955 scope: &mut CompileScope<'ctx>,
3956 elements: &[Expr],
3957 predicate: &Expr,
3958 ) -> Result<IntValue<'ctx>, String> {
3959 let len = elements.len();
3960 if len == 0 {
3961 return Ok(self.context.i64_type().const_int(0, false));
3962 }
3963
3964 let i64_type = self.context.i64_type();
3965 let array_type = i64_type.array_type(len as u32);
3966
3967 let out_ptr = self
3969 .builder
3970 .build_alloca(array_type, "filter_result")
3971 .map_err(|e| e.to_string())?;
3972
3973 let (param_name, body) = if let Expr::Closure { params, body, .. } = predicate {
3975 let name = if let Some(p) = params.first() {
3976 if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
3977 ident.name.clone()
3978 } else {
3979 "x".to_string()
3980 }
3981 } else {
3982 "x".to_string()
3983 };
3984 (name, body.as_ref())
3985 } else {
3986 return Err("Filter requires a closure predicate".to_string());
3987 };
3988
3989 let mut out_idx = 0u64;
3991 let mut count = i64_type.const_int(0, false);
3992
3993 for elem in elements.iter() {
3994 let elem_val = self.compile_expr(fn_value, scope, elem)?;
3995
3996 let param_ptr = self
3998 .builder
3999 .build_alloca(i64_type, ¶m_name)
4000 .map_err(|e| e.to_string())?;
4001 self.builder
4002 .build_store(param_ptr, elem_val)
4003 .map_err(|e| e.to_string())?;
4004
4005 let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
4006
4007 let pred_result = self.compile_expr(fn_value, scope, body)?;
4009
4010 if let Some(old) = old_val {
4012 scope.vars.insert(param_name.to_string(), old);
4013 } else {
4014 scope.vars.remove(¶m_name);
4015 }
4016
4017 let zero = i64_type.const_int(0, false);
4019 let is_true = self
4020 .builder
4021 .build_int_compare(IntPredicate::NE, pred_result, zero, "is_passing")
4022 .map_err(|e| e.to_string())?;
4023
4024 let one = i64_type.const_int(1, false);
4026 let inc = self
4027 .builder
4028 .build_select(is_true, one, zero, "inc")
4029 .map_err(|e| e.to_string())?
4030 .into_int_value();
4031 count = self
4032 .builder
4033 .build_int_add(count, inc, "count")
4034 .map_err(|e| e.to_string())?;
4035
4036 let indices = [
4038 i64_type.const_int(0, false),
4039 i64_type.const_int(out_idx, false),
4040 ];
4041 let elem_ptr = unsafe {
4042 self.builder
4043 .build_gep(array_type, out_ptr, &indices, "out_elem")
4044 }
4045 .map_err(|e| e.to_string())?;
4046
4047 let value_to_store = self
4049 .builder
4050 .build_select(is_true, elem_val, zero, "val_or_zero")
4051 .map_err(|e| e.to_string())?
4052 .into_int_value();
4053 self.builder
4054 .build_store(elem_ptr, value_to_store)
4055 .map_err(|e| e.to_string())?;
4056
4057 out_idx += 1;
4058 }
4059
4060 Ok(count)
4062 }
4063
4064 fn compile_array_filter_then_sum(
4067 &mut self,
4068 fn_value: FunctionValue<'ctx>,
4069 scope: &mut CompileScope<'ctx>,
4070 elements: &[Expr],
4071 predicate: &Expr,
4072 ) -> Result<IntValue<'ctx>, String> {
4073 let len = elements.len();
4074 if len == 0 {
4075 return Ok(self.context.i64_type().const_int(0, false));
4076 }
4077
4078 let i64_type = self.context.i64_type();
4079
4080 let (param_name, body) = if let Expr::Closure { params, body, .. } = predicate {
4082 let name = if let Some(p) = params.first() {
4083 if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
4084 ident.name.clone()
4085 } else {
4086 "x".to_string()
4087 }
4088 } else {
4089 "x".to_string()
4090 };
4091 (name, body.as_ref())
4092 } else {
4093 return Err("Filter requires a closure predicate".to_string());
4094 };
4095
4096 let mut sum = i64_type.const_int(0, false);
4097 let zero = i64_type.const_int(0, false);
4098
4099 for elem in elements.iter() {
4100 let elem_val = self.compile_expr(fn_value, scope, elem)?;
4101
4102 let param_ptr = self
4104 .builder
4105 .build_alloca(i64_type, ¶m_name)
4106 .map_err(|e| e.to_string())?;
4107 self.builder
4108 .build_store(param_ptr, elem_val)
4109 .map_err(|e| e.to_string())?;
4110
4111 let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
4112
4113 let pred_result = self.compile_expr(fn_value, scope, body)?;
4115
4116 if let Some(old) = old_val {
4118 scope.vars.insert(param_name.to_string(), old);
4119 } else {
4120 scope.vars.remove(¶m_name);
4121 }
4122
4123 let is_true = self
4125 .builder
4126 .build_int_compare(IntPredicate::NE, pred_result, zero, "is_passing")
4127 .map_err(|e| e.to_string())?;
4128
4129 let add_value = self
4131 .builder
4132 .build_select(is_true, elem_val, zero, "add_if_pass")
4133 .map_err(|e| e.to_string())?
4134 .into_int_value();
4135 sum = self
4136 .builder
4137 .build_int_add(sum, add_value, "sum")
4138 .map_err(|e| e.to_string())?;
4139 }
4140
4141 Ok(sum)
4142 }
4143
4144 fn compile_array_filter_then_product(
4147 &mut self,
4148 fn_value: FunctionValue<'ctx>,
4149 scope: &mut CompileScope<'ctx>,
4150 elements: &[Expr],
4151 predicate: &Expr,
4152 ) -> Result<IntValue<'ctx>, String> {
4153 let len = elements.len();
4154 if len == 0 {
4155 return Ok(self.context.i64_type().const_int(1, false));
4156 }
4157
4158 let i64_type = self.context.i64_type();
4159
4160 let (param_name, body) = if let Expr::Closure { params, body, .. } = predicate {
4162 let name = if let Some(p) = params.first() {
4163 if let ast::Pattern::Ident { name: ident, .. } = &p.pattern {
4164 ident.name.clone()
4165 } else {
4166 "x".to_string()
4167 }
4168 } else {
4169 "x".to_string()
4170 };
4171 (name, body.as_ref())
4172 } else {
4173 return Err("Filter requires a closure predicate".to_string());
4174 };
4175
4176 let mut product = i64_type.const_int(1, false);
4177 let one = i64_type.const_int(1, false);
4178 let zero = i64_type.const_int(0, false);
4179
4180 for elem in elements.iter() {
4181 let elem_val = self.compile_expr(fn_value, scope, elem)?;
4182
4183 let param_ptr = self
4185 .builder
4186 .build_alloca(i64_type, ¶m_name)
4187 .map_err(|e| e.to_string())?;
4188 self.builder
4189 .build_store(param_ptr, elem_val)
4190 .map_err(|e| e.to_string())?;
4191
4192 let old_val = scope.vars.insert(param_name.to_string(), param_ptr);
4193
4194 let pred_result = self.compile_expr(fn_value, scope, body)?;
4196
4197 if let Some(old) = old_val {
4199 scope.vars.insert(param_name.to_string(), old);
4200 } else {
4201 scope.vars.remove(¶m_name);
4202 }
4203
4204 let is_true = self
4206 .builder
4207 .build_int_compare(IntPredicate::NE, pred_result, zero, "is_passing")
4208 .map_err(|e| e.to_string())?;
4209
4210 let mul_value = self
4212 .builder
4213 .build_select(is_true, elem_val, one, "mul_if_pass")
4214 .map_err(|e| e.to_string())?
4215 .into_int_value();
4216 product = self
4217 .builder
4218 .build_int_mul(product, mul_value, "prod")
4219 .map_err(|e| e.to_string())?;
4220 }
4221
4222 Ok(product)
4223 }
4224
4225 fn compile_array_first(
4231 &mut self,
4232 fn_value: FunctionValue<'ctx>,
4233 scope: &mut CompileScope<'ctx>,
4234 elements: &[Expr],
4235 ) -> Result<IntValue<'ctx>, String> {
4236 if elements.is_empty() {
4237 return Ok(self.context.i64_type().const_int(0, false));
4239 }
4240 self.compile_expr(fn_value, scope, &elements[0])
4241 }
4242
4243 fn compile_array_last(
4245 &mut self,
4246 fn_value: FunctionValue<'ctx>,
4247 scope: &mut CompileScope<'ctx>,
4248 elements: &[Expr],
4249 ) -> Result<IntValue<'ctx>, String> {
4250 if elements.is_empty() {
4251 return Ok(self.context.i64_type().const_int(0, false));
4252 }
4253 self.compile_expr(fn_value, scope, &elements[elements.len() - 1])
4254 }
4255
4256 fn compile_array_nth(
4258 &mut self,
4259 fn_value: FunctionValue<'ctx>,
4260 scope: &mut CompileScope<'ctx>,
4261 elements: &[Expr],
4262 index_expr: &Expr,
4263 ) -> Result<IntValue<'ctx>, String> {
4264 if elements.is_empty() {
4265 return Ok(self.context.i64_type().const_int(0, false));
4266 }
4267
4268 if let Expr::Literal(ast::Literal::Int { value, .. }) = index_expr {
4270 if let Ok(n) = value.parse::<usize>() {
4271 if n < elements.len() {
4272 return self.compile_expr(fn_value, scope, &elements[n]);
4273 } else {
4274 return Ok(self.context.i64_type().const_int(0, false));
4276 }
4277 }
4278 }
4279
4280 let i64_type = self.context.i64_type();
4282 let len = elements.len();
4283 let array_type = i64_type.array_type(len as u32);
4284 let array_ptr = self
4285 .builder
4286 .build_alloca(array_type, "nth_array")
4287 .map_err(|e| e.to_string())?;
4288
4289 for (i, elem) in elements.iter().enumerate() {
4291 let value = self.compile_expr(fn_value, scope, elem)?;
4292 let indices = [
4293 i64_type.const_int(0, false),
4294 i64_type.const_int(i as u64, false),
4295 ];
4296 let elem_ptr = unsafe {
4297 self.builder
4298 .build_gep(array_type, array_ptr, &indices, "elem_ptr")
4299 }
4300 .map_err(|e| e.to_string())?;
4301 self.builder
4302 .build_store(elem_ptr, value)
4303 .map_err(|e| e.to_string())?;
4304 }
4305
4306 let idx = self.compile_expr(fn_value, scope, index_expr)?;
4308
4309 let len_val = i64_type.const_int(len as u64 - 1, false);
4311 let zero = i64_type.const_int(0, false);
4312 let clamped_high = self
4313 .builder
4314 .build_select(
4315 self.builder
4316 .build_int_compare(IntPredicate::UGT, idx, len_val, "gt_len")
4317 .map_err(|e| e.to_string())?,
4318 len_val,
4319 idx,
4320 "clamp_high",
4321 )
4322 .map_err(|e| e.to_string())?
4323 .into_int_value();
4324 let clamped = self
4325 .builder
4326 .build_select(
4327 self.builder
4328 .build_int_compare(IntPredicate::SLT, clamped_high, zero, "lt_zero")
4329 .map_err(|e| e.to_string())?,
4330 zero,
4331 clamped_high,
4332 "clamp_low",
4333 )
4334 .map_err(|e| e.to_string())?
4335 .into_int_value();
4336
4337 let indices = [i64_type.const_int(0, false), clamped];
4339 let elem_ptr = unsafe {
4340 self.builder
4341 .build_gep(array_type, array_ptr, &indices, "nth_ptr")
4342 }
4343 .map_err(|e| e.to_string())?;
4344 let value = self
4345 .builder
4346 .build_load(i64_type, elem_ptr, "nth_val")
4347 .map_err(|e| e.to_string())?;
4348
4349 Ok(value.into_int_value())
4350 }
4351
4352 fn compile_array_middle(
4354 &mut self,
4355 fn_value: FunctionValue<'ctx>,
4356 scope: &mut CompileScope<'ctx>,
4357 elements: &[Expr],
4358 ) -> Result<IntValue<'ctx>, String> {
4359 if elements.is_empty() {
4360 return Ok(self.context.i64_type().const_int(0, false));
4361 }
4362 let mid_idx = elements.len() / 2;
4363 self.compile_expr(fn_value, scope, &elements[mid_idx])
4364 }
4365
4366 fn compile_array_min(
4372 &mut self,
4373 fn_value: FunctionValue<'ctx>,
4374 scope: &mut CompileScope<'ctx>,
4375 elements: &[Expr],
4376 ) -> Result<IntValue<'ctx>, String> {
4377 if elements.is_empty() {
4378 return Ok(self.context.i64_type().const_int(i64::MAX as u64, true));
4379 }
4380
4381 let mut min_val = self.compile_expr(fn_value, scope, &elements[0])?;
4382
4383 for elem in &elements[1..] {
4384 let val = self.compile_expr(fn_value, scope, elem)?;
4385 let is_less = self
4386 .builder
4387 .build_int_compare(IntPredicate::SLT, val, min_val, "is_less")
4388 .map_err(|e| e.to_string())?;
4389 min_val = self
4390 .builder
4391 .build_select(is_less, val, min_val, "min_sel")
4392 .map_err(|e| e.to_string())?
4393 .into_int_value();
4394 }
4395
4396 Ok(min_val)
4397 }
4398
4399 fn compile_array_max(
4401 &mut self,
4402 fn_value: FunctionValue<'ctx>,
4403 scope: &mut CompileScope<'ctx>,
4404 elements: &[Expr],
4405 ) -> Result<IntValue<'ctx>, String> {
4406 if elements.is_empty() {
4407 return Ok(self.context.i64_type().const_int(i64::MIN as u64, true));
4408 }
4409
4410 let mut max_val = self.compile_expr(fn_value, scope, &elements[0])?;
4411
4412 for elem in &elements[1..] {
4413 let val = self.compile_expr(fn_value, scope, elem)?;
4414 let is_greater = self
4415 .builder
4416 .build_int_compare(IntPredicate::SGT, val, max_val, "is_greater")
4417 .map_err(|e| e.to_string())?;
4418 max_val = self
4419 .builder
4420 .build_select(is_greater, val, max_val, "max_sel")
4421 .map_err(|e| e.to_string())?
4422 .into_int_value();
4423 }
4424
4425 Ok(max_val)
4426 }
4427
4428 fn compile_array_all(
4430 &mut self,
4431 fn_value: FunctionValue<'ctx>,
4432 scope: &mut CompileScope<'ctx>,
4433 elements: &[Expr],
4434 ) -> Result<IntValue<'ctx>, String> {
4435 if elements.is_empty() {
4436 return Ok(self.context.i64_type().const_int(1, false));
4438 }
4439
4440 let zero = self.context.i64_type().const_int(0, false);
4441 let mut result = self.context.i64_type().const_int(1, false);
4442
4443 for elem in elements {
4444 let val = self.compile_expr(fn_value, scope, elem)?;
4445 let is_true = self
4446 .builder
4447 .build_int_compare(IntPredicate::NE, val, zero, "is_true")
4448 .map_err(|e| e.to_string())?;
4449 let as_int = self
4450 .builder
4451 .build_int_z_extend(is_true, self.context.i64_type(), "as_int")
4452 .map_err(|e| e.to_string())?;
4453 result = self
4454 .builder
4455 .build_and(result, as_int, "all_and")
4456 .map_err(|e| e.to_string())?;
4457 }
4458
4459 Ok(result)
4460 }
4461
4462 fn compile_array_any(
4464 &mut self,
4465 fn_value: FunctionValue<'ctx>,
4466 scope: &mut CompileScope<'ctx>,
4467 elements: &[Expr],
4468 ) -> Result<IntValue<'ctx>, String> {
4469 if elements.is_empty() {
4470 return Ok(self.context.i64_type().const_int(0, false));
4472 }
4473
4474 let zero = self.context.i64_type().const_int(0, false);
4475 let mut result = self.context.i64_type().const_int(0, false);
4476
4477 for elem in elements {
4478 let val = self.compile_expr(fn_value, scope, elem)?;
4479 let is_true = self
4480 .builder
4481 .build_int_compare(IntPredicate::NE, val, zero, "is_true")
4482 .map_err(|e| e.to_string())?;
4483 let as_int = self
4484 .builder
4485 .build_int_z_extend(is_true, self.context.i64_type(), "as_int")
4486 .map_err(|e| e.to_string())?;
4487 result = self
4488 .builder
4489 .build_or(result, as_int, "any_or")
4490 .map_err(|e| e.to_string())?;
4491 }
4492
4493 Ok(result)
4494 }
4495
4496 fn compile_array_sort(
4499 &mut self,
4500 fn_value: FunctionValue<'ctx>,
4501 scope: &mut CompileScope<'ctx>,
4502 elements: &[Expr],
4503 ) -> Result<IntValue<'ctx>, String> {
4504 self.compile_array_min(fn_value, scope, elements)
4506 }
4507
4508 fn compile_array_choice(
4511 &mut self,
4512 fn_value: FunctionValue<'ctx>,
4513 scope: &mut CompileScope<'ctx>,
4514 elements: &[Expr],
4515 ) -> Result<IntValue<'ctx>, String> {
4516 if elements.is_empty() {
4517 return Ok(self.context.i64_type().const_int(0, false));
4518 }
4519
4520 let len = elements.len();
4521 if len == 1 {
4522 return self.compile_expr(fn_value, scope, &elements[0]);
4523 }
4524
4525 let mut hash = self.compile_expr(fn_value, scope, &elements[0])?;
4527 for elem in &elements[1..] {
4528 let val = self.compile_expr(fn_value, scope, elem)?;
4529 hash = self
4530 .builder
4531 .build_int_add(hash, val, "hash_acc")
4532 .map_err(|e| e.to_string())?;
4533 }
4534
4535 let len_const = self.context.i64_type().const_int(len as u64, false);
4537
4538 let shift_amt = self.context.i64_type().const_int(63, false);
4540 let sign = self
4541 .builder
4542 .build_right_shift(hash, shift_amt, true, "sign")
4543 .map_err(|e| e.to_string())?;
4544 let xored = self
4545 .builder
4546 .build_xor(hash, sign, "xored")
4547 .map_err(|e| e.to_string())?;
4548 let abs_hash = self
4549 .builder
4550 .build_int_sub(xored, sign, "abs")
4551 .map_err(|e| e.to_string())?;
4552
4553 let index = self
4554 .builder
4555 .build_int_unsigned_rem(abs_hash, len_const, "choice_idx")
4556 .map_err(|e| e.to_string())?;
4557
4558 let i64_type = self.context.i64_type();
4560 let array_type = i64_type.array_type(len as u32);
4561 let array_ptr = self
4562 .builder
4563 .build_alloca(array_type, "choice_arr")
4564 .map_err(|e| e.to_string())?;
4565
4566 for (i, elem) in elements.iter().enumerate() {
4568 let val = self.compile_expr(fn_value, scope, elem)?;
4569 let indices = [
4570 i64_type.const_int(0, false),
4571 i64_type.const_int(i as u64, false),
4572 ];
4573 let ptr = unsafe {
4574 self.builder
4575 .build_gep(array_type, array_ptr, &indices, "elem_ptr")
4576 }
4577 .map_err(|e| e.to_string())?;
4578 self.builder
4579 .build_store(ptr, val)
4580 .map_err(|e| e.to_string())?;
4581 }
4582
4583 let result_ptr = unsafe {
4585 self.builder.build_gep(
4586 array_type,
4587 array_ptr,
4588 &[i64_type.const_int(0, false), index],
4589 "choice_ptr",
4590 )
4591 }
4592 .map_err(|e| e.to_string())?;
4593
4594 let result = self
4595 .builder
4596 .build_load(i64_type, result_ptr, "choice_val")
4597 .map_err(|e| e.to_string())?
4598 .into_int_value();
4599
4600 Ok(result)
4601 }
4602
4603 fn compile_array_reduce(
4605 &mut self,
4606 fn_value: FunctionValue<'ctx>,
4607 scope: &mut CompileScope<'ctx>,
4608 elements: &[Expr],
4609 reduce_fn: &Expr,
4610 ) -> Result<IntValue<'ctx>, String> {
4611 if elements.is_empty() {
4612 return Ok(self.context.i64_type().const_int(0, false));
4613 }
4614
4615 let (acc_name, elem_name, body) = if let Expr::Closure { params, body, .. } = reduce_fn
4617 {
4618 if params.len() != 2 {
4619 return Err("Reduce closure must have exactly 2 parameters".to_string());
4620 }
4621 let acc = if let ast::Pattern::Ident { name: ident, .. } = ¶ms[0].pattern {
4623 ident.name.clone()
4624 } else {
4625 "acc".to_string()
4626 };
4627 let elem = if let ast::Pattern::Ident { name: ident, .. } = ¶ms[1].pattern {
4628 ident.name.clone()
4629 } else {
4630 "x".to_string()
4631 };
4632 (acc, elem, body)
4633 } else {
4634 return Err("Reduce requires a closure".to_string());
4635 };
4636
4637 let i64_type = self.context.i64_type();
4638
4639 let acc_ptr = self
4641 .builder
4642 .build_alloca(i64_type, &acc_name)
4643 .map_err(|e| e.to_string())?;
4644 let elem_ptr = self
4645 .builder
4646 .build_alloca(i64_type, &elem_name)
4647 .map_err(|e| e.to_string())?;
4648
4649 let first = self.compile_expr(fn_value, scope, &elements[0])?;
4651 self.builder
4652 .build_store(acc_ptr, first)
4653 .map_err(|e| e.to_string())?;
4654
4655 scope.vars.insert(acc_name.clone(), acc_ptr);
4657 scope.vars.insert(elem_name.clone(), elem_ptr);
4658
4659 for elem in &elements[1..] {
4661 let val = self.compile_expr(fn_value, scope, elem)?;
4662 self.builder
4663 .build_store(elem_ptr, val)
4664 .map_err(|e| e.to_string())?;
4665
4666 let new_acc = self.compile_expr(fn_value, scope, body)?;
4668 self.builder
4669 .build_store(acc_ptr, new_acc)
4670 .map_err(|e| e.to_string())?;
4671 }
4672
4673 let result = self
4675 .builder
4676 .build_load(i64_type, acc_ptr, "reduce_result")
4677 .map_err(|e| e.to_string())?
4678 .into_int_value();
4679
4680 Ok(result)
4681 }
4682
4683 fn compile_array_literal(
4686 &mut self,
4687 fn_value: FunctionValue<'ctx>,
4688 scope: &mut CompileScope<'ctx>,
4689 elements: &[Expr],
4690 ) -> Result<IntValue<'ctx>, String> {
4691 let len = elements.len();
4692 if len == 0 {
4693 return Ok(self.context.i64_type().const_int(0, false));
4695 }
4696
4697 let i64_type = self.context.i64_type();
4698 let array_type = i64_type.array_type(len as u32);
4699
4700 let array_ptr = self
4702 .builder
4703 .build_alloca(array_type, "array")
4704 .map_err(|e| e.to_string())?;
4705
4706 for (i, elem) in elements.iter().enumerate() {
4708 let value = self.compile_expr(fn_value, scope, elem)?;
4709
4710 let indices = [
4712 self.context.i64_type().const_int(0, false),
4713 self.context.i64_type().const_int(i as u64, false),
4714 ];
4715 let elem_ptr = unsafe {
4716 self.builder
4717 .build_gep(array_type, array_ptr, &indices, "elem_ptr")
4718 }
4719 .map_err(|e| e.to_string())?;
4720
4721 self.builder
4723 .build_store(elem_ptr, value)
4724 .map_err(|e| e.to_string())?;
4725 }
4726
4727 let ptr_as_int = self
4730 .builder
4731 .build_ptr_to_int(array_ptr, i64_type, "arr_ptr")
4732 .map_err(|e| e.to_string())?;
4733
4734 Ok(ptr_as_int)
4739 }
4740
4741 fn compile_index(
4744 &mut self,
4745 fn_value: FunctionValue<'ctx>,
4746 scope: &mut CompileScope<'ctx>,
4747 expr: &Expr,
4748 index: &Expr,
4749 ) -> Result<IntValue<'ctx>, String> {
4750 let base_ptr_int = self.compile_expr(fn_value, scope, expr)?;
4751 let idx = self.compile_expr(fn_value, scope, index)?;
4752
4753 let i64_type = self.context.i64_type();
4754
4755 let base_ptr = self
4757 .builder
4758 .build_int_to_ptr(
4759 base_ptr_int,
4760 i64_type.ptr_type(Default::default()),
4761 "arr_ptr",
4762 )
4763 .map_err(|e| e.to_string())?;
4764
4765 let elem_ptr = unsafe {
4767 self.builder
4768 .build_gep(i64_type, base_ptr, &[idx], "elem_ptr")
4769 }
4770 .map_err(|e| e.to_string())?;
4771
4772 let value = self
4774 .builder
4775 .build_load(i64_type, elem_ptr, "elem")
4776 .map_err(|e| e.to_string())?;
4777
4778 Ok(value.into_int_value())
4779 }
4780
4781 fn compile_binary_op(
4783 &mut self,
4784 op: BinOp,
4785 lhs: IntValue<'ctx>,
4786 rhs: IntValue<'ctx>,
4787 ) -> Result<IntValue<'ctx>, String> {
4788 match op {
4789 BinOp::Add => self
4790 .builder
4791 .build_int_add(lhs, rhs, "add")
4792 .map_err(|e| e.to_string()),
4793 BinOp::Sub => self
4794 .builder
4795 .build_int_sub(lhs, rhs, "sub")
4796 .map_err(|e| e.to_string()),
4797 BinOp::Mul => self
4798 .builder
4799 .build_int_mul(lhs, rhs, "mul")
4800 .map_err(|e| e.to_string()),
4801 BinOp::Div => self
4802 .builder
4803 .build_int_signed_div(lhs, rhs, "div")
4804 .map_err(|e| e.to_string()),
4805 BinOp::Rem => self
4806 .builder
4807 .build_int_signed_rem(lhs, rhs, "rem")
4808 .map_err(|e| e.to_string()),
4809 BinOp::BitAnd => self
4810 .builder
4811 .build_and(lhs, rhs, "and")
4812 .map_err(|e| e.to_string()),
4813 BinOp::BitOr => self
4814 .builder
4815 .build_or(lhs, rhs, "or")
4816 .map_err(|e| e.to_string()),
4817 BinOp::BitXor => self
4818 .builder
4819 .build_xor(lhs, rhs, "xor")
4820 .map_err(|e| e.to_string()),
4821 BinOp::Shl => self
4822 .builder
4823 .build_left_shift(lhs, rhs, "shl")
4824 .map_err(|e| e.to_string()),
4825 BinOp::Shr => self
4826 .builder
4827 .build_right_shift(lhs, rhs, true, "shr")
4828 .map_err(|e| e.to_string()),
4829 BinOp::Eq => {
4830 let cmp = self
4831 .builder
4832 .build_int_compare(IntPredicate::EQ, lhs, rhs, "eq")
4833 .map_err(|e| e.to_string())?;
4834 self.builder
4835 .build_int_z_extend(cmp, self.context.i64_type(), "eq_ext")
4836 .map_err(|e| e.to_string())
4837 }
4838 BinOp::Ne => {
4839 let cmp = self
4840 .builder
4841 .build_int_compare(IntPredicate::NE, lhs, rhs, "ne")
4842 .map_err(|e| e.to_string())?;
4843 self.builder
4844 .build_int_z_extend(cmp, self.context.i64_type(), "ne_ext")
4845 .map_err(|e| e.to_string())
4846 }
4847 BinOp::Lt => {
4848 let cmp = self
4849 .builder
4850 .build_int_compare(IntPredicate::SLT, lhs, rhs, "lt")
4851 .map_err(|e| e.to_string())?;
4852 self.builder
4853 .build_int_z_extend(cmp, self.context.i64_type(), "lt_ext")
4854 .map_err(|e| e.to_string())
4855 }
4856 BinOp::Le => {
4857 let cmp = self
4858 .builder
4859 .build_int_compare(IntPredicate::SLE, lhs, rhs, "le")
4860 .map_err(|e| e.to_string())?;
4861 self.builder
4862 .build_int_z_extend(cmp, self.context.i64_type(), "le_ext")
4863 .map_err(|e| e.to_string())
4864 }
4865 BinOp::Gt => {
4866 let cmp = self
4867 .builder
4868 .build_int_compare(IntPredicate::SGT, lhs, rhs, "gt")
4869 .map_err(|e| e.to_string())?;
4870 self.builder
4871 .build_int_z_extend(cmp, self.context.i64_type(), "gt_ext")
4872 .map_err(|e| e.to_string())
4873 }
4874 BinOp::Ge => {
4875 let cmp = self
4876 .builder
4877 .build_int_compare(IntPredicate::SGE, lhs, rhs, "ge")
4878 .map_err(|e| e.to_string())?;
4879 self.builder
4880 .build_int_z_extend(cmp, self.context.i64_type(), "ge_ext")
4881 .map_err(|e| e.to_string())
4882 }
4883 BinOp::And => {
4884 let zero = self.context.i64_type().const_int(0, false);
4886 let lhs_bool = self
4887 .builder
4888 .build_int_compare(IntPredicate::NE, lhs, zero, "lhs_bool")
4889 .map_err(|e| e.to_string())?;
4890 let rhs_bool = self
4891 .builder
4892 .build_int_compare(IntPredicate::NE, rhs, zero, "rhs_bool")
4893 .map_err(|e| e.to_string())?;
4894 let and = self
4895 .builder
4896 .build_and(lhs_bool, rhs_bool, "and")
4897 .map_err(|e| e.to_string())?;
4898 self.builder
4899 .build_int_z_extend(and, self.context.i64_type(), "and_ext")
4900 .map_err(|e| e.to_string())
4901 }
4902 BinOp::Or => {
4903 let zero = self.context.i64_type().const_int(0, false);
4905 let lhs_bool = self
4906 .builder
4907 .build_int_compare(IntPredicate::NE, lhs, zero, "lhs_bool")
4908 .map_err(|e| e.to_string())?;
4909 let rhs_bool = self
4910 .builder
4911 .build_int_compare(IntPredicate::NE, rhs, zero, "rhs_bool")
4912 .map_err(|e| e.to_string())?;
4913 let or = self
4914 .builder
4915 .build_or(lhs_bool, rhs_bool, "or")
4916 .map_err(|e| e.to_string())?;
4917 self.builder
4918 .build_int_z_extend(or, self.context.i64_type(), "or_ext")
4919 .map_err(|e| e.to_string())
4920 }
4921 _ => Ok(self.context.i64_type().const_int(0, false)),
4922 }
4923 }
4924
4925 fn compile_unary_op(
4927 &mut self,
4928 op: UnaryOp,
4929 val: IntValue<'ctx>,
4930 ) -> Result<IntValue<'ctx>, String> {
4931 match op {
4932 UnaryOp::Neg => self
4933 .builder
4934 .build_int_neg(val, "neg")
4935 .map_err(|e| e.to_string()),
4936 UnaryOp::Not => {
4937 let zero = self.context.i64_type().const_int(0, false);
4939 let is_zero = self
4940 .builder
4941 .build_int_compare(IntPredicate::EQ, val, zero, "is_zero")
4942 .map_err(|e| e.to_string())?;
4943 self.builder
4944 .build_int_z_extend(is_zero, self.context.i64_type(), "not")
4945 .map_err(|e| e.to_string())
4946 }
4947 UnaryOp::Deref => {
4948 let ptr = self
4950 .builder
4951 .build_int_to_ptr(
4952 val,
4953 self.context.ptr_type(AddressSpace::default()),
4954 "deref_ptr",
4955 )
4956 .map_err(|e| e.to_string())?;
4957 let loaded = self
4958 .builder
4959 .build_load(self.context.i64_type(), ptr, "deref_val")
4960 .map_err(|e| e.to_string())?;
4961 Ok(loaded.into_int_value())
4962 }
4963 UnaryOp::Ref | UnaryOp::RefMut => {
4964 Ok(val)
4967 }
4968 _ => Ok(val),
4969 }
4970 }
4971
4972 fn compile_if(
4974 &mut self,
4975 fn_value: FunctionValue<'ctx>,
4976 scope: &mut CompileScope<'ctx>,
4977 condition: &Expr,
4978 then_branch: &ast::Block,
4979 else_branch: Option<&Expr>,
4980 ) -> Result<IntValue<'ctx>, String> {
4981 let (cond_val, let_binding) = if let Expr::Let { pattern, value } = condition {
4983 let val = self.compile_expr(fn_value, scope, value)?;
4985 let binding_name = match pattern {
4988 ast::Pattern::Ident { name, .. } => Some(name.name.clone()),
4989 ast::Pattern::TupleStruct { path, fields, .. } => {
4990 if !fields.is_empty() {
4993 if let ast::Pattern::Ident { name, .. } = &fields[0] {
4994 Some(name.name.clone())
4995 } else {
4996 None
4997 }
4998 } else {
4999 None
5000 }
5001 }
5002 _ => None,
5003 };
5004 (val, binding_name)
5005 } else {
5006 (self.compile_expr(fn_value, scope, condition)?, None)
5007 };
5008
5009 let zero = self.context.i64_type().const_int(0, false);
5011 let cond_bool = self
5012 .builder
5013 .build_int_compare(IntPredicate::NE, cond_val, zero, "cond")
5014 .map_err(|e| e.to_string())?;
5015
5016 let then_bb = self.context.append_basic_block(fn_value, "then");
5018 let else_bb = self.context.append_basic_block(fn_value, "else");
5019 let merge_bb = self.context.append_basic_block(fn_value, "merge");
5020
5021 self.builder
5022 .build_conditional_branch(cond_bool, then_bb, else_bb)
5023 .map_err(|e| e.to_string())?;
5024
5025 self.builder.position_at_end(then_bb);
5027
5028 if let Some(name) = let_binding {
5030 let alloca = self
5031 .builder
5032 .build_alloca(self.context.i64_type(), &name)
5033 .map_err(|e| e.to_string())?;
5034 self.builder
5035 .build_store(alloca, cond_val)
5036 .map_err(|e| e.to_string())?;
5037 scope.vars.insert(name, alloca);
5038 }
5039
5040 let then_val = self
5041 .compile_block(fn_value, scope, then_branch)?
5042 .unwrap_or_else(|| self.context.i64_type().const_int(0, false));
5043 let then_terminated = self
5044 .builder
5045 .get_insert_block()
5046 .unwrap()
5047 .get_terminator()
5048 .is_some();
5049 if !then_terminated {
5050 self.builder
5051 .build_unconditional_branch(merge_bb)
5052 .map_err(|e| e.to_string())?;
5053 }
5054 let then_bb_end = self.builder.get_insert_block().unwrap();
5055
5056 self.builder.position_at_end(else_bb);
5058 let else_val = if let Some(else_expr) = else_branch {
5059 self.compile_expr(fn_value, scope, else_expr)?
5060 } else {
5061 self.context.i64_type().const_int(0, false)
5062 };
5063 let else_terminated = self
5064 .builder
5065 .get_insert_block()
5066 .unwrap()
5067 .get_terminator()
5068 .is_some();
5069 if !else_terminated {
5070 self.builder
5071 .build_unconditional_branch(merge_bb)
5072 .map_err(|e| e.to_string())?;
5073 }
5074 let else_bb_end = self.builder.get_insert_block().unwrap();
5075
5076 self.builder.position_at_end(merge_bb);
5078
5079 if then_terminated && else_terminated {
5081 return Ok(self.context.i64_type().const_int(0, false));
5083 }
5084
5085 let phi = self
5086 .builder
5087 .build_phi(self.context.i64_type(), "if_result")
5088 .map_err(|e| e.to_string())?;
5089
5090 if !then_terminated {
5091 phi.add_incoming(&[(&then_val, then_bb_end)]);
5092 }
5093 if !else_terminated {
5094 phi.add_incoming(&[(&else_val, else_bb_end)]);
5095 }
5096
5097 Ok(phi.as_basic_value().into_int_value())
5098 }
5099
5100 fn compile_while(
5102 &mut self,
5103 fn_value: FunctionValue<'ctx>,
5104 scope: &mut CompileScope<'ctx>,
5105 condition: &Expr,
5106 body: &ast::Block,
5107 ) -> Result<IntValue<'ctx>, String> {
5108 let cond_bb = self.context.append_basic_block(fn_value, "while_cond");
5110 let body_bb = self.context.append_basic_block(fn_value, "while_body");
5111 let after_bb = self.context.append_basic_block(fn_value, "while_after");
5112
5113 self.builder
5115 .build_unconditional_branch(cond_bb)
5116 .map_err(|e| e.to_string())?;
5117
5118 self.builder.position_at_end(cond_bb);
5120 let cond_val = self.compile_expr(fn_value, scope, condition)?;
5121 let zero = self.context.i64_type().const_int(0, false);
5122 let cond_bool = self
5123 .builder
5124 .build_int_compare(IntPredicate::NE, cond_val, zero, "cond")
5125 .map_err(|e| e.to_string())?;
5126 self.builder
5127 .build_conditional_branch(cond_bool, body_bb, after_bb)
5128 .map_err(|e| e.to_string())?;
5129
5130 self.builder.position_at_end(body_bb);
5132 self.compile_block(fn_value, scope, body)?;
5133 if self
5135 .builder
5136 .get_insert_block()
5137 .unwrap()
5138 .get_terminator()
5139 .is_none()
5140 {
5141 self.builder
5142 .build_unconditional_branch(cond_bb)
5143 .map_err(|e| e.to_string())?;
5144 }
5145
5146 self.builder.position_at_end(after_bb);
5148 Ok(self.context.i64_type().const_int(0, false))
5149 }
5150
5151 fn compile_for_loop(
5153 &mut self,
5154 fn_value: FunctionValue<'ctx>,
5155 scope: &mut CompileScope<'ctx>,
5156 pattern: &ast::Pattern,
5157 iter: &Expr,
5158 body: &ast::Block,
5159 ) -> Result<IntValue<'ctx>, String> {
5160 let var_names: Vec<String> = match pattern {
5162 ast::Pattern::Ident { name, .. } => vec![name.name.clone()],
5163 ast::Pattern::Tuple(elements) => {
5164 elements
5166 .iter()
5167 .filter_map(|elem| {
5168 if let ast::Pattern::Ident { name, .. } = elem {
5169 Some(name.name.clone())
5170 } else {
5171 None
5172 }
5173 })
5174 .collect()
5175 }
5176 ast::Pattern::TupleStruct { path, fields, .. } => {
5177 fields
5179 .iter()
5180 .filter_map(|f| {
5181 if let ast::Pattern::Ident { name, .. } = f {
5182 Some(name.name.clone())
5183 } else {
5184 None
5185 }
5186 })
5187 .collect()
5188 }
5189 _ => vec!["_item".to_string()], };
5191
5192 let var_name = var_names
5193 .first()
5194 .cloned()
5195 .unwrap_or_else(|| "_item".to_string());
5196
5197 let iter_val = self.compile_expr(fn_value, scope, iter)?;
5199
5200 let init_bb = self.context.append_basic_block(fn_value, "for_init");
5202 let cond_bb = self.context.append_basic_block(fn_value, "for_cond");
5203 let body_bb = self.context.append_basic_block(fn_value, "for_body");
5204 let incr_bb = self.context.append_basic_block(fn_value, "for_incr");
5205 let after_bb = self.context.append_basic_block(fn_value, "for_after");
5206
5207 self.builder
5209 .build_unconditional_branch(init_bb)
5210 .map_err(|e| e.to_string())?;
5211
5212 self.builder.position_at_end(init_bb);
5214 let idx_ptr = self
5215 .builder
5216 .build_alloca(self.context.i64_type(), "for_idx")
5217 .map_err(|e| e.to_string())?;
5218 let zero = self.context.i64_type().const_int(0, false);
5219 self.builder
5220 .build_store(idx_ptr, zero)
5221 .map_err(|e| e.to_string())?;
5222
5223 for name in &var_names {
5225 let var_ptr = self
5226 .builder
5227 .build_alloca(self.context.i64_type(), name)
5228 .map_err(|e| e.to_string())?;
5229 scope.vars.insert(name.clone(), var_ptr);
5230 }
5231
5232 let len_val = self.get_array_length(iter_val)?;
5237
5238 self.builder
5239 .build_unconditional_branch(cond_bb)
5240 .map_err(|e| e.to_string())?;
5241
5242 self.builder.position_at_end(cond_bb);
5244 let idx_val = self
5245 .builder
5246 .build_load(self.context.i64_type(), idx_ptr, "idx")
5247 .map_err(|e| e.to_string())?
5248 .into_int_value();
5249 let cond = self
5250 .builder
5251 .build_int_compare(IntPredicate::ULT, idx_val, len_val, "for_cond")
5252 .map_err(|e| e.to_string())?;
5253 self.builder
5254 .build_conditional_branch(cond, body_bb, after_bb)
5255 .map_err(|e| e.to_string())?;
5256
5257 self.builder.position_at_end(body_bb);
5259
5260 let elem_val = self.get_array_element(iter_val, idx_val)?;
5262
5263 if let Some(&first_var_ptr) = scope.vars.get(&var_name) {
5266 self.builder
5267 .build_store(first_var_ptr, elem_val)
5268 .map_err(|e| e.to_string())?;
5269 }
5270
5271 self.compile_block(fn_value, scope, body)?;
5273
5274 if self
5276 .builder
5277 .get_insert_block()
5278 .unwrap()
5279 .get_terminator()
5280 .is_none()
5281 {
5282 self.builder
5283 .build_unconditional_branch(incr_bb)
5284 .map_err(|e| e.to_string())?;
5285 }
5286
5287 self.builder.position_at_end(incr_bb);
5289 let idx_val = self
5290 .builder
5291 .build_load(self.context.i64_type(), idx_ptr, "idx")
5292 .map_err(|e| e.to_string())?
5293 .into_int_value();
5294 let one = self.context.i64_type().const_int(1, false);
5295 let next_idx = self
5296 .builder
5297 .build_int_add(idx_val, one, "next_idx")
5298 .map_err(|e| e.to_string())?;
5299 self.builder
5300 .build_store(idx_ptr, next_idx)
5301 .map_err(|e| e.to_string())?;
5302 self.builder
5303 .build_unconditional_branch(cond_bb)
5304 .map_err(|e| e.to_string())?;
5305
5306 self.builder.position_at_end(after_bb);
5308
5309 scope.vars.remove(&var_name);
5311
5312 Ok(self.context.i64_type().const_int(0, false))
5313 }
5314
5315 fn get_array_length(&self, _array_val: IntValue<'ctx>) -> Result<IntValue<'ctx>, String> {
5317 Ok(self.context.i64_type().const_int(0, false))
5322 }
5323
5324 fn get_array_element(
5326 &self,
5327 _array_val: IntValue<'ctx>,
5328 _index: IntValue<'ctx>,
5329 ) -> Result<IntValue<'ctx>, String> {
5330 Ok(self.context.i64_type().const_int(0, false))
5333 }
5334
5335 fn compile_call(
5337 &mut self,
5338 fn_value: FunctionValue<'ctx>,
5339 scope: &mut CompileScope<'ctx>,
5340 func: &Expr,
5341 args: &[Expr],
5342 ) -> Result<IntValue<'ctx>, String> {
5343 let (fn_name, full_path) = if let Expr::Path(path) = func {
5345 let segments: Vec<&str> = path
5346 .segments
5347 .iter()
5348 .map(|s| s.ident.name.as_str())
5349 .collect();
5350 let short_name = segments.last().copied().ok_or("Empty path")?;
5351 let full = segments.join("::");
5352 (short_name, full)
5353 } else if let Expr::Field { field, .. } = func {
5354 let method_name = field.name.as_str();
5356 (method_name, method_name.to_string())
5357 } else {
5358 return Ok(self.context.i64_type().const_int(0, false));
5360 };
5361
5362 let full_path = if full_path.starts_with("Self::")
5364 || full_path.starts_with("This::")
5365 || full_path.starts_with("Self·")
5366 || full_path.starts_with("This·")
5367 {
5368 if let Some(ref self_type) = self.current_self_type {
5369 let method = if full_path.contains("::") {
5371 full_path.split("::").last().unwrap_or("")
5372 } else {
5373 full_path.split('·').last().unwrap_or("")
5374 };
5375 format!("{}::{}", self_type, method)
5377 } else {
5378 return Err(format!(
5379 "Self/This used outside of impl block: {}",
5380 full_path
5381 ));
5382 }
5383 } else {
5384 full_path
5385 };
5386
5387 if full_path == "Result::Ok" || full_path == "Result·Ok" {
5389 if args.is_empty() {
5390 return Ok(self.context.i64_type().const_int(0, false));
5391 }
5392 return self.compile_expr(fn_value, scope, &args[0]);
5393 }
5394 if full_path == "Result::Err" || full_path == "Result·Err" {
5395 if args.is_empty() {
5396 return Ok(self.context.i64_type().const_int(0, false));
5397 }
5398 return self.compile_expr(fn_value, scope, &args[0]);
5399 }
5400 if full_path == "Option::Some" || full_path == "Option·Some" {
5401 if args.is_empty() {
5402 return Ok(self.context.i64_type().const_int(0, false));
5403 }
5404 return self.compile_expr(fn_value, scope, &args[0]);
5405 }
5406 if full_path == "Option::None" || full_path == "Option·None" {
5407 return Ok(self.context.i64_type().const_int(0, false));
5408 }
5409 if full_path == "String::new" || full_path == "String·new" {
5410 let str_new_fn = self
5411 .module
5412 .get_function("sigil_string_new")
5413 .ok_or("sigil_string_new not declared")?;
5414 let call = self
5415 .builder
5416 .build_call(str_new_fn, &[], "string_new")
5417 .map_err(|e| e.to_string())?;
5418 return Ok(call
5419 .try_as_basic_value()
5420 .left()
5421 .map(|v| v.into_int_value())
5422 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5423 }
5424 if full_path == "String::from" || full_path == "String·from" {
5425 if args.is_empty() {
5426 return Ok(self.context.i64_type().const_int(0, false));
5427 }
5428 return self.compile_expr(fn_value, scope, &args[0]);
5429 }
5430 if full_path == "Config::default" {
5431 return Ok(self.context.i64_type().const_int(0, false));
5433 }
5434 if full_path == "println"
5436 || full_path == "print"
5437 || full_path == "eprintln"
5438 || full_path == "eprint"
5439 {
5440 let is_stderr = full_path == "eprintln" || full_path == "eprint";
5441 let with_newline = full_path == "println" || full_path == "eprintln";
5442
5443 if !args.is_empty() {
5444 let is_string = matches!(&args[0], Expr::Literal(Literal::String(_)));
5446
5447 if is_string {
5448 if let Expr::Literal(Literal::String(s)) = &args[0] {
5450 let str_ptr = self.create_global_string(s, "print_str");
5451 let print_fn_name = if is_stderr {
5452 if with_newline {
5453 "eprintln"
5454 } else {
5455 "eprint"
5456 }
5457 } else {
5458 if with_newline {
5459 "println"
5460 } else {
5461 "print"
5462 }
5463 };
5464 if let Some(print_fn) = self.module.get_function(print_fn_name) {
5466 self.builder
5467 .build_call(print_fn, &[str_ptr.into()], "print_call")
5468 .map_err(|e| e.to_string())?;
5469 } else if let Some(print_fn) =
5470 self.module.get_function("sigil_print_str")
5471 {
5472 self.builder
5473 .build_call(print_fn, &[str_ptr.into()], "print_call")
5474 .map_err(|e| e.to_string())?;
5475 if with_newline {
5477 let nl_ptr = self.create_global_string("\n", "newline");
5478 if let Some(write_fn) =
5479 self.module.get_function("sigil_write_str")
5480 {
5481 self.builder
5482 .build_call(write_fn, &[nl_ptr.into()], "nl_call")
5483 .map_err(|e| e.to_string())?;
5484 }
5485 }
5486 }
5487 }
5488 } else {
5489 let arg = self.compile_expr(fn_value, scope, &args[0])?;
5491 if let Some(print_fn) = self.module.get_function("sigil_print_int") {
5492 self.builder
5493 .build_call(print_fn, &[arg.into()], "print_call")
5494 .map_err(|e| e.to_string())?;
5495 }
5496 if with_newline {
5498 if let Some(print_nl) = self.module.get_function("sigil_print_newline")
5499 {
5500 self.builder
5501 .build_call(print_nl, &[], "nl_call")
5502 .map_err(|e| e.to_string())?;
5503 }
5504 }
5505 }
5506 } else {
5507 if with_newline {
5509 if let Some(print_nl) = self.module.get_function("sigil_print_newline") {
5510 self.builder
5511 .build_call(print_nl, &[], "nl_call")
5512 .map_err(|e| e.to_string())?;
5513 }
5514 }
5515 }
5516 return Ok(self.context.i64_type().const_int(0, false));
5517 }
5518 if full_path == "format" || full_path == "format!" {
5520 if !args.is_empty() {
5522 return self.compile_expr(fn_value, scope, &args[0]);
5523 }
5524 return Ok(self.context.i64_type().const_int(0, false));
5525 }
5526 if full_path == "panic" || full_path == "panic!" || full_path == "unreachable" {
5528 if let Some(panic_fn) = self.module.get_function("sigil_panic") {
5530 self.builder
5531 .build_call(panic_fn, &[], "panic_call")
5532 .map_err(|e| e.to_string())?;
5533 }
5534 return Ok(self.context.i64_type().const_int(0, false));
5535 }
5536 if full_path == "assert"
5538 || full_path == "assert!"
5539 || full_path == "assert_eq"
5540 || full_path == "assert_eq!"
5541 {
5542 for arg in args {
5544 self.compile_expr(fn_value, scope, arg)?;
5545 }
5546 return Ok(self.context.i64_type().const_int(0, false));
5547 }
5548
5549 match full_path.as_str() {
5551 "Vec::new" => {
5552 let capacity = self.context.i64_type().const_int(8, false);
5554 let vec_new_fn = self
5555 .module
5556 .get_function("sigil_vec_new")
5557 .ok_or("sigil_vec_new not declared")?;
5558 let call = self
5559 .builder
5560 .build_call(vec_new_fn, &[capacity.into()], "vec_new")
5561 .map_err(|e| e.to_string())?;
5562 return Ok(call
5563 .try_as_basic_value()
5564 .left()
5565 .map(|v| v.into_int_value())
5566 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5567 }
5568 "Vec::with_capacity" => {
5569 if args.is_empty() {
5570 return Err("Vec::with_capacity requires capacity argument".to_string());
5571 }
5572 let capacity = self.compile_expr(fn_value, scope, &args[0])?;
5573 let vec_new_fn = self
5574 .module
5575 .get_function("sigil_vec_new")
5576 .ok_or("sigil_vec_new not declared")?;
5577 let call = self
5578 .builder
5579 .build_call(vec_new_fn, &[capacity.into()], "vec_new")
5580 .map_err(|e| e.to_string())?;
5581 return Ok(call
5582 .try_as_basic_value()
5583 .left()
5584 .map(|v| v.into_int_value())
5585 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5586 }
5587 "Box::new" => {
5588 if args.is_empty() {
5590 return Err("Box::new requires a value argument".to_string());
5591 }
5592 let alloc_fn = self
5594 .module
5595 .get_function("sigil_alloc")
5596 .ok_or("sigil_alloc not declared")?;
5597 let size = self.context.i64_type().const_int(8, false);
5598 let call = self
5599 .builder
5600 .build_call(alloc_fn, &[size.into()], "box_alloc")
5601 .map_err(|e| e.to_string())?;
5602 let ptr = call
5603 .try_as_basic_value()
5604 .left()
5605 .map(|v| v.into_int_value())
5606 .unwrap_or_else(|| self.context.i64_type().const_int(0, false));
5607
5608 let value = self.compile_expr(fn_value, scope, &args[0])?;
5610 let ptr_as_ptr = self
5611 .builder
5612 .build_int_to_ptr(
5613 ptr,
5614 self.context.ptr_type(AddressSpace::default()),
5615 "box_ptr",
5616 )
5617 .map_err(|e| e.to_string())?;
5618 self.builder
5619 .build_store(ptr_as_ptr, value)
5620 .map_err(|e| e.to_string())?;
5621
5622 return Ok(ptr);
5623 }
5624 "File::read" | "File::read_all" => {
5626 if args.is_empty() {
5628 return Err("File::read requires a path argument".to_string());
5629 }
5630 let path_val = self.compile_expr(fn_value, scope, &args[0])?;
5632 let read_fn = self
5633 .module
5634 .get_function("sigil_file_read_all")
5635 .ok_or("sigil_file_read_all not declared")?;
5636 let call = self
5637 .builder
5638 .build_call(read_fn, &[path_val.into()], "file_read")
5639 .map_err(|e| e.to_string())?;
5640 return Ok(call
5641 .try_as_basic_value()
5642 .left()
5643 .map(|v| v.into_int_value())
5644 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5645 }
5646 "File::write" | "File::write_all" => {
5647 if args.len() < 2 {
5649 return Err("File::write requires path and content arguments".to_string());
5650 }
5651 let path_val = self.compile_expr(fn_value, scope, &args[0])?;
5652 let content_val = self.compile_expr(fn_value, scope, &args[1])?;
5653 let write_fn = self
5654 .module
5655 .get_function("sigil_file_write_all")
5656 .ok_or("sigil_file_write_all not declared")?;
5657 let call = self
5658 .builder
5659 .build_call(
5660 write_fn,
5661 &[path_val.into(), content_val.into()],
5662 "file_write",
5663 )
5664 .map_err(|e| e.to_string())?;
5665 return Ok(call
5666 .try_as_basic_value()
5667 .left()
5668 .map(|v| v.into_int_value())
5669 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5670 }
5671 "File::exists" => {
5672 if args.is_empty() {
5674 return Err("File::exists requires a path argument".to_string());
5675 }
5676 let path_val = self.compile_expr(fn_value, scope, &args[0])?;
5677 let exists_fn = self
5678 .module
5679 .get_function("sigil_file_exists")
5680 .ok_or("sigil_file_exists not declared")?;
5681 let call = self
5682 .builder
5683 .build_call(exists_fn, &[path_val.into()], "file_exists")
5684 .map_err(|e| e.to_string())?;
5685 return Ok(call
5686 .try_as_basic_value()
5687 .left()
5688 .map(|v| v.into_int_value())
5689 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
5690 }
5691 "F32x16::splat" => {
5695 if args.is_empty() {
5697 return Err("F32x16::splat requires a value argument".to_string());
5698 }
5699 let scalar = self.compile_expr(fn_value, scope, &args[0])?;
5700
5701 let alloc_fn = self
5703 .module
5704 .get_function("sigil_simd_alloc")
5705 .ok_or("sigil_simd_alloc not declared")?;
5706 let result_call = self
5708 .builder
5709 .build_call(
5710 alloc_fn,
5711 &[self.context.i64_type().const_int(16, false).into()],
5712 "result_buf",
5713 )
5714 .map_err(|e| e.to_string())?;
5715 let result_val = result_call
5716 .try_as_basic_value()
5717 .left()
5718 .ok_or("alloc returned void")?;
5719 let result_int = if result_val.is_pointer_value() {
5721 self.builder
5722 .build_ptr_to_int(
5723 result_val.into_pointer_value(),
5724 self.context.i64_type(),
5725 "result_int",
5726 )
5727 .map_err(|e| e.to_string())?
5728 } else {
5729 result_val.into_int_value()
5730 };
5731
5732 let f32_val = self
5734 .builder
5735 .build_bit_cast(scalar, self.context.f32_type(), "f32_val")
5736 .map_err(|e| e.to_string())?;
5737
5738 let splat_fn = self
5740 .module
5741 .get_function("sigil_simd_splat_f32x16")
5742 .ok_or("sigil_simd_splat_f32x16 not declared")?;
5743 let ptr_type = self.context.ptr_type(AddressSpace::default());
5744 let dest_ptr = self
5745 .builder
5746 .build_int_to_ptr(result_int, ptr_type, "dest")
5747 .map_err(|e| e.to_string())?;
5748 self.builder
5749 .build_call(splat_fn, &[dest_ptr.into(), f32_val.into()], "")
5750 .map_err(|e| e.to_string())?;
5751
5752 return Ok(result_int);
5753 }
5754 "F32x16::load_aligned" | "_mm512_load_ps" => {
5755 if args.is_empty() {
5757 return Err("F32x16::load_aligned requires a pointer argument".to_string());
5758 }
5759 let src_ptr_val = self.compile_expr(fn_value, scope, &args[0])?;
5760
5761 let alloc_fn = self
5763 .module
5764 .get_function("sigil_simd_alloc")
5765 .ok_or("sigil_simd_alloc not declared")?;
5766 let result_call = self
5767 .builder
5768 .build_call(
5769 alloc_fn,
5770 &[self.context.i64_type().const_int(16, false).into()],
5771 "result_buf",
5772 )
5773 .map_err(|e| e.to_string())?;
5774 let result_val = result_call
5775 .try_as_basic_value()
5776 .left()
5777 .ok_or("alloc returned void")?;
5778 let result_int = if result_val.is_pointer_value() {
5779 self.builder
5780 .build_ptr_to_int(
5781 result_val.into_pointer_value(),
5782 self.context.i64_type(),
5783 "result_int",
5784 )
5785 .map_err(|e| e.to_string())?
5786 } else {
5787 result_val.into_int_value()
5788 };
5789
5790 let load_fn = self
5792 .module
5793 .get_function("sigil_simd_load_f32x16")
5794 .ok_or("sigil_simd_load_f32x16 not declared")?;
5795 let ptr_type = self.context.ptr_type(AddressSpace::default());
5796 let dest_ptr = self
5797 .builder
5798 .build_int_to_ptr(result_int, ptr_type, "dest")
5799 .map_err(|e| e.to_string())?;
5800 let src_ptr = self
5801 .builder
5802 .build_int_to_ptr(src_ptr_val, ptr_type, "src")
5803 .map_err(|e| e.to_string())?;
5804 self.builder
5805 .build_call(load_fn, &[dest_ptr.into(), src_ptr.into()], "")
5806 .map_err(|e| e.to_string())?;
5807
5808 return Ok(result_int);
5809 }
5810 "F32x16::store_aligned" | "_mm512_store_ps" => {
5811 if args.len() < 2 {
5813 return Err(
5814 "F32x16::store_aligned requires destination and value".to_string()
5815 );
5816 }
5817 let dest_val = self.compile_expr(fn_value, scope, &args[0])?;
5818 let src_val = self.compile_expr(fn_value, scope, &args[1])?;
5819
5820 let store_fn = self
5822 .module
5823 .get_function("sigil_simd_store_f32x16")
5824 .ok_or("sigil_simd_store_f32x16 not declared")?;
5825 let ptr_type = self.context.ptr_type(AddressSpace::default());
5826 let dest_ptr = self
5827 .builder
5828 .build_int_to_ptr(dest_val, ptr_type, "dest")
5829 .map_err(|e| e.to_string())?;
5830 let src_ptr = self
5831 .builder
5832 .build_int_to_ptr(src_val, ptr_type, "src")
5833 .map_err(|e| e.to_string())?;
5834 self.builder
5835 .build_call(store_fn, &[dest_ptr.into(), src_ptr.into()], "")
5836 .map_err(|e| e.to_string())?;
5837
5838 return Ok(self.context.i64_type().const_int(0, false));
5839 }
5840 "F32x16::add" | "_mm512_add_ps" => {
5841 if args.len() < 2 {
5843 return Err("F32x16::add requires two vector arguments".to_string());
5844 }
5845 let a_ptr = self.compile_expr(fn_value, scope, &args[0])?;
5846 let b_ptr = self.compile_expr(fn_value, scope, &args[1])?;
5847
5848 let alloc_fn = self
5850 .module
5851 .get_function("sigil_simd_alloc")
5852 .ok_or("sigil_simd_alloc not declared")?;
5853 let result_call = self
5854 .builder
5855 .build_call(
5856 alloc_fn,
5857 &[self.context.i64_type().const_int(16, false).into()],
5858 "result_buf",
5859 )
5860 .map_err(|e| e.to_string())?;
5861 let result_val = result_call
5862 .try_as_basic_value()
5863 .left()
5864 .ok_or("alloc returned void")?;
5865 let result_int = if result_val.is_pointer_value() {
5866 self.builder
5867 .build_ptr_to_int(
5868 result_val.into_pointer_value(),
5869 self.context.i64_type(),
5870 "result_int",
5871 )
5872 .map_err(|e| e.to_string())?
5873 } else {
5874 result_val.into_int_value()
5875 };
5876
5877 let add_fn = self
5879 .module
5880 .get_function("sigil_simd_add_f32x16")
5881 .ok_or("sigil_simd_add_f32x16 not declared")?;
5882 let ptr_type = self.context.ptr_type(AddressSpace::default());
5883 let dest_ptr = self
5884 .builder
5885 .build_int_to_ptr(result_int, ptr_type, "dest")
5886 .map_err(|e| e.to_string())?;
5887 let a_ptr_cast = self
5888 .builder
5889 .build_int_to_ptr(a_ptr, ptr_type, "a")
5890 .map_err(|e| e.to_string())?;
5891 let b_ptr_cast = self
5892 .builder
5893 .build_int_to_ptr(b_ptr, ptr_type, "b")
5894 .map_err(|e| e.to_string())?;
5895 self.builder
5896 .build_call(
5897 add_fn,
5898 &[dest_ptr.into(), a_ptr_cast.into(), b_ptr_cast.into()],
5899 "",
5900 )
5901 .map_err(|e| e.to_string())?;
5902
5903 return Ok(result_int);
5904 }
5905 "F32x16::mul" | "_mm512_mul_ps" => {
5906 if args.len() < 2 {
5908 return Err("F32x16::mul requires two vector arguments".to_string());
5909 }
5910 let a_ptr = self.compile_expr(fn_value, scope, &args[0])?;
5911 let b_ptr = self.compile_expr(fn_value, scope, &args[1])?;
5912
5913 let alloc_fn = self
5915 .module
5916 .get_function("sigil_simd_alloc")
5917 .ok_or("sigil_simd_alloc not declared")?;
5918 let result_call = self
5919 .builder
5920 .build_call(
5921 alloc_fn,
5922 &[self.context.i64_type().const_int(16, false).into()],
5923 "result_buf",
5924 )
5925 .map_err(|e| e.to_string())?;
5926 let result_val = result_call
5927 .try_as_basic_value()
5928 .left()
5929 .ok_or("alloc returned void")?;
5930 let result_int = if result_val.is_pointer_value() {
5931 self.builder
5932 .build_ptr_to_int(
5933 result_val.into_pointer_value(),
5934 self.context.i64_type(),
5935 "result_int",
5936 )
5937 .map_err(|e| e.to_string())?
5938 } else {
5939 result_val.into_int_value()
5940 };
5941
5942 let mul_fn = self
5944 .module
5945 .get_function("sigil_simd_mul_f32x16")
5946 .ok_or("sigil_simd_mul_f32x16 not declared")?;
5947 let ptr_type = self.context.ptr_type(AddressSpace::default());
5948 let dest_ptr = self
5949 .builder
5950 .build_int_to_ptr(result_int, ptr_type, "dest")
5951 .map_err(|e| e.to_string())?;
5952 let a_ptr_cast = self
5953 .builder
5954 .build_int_to_ptr(a_ptr, ptr_type, "a")
5955 .map_err(|e| e.to_string())?;
5956 let b_ptr_cast = self
5957 .builder
5958 .build_int_to_ptr(b_ptr, ptr_type, "b")
5959 .map_err(|e| e.to_string())?;
5960 self.builder
5961 .build_call(
5962 mul_fn,
5963 &[dest_ptr.into(), a_ptr_cast.into(), b_ptr_cast.into()],
5964 "",
5965 )
5966 .map_err(|e| e.to_string())?;
5967
5968 return Ok(result_int);
5969 }
5970 "F32x16::fmadd" | "_mm512_fmadd_ps" => {
5971 if args.len() < 3 {
5973 return Err("F32x16::fmadd requires three vector arguments".to_string());
5974 }
5975 let a_ptr = self.compile_expr(fn_value, scope, &args[0])?;
5976 let b_ptr = self.compile_expr(fn_value, scope, &args[1])?;
5977 let c_ptr = self.compile_expr(fn_value, scope, &args[2])?;
5978
5979 let alloc_fn = self
5981 .module
5982 .get_function("sigil_simd_alloc")
5983 .ok_or("sigil_simd_alloc not declared")?;
5984 let result_call = self
5985 .builder
5986 .build_call(
5987 alloc_fn,
5988 &[self.context.i64_type().const_int(16, false).into()],
5989 "result_buf",
5990 )
5991 .map_err(|e| e.to_string())?;
5992 let result_val = result_call
5993 .try_as_basic_value()
5994 .left()
5995 .ok_or("alloc returned void")?;
5996 let result_int = if result_val.is_pointer_value() {
5997 self.builder
5998 .build_ptr_to_int(
5999 result_val.into_pointer_value(),
6000 self.context.i64_type(),
6001 "result_int",
6002 )
6003 .map_err(|e| e.to_string())?
6004 } else {
6005 result_val.into_int_value()
6006 };
6007
6008 let fmadd_fn = self
6010 .module
6011 .get_function("sigil_simd_fmadd_f32x16")
6012 .ok_or("sigil_simd_fmadd_f32x16 not declared")?;
6013 let ptr_type = self.context.ptr_type(AddressSpace::default());
6014 let dest_ptr = self
6015 .builder
6016 .build_int_to_ptr(result_int, ptr_type, "dest")
6017 .map_err(|e| e.to_string())?;
6018 let a_ptr_cast = self
6019 .builder
6020 .build_int_to_ptr(a_ptr, ptr_type, "a")
6021 .map_err(|e| e.to_string())?;
6022 let b_ptr_cast = self
6023 .builder
6024 .build_int_to_ptr(b_ptr, ptr_type, "b")
6025 .map_err(|e| e.to_string())?;
6026 let c_ptr_cast = self
6027 .builder
6028 .build_int_to_ptr(c_ptr, ptr_type, "c")
6029 .map_err(|e| e.to_string())?;
6030 self.builder
6031 .build_call(
6032 fmadd_fn,
6033 &[
6034 dest_ptr.into(),
6035 a_ptr_cast.into(),
6036 b_ptr_cast.into(),
6037 c_ptr_cast.into(),
6038 ],
6039 "",
6040 )
6041 .map_err(|e| e.to_string())?;
6042
6043 return Ok(result_int);
6044 }
6045 "F32x16::extract" => {
6046 if args.len() < 2 {
6048 return Err("F32x16::extract requires vector and index".to_string());
6049 }
6050 let vec_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6051 let idx = self.compile_expr(fn_value, scope, &args[1])?;
6052
6053 let extract_fn = self
6055 .module
6056 .get_function("sigil_simd_extract_f32x16")
6057 .ok_or("sigil_simd_extract_f32x16 not declared")?;
6058 let ptr_type = self.context.ptr_type(AddressSpace::default());
6059 let src_ptr = self
6060 .builder
6061 .build_int_to_ptr(vec_ptr, ptr_type, "src")
6062 .map_err(|e| e.to_string())?;
6063 let f32_result = self
6064 .builder
6065 .build_call(extract_fn, &[src_ptr.into(), idx.into()], "extract")
6066 .map_err(|e| e.to_string())?
6067 .try_as_basic_value()
6068 .left()
6069 .ok_or("extract returned void")?;
6070
6071 let bits = self
6073 .builder
6074 .build_bit_cast(f32_result, self.context.i32_type(), "bits")
6075 .map_err(|e| e.to_string())?;
6076 let extended = self
6077 .builder
6078 .build_int_z_extend(bits.into_int_value(), self.context.i64_type(), "ext")
6079 .map_err(|e| e.to_string())?;
6080 return Ok(extended);
6081 }
6082 "F32x16::reduce_add" => {
6083 if args.is_empty() {
6085 return Err("F32x16::reduce_add requires a vector argument".to_string());
6086 }
6087 let vec_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6088
6089 let reduce_fn = self
6091 .module
6092 .get_function("sigil_simd_reduce_add_f32x16")
6093 .ok_or("sigil_simd_reduce_add_f32x16 not declared")?;
6094 let ptr_type = self.context.ptr_type(AddressSpace::default());
6095 let src_ptr = self
6096 .builder
6097 .build_int_to_ptr(vec_ptr, ptr_type, "src")
6098 .map_err(|e| e.to_string())?;
6099 let f32_result = self
6100 .builder
6101 .build_call(reduce_fn, &[src_ptr.into()], "reduce")
6102 .map_err(|e| e.to_string())?
6103 .try_as_basic_value()
6104 .left()
6105 .ok_or("reduce returned void")?;
6106
6107 let bits = self
6109 .builder
6110 .build_bit_cast(f32_result, self.context.i32_type(), "bits")
6111 .map_err(|e| e.to_string())?;
6112 let extended = self
6113 .builder
6114 .build_int_z_extend(bits.into_int_value(), self.context.i64_type(), "ext")
6115 .map_err(|e| e.to_string())?;
6116 return Ok(extended);
6117 }
6118 "F32x16::dot" => {
6119 if args.len() < 2 {
6121 return Err("F32x16::dot requires two vector arguments".to_string());
6122 }
6123 let a_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6124 let b_ptr = self.compile_expr(fn_value, scope, &args[1])?;
6125
6126 let dot_fn = self
6128 .module
6129 .get_function("sigil_simd_dot_f32x16")
6130 .ok_or("sigil_simd_dot_f32x16 not declared")?;
6131 let ptr_type = self.context.ptr_type(AddressSpace::default());
6132 let a_ptr_cast = self
6133 .builder
6134 .build_int_to_ptr(a_ptr, ptr_type, "a")
6135 .map_err(|e| e.to_string())?;
6136 let b_ptr_cast = self
6137 .builder
6138 .build_int_to_ptr(b_ptr, ptr_type, "b")
6139 .map_err(|e| e.to_string())?;
6140 let f32_result = self
6141 .builder
6142 .build_call(dot_fn, &[a_ptr_cast.into(), b_ptr_cast.into()], "dot")
6143 .map_err(|e| e.to_string())?
6144 .try_as_basic_value()
6145 .left()
6146 .ok_or("dot returned void")?;
6147
6148 let bits = self
6150 .builder
6151 .build_bit_cast(f32_result, self.context.i32_type(), "bits")
6152 .map_err(|e| e.to_string())?;
6153 let extended = self
6154 .builder
6155 .build_int_z_extend(bits.into_int_value(), self.context.i64_type(), "ext")
6156 .map_err(|e| e.to_string())?;
6157 return Ok(extended);
6158 }
6159 "Cuda::init" | "cuda_init" => {
6163 let init_fn = self
6164 .module
6165 .get_function("sigil_cuda_init")
6166 .ok_or("sigil_cuda_init not declared")?;
6167 let result = self
6168 .builder
6169 .build_call(init_fn, &[], "cuda_init")
6170 .map_err(|e| e.to_string())?
6171 .try_as_basic_value()
6172 .left()
6173 .ok_or("cuda_init returned void")?;
6174 return Ok(result.into_int_value());
6175 }
6176 "Cuda::cleanup" | "cuda_cleanup" => {
6177 let cleanup_fn = self
6178 .module
6179 .get_function("sigil_cuda_cleanup")
6180 .ok_or("sigil_cuda_cleanup not declared")?;
6181 self.builder
6182 .build_call(cleanup_fn, &[], "")
6183 .map_err(|e| e.to_string())?;
6184 return Ok(self.context.i64_type().const_int(0, false));
6185 }
6186 "Cuda::device_count" | "cuda_device_count" => {
6187 let count_fn = self
6188 .module
6189 .get_function("sigil_cuda_get_device_count")
6190 .ok_or("sigil_cuda_get_device_count not declared")?;
6191 let result = self
6192 .builder
6193 .build_call(count_fn, &[], "device_count")
6194 .map_err(|e| e.to_string())?
6195 .try_as_basic_value()
6196 .left()
6197 .ok_or("device_count returned void")?;
6198 return Ok(result.into_int_value());
6199 }
6200 "Cuda::malloc" | "cuda_malloc" => {
6201 if args.is_empty() {
6202 return Err("Cuda::malloc requires size argument".to_string());
6203 }
6204 let size = self.compile_expr(fn_value, scope, &args[0])?;
6205 let malloc_fn = self
6206 .module
6207 .get_function("sigil_cuda_malloc")
6208 .ok_or("sigil_cuda_malloc not declared")?;
6209 let result = self
6210 .builder
6211 .build_call(malloc_fn, &[size.into()], "cuda_ptr")
6212 .map_err(|e| e.to_string())?
6213 .try_as_basic_value()
6214 .left()
6215 .ok_or("cuda_malloc returned void")?;
6216 return Ok(result.into_int_value());
6217 }
6218 "Cuda::free" | "cuda_free" => {
6219 if args.is_empty() {
6220 return Err("Cuda::free requires device pointer argument".to_string());
6221 }
6222 let ptr = self.compile_expr(fn_value, scope, &args[0])?;
6223 let free_fn = self
6224 .module
6225 .get_function("sigil_cuda_free")
6226 .ok_or("sigil_cuda_free not declared")?;
6227 self.builder
6228 .build_call(free_fn, &[ptr.into()], "")
6229 .map_err(|e| e.to_string())?;
6230 return Ok(self.context.i64_type().const_int(0, false));
6231 }
6232 "Cuda::memcpy_h2d" | "cuda_memcpy_h2d" => {
6233 if args.len() < 3 {
6234 return Err(
6235 "Cuda::memcpy_h2d requires (dst_device, src_host, size)".to_string()
6236 );
6237 }
6238 let dst = self.compile_expr(fn_value, scope, &args[0])?;
6239 let src = self.compile_expr(fn_value, scope, &args[1])?;
6240 let size = self.compile_expr(fn_value, scope, &args[2])?;
6241 let ptr_type = self.context.ptr_type(AddressSpace::default());
6242 let src_ptr = self
6243 .builder
6244 .build_int_to_ptr(src, ptr_type, "src_ptr")
6245 .map_err(|e| e.to_string())?;
6246 let h2d_fn = self
6247 .module
6248 .get_function("sigil_cuda_memcpy_h2d")
6249 .ok_or("sigil_cuda_memcpy_h2d not declared")?;
6250 let result = self
6251 .builder
6252 .build_call(h2d_fn, &[dst.into(), src_ptr.into(), size.into()], "h2d")
6253 .map_err(|e| e.to_string())?
6254 .try_as_basic_value()
6255 .left()
6256 .ok_or("h2d returned void")?;
6257 return Ok(result.into_int_value());
6258 }
6259 "Cuda::memcpy_d2h" | "cuda_memcpy_d2h" => {
6260 if args.len() < 3 {
6261 return Err(
6262 "Cuda::memcpy_d2h requires (dst_host, src_device, size)".to_string()
6263 );
6264 }
6265 let dst = self.compile_expr(fn_value, scope, &args[0])?;
6266 let src = self.compile_expr(fn_value, scope, &args[1])?;
6267 let size = self.compile_expr(fn_value, scope, &args[2])?;
6268 let ptr_type = self.context.ptr_type(AddressSpace::default());
6269 let dst_ptr = self
6270 .builder
6271 .build_int_to_ptr(dst, ptr_type, "dst_ptr")
6272 .map_err(|e| e.to_string())?;
6273 let d2h_fn = self
6274 .module
6275 .get_function("sigil_cuda_memcpy_d2h")
6276 .ok_or("sigil_cuda_memcpy_d2h not declared")?;
6277 let result = self
6278 .builder
6279 .build_call(d2h_fn, &[dst_ptr.into(), src.into(), size.into()], "d2h")
6280 .map_err(|e| e.to_string())?
6281 .try_as_basic_value()
6282 .left()
6283 .ok_or("d2h returned void")?;
6284 return Ok(result.into_int_value());
6285 }
6286 "Cuda::sync" | "cuda_sync" => {
6287 let sync_fn = self
6288 .module
6289 .get_function("sigil_cuda_sync")
6290 .ok_or("sigil_cuda_sync not declared")?;
6291 self.builder
6292 .build_call(sync_fn, &[], "")
6293 .map_err(|e| e.to_string())?;
6294 return Ok(self.context.i64_type().const_int(0, false));
6295 }
6296 "Cuda::compile_kernel" | "cuda_compile_kernel" => {
6297 if args.len() < 2 {
6298 return Err(
6299 "Cuda::compile_kernel requires (cuda_source, kernel_name)".to_string()
6300 );
6301 }
6302 let src = self.compile_expr(fn_value, scope, &args[0])?;
6303 let name = self.compile_expr(fn_value, scope, &args[1])?;
6304 let ptr_type = self.context.ptr_type(AddressSpace::default());
6305 let src_ptr = self
6306 .builder
6307 .build_int_to_ptr(src, ptr_type, "src_ptr")
6308 .map_err(|e| e.to_string())?;
6309 let name_ptr = self
6310 .builder
6311 .build_int_to_ptr(name, ptr_type, "name_ptr")
6312 .map_err(|e| e.to_string())?;
6313 let compile_fn = self
6314 .module
6315 .get_function("sigil_cuda_compile_kernel")
6316 .ok_or("sigil_cuda_compile_kernel not declared")?;
6317 let result = self
6318 .builder
6319 .build_call(
6320 compile_fn,
6321 &[src_ptr.into(), name_ptr.into()],
6322 "kernel_handle",
6323 )
6324 .map_err(|e| e.to_string())?
6325 .try_as_basic_value()
6326 .left()
6327 .ok_or("compile_kernel returned void")?;
6328 return Ok(result.into_int_value());
6329 }
6330 "Cuda::launch_1d" | "cuda_launch_1d" => {
6331 if args.len() < 5 {
6333 return Err("Cuda::launch_1d requires (handle, grid_x, block_x, args_ptr, num_args)".to_string());
6334 }
6335 let handle = self.compile_expr(fn_value, scope, &args[0])?;
6336 let grid_x = self.compile_expr(fn_value, scope, &args[1])?;
6337 let block_x = self.compile_expr(fn_value, scope, &args[2])?;
6338 let args_ptr = self.compile_expr(fn_value, scope, &args[3])?;
6339 let num_args = self.compile_expr(fn_value, scope, &args[4])?;
6340 let ptr_type = self.context.ptr_type(AddressSpace::default());
6341 let args_cast = self
6342 .builder
6343 .build_int_to_ptr(args_ptr, ptr_type, "args")
6344 .map_err(|e| e.to_string())?;
6345 let launch_fn = self
6346 .module
6347 .get_function("sigil_cuda_launch_kernel_1d")
6348 .ok_or("sigil_cuda_launch_kernel_1d not declared")?;
6349 let result = self
6350 .builder
6351 .build_call(
6352 launch_fn,
6353 &[
6354 handle.into(),
6355 grid_x.into(),
6356 block_x.into(),
6357 args_cast.into(),
6358 num_args.into(),
6359 ],
6360 "launch",
6361 )
6362 .map_err(|e| e.to_string())?
6363 .try_as_basic_value()
6364 .left()
6365 .ok_or("launch returned void")?;
6366 return Ok(result.into_int_value());
6367 }
6368 _ => {}
6369 }
6370
6371 match fn_name {
6373 "print" => {
6374 if !args.is_empty() {
6375 let arg_val = self.compile_expr(fn_value, scope, &args[0])?;
6376 let print_fn = self
6378 .module
6379 .get_function("sigil_print_int")
6380 .ok_or("sigil_print_int not declared")?;
6381 self.builder
6382 .build_call(print_fn, &[arg_val.into()], "")
6383 .map_err(|e| e.to_string())?;
6384 return Ok(arg_val);
6385 }
6386 return Ok(self.context.i64_type().const_int(0, false));
6387 }
6388 "now" => {
6389 let now_fn = self
6391 .module
6392 .get_function("sigil_now")
6393 .ok_or("sigil_now not declared")?;
6394 let call = self
6395 .builder
6396 .build_call(now_fn, &[], "now")
6397 .map_err(|e| e.to_string())?;
6398 return Ok(call
6399 .try_as_basic_value()
6400 .left()
6401 .map(|v| v.into_int_value())
6402 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6403 }
6404 "sqrt" | "sin" | "cos" | "tan" | "exp" | "ln" | "floor" | "ceil" | "abs" => {
6406 if args.is_empty() {
6407 return Err(format!("{} requires 1 argument", fn_name));
6408 }
6409 let arg = self.compile_expr(fn_value, scope, &args[0])?;
6410 let rt_name = format!("sigil_{}", fn_name);
6411 let rt_fn = self
6412 .module
6413 .get_function(&rt_name)
6414 .ok_or(format!("{} not declared", rt_name))?;
6415 let call = self
6416 .builder
6417 .build_call(rt_fn, &[arg.into()], fn_name)
6418 .map_err(|e| e.to_string())?;
6419 return Ok(call
6420 .try_as_basic_value()
6421 .left()
6422 .map(|v| v.into_int_value())
6423 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6424 }
6425 "pow" | "min" | "max" => {
6427 if args.len() < 2 {
6428 return Err(format!("{} requires 2 arguments", fn_name));
6429 }
6430 let arg1 = self.compile_expr(fn_value, scope, &args[0])?;
6431 let arg2 = self.compile_expr(fn_value, scope, &args[1])?;
6432 let rt_name = format!("sigil_{}", fn_name);
6433 let rt_fn = self
6434 .module
6435 .get_function(&rt_name)
6436 .ok_or(format!("{} not declared", rt_name))?;
6437 let call = self
6438 .builder
6439 .build_call(rt_fn, &[arg1.into(), arg2.into()], fn_name)
6440 .map_err(|e| e.to_string())?;
6441 return Ok(call
6442 .try_as_basic_value()
6443 .left()
6444 .map(|v| v.into_int_value())
6445 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6446 }
6447 "vec_new" => {
6449 if args.is_empty() {
6450 return Err("vec_new requires capacity argument".to_string());
6451 }
6452 let capacity = self.compile_expr(fn_value, scope, &args[0])?;
6453 let vec_new_fn = self
6454 .module
6455 .get_function("sigil_vec_new")
6456 .ok_or("sigil_vec_new not declared")?;
6457 let call = self
6458 .builder
6459 .build_call(vec_new_fn, &[capacity.into()], "vec_new")
6460 .map_err(|e| e.to_string())?;
6461 return Ok(call
6462 .try_as_basic_value()
6463 .left()
6464 .map(|v| v.into_int_value())
6465 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6466 }
6467 "vec_push" => {
6468 if args.len() < 2 {
6469 return Err("vec_push requires vec and value arguments".to_string());
6470 }
6471 let vec_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6472 let value = self.compile_expr(fn_value, scope, &args[1])?;
6473 let vec_push_fn = self
6474 .module
6475 .get_function("sigil_vec_push")
6476 .ok_or("sigil_vec_push not declared")?;
6477 self.builder
6478 .build_call(vec_push_fn, &[vec_ptr.into(), value.into()], "")
6479 .map_err(|e| e.to_string())?;
6480 return Ok(self.context.i64_type().const_int(0, false));
6481 }
6482 "vec_get" => {
6483 if args.len() < 2 {
6484 return Err("vec_get requires vec and index arguments".to_string());
6485 }
6486 let vec_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6487 let index = self.compile_expr(fn_value, scope, &args[1])?;
6488 let vec_get_fn = self
6489 .module
6490 .get_function("sigil_vec_get")
6491 .ok_or("sigil_vec_get not declared")?;
6492 let call = self
6493 .builder
6494 .build_call(vec_get_fn, &[vec_ptr.into(), index.into()], "vec_get")
6495 .map_err(|e| e.to_string())?;
6496 return Ok(call
6497 .try_as_basic_value()
6498 .left()
6499 .map(|v| v.into_int_value())
6500 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6501 }
6502 "vec_len" => {
6503 if args.is_empty() {
6504 return Err("vec_len requires vec argument".to_string());
6505 }
6506 let vec_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6507 let vec_len_fn = self
6508 .module
6509 .get_function("sigil_vec_len")
6510 .ok_or("sigil_vec_len not declared")?;
6511 let call = self
6512 .builder
6513 .build_call(vec_len_fn, &[vec_ptr.into()], "vec_len")
6514 .map_err(|e| e.to_string())?;
6515 return Ok(call
6516 .try_as_basic_value()
6517 .left()
6518 .map(|v| v.into_int_value())
6519 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6520 }
6521 "String_from" => {
6523 if args.is_empty() {
6524 return Err("String_from requires string literal argument".to_string());
6525 }
6526 let str_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6528 let string_from_fn = self
6529 .module
6530 .get_function("sigil_string_from")
6531 .ok_or("sigil_string_from not declared")?;
6532 let call = self
6533 .builder
6534 .build_call(string_from_fn, &[str_ptr.into()], "string_from")
6535 .map_err(|e| e.to_string())?;
6536 return Ok(call
6537 .try_as_basic_value()
6538 .left()
6539 .map(|v| v.into_int_value())
6540 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6541 }
6542 "string_len" => {
6543 if args.is_empty() {
6544 return Err("string_len requires string argument".to_string());
6545 }
6546 let str_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6547 let string_len_fn = self
6548 .module
6549 .get_function("sigil_string_len")
6550 .ok_or("sigil_string_len not declared")?;
6551 let call = self
6552 .builder
6553 .build_call(string_len_fn, &[str_ptr.into()], "string_len")
6554 .map_err(|e| e.to_string())?;
6555 return Ok(call
6556 .try_as_basic_value()
6557 .left()
6558 .map(|v| v.into_int_value())
6559 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6560 }
6561 "string_print" => {
6562 if args.is_empty() {
6563 return Err("string_print requires string argument".to_string());
6564 }
6565 let str_ptr = self.compile_expr(fn_value, scope, &args[0])?;
6566 let string_print_fn = self
6567 .module
6568 .get_function("sigil_string_print")
6569 .ok_or("sigil_string_print not declared")?;
6570 self.builder
6571 .build_call(string_print_fn, &[str_ptr.into()], "")
6572 .map_err(|e| e.to_string())?;
6573 return Ok(self.context.i64_type().const_int(0, false));
6574 }
6575 "string_concat" => {
6576 if args.len() < 2 {
6577 return Err("string_concat requires two string arguments".to_string());
6578 }
6579 let str1 = self.compile_expr(fn_value, scope, &args[0])?;
6580 let str2 = self.compile_expr(fn_value, scope, &args[1])?;
6581 let string_concat_fn = self
6582 .module
6583 .get_function("sigil_string_concat")
6584 .ok_or("sigil_string_concat not declared")?;
6585 let call = self
6586 .builder
6587 .build_call(
6588 string_concat_fn,
6589 &[str1.into(), str2.into()],
6590 "string_concat",
6591 )
6592 .map_err(|e| e.to_string())?;
6593 return Ok(call
6594 .try_as_basic_value()
6595 .left()
6596 .map(|v| v.into_int_value())
6597 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6598 }
6599 "Some" => {
6601 if args.is_empty() {
6602 return Err("Some requires a value argument".to_string());
6603 }
6604 let value = self.compile_expr(fn_value, scope, &args[0])?;
6605 let option_some_fn = self
6606 .module
6607 .get_function("sigil_option_some")
6608 .ok_or("sigil_option_some not declared")?;
6609 let call = self
6610 .builder
6611 .build_call(option_some_fn, &[value.into()], "some")
6612 .map_err(|e| e.to_string())?;
6613 return Ok(call
6614 .try_as_basic_value()
6615 .left()
6616 .map(|v| v.into_int_value())
6617 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6618 }
6619 "None" => {
6620 let option_none_fn = self
6621 .module
6622 .get_function("sigil_option_none")
6623 .ok_or("sigil_option_none not declared")?;
6624 let call = self
6625 .builder
6626 .build_call(option_none_fn, &[], "none")
6627 .map_err(|e| e.to_string())?;
6628 return Ok(call
6629 .try_as_basic_value()
6630 .left()
6631 .map(|v| v.into_int_value())
6632 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6633 }
6634 "is_some" => {
6635 if args.is_empty() {
6636 return Err("is_some requires an option argument".to_string());
6637 }
6638 let opt = self.compile_expr(fn_value, scope, &args[0])?;
6639 let is_some_fn = self
6640 .module
6641 .get_function("sigil_option_is_some")
6642 .ok_or("sigil_option_is_some not declared")?;
6643 let call = self
6644 .builder
6645 .build_call(is_some_fn, &[opt.into()], "is_some")
6646 .map_err(|e| e.to_string())?;
6647 return Ok(call
6648 .try_as_basic_value()
6649 .left()
6650 .map(|v| v.into_int_value())
6651 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6652 }
6653 "is_none" => {
6654 if args.is_empty() {
6655 return Err("is_none requires an option argument".to_string());
6656 }
6657 let opt = self.compile_expr(fn_value, scope, &args[0])?;
6658 let is_none_fn = self
6659 .module
6660 .get_function("sigil_option_is_none")
6661 .ok_or("sigil_option_is_none not declared")?;
6662 let call = self
6663 .builder
6664 .build_call(is_none_fn, &[opt.into()], "is_none")
6665 .map_err(|e| e.to_string())?;
6666 return Ok(call
6667 .try_as_basic_value()
6668 .left()
6669 .map(|v| v.into_int_value())
6670 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6671 }
6672 "unwrap" => {
6673 if args.is_empty() {
6674 return Err("unwrap requires an option argument".to_string());
6675 }
6676 let opt = self.compile_expr(fn_value, scope, &args[0])?;
6677 let unwrap_fn = self
6678 .module
6679 .get_function("sigil_option_unwrap")
6680 .ok_or("sigil_option_unwrap not declared")?;
6681 let call = self
6682 .builder
6683 .build_call(unwrap_fn, &[opt.into()], "unwrap")
6684 .map_err(|e| e.to_string())?;
6685 return Ok(call
6686 .try_as_basic_value()
6687 .left()
6688 .map(|v| v.into_int_value())
6689 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6690 }
6691 "unwrap_or" => {
6692 if args.len() < 2 {
6693 return Err("unwrap_or requires option and default arguments".to_string());
6694 }
6695 let opt = self.compile_expr(fn_value, scope, &args[0])?;
6696 let default_val = self.compile_expr(fn_value, scope, &args[1])?;
6697 let unwrap_or_fn = self
6698 .module
6699 .get_function("sigil_option_unwrap_or")
6700 .ok_or("sigil_option_unwrap_or not declared")?;
6701 let call = self
6702 .builder
6703 .build_call(unwrap_or_fn, &[opt.into(), default_val.into()], "unwrap_or")
6704 .map_err(|e| e.to_string())?;
6705 return Ok(call
6706 .try_as_basic_value()
6707 .left()
6708 .map(|v| v.into_int_value())
6709 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6710 }
6711 "file_exists" => {
6713 if args.is_empty() {
6714 return Err("file_exists requires a path argument".to_string());
6715 }
6716 let path = self.compile_expr(fn_value, scope, &args[0])?;
6717 let file_exists_fn = self
6718 .module
6719 .get_function("sigil_file_exists")
6720 .ok_or("sigil_file_exists not declared")?;
6721 let call = self
6722 .builder
6723 .build_call(file_exists_fn, &[path.into()], "file_exists")
6724 .map_err(|e| e.to_string())?;
6725 return Ok(call
6726 .try_as_basic_value()
6727 .left()
6728 .map(|v| v.into_int_value())
6729 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6730 }
6731 "file_read_all" => {
6732 if args.is_empty() {
6733 return Err("file_read_all requires a path argument".to_string());
6734 }
6735 let path = self.compile_expr(fn_value, scope, &args[0])?;
6736 let file_read_fn = self
6737 .module
6738 .get_function("sigil_file_read_all")
6739 .ok_or("sigil_file_read_all not declared")?;
6740 let call = self
6741 .builder
6742 .build_call(file_read_fn, &[path.into()], "file_read")
6743 .map_err(|e| e.to_string())?;
6744 return Ok(call
6745 .try_as_basic_value()
6746 .left()
6747 .map(|v| v.into_int_value())
6748 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6749 }
6750 "file_write_all" => {
6751 if args.len() < 2 {
6752 return Err(
6753 "file_write_all requires path and content arguments".to_string()
6754 );
6755 }
6756 let path = self.compile_expr(fn_value, scope, &args[0])?;
6757 let content = self.compile_expr(fn_value, scope, &args[1])?;
6758 let file_write_fn = self
6759 .module
6760 .get_function("sigil_file_write_all")
6761 .ok_or("sigil_file_write_all not declared")?;
6762 let call = self
6763 .builder
6764 .build_call(file_write_fn, &[path.into(), content.into()], "file_write")
6765 .map_err(|e| e.to_string())?;
6766 return Ok(call
6767 .try_as_basic_value()
6768 .left()
6769 .map(|v| v.into_int_value())
6770 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6771 }
6772 "Result::Ok" | "Result·Ok" => {
6774 if args.is_empty() {
6777 return Ok(self.context.i64_type().const_int(0, false));
6778 }
6779 return self.compile_expr(fn_value, scope, &args[0]);
6780 }
6781 "Result::Err" | "Result·Err" => {
6782 if args.is_empty() {
6786 return Ok(self.context.i64_type().const_int(0, false));
6787 }
6788 let result = self.compile_expr(fn_value, scope, &args[0]);
6790 return result;
6792 }
6793 "Option::Some" | "Option·Some" => {
6795 if args.is_empty() {
6796 return Ok(self.context.i64_type().const_int(0, false));
6797 }
6798 return self.compile_expr(fn_value, scope, &args[0]);
6799 }
6800 "Option::None" | "Option·None" => {
6801 return Ok(self.context.i64_type().const_int(0, false));
6803 }
6804 "String::new" | "String·new" => {
6806 let str_new_fn = self
6807 .module
6808 .get_function("sigil_string_new")
6809 .ok_or("sigil_string_new not declared")?;
6810 let call = self
6811 .builder
6812 .build_call(str_new_fn, &[], "string_new")
6813 .map_err(|e| e.to_string())?;
6814 return Ok(call
6815 .try_as_basic_value()
6816 .left()
6817 .map(|v| v.into_int_value())
6818 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6819 }
6820 "String::from" | "String·from" => {
6821 if args.is_empty() {
6822 return Ok(self.context.i64_type().const_int(0, false));
6823 }
6824 return self.compile_expr(fn_value, scope, &args[0]);
6826 }
6827 "Map::new" | "Map·new" | "HashMap::new" => {
6829 let map_new_fn = self
6830 .module
6831 .get_function("sigil_map_new")
6832 .ok_or("sigil_map_new not declared")?;
6833 let call = self
6834 .builder
6835 .build_call(map_new_fn, &[], "map_new")
6836 .map_err(|e| e.to_string())?;
6837 return Ok(call
6838 .try_as_basic_value()
6839 .left()
6840 .map(|v| v.into_int_value())
6841 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)));
6842 }
6843 _ => {
6844 }
6846 }
6847
6848 let resolved_path = if let Some(aliased) = self.use_aliases.get(fn_name) {
6850 aliased.clone()
6851 } else {
6852 full_path.clone()
6853 };
6854
6855 if full_path.ends_with("::new")
6858 || full_path.ends_with("·new")
6859 || full_path.ends_with("::default")
6860 || full_path.ends_with("·default")
6861 || full_path.ends_with("::create")
6862 || full_path.ends_with("·create")
6863 || full_path.ends_with("::init")
6864 || full_path.ends_with("·init")
6865 {
6866 return Ok(self.context.i64_type().const_int(0, false));
6870 }
6871
6872 if full_path.ends_with("::with_capacity")
6874 || full_path.ends_with("·with_capacity")
6875 || full_path.ends_with("::from_iter")
6876 || full_path.ends_with("·from_iter")
6877 {
6878 return Ok(self.context.i64_type().const_int(0, false));
6879 }
6880
6881 let callee = if let Some(f) = self.functions.get(&resolved_path) {
6883 *f
6884 } else if let Some(f) = self.functions.get(&full_path) {
6885 *f
6886 } else if let Some(f) = self.functions.get(fn_name) {
6887 *f
6888 } else if let Some(f) = self.module.get_function(&resolved_path.replace("::", "_")) {
6889 f
6890 } else if let Some(f) = self.module.get_function(&full_path.replace("::", "_")) {
6891 f
6892 } else if let Some(f) = self.module.get_function(fn_name) {
6893 f
6894 } else {
6895 let fn_lower = fn_name.to_lowercase();
6897
6898 if fn_lower.starts_with("lower")
6900 || fn_lower.starts_with("parse")
6901 || fn_lower.starts_with("compile")
6902 || fn_lower.starts_with("transform")
6903 || fn_lower.starts_with("convert")
6904 || fn_lower.starts_with("generate")
6905 || fn_lower.starts_with("create")
6906 || fn_lower.starts_with("build")
6907 || fn_lower.starts_with("make")
6908 || fn_lower.starts_with("read")
6909 || fn_lower.starts_with("load")
6910 || fn_lower.starts_with("fetch")
6911 || fn_lower.starts_with("get")
6912 || fn_lower.starts_with("find")
6913 || fn_lower.starts_with("lookup")
6914 || fn_lower.starts_with("resolve")
6915 || fn_lower.starts_with("extract")
6916 || fn_lower.starts_with("infer")
6917 || fn_lower.starts_with("derive")
6918 || fn_lower.starts_with("compute")
6919 || fn_lower.starts_with("calculate")
6920 {
6921 return Ok(self.context.i64_type().const_int(0, false));
6924 }
6925
6926 if fn_lower.starts_with("write")
6928 || fn_lower.starts_with("emit")
6929 || fn_lower.starts_with("output")
6930 || fn_lower.starts_with("print")
6931 || fn_lower.starts_with("log")
6932 || fn_lower.starts_with("debug")
6933 || fn_lower.starts_with("warn")
6934 || fn_lower.starts_with("error")
6935 || fn_lower.starts_with("report")
6936 || fn_lower.starts_with("notify")
6937 {
6938 return Ok(self.context.i64_type().const_int(0, false));
6940 }
6941
6942 if fn_lower.starts_with("check")
6944 || fn_lower.starts_with("validate")
6945 || fn_lower.starts_with("verify")
6946 || fn_lower.starts_with("test")
6947 || fn_lower.starts_with("is_")
6948 || fn_lower.starts_with("has_")
6949 || fn_lower.starts_with("can_")
6950 {
6951 return Ok(self.context.i64_type().const_int(0, false));
6953 }
6954
6955 return Ok(self.context.i64_type().const_int(0, false));
6958 };
6959
6960 let compiled_args: Result<Vec<_>, _> = args
6962 .iter()
6963 .map(|arg| self.compile_expr(fn_value, scope, arg).map(|v| v.into()))
6964 .collect();
6965 let compiled_args = compiled_args?;
6966
6967 let call = self
6969 .builder
6970 .build_call(callee, &compiled_args, "call")
6971 .map_err(|e| e.to_string())?;
6972
6973 call.set_tail_call(true);
6976
6977 Ok(call
6979 .try_as_basic_value()
6980 .left()
6981 .map(|v| v.into_int_value())
6982 .unwrap_or_else(|| self.context.i64_type().const_int(0, false)))
6983 }
6984
6985 fn compile_print_macro(
6987 &mut self,
6988 fn_value: FunctionValue<'ctx>,
6989 scope: &mut CompileScope<'ctx>,
6990 tokens: &str,
6991 newline: bool,
6992 ) -> Result<(), String> {
6993 let tokens = tokens.trim();
6996
6997 if tokens.is_empty() {
6998 if newline {
7000 let empty_str = self.create_global_string("\n", "empty_nl");
7001 let print_fn = self
7002 .module
7003 .get_function("sigil_print_str")
7004 .ok_or("sigil_print_str not declared")?;
7005 self.builder
7006 .build_call(print_fn, &[empty_str.into()], "")
7007 .map_err(|e| e.to_string())?;
7008 }
7009 return Ok(());
7010 }
7011
7012 let (format_str, args_str) = if tokens.starts_with('"') {
7014 let mut chars = tokens[1..].chars().peekable();
7016 let mut format_content = String::new();
7017 let mut escaped = false;
7018
7019 while let Some(c) = chars.next() {
7020 if escaped {
7021 format_content.push(c);
7022 escaped = false;
7023 } else if c == '\\' {
7024 format_content.push(c);
7025 escaped = true;
7026 } else if c == '"' {
7027 break;
7028 } else {
7029 format_content.push(c);
7030 }
7031 }
7032
7033 let remaining: String = chars.collect();
7035 let args_owned = remaining.trim_start_matches(',').trim().to_string();
7036 (format_content, args_owned)
7037 } else {
7038 (String::new(), tokens.to_string())
7040 };
7041
7042 let has_placeholders = format_str.contains("{}");
7044
7045 if !has_placeholders && args_str.is_empty() {
7046 let output = format_str.replace("\\n", "\n").replace("\\t", "\t");
7048
7049 let write_str_fn = self
7050 .module
7051 .get_function("sigil_write_str")
7052 .ok_or("sigil_write_str not declared")?;
7053
7054 let str_ptr = self.create_global_string(&output, "print_str");
7055 self.builder
7056 .build_call(write_str_fn, &[str_ptr.into()], "")
7057 .map_err(|e| e.to_string())?;
7058
7059 if newline {
7061 let nl_str = self.create_global_string("\n", "newline");
7062 self.builder
7063 .build_call(write_str_fn, &[nl_str.into()], "")
7064 .map_err(|e| e.to_string())?;
7065 }
7066 } else if has_placeholders {
7067 let parts: Vec<&str> = format_str.split("{}").collect();
7070 let args: Vec<&str> = args_str
7071 .split(',')
7072 .map(|s| s.trim())
7073 .filter(|s| !s.is_empty())
7074 .collect();
7075
7076 let write_str_fn = self
7078 .module
7079 .get_function("sigil_write_str")
7080 .ok_or("sigil_write_str not declared")?;
7081 let write_int_fn = self
7082 .module
7083 .get_function("sigil_write_int")
7084 .ok_or("sigil_write_int not declared")?;
7085
7086 for (i, part) in parts.iter().enumerate() {
7087 if !part.is_empty() {
7089 let part_str = part.replace("\\n", "\n").replace("\\t", "\t");
7090 let str_ptr = self.create_global_string(&part_str, "fmt_part");
7091 self.builder
7092 .build_call(write_str_fn, &[str_ptr.into()], "")
7093 .map_err(|e| e.to_string())?;
7094 }
7095
7096 if i < args.len() {
7098 let arg_str = args[i];
7099 let arg_value = self.compile_format_arg(fn_value, scope, arg_str)?;
7101 self.builder
7102 .build_call(write_int_fn, &[arg_value.into()], "")
7103 .map_err(|e| e.to_string())?;
7104 }
7105 }
7106
7107 if newline {
7109 let nl_str = self.create_global_string("\n", "newline");
7110 self.builder
7111 .build_call(write_str_fn, &[nl_str.into()], "")
7112 .map_err(|e| e.to_string())?;
7113 }
7114 } else if !args_str.is_empty() {
7115 let arg_value = self.compile_format_arg(fn_value, scope, &args_str)?;
7117 let print_int_fn = self
7118 .module
7119 .get_function("sigil_print_int")
7120 .ok_or("sigil_print_int not declared")?;
7121 self.builder
7122 .build_call(print_int_fn, &[arg_value.into()], "")
7123 .map_err(|e| e.to_string())?;
7124 }
7125
7126 Ok(())
7127 }
7128
7129 fn compile_format_arg(
7131 &mut self,
7132 fn_value: FunctionValue<'ctx>,
7133 scope: &mut CompileScope<'ctx>,
7134 arg_str: &str,
7135 ) -> Result<IntValue<'ctx>, String> {
7136 let arg_str = arg_str.trim();
7137
7138 if let Ok(n) = arg_str.parse::<i64>() {
7140 return Ok(self.context.i64_type().const_int(n as u64, n < 0));
7141 }
7142
7143 if let Some(var) = scope.vars.get(arg_str) {
7145 let loaded = self
7146 .builder
7147 .build_load(self.context.i64_type(), *var, arg_str)
7148 .map_err(|e| e.to_string())?;
7149 return Ok(loaded.into_int_value());
7150 }
7151
7152 let mut parser = Parser::new(arg_str);
7154 if let Ok(expr) = parser.parse_expr() {
7155 return self.compile_expr(fn_value, scope, &expr);
7156 }
7157
7158 Ok(self.context.i64_type().const_int(0, false))
7160 }
7161
7162 fn create_global_string(&self, s: &str, name: &str) -> PointerValue<'ctx> {
7164 let counter = self.string_counter.get();
7165 self.string_counter.set(counter + 1);
7166 let unique_name = format!("{}_{}", name, counter);
7167
7168 let string_val = self.context.const_string(s.as_bytes(), true);
7170 let global = self
7171 .module
7172 .add_global(string_val.get_type(), None, &unique_name);
7173 global.set_initializer(&string_val);
7174 global.set_constant(true);
7175 global.set_linkage(inkwell::module::Linkage::Private);
7176
7177 global.as_pointer_value()
7179 }
7180
7181 fn process_use(&mut self, use_decl: &ast::UseDecl) -> Result<(), String> {
7183 self.process_use_tree(&use_decl.tree, &[])
7184 }
7185
7186 fn process_use_tree(
7188 &mut self,
7189 tree: &ast::UseTree,
7190 prefix: &[String],
7191 ) -> Result<(), String> {
7192 match tree {
7193 ast::UseTree::Path {
7194 prefix: ident,
7195 suffix,
7196 } => {
7197 let mut new_prefix = prefix.to_vec();
7198 new_prefix.push(ident.name.clone());
7199 self.process_use_tree(suffix, &new_prefix)
7200 }
7201 ast::UseTree::Name(ident) => {
7202 let mut full_path = prefix.to_vec();
7203 full_path.push(ident.name.clone());
7204 let full_name = full_path.join("::");
7205 self.use_aliases.insert(ident.name.clone(), full_name);
7206 Ok(())
7207 }
7208 ast::UseTree::Rename { name, alias } => {
7209 let mut full_path = prefix.to_vec();
7210 full_path.push(name.name.clone());
7211 let full_name = full_path.join("::");
7212 self.use_aliases.insert(alias.name.clone(), full_name);
7213 Ok(())
7214 }
7215 ast::UseTree::Glob => Ok(()),
7216 ast::UseTree::Group(trees) => {
7217 for sub_tree in trees {
7218 self.process_use_tree(sub_tree, prefix)?;
7219 }
7220 Ok(())
7221 }
7222 }
7223 }
7224
7225 fn process_module(&mut self, module: &ast::Module) -> Result<(), String> {
7227 let saved_module = self.current_module.clone();
7228 self.current_module.push(module.name.name.clone());
7229
7230 if let Some(ref items) = module.items {
7231 for spanned_item in items {
7232 match &spanned_item.node {
7233 Item::Function(func) => {
7234 self.declare_function(func)?;
7235 }
7236 Item::Module(m) => {
7237 self.process_module(m)?;
7238 }
7239 Item::Use(u) => {
7240 self.process_use(u)?;
7241 }
7242 _ => {}
7243 }
7244 }
7245 }
7246
7247 self.current_module = saved_module;
7248 Ok(())
7249 }
7250
7251 fn compile_module_functions(&mut self, module: &ast::Module) -> Result<(), String> {
7253 let saved_module = self.current_module.clone();
7254 self.current_module.push(module.name.name.clone());
7255
7256 if let Some(ref items) = module.items {
7257 for spanned_item in items {
7258 match &spanned_item.node {
7259 Item::Function(func) => {
7260 self.compile_function(func)?;
7261 }
7262 Item::Module(m) => {
7263 self.compile_module_functions(m)?;
7264 }
7265 _ => {}
7266 }
7267 }
7268 }
7269
7270 self.current_module = saved_module;
7271 Ok(())
7272 }
7273
7274 fn run_llvm_optimizations(&self) -> Result<(), String> {
7276 Target::initialize_all(&InitializationConfig::default());
7277
7278 let triple = TargetMachine::get_default_triple();
7279 let target = Target::from_triple(&triple).map_err(|e| e.to_string())?;
7280
7281 let cpu = TargetMachine::get_host_cpu_name();
7283 let features = TargetMachine::get_host_cpu_features();
7284
7285 let target_machine = target
7286 .create_target_machine(
7287 &triple,
7288 cpu.to_str().unwrap_or("native"),
7289 features.to_str().unwrap_or(""),
7290 OptimizationLevel::Aggressive,
7291 RelocMode::Default,
7292 CodeModel::Default,
7293 )
7294 .ok_or("Failed to create target machine")?;
7295
7296 let passes = match self.opt_level {
7299 OptLevel::None => "default<O0>",
7300 OptLevel::Basic => "default<O1>",
7301 OptLevel::Standard | OptLevel::Size => "default<O2>",
7302 OptLevel::Aggressive => "default<O3>",
7304 };
7305
7306 self.module
7307 .run_passes(passes, &target_machine, PassBuilderOptions::create())
7308 .map_err(|e| e.to_string())?;
7309
7310 Ok(())
7311 }
7312
7313 pub fn run(&mut self) -> Result<i64, String> {
7315 Target::initialize_x86(&InitializationConfig::default());
7317
7318 if let Err(msg) = self.module.verify() {
7320 return Err(format!("Module verification failed: {}", msg.to_string()));
7321 }
7322
7323 let ee = self
7325 .module
7326 .create_jit_execution_engine(OptimizationLevel::Aggressive)
7327 .map_err(|e| e.to_string())?;
7328
7329 if let Some(f) = self.module.get_function("sigil_now") {
7331 ee.add_global_mapping(&f, sigil_now as usize);
7332 }
7333 if let Some(f) = self.module.get_function("sigil_print_int") {
7334 ee.add_global_mapping(&f, sigil_print_int as usize);
7335 }
7336
7337 if let Some(f) = self.module.get_function("sigil_sqrt") {
7339 ee.add_global_mapping(&f, sigil_sqrt as usize);
7340 }
7341 if let Some(f) = self.module.get_function("sigil_sin") {
7342 ee.add_global_mapping(&f, sigil_sin as usize);
7343 }
7344 if let Some(f) = self.module.get_function("sigil_cos") {
7345 ee.add_global_mapping(&f, sigil_cos as usize);
7346 }
7347 if let Some(f) = self.module.get_function("sigil_tan") {
7348 ee.add_global_mapping(&f, sigil_tan as usize);
7349 }
7350 if let Some(f) = self.module.get_function("sigil_exp") {
7351 ee.add_global_mapping(&f, sigil_exp as usize);
7352 }
7353 if let Some(f) = self.module.get_function("sigil_ln") {
7354 ee.add_global_mapping(&f, sigil_ln as usize);
7355 }
7356 if let Some(f) = self.module.get_function("sigil_pow") {
7357 ee.add_global_mapping(&f, sigil_pow as usize);
7358 }
7359 if let Some(f) = self.module.get_function("sigil_floor") {
7360 ee.add_global_mapping(&f, sigil_floor as usize);
7361 }
7362 if let Some(f) = self.module.get_function("sigil_ceil") {
7363 ee.add_global_mapping(&f, sigil_ceil as usize);
7364 }
7365 if let Some(f) = self.module.get_function("sigil_abs") {
7366 ee.add_global_mapping(&f, sigil_abs as usize);
7367 }
7368 if let Some(f) = self.module.get_function("sigil_min") {
7369 ee.add_global_mapping(&f, sigil_min as usize);
7370 }
7371 if let Some(f) = self.module.get_function("sigil_max") {
7372 ee.add_global_mapping(&f, sigil_max as usize);
7373 }
7374
7375 if let Some(f) = self.module.get_function("sigil_vec_new") {
7377 ee.add_global_mapping(&f, sigil_vec_new as usize);
7378 }
7379 if let Some(f) = self.module.get_function("sigil_vec_push") {
7380 ee.add_global_mapping(&f, sigil_vec_push as usize);
7381 }
7382 if let Some(f) = self.module.get_function("sigil_vec_get") {
7383 ee.add_global_mapping(&f, sigil_vec_get as usize);
7384 }
7385 if let Some(f) = self.module.get_function("sigil_vec_len") {
7386 ee.add_global_mapping(&f, sigil_vec_len as usize);
7387 }
7388
7389 if let Some(f) = self.module.get_function("sigil_string_new") {
7391 ee.add_global_mapping(&f, sigil_string_new as usize);
7392 }
7393 if let Some(f) = self.module.get_function("sigil_string_from") {
7394 ee.add_global_mapping(&f, sigil_string_from as usize);
7395 }
7396 if let Some(f) = self.module.get_function("sigil_string_len") {
7397 ee.add_global_mapping(&f, sigil_string_len as usize);
7398 }
7399 if let Some(f) = self.module.get_function("sigil_string_print") {
7400 ee.add_global_mapping(&f, sigil_string_print as usize);
7401 }
7402 if let Some(f) = self.module.get_function("sigil_string_concat") {
7403 ee.add_global_mapping(&f, sigil_string_concat as usize);
7404 }
7405
7406 if let Some(f) = self.module.get_function("sigil_option_some") {
7408 ee.add_global_mapping(&f, sigil_option_some as usize);
7409 }
7410 if let Some(f) = self.module.get_function("sigil_option_none") {
7411 ee.add_global_mapping(&f, sigil_option_none as usize);
7412 }
7413 if let Some(f) = self.module.get_function("sigil_option_is_some") {
7414 ee.add_global_mapping(&f, sigil_option_is_some as usize);
7415 }
7416 if let Some(f) = self.module.get_function("sigil_option_is_none") {
7417 ee.add_global_mapping(&f, sigil_option_is_none as usize);
7418 }
7419 if let Some(f) = self.module.get_function("sigil_option_unwrap") {
7420 ee.add_global_mapping(&f, sigil_option_unwrap as usize);
7421 }
7422 if let Some(f) = self.module.get_function("sigil_option_unwrap_or") {
7423 ee.add_global_mapping(&f, sigil_option_unwrap_or as usize);
7424 }
7425
7426 if let Some(f) = self.module.get_function("sigil_file_exists") {
7428 ee.add_global_mapping(&f, sigil_file_exists as usize);
7429 }
7430 if let Some(f) = self.module.get_function("sigil_file_read_all") {
7431 ee.add_global_mapping(&f, sigil_file_read_all as usize);
7432 }
7433 if let Some(f) = self.module.get_function("sigil_file_write_all") {
7434 ee.add_global_mapping(&f, sigil_file_write_all as usize);
7435 }
7436
7437 self.execution_engine = Some(ee);
7438
7439 unsafe {
7441 let main: JitFunction<MainFn> = self
7442 .execution_engine
7443 .as_ref()
7444 .unwrap()
7445 .get_function("main")
7446 .map_err(|e| e.to_string())?;
7447
7448 Ok(main.call())
7449 }
7450 }
7451
7452 pub fn write_object_file(&self, path: &Path) -> Result<(), String> {
7454 Target::initialize_all(&InitializationConfig::default());
7455
7456 let triple = TargetMachine::get_default_triple();
7457 let target = Target::from_triple(&triple).map_err(|e| e.to_string())?;
7458 let target_machine = target
7459 .create_target_machine(
7460 &triple,
7461 "generic",
7462 "",
7463 OptimizationLevel::Aggressive,
7464 RelocMode::PIC, CodeModel::Default,
7466 )
7467 .ok_or("Failed to create target machine")?;
7468
7469 target_machine
7470 .write_to_file(&self.module, FileType::Object, path)
7471 .map_err(|e| e.to_string())
7472 }
7473
7474 pub fn get_ir(&self) -> String {
7476 self.module.print_to_string().to_string()
7477 }
7478 }
7479
7480 struct CompileScope<'ctx> {
7482 vars: HashMap<String, PointerValue<'ctx>>,
7483 }
7484
7485 impl<'ctx> CompileScope<'ctx> {
7486 fn new() -> Self {
7487 Self {
7488 vars: HashMap::new(),
7489 }
7490 }
7491 }
7492
7493 #[cfg(test)]
7497 mod tests {
7498 use super::*;
7499 use crate::optimize::OptLevel;
7500
7501 fn run_sigil(source: &str) -> Result<i64, String> {
7502 let context = Context::create();
7503 let mut compiler = LlvmCompiler::new(&context, OptLevel::Standard)?;
7504 compiler.compile(source)?;
7505 compiler.run()
7506 }
7507
7508 #[test]
7513 fn test_evidential_known_unwrap() {
7514 let result = run_sigil(
7516 r#"
7517 rite main() -> i64 {
7518 ≔ x = 42!;
7519 x
7520 }
7521 "#,
7522 );
7523 assert_eq!(result.unwrap(), 42);
7524 }
7525
7526 #[test]
7527 fn test_evidential_uncertain() {
7528 let result = run_sigil(
7530 r#"
7531 rite main() -> i64 {
7532 ≔ x = 100?;
7533 x
7534 }
7535 "#,
7536 );
7537 assert_eq!(result.unwrap(), 100);
7538 }
7539
7540 #[test]
7541 fn test_evidential_reported() {
7542 let result = run_sigil(
7544 r#"
7545 rite main() -> i64 {
7546 ≔ x = 200~;
7547 x
7548 }
7549 "#,
7550 );
7551 assert_eq!(result.unwrap(), 200);
7552 }
7553
7554 #[test]
7555 fn test_evidential_predicted() {
7556 let result = run_sigil(
7558 r#"
7559 rite main() -> i64 {
7560 ≔ x = 300◊;
7561 x
7562 }
7563 "#,
7564 );
7565 assert_eq!(result.unwrap(), 300);
7566 }
7567
7568 #[test]
7569 fn test_evidential_in_expression() {
7570 let result = run_sigil(
7572 r#"
7573 rite main() -> i64 {
7574 ≔ a = 10?;
7575 ≔ b = 20?;
7576 a + b
7577 }
7578 "#,
7579 );
7580 assert_eq!(result.unwrap(), 30);
7581 }
7582
7583 #[test]
7584 fn test_evidential_unwrap_chain() {
7585 let result = run_sigil(
7587 r#"
7588 rite main() -> i64 {
7589 ≔ x = 42?;
7590 ≔ y = x!;
7591 y
7592 }
7593 "#,
7594 );
7595 assert_eq!(result.unwrap(), 42);
7596 }
7597
7598 #[test]
7599 fn test_evidential_nested() {
7600 let result = run_sigil(
7602 r#"
7603 rite main() -> i64 {
7604 ≔ x = (50?)!;
7605 x + 5
7606 }
7607 "#,
7608 );
7609 assert_eq!(result.unwrap(), 55);
7610 }
7611
7612 #[test]
7613 fn test_evidential_with_arithmetic() {
7614 let result = run_sigil(
7616 r#"
7617 rite main() -> i64 {
7618 ≔ known = 100!;
7619 ≔ uncertain = 50?;
7620 known + uncertain * 2
7621 }
7622 "#,
7623 );
7624 assert_eq!(result.unwrap(), 200);
7625 }
7626
7627 #[test]
7628 fn test_evidential_function_return() {
7629 let result = run_sigil(
7631 r#"
7632 rite get_uncertain() -> i64 {
7633 42?
7634 }
7635
7636 rite main() -> i64 {
7637 ≔ x = get_uncertain();
7638 x + 8
7639 }
7640 "#,
7641 );
7642 assert_eq!(result.unwrap(), 50);
7643 }
7644
7645 #[test]
7646 fn test_evidential_mixed_markers() {
7647 let result = run_sigil(
7649 r#"
7650 rite main() -> i64 {
7651 ≔ a = 10!; // known
7652 ≔ b = 20?; // uncertain
7653 ≔ c = 30~; // reported
7654 a + b + c
7655 }
7656 "#,
7657 );
7658 assert_eq!(result.unwrap(), 60);
7659 }
7660
7661 #[test]
7662 fn test_evidential_in_if() {
7663 let result = run_sigil(
7665 r#"
7666 rite main() -> i64 {
7667 ≔ x = 1?;
7668 ⎇ x == 1 {
7669 100?
7670 } ⎉ {
7671 200?
7672 }
7673 }
7674 "#,
7675 );
7676 assert_eq!(result.unwrap(), 100);
7677 }
7678
7679 #[test]
7680 fn test_evidential_paradox() {
7681 let result = run_sigil(
7683 r#"
7684 rite main() -> i64 {
7685 ≔ x = 42‽;
7686 x
7687 }
7688 "#,
7689 );
7690 assert_eq!(result.unwrap(), 42);
7691 }
7692
7693 #[test]
7694 fn test_evidential_multiple_unwraps() {
7695 let result = run_sigil(
7697 r#"
7698 rite main() -> i64 {
7699 ≔ a = 10?;
7700 ≔ b = a!;
7701 ≔ c = b!;
7702 c
7703 }
7704 "#,
7705 );
7706 assert_eq!(result.unwrap(), 10);
7707 }
7708
7709 #[test]
7710 fn test_evidential_in_loop() {
7711 let result = run_sigil(
7713 r#"
7714 rite main() -> i64 {
7715 ≔ Δ sum = 0?;
7716 ≔ Δ i = 0;
7717 ⟳ i < 5 {
7718 sum = sum + i?;
7719 i = i + 1;
7720 }
7721 sum!
7722 }
7723 "#,
7724 );
7725 assert_eq!(result.unwrap(), 10); }
7727
7728 #[test]
7729 fn test_evidential_comparison() {
7730 let result = run_sigil(
7732 r#"
7733 rite main() -> i64 {
7734 ≔ a = 10?;
7735 ≔ b = 20?;
7736 ⎇ a < b {
7737 1!
7738 } ⎉ {
7739 0!
7740 }
7741 }
7742 "#,
7743 );
7744 assert_eq!(result.unwrap(), 1);
7745 }
7746
7747 #[test]
7748 fn test_evidential_negation() {
7749 let result = run_sigil(
7751 r#"
7752 rite main() -> i64 {
7753 ≔ x = 42?;
7754 ≔ y = -x;
7755 y + 100
7756 }
7757 "#,
7758 );
7759 assert_eq!(result.unwrap(), 58); }
7761
7762 #[test]
7763 fn test_evidential_chain_operations() {
7764 let result = run_sigil(
7766 r#"
7767 rite main() -> i64 {
7768 ≔ x = 10!;
7769 ≔ y = 20?;
7770 ≔ z = 30~;
7771 ≔ w = 40◊;
7772 x + y + z + w
7773 }
7774 "#,
7775 );
7776 assert_eq!(result.unwrap(), 100);
7777 }
7778
7779 #[test]
7780 fn test_evidential_deeply_nested() {
7781 let result = run_sigil(
7783 r#"
7784 rite main() -> i64 {
7785 ≔ x = ((((42?)?)?)?)?;
7786 x!
7787 }
7788 "#,
7789 );
7790 assert_eq!(result.unwrap(), 42);
7791 }
7792
7793 #[test]
7794 fn test_evidential_struct_field() {
7795 let result = run_sigil(
7797 r#"
7798 Σ Data {
7799 value: i64,
7800 }
7801
7802 rite main() -> i64 {
7803 ≔ d = Data { value: 100? };
7804 d.value + 1
7805 }
7806 "#,
7807 );
7808 assert_eq!(result.unwrap(), 101);
7809 }
7810
7811 #[test]
7812 fn test_evidential_function_param() {
7813 let result = run_sigil(
7815 r#"
7816 rite double(x: i64) -> i64 {
7817 x * 2
7818 }
7819
7820 rite main() -> i64 {
7821 ≔ val = 25?;
7822 double(val!)
7823 }
7824 "#,
7825 );
7826 assert_eq!(result.unwrap(), 50);
7827 }
7828
7829 #[test]
7830 fn test_evidential_all_markers_chain() {
7831 let result = run_sigil(
7833 r#"
7834 rite main() -> i64 {
7835 ≔ known = 1!; // Known
7836 ≔ uncertain = 2?; // Uncertain
7837 ≔ reported = 3~; // Reported
7838 ≔ predicted = 4◊; // Predicted
7839 ≔ paradox = 5‽; // Paradox
7840 known + uncertain + reported + predicted + paradox
7841 }
7842 "#,
7843 );
7844 assert_eq!(result.unwrap(), 15);
7845 }
7846
7847 #[test]
7852 fn test_generic_struct_basic() {
7853 let result = run_sigil(
7854 r#"
7855 Σ Container<T> {
7856 value: T,
7857 count: i32,
7858 }
7859
7860 rite main() -> i64 {
7861 ≔ c = Container·<i32> { value: 42, count: 1 };
7862 c.value + c.count
7863 }
7864 "#,
7865 );
7866 assert_eq!(result.unwrap(), 43);
7867 }
7868
7869 #[test]
7870 fn test_generic_struct_two_params() {
7871 let result = run_sigil(
7872 r#"
7873 Σ Pair<A, B> {
7874 first: A,
7875 second: B,
7876 }
7877
7878 rite main() -> i64 {
7879 ≔ p = Pair·<i32, i32> { first: 10, second: 20 };
7880 p.first + p.second
7881 }
7882 "#,
7883 );
7884 assert_eq!(result.unwrap(), 30);
7885 }
7886
7887 #[test]
7892 fn test_morpheme_first() {
7893 let result = run_sigil(
7895 r#"
7896 rite main() -> i64 {
7897 [10, 20, 30] |α
7898 }
7899 "#,
7900 );
7901 assert_eq!(result.unwrap(), 10);
7902 }
7903
7904 #[test]
7905 fn test_morpheme_last() {
7906 let result = run_sigil(
7908 r#"
7909 rite main() -> i64 {
7910 [10, 20, 30] |ω
7911 }
7912 "#,
7913 );
7914 assert_eq!(result.unwrap(), 30);
7915 }
7916
7917 #[test]
7918 fn test_morpheme_middle() {
7919 let result = run_sigil(
7921 r#"
7922 rite main() -> i64 {
7923 [10, 20, 30, 40, 50] |μ
7924 }
7925 "#,
7926 );
7927 assert_eq!(result.unwrap(), 30);
7928 }
7929
7930 #[test]
7931 fn test_morpheme_nth() {
7932 let result = run_sigil(
7934 r#"
7935 rite main() -> i64 {
7936 [10, 20, 30] |ν{1}
7937 }
7938 "#,
7939 );
7940 assert_eq!(result.unwrap(), 20);
7941 }
7942
7943 #[test]
7948 fn test_morpheme_reduce_min() {
7949 let result = run_sigil(
7951 r#"
7952 rite min2(a: i64, b: i64) -> i64 {
7953 ⎇ a < b { a } ⎉ { b }
7954 }
7955 rite main() -> i64 {
7956 min2(min2(5, 2), min2(8, 1))
7957 }
7958 "#,
7959 );
7960 assert_eq!(result.unwrap(), 1);
7961 }
7962
7963 #[test]
7964 fn test_morpheme_reduce_max() {
7965 let result = run_sigil(
7967 r#"
7968 rite max2(a: i64, b: i64) -> i64 {
7969 ⎇ a > b { a } ⎉ { b }
7970 }
7971 rite main() -> i64 {
7972 max2(max2(5, 2), max2(8, 9))
7973 }
7974 "#,
7975 );
7976 assert_eq!(result.unwrap(), 9);
7977 }
7978
7979 #[test]
7980 fn test_morpheme_reduce_all_true() {
7981 let result = run_sigil(
7983 r#"
7984 rite main() -> i64 {
7985 [1, 2, 3] |ρ&
7986 }
7987 "#,
7988 );
7989 assert_eq!(result.unwrap(), 1);
7990 }
7991
7992 #[test]
7993 fn test_morpheme_reduce_all_false() {
7994 let result = run_sigil(
7996 r#"
7997 rite main() -> i64 {
7998 [1, 0, 3] |ρ&
7999 }
8000 "#,
8001 );
8002 assert_eq!(result.unwrap(), 0);
8003 }
8004
8005 #[test]
8006 fn test_morpheme_reduce_any_true() {
8007 let result = run_sigil(
8009 r#"
8010 rite main() -> i64 {
8011 [0, 0, 1] |ρ|
8012 }
8013 "#,
8014 );
8015 assert_eq!(result.unwrap(), 1);
8016 }
8017
8018 #[test]
8019 fn test_morpheme_reduce_any_false() {
8020 let result = run_sigil(
8022 r#"
8023 rite main() -> i64 {
8024 [0, 0, 0] |ρ|
8025 }
8026 "#,
8027 );
8028 assert_eq!(result.unwrap(), 0);
8029 }
8030
8031 #[test]
8036 fn test_morpheme_transform_then_first() {
8037 let result = run_sigil(
8039 r#"
8040 rite main() -> i64 {
8041 ≔ arr = [1, 2, 3] |τ{|x| x * 10};
8042 arr |α
8043 }
8044 "#,
8045 );
8046 assert!(result.is_ok());
8049 }
8050
8051 #[test]
8052 fn test_morpheme_filter_then_sum() {
8053 let result = run_sigil(
8055 r#"
8056 rite main() -> i64 {
8057 [1, 5, 2, 8, 3, 7] |φ{|x| x > 3} |ρ+
8058 }
8059 "#,
8060 );
8061 assert_eq!(result.unwrap(), 20);
8063 }
8064
8065 #[test]
8070 fn test_morpheme_sort_basic() {
8071 let result = run_sigil(
8073 r#"
8074 rite main() -> i64 {
8075 [3, 1, 2] |σ
8076 }
8077 "#,
8078 );
8079 assert_eq!(result.unwrap(), 1);
8080 }
8081
8082 #[test]
8083 fn test_morpheme_sort_already_sorted() {
8084 let result = run_sigil(
8086 r#"
8087 rite main() -> i64 {
8088 [1, 2, 3] |σ
8089 }
8090 "#,
8091 );
8092 assert_eq!(result.unwrap(), 1);
8093 }
8094
8095 #[test]
8096 fn test_morpheme_sort_reverse() {
8097 let result = run_sigil(
8099 r#"
8100 rite main() -> i64 {
8101 [5, 4, 3, 2, 1] |σ
8102 }
8103 "#,
8104 );
8105 assert_eq!(result.unwrap(), 1);
8106 }
8107
8108 #[test]
8109 fn test_morpheme_sort_single() {
8110 let result = run_sigil(
8112 r#"
8113 rite main() -> i64 {
8114 [42] |σ
8115 }
8116 "#,
8117 );
8118 assert_eq!(result.unwrap(), 42);
8119 }
8120
8121 #[test]
8122 fn test_morpheme_choice_deterministic() {
8123 let result = run_sigil(
8125 r#"
8126 rite main() -> i64 {
8127 [10, 20, 30] |χ
8128 }
8129 "#,
8130 );
8131 let val = result.unwrap();
8133 assert!(val == 10 || val == 20 || val == 30);
8134 }
8135
8136 #[test]
8137 fn test_morpheme_choice_single() {
8138 let result = run_sigil(
8140 r#"
8141 rite main() -> i64 {
8142 [42] |χ
8143 }
8144 "#,
8145 );
8146 assert_eq!(result.unwrap(), 42);
8147 }
8148
8149 #[test]
8150 fn test_morpheme_custom_reduce_sum() {
8151 let result = run_sigil(
8153 r#"
8154 rite main() -> i64 {
8155 [1, 2, 3, 4] |ρ{|acc, x| acc + x}
8156 }
8157 "#,
8158 );
8159 assert_eq!(result.unwrap(), 10);
8160 }
8161
8162 #[test]
8163 fn test_morpheme_custom_reduce_product() {
8164 let result = run_sigil(
8166 r#"
8167 rite main() -> i64 {
8168 [1, 2, 3, 4] |ρ{|acc, x| acc * x}
8169 }
8170 "#,
8171 );
8172 assert_eq!(result.unwrap(), 24);
8173 }
8174
8175 #[test]
8176 fn test_morpheme_custom_reduce_difference() {
8177 let result = run_sigil(
8179 r#"
8180 rite main() -> i64 {
8181 [100, 20, 5] |ρ{|acc, x| acc - x}
8182 }
8183 "#,
8184 );
8185 assert_eq!(result.unwrap(), 75);
8186 }
8187
8188 #[test]
8189 fn test_morpheme_custom_reduce_single() {
8190 let result = run_sigil(
8192 r#"
8193 rite main() -> i64 {
8194 [42] |ρ{|acc, x| acc + x}
8195 }
8196 "#,
8197 );
8198 assert_eq!(result.unwrap(), 42);
8199 }
8200
8201 #[test]
8202 fn test_morpheme_await_expr() {
8203 let result = run_sigil(
8205 r#"
8206 rite main() -> i64 {
8207 ≔ x = 42;
8208 x⌛
8209 }
8210 "#,
8211 );
8212 assert_eq!(result.unwrap(), 42);
8214 }
8215
8216 #[test]
8217 fn test_morpheme_await_nested() {
8218 let result = run_sigil(
8220 r#"
8221 rite main() -> i64 {
8222 ≔ x = 21;
8223 ≔ y = x⌛ + x⌛;
8224 y
8225 }
8226 "#,
8227 );
8228 assert_eq!(result.unwrap(), 42);
8229 }
8230 }
8231}