diff --git a/src/bindings/ruby/lib/hammer.rb b/src/bindings/ruby/lib/hammer.rb index 54b2501c71bd21bcae02b44977c9ea7e70e625fb..0ae353c185ce9e60d5dce76f0fc7ac0fe31a4a5d 100644 --- a/src/bindings/ruby/lib/hammer.rb +++ b/src/bindings/ruby/lib/hammer.rb @@ -71,3 +71,5 @@ p parser.parse 'abcabdabd' p parser.parse 'abcabd' p parser.parse 'abdabd' p parser.parse 'abd' + +$r = parser.parse 'abcabd' diff --git a/src/bindings/ruby/lib/hammer/internal.rb b/src/bindings/ruby/lib/hammer/internal.rb index 3ef39a1fb48bf22ef28695543a8ecb25844412b7..9cd82fa2c146832c8c3a1f02d3c35d7b0344df37 100644 --- a/src/bindings/ruby/lib/hammer/internal.rb +++ b/src/bindings/ruby/lib/hammer/internal.rb @@ -7,10 +7,59 @@ module Hammer ffi_lib 'libhammer.dylib' typedef :pointer, :h_parser - typedef :pointer, :h_parse_result + + HTokenType = enum(:none, 1, + :bytes, 2, + :sint, 4, + :uint, 8, + :sequence, 16, + :reserved_1, + :err, 32, + :user, 64, + :max) + + class HCountedArray < FFI::Struct + layout :capacity, :size_t, + :used, :size_t, + :arena, :pointer, + :elements, :pointer # TODO + end + + class HBytes < FFI::Struct + layout :token, :uint8, + :len, :size_t + end + + class HParsedTokenDataUnion < FFI::Union + layout :bytes, HBytes.by_value, + :sint, :int64, + :uint, :uint64, + :dbl, :double, + :flt, :float, + :seq, HCountedArray.by_ref, + :user, :pointer + end + + class HParsedToken < FFI::Struct + layout :token_type, HTokenType, + :data, HParsedTokenDataUnion.by_value, + :index, :size_t, + :bit_offset, :char + end + + class HParseResult < FFI::Struct + layout :ast, HParsedToken.by_ref, + :bit_length, :long_long, + :arena, :pointer + + def self.release(ptr) + p "freeing #{ptr}" + Hammer::Internal.h_parse_result_free(ptr) unless ptr.null? + end + end # run a parser - attach_function :h_parse, [:h_parser, :string, :size_t], :h_parse_result + attach_function :h_parse, [:h_parser, :string, :size_t], HParseResult.auto_ptr # build a parser attach_function :h_token, [:string, :size_t], :h_parser @@ -57,14 +106,8 @@ module Hammer #attach_function :h_action, [:h_parser, ...], :h_parser #attach_function :h_attr_bool, [:h_parser, ...], :h_parser - #class HParseResult < FFI::Struct - # layout :ast, :pointer, - # :bit_length, :longlong, - # :arena, :pointer - #end - # free the parse result - attach_function :h_parse_result_free, [:h_parse_result], :void + attach_function :h_parse_result_free, [HParseResult.by_ref], :void # TODO: Does the HParser* need to be freed? end diff --git a/src/bindings/ruby/lib/hammer/parser.rb b/src/bindings/ruby/lib/hammer/parser.rb index 8ae6ee8bf5586ab65c7def6a1e856259757828ec..a7e175dbccf5e2b6e26da74adf6599c48e99a2e9 100644 --- a/src/bindings/ruby/lib/hammer/parser.rb +++ b/src/bindings/ruby/lib/hammer/parser.rb @@ -16,17 +16,15 @@ module Hammer attr_reader :name attr_reader :h_parser - # Parse the given data. Returns true if successful, false otherwise. + # Parse the given data. Returns the parse result if successful, nil otherwise. # # data: A string containing the data to parse. def parse(data) raise RuntimeError, '@h_parser is nil' if @h_parser.nil? raise ArgumentError, 'expecting a String' unless data.is_a? String # TODO: Not needed, FFI checks that. + result = Hammer::Internal.h_parse(@h_parser, data, data.length) - # TODO: Do something with the data - # (wrap in garbage-collected object, call h_parse_result_free when destroyed by GC) - Hammer::Internal.h_parse_result_free(result) - !result.null? + return result unless result.null? end # Binds an indirect parser. @@ -36,6 +34,9 @@ module Hammer end def self.token(string) + # TODO: + # This might fail in JRuby. + # See "String Memory Allocation" at https://github.com/ffi/ffi/wiki/Core-Concepts h_string = string.dup h_parser = Hammer::Internal.h_token(h_string, h_string.length)