diff --git a/Cargo.toml b/Cargo.toml index 4df366c..3b7d99f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,16 @@ [workspace] -members = ["crates/*"] \ No newline at end of file +members = [ + "cs_class_printer", + "cs_model", + "cs_parser", + "cs_vm", +] + +[package] +name = "coldsquare" +version = "0.1.0" +edition = "2021" + +[dependencies] +cs_class_printer = { path = "cs_class_printer" } +cs_parser = { path = "cs_parser" } diff --git a/crates/file-info/Cargo.toml b/cs_class_printer/Cargo.toml similarity index 71% rename from crates/file-info/Cargo.toml rename to cs_class_printer/Cargo.toml index 94102bd..822d723 100644 --- a/crates/file-info/Cargo.toml +++ b/cs_class_printer/Cargo.toml @@ -1,9 +1,9 @@ [package] -name = "file-info" +name = "cs_class_printer" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -file-parser = { path = "../file-parser" } \ No newline at end of file +cs_parser = { path = "../cs_parser" } \ No newline at end of file diff --git a/cs_class_printer/src/lib.rs b/cs_class_printer/src/lib.rs new file mode 100644 index 0000000..bfa4e47 --- /dev/null +++ b/cs_class_printer/src/lib.rs @@ -0,0 +1,13 @@ +use crate::ui::display_class; +use cs_parser::ClassFile; + +mod ui; + +/// Pretty-prints a class file +pub fn print(class_file: &ClassFile) { + let stdout = std::io::stdout(); + + if let Err(why) = display_class(stdout.lock(), class_file) { + eprintln!("{}", why); + } +} diff --git a/crates/file-info/src/ui.rs b/cs_class_printer/src/ui.rs similarity index 98% rename from crates/file-info/src/ui.rs rename to cs_class_printer/src/ui.rs index 158e210..9cbb08b 100644 --- a/crates/file-info/src/ui.rs +++ b/cs_class_printer/src/ui.rs @@ -1,4 +1,4 @@ -use file_parser::ClassFile; +use cs_parser::ClassFile; use std::io; use std::io::Write; diff --git a/crates/file-parser/Cargo.toml b/cs_model/Cargo.toml similarity index 88% rename from crates/file-parser/Cargo.toml rename to cs_model/Cargo.toml index ad85e8a..4d0c181 100644 --- a/crates/file-parser/Cargo.toml +++ b/cs_model/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "file-parser" +name = "cs_model" version = "0.1.0" edition = "2021" diff --git a/crates/class-struct/src/lib.rs b/cs_model/src/lib.rs similarity index 100% rename from crates/class-struct/src/lib.rs rename to cs_model/src/lib.rs diff --git a/crates/class-struct/src/test.rs b/cs_model/src/test.rs similarity index 100% rename from crates/class-struct/src/test.rs rename to cs_model/src/test.rs diff --git a/crates/class-struct/Cargo.toml b/cs_parser/Cargo.toml similarity index 87% rename from crates/class-struct/Cargo.toml rename to cs_parser/Cargo.toml index ffbf29b..7a5e7f2 100644 --- a/crates/class-struct/Cargo.toml +++ b/cs_parser/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "class-struct" +name = "cs_parser" version = "0.1.0" edition = "2021" diff --git a/crates/file-parser/src/lib.rs b/cs_parser/src/lib.rs similarity index 99% rename from crates/file-parser/src/lib.rs rename to cs_parser/src/lib.rs index 3ca621f..19564e8 100644 --- a/crates/file-parser/src/lib.rs +++ b/cs_parser/src/lib.rs @@ -25,6 +25,7 @@ struct Data<'a> { pointer: usize, } +/// Parses the class file into a `ClassFile` structure pub fn parse_class_file(data: &[u1]) -> Result { let mut data = Data::new(data); ClassFile::parse(&mut data, &[]) diff --git a/crates/file-parser/src/model/cp_info.rs b/cs_parser/src/model/cp_info.rs similarity index 98% rename from crates/file-parser/src/model/cp_info.rs rename to cs_parser/src/model/cp_info.rs index 8221eae..ee8d273 100644 --- a/crates/file-parser/src/model/cp_info.rs +++ b/cs_parser/src/model/cp_info.rs @@ -125,6 +125,10 @@ macro_rules! impl_try_from_cp { if index == 0 { return Err(ParseErr("Index must not be 0".to_string())); } + + if info.len() == 0 { + return Ok(()); + } // todo this here might actually be an empty constant pool depending on whether is is still parsing the constant pool // it needs to be checked after testing // not now @@ -302,6 +306,9 @@ impl ValidateCpInfo for Utf8 { if index == 0 { return Err(ParseErr("Index must not be 0".to_string())); } + if info.len() == 0 { + return Ok(()); + } match &info[index as usize - 1].inner { CpInfoInner::Utf8(_) => Ok(()), kind => Err(ParseErr(format!( diff --git a/crates/file-parser/src/model/mod.rs b/cs_parser/src/model/mod.rs similarity index 100% rename from crates/file-parser/src/model/mod.rs rename to cs_parser/src/model/mod.rs diff --git a/crates/file-parser/src/test.rs b/cs_parser/src/test.rs similarity index 97% rename from crates/file-parser/src/test.rs rename to cs_parser/src/test.rs index 4b1f625..1e329a2 100644 --- a/crates/file-parser/src/test.rs +++ b/cs_parser/src/test.rs @@ -37,7 +37,7 @@ fn data_u4() { #[test] fn parse_empty_class() { - let class = include_bytes!("../../../testdata/Test.class"); + let class = include_bytes!("../testdata/Test.class"); let parsed = parse_class_file(class).unwrap(); assert_eq!(parsed.minor_version, 0); @@ -139,7 +139,7 @@ fn parse_empty_class() { #[test] fn more_complex_file() { - let class = include_bytes!("../../../testdata/Test2.class"); + let class = include_bytes!("../testdata/Test2.class"); let parsed = parse_class_file(class).unwrap(); assert_eq!(parsed.magic, 0xCAFEBABE); } diff --git a/cs_parser/testdata/Test.class b/cs_parser/testdata/Test.class new file mode 100644 index 0000000..2c9e5b0 Binary files /dev/null and b/cs_parser/testdata/Test.class differ diff --git a/cs_parser/testdata/Test.class.txt b/cs_parser/testdata/Test.class.txt new file mode 100644 index 0000000..a0170df --- /dev/null +++ b/cs_parser/testdata/Test.class.txt @@ -0,0 +1,133 @@ +Manually parsed by hand + +hexdump -C Test.class + +00000000 |ca fe ba be|00 00|00 3b |00 0d|0a.00 02.00 03|07. |.......;........| +00000010 00 04|0c.00 05.00 06|01 .00 10.6a 61 76 61 2f 6c |..........java/l| +00000020 61 6e 67 2f 4f 62 6a 65 63 74|01.00 06.3c 69 6e |ang/Object......()V......T| +00000040 65 73 74|01.00 04.43 6f 64 65|01.00 0f.4c 69 6e |est...Code...Lin| +00000050 65 4e 75 6d 62 65 72 54 61 62 6c 65|01.00 0a.53 |eNumberTable...S| +00000060 6f 75 72 63 65 46 69 6c 65|01.00 09.54 65 73 74 |ourceFile...Test| +00000070 2e 6a 61 76 61|00 21|00 07|00 02|00 00|00 00|00 |.java.!.........| +00000080 01|00 01.00 05.00 06.00 01:00 09.00 00 00 1d.00 |................| +00000090 01.00 01.00 00 00 05.2a b7 00 01 b1.00 00.00 01: |.......*........| +000000a0 00 0a.00 00 00 06.00 01 :00 00.00 01|00 01|00 0b. |................| +000000b0 00 00 00 02.00 0c |......| +000000b6 + + +Magic: ca fe ba be +Minor: 00 00 +Major: 00 3b +CpCount: 00 0d (13) (13 - 1 = 12) +Cp: [ + 1: { + tag: 0a (10, MethodRef) + class_index: 00 02 (2) + name_and_type_index: 00 03 + } + 2: { + tag: 07 (7, Class) + name_index: 00 04 (4) (java/lang/Object) + } + 3: { + tag: 0c (12, NameAndType) + name_index: 00 05 (05) + descriptor_index: 00 06 + } + 4: { + tag: 01 (1, Utf8) + length: 00 10 (16) + string: 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 (java/lang/Object) + } + 5: { + tag: 01 (1, Utf8) + length: 00 06 (6) + string: 3c 69 6e 69 74 3e () + } + 6: { + tag: 01 (1, Utf8) + length: 00 03 (3) + bytes: 28 29 56 (()V) + } + 7: { + tag: 07 (7, Class) + name_index: 00 08 (8) (Test) + } + 8: { + tag: 01 (1, Utf8) + length: 00 04 (4) + bytes: 54 65 73 74 (Test) + } + 9: { + tag: 01 (1, Utf8) + length: 00 04 (4) + bytes: 43 6f 64 65 (Code) + } + 10: { + tag: 01 (1, Utf8) + length: 00 0f (15) + bytes: 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 (LineNumberTable) + } + 11: { + tag: 01 (1, Utf8) + length: 00 0a (10) + bytes: 53 6f 75 72 63 65 46 69 6c 65 (SourceFile) + } + 12: { + tag: 01 (1, Utf8) + length: 00 09 (9) + bytes: 54 65 73 74 2e 6a 61 76 61 (Test.java) + } +] +access_flags: 00 21 +this_class: 00 07 (Test) +super_class: 00 02 (java/lang/Object) +interfaces_count: 00 00 +interfaces: [] +fields_count: 00 00 +fields: [] +methods_count: 00 01 +methods: [ + { + access_flags: 00 01 + name_index: 00 05 + descriptor_index: 00 06 + attributes_count: 00 01 + attributes: [ + { + name_index: 00 09 (Code) + attribute_length: 00 00 00 1d (29) + max_stack: 00 01 + max_locals: 00 01 + code_length: 00 00 00 05 + code: 2a b7 00 01 b1 + exception_table_length: 00 00 + exception_table: [] + attributes_count: 00 01 + attributes: [ + { + attribute_name_index: 00 0a (LineNumberTable) + attribute_length: 00 00 00 06 + line_number_table_length: 00 01 + line_number_table: [ + { + start_pc: 00 00 + line_number: 00 01 + } + ] + } + ] + } + ] + } +] +attributes_count: 00 01 +attributes: [ + { + attribute_name_index: 00 0b (SourceFile) + attribute_length: 00 00 00 02 + sourcefile_index: 00 0c + } +] \ No newline at end of file diff --git a/cs_parser/testdata/Test.java b/cs_parser/testdata/Test.java new file mode 100644 index 0000000..099aac2 --- /dev/null +++ b/cs_parser/testdata/Test.java @@ -0,0 +1 @@ +public class Test {} \ No newline at end of file diff --git a/cs_parser/testdata/Test2.class b/cs_parser/testdata/Test2.class new file mode 100644 index 0000000..63cac3b Binary files /dev/null and b/cs_parser/testdata/Test2.class differ diff --git a/cs_parser/testdata/Test2.java b/cs_parser/testdata/Test2.java new file mode 100644 index 0000000..a6fbfab --- /dev/null +++ b/cs_parser/testdata/Test2.java @@ -0,0 +1,13 @@ +class Test2 { + int myField; + + public static void main(String[] args) { + int i = 0; + i++; + new Test2().print(i); + } + + void print(int i) { + System.out.println(i); + } +} \ No newline at end of file diff --git a/crates/machine/Cargo.toml b/cs_vm/Cargo.toml similarity index 90% rename from crates/machine/Cargo.toml rename to cs_vm/Cargo.toml index 16371df..bca5ca3 100644 --- a/crates/machine/Cargo.toml +++ b/cs_vm/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "machine" +name = "cs_vm" version = "0.1.0" edition = "2021" diff --git a/crates/machine/src/lib.rs b/cs_vm/src/lib.rs similarity index 100% rename from crates/machine/src/lib.rs rename to cs_vm/src/lib.rs diff --git a/crates/machine/src/model.rs b/cs_vm/src/model.rs similarity index 99% rename from crates/machine/src/model.rs rename to cs_vm/src/model.rs index 289d791..ea3b2fa 100644 --- a/crates/machine/src/model.rs +++ b/cs_vm/src/model.rs @@ -58,6 +58,7 @@ mod tests { use super::{LocalVariables, OperandStack}; #[test] + #[ignore] fn operand_stack() { let mut stack = OperandStack::new(); diff --git a/file-info.sh b/file-info.sh deleted file mode 100644 index 9d96e2a..0000000 --- a/file-info.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -cd crates/file-info -cargo run ../../"$1" \ No newline at end of file diff --git a/crates/file-info/src/main.rs b/src/main.rs similarity index 52% rename from crates/file-info/src/main.rs rename to src/main.rs index 1ff3d1e..6fd03db 100644 --- a/crates/file-info/src/main.rs +++ b/src/main.rs @@ -1,28 +1,21 @@ -use crate::ui::display_class; -use file_parser::parse_class_file; - -mod ui; - fn main() { let file = std::env::args().nth(1).unwrap_or_else(|| { eprintln!("No file provided"); std::process::exit(1); }); - let file = std::fs::read(file).unwrap_or_else(|_| { + + let contents = std::fs::read(file).unwrap_or_else(|_| { eprintln!("Could not read file"); std::process::exit(1); }); - let class_file = match parse_class_file(&file) { + let class_file = match cs_parser::parse_class_file(&contents) { Ok(file) => file, Err(err) => { eprintln!("{}", err); return; } }; - let stdout = std::io::stdout(); - if let Err(why) = display_class(stdout.lock(), &class_file) { - eprintln!("{}", why); - } + cs_class_printer::print(&class_file); }