Skip to content

Commit

Permalink
Merge pull request #108 from LunaStev/develop
Browse files Browse the repository at this point in the history
Development Enablement and Code Refinements
  • Loading branch information
LunaStev authored Feb 21, 2025
2 parents 9854ce5 + e106d16 commit 7ebec29
Show file tree
Hide file tree
Showing 10 changed files with 408 additions and 728 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wave"
version = "0.0.2-pre-beta"
version = "0.0.3-pre-beta"
edition = "2021"

[target.x86_64-apple-darwin]
Expand Down
147 changes: 103 additions & 44 deletions src/llvm_temporary/llvm_codegen.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
use crate::parser::ast::{ASTNode, FunctionNode, StatementNode};

use crate::parser::ast::{ASTNode, FunctionNode, StatementNode, Expression, VariableNode, Literal};
use inkwell::context::Context;
use inkwell::module::Linkage;
use inkwell::values::PointerValue;
use inkwell::values::{PointerValue, FunctionValue};
use inkwell::AddressSpace;

use std::collections::HashMap;

pub unsafe fn generate_ir(ast: &ASTNode) -> String {
let context = Context::create();
let module = context.create_module("main");
let builder = context.create_builder();

// HashMap to store variables
let mut variables: HashMap<String, PointerValue> = HashMap::new();

if let ASTNode::Function(FunctionNode { name, parameters: _, body }) = ast {
// Create function type (void -> void)
let fn_type = context.void_type().fn_type(&[], false);
Expand All @@ -22,47 +26,92 @@ pub unsafe fn generate_ir(ast: &ASTNode) -> String {
let mut string_counter = 0;

for stmt in body {
if let ASTNode::Statement(StatementNode::Println(message)) = stmt {
// Generate unique global name
let global_name = format!("str_{}_{}", name, string_counter);
string_counter += 1;

// Create null-terminated string
let mut bytes = message.as_bytes().to_vec();
bytes.push(0);
let const_str = context.const_string(&bytes, false);

// Create global variable
let global = module.add_global(
context.i8_type().array_type(bytes.len() as u32),
None,
&global_name,
);
global.set_initializer(&const_str);
global.set_linkage(Linkage::Private);
global.set_constant(true);

// Get printf function
let printf_type = context.i32_type().fn_type(
&[context.i8_type().ptr_type(AddressSpace::default()).into()],
true
);
let printf_func = match module.get_function("printf") {
Some(func) => func,
None => module.add_function("printf", printf_type, None),
};

// Create GEP to get i8* pointer
let zero = context.i32_type().const_zero();
let indices = [zero, zero];
let gep = builder.build_gep(
global.as_pointer_value(),
&indices,
"gep",
).unwrap();

// Call printf
let _ = builder.build_call(printf_func, &[gep.into()], "printf_call");
match stmt {
ASTNode::Variable(VariableNode { name, type_name, initial_value }) => {
// Create variable alloca
let alloca = builder.build_alloca(context.i32_type(), &name).unwrap();
variables.insert(name.clone(), alloca);

// Initializing Variables
if let Some(Literal::Number(value)) = initial_value {
let init_value = context.i32_type().const_int(*value as u64, false);
let _ = builder.build_store(alloca, init_value);
}
}
ASTNode::Statement(StatementNode::Println { format, args }) |
ASTNode::Statement(StatementNode::Print { format, args })=> {
// Convert '{}' to '%d' in format string
let format = format.replace("{}", "%d");

// Generate unique global name for the format string
let global_name = format!("str_{}_{}", name, string_counter);
string_counter += 1;

// Create null-terminated string
let mut bytes = format.as_bytes().to_vec();
bytes.push(0);
let const_str = context.const_string(&bytes, false);

// Create global variable for the format string
let global = module.add_global(
context.i8_type().array_type(bytes.len() as u32),
None,
&global_name,
);
global.set_initializer(&const_str);
global.set_linkage(Linkage::Private);
global.set_constant(true);

// Get printf function
let printf_type = context.i32_type().fn_type(
&[context.i8_type().ptr_type(AddressSpace::default()).into()],
true
);
let printf_func = match module.get_function("printf") {
Some(func) => func,
None => module.add_function("printf", printf_type, None),
};

// Create GEP to get i8* pointer to the format string
let zero = context.i32_type().const_zero();
let indices = [zero, zero];
let gep = builder.build_gep(
global.as_pointer_value(),
&indices,
"gep",
).unwrap();

// Prepare arguments for printf
let mut printf_args = vec![gep.into()];

// Add additional arguments
for arg in args {
let value = match arg {
Expression::Variable(var_name) => {
// Find the alloca of the variable and load the value
if let Some(alloca) = variables.get(var_name) {
builder.build_load(*alloca, var_name).unwrap().into_int_value()
} else {
panic!("Variable {} not found", var_name);
}
}
Expression::Literal(literal) => {
match literal {
Literal::Number(value) => {
context.i32_type().const_int(*value as u64, false)
}
_ => unimplemented!("Unsupported literal type"),
}
}
_ => unimplemented!("Unsupported expression type"),
};
printf_args.push(value.into());
}

// Call printf
let _ = builder.build_call(printf_func, &printf_args, "printf_call");
}
_ => {}
}
}

Expand All @@ -72,3 +121,13 @@ pub unsafe fn generate_ir(ast: &ASTNode) -> String {

module.print_to_string().to_string()
}

unsafe fn create_alloca<'a>(
context: &'a Context,
builder: &'a inkwell::builder::Builder<'a>,
function: FunctionValue<'a>,
name: &'a str,
) -> PointerValue<'a> {
let alloca = builder.build_alloca(context.i32_type(), name).unwrap();
alloca
}
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,11 @@ unsafe fn run_wave_file(file_path: &str) {
let params = extract_parameters(&tokens[..], 0, tokens.len());
let mut peekable_tokens = tokens.iter().peekable();
let body = extract_body(&mut peekable_tokens);
let ast = function(function_name, params, body);
let ast = function(function_name, params.clone(), body.clone());

// eprintln!("AST:\n{:#?}", &ast);
// dbg!("{},", &params);
// dbg!("{},", &body);

let ir = generate_ir(&ast);
// eprintln!("Generated LLVM IR:\n{}", ir);
Expand Down
68 changes: 43 additions & 25 deletions src/parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub enum ASTNode {
Program(ParameterNode),
Statement(StatementNode),
Variable(VariableNode),
Expression(Expression),
}

#[derive(Debug, Clone)]
Expand All @@ -28,39 +29,56 @@ pub struct ParameterNode {
}

#[derive(Debug, Clone)]
pub enum StatementNode {
Print(String),
Println(String),
Variable(String),
If { condition: String, body: Vec<ASTNode> },
For { iterator: String, body: Vec<ASTNode> },
While { condition: String, body: Vec<ASTNode> },
pub enum FormatPart {
Literal(String),
Placeholder,
}

#[derive(Debug, Clone)]
pub struct VariableNode {
pub name: String,
pub type_name: String,
pub initial_value: Option<String>,
pub enum Expression {
Literal(Literal),
Variable(String),
BinaryExpression {
left: Box<Expression>,
operator: BinaryOperator,
right: Box<Expression>,
},
Grouped(Box<Expression>),
}

/*
#[derive(Debug, Clone)]
pub struct AST {
pub nodes: Vec<ASTNode>,
pub enum Literal {
Number(f64),
String(String),
}

impl AST {
pub fn new() -> Self {
AST {
nodes: Vec::new()
}
}
#[derive(Debug, Clone)]
pub enum BinaryOperator {
Add,
Subtract,
Multiply,
Divide,
}

pub fn add_node(&mut self, node: ASTNode) {
eprintln!("Adding node to AST: {:?}", node);
self.nodes.push(node);
}
#[derive(Debug, Clone)]
pub enum StatementNode {
Print {
format: String,
args: Vec<Expression>,
},
Println {
format: String,
args: Vec<Expression>,
},
Variable(String),
If { condition: String, body: Vec<ASTNode> },
For { iterator: String, body: Vec<ASTNode> },
While { condition: String, body: Vec<ASTNode> },
}

*/
#[derive(Debug, Clone)]
pub struct VariableNode {
pub name: String,
pub type_name: String,
pub initial_value: Option<Literal>,
}
Loading

0 comments on commit 7ebec29

Please sign in to comment.