diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ffi_yajl/ffi/parser.rb | 60 |
1 files changed, 27 insertions, 33 deletions
diff --git a/lib/ffi_yajl/ffi/parser.rb b/lib/ffi_yajl/ffi/parser.rb index 05fa11e..4df58da 100644 --- a/lib/ffi_yajl/ffi/parser.rb +++ b/lib/ffi_yajl/ffi/parser.rb @@ -1,12 +1,17 @@ + +require 'ffi_yajl/ffi' + module FFI_Yajl module FFI module Parser - class State attr_accessor :stack, :key_stack, :key - def initialize - @stack = Array.new - @key_stack = Array.new + def stack + @stack ||= Array.new + end + + def key_stack + @key_stack ||= Array.new end def save_key @@ -28,20 +33,18 @@ module FFI_Yajl raise end end - end def setup_callbacks - ctx_mapping = @ctx_mapping # get a local alias @null_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx| - ctx_mapping[ctx.get_ulong(0)].set_value(nil) + self.set_value(nil) 1 end @boolean_callback = ::FFI::Function.new(:int, [:pointer, :int]) do |ctx, boolval| - ctx_mapping[ctx.get_ulong(0)].set_value(boolval == 1 ? true : false) + self.set_value(boolval == 1 ? true : false) 1 end @integer_callback = ::FFI::Function.new(:int, [:pointer, :long_long]) do |ctx, intval| - ctx_mapping[ctx.get_ulong(0)].set_value(intval) + self.set_value(intval) 1 end @number_callback = ::FFI::Function.new(:int, [:pointer, :string, :size_t ]) do |ctx, stringval, stringlen| @@ -49,56 +52,48 @@ module FFI_Yajl s.force_encoding('UTF-8') if defined? Encoding # XXX: I can't think of a better way to do this right now. need to call to_f if and only if its a float. v = ( s =~ /\./ ) ? s.to_f : s.to_i - ctx_mapping[ctx.get_ulong(0)].set_value(v) + self.set_value(v) 1 end @double_callback = ::FFI::Function.new(:int, [:pointer, :double]) do |ctx, doubleval| - ctx_mapping[ctx.get_ulong(0)].set_value(doubleval) + self.set_value(doubleval) 1 end @string_callback = ::FFI::Function.new(:int, [:pointer, :string, :size_t]) do |ctx, stringval, stringlen| s = stringval.slice(0,stringlen) s.force_encoding('UTF-8') if defined? Encoding - ctx_mapping[ctx.get_ulong(0)].set_value(s) + self.set_value(s) 1 end @start_map_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx| - state = ctx_mapping[ctx.get_ulong(0)] - state.save_key - state.stack.push(Hash.new) + self.save_key + self.stack.push(Hash.new) 1 end @map_key_callback = ::FFI::Function.new(:int, [:pointer, :string, :size_t]) do |ctx, key, keylen| - ctx_mapping[ctx.get_ulong(0)].key = key.slice(0,keylen) + self.key = key.slice(0,keylen) 1 end @end_map_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx| - state = ctx_mapping[ctx.get_ulong(0)] - state.restore_key - state.set_value( state.stack.pop ) if state.stack.length > 1 + self.restore_key + self.set_value( self.stack.pop ) if self.stack.length > 1 1 end @start_array_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx| - state = ctx_mapping[ctx.get_ulong(0)] - state.save_key - state.stack.push(Array.new) + self.save_key + self.stack.push(Array.new) 1 end @end_array_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx| - state = ctx_mapping[ctx.get_ulong(0)] - state.restore_key - ctx_mapping[ctx.get_ulong(0)].set_value( ctx_mapping[ctx.get_ulong(0)].stack.pop ) if ctx_mapping[ctx.get_ulong(0)].stack.length > 1 + self.restore_key + self.set_value( self.stack.pop ) if self.stack.length > 1 1 end end + def do_yajl_parse(str, opts = {}) - @ctx_mapping ||= Hash.new setup_callbacks - rb_ctx = ::FFI_Yajl::FFI::Parser::State.new() - @ctx_mapping[rb_ctx.object_id] = rb_ctx - ctx = ::FFI::MemoryPointer.new(:long) - ctx.write_long( rb_ctx.object_id ) callback_ptr = ::FFI::MemoryPointer.new(::FFI_Yajl::YajlCallbacks) callbacks = ::FFI_Yajl::YajlCallbacks.new(callback_ptr) callbacks[:yajl_null] = @null_callback @@ -112,7 +107,7 @@ module FFI_Yajl callbacks[:yajl_end_map] = @end_map_callback callbacks[:yajl_start_array] = @start_array_callback callbacks[:yajl_end_array] = @end_array_callback - yajl_handle = ::FFI_Yajl.yajl_alloc(callback_ptr, nil, ctx) + yajl_handle = ::FFI_Yajl.yajl_alloc(callback_ptr, nil, nil) if ( stat = ::FFI_Yajl.yajl_parse(yajl_handle, str, str.bytesize) != :yajl_status_ok ) # FIXME: dup the error and call yajl_free_error? error = ::FFI_Yajl.yajl_get_error(yajl_handle, 1, str, str.length) @@ -123,10 +118,9 @@ module FFI_Yajl error = ::FFI_Yajl.yajl_get_error(yajl_handle, 1, str, str.length) raise ::FFI_Yajl::ParseError.new(error) end - rb_ctx.stack.pop + stack.pop ensure ::FFI_Yajl.yajl_free(yajl_handle) if yajl_handle - @ctx_mapping.delete(rb_ctx.object_id) if rb_ctx && rb_ctx.object_id end end end |