1 个不稳定版本
0.1.0 | 2018年12月31日 |
---|
#2202 在 解析器实现
53KB
1.5K SLoC
用于解析 JVM 类文件的库。
它使用 nom 实现其惊人的速度,所以请感谢作者。
截至编写时,这个包“基本上功能完整”。
- 所有标准属性均如 JVMS 11 所声明。
- 所有标准常量池条目均如 JVMS 11 所声明。
- 类型检查的常量池索引
关于实现的解释并不多。
它使用 nom 和很多宏...
并不仅限于 nom...
这个包应该是对规范的一个完整的逐一生成实现。
如果规范说某个二进制结构定义了这样一个结构,而这个结构又定义了另一个结构,依此类推。
那么在这里,它将被复制。
这个包的设计不是面向用户,而是供其他库使用。
它非常底层。
有几件事需要注意
常量池索引携带有关其内容的信息。
因此,如果您从常量池中获取一个索引,您将获得一个特定的值。
一个展示它的简单例子是
extern crate class_file;
use class_file::*;
fn main() {
let data = include_bytes!("Main.class");
let class_file = ClassFile::parse(data)
.expect("Failed to parse \"Main.class\"")
.1; // This is needed because I actually return a nom result, which means you'll get back the remaining bytes.... Still undecided if I should hide that...
let cp = &class_file.constant_pool;
// So if you don't know, this_class is an index into the constant pool.
// Specifically, it's an index to a ClassInfo at that location.
// So the type of this_class is something like `CPIndex<'_, ClassInfo<'_>>`
let this_class = class_file.this_class;
// This information is used when you try fetching data from the constant pool.
// This returns a ClassInfo, and from there, you'll start going down the rabbit hole that is the specification.
let class_info = cp.index(this_class);
// For example, to fetch the name of the class itself, you have to do something like:
let class_name: &mstr = {
let this_class = class_file.this_class;
let class_info = cp.index(this_class)
.expect("Unable to locate \"this_class\" inside of constant pool.");
let info = cp.index(class_info.name_index)
.expect("Unable to locate \"this_class.name_index\" in constant pool");
info.data
};
// But as you might have noticed, that's not a str, but a mstr.
// This is because the JVM classfile uses MUTF8 strings.
// So to save converting literally every string a classfile has, it's returned as a mstr.
// You can easily call .to_utf8() on it, and it'll convert it to a `Cow<'_, str>`.
println!("This class: {}", class_name.to_utf8());
// Side-note: mstr doesn't implement Display, because I'm a lazy fuck, but I'll get around to it...
}
如果您想了解更多,请查看我有的一个测试...
尽管如此,它基本上与上面的代码相同...
一个相当重要的注释
目前,一些东西是 pub 的,直到我扩展这个包的内部和易用性...
这个包还做了哪些疯狂的事情...
嗯,它为 JVM 中的大多数东西提供了常量。
大多数东西...
有些东西还缺失,我将在适当的时候添加它们。
例如,我知道 attr 模块中还有一些常量我还没有移动到那里...
嗯,还有其他什么...
属性只是一个特质,因此您可以实现自己的属性。
如果您使用宏,这很简单。
实际上,即使不使用宏,这也相当简单。
您只需要将 nom 的结果映射到可选值。
并实际实现解析部分。
目标
MUTF-8 处理并不完美……我想扩展它并使其更加无缝。
这可能是更疯狂的事情,但理想情况下,我想能够序列化整个结构。
想法是您可以使用这个库来解析一个类文件,修改它,然后将其导出。
甚至更疯狂的是,能够从头创建这些结构。
关于这一点,我有一些想法。
我一直在想一个类似objectasm的库,虽然这仍然是一个选择,但我不确定我是否喜欢它的最终效果。
访问者模式与Rust的语义产生了奇怪的行为。
最终结果是,尝试使用你通常会用objectasm做的操作变得非常混乱。
所以,我想在清理这个和mutf8之后,尝试另一个想法。
基本上,使用syn和quote这些crate相同的技巧,创建一些接受创建和转换classfiles语法的宏库。
Jasmin非常适合这个类别,使其成为完美的目标。
我会研究一下,看看效果如何。
理想情况下,我想将这个和理论上的jasmin crate结合起来,以便轻松创建和修改classfiles。
- 改进MUTF-8处理
- 开始使用这个crate,也许是一个类似quote的crate,带有类似jasmin的语法。
我可能会忘记改变这个列表,但截至目前,这些是我的主要目标。
依赖项
~1MB
~18K SLoC