1use super::jvm_types::{ConstantPool, ConstantPoolEntry, JvmInstruction};
2use crate::analyzer::SemanticAnalyzer;
3use std::fs;
5
6#[derive(Debug)]
8pub enum JavaClassGeneratorError {
9 CompilationError(String),
10}
11
12impl From<Box<dyn std::error::Error>> for JavaClassGeneratorError {
13 fn from(error: Box<dyn std::error::Error>) -> Self {
14 JavaClassGeneratorError::CompilationError(error.to_string())
15 }
16}
17
18impl From<String> for JavaClassGeneratorError {
19 fn from(error: String) -> Self {
20 JavaClassGeneratorError::CompilationError(error)
21 }
22}
23
24impl std::fmt::Display for JavaClassGeneratorError {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 match self {
27 JavaClassGeneratorError::CompilationError(msg) => write!(f, "Compilation error: {msg}"),
28 }
29 }
30}
31
32impl std::error::Error for JavaClassGeneratorError {}
33
34pub struct JavaClassGenerator {
36 constant_pool: ConstantPool,
37 class_name: String,
38}
39
40impl JavaClassGenerator {
41 pub fn new(class_name: String) -> Self {
42 Self {
43 constant_pool: ConstantPool::new(),
44 class_name,
45 }
46 }
47
48 pub fn generate_dice_class(
50 &mut self,
51 expression: &str,
52 ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
53 let mut analyzer = SemanticAnalyzer::new(expression)?;
55 let ast = analyzer.analyze()?;
56
57 if let Some(stmt) = ast.statement {
58 let crate::ast::StatementKind::Expression { expr } = stmt.kind;
59 let crate::ast::ExpressionKind::Dice { count, faces } = expr.kind;
60
61 self.setup_constant_pool()
62 .map_err(JavaClassGeneratorError::CompilationError)?;
63 let bytecode = self.generate_dice_bytecode(count, faces)?;
64 return self.generate_class_file(bytecode);
65 }
66
67 Err("Invalid expression".into())
68 }
69
70 pub fn generate_dice_instructions(
72 &mut self,
73 expression: &str,
74 ) -> Result<Vec<JvmInstruction>, Box<dyn std::error::Error>> {
75 let mut analyzer = SemanticAnalyzer::new(expression)?;
76 let ast = analyzer.analyze()?;
77
78 if let Some(stmt) = ast.statement {
79 let crate::ast::StatementKind::Expression { expr } = stmt.kind;
80 let crate::ast::ExpressionKind::Dice { count, faces } = expr.kind;
81
82 return Ok(self.generate_dice_bytecode(count, faces)?);
83 }
84
85 Err("Invalid expression".into())
86 }
87
88 fn setup_constant_pool(&mut self) -> Result<(), String> {
90 self.constant_pool.add_utf8(self.class_name.clone())?; self.constant_pool
92 .add_utf8("java/lang/Object".to_string())?; self.constant_pool.add_utf8("main".to_string())?; self.constant_pool
95 .add_utf8("([Ljava/lang/String;)V".to_string())?; self.constant_pool.add_utf8("Code".to_string())?; self.constant_pool
98 .add_utf8("java/lang/System".to_string())?; self.constant_pool.add_utf8("out".to_string())?; self.constant_pool.add_utf8("err".to_string())?; self.constant_pool
102 .add_utf8("Ljava/io/PrintStream;".to_string())?; self.constant_pool
104 .add_utf8("java/io/PrintStream".to_string())?; self.constant_pool.add_utf8("println".to_string())?; self.constant_pool.add_utf8("(I)V".to_string())?; self.constant_pool.add_utf8("java/lang/Math".to_string())?; self.constant_pool.add_utf8("random".to_string())?; self.constant_pool.add_utf8("()D".to_string())?;
111 self.constant_pool.add_utf8("Total: ".to_string())?;
113 self.constant_pool.add_utf8("print".to_string())?;
115 self.constant_pool
117 .add_utf8("(Ljava/lang/String;)V".to_string())?;
118
119 self.constant_pool.add_class(1)?;
122 self.constant_pool.add_class(2)?;
124 self.constant_pool.add_class(6)?;
126 self.constant_pool.add_class(10)?;
128 self.constant_pool.add_class(13)?;
130
131 self.constant_pool.add_string(16)?;
134
135 self.constant_pool.add_name_and_type(3, 4)?;
138 self.constant_pool.add_name_and_type(7, 9)?;
140 self.constant_pool.add_name_and_type(8, 9)?;
142 self.constant_pool.add_name_and_type(11, 12)?;
144 self.constant_pool.add_name_and_type(17, 18)?;
146 self.constant_pool.add_name_and_type(14, 15)?;
148
149 self.constant_pool.add_fieldref(21, 26)?;
152 self.constant_pool.add_fieldref(21, 27)?;
154 self.constant_pool.add_methodref(22, 28)?;
156 self.constant_pool.add_methodref(22, 29)?;
158 self.constant_pool.add_methodref(23, 30)?;
160
161 Ok(())
162 }
163
164 fn generate_dice_bytecode(
166 &mut self,
167 count: u32,
168 faces: u32,
169 ) -> Result<Vec<JvmInstruction>, JavaClassGeneratorError> {
170 let mut instructions = Vec::new();
171
172 if count == 1 {
173 self.generate_single_dice(&mut instructions, faces)
175 .map_err(JavaClassGeneratorError::from)?;
176 } else {
177 self.generate_multiple_dice(&mut instructions, count, faces)
179 .map_err(JavaClassGeneratorError::from)?;
180 }
181
182 instructions.push(JvmInstruction::Return);
183 Ok(instructions)
184 }
185
186 fn generate_single_dice(
188 &mut self,
189 instructions: &mut Vec<JvmInstruction>,
190 faces: u32,
191 ) -> Result<(), String> {
192 instructions.push(JvmInstruction::Invokestatic(35)); self.push_double_constant(instructions, faces as f64)?;
195 instructions.push(JvmInstruction::Dmul);
196 instructions.push(JvmInstruction::Dconst1);
197 instructions.push(JvmInstruction::Dadd);
198 instructions.push(JvmInstruction::D2i);
199
200 instructions.push(JvmInstruction::Getstatic(31)); instructions.push(JvmInstruction::Swap);
203 instructions.push(JvmInstruction::Invokevirtual(33)); Ok(())
205 }
206
207 fn generate_multiple_dice(
209 &mut self,
210 instructions: &mut Vec<JvmInstruction>,
211 count: u32,
212 faces: u32,
213 ) -> Result<(), String> {
214 instructions.push(JvmInstruction::Iconst0); for _ in 0..count {
218 instructions.push(JvmInstruction::Invokestatic(35)); self.push_double_constant(instructions, faces as f64)?;
221 instructions.push(JvmInstruction::Dmul);
222 instructions.push(JvmInstruction::Dconst1);
223 instructions.push(JvmInstruction::Dadd);
224 instructions.push(JvmInstruction::D2i);
225
226 instructions.push(JvmInstruction::Dup);
228
229 instructions.push(JvmInstruction::Getstatic(31)); instructions.push(JvmInstruction::Swap);
232 instructions.push(JvmInstruction::Invokevirtual(33)); instructions.push(JvmInstruction::Iadd);
236 }
237
238 instructions.push(JvmInstruction::Dup); instructions.push(JvmInstruction::Getstatic(32)); instructions.push(JvmInstruction::Ldc(24)); instructions.push(JvmInstruction::Invokevirtual(34)); instructions.push(JvmInstruction::Getstatic(32)); instructions.push(JvmInstruction::Swap);
247 instructions.push(JvmInstruction::Invokevirtual(33)); instructions.push(JvmInstruction::Pop); Ok(())
250 }
251
252 fn push_double_constant(
254 &mut self,
255 instructions: &mut Vec<JvmInstruction>,
256 value: f64,
257 ) -> Result<(), String> {
258 if value == 0.0 {
259 instructions.push(JvmInstruction::Dconst0);
260 } else if value == 1.0 {
261 instructions.push(JvmInstruction::Dconst1);
262 } else {
263 let int_val = value as i32;
265 self.push_int_constant(instructions, int_val)?;
266 instructions.push(JvmInstruction::I2d);
267 }
268 Ok(())
269 }
270
271 fn push_int_constant(
273 &mut self,
274 instructions: &mut Vec<JvmInstruction>,
275 value: i32,
276 ) -> Result<(), String> {
277 match value {
278 -1 => instructions.push(JvmInstruction::IconstM1),
279 0 => instructions.push(JvmInstruction::Iconst0),
280 1 => instructions.push(JvmInstruction::Iconst1),
281 2 => instructions.push(JvmInstruction::Iconst2),
282 3 => instructions.push(JvmInstruction::Iconst3),
283 4 => instructions.push(JvmInstruction::Iconst4),
284 5 => instructions.push(JvmInstruction::Iconst5),
285 _ if (-128..=127).contains(&value) => {
286 instructions.push(JvmInstruction::Bipush(value as i8));
287 }
288 _ if (-32768..=32767).contains(&value) => {
289 instructions.push(JvmInstruction::Sipush(value as i16));
290 }
291 _ => {
292 let index = self.constant_pool.add_integer(value)?;
294 instructions.push(JvmInstruction::Ldc(index));
295 }
296 }
297 Ok(())
298 }
299
300 fn generate_class_file(
302 &self,
303 bytecode_instructions: Vec<JvmInstruction>,
304 ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
305 let mut bytes = Vec::new();
306
307 bytes.extend_from_slice(&0xCAFEBABEu32.to_be_bytes());
309
310 bytes.extend_from_slice(&0u16.to_be_bytes()); bytes.extend_from_slice(&52u16.to_be_bytes()); let non_placeholder_count = self
316 .constant_pool
317 .entries()
318 .iter()
319 .filter(|entry| !matches!(entry, ConstantPoolEntry::Placeholder))
320 .count();
321 bytes.extend_from_slice(&(non_placeholder_count as u16 + 1).to_be_bytes());
322
323 self.write_constant_pool(&mut bytes);
325
326 bytes.extend_from_slice(&0x0021u16.to_be_bytes());
328
329 bytes.extend_from_slice(&19u16.to_be_bytes());
331
332 bytes.extend_from_slice(&20u16.to_be_bytes());
334
335 bytes.extend_from_slice(&0u16.to_be_bytes());
337
338 bytes.extend_from_slice(&0u16.to_be_bytes());
340
341 bytes.extend_from_slice(&1u16.to_be_bytes());
343
344 self.write_main_method(&mut bytes, bytecode_instructions);
346
347 bytes.extend_from_slice(&0u16.to_be_bytes());
349
350 Ok(bytes)
351 }
352
353 fn write_constant_pool(&self, bytes: &mut Vec<u8>) {
355 for entry in self.constant_pool.entries() {
356 match entry {
357 ConstantPoolEntry::Utf8(s) => {
358 bytes.push(1); bytes.extend_from_slice(&(s.len() as u16).to_be_bytes());
360 bytes.extend_from_slice(s.as_bytes());
361 }
362 ConstantPoolEntry::Class(name_index) => {
363 bytes.push(7); bytes.extend_from_slice(&name_index.to_be_bytes());
365 }
366 ConstantPoolEntry::String(utf8_index) => {
367 bytes.push(8); bytes.extend_from_slice(&utf8_index.to_be_bytes());
369 }
370 ConstantPoolEntry::Fieldref(class_index, name_and_type_index) => {
371 bytes.push(9); bytes.extend_from_slice(&class_index.to_be_bytes());
373 bytes.extend_from_slice(&name_and_type_index.to_be_bytes());
374 }
375 ConstantPoolEntry::Methodref(class_index, name_and_type_index) => {
376 bytes.push(10); bytes.extend_from_slice(&class_index.to_be_bytes());
378 bytes.extend_from_slice(&name_and_type_index.to_be_bytes());
379 }
380 ConstantPoolEntry::NameAndType(name_index, descriptor_index) => {
381 bytes.push(12); bytes.extend_from_slice(&name_index.to_be_bytes());
383 bytes.extend_from_slice(&descriptor_index.to_be_bytes());
384 }
385 ConstantPoolEntry::Integer(i) => {
386 bytes.push(3); bytes.extend_from_slice(&i.to_be_bytes());
388 }
389 ConstantPoolEntry::Float(f) => {
390 bytes.push(4); bytes.extend_from_slice(&f.to_be_bytes());
392 }
393 ConstantPoolEntry::Long(l) => {
394 bytes.push(5); bytes.extend_from_slice(&l.to_be_bytes());
396 }
397 ConstantPoolEntry::Double(d) => {
398 bytes.push(6); bytes.extend_from_slice(&d.to_be_bytes());
400 }
401 ConstantPoolEntry::Placeholder => {
402 continue;
406 }
407 }
408 }
409 }
410
411 fn write_main_method(&self, bytes: &mut Vec<u8>, instructions: Vec<JvmInstruction>) {
413 bytes.extend_from_slice(&0x0009u16.to_be_bytes());
415
416 bytes.extend_from_slice(&3u16.to_be_bytes());
418
419 bytes.extend_from_slice(&4u16.to_be_bytes());
421
422 bytes.extend_from_slice(&1u16.to_be_bytes());
424
425 bytes.extend_from_slice(&5u16.to_be_bytes());
427
428 let code_bytes = self.instructions_to_bytes(instructions);
430 let attribute_length = code_bytes.len() as u32 + 12;
431
432 bytes.extend_from_slice(&attribute_length.to_be_bytes());
433 bytes.extend_from_slice(&5u16.to_be_bytes()); bytes.extend_from_slice(&2u16.to_be_bytes()); bytes.extend_from_slice(&(code_bytes.len() as u32).to_be_bytes()); bytes.extend_from_slice(&code_bytes); bytes.extend_from_slice(&0u16.to_be_bytes()); bytes.extend_from_slice(&0u16.to_be_bytes()); }
440
441 fn instructions_to_bytes(&self, instructions: Vec<JvmInstruction>) -> Vec<u8> {
443 let mut bytes = Vec::new();
444
445 for instruction in instructions {
446 match instruction {
447 JvmInstruction::Iconst0 => bytes.push(0x03),
448 JvmInstruction::Iconst1 => bytes.push(0x04),
449 JvmInstruction::Iconst2 => bytes.push(0x05),
450 JvmInstruction::Iconst3 => bytes.push(0x06),
451 JvmInstruction::Iconst4 => bytes.push(0x07),
452 JvmInstruction::Iconst5 => bytes.push(0x08),
453 JvmInstruction::IconstM1 => bytes.push(0x02),
454 JvmInstruction::Bipush(value) => {
455 bytes.push(0x10);
456 bytes.push(value as u8);
457 }
458 JvmInstruction::Sipush(value) => {
459 bytes.push(0x11);
460 bytes.extend_from_slice(&(value as u16).to_be_bytes());
461 }
462 JvmInstruction::Ldc(index) => {
463 bytes.push(0x12);
464 bytes.push(index as u8);
465 }
466 JvmInstruction::Dup => bytes.push(0x59),
467 JvmInstruction::Pop => bytes.push(0x57),
468 JvmInstruction::Swap => bytes.push(0x5F),
469 JvmInstruction::Iadd => bytes.push(0x60),
470 JvmInstruction::Isub => bytes.push(0x64),
471 JvmInstruction::Imul => bytes.push(0x68),
472 JvmInstruction::Idiv => bytes.push(0x6C),
473 JvmInstruction::Irem => bytes.push(0x70),
474 JvmInstruction::Dadd => bytes.push(0x63),
475 JvmInstruction::Dsub => bytes.push(0x67),
476 JvmInstruction::Dmul => bytes.push(0x6B),
477 JvmInstruction::Ddiv => bytes.push(0x6F),
478 JvmInstruction::I2d => bytes.push(0x87),
479 JvmInstruction::D2i => bytes.push(0x8E),
480 JvmInstruction::Dconst0 => bytes.push(0x0E),
481 JvmInstruction::Dconst1 => bytes.push(0x0F),
482 JvmInstruction::Getstatic(index) => {
483 bytes.push(0xB2);
484 bytes.extend_from_slice(&index.to_be_bytes());
485 }
486 JvmInstruction::Invokestatic(index) => {
487 bytes.push(0xB8);
488 bytes.extend_from_slice(&index.to_be_bytes());
489 }
490 JvmInstruction::Invokevirtual(index) => {
491 bytes.push(0xB6);
492 bytes.extend_from_slice(&index.to_be_bytes());
493 }
494 JvmInstruction::Return => bytes.push(0xB1),
495 JvmInstruction::Ireturn => bytes.push(0xAC),
496 JvmInstruction::Nop => bytes.push(0x00),
497 other_instruction => {
498 eprintln!(
502 "Warning: JVM instruction not implemented in bytecode generation: {other_instruction:?}, falling back to NOP"
503 );
504 bytes.push(0x00); }
507 }
508 }
509
510 bytes
511 }
512
513 pub fn constant_pool(&self) -> &ConstantPool {
514 &self.constant_pool
515 }
516}
517
518pub fn generate_java_class(
520 expression: &str,
521 class_name: &str,
522) -> Result<(), Box<dyn std::error::Error>> {
523 let mut generator = JavaClassGenerator::new(class_name.to_string());
524 let class_bytes = generator.generate_dice_class(expression)?;
525 let filename = format!("{class_name}.class");
526 fs::write(&filename, &class_bytes)?;
527
528 println!("Generated: {filename}");
529 println!("Run with: java {class_name}");
530 println!("View bytecode with: javap -c {class_name}.class");
531
532 Ok(())
533}
534
535pub fn generate_vm_instructions(
537 expression: &str,
538) -> Result<(Vec<JvmInstruction>, ConstantPool), Box<dyn std::error::Error>> {
539 let mut generator = JavaClassGenerator::new("DiceRoll".to_string());
540 generator
541 .setup_constant_pool()
542 .map_err(JavaClassGeneratorError::CompilationError)?;
543 let instructions = generator.generate_dice_instructions(expression)?;
544 Ok((instructions, generator.constant_pool.clone()))
545}