@@ -1,9 +1,9 @@
|
|||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|
||||||
use alecc::lexer::Lexer;
|
|
||||||
use alecc::parser::Parser;
|
|
||||||
use alecc::codegen::CodeGenerator;
|
use alecc::codegen::CodeGenerator;
|
||||||
use alecc::optimizer::{Optimizer, OptimizationLevel};
|
use alecc::lexer::Lexer;
|
||||||
|
use alecc::optimizer::{OptimizationLevel, Optimizer};
|
||||||
|
use alecc::parser::Parser;
|
||||||
use alecc::targets::Target;
|
use alecc::targets::Target;
|
||||||
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
|
|
||||||
const SIMPLE_C_CODE: &str = r#"
|
const SIMPLE_C_CODE: &str = r#"
|
||||||
int main() {
|
int main() {
|
||||||
@@ -119,5 +119,11 @@ fn bench_optimizer(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_group!(benches, bench_lexer, bench_parser, bench_codegen, bench_optimizer);
|
criterion_group!(
|
||||||
|
benches,
|
||||||
|
bench_lexer,
|
||||||
|
bench_parser,
|
||||||
|
bench_codegen,
|
||||||
|
bench_optimizer
|
||||||
|
);
|
||||||
criterion_main!(benches);
|
criterion_main!(benches);
|
||||||
|
|||||||
385
src/codegen.rs
385
src/codegen.rs
@@ -1,6 +1,8 @@
|
|||||||
use crate::parser::{Program, Function, Expression, Statement, Type, BinaryOperator, UnaryOperator};
|
|
||||||
use crate::targets::Target;
|
|
||||||
use crate::error::{AleccError, Result};
|
use crate::error::{AleccError, Result};
|
||||||
|
use crate::parser::{
|
||||||
|
BinaryOperator, Expression, Function, Program, Statement, Type, UnaryOperator,
|
||||||
|
};
|
||||||
|
use crate::targets::Target;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct CodeGenerator {
|
pub struct CodeGenerator {
|
||||||
@@ -11,8 +13,8 @@ pub struct CodeGenerator {
|
|||||||
current_function_params: Vec<(String, i32)>, // (name, stack_offset)
|
current_function_params: Vec<(String, i32)>, // (name, stack_offset)
|
||||||
epilogue_emitted: bool,
|
epilogue_emitted: bool,
|
||||||
local_variables: HashMap<String, i32>, // (name, stack_offset)
|
local_variables: HashMap<String, i32>, // (name, stack_offset)
|
||||||
stack_offset: i32, // Current stack offset for local variables
|
stack_offset: i32, // Current stack offset for local variables
|
||||||
last_call_stack_cleanup: usize, // Stack bytes to clean up after last call
|
last_call_stack_cleanup: usize, // Stack bytes to clean up after last call
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodeGenerator {
|
impl CodeGenerator {
|
||||||
@@ -35,9 +37,9 @@ impl CodeGenerator {
|
|||||||
for function in &program.functions {
|
for function in &program.functions {
|
||||||
self.collect_string_literals_from_statement(&function.body)?;
|
self.collect_string_literals_from_statement(&function.body)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.emit_header();
|
self.emit_header();
|
||||||
|
|
||||||
// Generate string literals section
|
// Generate string literals section
|
||||||
if !self.string_literals.is_empty() {
|
if !self.string_literals.is_empty() {
|
||||||
self.emit_line(".section .rodata");
|
self.emit_line(".section .rodata");
|
||||||
@@ -74,23 +76,23 @@ impl CodeGenerator {
|
|||||||
self.emit_line("");
|
self.emit_line("");
|
||||||
self.emit_line(".globl _start");
|
self.emit_line(".globl _start");
|
||||||
self.emit_line("_start:");
|
self.emit_line("_start:");
|
||||||
|
|
||||||
// Set up stack and call main
|
// Set up stack and call main
|
||||||
self.emit_line(" push rbp");
|
self.emit_line(" push rbp");
|
||||||
self.emit_line(" mov rbp, rsp");
|
self.emit_line(" mov rbp, rsp");
|
||||||
|
|
||||||
// Reserve space for temporary operations (ensures proper stack alignment)
|
// Reserve space for temporary operations (ensures proper stack alignment)
|
||||||
// 120 bytes = 15*8, so after rbp push (8 bytes), total is 128 bytes = multiple of 16
|
// 120 bytes = 15*8, so after rbp push (8 bytes), total is 128 bytes = multiple of 16
|
||||||
self.emit_line(" sub rsp, 120");
|
self.emit_line(" sub rsp, 120");
|
||||||
|
|
||||||
// Call main function
|
// Call main function
|
||||||
self.emit_line(" call main");
|
self.emit_line(" call main");
|
||||||
|
|
||||||
// Exit syscall with main's return value
|
// Exit syscall with main's return value
|
||||||
self.emit_line(" mov rdi, rax"); // exit status = main's return value
|
self.emit_line(" mov rdi, rax"); // exit status = main's return value
|
||||||
self.emit_line(" mov rax, 60"); // sys_exit syscall number
|
self.emit_line(" mov rax, 60"); // sys_exit syscall number
|
||||||
self.emit_line(" syscall"); // invoke syscall
|
self.emit_line(" syscall"); // invoke syscall
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,27 +124,27 @@ impl CodeGenerator {
|
|||||||
// This is a function definition, generate the actual function
|
// This is a function definition, generate the actual function
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.emit_line(&format!(".globl {}", function.name));
|
self.emit_line(&format!(".globl {}", function.name));
|
||||||
self.emit_line(&format!("{}:", function.name));
|
self.emit_line(&format!("{}:", function.name));
|
||||||
|
|
||||||
// Set up parameter tracking
|
// Set up parameter tracking
|
||||||
self.current_function_params.clear();
|
self.current_function_params.clear();
|
||||||
self.local_variables.clear();
|
self.local_variables.clear();
|
||||||
// Start local variables after parameters to avoid collision
|
// Start local variables after parameters to avoid collision
|
||||||
self.stack_offset = -(function.parameters.len() as i32 * 8);
|
self.stack_offset = -(function.parameters.len() as i32 * 8);
|
||||||
self.epilogue_emitted = false;
|
self.epilogue_emitted = false;
|
||||||
|
|
||||||
// Function prologue
|
// Function prologue
|
||||||
self.emit_function_prologue(&function.parameters)?;
|
self.emit_function_prologue(&function.parameters)?;
|
||||||
|
|
||||||
// Function body
|
// Function body
|
||||||
self.generate_statement(&function.body)?;
|
self.generate_statement(&function.body)?;
|
||||||
|
|
||||||
// Function epilogue (always ensure we have a proper function ending)
|
// Function epilogue (always ensure we have a proper function ending)
|
||||||
// This handles cases where there might not be explicit returns in all paths
|
// This handles cases where there might not be explicit returns in all paths
|
||||||
self.emit_function_epilogue()?;
|
self.emit_function_epilogue()?;
|
||||||
|
|
||||||
self.emit_line("");
|
self.emit_line("");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -152,59 +154,64 @@ impl CodeGenerator {
|
|||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
self.emit_line(" push ebp");
|
self.emit_line(" push ebp");
|
||||||
self.emit_line(" mov ebp, esp");
|
self.emit_line(" mov ebp, esp");
|
||||||
|
|
||||||
// Reserve space for parameters only (no extra temporaries for now)
|
// Reserve space for parameters only (no extra temporaries for now)
|
||||||
let stack_space = parameters.len() * 4;
|
let stack_space = parameters.len() * 4;
|
||||||
if stack_space > 0 {
|
if stack_space > 0 {
|
||||||
self.emit_line(&format!(" sub esp, {}", stack_space));
|
self.emit_line(&format!(" sub esp, {}", stack_space));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store parameters from stack (i386 calling convention)
|
// Store parameters from stack (i386 calling convention)
|
||||||
for (i, (name, _)) in parameters.iter().enumerate() {
|
for (i, (name, _)) in parameters.iter().enumerate() {
|
||||||
let param_offset = -(i as i32 + 1) * 4;
|
let param_offset = -(i as i32 + 1) * 4;
|
||||||
let stack_offset = 8 + i as i32 * 4; // ebp + 8 + offset
|
let stack_offset = 8 + i as i32 * 4; // ebp + 8 + offset
|
||||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", stack_offset));
|
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", stack_offset));
|
||||||
self.emit_line(&format!(" mov DWORD PTR [ebp + {}], eax", param_offset));
|
self.emit_line(&format!(" mov DWORD PTR [ebp + {}], eax", param_offset));
|
||||||
self.current_function_params.push((name.clone(), param_offset));
|
self.current_function_params
|
||||||
|
.push((name.clone(), param_offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
self.emit_line(" push rbp");
|
self.emit_line(" push rbp");
|
||||||
self.emit_line(" mov rbp, rsp");
|
self.emit_line(" mov rbp, rsp");
|
||||||
|
|
||||||
// Reserve space for parameters + ensure 16-byte alignment
|
// Reserve space for parameters + ensure 16-byte alignment
|
||||||
let stack_space = parameters.len() * 8;
|
let stack_space = parameters.len() * 8;
|
||||||
// Always reserve at least 8 bytes to maintain 16-byte alignment after rbp push
|
// Always reserve at least 8 bytes to maintain 16-byte alignment after rbp push
|
||||||
let min_space = if stack_space == 0 { 8 } else { stack_space };
|
let min_space = if stack_space == 0 { 8 } else { stack_space };
|
||||||
let aligned_space = ((min_space + 15) / 16) * 16; // Round up to 16-byte boundary
|
let aligned_space = ((min_space + 15) / 16) * 16; // Round up to 16-byte boundary
|
||||||
self.emit_line(&format!(" sub rsp, {}", aligned_space));
|
self.emit_line(&format!(" sub rsp, {}", aligned_space));
|
||||||
|
|
||||||
// Store parameters from registers (x86_64 calling convention)
|
// Store parameters from registers (x86_64 calling convention)
|
||||||
let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||||
for (i, (name, _)) in parameters.iter().enumerate() {
|
for (i, (name, _)) in parameters.iter().enumerate() {
|
||||||
let param_offset = -(i as i32 + 1) * 8;
|
let param_offset = -(i as i32 + 1) * 8;
|
||||||
if i < param_registers.len() {
|
if i < param_registers.len() {
|
||||||
// Parameter passed in register
|
// Parameter passed in register
|
||||||
self.emit_line(&format!(" mov QWORD PTR [rbp + {}], {}", param_offset, param_registers[i]));
|
self.emit_line(&format!(
|
||||||
|
" mov QWORD PTR [rbp + {}], {}",
|
||||||
|
param_offset, param_registers[i]
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
// Parameter passed on stack
|
// Parameter passed on stack
|
||||||
let stack_offset = 16 + (i - param_registers.len()) as i32 * 8;
|
let stack_offset = 16 + (i - param_registers.len()) as i32 * 8;
|
||||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", stack_offset));
|
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", stack_offset));
|
||||||
self.emit_line(&format!(" mov QWORD PTR [rbp + {}], rax", param_offset));
|
self.emit_line(&format!(" mov QWORD PTR [rbp + {}], rax", param_offset));
|
||||||
}
|
}
|
||||||
self.current_function_params.push((name.clone(), param_offset));
|
self.current_function_params
|
||||||
|
.push((name.clone(), param_offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
Target::Arm64 => {
|
||||||
self.emit_line(" stp x29, x30, [sp, #-16]!");
|
self.emit_line(" stp x29, x30, [sp, #-16]!");
|
||||||
self.emit_line(" mov x29, sp");
|
self.emit_line(" mov x29, sp");
|
||||||
|
|
||||||
let stack_space = parameters.len() * 8;
|
let stack_space = parameters.len() * 8;
|
||||||
if stack_space > 0 {
|
if stack_space > 0 {
|
||||||
let aligned_space = (stack_space + 15) & !15; // 16-byte aligned
|
let aligned_space = (stack_space + 15) & !15; // 16-byte aligned
|
||||||
self.emit_line(&format!(" sub sp, sp, #{}", aligned_space));
|
self.emit_line(&format!(" sub sp, sp, #{}", aligned_space));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store parameters from registers (ARM64 calling convention)
|
// Store parameters from registers (ARM64 calling convention)
|
||||||
for (i, (name, _)) in parameters.iter().enumerate() {
|
for (i, (name, _)) in parameters.iter().enumerate() {
|
||||||
let param_offset = -(i as i32 + 1) * 8;
|
let param_offset = -(i as i32 + 1) * 8;
|
||||||
@@ -217,7 +224,8 @@ impl CodeGenerator {
|
|||||||
self.emit_line(&format!(" ldr x9, [x29, #{}]", stack_offset));
|
self.emit_line(&format!(" ldr x9, [x29, #{}]", stack_offset));
|
||||||
self.emit_line(&format!(" str x9, [x29, #{}]", param_offset));
|
self.emit_line(&format!(" str x9, [x29, #{}]", param_offset));
|
||||||
}
|
}
|
||||||
self.current_function_params.push((name.clone(), param_offset));
|
self.current_function_params
|
||||||
|
.push((name.clone(), param_offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,7 +236,7 @@ impl CodeGenerator {
|
|||||||
if self.epilogue_emitted {
|
if self.epilogue_emitted {
|
||||||
return Ok(()); // Don't emit duplicate epilogues
|
return Ok(()); // Don't emit duplicate epilogues
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
self.emit_line(" mov esp, ebp");
|
self.emit_line(" mov esp, ebp");
|
||||||
@@ -246,7 +254,7 @@ impl CodeGenerator {
|
|||||||
self.emit_line(" ret");
|
self.emit_line(" ret");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.epilogue_emitted = true;
|
self.epilogue_emitted = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -270,7 +278,7 @@ impl CodeGenerator {
|
|||||||
self.emit_line(" ret");
|
self.emit_line(" ret");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.epilogue_emitted = true;
|
self.epilogue_emitted = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -280,30 +288,40 @@ impl CodeGenerator {
|
|||||||
Statement::Expression(expr) => {
|
Statement::Expression(expr) => {
|
||||||
self.generate_expression(expr)?;
|
self.generate_expression(expr)?;
|
||||||
}
|
}
|
||||||
Statement::Declaration { name, var_type, initializer } => {
|
Statement::Declaration {
|
||||||
|
name,
|
||||||
|
var_type,
|
||||||
|
initializer,
|
||||||
|
} => {
|
||||||
// Calculate space needed based on type
|
// Calculate space needed based on type
|
||||||
let size = match var_type {
|
let size = match var_type {
|
||||||
Type::Array(_, Some(length)) => length * 8, // Assuming 8-byte elements
|
Type::Array(_, Some(length)) => length * 8, // Assuming 8-byte elements
|
||||||
Type::Array(_, None) => 80, // Default size for unsized arrays
|
Type::Array(_, None) => 80, // Default size for unsized arrays
|
||||||
_ => 8, // Default 8 bytes for simple types
|
_ => 8, // Default 8 bytes for simple types
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allocate space for variable/array
|
// Allocate space for variable/array
|
||||||
self.stack_offset -= size as i32;
|
self.stack_offset -= size as i32;
|
||||||
let var_offset = self.stack_offset;
|
let var_offset = self.stack_offset;
|
||||||
|
|
||||||
// Store variable name and offset for later reference
|
// Store variable name and offset for later reference
|
||||||
self.local_variables.insert(name.clone(), var_offset);
|
self.local_variables.insert(name.clone(), var_offset);
|
||||||
|
|
||||||
if let Some(init_expr) = initializer {
|
if let Some(init_expr) = initializer {
|
||||||
self.generate_expression(init_expr)?;
|
self.generate_expression(init_expr)?;
|
||||||
// Store the value in the local variable slot
|
// Store the value in the local variable slot
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
self.emit_line(&format!(" mov QWORD PTR [rbp + {}], rax", var_offset));
|
self.emit_line(&format!(
|
||||||
|
" mov QWORD PTR [rbp + {}], rax",
|
||||||
|
var_offset
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
self.emit_line(&format!(" mov DWORD PTR [ebp + {}], eax", var_offset));
|
self.emit_line(&format!(
|
||||||
|
" mov DWORD PTR [ebp + {}], eax",
|
||||||
|
var_offset
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
Target::Arm64 => {
|
||||||
self.emit_line(&format!(" str x0, [x29, #{}]", var_offset));
|
self.emit_line(&format!(" str x0, [x29, #{}]", var_offset));
|
||||||
@@ -335,16 +353,20 @@ impl CodeGenerator {
|
|||||||
self.generate_statement(stmt)?;
|
self.generate_statement(stmt)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Statement::If { condition, then_stmt, else_stmt } => {
|
Statement::If {
|
||||||
|
condition,
|
||||||
|
then_stmt,
|
||||||
|
else_stmt,
|
||||||
|
} => {
|
||||||
let else_label = self.new_label("else");
|
let else_label = self.new_label("else");
|
||||||
let end_label = self.new_label("endif");
|
let end_label = self.new_label("endif");
|
||||||
|
|
||||||
self.generate_expression(condition)?;
|
self.generate_expression(condition)?;
|
||||||
self.emit_conditional_jump(false, &else_label)?;
|
self.emit_conditional_jump(false, &else_label)?;
|
||||||
|
|
||||||
self.generate_statement(then_stmt)?;
|
self.generate_statement(then_stmt)?;
|
||||||
self.emit_jump(&end_label)?;
|
self.emit_jump(&end_label)?;
|
||||||
|
|
||||||
self.emit_line(&format!("{}:", else_label));
|
self.emit_line(&format!("{}:", else_label));
|
||||||
if let Some(else_stmt) = else_stmt {
|
if let Some(else_stmt) = else_stmt {
|
||||||
// Reset epilogue flag for else branch in case it contains a return
|
// Reset epilogue flag for else branch in case it contains a return
|
||||||
@@ -356,47 +378,52 @@ impl CodeGenerator {
|
|||||||
self.epilogue_emitted = saved_epilogue_state;
|
self.epilogue_emitted = saved_epilogue_state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.emit_line(&format!("{}:", end_label));
|
self.emit_line(&format!("{}:", end_label));
|
||||||
}
|
}
|
||||||
Statement::While { condition, body } => {
|
Statement::While { condition, body } => {
|
||||||
let loop_label = self.new_label("loop");
|
let loop_label = self.new_label("loop");
|
||||||
let end_label = self.new_label("endloop");
|
let end_label = self.new_label("endloop");
|
||||||
|
|
||||||
self.emit_line(&format!("{}:", loop_label));
|
self.emit_line(&format!("{}:", loop_label));
|
||||||
self.generate_expression(condition)?;
|
self.generate_expression(condition)?;
|
||||||
self.emit_conditional_jump(false, &end_label)?;
|
self.emit_conditional_jump(false, &end_label)?;
|
||||||
|
|
||||||
self.generate_statement(body)?;
|
self.generate_statement(body)?;
|
||||||
self.emit_jump(&loop_label)?;
|
self.emit_jump(&loop_label)?;
|
||||||
|
|
||||||
self.emit_line(&format!("{}:", end_label));
|
self.emit_line(&format!("{}:", end_label));
|
||||||
}
|
}
|
||||||
Statement::For { init, condition, increment, body } => {
|
Statement::For {
|
||||||
|
init,
|
||||||
|
condition,
|
||||||
|
increment,
|
||||||
|
body,
|
||||||
|
} => {
|
||||||
// Generate initialization
|
// Generate initialization
|
||||||
if let Some(init_stmt) = init {
|
if let Some(init_stmt) = init {
|
||||||
self.generate_statement(init_stmt)?;
|
self.generate_statement(init_stmt)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let loop_label = self.new_label("forloop");
|
let loop_label = self.new_label("forloop");
|
||||||
let end_label = self.new_label("endfor");
|
let end_label = self.new_label("endfor");
|
||||||
|
|
||||||
self.emit_line(&format!("{}:", loop_label));
|
self.emit_line(&format!("{}:", loop_label));
|
||||||
|
|
||||||
// Generate condition check
|
// Generate condition check
|
||||||
if let Some(cond_expr) = condition {
|
if let Some(cond_expr) = condition {
|
||||||
self.generate_expression(cond_expr)?;
|
self.generate_expression(cond_expr)?;
|
||||||
self.emit_conditional_jump(false, &end_label)?;
|
self.emit_conditional_jump(false, &end_label)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate body
|
// Generate body
|
||||||
self.generate_statement(body)?;
|
self.generate_statement(body)?;
|
||||||
|
|
||||||
// Generate increment
|
// Generate increment
|
||||||
if let Some(inc_expr) = increment {
|
if let Some(inc_expr) = increment {
|
||||||
self.generate_expression(inc_expr)?;
|
self.generate_expression(inc_expr)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.emit_jump(&loop_label)?;
|
self.emit_jump(&loop_label)?;
|
||||||
self.emit_line(&format!("{}:", end_label));
|
self.emit_line(&format!("{}:", end_label));
|
||||||
}
|
}
|
||||||
@@ -412,19 +439,17 @@ impl CodeGenerator {
|
|||||||
|
|
||||||
fn generate_expression(&mut self, expression: &Expression) -> Result<()> {
|
fn generate_expression(&mut self, expression: &Expression) -> Result<()> {
|
||||||
match expression {
|
match expression {
|
||||||
Expression::IntegerLiteral(value) => {
|
Expression::IntegerLiteral(value) => match self.target {
|
||||||
match self.target {
|
Target::I386 => {
|
||||||
Target::I386 => {
|
self.emit_line(&format!(" mov eax, {}", value));
|
||||||
self.emit_line(&format!(" mov eax, {}", value));
|
|
||||||
}
|
|
||||||
Target::Amd64 => {
|
|
||||||
self.emit_line(&format!(" mov rax, {}", value));
|
|
||||||
}
|
|
||||||
Target::Arm64 => {
|
|
||||||
self.emit_line(&format!(" mov x0, #{}", value));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
Target::Amd64 => {
|
||||||
|
self.emit_line(&format!(" mov rax, {}", value));
|
||||||
|
}
|
||||||
|
Target::Arm64 => {
|
||||||
|
self.emit_line(&format!(" mov x0, #{}", value));
|
||||||
|
}
|
||||||
|
},
|
||||||
Expression::StringLiteral(value) => {
|
Expression::StringLiteral(value) => {
|
||||||
let label = self.get_string_literal_label(value);
|
let label = self.get_string_literal_label(value);
|
||||||
match self.target {
|
match self.target {
|
||||||
@@ -442,7 +467,11 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
Expression::Identifier(name) => {
|
Expression::Identifier(name) => {
|
||||||
// Check if it's a function parameter first
|
// Check if it's a function parameter first
|
||||||
if let Some((_, offset)) = self.current_function_params.iter().find(|(param_name, _)| param_name == name) {
|
if let Some((_, offset)) = self
|
||||||
|
.current_function_params
|
||||||
|
.iter()
|
||||||
|
.find(|(param_name, _)| param_name == name)
|
||||||
|
{
|
||||||
// Load parameter from stack
|
// Load parameter from stack
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
@@ -485,7 +514,10 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Call { function, arguments } => {
|
Expression::Call {
|
||||||
|
function,
|
||||||
|
arguments,
|
||||||
|
} => {
|
||||||
// Generate arguments and place in calling convention registers/stack
|
// Generate arguments and place in calling convention registers/stack
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
@@ -498,13 +530,17 @@ impl CodeGenerator {
|
|||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
// x86_64: first 6 args in registers, rest on stack
|
// x86_64: first 6 args in registers, rest on stack
|
||||||
let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||||
|
|
||||||
// Ensure stack alignment before function call
|
// Ensure stack alignment before function call
|
||||||
// Stack must be 16-byte aligned before 'call' instruction
|
// Stack must be 16-byte aligned before 'call' instruction
|
||||||
// Since 'call' pushes 8 bytes (return address), we need stack to be 8 bytes off 16-byte boundary
|
// Since 'call' pushes 8 bytes (return address), we need stack to be 8 bytes off 16-byte boundary
|
||||||
let stack_args = if arguments.len() > param_registers.len() { arguments.len() - param_registers.len() } else { 0 };
|
let stack_args = if arguments.len() > param_registers.len() {
|
||||||
|
arguments.len() - param_registers.len()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
let mut stack_cleanup_size = 0;
|
let mut stack_cleanup_size = 0;
|
||||||
|
|
||||||
// Handle stack arguments if any
|
// Handle stack arguments if any
|
||||||
if stack_args > 0 {
|
if stack_args > 0 {
|
||||||
let total_stack_bytes = stack_args * 8;
|
let total_stack_bytes = stack_args * 8;
|
||||||
@@ -516,7 +552,7 @@ impl CodeGenerator {
|
|||||||
stack_cleanup_size += stack_args * 8;
|
stack_cleanup_size += stack_args * 8;
|
||||||
}
|
}
|
||||||
// Note: No additional alignment for register-only calls since function prologue handles it
|
// Note: No additional alignment for register-only calls since function prologue handles it
|
||||||
|
|
||||||
// First, save any arguments that go on the stack (in reverse order)
|
// First, save any arguments that go on the stack (in reverse order)
|
||||||
if arguments.len() > param_registers.len() {
|
if arguments.len() > param_registers.len() {
|
||||||
for arg in arguments.iter().skip(param_registers.len()).rev() {
|
for arg in arguments.iter().skip(param_registers.len()).rev() {
|
||||||
@@ -524,14 +560,15 @@ impl CodeGenerator {
|
|||||||
self.emit_line(" push rax");
|
self.emit_line(" push rax");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then handle register arguments in reverse order to avoid overwriting
|
// Then handle register arguments in reverse order to avoid overwriting
|
||||||
let reg_args: Vec<_> = arguments.iter().take(param_registers.len()).collect();
|
let reg_args: Vec<_> =
|
||||||
|
arguments.iter().take(param_registers.len()).collect();
|
||||||
for (i, arg) in reg_args.iter().enumerate().rev() {
|
for (i, arg) in reg_args.iter().enumerate().rev() {
|
||||||
self.generate_expression(arg)?;
|
self.generate_expression(arg)?;
|
||||||
self.emit_line(&format!(" mov {}, rax", param_registers[i]));
|
self.emit_line(&format!(" mov {}, rax", param_registers[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store cleanup size for later use
|
// Store cleanup size for later use
|
||||||
self.last_call_stack_cleanup = stack_cleanup_size;
|
self.last_call_stack_cleanup = stack_cleanup_size;
|
||||||
}
|
}
|
||||||
@@ -544,7 +581,7 @@ impl CodeGenerator {
|
|||||||
self.emit_line(" str x0, [sp, #-16]!");
|
self.emit_line(" str x0, [sp, #-16]!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then handle register arguments in reverse order
|
// Then handle register arguments in reverse order
|
||||||
let reg_args: Vec<_> = arguments.iter().take(8).collect();
|
let reg_args: Vec<_> = arguments.iter().take(8).collect();
|
||||||
for (i, arg) in reg_args.iter().enumerate().rev() {
|
for (i, arg) in reg_args.iter().enumerate().rev() {
|
||||||
@@ -556,7 +593,7 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Expression::Identifier(func_name) = function.as_ref() {
|
if let Expression::Identifier(func_name) = function.as_ref() {
|
||||||
self.emit_line(&format!(" call {}", func_name));
|
self.emit_line(&format!(" call {}", func_name));
|
||||||
} else {
|
} else {
|
||||||
@@ -564,7 +601,7 @@ impl CodeGenerator {
|
|||||||
message: "Indirect function calls not implemented".to_string(),
|
message: "Indirect function calls not implemented".to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up stack for arguments that were pushed
|
// Clean up stack for arguments that were pushed
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
@@ -576,73 +613,87 @@ impl CodeGenerator {
|
|||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
// Clean up stack using stored cleanup size
|
// Clean up stack using stored cleanup size
|
||||||
if self.last_call_stack_cleanup > 0 {
|
if self.last_call_stack_cleanup > 0 {
|
||||||
self.emit_line(&format!(" add rsp, {}", self.last_call_stack_cleanup));
|
self.emit_line(&format!(
|
||||||
|
" add rsp, {}",
|
||||||
|
self.last_call_stack_cleanup
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
Target::Arm64 => {
|
||||||
// Clean up stack arguments (if any)
|
// Clean up stack arguments (if any)
|
||||||
let stack_args = if arguments.len() > 8 { arguments.len() - 8 } else { 0 };
|
let stack_args = if arguments.len() > 8 {
|
||||||
|
arguments.len() - 8
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
if stack_args > 0 {
|
if stack_args > 0 {
|
||||||
self.emit_line(&format!(" add sp, sp, #{}", stack_args * 16));
|
self.emit_line(&format!(" add sp, sp, #{}", stack_args * 16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Binary { left, operator, right } => {
|
Expression::Binary {
|
||||||
|
left,
|
||||||
|
operator,
|
||||||
|
right,
|
||||||
|
} => {
|
||||||
// Generate binary operations
|
// Generate binary operations
|
||||||
// First generate right operand and save it
|
// First generate right operand and save it
|
||||||
self.generate_expression(right)?;
|
self.generate_expression(right)?;
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
self.emit_line(" push eax"); // Save right operand
|
self.emit_line(" push eax"); // Save right operand
|
||||||
}
|
}
|
||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
self.emit_line(" push rax"); // Save right operand
|
self.emit_line(" push rax"); // Save right operand
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
Target::Arm64 => {
|
||||||
self.emit_line(" str x0, [sp, #-16]!"); // Save right operand
|
self.emit_line(" str x0, [sp, #-16]!"); // Save right operand
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate left operand
|
// Generate left operand
|
||||||
self.generate_expression(left)?;
|
self.generate_expression(left)?;
|
||||||
|
|
||||||
// Pop right operand and perform operation
|
// Pop right operand and perform operation
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
self.emit_line(" pop ebx"); // Right operand in ebx
|
self.emit_line(" pop ebx"); // Right operand in ebx
|
||||||
match operator {
|
match operator {
|
||||||
BinaryOperator::Add => self.emit_line(" add eax, ebx"),
|
BinaryOperator::Add => self.emit_line(" add eax, ebx"),
|
||||||
BinaryOperator::Subtract => self.emit_line(" sub eax, ebx"),
|
BinaryOperator::Subtract => self.emit_line(" sub eax, ebx"),
|
||||||
BinaryOperator::Multiply => self.emit_line(" imul eax, ebx"),
|
BinaryOperator::Multiply => self.emit_line(" imul eax, ebx"),
|
||||||
BinaryOperator::Divide => {
|
BinaryOperator::Divide => {
|
||||||
self.emit_line(" cdq"); // Sign extend eax to edx:eax
|
self.emit_line(" cdq"); // Sign extend eax to edx:eax
|
||||||
self.emit_line(" idiv ebx");
|
self.emit_line(" idiv ebx");
|
||||||
}
|
}
|
||||||
BinaryOperator::Modulo => {
|
BinaryOperator::Modulo => {
|
||||||
self.emit_line(" cdq"); // Sign extend eax to edx:eax
|
self.emit_line(" cdq"); // Sign extend eax to edx:eax
|
||||||
self.emit_line(" idiv ebx");
|
self.emit_line(" idiv ebx");
|
||||||
self.emit_line(" mov eax, edx"); // Remainder is in edx
|
self.emit_line(" mov eax, edx"); // Remainder is in edx
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(AleccError::CodegenError {
|
return Err(AleccError::CodegenError {
|
||||||
message: format!("Binary operator {:?} not implemented for i386", operator),
|
message: format!(
|
||||||
|
"Binary operator {:?} not implemented for i386",
|
||||||
|
operator
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
self.emit_line(" pop rbx"); // Right operand in rbx
|
self.emit_line(" pop rbx"); // Right operand in rbx
|
||||||
match operator {
|
match operator {
|
||||||
BinaryOperator::Add => self.emit_line(" add rax, rbx"),
|
BinaryOperator::Add => self.emit_line(" add rax, rbx"),
|
||||||
BinaryOperator::Subtract => self.emit_line(" sub rax, rbx"),
|
BinaryOperator::Subtract => self.emit_line(" sub rax, rbx"),
|
||||||
BinaryOperator::Multiply => self.emit_line(" imul rax, rbx"),
|
BinaryOperator::Multiply => self.emit_line(" imul rax, rbx"),
|
||||||
BinaryOperator::Divide => {
|
BinaryOperator::Divide => {
|
||||||
self.emit_line(" cqo"); // Sign extend rax to rdx:rax
|
self.emit_line(" cqo"); // Sign extend rax to rdx:rax
|
||||||
self.emit_line(" idiv rbx");
|
self.emit_line(" idiv rbx");
|
||||||
}
|
}
|
||||||
BinaryOperator::Modulo => {
|
BinaryOperator::Modulo => {
|
||||||
self.emit_line(" cqo"); // Sign extend rax to rdx:rax
|
self.emit_line(" cqo"); // Sign extend rax to rdx:rax
|
||||||
self.emit_line(" idiv rbx");
|
self.emit_line(" idiv rbx");
|
||||||
self.emit_line(" mov rax, rdx"); // Remainder is in rdx
|
self.emit_line(" mov rax, rdx"); // Remainder is in rdx
|
||||||
}
|
}
|
||||||
@@ -710,19 +761,22 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
Target::Arm64 => {
|
||||||
self.emit_line(" ldr x1, [sp], #16"); // Right operand in x1
|
self.emit_line(" ldr x1, [sp], #16"); // Right operand in x1
|
||||||
match operator {
|
match operator {
|
||||||
BinaryOperator::Add => self.emit_line(" add x0, x0, x1"),
|
BinaryOperator::Add => self.emit_line(" add x0, x0, x1"),
|
||||||
BinaryOperator::Subtract => self.emit_line(" sub x0, x0, x1"),
|
BinaryOperator::Subtract => self.emit_line(" sub x0, x0, x1"),
|
||||||
BinaryOperator::Multiply => self.emit_line(" mul x0, x0, x1"),
|
BinaryOperator::Multiply => self.emit_line(" mul x0, x0, x1"),
|
||||||
BinaryOperator::Divide => self.emit_line(" sdiv x0, x0, x1"),
|
BinaryOperator::Divide => self.emit_line(" sdiv x0, x0, x1"),
|
||||||
BinaryOperator::Modulo => {
|
BinaryOperator::Modulo => {
|
||||||
self.emit_line(" sdiv x2, x0, x1"); // x2 = x0 / x1
|
self.emit_line(" sdiv x2, x0, x1"); // x2 = x0 / x1
|
||||||
self.emit_line(" msub x0, x2, x1, x0"); // x0 = x0 - (x2 * x1)
|
self.emit_line(" msub x0, x2, x1, x0"); // x0 = x0 - (x2 * x1)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(AleccError::CodegenError {
|
return Err(AleccError::CodegenError {
|
||||||
message: format!("Binary operator {:?} not implemented for arm64", operator),
|
message: format!(
|
||||||
|
"Binary operator {:?} not implemented for arm64",
|
||||||
|
operator
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -788,12 +842,24 @@ impl CodeGenerator {
|
|||||||
if let Some(&offset) = self.local_variables.get(name) {
|
if let Some(&offset) = self.local_variables.get(name) {
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
self.emit_line(&format!(" inc DWORD PTR [ebp + {}]", offset));
|
self.emit_line(&format!(
|
||||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
" inc DWORD PTR [ebp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
|
self.emit_line(&format!(
|
||||||
|
" mov eax, DWORD PTR [ebp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
self.emit_line(&format!(" inc QWORD PTR [rbp + {}]", offset));
|
self.emit_line(&format!(
|
||||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
" inc QWORD PTR [rbp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
|
self.emit_line(&format!(
|
||||||
|
" mov rax, QWORD PTR [rbp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
Target::Arm64 => {
|
||||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||||
@@ -808,7 +874,8 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(AleccError::CodegenError {
|
return Err(AleccError::CodegenError {
|
||||||
message: "Pre-increment can only be applied to variables".to_string(),
|
message: "Pre-increment can only be applied to variables"
|
||||||
|
.to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -818,12 +885,24 @@ impl CodeGenerator {
|
|||||||
if let Some(&offset) = self.local_variables.get(name) {
|
if let Some(&offset) = self.local_variables.get(name) {
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
self.emit_line(&format!(
|
||||||
self.emit_line(&format!(" inc DWORD PTR [ebp + {}]", offset));
|
" mov eax, DWORD PTR [ebp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
|
self.emit_line(&format!(
|
||||||
|
" inc DWORD PTR [ebp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
self.emit_line(&format!(
|
||||||
self.emit_line(&format!(" inc QWORD PTR [rbp + {}]", offset));
|
" mov rax, QWORD PTR [rbp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
|
self.emit_line(&format!(
|
||||||
|
" inc QWORD PTR [rbp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
Target::Arm64 => {
|
||||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||||
@@ -839,7 +918,8 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(AleccError::CodegenError {
|
return Err(AleccError::CodegenError {
|
||||||
message: "Post-increment can only be applied to variables".to_string(),
|
message: "Post-increment can only be applied to variables"
|
||||||
|
.to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -849,12 +929,24 @@ impl CodeGenerator {
|
|||||||
if let Some(&offset) = self.local_variables.get(name) {
|
if let Some(&offset) = self.local_variables.get(name) {
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
self.emit_line(&format!(" dec DWORD PTR [ebp + {}]", offset));
|
self.emit_line(&format!(
|
||||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
" dec DWORD PTR [ebp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
|
self.emit_line(&format!(
|
||||||
|
" mov eax, DWORD PTR [ebp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
self.emit_line(&format!(" dec QWORD PTR [rbp + {}]", offset));
|
self.emit_line(&format!(
|
||||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
" dec QWORD PTR [rbp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
|
self.emit_line(&format!(
|
||||||
|
" mov rax, QWORD PTR [rbp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
Target::Arm64 => {
|
||||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||||
@@ -869,7 +961,8 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(AleccError::CodegenError {
|
return Err(AleccError::CodegenError {
|
||||||
message: "Pre-decrement can only be applied to variables".to_string(),
|
message: "Pre-decrement can only be applied to variables"
|
||||||
|
.to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -879,12 +972,24 @@ impl CodeGenerator {
|
|||||||
if let Some(&offset) = self.local_variables.get(name) {
|
if let Some(&offset) = self.local_variables.get(name) {
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
self.emit_line(&format!(
|
||||||
self.emit_line(&format!(" dec DWORD PTR [ebp + {}]", offset));
|
" mov eax, DWORD PTR [ebp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
|
self.emit_line(&format!(
|
||||||
|
" dec DWORD PTR [ebp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
self.emit_line(&format!(
|
||||||
self.emit_line(&format!(" dec QWORD PTR [rbp + {}]", offset));
|
" mov rax, QWORD PTR [rbp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
|
self.emit_line(&format!(
|
||||||
|
" dec QWORD PTR [rbp + {}]",
|
||||||
|
offset
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
Target::Arm64 => {
|
||||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||||
@@ -900,7 +1005,8 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(AleccError::CodegenError {
|
return Err(AleccError::CodegenError {
|
||||||
message: "Post-decrement can only be applied to variables".to_string(),
|
message: "Post-decrement can only be applied to variables"
|
||||||
|
.to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -953,13 +1059,13 @@ impl CodeGenerator {
|
|||||||
if let Some(&base_offset) = self.local_variables.get(array_name) {
|
if let Some(&base_offset) = self.local_variables.get(array_name) {
|
||||||
// Generate the index expression
|
// Generate the index expression
|
||||||
self.generate_expression(index)?;
|
self.generate_expression(index)?;
|
||||||
|
|
||||||
// Calculate the array element address: base + index * element_size
|
// Calculate the array element address: base + index * element_size
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
// Multiply index by 8 (assuming int is 8 bytes for simplicity)
|
// Multiply index by 8 (assuming int is 8 bytes for simplicity)
|
||||||
self.emit_line(" imul rax, 8"); // Use imul instead of mul
|
self.emit_line(" imul rax, 8"); // Use imul instead of mul
|
||||||
// Add base address
|
// Add base address
|
||||||
self.emit_line(&format!(" lea rbx, [rbp + {}]", base_offset));
|
self.emit_line(&format!(" lea rbx, [rbp + {}]", base_offset));
|
||||||
self.emit_line(" add rax, rbx");
|
self.emit_line(" add rax, rbx");
|
||||||
// Load the value at that address
|
// Load the value at that address
|
||||||
@@ -991,7 +1097,11 @@ impl CodeGenerator {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Assignment { target, operator, value } => {
|
Expression::Assignment {
|
||||||
|
target,
|
||||||
|
operator,
|
||||||
|
value,
|
||||||
|
} => {
|
||||||
// Handle compound assignment operators
|
// Handle compound assignment operators
|
||||||
match operator {
|
match operator {
|
||||||
crate::parser::AssignmentOperator::Assign => {
|
crate::parser::AssignmentOperator::Assign => {
|
||||||
@@ -1105,7 +1215,8 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(AleccError::CodegenError {
|
return Err(AleccError::CodegenError {
|
||||||
message: "Complex assignment targets not supported for compound operators yet".to_string(),
|
message: "Complex assignment targets not supported for compound operators yet"
|
||||||
|
.to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1144,7 +1255,8 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(AleccError::CodegenError {
|
return Err(AleccError::CodegenError {
|
||||||
message: "Complex assignment targets not supported for compound operators yet".to_string(),
|
message: "Complex assignment targets not supported for compound operators yet"
|
||||||
|
.to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1152,7 +1264,7 @@ impl CodeGenerator {
|
|||||||
|
|
||||||
fn emit_conditional_jump(&mut self, condition: bool, label: &str) -> Result<()> {
|
fn emit_conditional_jump(&mut self, condition: bool, label: &str) -> Result<()> {
|
||||||
let instruction = if condition { "jnz" } else { "jz" };
|
let instruction = if condition { "jnz" } else { "jz" };
|
||||||
|
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 | Target::Amd64 => {
|
Target::I386 | Target::Amd64 => {
|
||||||
self.emit_line(&format!(" test eax, eax"));
|
self.emit_line(&format!(" test eax, eax"));
|
||||||
@@ -1209,7 +1321,8 @@ impl CodeGenerator {
|
|||||||
label.clone()
|
label.clone()
|
||||||
} else {
|
} else {
|
||||||
let label = format!(".LC{}", self.string_literals.len());
|
let label = format!(".LC{}", self.string_literals.len());
|
||||||
self.string_literals.insert(content.to_string(), label.clone());
|
self.string_literals
|
||||||
|
.insert(content.to_string(), label.clone());
|
||||||
label
|
label
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1248,7 +1361,11 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Statement::If { condition, then_stmt, else_stmt } => {
|
Statement::If {
|
||||||
|
condition,
|
||||||
|
then_stmt,
|
||||||
|
else_stmt,
|
||||||
|
} => {
|
||||||
self.collect_string_literals_from_expression(condition)?;
|
self.collect_string_literals_from_expression(condition)?;
|
||||||
self.collect_string_literals_from_statement(then_stmt)?;
|
self.collect_string_literals_from_statement(then_stmt)?;
|
||||||
if let Some(else_statement) = else_stmt {
|
if let Some(else_statement) = else_stmt {
|
||||||
@@ -1261,7 +1378,12 @@ impl CodeGenerator {
|
|||||||
self.collect_string_literals_from_statement(body)?;
|
self.collect_string_literals_from_statement(body)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Statement::For { init, condition, increment, body } => {
|
Statement::For {
|
||||||
|
init,
|
||||||
|
condition,
|
||||||
|
increment,
|
||||||
|
body,
|
||||||
|
} => {
|
||||||
if let Some(init_stmt) = init {
|
if let Some(init_stmt) = init {
|
||||||
self.collect_string_literals_from_statement(init_stmt)?;
|
self.collect_string_literals_from_statement(init_stmt)?;
|
||||||
}
|
}
|
||||||
@@ -1280,7 +1402,7 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Ok(()) // Other statement types don't have expressions we need to collect
|
_ => Ok(()), // Other statement types don't have expressions we need to collect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1299,7 +1421,10 @@ impl CodeGenerator {
|
|||||||
self.collect_string_literals_from_expression(operand)?;
|
self.collect_string_literals_from_expression(operand)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Expression::Call { function, arguments } => {
|
Expression::Call {
|
||||||
|
function,
|
||||||
|
arguments,
|
||||||
|
} => {
|
||||||
self.collect_string_literals_from_expression(function)?;
|
self.collect_string_literals_from_expression(function)?;
|
||||||
for arg in arguments {
|
for arg in arguments {
|
||||||
self.collect_string_literals_from_expression(arg)?;
|
self.collect_string_literals_from_expression(arg)?;
|
||||||
@@ -1311,7 +1436,7 @@ impl CodeGenerator {
|
|||||||
self.collect_string_literals_from_expression(value)?;
|
self.collect_string_literals_from_expression(value)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Ok(()) // Other expression types don't contain string literals
|
_ => Ok(()), // Other expression types don't contain string literals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
123
src/compiler.rs
123
src/compiler.rs
@@ -1,15 +1,15 @@
|
|||||||
use crate::cli::Args;
|
use crate::cli::Args;
|
||||||
use crate::lexer::Lexer;
|
|
||||||
use crate::parser::Parser;
|
|
||||||
use crate::codegen::CodeGenerator;
|
use crate::codegen::CodeGenerator;
|
||||||
use crate::optimizer::{Optimizer, OptimizationLevel};
|
|
||||||
use crate::linker::Linker;
|
|
||||||
use crate::targets::Target;
|
|
||||||
use crate::error::{AleccError, Result};
|
use crate::error::{AleccError, Result};
|
||||||
|
use crate::lexer::Lexer;
|
||||||
|
use crate::linker::Linker;
|
||||||
|
use crate::optimizer::{OptimizationLevel, Optimizer};
|
||||||
|
use crate::parser::Parser;
|
||||||
|
use crate::targets::Target;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
use tracing::{info, debug, warn};
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
pub struct Compiler {
|
pub struct Compiler {
|
||||||
args: Args,
|
args: Args,
|
||||||
@@ -19,11 +19,10 @@ pub struct Compiler {
|
|||||||
|
|
||||||
impl Compiler {
|
impl Compiler {
|
||||||
pub fn new(args: Args) -> Result<Self> {
|
pub fn new(args: Args) -> Result<Self> {
|
||||||
let target = Target::from_string(&args.target).ok_or_else(|| {
|
let target =
|
||||||
AleccError::UnsupportedTarget {
|
Target::from_string(&args.target).ok_or_else(|| AleccError::UnsupportedTarget {
|
||||||
target: args.target.clone(),
|
target: args.target.clone(),
|
||||||
}
|
})?;
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
args,
|
args,
|
||||||
@@ -39,9 +38,11 @@ impl Compiler {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Compiling {} files for target {}",
|
info!(
|
||||||
self.args.input_files.len(),
|
"Compiling {} files for target {}",
|
||||||
self.target.as_str());
|
self.args.input_files.len(),
|
||||||
|
self.target.as_str()
|
||||||
|
);
|
||||||
|
|
||||||
let mut object_files = Vec::new();
|
let mut object_files = Vec::new();
|
||||||
let input_files = self.args.input_files.clone(); // Clone to avoid borrow issues
|
let input_files = self.args.input_files.clone(); // Clone to avoid borrow issues
|
||||||
@@ -49,15 +50,19 @@ impl Compiler {
|
|||||||
// Process each input file
|
// Process each input file
|
||||||
for input_file in &input_files {
|
for input_file in &input_files {
|
||||||
debug!("Processing file: {}", input_file.display());
|
debug!("Processing file: {}", input_file.display());
|
||||||
|
|
||||||
let extension = input_file.extension()
|
let extension = input_file
|
||||||
|
.extension()
|
||||||
.and_then(|ext| ext.to_str())
|
.and_then(|ext| ext.to_str())
|
||||||
.unwrap_or("");
|
.unwrap_or("");
|
||||||
|
|
||||||
match extension {
|
match extension {
|
||||||
"c" | "cpp" | "cxx" | "cc" | "C" => {
|
"c" | "cpp" | "cxx" | "cc" | "C" => {
|
||||||
let obj_file = self.compile_source_file(input_file).await?;
|
let obj_file = self.compile_source_file(input_file).await?;
|
||||||
if !self.args.compile_only && !self.args.assembly_only && !self.args.preprocess_only {
|
if !self.args.compile_only
|
||||||
|
&& !self.args.assembly_only
|
||||||
|
&& !self.args.preprocess_only
|
||||||
|
{
|
||||||
object_files.push(obj_file);
|
object_files.push(obj_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,10 +76,15 @@ impl Compiler {
|
|||||||
object_files.push(input_file.clone());
|
object_files.push(input_file.clone());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
warn!("Unknown file extension for {}, treating as C source",
|
warn!(
|
||||||
input_file.display());
|
"Unknown file extension for {}, treating as C source",
|
||||||
|
input_file.display()
|
||||||
|
);
|
||||||
let obj_file = self.compile_source_file(input_file).await?;
|
let obj_file = self.compile_source_file(input_file).await?;
|
||||||
if !self.args.compile_only && !self.args.assembly_only && !self.args.preprocess_only {
|
if !self.args.compile_only
|
||||||
|
&& !self.args.assembly_only
|
||||||
|
&& !self.args.preprocess_only
|
||||||
|
{
|
||||||
object_files.push(obj_file);
|
object_files.push(obj_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,19 +106,20 @@ impl Compiler {
|
|||||||
info!("Compiling source file: {}", input_file.display());
|
info!("Compiling source file: {}", input_file.display());
|
||||||
|
|
||||||
// Read source file
|
// Read source file
|
||||||
let source = fs::read_to_string(input_file).await.map_err(|_e| {
|
let source =
|
||||||
AleccError::FileNotFound {
|
fs::read_to_string(input_file)
|
||||||
path: input_file.to_string_lossy().to_string(),
|
.await
|
||||||
}
|
.map_err(|_e| AleccError::FileNotFound {
|
||||||
})?;
|
path: input_file.to_string_lossy().to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
// Preprocessing
|
// Preprocessing
|
||||||
let preprocessed = if self.args.preprocess_only {
|
let preprocessed = if self.args.preprocess_only {
|
||||||
let output_path = self.get_output_path(input_file, "i")?;
|
let output_path = self.get_output_path(input_file, "i")?;
|
||||||
let preprocessed = self.preprocess(&source, input_file).await?;
|
let preprocessed = self.preprocess(&source, input_file).await?;
|
||||||
fs::write(&output_path, preprocessed).await.map_err(|e| {
|
fs::write(&output_path, preprocessed)
|
||||||
AleccError::IoError(e)
|
.await
|
||||||
})?;
|
.map_err(|e| AleccError::IoError(e))?;
|
||||||
return Ok(output_path);
|
return Ok(output_path);
|
||||||
} else {
|
} else {
|
||||||
self.preprocess(&source, input_file).await?
|
self.preprocess(&source, input_file).await?
|
||||||
@@ -136,17 +147,17 @@ impl Compiler {
|
|||||||
|
|
||||||
if self.args.assembly_only {
|
if self.args.assembly_only {
|
||||||
let output_path = self.get_output_path(input_file, "s")?;
|
let output_path = self.get_output_path(input_file, "s")?;
|
||||||
fs::write(&output_path, assembly).await.map_err(|e| {
|
fs::write(&output_path, assembly)
|
||||||
AleccError::IoError(e)
|
.await
|
||||||
})?;
|
.map_err(|e| AleccError::IoError(e))?;
|
||||||
return Ok(output_path);
|
return Ok(output_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write assembly to temporary file
|
// Write assembly to temporary file
|
||||||
let asm_path = self.create_temp_file("s")?;
|
let asm_path = self.create_temp_file("s")?;
|
||||||
fs::write(&asm_path, assembly).await.map_err(|e| {
|
fs::write(&asm_path, assembly)
|
||||||
AleccError::IoError(e)
|
.await
|
||||||
})?;
|
.map_err(|e| AleccError::IoError(e))?;
|
||||||
|
|
||||||
// Assemble
|
// Assemble
|
||||||
let obj_path = self.assemble_file(&asm_path).await?;
|
let obj_path = self.assemble_file(&asm_path).await?;
|
||||||
@@ -156,7 +167,7 @@ impl Compiler {
|
|||||||
|
|
||||||
async fn preprocess(&self, source: &str, input_file: &Path) -> Result<String> {
|
async fn preprocess(&self, source: &str, input_file: &Path) -> Result<String> {
|
||||||
debug!("Preprocessing {}", input_file.display());
|
debug!("Preprocessing {}", input_file.display());
|
||||||
|
|
||||||
// Simple preprocessing - just handle basic #include and #define
|
// Simple preprocessing - just handle basic #include and #define
|
||||||
let mut preprocessed = String::new();
|
let mut preprocessed = String::new();
|
||||||
let mut defines = std::collections::HashMap::new();
|
let mut defines = std::collections::HashMap::new();
|
||||||
@@ -175,7 +186,7 @@ impl Compiler {
|
|||||||
// Process source line by line
|
// Process source line by line
|
||||||
for line in source.lines() {
|
for line in source.lines() {
|
||||||
let trimmed = line.trim();
|
let trimmed = line.trim();
|
||||||
|
|
||||||
if trimmed.starts_with("#include") {
|
if trimmed.starts_with("#include") {
|
||||||
// Handle #include (simplified)
|
// Handle #include (simplified)
|
||||||
match self.extract_include_file(trimmed) {
|
match self.extract_include_file(trimmed) {
|
||||||
@@ -238,7 +249,7 @@ impl Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(start) = line.find('<') {
|
if let Some(start) = line.find('<') {
|
||||||
if let Some(end) = line.rfind('>') {
|
if let Some(end) = line.rfind('>') {
|
||||||
if start != end {
|
if start != end {
|
||||||
@@ -278,7 +289,7 @@ impl Compiler {
|
|||||||
],
|
],
|
||||||
Target::Amd64 => vec![
|
Target::Amd64 => vec![
|
||||||
"/usr/include",
|
"/usr/include",
|
||||||
"/usr/local/include",
|
"/usr/local/include",
|
||||||
"/usr/include/x86_64-linux-gnu",
|
"/usr/include/x86_64-linux-gnu",
|
||||||
],
|
],
|
||||||
Target::Arm64 => vec![
|
Target::Arm64 => vec![
|
||||||
@@ -311,12 +322,12 @@ impl Compiler {
|
|||||||
|
|
||||||
let assembler = match self.target {
|
let assembler = match self.target {
|
||||||
Target::I386 => "as",
|
Target::I386 => "as",
|
||||||
Target::Amd64 => "as",
|
Target::Amd64 => "as",
|
||||||
Target::Arm64 => "aarch64-linux-gnu-as",
|
Target::Arm64 => "aarch64-linux-gnu-as",
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut command = Command::new(assembler);
|
let mut command = Command::new(assembler);
|
||||||
|
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
command.args(&["--32"]);
|
command.args(&["--32"]);
|
||||||
@@ -330,8 +341,9 @@ impl Compiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
command.args(&[
|
command.args(&[
|
||||||
"-o", &obj_path.to_string_lossy(),
|
"-o",
|
||||||
&asm_file.to_string_lossy()
|
&obj_path.to_string_lossy(),
|
||||||
|
&asm_file.to_string_lossy(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let output = command.output().map_err(|e| AleccError::CodegenError {
|
let output = command.output().map_err(|e| AleccError::CodegenError {
|
||||||
@@ -352,7 +364,7 @@ impl Compiler {
|
|||||||
info!("Linking {} object files", object_files.len());
|
info!("Linking {} object files", object_files.len());
|
||||||
|
|
||||||
let mut linker = Linker::new(self.target);
|
let mut linker = Linker::new(self.target);
|
||||||
|
|
||||||
// Set output path
|
// Set output path
|
||||||
let output_path = self.args.output.clone().unwrap_or_else(|| {
|
let output_path = self.args.output.clone().unwrap_or_else(|| {
|
||||||
if self.args.shared {
|
if self.args.shared {
|
||||||
@@ -401,20 +413,26 @@ impl Compiler {
|
|||||||
if let Some(ref output) = self.args.output {
|
if let Some(ref output) = self.args.output {
|
||||||
Ok(output.clone())
|
Ok(output.clone())
|
||||||
} else {
|
} else {
|
||||||
let stem = input_file.file_stem()
|
let stem = input_file
|
||||||
|
.file_stem()
|
||||||
.ok_or_else(|| AleccError::InvalidArgument {
|
.ok_or_else(|| AleccError::InvalidArgument {
|
||||||
message: "Invalid input file name".to_string(),
|
message: "Invalid input file name".to_string(),
|
||||||
})?;
|
})?;
|
||||||
Ok(PathBuf::from(format!("{}.{}", stem.to_string_lossy(), extension)))
|
Ok(PathBuf::from(format!(
|
||||||
|
"{}.{}",
|
||||||
|
stem.to_string_lossy(),
|
||||||
|
extension
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_temp_file(&mut self, extension: &str) -> Result<PathBuf> {
|
fn create_temp_file(&mut self, extension: &str) -> Result<PathBuf> {
|
||||||
let temp_path = std::env::temp_dir()
|
let temp_path = std::env::temp_dir().join(format!(
|
||||||
.join(format!("alecc_{}_{}.{}",
|
"alecc_{}_{}.{}",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
self.temp_files.len(),
|
self.temp_files.len(),
|
||||||
extension));
|
extension
|
||||||
|
));
|
||||||
self.temp_files.push(temp_path.clone());
|
self.temp_files.push(temp_path.clone());
|
||||||
Ok(temp_path)
|
Ok(temp_path)
|
||||||
}
|
}
|
||||||
@@ -423,8 +441,11 @@ impl Compiler {
|
|||||||
for temp_file in &self.temp_files {
|
for temp_file in &self.temp_files {
|
||||||
if temp_file.exists() {
|
if temp_file.exists() {
|
||||||
if let Err(e) = fs::remove_file(temp_file).await {
|
if let Err(e) = fs::remove_file(temp_file).await {
|
||||||
warn!("Failed to remove temporary file {}: {}",
|
warn!(
|
||||||
temp_file.display(), e);
|
"Failed to remove temporary file {}: {}",
|
||||||
|
temp_file.display(),
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
162
src/lexer.rs
162
src/lexer.rs
@@ -12,36 +12,116 @@ pub enum TokenType {
|
|||||||
Identifier(String),
|
Identifier(String),
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
Auto, Break, Case, Char, Const, Continue, Default, Do,
|
Auto,
|
||||||
Double, Else, Enum, Extern, Float, For, Goto, If,
|
Break,
|
||||||
Int, Long, Register, Return, Short, Signed, Sizeof, Static,
|
Case,
|
||||||
Struct, Switch, Typedef, Union, Unsigned, Void, Volatile, While,
|
Char,
|
||||||
|
Const,
|
||||||
|
Continue,
|
||||||
|
Default,
|
||||||
|
Do,
|
||||||
|
Double,
|
||||||
|
Else,
|
||||||
|
Enum,
|
||||||
|
Extern,
|
||||||
|
Float,
|
||||||
|
For,
|
||||||
|
Goto,
|
||||||
|
If,
|
||||||
|
Int,
|
||||||
|
Long,
|
||||||
|
Register,
|
||||||
|
Return,
|
||||||
|
Short,
|
||||||
|
Signed,
|
||||||
|
Sizeof,
|
||||||
|
Static,
|
||||||
|
Struct,
|
||||||
|
Switch,
|
||||||
|
Typedef,
|
||||||
|
Union,
|
||||||
|
Unsigned,
|
||||||
|
Void,
|
||||||
|
Volatile,
|
||||||
|
While,
|
||||||
|
|
||||||
// C++ Keywords
|
// C++ Keywords
|
||||||
Bool, Class, Explicit, Export, False, Friend, Inline, Mutable,
|
Bool,
|
||||||
Namespace, New, Operator, Private, Protected, Public, Template,
|
Class,
|
||||||
This, Throw, True, Try, Typename, Using, Virtual,
|
Explicit,
|
||||||
|
Export,
|
||||||
|
False,
|
||||||
|
Friend,
|
||||||
|
Inline,
|
||||||
|
Mutable,
|
||||||
|
Namespace,
|
||||||
|
New,
|
||||||
|
Operator,
|
||||||
|
Private,
|
||||||
|
Protected,
|
||||||
|
Public,
|
||||||
|
Template,
|
||||||
|
This,
|
||||||
|
Throw,
|
||||||
|
True,
|
||||||
|
Try,
|
||||||
|
Typename,
|
||||||
|
Using,
|
||||||
|
Virtual,
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
Plus, Minus, Multiply, Divide, Modulo,
|
Plus,
|
||||||
Assign, PlusAssign, MinusAssign, MultiplyAssign, DivideAssign, ModuloAssign,
|
Minus,
|
||||||
Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual,
|
Multiply,
|
||||||
LogicalAnd, LogicalOr, LogicalNot,
|
Divide,
|
||||||
BitwiseAnd, BitwiseOr, BitwiseXor, BitwiseNot,
|
Modulo,
|
||||||
LeftShift, RightShift, LeftShiftAssign, RightShiftAssign,
|
Assign,
|
||||||
BitwiseAndAssign, BitwiseOrAssign, BitwiseXorAssign,
|
PlusAssign,
|
||||||
Increment, Decrement,
|
MinusAssign,
|
||||||
Arrow, Dot, Question, Colon,
|
MultiplyAssign,
|
||||||
|
DivideAssign,
|
||||||
|
ModuloAssign,
|
||||||
|
Equal,
|
||||||
|
NotEqual,
|
||||||
|
Less,
|
||||||
|
Greater,
|
||||||
|
LessEqual,
|
||||||
|
GreaterEqual,
|
||||||
|
LogicalAnd,
|
||||||
|
LogicalOr,
|
||||||
|
LogicalNot,
|
||||||
|
BitwiseAnd,
|
||||||
|
BitwiseOr,
|
||||||
|
BitwiseXor,
|
||||||
|
BitwiseNot,
|
||||||
|
LeftShift,
|
||||||
|
RightShift,
|
||||||
|
LeftShiftAssign,
|
||||||
|
RightShiftAssign,
|
||||||
|
BitwiseAndAssign,
|
||||||
|
BitwiseOrAssign,
|
||||||
|
BitwiseXorAssign,
|
||||||
|
Increment,
|
||||||
|
Decrement,
|
||||||
|
Arrow,
|
||||||
|
Dot,
|
||||||
|
Question,
|
||||||
|
Colon,
|
||||||
|
|
||||||
// Delimiters
|
// Delimiters
|
||||||
LeftParen, RightParen,
|
LeftParen,
|
||||||
LeftBrace, RightBrace,
|
RightParen,
|
||||||
LeftBracket, RightBracket,
|
LeftBrace,
|
||||||
Semicolon, Comma,
|
RightBrace,
|
||||||
|
LeftBracket,
|
||||||
|
RightBracket,
|
||||||
|
Semicolon,
|
||||||
|
Comma,
|
||||||
Ellipsis, // ...
|
Ellipsis, // ...
|
||||||
|
|
||||||
// Preprocessor
|
// Preprocessor
|
||||||
Hash, HashHash,
|
Hash,
|
||||||
|
HashHash,
|
||||||
|
|
||||||
// Special
|
// Special
|
||||||
Eof,
|
Eof,
|
||||||
@@ -100,10 +180,10 @@ impl Lexer {
|
|||||||
|
|
||||||
pub fn tokenize(&mut self) -> crate::error::Result<Vec<Token>> {
|
pub fn tokenize(&mut self) -> crate::error::Result<Vec<Token>> {
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
|
|
||||||
while !self.is_at_end() {
|
while !self.is_at_end() {
|
||||||
self.skip_whitespace();
|
self.skip_whitespace();
|
||||||
|
|
||||||
if self.is_at_end() {
|
if self.is_at_end() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -128,7 +208,7 @@ impl Lexer {
|
|||||||
|
|
||||||
fn scan_token(&mut self) -> crate::error::Result<Option<TokenType>> {
|
fn scan_token(&mut self) -> crate::error::Result<Option<TokenType>> {
|
||||||
let c = self.advance();
|
let c = self.advance();
|
||||||
|
|
||||||
match c {
|
match c {
|
||||||
'+' => {
|
'+' => {
|
||||||
if self.match_char('=') {
|
if self.match_char('=') {
|
||||||
@@ -365,7 +445,7 @@ impl Lexer {
|
|||||||
}
|
}
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(crate::error::AleccError::LexError {
|
Err(crate::error::AleccError::LexError {
|
||||||
line: self.line,
|
line: self.line,
|
||||||
column: self.column,
|
column: self.column,
|
||||||
@@ -375,13 +455,13 @@ impl Lexer {
|
|||||||
|
|
||||||
fn scan_string(&mut self) -> crate::error::Result<Option<TokenType>> {
|
fn scan_string(&mut self) -> crate::error::Result<Option<TokenType>> {
|
||||||
let mut value = String::new();
|
let mut value = String::new();
|
||||||
|
|
||||||
while !self.is_at_end() && self.current_char() != '"' {
|
while !self.is_at_end() && self.current_char() != '"' {
|
||||||
if self.current_char() == '\n' {
|
if self.current_char() == '\n' {
|
||||||
self.line += 1;
|
self.line += 1;
|
||||||
self.column = 1;
|
self.column = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.current_char() == '\\' {
|
if self.current_char() == '\\' {
|
||||||
self.advance();
|
self.advance();
|
||||||
if !self.is_at_end() {
|
if !self.is_at_end() {
|
||||||
@@ -402,7 +482,7 @@ impl Lexer {
|
|||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_at_end() {
|
if self.is_at_end() {
|
||||||
return Err(crate::error::AleccError::LexError {
|
return Err(crate::error::AleccError::LexError {
|
||||||
line: self.line,
|
line: self.line,
|
||||||
@@ -410,7 +490,7 @@ impl Lexer {
|
|||||||
message: "Unterminated string literal".to_string(),
|
message: "Unterminated string literal".to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.advance(); // consume closing '"'
|
self.advance(); // consume closing '"'
|
||||||
Ok(Some(TokenType::StringLiteral(value)))
|
Ok(Some(TokenType::StringLiteral(value)))
|
||||||
}
|
}
|
||||||
@@ -423,7 +503,7 @@ impl Lexer {
|
|||||||
message: "Unterminated character literal".to_string(),
|
message: "Unterminated character literal".to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let c = if self.current_char() == '\\' {
|
let c = if self.current_char() == '\\' {
|
||||||
self.advance();
|
self.advance();
|
||||||
if self.is_at_end() {
|
if self.is_at_end() {
|
||||||
@@ -445,9 +525,9 @@ impl Lexer {
|
|||||||
} else {
|
} else {
|
||||||
self.current_char()
|
self.current_char()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.advance();
|
self.advance();
|
||||||
|
|
||||||
if self.is_at_end() || self.current_char() != '\'' {
|
if self.is_at_end() || self.current_char() != '\'' {
|
||||||
return Err(crate::error::AleccError::LexError {
|
return Err(crate::error::AleccError::LexError {
|
||||||
line: self.line,
|
line: self.line,
|
||||||
@@ -455,30 +535,30 @@ impl Lexer {
|
|||||||
message: "Unterminated character literal".to_string(),
|
message: "Unterminated character literal".to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.advance(); // consume closing '\''
|
self.advance(); // consume closing '\''
|
||||||
Ok(Some(TokenType::CharLiteral(c)))
|
Ok(Some(TokenType::CharLiteral(c)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_number(&mut self) -> crate::error::Result<Option<TokenType>> {
|
fn scan_number(&mut self) -> crate::error::Result<Option<TokenType>> {
|
||||||
let start = self.position - 1;
|
let start = self.position - 1;
|
||||||
|
|
||||||
while !self.is_at_end() && self.current_char().is_ascii_digit() {
|
while !self.is_at_end() && self.current_char().is_ascii_digit() {
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut is_float = false;
|
let mut is_float = false;
|
||||||
if !self.is_at_end() && self.current_char() == '.' && self.peek().is_ascii_digit() {
|
if !self.is_at_end() && self.current_char() == '.' && self.peek().is_ascii_digit() {
|
||||||
is_float = true;
|
is_float = true;
|
||||||
self.advance(); // consume '.'
|
self.advance(); // consume '.'
|
||||||
|
|
||||||
while !self.is_at_end() && self.current_char().is_ascii_digit() {
|
while !self.is_at_end() && self.current_char().is_ascii_digit() {
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = &self.input[start..self.position];
|
let text = &self.input[start..self.position];
|
||||||
|
|
||||||
if is_float {
|
if is_float {
|
||||||
match text.parse::<f64>() {
|
match text.parse::<f64>() {
|
||||||
Ok(value) => Ok(Some(TokenType::FloatLiteral(value))),
|
Ok(value) => Ok(Some(TokenType::FloatLiteral(value))),
|
||||||
@@ -502,7 +582,7 @@ impl Lexer {
|
|||||||
|
|
||||||
fn scan_identifier(&mut self) -> crate::error::Result<Option<TokenType>> {
|
fn scan_identifier(&mut self) -> crate::error::Result<Option<TokenType>> {
|
||||||
let start = self.position - 1;
|
let start = self.position - 1;
|
||||||
|
|
||||||
while !self.is_at_end() {
|
while !self.is_at_end() {
|
||||||
let c = self.current_char();
|
let c = self.current_char();
|
||||||
if c.is_ascii_alphanumeric() || c == '_' {
|
if c.is_ascii_alphanumeric() || c == '_' {
|
||||||
@@ -511,7 +591,7 @@ impl Lexer {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = &self.input[start..self.position];
|
let text = &self.input[start..self.position];
|
||||||
let token_type = match text {
|
let token_type = match text {
|
||||||
"auto" => TokenType::Auto,
|
"auto" => TokenType::Auto,
|
||||||
@@ -571,7 +651,7 @@ impl Lexer {
|
|||||||
"virtual" => TokenType::Virtual,
|
"virtual" => TokenType::Virtual,
|
||||||
_ => TokenType::Identifier(text.to_string()),
|
_ => TokenType::Identifier(text.to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Some(token_type))
|
Ok(Some(token_type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/lib.rs
12
src/lib.rs
@@ -1,9 +1,9 @@
|
|||||||
pub mod lexer;
|
|
||||||
pub mod parser;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod targets;
|
|
||||||
pub mod compiler;
|
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
pub mod codegen;
|
||||||
|
pub mod compiler;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod optimizer;
|
pub mod lexer;
|
||||||
pub mod linker;
|
pub mod linker;
|
||||||
|
pub mod optimizer;
|
||||||
|
pub mod parser;
|
||||||
|
pub mod targets;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::targets::Target;
|
|
||||||
use crate::error::{AleccError, Result};
|
use crate::error::{AleccError, Result};
|
||||||
|
use crate::targets::Target;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ impl Linker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let linker_command = self.build_linker_command()?;
|
let linker_command = self.build_linker_command()?;
|
||||||
|
|
||||||
let output = Command::new(&linker_command[0])
|
let output = Command::new(&linker_command[0])
|
||||||
.args(&linker_command[1..])
|
.args(&linker_command[1..])
|
||||||
.output()
|
.output()
|
||||||
@@ -108,14 +108,14 @@ impl Linker {
|
|||||||
|
|
||||||
fn build_linker_command(&self) -> Result<Vec<String>> {
|
fn build_linker_command(&self) -> Result<Vec<String>> {
|
||||||
let mut command = Vec::new();
|
let mut command = Vec::new();
|
||||||
|
|
||||||
// Choose linker based on target
|
// Choose linker based on target
|
||||||
let linker = match self.target {
|
let linker = match self.target {
|
||||||
Target::I386 => "ld",
|
Target::I386 => "ld",
|
||||||
Target::Amd64 => "ld",
|
Target::Amd64 => "ld",
|
||||||
Target::Arm64 => "aarch64-linux-gnu-ld",
|
Target::Arm64 => "aarch64-linux-gnu-ld",
|
||||||
};
|
};
|
||||||
|
|
||||||
command.push(linker.to_string());
|
command.push(linker.to_string());
|
||||||
|
|
||||||
// Target-specific flags
|
// Target-specific flags
|
||||||
@@ -238,10 +238,7 @@ impl Linker {
|
|||||||
"/usr/lib64",
|
"/usr/lib64",
|
||||||
"/lib64",
|
"/lib64",
|
||||||
],
|
],
|
||||||
Target::Arm64 => vec![
|
Target::Arm64 => vec!["/usr/lib/aarch64-linux-gnu", "/lib/aarch64-linux-gnu"],
|
||||||
"/usr/lib/aarch64-linux-gnu",
|
|
||||||
"/lib/aarch64-linux-gnu",
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for path in lib_paths {
|
for path in lib_paths {
|
||||||
@@ -274,7 +271,7 @@ impl Linker {
|
|||||||
|
|
||||||
let libgcc_path = String::from_utf8_lossy(&output.stdout);
|
let libgcc_path = String::from_utf8_lossy(&output.stdout);
|
||||||
let libgcc_path = libgcc_path.trim();
|
let libgcc_path = libgcc_path.trim();
|
||||||
|
|
||||||
if let Some(parent) = Path::new(libgcc_path).parent() {
|
if let Some(parent) = Path::new(libgcc_path).parent() {
|
||||||
Ok(parent.to_string_lossy().to_string())
|
Ok(parent.to_string_lossy().to_string())
|
||||||
} else {
|
} else {
|
||||||
@@ -286,15 +283,15 @@ impl Linker {
|
|||||||
|
|
||||||
pub async fn link_shared_library(&self, soname: Option<&str>) -> Result<()> {
|
pub async fn link_shared_library(&self, soname: Option<&str>) -> Result<()> {
|
||||||
let mut command = self.build_linker_command()?;
|
let mut command = self.build_linker_command()?;
|
||||||
|
|
||||||
// Remove executable-specific flags
|
// Remove executable-specific flags
|
||||||
command.retain(|arg| arg != "-pie" && !arg.starts_with("-dynamic-linker"));
|
command.retain(|arg| arg != "-pie" && !arg.starts_with("-dynamic-linker"));
|
||||||
|
|
||||||
// Add shared library flags
|
// Add shared library flags
|
||||||
if !command.contains(&"-shared".to_string()) {
|
if !command.contains(&"-shared".to_string()) {
|
||||||
command.push("-shared".to_string());
|
command.push("-shared".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(soname) = soname {
|
if let Some(soname) = soname {
|
||||||
command.push("-soname".to_string());
|
command.push("-soname".to_string());
|
||||||
command.push(soname.to_string());
|
command.push(soname.to_string());
|
||||||
@@ -322,7 +319,7 @@ impl Linker {
|
|||||||
// Use ar to create static library
|
// Use ar to create static library
|
||||||
let mut command = vec!["ar".to_string(), "rcs".to_string()];
|
let mut command = vec!["ar".to_string(), "rcs".to_string()];
|
||||||
command.push(self.output_path.to_string_lossy().to_string());
|
command.push(self.output_path.to_string_lossy().to_string());
|
||||||
|
|
||||||
for obj in &self.object_files {
|
for obj in &self.object_files {
|
||||||
command.push(obj.to_string_lossy().to_string());
|
command.push(obj.to_string_lossy().to_string());
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/main.rs
26
src/main.rs
@@ -1,19 +1,19 @@
|
|||||||
use clap::Parser;
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use tracing::{info, error};
|
use clap::Parser;
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
mod compiler;
|
|
||||||
mod lexer;
|
|
||||||
mod parser;
|
|
||||||
mod codegen;
|
|
||||||
mod optimizer;
|
|
||||||
mod linker;
|
|
||||||
mod targets;
|
|
||||||
mod cli;
|
mod cli;
|
||||||
|
mod codegen;
|
||||||
|
mod compiler;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod lexer;
|
||||||
|
mod linker;
|
||||||
|
mod optimizer;
|
||||||
|
mod parser;
|
||||||
|
mod targets;
|
||||||
|
|
||||||
use compiler::Compiler;
|
|
||||||
use cli::Args;
|
use cli::Args;
|
||||||
|
use compiler::Compiler;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
@@ -21,11 +21,11 @@ async fn main() -> Result<()> {
|
|||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
info!("Starting ALECC compiler v{}", env!("CARGO_PKG_VERSION"));
|
info!("Starting ALECC compiler v{}", env!("CARGO_PKG_VERSION"));
|
||||||
|
|
||||||
let mut compiler = Compiler::new(args.clone())?;
|
let mut compiler = Compiler::new(args.clone())?;
|
||||||
|
|
||||||
match compiler.compile().await {
|
match compiler.compile().await {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
info!("Compilation completed successfully");
|
info!("Compilation completed successfully");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::parser::Program;
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
use crate::parser::Program;
|
||||||
|
|
||||||
pub struct Optimizer {
|
pub struct Optimizer {
|
||||||
level: OptimizationLevel,
|
level: OptimizationLevel,
|
||||||
@@ -40,9 +40,7 @@ impl Optimizer {
|
|||||||
// No optimization
|
// No optimization
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
OptimizationLevel::Basic => {
|
OptimizationLevel::Basic => self.basic_optimizations(program),
|
||||||
self.basic_optimizations(program)
|
|
||||||
}
|
|
||||||
OptimizationLevel::Moderate => {
|
OptimizationLevel::Moderate => {
|
||||||
self.basic_optimizations(program)?;
|
self.basic_optimizations(program)?;
|
||||||
self.moderate_optimizations(program)
|
self.moderate_optimizations(program)
|
||||||
@@ -67,59 +65,59 @@ impl Optimizer {
|
|||||||
fn basic_optimizations(&mut self, program: &mut Program) -> Result<()> {
|
fn basic_optimizations(&mut self, program: &mut Program) -> Result<()> {
|
||||||
// Dead code elimination
|
// Dead code elimination
|
||||||
self.eliminate_dead_code(program)?;
|
self.eliminate_dead_code(program)?;
|
||||||
|
|
||||||
// Constant folding
|
// Constant folding
|
||||||
self.fold_constants(program)?;
|
self.fold_constants(program)?;
|
||||||
|
|
||||||
// Basic strength reduction
|
// Basic strength reduction
|
||||||
self.basic_strength_reduction(program)?;
|
self.basic_strength_reduction(program)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn moderate_optimizations(&mut self, program: &mut Program) -> Result<()> {
|
fn moderate_optimizations(&mut self, program: &mut Program) -> Result<()> {
|
||||||
// Loop optimizations
|
// Loop optimizations
|
||||||
self.optimize_loops(program)?;
|
self.optimize_loops(program)?;
|
||||||
|
|
||||||
// Function inlining (basic)
|
// Function inlining (basic)
|
||||||
self.inline_small_functions(program)?;
|
self.inline_small_functions(program)?;
|
||||||
|
|
||||||
// Common subexpression elimination
|
// Common subexpression elimination
|
||||||
self.eliminate_common_subexpressions(program)?;
|
self.eliminate_common_subexpressions(program)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aggressive_optimizations(&mut self, program: &mut Program) -> Result<()> {
|
fn aggressive_optimizations(&mut self, program: &mut Program) -> Result<()> {
|
||||||
// Advanced loop optimizations
|
// Advanced loop optimizations
|
||||||
self.advanced_loop_optimizations(program)?;
|
self.advanced_loop_optimizations(program)?;
|
||||||
|
|
||||||
// Aggressive function inlining
|
// Aggressive function inlining
|
||||||
self.aggressive_inlining(program)?;
|
self.aggressive_inlining(program)?;
|
||||||
|
|
||||||
// Inter-procedural optimizations
|
// Inter-procedural optimizations
|
||||||
self.interprocedural_optimizations(program)?;
|
self.interprocedural_optimizations(program)?;
|
||||||
|
|
||||||
// Vectorization
|
// Vectorization
|
||||||
self.auto_vectorization(program)?;
|
self.auto_vectorization(program)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_optimizations(&mut self, program: &mut Program) -> Result<()> {
|
fn size_optimizations(&mut self, program: &mut Program) -> Result<()> {
|
||||||
// Prefer smaller code sequences
|
// Prefer smaller code sequences
|
||||||
self.optimize_for_size(program)?;
|
self.optimize_for_size(program)?;
|
||||||
|
|
||||||
// Merge identical functions
|
// Merge identical functions
|
||||||
self.merge_identical_functions(program)?;
|
self.merge_identical_functions(program)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aggressive_size_optimizations(&mut self, program: &mut Program) -> Result<()> {
|
fn aggressive_size_optimizations(&mut self, program: &mut Program) -> Result<()> {
|
||||||
// More aggressive size optimizations that might impact performance
|
// More aggressive size optimizations that might impact performance
|
||||||
self.ultra_size_optimizations(program)?;
|
self.ultra_size_optimizations(program)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
313
src/parser.rs
313
src/parser.rs
@@ -1,5 +1,5 @@
|
|||||||
use crate::lexer::{Token, TokenType};
|
|
||||||
use crate::error::{AleccError, Result};
|
use crate::error::{AleccError, Result};
|
||||||
|
use crate::lexer::{Token, TokenType};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -97,30 +97,59 @@ pub enum Expression {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum BinaryOperator {
|
pub enum BinaryOperator {
|
||||||
Add, Subtract, Multiply, Divide, Modulo,
|
Add,
|
||||||
Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual,
|
Subtract,
|
||||||
LogicalAnd, LogicalOr,
|
Multiply,
|
||||||
BitwiseAnd, BitwiseOr, BitwiseXor,
|
Divide,
|
||||||
LeftShift, RightShift,
|
Modulo,
|
||||||
|
Equal,
|
||||||
|
NotEqual,
|
||||||
|
Less,
|
||||||
|
Greater,
|
||||||
|
LessEqual,
|
||||||
|
GreaterEqual,
|
||||||
|
LogicalAnd,
|
||||||
|
LogicalOr,
|
||||||
|
BitwiseAnd,
|
||||||
|
BitwiseOr,
|
||||||
|
BitwiseXor,
|
||||||
|
LeftShift,
|
||||||
|
RightShift,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum UnaryOperator {
|
pub enum UnaryOperator {
|
||||||
Plus, Minus, LogicalNot, BitwiseNot,
|
Plus,
|
||||||
PreIncrement, PostIncrement,
|
Minus,
|
||||||
PreDecrement, PostDecrement,
|
LogicalNot,
|
||||||
AddressOf, Dereference,
|
BitwiseNot,
|
||||||
|
PreIncrement,
|
||||||
|
PostIncrement,
|
||||||
|
PreDecrement,
|
||||||
|
PostDecrement,
|
||||||
|
AddressOf,
|
||||||
|
Dereference,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum AssignmentOperator {
|
pub enum AssignmentOperator {
|
||||||
Assign, PlusAssign, MinusAssign, MultiplyAssign, DivideAssign,
|
Assign,
|
||||||
#[allow(dead_code)] ModuloAssign,
|
PlusAssign,
|
||||||
#[allow(dead_code)] BitwiseAndAssign,
|
MinusAssign,
|
||||||
#[allow(dead_code)] BitwiseOrAssign,
|
MultiplyAssign,
|
||||||
#[allow(dead_code)] BitwiseXorAssign,
|
DivideAssign,
|
||||||
#[allow(dead_code)] LeftShiftAssign,
|
#[allow(dead_code)]
|
||||||
#[allow(dead_code)] RightShiftAssign,
|
ModuloAssign,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
BitwiseAndAssign,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
BitwiseOrAssign,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
BitwiseXorAssign,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
LeftShiftAssign,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
RightShiftAssign,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -235,9 +264,11 @@ impl Parser {
|
|||||||
} else {
|
} else {
|
||||||
let storage_class = self.parse_storage_class();
|
let storage_class = self.parse_storage_class();
|
||||||
let base_type = self.parse_type()?;
|
let base_type = self.parse_type()?;
|
||||||
|
|
||||||
if self.check(&TokenType::LeftParen) ||
|
if self.check(&TokenType::LeftParen)
|
||||||
(self.check(&TokenType::Identifier("".to_string())) && self.peek_ahead(1)?.token_type == TokenType::LeftParen) {
|
|| (self.check(&TokenType::Identifier("".to_string()))
|
||||||
|
&& self.peek_ahead(1)?.token_type == TokenType::LeftParen)
|
||||||
|
{
|
||||||
self.parse_function_declaration(storage_class, base_type)
|
self.parse_function_declaration(storage_class, base_type)
|
||||||
} else {
|
} else {
|
||||||
self.parse_variable_declaration(storage_class, base_type)
|
self.parse_variable_declaration(storage_class, base_type)
|
||||||
@@ -300,7 +331,7 @@ impl Parser {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut fields = Vec::new();
|
let mut fields = Vec::new();
|
||||||
|
|
||||||
if self.match_token(&TokenType::LeftBrace) {
|
if self.match_token(&TokenType::LeftBrace) {
|
||||||
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
|
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
|
||||||
let field_type = self.parse_type()?;
|
let field_type = self.parse_type()?;
|
||||||
@@ -313,11 +344,14 @@ impl Parser {
|
|||||||
message: "Expected field name".to_string(),
|
message: "Expected field name".to_string(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.consume(&TokenType::Semicolon, "Expected ';' after field declaration")?;
|
self.consume(
|
||||||
|
&TokenType::Semicolon,
|
||||||
|
"Expected ';' after field declaration",
|
||||||
|
)?;
|
||||||
fields.push((field_name, field_type));
|
fields.push((field_name, field_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.consume(&TokenType::RightBrace, "Expected '}' after struct body")?;
|
self.consume(&TokenType::RightBrace, "Expected '}' after struct body")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +371,7 @@ impl Parser {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut fields = Vec::new();
|
let mut fields = Vec::new();
|
||||||
|
|
||||||
if self.match_token(&TokenType::LeftBrace) {
|
if self.match_token(&TokenType::LeftBrace) {
|
||||||
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
|
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
|
||||||
let field_type = self.parse_type()?;
|
let field_type = self.parse_type()?;
|
||||||
@@ -350,11 +384,14 @@ impl Parser {
|
|||||||
message: "Expected field name".to_string(),
|
message: "Expected field name".to_string(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.consume(&TokenType::Semicolon, "Expected ';' after field declaration")?;
|
self.consume(
|
||||||
|
&TokenType::Semicolon,
|
||||||
|
"Expected ';' after field declaration",
|
||||||
|
)?;
|
||||||
fields.push((field_name, field_type));
|
fields.push((field_name, field_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.consume(&TokenType::RightBrace, "Expected '}' after union body")?;
|
self.consume(&TokenType::RightBrace, "Expected '}' after union body")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,10 +411,11 @@ impl Parser {
|
|||||||
|
|
||||||
let mut variants = Vec::new();
|
let mut variants = Vec::new();
|
||||||
let mut current_value = 0i64;
|
let mut current_value = 0i64;
|
||||||
|
|
||||||
if self.match_token(&TokenType::LeftBrace) {
|
if self.match_token(&TokenType::LeftBrace) {
|
||||||
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
|
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
|
||||||
let variant_name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
let variant_name = if let TokenType::Identifier(name) = &self.advance()?.token_type
|
||||||
|
{
|
||||||
name.clone()
|
name.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(AleccError::ParseError {
|
return Err(AleccError::ParseError {
|
||||||
@@ -386,7 +424,7 @@ impl Parser {
|
|||||||
message: "Expected enum variant name".to_string(),
|
message: "Expected enum variant name".to_string(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.match_token(&TokenType::Assign) {
|
if self.match_token(&TokenType::Assign) {
|
||||||
if let TokenType::IntegerLiteral(value) = &self.advance()?.token_type {
|
if let TokenType::IntegerLiteral(value) = &self.advance()?.token_type {
|
||||||
current_value = *value;
|
current_value = *value;
|
||||||
@@ -398,15 +436,15 @@ impl Parser {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
variants.push((variant_name, current_value));
|
variants.push((variant_name, current_value));
|
||||||
current_value += 1;
|
current_value += 1;
|
||||||
|
|
||||||
if !self.check(&TokenType::RightBrace) {
|
if !self.check(&TokenType::RightBrace) {
|
||||||
self.consume(&TokenType::Comma, "Expected ',' between enum variants")?;
|
self.consume(&TokenType::Comma, "Expected ',' between enum variants")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.consume(&TokenType::RightBrace, "Expected '}' after enum body")?;
|
self.consume(&TokenType::RightBrace, "Expected '}' after enum body")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,11 +453,13 @@ impl Parser {
|
|||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
fn current_token(&self) -> Result<&Token> {
|
fn current_token(&self) -> Result<&Token> {
|
||||||
self.tokens.get(self.current).ok_or_else(|| AleccError::ParseError {
|
self.tokens
|
||||||
line: 0,
|
.get(self.current)
|
||||||
column: 0,
|
.ok_or_else(|| AleccError::ParseError {
|
||||||
message: "Unexpected end of input".to_string(),
|
line: 0,
|
||||||
})
|
column: 0,
|
||||||
|
message: "Unexpected end of input".to_string(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn advance(&mut self) -> Result<&Token> {
|
fn advance(&mut self) -> Result<&Token> {
|
||||||
@@ -445,32 +485,39 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn previous(&self) -> Result<&Token> {
|
fn previous(&self) -> Result<&Token> {
|
||||||
self.tokens.get(self.current - 1).ok_or_else(|| AleccError::ParseError {
|
self.tokens
|
||||||
line: 0,
|
.get(self.current - 1)
|
||||||
column: 0,
|
.ok_or_else(|| AleccError::ParseError {
|
||||||
message: "No previous token".to_string(),
|
line: 0,
|
||||||
})
|
column: 0,
|
||||||
|
message: "No previous token".to_string(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_ahead(&self, offset: usize) -> Result<&Token> {
|
fn peek_ahead(&self, offset: usize) -> Result<&Token> {
|
||||||
self.tokens.get(self.current + offset).ok_or_else(|| AleccError::ParseError {
|
self.tokens
|
||||||
line: 0,
|
.get(self.current + offset)
|
||||||
column: 0,
|
.ok_or_else(|| AleccError::ParseError {
|
||||||
message: "Unexpected end of input".to_string(),
|
line: 0,
|
||||||
})
|
column: 0,
|
||||||
|
message: "Unexpected end of input".to_string(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_at_end(&self) -> bool {
|
fn is_at_end(&self) -> bool {
|
||||||
self.current >= self.tokens.len() ||
|
self.current >= self.tokens.len()
|
||||||
matches!(self.tokens.get(self.current).map(|t| &t.token_type), Some(TokenType::Eof))
|
|| matches!(
|
||||||
|
self.tokens.get(self.current).map(|t| &t.token_type),
|
||||||
|
Some(TokenType::Eof)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(&self, token_type: &TokenType) -> bool {
|
fn check(&self, token_type: &TokenType) -> bool {
|
||||||
if self.is_at_end() {
|
if self.is_at_end() {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
std::mem::discriminant(&self.current_token().unwrap().token_type) ==
|
std::mem::discriminant(&self.current_token().unwrap().token_type)
|
||||||
std::mem::discriminant(token_type)
|
== std::mem::discriminant(token_type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,12 +568,16 @@ impl Parser {
|
|||||||
message: "Expected typedef name".to_string(),
|
message: "Expected typedef name".to_string(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.consume(&TokenType::Semicolon, "Expected ';' after typedef")?;
|
self.consume(&TokenType::Semicolon, "Expected ';' after typedef")?;
|
||||||
Ok(Declaration::TypeDef(name, base_type))
|
Ok(Declaration::TypeDef(name, base_type))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_function_declaration(&mut self, _storage: StorageClass, return_type: Type) -> Result<Declaration> {
|
fn parse_function_declaration(
|
||||||
|
&mut self,
|
||||||
|
_storage: StorageClass,
|
||||||
|
return_type: Type,
|
||||||
|
) -> Result<Declaration> {
|
||||||
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
||||||
name.clone()
|
name.clone()
|
||||||
} else {
|
} else {
|
||||||
@@ -538,16 +589,16 @@ impl Parser {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.consume(&TokenType::LeftParen, "Expected '(' after function name")?;
|
self.consume(&TokenType::LeftParen, "Expected '(' after function name")?;
|
||||||
|
|
||||||
let mut parameters = Vec::new();
|
let mut parameters = Vec::new();
|
||||||
let mut is_variadic = false;
|
let mut is_variadic = false;
|
||||||
|
|
||||||
while !self.check(&TokenType::RightParen) && !self.is_at_end() {
|
while !self.check(&TokenType::RightParen) && !self.is_at_end() {
|
||||||
if self.match_token(&TokenType::Ellipsis) {
|
if self.match_token(&TokenType::Ellipsis) {
|
||||||
is_variadic = true;
|
is_variadic = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let param_type = self.parse_type()?;
|
let param_type = self.parse_type()?;
|
||||||
let param_name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
let param_name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
||||||
name.clone()
|
name.clone()
|
||||||
@@ -558,21 +609,24 @@ impl Parser {
|
|||||||
message: "Expected parameter name".to_string(),
|
message: "Expected parameter name".to_string(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
parameters.push((param_name, param_type));
|
parameters.push((param_name, param_type));
|
||||||
|
|
||||||
if !self.check(&TokenType::RightParen) {
|
if !self.check(&TokenType::RightParen) {
|
||||||
self.consume(&TokenType::Comma, "Expected ',' between parameters")?;
|
self.consume(&TokenType::Comma, "Expected ',' between parameters")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.consume(&TokenType::RightParen, "Expected ')' after parameters")?;
|
self.consume(&TokenType::RightParen, "Expected ')' after parameters")?;
|
||||||
|
|
||||||
let body = if self.check(&TokenType::LeftBrace) {
|
let body = if self.check(&TokenType::LeftBrace) {
|
||||||
self.advance()?; // Consume the LeftBrace
|
self.advance()?; // Consume the LeftBrace
|
||||||
self.parse_block_statement()?
|
self.parse_block_statement()?
|
||||||
} else {
|
} else {
|
||||||
self.consume(&TokenType::Semicolon, "Expected ';' after function declaration")?;
|
self.consume(
|
||||||
|
&TokenType::Semicolon,
|
||||||
|
"Expected ';' after function declaration",
|
||||||
|
)?;
|
||||||
Statement::Block(Vec::new()) // Forward declaration
|
Statement::Block(Vec::new()) // Forward declaration
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -588,7 +642,11 @@ impl Parser {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_variable_declaration(&mut self, _storage: StorageClass, var_type: Type) -> Result<Declaration> {
|
fn parse_variable_declaration(
|
||||||
|
&mut self,
|
||||||
|
_storage: StorageClass,
|
||||||
|
var_type: Type,
|
||||||
|
) -> Result<Declaration> {
|
||||||
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
||||||
name.clone()
|
name.clone()
|
||||||
} else {
|
} else {
|
||||||
@@ -605,8 +663,11 @@ impl Parser {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
self.consume(&TokenType::Semicolon, "Expected ';' after variable declaration")?;
|
self.consume(
|
||||||
|
&TokenType::Semicolon,
|
||||||
|
"Expected ';' after variable declaration",
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(Declaration::Variable(name, var_type, initializer))
|
Ok(Declaration::Variable(name, var_type, initializer))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,7 +677,7 @@ impl Parser {
|
|||||||
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
|
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
|
||||||
statements.push(self.parse_statement()?);
|
statements.push(self.parse_statement()?);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.consume(&TokenType::RightBrace, "Expected '}'")?;
|
self.consume(&TokenType::RightBrace, "Expected '}'")?;
|
||||||
Ok(Statement::Block(statements))
|
Ok(Statement::Block(statements))
|
||||||
}
|
}
|
||||||
@@ -676,8 +737,11 @@ impl Parser {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
self.consume(&TokenType::Semicolon, "Expected ';' after variable declaration")?;
|
self.consume(
|
||||||
|
&TokenType::Semicolon,
|
||||||
|
"Expected ';' after variable declaration",
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(Statement::Declaration {
|
Ok(Statement::Declaration {
|
||||||
name,
|
name,
|
||||||
var_type,
|
var_type,
|
||||||
@@ -695,14 +759,14 @@ impl Parser {
|
|||||||
self.consume(&TokenType::LeftParen, "Expected '(' after 'if'")?;
|
self.consume(&TokenType::LeftParen, "Expected '(' after 'if'")?;
|
||||||
let condition = self.parse_expression()?;
|
let condition = self.parse_expression()?;
|
||||||
self.consume(&TokenType::RightParen, "Expected ')' after if condition")?;
|
self.consume(&TokenType::RightParen, "Expected ')' after if condition")?;
|
||||||
|
|
||||||
let then_stmt = Box::new(self.parse_statement()?);
|
let then_stmt = Box::new(self.parse_statement()?);
|
||||||
let else_stmt = if self.match_token(&TokenType::Else) {
|
let else_stmt = if self.match_token(&TokenType::Else) {
|
||||||
Some(Box::new(self.parse_statement()?))
|
Some(Box::new(self.parse_statement()?))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Statement::If {
|
Ok(Statement::If {
|
||||||
condition,
|
condition,
|
||||||
then_stmt,
|
then_stmt,
|
||||||
@@ -715,39 +779,39 @@ impl Parser {
|
|||||||
let condition = self.parse_expression()?;
|
let condition = self.parse_expression()?;
|
||||||
self.consume(&TokenType::RightParen, "Expected ')' after while condition")?;
|
self.consume(&TokenType::RightParen, "Expected ')' after while condition")?;
|
||||||
let body = Box::new(self.parse_statement()?);
|
let body = Box::new(self.parse_statement()?);
|
||||||
|
|
||||||
Ok(Statement::While { condition, body })
|
Ok(Statement::While { condition, body })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_for_statement(&mut self) -> Result<Statement> {
|
fn parse_for_statement(&mut self) -> Result<Statement> {
|
||||||
self.consume(&TokenType::LeftParen, "Expected '(' after 'for'")?;
|
self.consume(&TokenType::LeftParen, "Expected '(' after 'for'")?;
|
||||||
|
|
||||||
let init = if self.check(&TokenType::Semicolon) {
|
let init = if self.check(&TokenType::Semicolon) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(Box::new(self.parse_statement()?))
|
Some(Box::new(self.parse_statement()?))
|
||||||
};
|
};
|
||||||
|
|
||||||
if init.is_none() {
|
if init.is_none() {
|
||||||
self.advance()?; // consume semicolon
|
self.advance()?; // consume semicolon
|
||||||
}
|
}
|
||||||
|
|
||||||
let condition = if self.check(&TokenType::Semicolon) {
|
let condition = if self.check(&TokenType::Semicolon) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self.parse_expression()?)
|
Some(self.parse_expression()?)
|
||||||
};
|
};
|
||||||
self.consume(&TokenType::Semicolon, "Expected ';' after for condition")?;
|
self.consume(&TokenType::Semicolon, "Expected ';' after for condition")?;
|
||||||
|
|
||||||
let increment = if self.check(&TokenType::RightParen) {
|
let increment = if self.check(&TokenType::RightParen) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self.parse_expression()?)
|
Some(self.parse_expression()?)
|
||||||
};
|
};
|
||||||
self.consume(&TokenType::RightParen, "Expected ')' after for clauses")?;
|
self.consume(&TokenType::RightParen, "Expected ')' after for clauses")?;
|
||||||
|
|
||||||
let body = Box::new(self.parse_statement()?);
|
let body = Box::new(self.parse_statement()?);
|
||||||
|
|
||||||
Ok(Statement::For {
|
Ok(Statement::For {
|
||||||
init,
|
init,
|
||||||
condition,
|
condition,
|
||||||
@@ -757,10 +821,18 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_type(&self, token_type: &TokenType) -> bool {
|
fn is_type(&self, token_type: &TokenType) -> bool {
|
||||||
matches!(token_type,
|
matches!(
|
||||||
TokenType::Int | TokenType::Float | TokenType::Double |
|
token_type,
|
||||||
TokenType::Char | TokenType::Void | TokenType::Short |
|
TokenType::Int
|
||||||
TokenType::Long | TokenType::Signed | TokenType::Unsigned)
|
| TokenType::Float
|
||||||
|
| TokenType::Double
|
||||||
|
| TokenType::Char
|
||||||
|
| TokenType::Void
|
||||||
|
| TokenType::Short
|
||||||
|
| TokenType::Long
|
||||||
|
| TokenType::Signed
|
||||||
|
| TokenType::Unsigned
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expression(&mut self) -> Result<Expression> {
|
fn parse_expression(&mut self) -> Result<Expression> {
|
||||||
@@ -769,7 +841,7 @@ impl Parser {
|
|||||||
|
|
||||||
fn parse_assignment(&mut self) -> Result<Expression> {
|
fn parse_assignment(&mut self) -> Result<Expression> {
|
||||||
let expr = self.parse_logical_or()?;
|
let expr = self.parse_logical_or()?;
|
||||||
|
|
||||||
if self.match_token(&TokenType::Assign) {
|
if self.match_token(&TokenType::Assign) {
|
||||||
let value = self.parse_assignment()?; // Right associative
|
let value = self.parse_assignment()?; // Right associative
|
||||||
return Ok(Expression::Assignment {
|
return Ok(Expression::Assignment {
|
||||||
@@ -806,13 +878,13 @@ impl Parser {
|
|||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_logical_or(&mut self) -> Result<Expression> {
|
fn parse_logical_or(&mut self) -> Result<Expression> {
|
||||||
let mut expr = self.parse_logical_and()?;
|
let mut expr = self.parse_logical_and()?;
|
||||||
|
|
||||||
while self.match_token(&TokenType::LogicalOr) {
|
while self.match_token(&TokenType::LogicalOr) {
|
||||||
let operator = BinaryOperator::LogicalOr;
|
let operator = BinaryOperator::LogicalOr;
|
||||||
let right = self.parse_logical_and()?;
|
let right = self.parse_logical_and()?;
|
||||||
@@ -822,13 +894,13 @@ impl Parser {
|
|||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_logical_and(&mut self) -> Result<Expression> {
|
fn parse_logical_and(&mut self) -> Result<Expression> {
|
||||||
let mut expr = self.parse_bitwise_or()?;
|
let mut expr = self.parse_bitwise_or()?;
|
||||||
|
|
||||||
while self.match_token(&TokenType::LogicalAnd) {
|
while self.match_token(&TokenType::LogicalAnd) {
|
||||||
let operator = BinaryOperator::LogicalAnd;
|
let operator = BinaryOperator::LogicalAnd;
|
||||||
let right = self.parse_bitwise_or()?;
|
let right = self.parse_bitwise_or()?;
|
||||||
@@ -838,13 +910,13 @@ impl Parser {
|
|||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_bitwise_or(&mut self) -> Result<Expression> {
|
fn parse_bitwise_or(&mut self) -> Result<Expression> {
|
||||||
let mut expr = self.parse_bitwise_xor()?;
|
let mut expr = self.parse_bitwise_xor()?;
|
||||||
|
|
||||||
while self.match_token(&TokenType::BitwiseOr) {
|
while self.match_token(&TokenType::BitwiseOr) {
|
||||||
let operator = BinaryOperator::BitwiseOr;
|
let operator = BinaryOperator::BitwiseOr;
|
||||||
let right = self.parse_bitwise_xor()?;
|
let right = self.parse_bitwise_xor()?;
|
||||||
@@ -854,13 +926,13 @@ impl Parser {
|
|||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_bitwise_xor(&mut self) -> Result<Expression> {
|
fn parse_bitwise_xor(&mut self) -> Result<Expression> {
|
||||||
let mut expr = self.parse_bitwise_and()?;
|
let mut expr = self.parse_bitwise_and()?;
|
||||||
|
|
||||||
while self.match_token(&TokenType::BitwiseXor) {
|
while self.match_token(&TokenType::BitwiseXor) {
|
||||||
let operator = BinaryOperator::BitwiseXor;
|
let operator = BinaryOperator::BitwiseXor;
|
||||||
let right = self.parse_bitwise_and()?;
|
let right = self.parse_bitwise_and()?;
|
||||||
@@ -870,13 +942,13 @@ impl Parser {
|
|||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_bitwise_and(&mut self) -> Result<Expression> {
|
fn parse_bitwise_and(&mut self) -> Result<Expression> {
|
||||||
let mut expr = self.parse_equality()?;
|
let mut expr = self.parse_equality()?;
|
||||||
|
|
||||||
while self.match_token(&TokenType::BitwiseAnd) {
|
while self.match_token(&TokenType::BitwiseAnd) {
|
||||||
let operator = BinaryOperator::BitwiseAnd;
|
let operator = BinaryOperator::BitwiseAnd;
|
||||||
let right = self.parse_equality()?;
|
let right = self.parse_equality()?;
|
||||||
@@ -886,13 +958,13 @@ impl Parser {
|
|||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_equality(&mut self) -> Result<Expression> {
|
fn parse_equality(&mut self) -> Result<Expression> {
|
||||||
let mut expr = self.parse_comparison()?;
|
let mut expr = self.parse_comparison()?;
|
||||||
|
|
||||||
while self.match_tokens(&[TokenType::Equal, TokenType::NotEqual]) {
|
while self.match_tokens(&[TokenType::Equal, TokenType::NotEqual]) {
|
||||||
let operator = match self.previous()?.token_type {
|
let operator = match self.previous()?.token_type {
|
||||||
TokenType::Equal => BinaryOperator::Equal,
|
TokenType::Equal => BinaryOperator::Equal,
|
||||||
@@ -906,15 +978,19 @@ impl Parser {
|
|||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_comparison(&mut self) -> Result<Expression> {
|
fn parse_comparison(&mut self) -> Result<Expression> {
|
||||||
let mut expr = self.parse_shift()?;
|
let mut expr = self.parse_shift()?;
|
||||||
|
|
||||||
while self.match_tokens(&[TokenType::Greater, TokenType::GreaterEqual,
|
while self.match_tokens(&[
|
||||||
TokenType::Less, TokenType::LessEqual]) {
|
TokenType::Greater,
|
||||||
|
TokenType::GreaterEqual,
|
||||||
|
TokenType::Less,
|
||||||
|
TokenType::LessEqual,
|
||||||
|
]) {
|
||||||
let operator = match self.previous()?.token_type {
|
let operator = match self.previous()?.token_type {
|
||||||
TokenType::Greater => BinaryOperator::Greater,
|
TokenType::Greater => BinaryOperator::Greater,
|
||||||
TokenType::GreaterEqual => BinaryOperator::GreaterEqual,
|
TokenType::GreaterEqual => BinaryOperator::GreaterEqual,
|
||||||
@@ -929,13 +1005,13 @@ impl Parser {
|
|||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_shift(&mut self) -> Result<Expression> {
|
fn parse_shift(&mut self) -> Result<Expression> {
|
||||||
let mut expr = self.parse_term()?;
|
let mut expr = self.parse_term()?;
|
||||||
|
|
||||||
while self.match_tokens(&[TokenType::LeftShift, TokenType::RightShift]) {
|
while self.match_tokens(&[TokenType::LeftShift, TokenType::RightShift]) {
|
||||||
let operator = match self.previous()?.token_type {
|
let operator = match self.previous()?.token_type {
|
||||||
TokenType::LeftShift => BinaryOperator::LeftShift,
|
TokenType::LeftShift => BinaryOperator::LeftShift,
|
||||||
@@ -949,13 +1025,13 @@ impl Parser {
|
|||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_term(&mut self) -> Result<Expression> {
|
fn parse_term(&mut self) -> Result<Expression> {
|
||||||
let mut expr = self.parse_factor()?;
|
let mut expr = self.parse_factor()?;
|
||||||
|
|
||||||
while self.match_tokens(&[TokenType::Minus, TokenType::Plus]) {
|
while self.match_tokens(&[TokenType::Minus, TokenType::Plus]) {
|
||||||
let operator = match self.previous()?.token_type {
|
let operator = match self.previous()?.token_type {
|
||||||
TokenType::Minus => BinaryOperator::Subtract,
|
TokenType::Minus => BinaryOperator::Subtract,
|
||||||
@@ -969,13 +1045,13 @@ impl Parser {
|
|||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_factor(&mut self) -> Result<Expression> {
|
fn parse_factor(&mut self) -> Result<Expression> {
|
||||||
let mut expr = self.parse_unary()?;
|
let mut expr = self.parse_unary()?;
|
||||||
|
|
||||||
while self.match_tokens(&[TokenType::Divide, TokenType::Multiply, TokenType::Modulo]) {
|
while self.match_tokens(&[TokenType::Divide, TokenType::Multiply, TokenType::Modulo]) {
|
||||||
let operator = match self.previous()?.token_type {
|
let operator = match self.previous()?.token_type {
|
||||||
TokenType::Divide => BinaryOperator::Divide,
|
TokenType::Divide => BinaryOperator::Divide,
|
||||||
@@ -990,12 +1066,21 @@ impl Parser {
|
|||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_unary(&mut self) -> Result<Expression> {
|
fn parse_unary(&mut self) -> Result<Expression> {
|
||||||
if self.match_tokens(&[TokenType::LogicalNot, TokenType::Minus, TokenType::Plus, TokenType::Increment, TokenType::Decrement, TokenType::BitwiseAnd, TokenType::Multiply, TokenType::BitwiseNot]) {
|
if self.match_tokens(&[
|
||||||
|
TokenType::LogicalNot,
|
||||||
|
TokenType::Minus,
|
||||||
|
TokenType::Plus,
|
||||||
|
TokenType::Increment,
|
||||||
|
TokenType::Decrement,
|
||||||
|
TokenType::BitwiseAnd,
|
||||||
|
TokenType::Multiply,
|
||||||
|
TokenType::BitwiseNot,
|
||||||
|
]) {
|
||||||
let operator = match self.previous()?.token_type {
|
let operator = match self.previous()?.token_type {
|
||||||
TokenType::LogicalNot => UnaryOperator::LogicalNot,
|
TokenType::LogicalNot => UnaryOperator::LogicalNot,
|
||||||
TokenType::Minus => UnaryOperator::Minus,
|
TokenType::Minus => UnaryOperator::Minus,
|
||||||
@@ -1013,13 +1098,13 @@ impl Parser {
|
|||||||
operand: Box::new(right),
|
operand: Box::new(right),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.parse_call()
|
self.parse_call()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_call(&mut self) -> Result<Expression> {
|
fn parse_call(&mut self) -> Result<Expression> {
|
||||||
let mut expr = self.parse_primary()?;
|
let mut expr = self.parse_primary()?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if self.match_token(&TokenType::LeftParen) {
|
if self.match_token(&TokenType::LeftParen) {
|
||||||
expr = self.finish_call(expr)?;
|
expr = self.finish_call(expr)?;
|
||||||
@@ -1045,13 +1130,13 @@ impl Parser {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_call(&mut self, callee: Expression) -> Result<Expression> {
|
fn finish_call(&mut self, callee: Expression) -> Result<Expression> {
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
if !self.check(&TokenType::RightParen) {
|
if !self.check(&TokenType::RightParen) {
|
||||||
loop {
|
loop {
|
||||||
arguments.push(self.parse_expression()?);
|
arguments.push(self.parse_expression()?);
|
||||||
@@ -1060,9 +1145,9 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.consume(&TokenType::RightParen, "Expected ')' after arguments")?;
|
self.consume(&TokenType::RightParen, "Expected ')' after arguments")?;
|
||||||
|
|
||||||
Ok(Expression::Call {
|
Ok(Expression::Call {
|
||||||
function: Box::new(callee),
|
function: Box::new(callee),
|
||||||
arguments,
|
arguments,
|
||||||
@@ -1075,7 +1160,7 @@ impl Parser {
|
|||||||
self.consume(&TokenType::RightParen, "Expected ')' after expression")?;
|
self.consume(&TokenType::RightParen, "Expected ')' after expression")?;
|
||||||
return Ok(expr);
|
return Ok(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
let token = self.advance()?;
|
let token = self.advance()?;
|
||||||
match &token.token_type {
|
match &token.token_type {
|
||||||
TokenType::IntegerLiteral(value) => Ok(Expression::IntegerLiteral(*value)),
|
TokenType::IntegerLiteral(value) => Ok(Expression::IntegerLiteral(*value)),
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ impl Target {
|
|||||||
pub fn native() -> Self {
|
pub fn native() -> Self {
|
||||||
#[cfg(target_arch = "x86")]
|
#[cfg(target_arch = "x86")]
|
||||||
return Target::I386;
|
return Target::I386;
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
return Target::Amd64;
|
return Target::Amd64;
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
return Target::Arm64;
|
return Target::Arm64;
|
||||||
|
|
||||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
|
||||||
return Target::Amd64; // Default fallback
|
return Target::Amd64; // Default fallback
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ impl Target {
|
|||||||
pub fn linker(&self) -> &'static str {
|
pub fn linker(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Target::I386 => "ld -m elf_i386",
|
Target::I386 => "ld -m elf_i386",
|
||||||
Target::Amd64 => "ld -m elf_x86_64",
|
Target::Amd64 => "ld -m elf_x86_64",
|
||||||
Target::Arm64 => "aarch64-linux-gnu-ld",
|
Target::Arm64 => "aarch64-linux-gnu-ld",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,9 +113,9 @@ impl Target {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum CallingConvention {
|
pub enum CallingConvention {
|
||||||
Cdecl, // x86-32
|
Cdecl, // x86-32
|
||||||
SystemV, // x86-64
|
SystemV, // x86-64
|
||||||
Aapcs64, // ARM64
|
Aapcs64, // ARM64
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@@ -131,8 +131,15 @@ impl RegisterSet {
|
|||||||
pub fn general_purpose_registers(&self) -> &'static [&'static str] {
|
pub fn general_purpose_registers(&self) -> &'static [&'static str] {
|
||||||
match self {
|
match self {
|
||||||
RegisterSet::X86_32 => &["eax", "ebx", "ecx", "edx", "esi", "edi"],
|
RegisterSet::X86_32 => &["eax", "ebx", "ecx", "edx", "esi", "edi"],
|
||||||
RegisterSet::X86_64 => &["rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"],
|
RegisterSet::X86_64 => &[
|
||||||
RegisterSet::Aarch64 => &["x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28"],
|
"rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13",
|
||||||
|
"r14", "r15",
|
||||||
|
],
|
||||||
|
RegisterSet::Aarch64 => &[
|
||||||
|
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12",
|
||||||
|
"x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24",
|
||||||
|
"x25", "x26", "x27", "x28",
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use alecc::cli::Args;
|
||||||
|
use alecc::codegen::CodeGenerator;
|
||||||
|
use alecc::compiler::Compiler;
|
||||||
use alecc::lexer::{Lexer, TokenType};
|
use alecc::lexer::{Lexer, TokenType};
|
||||||
use alecc::parser::Parser;
|
use alecc::parser::Parser;
|
||||||
use alecc::codegen::CodeGenerator;
|
|
||||||
use alecc::targets::Target;
|
use alecc::targets::Target;
|
||||||
use alecc::compiler::Compiler;
|
|
||||||
use alecc::cli::Args;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -13,7 +13,7 @@ mod tests {
|
|||||||
let input = "int main() { return 0; }".to_string();
|
let input = "int main() { return 0; }".to_string();
|
||||||
let mut lexer = Lexer::new(input);
|
let mut lexer = Lexer::new(input);
|
||||||
let tokens = lexer.tokenize().unwrap();
|
let tokens = lexer.tokenize().unwrap();
|
||||||
|
|
||||||
assert!(!tokens.is_empty());
|
assert!(!tokens.is_empty());
|
||||||
assert!(matches!(tokens[0].token_type, TokenType::Int));
|
assert!(matches!(tokens[0].token_type, TokenType::Int));
|
||||||
}
|
}
|
||||||
@@ -23,8 +23,11 @@ mod tests {
|
|||||||
let input = "42 3.14 'a' \"hello\"".to_string();
|
let input = "42 3.14 'a' \"hello\"".to_string();
|
||||||
let mut lexer = Lexer::new(input);
|
let mut lexer = Lexer::new(input);
|
||||||
let tokens = lexer.tokenize().unwrap();
|
let tokens = lexer.tokenize().unwrap();
|
||||||
|
|
||||||
assert!(matches!(tokens[0].token_type, TokenType::IntegerLiteral(42)));
|
assert!(matches!(
|
||||||
|
tokens[0].token_type,
|
||||||
|
TokenType::IntegerLiteral(42)
|
||||||
|
));
|
||||||
assert!(matches!(tokens[1].token_type, TokenType::FloatLiteral(_)));
|
assert!(matches!(tokens[1].token_type, TokenType::FloatLiteral(_)));
|
||||||
assert!(matches!(tokens[2].token_type, TokenType::CharLiteral('a')));
|
assert!(matches!(tokens[2].token_type, TokenType::CharLiteral('a')));
|
||||||
assert!(matches!(tokens[3].token_type, TokenType::StringLiteral(_)));
|
assert!(matches!(tokens[3].token_type, TokenType::StringLiteral(_)));
|
||||||
@@ -35,7 +38,7 @@ mod tests {
|
|||||||
let input = "+ - * / == != < > <= >=".to_string();
|
let input = "+ - * / == != < > <= >=".to_string();
|
||||||
let mut lexer = Lexer::new(input);
|
let mut lexer = Lexer::new(input);
|
||||||
let tokens = lexer.tokenize().unwrap();
|
let tokens = lexer.tokenize().unwrap();
|
||||||
|
|
||||||
assert!(matches!(tokens[0].token_type, TokenType::Plus));
|
assert!(matches!(tokens[0].token_type, TokenType::Plus));
|
||||||
assert!(matches!(tokens[1].token_type, TokenType::Minus));
|
assert!(matches!(tokens[1].token_type, TokenType::Minus));
|
||||||
assert!(matches!(tokens[2].token_type, TokenType::Multiply));
|
assert!(matches!(tokens[2].token_type, TokenType::Multiply));
|
||||||
@@ -49,9 +52,10 @@ mod tests {
|
|||||||
let input = "int x; // comment\n/* block comment */ int y;".to_string();
|
let input = "int x; // comment\n/* block comment */ int y;".to_string();
|
||||||
let mut lexer = Lexer::new(input);
|
let mut lexer = Lexer::new(input);
|
||||||
let tokens = lexer.tokenize().unwrap();
|
let tokens = lexer.tokenize().unwrap();
|
||||||
|
|
||||||
// Comments should be filtered out
|
// Comments should be filtered out
|
||||||
let identifier_count = tokens.iter()
|
let identifier_count = tokens
|
||||||
|
.iter()
|
||||||
.filter(|t| matches!(t.token_type, TokenType::Identifier(_)))
|
.filter(|t| matches!(t.token_type, TokenType::Identifier(_)))
|
||||||
.count();
|
.count();
|
||||||
assert_eq!(identifier_count, 2); // x and y
|
assert_eq!(identifier_count, 2); // x and y
|
||||||
@@ -64,7 +68,7 @@ mod tests {
|
|||||||
let tokens = lexer.tokenize().unwrap();
|
let tokens = lexer.tokenize().unwrap();
|
||||||
let mut parser = Parser::new(tokens);
|
let mut parser = Parser::new(tokens);
|
||||||
let program = parser.parse().unwrap();
|
let program = parser.parse().unwrap();
|
||||||
|
|
||||||
assert_eq!(program.functions.len(), 1);
|
assert_eq!(program.functions.len(), 1);
|
||||||
assert_eq!(program.functions[0].name, "main");
|
assert_eq!(program.functions[0].name, "main");
|
||||||
}
|
}
|
||||||
@@ -92,10 +96,10 @@ mod tests {
|
|||||||
let tokens = lexer.tokenize().unwrap();
|
let tokens = lexer.tokenize().unwrap();
|
||||||
let mut parser = Parser::new(tokens);
|
let mut parser = Parser::new(tokens);
|
||||||
let program = parser.parse().unwrap();
|
let program = parser.parse().unwrap();
|
||||||
|
|
||||||
let mut codegen = CodeGenerator::new(Target::Amd64);
|
let mut codegen = CodeGenerator::new(Target::Amd64);
|
||||||
let assembly = codegen.generate(&program).unwrap();
|
let assembly = codegen.generate(&program).unwrap();
|
||||||
|
|
||||||
assert!(assembly.contains("main:"));
|
assert!(assembly.contains("main:"));
|
||||||
assert!(assembly.contains("ret"));
|
assert!(assembly.contains("ret"));
|
||||||
}
|
}
|
||||||
@@ -136,13 +140,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_error_types() {
|
fn test_error_types() {
|
||||||
use alecc::error::AleccError;
|
use alecc::error::AleccError;
|
||||||
|
|
||||||
let lex_error = AleccError::LexError {
|
let lex_error = AleccError::LexError {
|
||||||
line: 1,
|
line: 1,
|
||||||
column: 5,
|
column: 5,
|
||||||
message: "Unexpected character".to_string(),
|
message: "Unexpected character".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(format!("{}", lex_error).contains("line 1"));
|
assert!(format!("{}", lex_error).contains("line 1"));
|
||||||
assert!(format!("{}", lex_error).contains("column 5"));
|
assert!(format!("{}", lex_error).contains("column 5"));
|
||||||
}
|
}
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user