Skip to content

Patch 1 #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/generator/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def run
process_args
if ARGV.size == 2
File.open(ARGV[1], 'w') do |file|
file << FFI::Generator::Parser.new.generate(Nokogiri::XML(File.open(ARGV[0])))
file << FFI::Generator::Parser.new.generate(Nokogiri::XML(File.open(ARGV[0])) do |cfg| cfg.noblanks end)
end
else
help
Expand Down
2 changes: 1 addition & 1 deletion lib/generator/generatortask.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def define_file_task(fn, xml_fn, output_fn)
parser.load_config(config_fn)
end
File.open(output_fn, 'w') do |file|
file << parser.generate(Nokogiri::XML(File.open(xml_fn)))
file << parser.generate(Nokogiri::XML(File.open(xml_fn)) do |cfg| cfg.noblanks end)
end
end
end
Expand Down
39 changes: 32 additions & 7 deletions lib/generator/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def initialize(indent = 2)
@nested_structure = {}
@ignored = []
@ignore_at_second_pass = []
@swig30_xml = false
end
def generate(node)
result = ""
Expand Down Expand Up @@ -67,8 +68,8 @@ def typedef_alias?(node)
# This is to handle the case where a typedef references an opaque
# struct. In that case the typedef code would output something that
# throws an error. See issue #21
return false if get_attr(node, 'type') =~ /^struct /
typedef?(node) and !callback?(node) and !get_attr(node, 'sym_name').nil?
# return false if get_attr(node, 'type') =~ /^struct |^union /
typedef?(node) and !callback?(node) and (!get_attr(node, 'sym_name').nil? or !get_attr(node, 'name').nil?)
end
def callback?(node)
get_attr(node, 'decl') =~ /^p\.f\(/
Expand Down Expand Up @@ -99,6 +100,8 @@ def find_nested_struct(node, id)
result << fix_nested_structure(nested_node) if nested_node
end
def fixme(code, message)
# in swig-3.0 generated xml file, the order of the declarations in the structure|union is correctly.
return code if @swig30_xml
comment('FIXME: ' + message) << comment(code)
end
def comment(code)
Expand Down Expand Up @@ -130,6 +133,20 @@ def ignore?(name)
end
end
def pass(node)
# in swig-3.0 generated xml file, the nested indicate format is changed.
# first pass find all nested_type.
# FIXME: hard-code xpath
if @nested_type.empty? && !node./("//class/attributelist/attribute[@name='nested'][@value='1']").empty?
@swig30_xml = true
node.xpath("//class/attributelist/attribute[@name='kind'][@value='struct']",
"//class/attributelist/attribute[@name='kind'][@value='union']").each do |node2|
node2 = node2.parent.parent rescue next
next if node2./("./attributelist/attribute[@name='nested'][@value='1']").empty?
type = get_attr(node2, 'name').split(".").last
node2 = node.xpath("//class/cdecl/attributelist/attribute[@name='type'][@value='#{type}']")
@nested_type[type] = get_attr(node2[0].parent.parent.parent, 'name') if node2[0]
end
end
result = []
node.traverse do |node|
node_result = ''
Expand All @@ -141,13 +158,21 @@ def pass(node)
elsif typedef?(node)
node_type = :typedef
typedef = Typedef.new(:node => node, :indent => @indent, :typedefs => @typedefs)
add_type(typedef.symname, ":#{typedef.symname}")
if /^struct |^union / =~ typedef.type.full_decl
add_type(typedef.symname, "#{typedef.type.full_decl}")
else
if /^struct |^union / =~ @typedefs[typedef.type.full_decl]
add_type(typedef.symname, @typedefs[typedef.type.full_decl])
else
add_type(typedef.symname, ":#{typedef.symname}")
end
end
if callback?(node)
cb = Callback.new(:node => node, :indent => @indent, :typedefs => @typedefs).to_s << "\n"
add_type(typedef.symname, "callback #{typedef.symname}")
node_result << cb.to_s
elsif typedef_alias?(node)
node_result << typedef.to_s << "\n"
node_result << typedef.to_s << "\n" if typedef.to_s != ""
end
elsif enum?(node)
node_type = :enum
Expand Down Expand Up @@ -183,7 +208,7 @@ def pass(node)
elsif node.name == 'insert' and not insert_runtime?(node) and not node.parent.name == 'class'
node_type = :insert
node_result << get_verbatim(node)
end
end
end

# don't append unhandled node types
Expand Down Expand Up @@ -252,8 +277,8 @@ def pass(node)
# generated code segment. If the layout of the struct is never
# supplied, we convert all Struct.ptr references to :pointer.
generated.scan(/([a-z0-9]+)\.ptr/i).uniq.flatten.each do |klass|
if result.find { |t,b| b =~ /^ class #{klass}/ }
buf << "#{" " * @indent}class #{klass} < FFI::Struct; end\n"
if result.find { |t,b| b =~ /^ (class #{klass}.*)/ }
buf << "#{" " * @indent}#{$1}; end\n"
else
generated.gsub! /([^a-zA-Z0-9])#{klass}.ptr/, "\\1:pointer"
end
Expand Down
5 changes: 4 additions & 1 deletion lib/generator/type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ def pointer
decl = Declaration.new(tail_decl)
return Struct.camelcase(tail_decl.split(" ").last) + ".ptr" if
decl.is_struct?
return Struct.camelcase(tail_decl.split(" ").last) + ".ptr" if
decl.is_union?

# Everything else is a :pointer
":pointer"
Expand All @@ -102,7 +104,8 @@ def struct
Struct.camelcase(@full_decl.scan(/^struct\s(\w+)/).flatten[0]) + ".by_value"
end
def union
Union.camelcase(@full_decl.scan(/^union\s(\w+)/).flatten[0]) if @declaration.is_union?
return nil unless @declaration.is_union?
Union.camelcase(@full_decl.scan(/^union\s(\w+)/).flatten[0]) + ".by_value"
end
def enum
return nil unless @declaration.is_enum?
Expand Down
13 changes: 11 additions & 2 deletions lib/generator/typedef.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ class Typedef < Type
attr_reader :name
def initialize(params = { })
super
@name = get_attr('sym_name')
@name = get_attr('sym_name') || get_attr('name')
@type = Type.new(:node => @node, :typedefs => @typedefs)
end
def to_s
@indent_str + "typedef #{@type}, :#{@name}"
symm = @type.to_s
if /\.by_value$/ =~ symm
if Struct.camelcase(@name) != symm[0...-9]
@indent_str + "#{Struct.camelcase(@name)} = #{symm[0...-9]}"
else
''
end
else
@indent_str + "typedef #{symm}, :#{@name}"
end
end
private
end
Expand Down
80 changes: 51 additions & 29 deletions spec/generator/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,50 @@
end

it 'should generate ruby ffi wrap code' do
Generator::Parser.new.generate(@node).should == <<EOC
nested_class = if @node./("//class/attributelist/attribute[@name='nested'][@value='1']").empty?
<<-EOC
# FIXME: Nested structures are not correctly supported at the moment.
# Please check the order of the declarations in the structure below.
# class TestStruct5BigUnionField < FFI::Union
# layout(
# :f, :float,
# :nested_struct_field_1, TestStruct5BigUnionFieldNestedStructField1.by_value,
# :nested_struct_field_2, TestStruct5BigUnionFieldNestedStructField2.by_value,
# :nested_struct_field_3, TestStruct5BigUnionFieldNestedStructField3.by_value,
# :union_field, TestStruct5BigUnionFieldUnionField.by_value
# )
# end
# FIXME: Nested structures are not correctly supported at the moment.
# Please check the order of the declarations in the structure below.
# class TestStruct5 < FFI::Struct
# layout(
# :i, :int,
# :c, :char,
# :big_union_field, TestStruct5BigUnionField.by_value
# )
# end
EOC
else
<<-EOC
class TestStruct5BigUnionField < FFI::Union
layout(
:nested_struct_field_1, TestStruct5BigUnionFieldNestedStructField1.by_value,
:nested_struct_field_2, TestStruct5BigUnionFieldNestedStructField2.by_value,
:nested_struct_field_3, TestStruct5BigUnionFieldNestedStructField3.by_value,
:union_field, TestStruct5BigUnionFieldUnionField.by_value,
:f, :float
)
end
class TestStruct5 < FFI::Struct
layout(
:i, :int,
:big_union_field, TestStruct5BigUnionField.by_value,
:c, :char
)
end
EOC
end
Generator::Parser.new.generate(@node).should == (_tmp1 = <<EOC)

module TestLib
extend FFI::Library
Expand All @@ -57,6 +100,7 @@ class TestStruct < FFI::Struct; end
:'3',
]

typedef e_1, :enum_t
class UnionT < FFI::Union
layout(
:c, :char,
Expand Down Expand Up @@ -92,7 +136,7 @@ class TestStruct2 < FFI::Struct
:s_3, TestStruct3.by_value,
:e, :enum_t,
:func, Callback_cb,
:u, UnionT,
:u, UnionT.by_value,
:callback, Callback_cb,
:inline_callback, callback([ Callback_cb_2 ], :void)
)
Expand Down Expand Up @@ -164,26 +208,7 @@ class TestStruct5BigUnionFieldUnionField < FFI::Union
:ll, :long_long
)
end
# FIXME: Nested structures are not correctly supported at the moment.
# Please check the order of the declarations in the structure below.
# class TestStruct5BigUnionField < FFI::Union
# layout(
# :f, :float,
# :nested_struct_field_1, TestStruct5BigUnionFieldNestedStructField1.by_value,
# :nested_struct_field_2, TestStruct5BigUnionFieldNestedStructField2.by_value,
# :nested_struct_field_3, TestStruct5BigUnionFieldNestedStructField3.by_value,
# :union_field, TestStruct5BigUnionFieldUnionField
# )
# end
# FIXME: Nested structures are not correctly supported at the moment.
# Please check the order of the declarations in the structure below.
# class TestStruct5 < FFI::Struct
# layout(
# :i, :int,
# :c, :char,
# :big_union_field, TestStruct5BigUnionField
# )
# end
#{nested_class.chomp}
attach_function :get_int, :get_int, [ TestStruct.ptr ], :int
attach_function :get_char, :get_char, [ TestStruct.ptr ], :char
attach_function :func_with_enum, :func_with_enum, [ e_1 ], :int
Expand All @@ -197,13 +222,14 @@ class TestStruct5BigUnionFieldUnionField < FFI::Union
parser = Generator::Parser.new
parser.ignore 'CONST_1', 'e_1', 'test_struct', 'test_struct_5'
parser.ignore(/^func_with_enum/)
parser.generate(@node).should == <<EOC
parser.generate(@node).should == (_tmp1 = <<EOC)

module TestLib
extend FFI::Library
class TestStruct < FFI::Struct; end
class TestStruct3 < FFI::Struct; end
CONST_2 = 0x20
typedef :uchar, :byte
typedef :int, :enum_t
class UnionT < FFI::Union
layout(
:c, :char,
Expand Down Expand Up @@ -232,7 +258,7 @@ class TestStruct2 < FFI::Struct
:s_3, TestStruct3.by_value,
:e, :enum_t,
:func, Callback_cb,
:u, UnionT,
:u, UnionT.by_value,
:callback, Callback_cb,
:inline_callback, callback([ Callback_cb_2 ], :void)
)
Expand Down Expand Up @@ -298,10 +324,6 @@ def inline_callback
end

it 'should not use pointers to opaque structs' do
m = Module.new
m.module_exec do
extend FFI::Library
end
xml = generate_xml_wrap_from('parser_opaque_struct')
buf = Generator::Parser.new.generate(xml)
buf.include?("OpaqueStruct.ptr").should == false
Expand Down
20 changes: 10 additions & 10 deletions spec/generator/struct_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@node = generate_xml_wrap_from('structs')
end
it 'should properly generate the layout of a FFI::Struct class' do
Generator::Struct.new(:node => (@node / 'class')[0]).to_s.should == <<EOC
Generator::Struct.new(:node => (@node / 'class')[0]).to_s.should == (_tmp1 = <<EOC)
class TestStruct1 < FFI::Struct
layout(
:i, :int,
Expand All @@ -30,7 +30,7 @@ def s

end
it 'should properly generate the layout of a FFI::Struct containing pointer field' do
Generator::Struct.new(:node => (@node / 'class')[1]).to_s.should == <<EOC
Generator::Struct.new(:node => (@node / 'class')[1]).to_s.should == (_tmp1 = <<EOC)
class TestStruct2 < FFI::Struct
layout(
:ptr, :pointer
Expand All @@ -39,7 +39,7 @@ class TestStruct2 < FFI::Struct
EOC
end
it 'should properly generate the layout of a FFI::Struct containing array field' do
Generator::Struct.new(:node => (@node / 'class')[2]).to_s.should == <<EOC
Generator::Struct.new(:node => (@node / 'class')[2]).to_s.should == (_tmp1 = <<EOC)
class TestStruct3 < FFI::Struct
layout(
:c, [:char, 5]
Expand All @@ -49,7 +49,7 @@ class TestStruct3 < FFI::Struct

end
it 'should properly generate the layout of a FFI::Struct containing array field' do
Generator::Struct.new(:node => (@node / 'class')[3]).to_s.should == <<EOC
Generator::Struct.new(:node => (@node / 'class')[3]).to_s.should == (_tmp1 = <<EOC)
class TestStruct4 < FFI::Struct
layout(
:s, [TestStruct3.by_value, 5]
Expand All @@ -60,7 +60,7 @@ class TestStruct4 < FFI::Struct

it 'should properly generate the layout for struct containing struct' do
node = (@node / "class//[value='test_struct_5']")[0].ancestors("class")[0]
Generator::Struct.new(:node => node).to_s.should == <<EOC
Generator::Struct.new(:node => node).to_s.should == (_tmp1 = <<EOC)
class TestStruct5 < FFI::Struct
layout(
:s, TestStruct4.by_value
Expand All @@ -71,7 +71,7 @@ class TestStruct5 < FFI::Struct

it 'should properly generate the layout for struct containing struct pointer' do
node = (@node / "class//[value='test_struct_6']")[0].ancestors("class")[0]
Generator::Struct.new(:node => node).to_s.should == <<EOC
Generator::Struct.new(:node => node).to_s.should == (_tmp1 = <<EOC)
class TestStruct6 < FFI::Struct
layout(
:s, TestStruct4.ptr
Expand All @@ -81,7 +81,7 @@ class TestStruct6 < FFI::Struct
end
it 'should prepend struct dependencies' do
node = (@node / "class//[value='test_struct_7']")[0].ancestors("class")[0]
Generator::Struct.new(:node => node).to_s.should == <<EOC
Generator::Struct.new(:node => node).to_s.should == (_tmp1 = <<EOC)
class TestStruct7 < FFI::Struct
layout(
:s, UndefinedStruct.ptr
Expand All @@ -101,10 +101,10 @@ class TestStruct7 < FFI::Struct

# Parse it and verify we're referencing the union in the typedef
Generator::Struct.new(:node => node, :typedefs => typedefs).to_s \
.should == <<EOC
.should == (_tmp1 = <<EOC)
class TestStruct8 < FFI::Struct
layout(
:data, TestStruct8Data
:data, TestStruct8Data.by_value
)
end
EOC
Expand All @@ -117,7 +117,7 @@ class TestStruct8 < FFI::Struct
@node = generate_xml_wrap_from('unions')
end
it 'should properly generate the layout of a FFI::Union class' do
Generator::Union.new(:node => (@node / 'class')[0]).to_s.should == <<EOC
Generator::Union.new(:node => (@node / 'class')[0]).to_s.should == (_tmp1 = <<EOC)
class UnionT < FFI::Union
layout(
:c, :char,
Expand Down
Loading