From 9a631533013160649084f9528e0865afa2d97d13 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 31 Jul 2024 19:51:03 +0200 Subject: [PATCH 01/13] Make `Multianewarray` hold a `FieldType` --- src/bytecode.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index f4355ad..177ce8c 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -9,6 +9,7 @@ use crate::constant_pool::{ ConstantPoolEntry, ConstantPoolEntryTypes, InvokeDynamic, Loadable, MemberRef, }; use crate::{read_u1, read_u2, read_u4, ParseError}; +use crate::descriptor::FieldType; pub type JumpOffset = i32; @@ -187,7 +188,7 @@ pub enum Opcode<'a> { Lxor, Monitorenter, Monitorexit, - Multianewarray(Cow<'a, str>, u8), + Multianewarray(FieldType<'a>, u8), New(Cow<'a, str>), Newarray(PrimitiveArrayType), Nop, @@ -663,7 +664,7 @@ fn read_opcodes<'a>( } } 0xc5 => Opcode::Multianewarray( - read_cp_classinfo(code, &mut ix, pool)?, + FieldType::parse(&read_cp_classinfo(code, &mut ix, pool)?)?, read_u1(code, &mut ix)?, ), 0xc6 => Opcode::Ifnull((read_u2(code, &mut ix)? as i16).into()), From 6311e34dfa118b6b33c178962a5b2b94d044a2d6 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 31 Jul 2024 19:53:09 +0200 Subject: [PATCH 02/13] Make ci format check happy? --- src/bytecode.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index 177ce8c..95aa582 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -8,8 +8,8 @@ use crate::constant_pool::{ use crate::constant_pool::{ ConstantPoolEntry, ConstantPoolEntryTypes, InvokeDynamic, Loadable, MemberRef, }; -use crate::{read_u1, read_u2, read_u4, ParseError}; use crate::descriptor::FieldType; +use crate::{read_u1, read_u2, read_u4, ParseError}; pub type JumpOffset = i32; From 14674059fac89c58d6b6a87e830642c6b5ab62e7 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 31 Jul 2024 22:46:46 +0200 Subject: [PATCH 03/13] Make `Anewarray` hold a FieldType --- src/bytecode.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index 95aa582..b291e7a 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -8,7 +8,7 @@ use crate::constant_pool::{ use crate::constant_pool::{ ConstantPoolEntry, ConstantPoolEntryTypes, InvokeDynamic, Loadable, MemberRef, }; -use crate::descriptor::FieldType; +use crate::descriptor::{FieldType, Ty}; use crate::{read_u1, read_u2, read_u4, ParseError}; pub type JumpOffset = i32; @@ -45,7 +45,7 @@ pub enum Opcode<'a> { Aastore, AconstNull, Aload(u16), // both wide and narrow - Anewarray(Cow<'a, str>), + Anewarray(FieldType<'a>), Areturn, Arraylength, Astore(u16), // both wide and narrow @@ -634,7 +634,13 @@ fn read_opcodes<'a>( }; Opcode::Newarray(primitive_type) } - 0xbd => Opcode::Anewarray(read_cp_classinfo(code, &mut ix, pool)?), + 0xbd => Opcode::Anewarray({ + let ty = read_cp_classinfo(code, &mut ix, pool)?; + match FieldType::parse(&ty) { + Ok(ty) => ty, + Err(_) => FieldType::Ty(Ty::Object(ty)), + } + }), 0xbe => Opcode::Arraylength, 0xbf => Opcode::Athrow, 0xc0 => Opcode::Checkcast(read_cp_classinfo(code, &mut ix, pool)?), From 207d62cf72a5589b6a9d715bef614072991b6685 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 31 Jul 2024 22:48:23 +0200 Subject: [PATCH 04/13] Add handwritten test Currently the test tests that `anewarray` gets parsed correctly --- tests/parse/clazz/Test.clazz | Bin 0 -> 437 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/parse/clazz/Test.clazz diff --git a/tests/parse/clazz/Test.clazz b/tests/parse/clazz/Test.clazz new file mode 100644 index 0000000000000000000000000000000000000000..f846e5a96713534395d4bcd2a16c91d2ac5637b9 GIT binary patch literal 437 zcmZutO;5r=6r9&WODjqR#E+Xd@IdcEyqI_}jUFIy=xJLwb+NRj6#the6BGRb{wU*H zz=*~@%-flHZ(epkK40Gf3~@rJJw7D;Ap?EErK;v znJO;`X16z~!-DOif*PSx-m3+{4ZZ^htj&eW2%T;i`~;86LS@OIHzBmcZDYN0U}KNa z`q%IXMtE(b$|S51% aLu1OYuc0;ln`3R|cxdB*X9&lP2C84T4pdJ7 literal 0 HcmV?d00001 From 21a6f8ebcc0c834eddf84236d3274424e4362180 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 31 Jul 2024 23:25:03 +0200 Subject: [PATCH 05/13] Make `Checkcast` hold a FieldType The run-time constant pool item at the index must be a symbolic reference to a class, array, or interface type. - https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.checkcast --- src/bytecode.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index b291e7a..144d352 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -56,7 +56,7 @@ pub enum Opcode<'a> { Breakpoint, Caload, Castore, - Checkcast(Cow<'a, str>), + Checkcast(FieldType<'a>), D2f, D2i, D2l, @@ -643,8 +643,14 @@ fn read_opcodes<'a>( }), 0xbe => Opcode::Arraylength, 0xbf => Opcode::Athrow, - 0xc0 => Opcode::Checkcast(read_cp_classinfo(code, &mut ix, pool)?), 0xc1 => Opcode::Instanceof(read_cp_classinfo(code, &mut ix, pool)?), + 0xc0 => Opcode::Checkcast({ + let ty = read_cp_classinfo(code, &mut ix, pool)?; + match FieldType::parse(&ty) { + Ok(ty) => ty, + Err(_) => FieldType::Ty(Ty::Object(ty)), + } + }), 0xc2 => Opcode::Monitorenter, 0xc3 => Opcode::Monitorexit, 0xc4 => { From 474a208b6810c1d27a2d6d2ce702cd27a8054021 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 31 Jul 2024 23:25:26 +0200 Subject: [PATCH 06/13] Make `Instanceof` hold a FieldType The run-time constant pool item at the index must be a symbolic reference to a class, array, or interface type. - https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.instanceof --- src/bytecode.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index 144d352..5e3e29c 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -143,7 +143,7 @@ pub enum Opcode<'a> { Impdep2, Imul, Ineg, - Instanceof(Cow<'a, str>), + Instanceof(FieldType<'a>), Invokedynamic(InvokeDynamic<'a>), Invokeinterface(MemberRef<'a>, u8), Invokespecial(MemberRef<'a>), @@ -643,7 +643,6 @@ fn read_opcodes<'a>( }), 0xbe => Opcode::Arraylength, 0xbf => Opcode::Athrow, - 0xc1 => Opcode::Instanceof(read_cp_classinfo(code, &mut ix, pool)?), 0xc0 => Opcode::Checkcast({ let ty = read_cp_classinfo(code, &mut ix, pool)?; match FieldType::parse(&ty) { @@ -651,6 +650,13 @@ fn read_opcodes<'a>( Err(_) => FieldType::Ty(Ty::Object(ty)), } }), + 0xc1 => Opcode::Instanceof({ + let ty = read_cp_classinfo(code, &mut ix, pool)?; + match FieldType::parse(&ty) { + Ok(ty) => ty, + Err(_) => FieldType::Ty(Ty::Object(ty)), + } + }), 0xc2 => Opcode::Monitorenter, 0xc3 => Opcode::Monitorexit, 0xc4 => { From 933458ef0f4abf79b42ba9892e2e7dfb579ded09 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 31 Jul 2024 23:42:32 +0200 Subject: [PATCH 07/13] Include more exhaustive test --- tests/parse/clazz/Test.clazz | Bin 437 -> 484 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/parse/clazz/Test.clazz b/tests/parse/clazz/Test.clazz index f846e5a96713534395d4bcd2a16c91d2ac5637b9..e12a40552d89b79816d0ff88706e0599a97430ad 100644 GIT binary patch delta 213 zcmdnW{Dhh7)W2Q(7#J9A7-S}L?UECY_Q^^tOVrOv%uCk~E-A{)OSfic5Mg9sNi0e) zo_ODYlQ*~|F*(~ev0yR>qdKGbWCKRAdI_KbYz&M*l9@pgNb-Q$tPETX+&~^Dkk1Pg z5eKrv7?{9v%4~ZX_``vOAcznK5&Xgq UGJ_a{2oF#VBZD-MWMW_i0Llv?KL7v# delta 189 zcmaFDyp@^j)W2Q(7#J9A7^Eh0?UH6mEJ`nCWDt(_$x19s)Xz!GOVS1JHmjqHw46FdrI2sfH From db56c98736b1a0c70bbce55ba3019c4ff41ad645 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Mon, 5 Aug 2024 23:57:55 +0200 Subject: [PATCH 08/13] remap `BaseType`'s back to their Object types --- src/bytecode.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index 5e3e29c..22555e8 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -636,25 +636,37 @@ fn read_opcodes<'a>( } 0xbd => Opcode::Anewarray({ let ty = read_cp_classinfo(code, &mut ix, pool)?; - match FieldType::parse(&ty) { + let ty = match FieldType::parse(&ty) { Ok(ty) => ty, Err(_) => FieldType::Ty(Ty::Object(ty)), + }; + match ty { + FieldType::Ty(Ty::Base(base)) => FieldType::Ty(Ty::Object(Cow::Owned(base.to_string()))), + ty => ty, } }), 0xbe => Opcode::Arraylength, 0xbf => Opcode::Athrow, 0xc0 => Opcode::Checkcast({ let ty = read_cp_classinfo(code, &mut ix, pool)?; - match FieldType::parse(&ty) { + let ty = match FieldType::parse(&ty) { Ok(ty) => ty, Err(_) => FieldType::Ty(Ty::Object(ty)), + }; + match ty { + FieldType::Ty(Ty::Base(base)) => FieldType::Ty(Ty::Object(Cow::Owned(base.to_string()))), + ty => ty, } }), 0xc1 => Opcode::Instanceof({ let ty = read_cp_classinfo(code, &mut ix, pool)?; - match FieldType::parse(&ty) { + let ty = match FieldType::parse(&ty) { Ok(ty) => ty, Err(_) => FieldType::Ty(Ty::Object(ty)), + }; + match ty { + FieldType::Ty(Ty::Base(base)) => FieldType::Ty(Ty::Object(Cow::Owned(base.to_string()))), + ty => ty, } }), 0xc2 => Opcode::Monitorenter, From 70ffbad0acac3f1474ac17c08e1f3a44175a245b Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 6 Aug 2024 00:24:50 +0200 Subject: [PATCH 09/13] Use a new `ReferenceType` instead --- src/bytecode.rs | 24 +++++------------------- src/descriptor.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index 22555e8..2f4a3b5 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -8,7 +8,7 @@ use crate::constant_pool::{ use crate::constant_pool::{ ConstantPoolEntry, ConstantPoolEntryTypes, InvokeDynamic, Loadable, MemberRef, }; -use crate::descriptor::{FieldType, Ty}; +use crate::descriptor::{FieldType, ReferenceType, Ty}; use crate::{read_u1, read_u2, read_u4, ParseError}; pub type JumpOffset = i32; @@ -45,7 +45,7 @@ pub enum Opcode<'a> { Aastore, AconstNull, Aload(u16), // both wide and narrow - Anewarray(FieldType<'a>), + Anewarray(ReferenceType<'a>), Areturn, Arraylength, Astore(u16), // both wide and narrow @@ -56,7 +56,7 @@ pub enum Opcode<'a> { Breakpoint, Caload, Castore, - Checkcast(FieldType<'a>), + Checkcast(ReferenceType<'a>), D2f, D2i, D2l, @@ -636,27 +636,13 @@ fn read_opcodes<'a>( } 0xbd => Opcode::Anewarray({ let ty = read_cp_classinfo(code, &mut ix, pool)?; - let ty = match FieldType::parse(&ty) { - Ok(ty) => ty, - Err(_) => FieldType::Ty(Ty::Object(ty)), - }; - match ty { - FieldType::Ty(Ty::Base(base)) => FieldType::Ty(Ty::Object(Cow::Owned(base.to_string()))), - ty => ty, - } + ReferenceType::parse(&ty)? }), 0xbe => Opcode::Arraylength, 0xbf => Opcode::Athrow, 0xc0 => Opcode::Checkcast({ let ty = read_cp_classinfo(code, &mut ix, pool)?; - let ty = match FieldType::parse(&ty) { - Ok(ty) => ty, - Err(_) => FieldType::Ty(Ty::Object(ty)), - }; - match ty { - FieldType::Ty(Ty::Base(base)) => FieldType::Ty(Ty::Object(Cow::Owned(base.to_string()))), - ty => ty, - } + ReferenceType::parse(&ty)? }), 0xc1 => Opcode::Instanceof({ let ty = read_cp_classinfo(code, &mut ix, pool)?; diff --git a/src/descriptor.rs b/src/descriptor.rs index 0a31f23..fb17c5e 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -80,6 +80,53 @@ pub enum FieldType<'a> { Array { dimensions: usize, ty: Ty<'a> }, } +/// FieldType as described in section 4.3.2 of the [JVM 18 specification](https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.3.2) +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub enum ReferenceType<'a> { + Object(Cow<'a, str>), + Array { dimensions: usize, ty: Ty<'a> }, +} + +impl<'a> ReferenceType<'a> { + pub(crate) fn parse(chars: &Cow<'a, str>) -> Result { + let mut chars_idx = chars.char_indices(); + Self::parse_from_chars_idx(chars, &mut chars_idx) + } + + fn parse_from_chars_idx( + chars: &Cow<'a, str>, + chars_idx: &mut CharIndices, + ) -> Result { + let mut array_depth = 0; + + + while let Some(ch) = chars_idx.next().map(|(_, ch)| ch) { + match ch { + '[' => { + array_depth += 1; + + // A field descriptor representing an array type is valid only if it represents a type with 255 or fewer dimensions. + // see: https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.3.2 + if array_depth > 255 { + fail!("Array exceeds 255 dimensions"); + } + } + 'L' if array_depth != 0 => { + return Ok(ReferenceType::Array {dimensions: array_depth, ty: Ty::Object(parse_object(chars, chars_idx)?)}); + } + ch => { + return Ok(if array_depth == 0 { + ReferenceType::Object(chars.clone()) + } else { + ReferenceType::Array {dimensions: array_depth, ty: Ty::Base(BaseType::parse(ch)?)} + }) + } + }; + } + fail!("no ReferenceType found") + } +} + impl<'a> FieldType<'a> { pub(crate) fn parse(chars: &Cow<'a, str>) -> Result { let mut chars_idx = chars.char_indices(); From c4fc437052cf3e02444312ec2a2ec118e471b85f Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 6 Aug 2024 00:26:40 +0200 Subject: [PATCH 10/13] Run `cargo fmt` --- src/bytecode.rs | 4 +++- src/descriptor.rs | 11 ++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index 2f4a3b5..ac099d8 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -651,7 +651,9 @@ fn read_opcodes<'a>( Err(_) => FieldType::Ty(Ty::Object(ty)), }; match ty { - FieldType::Ty(Ty::Base(base)) => FieldType::Ty(Ty::Object(Cow::Owned(base.to_string()))), + FieldType::Ty(Ty::Base(base)) => { + FieldType::Ty(Ty::Object(Cow::Owned(base.to_string()))) + } ty => ty, } }), diff --git a/src/descriptor.rs b/src/descriptor.rs index fb17c5e..3e4cab1 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -99,7 +99,6 @@ impl<'a> ReferenceType<'a> { ) -> Result { let mut array_depth = 0; - while let Some(ch) = chars_idx.next().map(|(_, ch)| ch) { match ch { '[' => { @@ -112,13 +111,19 @@ impl<'a> ReferenceType<'a> { } } 'L' if array_depth != 0 => { - return Ok(ReferenceType::Array {dimensions: array_depth, ty: Ty::Object(parse_object(chars, chars_idx)?)}); + return Ok(ReferenceType::Array { + dimensions: array_depth, + ty: Ty::Object(parse_object(chars, chars_idx)?), + }); } ch => { return Ok(if array_depth == 0 { ReferenceType::Object(chars.clone()) } else { - ReferenceType::Array {dimensions: array_depth, ty: Ty::Base(BaseType::parse(ch)?)} + ReferenceType::Array { + dimensions: array_depth, + ty: Ty::Base(BaseType::parse(ch)?), + } }) } }; From 3c37c2abca5364bdc2fad0b454c16b6dddb2063d Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:52:54 +0200 Subject: [PATCH 11/13] Move all `FieldType`'s in Opcode to `ReferenceType`'s --- src/bytecode.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index ac099d8..d80c7b9 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -2,14 +2,14 @@ use std::borrow::Cow; use std::convert::TryFrom; use std::rc::Rc; +use crate::{ParseError, read_u1, read_u2, read_u4}; use crate::constant_pool::{ get_cp_loadable, read_cp_classinfo, read_cp_invokedynamic, read_cp_memberref, }; use crate::constant_pool::{ ConstantPoolEntry, ConstantPoolEntryTypes, InvokeDynamic, Loadable, MemberRef, }; -use crate::descriptor::{FieldType, ReferenceType, Ty}; -use crate::{read_u1, read_u2, read_u4, ParseError}; +use crate::descriptor::ReferenceType; pub type JumpOffset = i32; @@ -143,7 +143,7 @@ pub enum Opcode<'a> { Impdep2, Imul, Ineg, - Instanceof(FieldType<'a>), + Instanceof(ReferenceType<'a>), Invokedynamic(InvokeDynamic<'a>), Invokeinterface(MemberRef<'a>, u8), Invokespecial(MemberRef<'a>), @@ -188,7 +188,7 @@ pub enum Opcode<'a> { Lxor, Monitorenter, Monitorexit, - Multianewarray(FieldType<'a>, u8), + Multianewarray(ReferenceType<'a>, u8), New(Cow<'a, str>), Newarray(PrimitiveArrayType), Nop, @@ -646,16 +646,7 @@ fn read_opcodes<'a>( }), 0xc1 => Opcode::Instanceof({ let ty = read_cp_classinfo(code, &mut ix, pool)?; - let ty = match FieldType::parse(&ty) { - Ok(ty) => ty, - Err(_) => FieldType::Ty(Ty::Object(ty)), - }; - match ty { - FieldType::Ty(Ty::Base(base)) => { - FieldType::Ty(Ty::Object(Cow::Owned(base.to_string()))) - } - ty => ty, - } + ReferenceType::parse(&ty)? }), 0xc2 => Opcode::Monitorenter, 0xc3 => Opcode::Monitorexit, @@ -682,7 +673,7 @@ fn read_opcodes<'a>( } } 0xc5 => Opcode::Multianewarray( - FieldType::parse(&read_cp_classinfo(code, &mut ix, pool)?)?, + ReferenceType::parse(&read_cp_classinfo(code, &mut ix, pool)?)?, read_u1(code, &mut ix)?, ), 0xc6 => Opcode::Ifnull((read_u2(code, &mut ix)? as i16).into()), From 1a289f87291c6dd66d56b14351c885ee8142e1a3 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:53:11 +0200 Subject: [PATCH 12/13] Run `cargo fmt` --- src/bytecode.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index d80c7b9..8f020ea 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -2,7 +2,6 @@ use std::borrow::Cow; use std::convert::TryFrom; use std::rc::Rc; -use crate::{ParseError, read_u1, read_u2, read_u4}; use crate::constant_pool::{ get_cp_loadable, read_cp_classinfo, read_cp_invokedynamic, read_cp_memberref, }; @@ -10,6 +9,7 @@ use crate::constant_pool::{ ConstantPoolEntry, ConstantPoolEntryTypes, InvokeDynamic, Loadable, MemberRef, }; use crate::descriptor::ReferenceType; +use crate::{read_u1, read_u2, read_u4, ParseError}; pub type JumpOffset = i32; From 9c1c8bea5cbae5bcd1a2b88dbc6cbea4bc01a1f1 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:08:44 +0200 Subject: [PATCH 13/13] Add proposed test --- tests/parse/clazz/L.clazz | Bin 0 -> 380 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/parse/clazz/L.clazz diff --git a/tests/parse/clazz/L.clazz b/tests/parse/clazz/L.clazz new file mode 100644 index 0000000000000000000000000000000000000000..690d9a957f80f125dceee49f0773179f71334de2 GIT binary patch literal 380 zcmZWkO-sW-5Pg$0iNtO3%TQg>w=%cE>%htVsP?~&9}Ck@D5v3ut(lq zH6X?ol~8Z