Fix memory issues, add HBytes#token.

This commit is contained in:
Jakob Rath 2013-12-16 21:00:59 +01:00 committed by Dan Hirsch
parent cf59ec83ed
commit b16eab8f33
3 changed files with 23 additions and 3 deletions

View file

@ -16,4 +16,7 @@ parser = Hammer::Parser.build {
}
x.bind(Hammer::Parser.token('abd'))
#$p = parser
$r = parser.parse 'abcabd'
p $r[:ast][:data][:seq].elements.map {|e| e[:data][:bytes].token }

View file

@ -37,6 +37,11 @@ module Hammer
class HBytes < FFI::Struct
layout :token, :pointer, # uint8_t*
:len, :size_t
def token
# TODO: Encoding? Should probably be the same encoding as the string the token was created with.
return self[:token].read_string(self[:len]) #.force_encoding('UTF-8')
end
end
class HParsedTokenDataUnion < FFI::Union

View file

@ -7,10 +7,12 @@ module Hammer
# name: Name of the parser. Should be a symbol.
# h_parser: The pointer to the parser as returned by hammer.
# dont_gc: Pass additional data that's used by the parser and needs to be saved from the garbage collector (at least as long this object lives).
def initialize(name, h_parser, dont_gc)
def initialize(name, h_parser, dont_gc=[])
@name = name
@h_parser = h_parser
@dont_gc = dont_gc
# Always store as array, so we can easily add stuff later on
dont_gc = [dont_gc] unless dont_gc.is_a? Array
@dont_gc = dont_gc.dup
end
attr_reader :name
@ -24,13 +26,23 @@ module Hammer
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.bytesize)
return result unless result.null?
if result.null?
return nil
else
# NOTE:
# The parse result *must* hold a reference to the parser that created it!
# Otherwise, the parser might get garbage-collected while the result is still valid.
# Any pointers to token strings will then be invalid.
result.instance_variable_set :@parser, self
return result
end
end
# Binds an indirect parser.
def bind(other_parser)
raise RuntimeError, 'can only bind indirect parsers' unless self.name == :indirect
Hammer::Internal.h_bind_indirect(self.h_parser, other_parser.h_parser)
@dont_gc << other_parser
end
def self.token(string)