论坛首页 编程语言技术论坛

发布DynamicStruct-0.2 and BytecodeStruct-0.1

浏览 7753 次
精华帖 (0) :: 良好帖 (11) :: 新手帖 (0) :: 隐藏帖 (2)
作者 正文
   发表时间:2008-02-05  
DynamicStruct,是我最近自己在鼓捣的一个ruby项目,这是一个更大的计划的一部分。

当他完成之后,应该是这样的一个结构:

   Aurum
     |
     V
  RubyBCL
     |
     V
DynamicStruct

Aurum是目前徐昊正在做的一个项目,简单的介绍可以看这里:《A very brief introduction to Aurum

通过aurum,可以更加方便的定义新的语言。

但是,仅仅依靠aurum,只能让新设计出来的语言,运行于aurum的解释环境中,ruby就已经是够慢的解释语言了,这样的解释执行方式,可以说完全无法得到具有实用价值的语言。但是,如果可以通过aurum,将一种语言编译成Java Bytecode,那么,美好的未来就会是:“能够快速的定义,具有实用价值的,新语言!而且,各种新语言,都能够基于JVM,互联互通。”

RubyBCL,现在还没有出现。仅有的灵感,来自Charles Nutter的一篇blog:《Bytecode Tools in Ruby: A Low-level DSL》。这篇blog可能无法在国内访问。转贴一点过来吧:

  cb = Compiler::ClassBuilder.build("MyClass", "MyClass.java") do
    field :list, ArrayList
    
    constructor(String, ArrayList) do
      aload 0
      invokespecial Object, "<init>", Void::TYPE
      aload 0
      aload 1
      aload 2
      invokevirtual this, :bar, [ArrayList, String, ArrayList]
      aload 0
      swap
      putfield this, :list, ArrayList
      returnvoid
    end
    
    static_method(:foo, this, String) do
      new this
      dup
      aload 0
      new ArrayList
      dup
      invokespecial ArrayList, "<init>", Void::TYPE
      invokespecial this, "<init>", [Void::TYPE, String, ArrayList]
      areturn
    end
    
    method(:bar, ArrayList, String, ArrayList) do
      aload 1
      invokevirtual(String, :toLowerCase, String)
      aload 2
      swap
      invokevirtual(ArrayList, :add, [Boolean::TYPE, Object])
      aload 2
      areturn
    end
    
    method(:getList, ArrayList) do
      aload 0
      getfield this, :list, ArrayList
      areturn
    end
    
    static_method(:main, Void::TYPE, String[]) do
      aload 0
      ldc_int 0
      aaload
      invokestatic this, :foo, [this, String]
      invokevirtual this, :getList, ArrayList
      aprintln
      returnvoid
    end
  end
  cb.write("MyClass.class")


这样一段代码,就能够得到一个MyClass.class。这个class,也可以用下面的java代码编译得到。

import java.util.ArrayList;
public class MyClass {
  public ArrayList list;
  public MyClass(String a, ArrayList b) {
    list = bar(a, b);
  }
  public static MyClass foo(String a) {
    return new MyClass(a, new ArrayList());
  }
  public ArrayList bar(String a, ArrayList b) {
    b.add(a.toLowerCase());
    return b;
  }
  public ArrayList getList() {
    return list;
  }
  public static void main(String[] args) {
    System.out.println(foo(args[0]).getList());
  }
}


非常漂亮的DSL,但是,在看过Charles Nutter放在svn里的代码之后,我才发现,这家伙太讨巧了,事实上他上面的那些DSL,最后还是利用JRuby,调用了ASM这个java类库。所以,我打算,仅仅借鉴他的DSL设计,但是却用纯粹的ruby,来实现一个生成Java Bytecode的lib。

至于DynamicStruct,要从BitStruct说起,由于ruby没有一个很方便的处理二进制文件的类库,所以我找到了bit-struct,还有一篇不错的中文介绍:《用bit-struct处理结构化(二进制)数据

但是,后来我发现,这个bit-struct,存在绝大的问题,甚至不能仅仅在他的基础上进行修改。因为他只能支持定长的数据结构,而不是可变长度的array list,变长的string,或者switch结构。因此,只能推倒重写。

我现在的工作,就是一个初步的二进制文件读写类库的实现。

简单的看看其中的测试代码吧:

require "dynamic-struct"

class ClassFile<DynamicStruct
  u4 :magic
  u2 :file  
  field_type :clsf
end

class Temp<DynamicStruct
  u2 :t_file
  clsf :cf
  field_type :temp
end

class Temp2<DynamicStruct
  u2 :t_file
  clsf :cf
  temp :ttt  
  u1 :uu1
  u2 :uu2
end

a=Temp2.new
a.t_file=1
a.cf.magic=2
a.cf.file=3
a.ttt.t_file=4
a.ttt.cf.magic=5
a.ttt.cf.file=6
a.uu1=444
a.uu2=888

f=open("C:\\test1.class","wb")
a.write(f)
f.close

f = File.new("C:\\test1.class")
b=Temp2.new
b.read(f)
f.close

puts b.to_s


这个test1,基本完成了与bit-struct类似的工作。

require "dynamic-struct"

class Temp<DynamicStruct
  string :str,1
end

a=Temp.new
a.str='String Test!'

f=open("C:\\test2.class","wb")
a.write(f)
f.close
f = File.new("C:\\test2.class")
b=Temp.new
b.read(f)
f.close
puts b.to_s


这是动态字符串的效果。

