From d0a9b6bd2171d4e63257202d7cb02c70607f5f85 Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 13 Jul 2025 00:53:23 +0530 Subject: [PATCH 01/14] Update: Added Compiler Test Examples --- examples/compile_test.de | 4 ++++ examples/hello_compiled.de | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 examples/compile_test.de create mode 100644 examples/hello_compiled.de diff --git a/examples/compile_test.de b/examples/compile_test.de new file mode 100644 index 0000000..9d22052 --- /dev/null +++ b/examples/compile_test.de @@ -0,0 +1,4 @@ +let x be 10 +let y be 5 +let result be x + y * 2 +show result \ No newline at end of file diff --git a/examples/hello_compiled.de b/examples/hello_compiled.de new file mode 100644 index 0000000..2ec302a --- /dev/null +++ b/examples/hello_compiled.de @@ -0,0 +1,3 @@ +show "Hello, compiled Delta language!" +let message be "This is a message from the compiled code." +show message \ No newline at end of file From 44c53e2c9eb7ce2e70e8c3c2e4b451a9470bbf06 Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 13 Jul 2025 01:01:30 +0530 Subject: [PATCH 02/14] Update: Added Compiler Dependencies, Refactored Codegen from Beginning. --- Cargo.toml | 9 ++++ src/codegen.rs | 123 +++++++++---------------------------------------- 2 files changed, 32 insertions(+), 100 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b1077bc..3c1d113 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,14 @@ name = "delta" version = "1.0.0" edition = "2024" +description = "Delta - A natural language inspired programming language" +authors = ["Pranav Verma "] + +[[bin]] +name = delta +path = "src/main.rs" [dependencies] +inkwell = { version = "0.4", features = ["llvm17-0"] } +# Future dependencies for LLVM backend +# llvm-sys = "170" diff --git a/src/codegen.rs b/src/codegen.rs index a613bea..06ac026 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,107 +1,30 @@ use crate::ast::*; use std::collections::HashMap; +use inkwell::context::Context; +use inkwell::builder::Builder; +use inkwell::module::Module; +use inkwell::values::{FloatValue, FunctionValue, PointerValue}; +use inkwell::types::FloatType; +use inkwell::FloatPredicate; +use std::error::Error; +use std::fmt; -pub struct CodeGenerator { - variables: HashMap, +#[derive(Debug)] +pub struct CodegenError { + message: String, } -impl CodeGenerator { - pub fn new() -> Self { - CodeGenerator { - variables: HashMap::new(), - } - } - - pub fn generate(&mut self, _program: &Program) -> Result<(), String> { - // TODO: Add LLVM IR Generation Code. - // For now, we wil just interpret the AST. - println!("Code generation not yet implemented - use interpreter"); - Ok(()) - } - - pub fn interpret(&mut self, program: &Program) -> Result<(), String> { - for statement in &program.statements { - self.interpret_statement(statement)?; - } - Ok(()) - } - - fn interpret_statement(&mut self, statement: &Statement) -> Result<(), String> { - match statement { - Statement::Show(show) => { - let value = self.evaluate_expression(&show.value)?; - println!("{}", value); - } - Statement::Let(let_stmt) => { - let value = self.evaluate_expression(&let_stmt.value)?; - self.variables.insert(let_stmt.identifier.clone(), value); - } - Statement::When(when_stmt) => { - let condition_result = self.evaluate_expression(&when_stmt.condition)?; - // For now, simple string-based evaluation - if condition_result.contains("true") || condition_result.contains("True") { - for stmt in &when_stmt.then_block { - self.interpret_statement(stmt)?; - } - } else if let Some(otherwise_block) = &when_stmt.otherwise_block { - for stmt in otherwise_block { - self.interpret_statement(stmt)?; - } - } - } - Statement::FunctionDef(func_def) => { - println!("Defined function: {}", func_def.name); - } - Statement::Expression(expr) => { - let _value = self.evaluate_expression(expr)?; - // Expression statements don't print by default - } - } - Ok(()) - } - - fn evaluate_expression(&mut self, expression: &Expression) -> Result { - match expression { - Expression::Number(n) => Ok(n.to_string()), - Expression::String(s) => Ok(s.clone()), - Expression::Identifier(name) => { - if let Some(value) = self.variables.get(name) { - Ok(value.clone()) - } else { - Ok(format!("", name)) - } - } - Expression::BinaryOp(binop) => { - let left_val = self.evaluate_expression(&binop.left)?; - let right_val = self.evaluate_expression(&binop.right)?; - - // Try to parse as numbers for comparison and arithmetic - if let (Ok(left_num), Ok(right_num)) = (left_val.parse::(), right_val.parse::()) { - let result = match binop.operator { - BinaryOperator::GreaterThan => return Ok((left_num > right_num).to_string()), - BinaryOperator::LessThan => return Ok((left_num < right_num).to_string()), - BinaryOperator::GreaterThanOrEqual => return Ok((left_num >= right_num).to_string()), - BinaryOperator::LessThanOrEqual => return Ok((left_num <= right_num).to_string()), - BinaryOperator::Equal => return Ok(((left_num - right_num).abs() < f64::EPSILON).to_string()), - BinaryOperator::NotEqual => return Ok(((left_num - right_num).abs() >= f64::EPSILON).to_string()), - BinaryOperator::Add => left_num + right_num, - BinaryOperator::Subtract => left_num - right_num, - BinaryOperator::Multiply => left_num * right_num, - BinaryOperator::Divide => { - if right_num == 0.0 { - return Err("Division by zero".to_string()); - } - left_num / right_num - } - }; - Ok(result.to_string()) - } else { - Ok(format!("({} {:?} {})", left_val, binop.operator, right_val)) - } - } - Expression::FunctionCall(call) => { - Ok(format!("", call.name)) - } - } +impl fmt::Display for CodegenError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.message) } +} + +impl Error for CodegenError {} + +pub struct CodeGenerator<'ctx> { + context: &'ctx Context, + module: Module<'ctx>, + builder: Builder<'ctx>, + variables: Hashmap>, } \ No newline at end of file From 7af9bec72406e9f516686bf16af635d6835d5554 Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 13 Jul 2025 12:46:08 +0530 Subject: [PATCH 03/14] Update: Enhance code generation with new CodeGenerator struct and methods for LLVM IR generation --- Cargo.lock | 154 +++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- src/codegen.rs | 82 ++++++++++++++++++++++++++ 3 files changed, 237 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index b4a0dc5..a28c954 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,160 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "cc" +version = "1.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +dependencies = [ + "shlex", +] + [[package]] name = "delta" version = "1.0.0" +dependencies = [ + "inkwell", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "inkwell" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b597a7b2cdf279aeef6d7149071e35e4bc87c2cf05a5b7f2d731300bffe587ea" +dependencies = [ + "either", + "inkwell_internals", + "libc", + "llvm-sys", + "once_cell", + "thiserror", +] + +[[package]] +name = "inkwell_internals" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa4d8d74483041a882adaa9a29f633253a66dde85055f0495c121620ac484b2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "llvm-sys" +version = "170.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1ee92492ae76bb6e24495ce15e311ba13ffb58c0140d89ac9910b92477cec8" +dependencies = [ + "anyhow", + "cc", + "lazy_static", + "libc", + "regex-lite", + "semver", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/Cargo.toml b/Cargo.toml index 3c1d113..9427a5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ description = "Delta - A natural language inspired programming language" authors = ["Pranav Verma "] [[bin]] -name = delta +name = "delta" path = "src/main.rs" [dependencies] diff --git a/src/codegen.rs b/src/codegen.rs index 06ac026..88f66e9 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -27,4 +27,86 @@ pub struct CodeGenerator<'ctx> { module: Module<'ctx>, builder: Builder<'ctx>, variables: Hashmap>, +} + +impl<'ctx> CodeGenerator<'ctx> { + pub fn new(context: &'ctx Context, module_name: &str) -> Result> { + let module = context.create_module(module_name); + let builder = context.create_builder(); + + Ok(CodeGenerator { + context, + module, + builder, + variables: HashMap::new(), + }) + } + + fn get_float_type(&self) -> FloatType<'ctx> { + self.context.f64_type() + } + + pub fn compile(&mu self, program: &Program) -> Result<(), Box> { + let main_type = self.context.i32_type().fn_type(&[], false); + let main_fn = self.module.add_function("main", main_type, None); + let basic_block = self.context.append_basic_block(main_fn, "entry"); + self.builder.position_at_end(basic_block); + + self.add_printf_declaration(); + + for statement in &program.statements { + self.compile_statement(statement)?; + } + + let return_value = self.context.i32_type().const_int(0, false); + self.builder.build_return(Some(&return_value))?; + + if let Err(errors) = self.module.verify() { + return Err(Box::new(CodegenError { + message: format!("Module verification failed: {}", errors), + })); + } + + println!("LLVM IR generated successfully!") + self.module.print_to_stderr(); + Ok(()) + } + + fn add_printf_declaration(&mut self) { + let i8_type = self.context.i8_type(); + let i8_ptr_type = i8_type.ptr_type(inkwell::AddressSpace::default()); + let printf_type = self.context.i32_type().fn_type(&[i8_ptr_type.into()], true); + + self.module.add_function("printf", printf_type, None); + } + + fn compile_statement(&mut self, statement: &Statement) -> Result<(), Box> { + match statement { + Statement::Let(let_stmt) => { + let value - self.compile_expression(&let_stmt.value)?; + + let alloc_s = self.builder.build_alloca(self.get_float_type(), &let_stmt.identifier)?; + self.builder.build_store(alloc_s, value); + self.variables.insert(let_stmt.identifier.clone(), alloc_s); + } + Statement::Show(show_stmt) => { + let value = self.compile_expression(&show_stmt.value)?; + self.generate_print_call(value)?; + } + Statement::When(when_stmt) => { + self.compile_when_statement(when_stmt)?; + } + Statement::FunctionDef(_) => { + // TODO: Implement function definitions + println!("Function definitions not yet implemented in Compiler"); + } + Statement::Expression(expr) => { + self.compile_expression(expr)?; + } + } + + Ok(()) + } + + // TO ADD ALL FUNCTIONS IN THE ABOVE FUNCTION. } \ No newline at end of file From f8a9a7e6dafc5e47bdbf7f96a2812d7435b0f20c Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Fri, 18 Jul 2025 00:57:45 +0530 Subject: [PATCH 04/14] Update: Implement compile_when_statement for conditional statement handling in code generation --- src/codegen.rs | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/codegen.rs b/src/codegen.rs index 88f66e9..9dfbbe9 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -108,5 +108,46 @@ impl<'ctx> CodeGenerator<'ctx> { Ok(()) } - // TO ADD ALL FUNCTIONS IN THE ABOVE FUNCTION. + // TODO: TO ADD ALL FUNCTIONS IN THE ABOVE FUNCTION. + + fn compile_when_statement(&mut self, when_stmt: &WhenStatement) -> Result<(), Box> { + let condition = self.compile_expression(&when_stmt.condition)?; + + let current_fn = self.builder.get_insert_block().unwrap().get_parent().unwrap(); + let then_block = self.context.append_basic_block(current_fn, "then"); + let else_block = self.context.append_basic_block(current_fn, "else"); + let merge_block = self.context.append_basic_block(current_fn, "merge"); + + // convert it to a bool (assume float) + let zero = self.get_float_type().const_float(0.0); + let cond_bool = self.builder.build_float_compare( + FloatPredicate::ONE, // not equal to zero (true mf) + condition, + zero, + "cond" + )?; + + self.builder.build_conditional_branch(cond_bool, then_block, else_block)?; + + // then block compilation + self.builder.position_at_end(then_block); + for stmt in &when_stmt.then_block { + self.compile_statement(stmt)?; + } + self.builder.build_unconditional_branch(merge_block)?; + + // else block compilation + self.builder.position_at_end(else_block); + if let Some(otherwise_block) = &when_stmt.otherwise_block { + for stmt in otherwise_block { + self.compile_statement(stmt)?; + } + } + self.builder.build_unconditional_branch(merge_block)?; + + // continue + self.builder.position_at_end(merge_block); + + Ok(()) + } } \ No newline at end of file From 7697fc9d24d7fa909c7270e0da07bb3a72a4a530 Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Fri, 18 Jul 2025 01:05:33 +0530 Subject: [PATCH 05/14] Update: Implement compile_expression method for handling various expression types in code generation --- src/codegen.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/codegen.rs b/src/codegen.rs index 9dfbbe9..4431850 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -150,4 +150,86 @@ impl<'ctx> CodeGenerator<'ctx> { Ok(()) } + + fn compile_expression(&mut self, expr: &Expression) -> Result, Box> { + match expr { + Expression::Number(n) => { + Ok(self.get_float_type().const_float(*n)) + } + Expression::String(s) => { + // TODO: we need special handling for output, for now print it directly. + + let printf_fn = self.module.get_function("printf").unwrap(); + let string_ptr = self.builder.build_global_string_ptr(&format!("{}\n", s), "str")?; + + self.builder.build_call(printf_fn, &[string_ptr.as_pointer_value().into(), "printf_string"], name)?; + + // return 0 as the numeric value + Ok(self.get_float_type().const_float(0.0)) + } + Expression::Identifier(name) => { + if let Some(alloca) = self.variables.get(name) { + let loaded = self.builder.build_load(self.get_float_type(), *alloca, name)?; + Ok(loaded.into_float_value()) + } else { + Err(Box::new(CodegenError { + message: format!("Undefined variable: {}", name), + })) + } + } + Expression::BinaryOp(binop) => { + let left = self.compile_expression(&binop.left)?; + let right = self.compile_expression(&binop.right)?; + + match binop.operator { // This Match Statement is generated by AI (I aint writing this shit by hand) + BinaryOperator::Add => { + Ok(self.builder.build_float_add(left, right, "add")?) + } + BinaryOperator::Subtract => { + Ok(self.builder.build_float_sub(left, right, "sub")?) + } + BinaryOperator::Multiply => { + Ok(self.builder.build_float_mul(left, right, "mul")?) + } + BinaryOperator::Divide => { + Ok(self.builder.build_float_div(left, right, "div")?) + } + BinaryOperator::GreaterThan => { + let cmp = self.builder.build_float_compare(FloatPredicate::OGT, left, right, "gt")?; + let result = self.builder.build_unsigned_int_to_float(cmp, self.get_float_type(), "gt_float")?; + Ok(result) + } + BinaryOperator::LessThan => { + let cmp = self.builder.build_float_compare(FloatPredicate::OLT, left, right, "lt")?; + let result = self.builder.build_unsigned_int_to_float(cmp, self.get_float_type(), "lt_float")?; + Ok(result) + } + BinaryOperator::GreaterThanOrEqual => { + let cmp = self.builder.build_float_compare(FloatPredicate::OGE, left, right, "gte")?; + let result = self.builder.build_unsigned_int_to_float(cmp, self.get_float_type(), "gte_float")?; + Ok(result) + } + BinaryOperator::LessThanOrEqual => { + let cmp = self.builder.build_float_compare(FloatPredicate::OLE, left, right, "lte")?; + let result = self.builder.build_unsigned_int_to_float(cmp, self.get_float_type(), "lte_float")?; + Ok(result) + } + BinaryOperator::Equal => { + let cmp = self.builder.build_float_compare(FloatPredicate::OEQ, left, right, "eq")?; + let result = self.builder.build_unsigned_int_to_float(cmp, self.get_float_type(), "eq_float")?; + Ok(result) + } + BinaryOperator::NotEqual => { + let cmp = self.builder.build_float_compare(FloatPredicate::ONE, left, right, "ne")?; + let result = self.builder.build_unsigned_int_to_float(cmp, self.get_float_type(), "ne_float")?; + Ok(result) + } + } + } + Expression::FunctionCall(_) => { + // TODO: Implement function calls + Ok(self.get_float_type().const_float(0.0)) + } + } + } } \ No newline at end of file From 2b71a6bc6b1f137bb8c833a59e1c5f50822047d7 Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 3 Aug 2025 01:58:50 +0530 Subject: [PATCH 06/14] Update: Add `generate_print_call `method for printing float values and enhance `save_to_file` functionality --- src/codegen.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/codegen.rs b/src/codegen.rs index 4431850..7ca9ae2 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -232,4 +232,24 @@ impl<'ctx> CodeGenerator<'ctx> { } } } + + fn generate_print_call(&mut self, value: FloatValue<'ctx>) -> Result<(), Box> { + let print_fn = self.module.get_function("printf").unwrap(); + + // create format str for print floatrs + let format_str = self.builder.build_global_string_ptr("%.2f\n", "fmt")?; + + self.builder.build_Call( + print_fn, + &[format_str.as_pointer_value().into(), value.into()], + "printf_call" + )?; + + Ok(()) + } + + pub fn save_to_file(&self, filename: &str) -> Result<(), Box> { + self.module.print_to_file(filename)?; + Ok(()) + } } \ No newline at end of file From a9c5c1465cf0fa3997320c0761094b62f1c9b469 Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 3 Aug 2025 01:59:13 +0530 Subject: [PATCH 07/14] Update: Add `interpret` method for executing program statements with variable tracking --- src/codegen.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/codegen.rs b/src/codegen.rs index 7ca9ae2..7da8257 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -252,4 +252,14 @@ impl<'ctx> CodeGenerator<'ctx> { self.module.print_to_file(filename)?; Ok(()) } + + // keeping the int. for comp. + pub fn interpret(&mut self, program: &Program) -> Result<(), String> { + let mut interpreter_vars: HashMap = HashMap::new(); + + for statement in &program.statements { + self.interpret_statement(statement, &mut interpreter_vars)?; + } + Ok(()) + } } \ No newline at end of file From f7dfe1c129cfc6e4cdac136f3a400e0b58d0b53d Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 3 Aug 2025 02:00:13 +0530 Subject: [PATCH 08/14] Update: Implement `interpret_statement` method for executing various program statements --- src/codegen.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/codegen.rs b/src/codegen.rs index 7da8257..35286eb 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -262,4 +262,36 @@ impl<'ctx> CodeGenerator<'ctx> { } Ok(()) } + + fn interpret_statement(&self, statement: &Statement, variables: &mut HashMap) -> Result<(), String> { + match statement { + Statement::Show(show) => { + let value = self.evaluate_expression(&show.value, variables)?; + println!("{}", value); + } + Statement::Let(let_stmt) => { + let value = self.evaluate_expression(&let_stmt.value, variables)?; + variables.insert(let_stmt.identifier.clone(), value); + } + Statement::When(when_stmt) => { + let condition_result = self.evaluate_expression(&when_stmt.condition, variables)?; + if condition_result.contains("true") || condition_result.contains("True") { + for stmt in &when_stmt.then_block { + self.interpret_statement(stmt, variables)?; + } + } else if let Some(otherwise_block) = &when_stmt.otherwise_block { + for stmt in otherwise_block { + self.interpret_statement(stmt, variables)?; + } + } + } + Statement::FunctionDef(func_def) => { + println!("Defined function: {}", func_def.name); + } + Statement::Expression(expr) => { + let _value = self.evaluate_expression(expr, variables)?; + } + } + Ok(()) + } } \ No newline at end of file From c54dd6428fb5d87e9639a4f10d13ac3cccb4349e Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 3 Aug 2025 02:00:51 +0530 Subject: [PATCH 09/14] Update: Implement evaluate_expression method for handling various expression types and binary operations --- src/codegen.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/codegen.rs b/src/codegen.rs index 35286eb..8963a57 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -294,4 +294,48 @@ impl<'ctx> CodeGenerator<'ctx> { } Ok(()) } + + fn evaluate_expression(&self, expression: &Expression, variables: &HashMap) -> Result { + match expression { + Expression::Number(n) => Ok(n.to_string()), + Expression::String(s) => Ok(s.clone()), + Expression::Identifier(name) => { + if let Some(value) = variables.get(name) { + Ok(value.clone()) + } else { + Ok(format!("", name)) + } + } + Expression::BinaryOp(binop) => { + let left_val = self.evaluate_expression(&binop.left, variables)?; + let right_val = self.evaluate_expression(&binop.right, variables)?; + + if let (Ok(left_num), Ok(right_num)) = (left_val.parse::(), right_val.parse::()) { + let result = match binop.operator { + BinaryOperator::GreaterThan => return Ok((left_num > right_num).to_string()), + BinaryOperator::LessThan => return Ok((left_num < right_num).to_string()), + BinaryOperator::GreaterThanOrEqual => return Ok((left_num >= right_num).to_string()), + BinaryOperator::LessThanOrEqual => return Ok((left_num <= right_num).to_string()), + BinaryOperator::Equal => return Ok(((left_num - right_num).abs() < f64::EPSILON).to_string()), + BinaryOperator::NotEqual => return Ok(((left_num - right_num).abs() >= f64::EPSILON).to_string()), + BinaryOperator::Add => left_num + right_num, + BinaryOperator::Subtract => left_num - right_num, + BinaryOperator::Multiply => left_num * right_num, + BinaryOperator::Divide => { + if right_num == 0.0 { + return Err("Division by zero".to_string()); + } + left_num / right_num + } + }; + Ok(result.to_string()) + } else { + Ok(format!("({} {:?} {})", left_val, binop.operator, right_val)) + } + } + Expression::FunctionCall(call) => { + Ok(format!("", call.name)) + } + } + } } \ No newline at end of file From a0dd0c4a1ade332366cec4b47fa84226908cda61 Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 3 Aug 2025 02:03:34 +0530 Subject: [PATCH 10/14] Fix: Fix typos and improve formatting in code generation methods --- src/codegen.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/codegen.rs b/src/codegen.rs index 8963a57..dc203b5 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -26,7 +26,7 @@ pub struct CodeGenerator<'ctx> { context: &'ctx Context, module: Module<'ctx>, builder: Builder<'ctx>, - variables: Hashmap>, + variables: HashMap>, } impl<'ctx> CodeGenerator<'ctx> { @@ -46,7 +46,7 @@ impl<'ctx> CodeGenerator<'ctx> { self.context.f64_type() } - pub fn compile(&mu self, program: &Program) -> Result<(), Box> { + pub fn compile(&mut self, program: &Program) -> Result<(), Box> { let main_type = self.context.i32_type().fn_type(&[], false); let main_fn = self.module.add_function("main", main_type, None); let basic_block = self.context.append_basic_block(main_fn, "entry"); @@ -67,7 +67,7 @@ impl<'ctx> CodeGenerator<'ctx> { })); } - println!("LLVM IR generated successfully!") + println!("LLVM IR generated successfully!"); self.module.print_to_stderr(); Ok(()) } @@ -83,7 +83,7 @@ impl<'ctx> CodeGenerator<'ctx> { fn compile_statement(&mut self, statement: &Statement) -> Result<(), Box> { match statement { Statement::Let(let_stmt) => { - let value - self.compile_expression(&let_stmt.value)?; + let value = self.compile_expression(&let_stmt.value)?; let alloc_s = self.builder.build_alloca(self.get_float_type(), &let_stmt.identifier)?; self.builder.build_store(alloc_s, value); @@ -162,7 +162,11 @@ impl<'ctx> CodeGenerator<'ctx> { let printf_fn = self.module.get_function("printf").unwrap(); let string_ptr = self.builder.build_global_string_ptr(&format!("{}\n", s), "str")?; - self.builder.build_call(printf_fn, &[string_ptr.as_pointer_value().into(), "printf_string"], name)?; + self.builder.build_call( + printf_fn, + &[string_ptr.as_pointer_value().into()], + "printf_string" + )?; // return 0 as the numeric value Ok(self.get_float_type().const_float(0.0)) @@ -234,13 +238,13 @@ impl<'ctx> CodeGenerator<'ctx> { } fn generate_print_call(&mut self, value: FloatValue<'ctx>) -> Result<(), Box> { - let print_fn = self.module.get_function("printf").unwrap(); + let printf_fn = self.module.get_function("printf").unwrap(); // create format str for print floatrs let format_str = self.builder.build_global_string_ptr("%.2f\n", "fmt")?; - self.builder.build_Call( - print_fn, + self.builder.build_call( + printf_fn, &[format_str.as_pointer_value().into(), value.into()], "printf_call" )?; From 51bb32c7431e1d9e0ba6a93e5a1d6f4e32f35a1e Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 3 Aug 2025 02:05:20 +0530 Subject: [PATCH 11/14] Fix: Correct variable type name and syntax errors in CodeGenerator; update usage instructions in main function --- src/codegen.rs | 20 ++++++++++++-------- src/main.rs | 6 ++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/codegen.rs b/src/codegen.rs index 8963a57..dc203b5 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -26,7 +26,7 @@ pub struct CodeGenerator<'ctx> { context: &'ctx Context, module: Module<'ctx>, builder: Builder<'ctx>, - variables: Hashmap>, + variables: HashMap>, } impl<'ctx> CodeGenerator<'ctx> { @@ -46,7 +46,7 @@ impl<'ctx> CodeGenerator<'ctx> { self.context.f64_type() } - pub fn compile(&mu self, program: &Program) -> Result<(), Box> { + pub fn compile(&mut self, program: &Program) -> Result<(), Box> { let main_type = self.context.i32_type().fn_type(&[], false); let main_fn = self.module.add_function("main", main_type, None); let basic_block = self.context.append_basic_block(main_fn, "entry"); @@ -67,7 +67,7 @@ impl<'ctx> CodeGenerator<'ctx> { })); } - println!("LLVM IR generated successfully!") + println!("LLVM IR generated successfully!"); self.module.print_to_stderr(); Ok(()) } @@ -83,7 +83,7 @@ impl<'ctx> CodeGenerator<'ctx> { fn compile_statement(&mut self, statement: &Statement) -> Result<(), Box> { match statement { Statement::Let(let_stmt) => { - let value - self.compile_expression(&let_stmt.value)?; + let value = self.compile_expression(&let_stmt.value)?; let alloc_s = self.builder.build_alloca(self.get_float_type(), &let_stmt.identifier)?; self.builder.build_store(alloc_s, value); @@ -162,7 +162,11 @@ impl<'ctx> CodeGenerator<'ctx> { let printf_fn = self.module.get_function("printf").unwrap(); let string_ptr = self.builder.build_global_string_ptr(&format!("{}\n", s), "str")?; - self.builder.build_call(printf_fn, &[string_ptr.as_pointer_value().into(), "printf_string"], name)?; + self.builder.build_call( + printf_fn, + &[string_ptr.as_pointer_value().into()], + "printf_string" + )?; // return 0 as the numeric value Ok(self.get_float_type().const_float(0.0)) @@ -234,13 +238,13 @@ impl<'ctx> CodeGenerator<'ctx> { } fn generate_print_call(&mut self, value: FloatValue<'ctx>) -> Result<(), Box> { - let print_fn = self.module.get_function("printf").unwrap(); + let printf_fn = self.module.get_function("printf").unwrap(); // create format str for print floatrs let format_str = self.builder.build_global_string_ptr("%.2f\n", "fmt")?; - self.builder.build_Call( - print_fn, + self.builder.build_call( + printf_fn, &[format_str.as_pointer_value().into(), value.into()], "printf_call" )?; diff --git a/src/main.rs b/src/main.rs index fed1028..5dbc9ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,8 +14,10 @@ use codegen::CodeGenerator; fn main() { let args: Vec = env::args().collect(); - if args.len() != 2 { - eprintln!("Usage: {} ", args[0]); + if args.len() < 2 || args.len() > 3 { + eprintln!("Usage: {} [--compile|--interpret]", args[0]); + eprintln!(" --compile : Generate LLVM IR and compile (default)"); + eprintln!(" --interpret : Run in interpreter mode"); process::exit(1); } From 71ddcc9bde048996c3e2dfb9e3609898cc82bc06 Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 3 Aug 2025 02:06:30 +0530 Subject: [PATCH 12/14] Fix: Correct indentation and formatting for mode selection in main function --- src/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.rs b/src/main.rs index 5dbc9ed..51add48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,13 @@ fn main() { } let filename = &args[1]; + + let mode = if args.len() == 3 { + &args[2] + } else { + "--compile" + }; + let source = match fs::read_to_string(filename) { Ok(content) => content, Err(err) => { From 788c7df878c28babd48a52f0b05e1e57ade2c0a2 Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 3 Aug 2025 02:07:40 +0530 Subject: [PATCH 13/14] Refactor: Improve debug output and error handling in main function; streamline code generation process --- src/main.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 51add48..eb9cb52 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ mod codegen; use lexer::Lexer; use parser::Parser; use codegen::CodeGenerator; +use inkwell::context::Context; fn main() { let args: Vec = env::args().collect(); @@ -37,7 +38,7 @@ fn main() { } }; - // Step 1: Tokenize (Lexer) + // Step 1: Tokenize let mut lexer = Lexer::new(&source); let tokens = match lexer.tokenize() { Ok(tokens) => tokens, @@ -47,7 +48,9 @@ fn main() { } }; - // println!("Tokens: {:?}", tokens); + if mode == "--debug" { + println!("Tokens: {:?}", tokens); + } // Step 2: Parse into AST let mut parser = Parser::new(tokens); @@ -59,13 +62,54 @@ fn main() { } }; - // Step 3: Print AST (debug output) - // println!("AST: {:#?}", ast); + if mode == "--debug" { + println!("AST: {:#?}", ast); + } - // Step 4: For now, just interpret - let mut codegen = CodeGenerator::new(); - if let Err(err) = codegen.interpret(&ast) { - eprintln!("Interpreter error: {}", err); - process::exit(1); + // Step 3: Execute based on mode + match mode { + "--interpret" => { + println!("Running in interpreter mode..."); + let context = Context::create(); + let mut codegen = match CodeGenerator::new(&context, "delta_module") { + Ok(cg) => cg, + Err(err) => { + eprintln!("Failed to create code generator: {}", err); + process::exit(1); + } + }; + + if let Err(err) = codegen.interpret(&ast) { + eprintln!("Interpreter error: {}", err); + process::exit(1); + } + } + "--compile" | _ => { + println!("Compiling to LLVM IR..."); + let context = Context::create(); + let mut codegen = match CodeGenerator::new(&context, "delta_module") { + Ok(cg) => cg, + Err(err) => { + eprintln!("Failed to create code generator: {}", err); + process::exit(1); + } + }; + + if let Err(err) = codegen.compile(&ast) { + eprintln!("Compilation error: {}", err); + process::exit(1); + } + + // Save LLVM IR to file + let ir_filename = filename.replace(".de", ".ll"); + if let Err(err) = codegen.save_to_file(&ir_filename) { + eprintln!("Failed to save LLVM IR: {}", err); + process::exit(1); + } + + println!("LLVM IR saved to: {}", ir_filename); + println!("To compile to executable, run:"); + println!(" clang {} -o {}", ir_filename, filename.replace(".de", "")); + } } } From 11aa0d6ac01f23233cdf794e94927a1a5e395fa3 Mon Sep 17 00:00:00 2001 From: Pranav Verma Date: Sun, 3 Aug 2025 02:09:39 +0530 Subject: [PATCH 14/14] Fix: Add *.ll to .gitignore to exclude LLVM intermediate files from version control --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4531364..b37eab4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target -VERSIONING/ \ No newline at end of file +VERSIONING/ +*.ll \ No newline at end of file