1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::ast::Statement;

use super::Codegen;

pub struct MipsCodegen;

impl Codegen for MipsCodegen {
  fn generate(&self, ast: Vec<Statement>) -> String {
    let mut data_section = celestial_hub_astrolabe::ast::DataSection::default();
    let mut text_section = celestial_hub_astrolabe::ast::TextSection {
      entrypoint: "main".to_string(),
      ..Default::default()
    };

    let mut register_counter = 0;
    let mut register_map = std::collections::HashMap::new();

    for statement in ast {
      match statement {
        Statement::VariableDeclaration(var) => {
          let register = format!("${}", register_counter);
          register_counter += 1;
          register_map.insert(var.name.clone(), register.clone());

          match var.value {
            crate::ast::Expr::Operand(op) => match op {
              crate::ast::Operand::LiteralI8(val) => {
                text_section
                  .statements
                  .push(celestial_hub_astrolabe::ast::Statement::Instruction(
                    celestial_hub_astrolabe::ast::Instruction::Li(
                      [
                        celestial_hub_astrolabe::ast::InstructionArgument::Register(
                          celestial_hub_astrolabe::ast::Register { name: register },
                        ),
                        celestial_hub_astrolabe::ast::InstructionArgument::Immediate(val as u32),
                      ]
                      .into(),
                    ),
                  ));
              }
              crate::ast::Operand::LiteralStr(_) => todo!(),
              crate::ast::Operand::LiteralBool(_) => todo!(),
              crate::ast::Operand::LiteralI16(_) => todo!(),
              crate::ast::Operand::LiteralI32(_) => todo!(),
              crate::ast::Operand::LiteralI64(_) => todo!(),
              crate::ast::Operand::LiteralU8(_) => todo!(),
              crate::ast::Operand::LiteralU16(_) => todo!(),
              crate::ast::Operand::LiteralU32(_) => todo!(),
              crate::ast::Operand::LiteralU64(_) => todo!(),
              crate::ast::Operand::LiteralF32(_) => todo!(),
              crate::ast::Operand::LiteralF64(_) => todo!(),
              crate::ast::Operand::Identifier(_) => todo!(),
            },
            crate::ast::Expr::BinaryOperation(bin_op) => match bin_op {
              crate::ast::BinaryOperation::Arithmetic {
                lhs, operator, rhs, ..
              } => {
                if let (
                  crate::ast::Operand::Identifier(lhs),
                  crate::ast::Operand::Identifier(rhs),
                ) = (lhs, rhs)
                {
                  let lhs_register = register_map.get(&lhs).unwrap().clone();
                  let rhs_register = register_map.get(&rhs).unwrap().clone();

                  // Depending on the operator, we need to use different instructions
                  text_section.statements.push(
                    celestial_hub_astrolabe::ast::Statement::Instruction(match operator {
                      crate::ast::Operator::Add => celestial_hub_astrolabe::ast::Instruction::Add(
                        [
                          celestial_hub_astrolabe::ast::InstructionArgument::Register(
                            celestial_hub_astrolabe::ast::Register { name: register },
                          ),
                          celestial_hub_astrolabe::ast::InstructionArgument::Register(
                            celestial_hub_astrolabe::ast::Register { name: lhs_register },
                          ),
                          celestial_hub_astrolabe::ast::InstructionArgument::Register(
                            celestial_hub_astrolabe::ast::Register { name: rhs_register },
                          ),
                        ]
                        .into(),
                      ),
                      crate::ast::Operator::Sub => todo!(),
                      crate::ast::Operator::Mul => todo!(),
                      crate::ast::Operator::Div => todo!(),
                    }),
                  );
                }
              }
              crate::ast::BinaryOperation::Conditional {
                lhs,
                condition,
                rhs,
                operation_type,
              } => todo!(),
            },
            crate::ast::Expr::FunctionCall(_) => todo!(),
          }
        }
        Statement::ConditionalJump {
          condition,
          label,
          location,
        } => todo!(),
        Statement::UnconditionalJump { label, location } => todo!(),
        Statement::Label { name, location } => todo!(),
        Statement::FunctionDefinition(_) => todo!(),
      }
    }

    let program = celestial_hub_astrolabe::ast::Program {
      data_section,
      text_section,
    };

    format!("{program}")
  }
}