require "dynamic-struct"

class TempArray<ArrayField
  size_byte 1
  item_type :u2
  field_type :u2array
end

class TempStruct<DynamicStruct
  u2array :ua
end

ts=TempStruct.new
ts.ua.add(1)
ts.ua.add(2)
ts.ua.add(3)
ts.ua[2]=4
puts ts.to_s
f=open("C:\\test3.class","wb")
ts.write(f)
f.close
f = File.new("C:\\test3.class")
b=TempStruct.new
b.read(f)
f.close

puts b.to_s


这是array list的效果。

require "dynamic-struct"

class TempSwitch<SwitchField
  size_byte 1
  item_type_list({1=>:u1,2=>:u2,3=>:u4,4=>:u8})
  field_type :temps
end

class TempStruct<DynamicStruct
  temps :tus
end

ts=TempStruct.new
u=UnsignedField.new
u.field_type_name="u4"
u.value=33
ts.tus.value=u
  
puts ts.to_s
f=open("C:\\test4.class","wb")
ts.write(f)
f.close
f = File.new("C:\\test4.class")
b=TempStruct.new
b.read(f)
f.close

puts b.to_s


这是switch的效果。

附上源代码,欢迎多多批评!
   发表时间:2008-02-05  
刚才google搜索才发现,已经有人做了与我这个很类似的工作。而且就是JavaEye的朋友~~~

为BitStruct添加list类型

不过他这样的扩展,正如我所说的,受限于bit-struct,而无法实现真正的可变长数组~~~
0 请登录后投票
   发表时间:2008-02-09  
我没有搞明白这个类库是干什么用的。从你写的测试代码来看,貌似是用来读取Java的class文件,可以从class文件当中提取Java的类结构和数据的,是这么回事吗?

那这样做的意义何在?用ruby编写Java的DSL源代码,然后再编译为class,这不是多此一举吗?我直接写Java源代码,然后编译不就可以了吗?
0 请登录后投票
   发表时间:2008-02-09  
按我的理解是方便地实现DSL语言并且在JVM上运行吧
0 请登录后投票
   发表时间:2008-02-09  
neodoxy 写道
按我的理解是方便地实现DSL语言并且在JVM上运行吧

直接用ruby做DSL,然后用jruby来跑,不是更直接?
0 请登录后投票
   发表时间:2008-02-09  
JRuby之所以可能,是因为通过Antlr,将ruby语言,解释为了JVM能够理解的字节码。

而aurum,就可以认为是一个ruby版的antlr,而且,可以期待的是,借助于ruby强大的DSL能力,这个ruby的版本,会远比java的版本,更为方便好用。

因此,aurum不是一个DSL支持框架,而是任意语言的快速实现平台。

但是,aurum在开发之初,并没有考虑过有关效率的任何问题。因此,如果有一组支撑类库,能够帮助aurum,将他所能够解释出来的语言,直接编译为java的Bytecode,则这条道路,就会比antlr+asm,更为快捷。

至于读取bytecode的结构化数据,则是独立于我上面所说的需求之外的能力。毕竟我已经可能很方便的实现结构化的二进制数据写入,为什么不顺便实现一个读取呢?

让ruby,拥有对于class文件的读取、分析、修改的能力,不是也很棒吗?
0 请登录后投票
   发表时间:2008-02-10  
庄表伟 写道
JRuby之所以可能,是因为通过Antlr,将ruby语言,解释为了JVM能够理解的字节码。

而aurum,就可以认为是一个ruby版的antlr,而且,可以期待的是,借助于ruby强大的DSL能力,这个ruby的版本,会远比java的版本,更为方便好用。

因此,aurum不是一个DSL支持框架,而是任意语言的快速实现平台。

但是,aurum在开发之初,并没有考虑过有关效率的任何问题。因此,如果有一组支撑类库,能够帮助aurum,将他所能够解释出来的语言,直接编译为java的Bytecode,则这条道路,就会比antlr+asm,更为快捷。

至于读取bytecode的结构化数据,则是独立于我上面所说的需求之外的能力。毕竟我已经可能很方便的实现结构化的二进制数据写入,为什么不顺便实现一个读取呢?

让ruby,拥有对于class文件的读取、分析、修改的能力,不是也很棒吗?

但是没有人会通过ruby-java这个途径再去创造一种新的通用语言,我相信主要用途还是DSL方面的
0 请登录后投票
   发表时间:2008-02-15  
正是我所需要的,BitStruct无法处理变长字符串已经让我抓狂了。抛开未来计划不谈,这个东东对使用ruby处理二进制是福音啊,希望老大继续发展。
0 请登录后投票
   发表时间:2008-03-12  
C:\Real.java
class Real {
	public static void main(String[] args) throws Exception	{
		System.out.println("Hello World!");
	}
}


在运行了如下一段程序之后
require 'bytecode-struct'

f = File.open("C:\\Real.class","rb")
b=ClassFile.new
b.read(f)
f.close

b.constant_pool[19].value='Hello World!你好,我好,大家好!'
f = File.new("D:\\Real.class","wb")
b.write(f)
f.close


在D:\下执行
引用
java Real

就会得到:  Hello World!你好,我好,大家好!

纯ruby实现的,读写Java Class,初步实现!

源代码在:  http://svn.w18.net/svn/rds/
0 请登录后投票
   发表时间:2008-03-12  
补充:

不同的javac,编译出来的Class,Hello World的String,未必在第20个,所以我这段代码,不一定能够正确运行的

0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics