ruby/test/racc/assets/php_serialization.y

99 строки
3.2 KiB
Plaintext

# MIT License
# See https://github.com/divoxx/ruby-php-serialization/blob/master/LICENSE.txt
class PhpSerialization::Unserializer
rule
data : null ';' { @object = val[0] }
| bool ';' { @object = val[0] }
| integer ';' { @object = val[0] }
| double ';' { @object = val[0] }
| string ';' { @object = val[0] }
| assoc_array { @object = val[0] }
| object { @object = val[0] }
;
null : 'N' { result = nil }
;
bool : 'b' ':' NUMBER { result = Integer(val[2]) > 0 }
;
integer : 'i' ':' NUMBER { result = Integer(val[2]) }
;
double : 'd' ':' NUMBER { result = Float(val[2]) }
;
string : 's' ':' NUMBER ':' STRING { result = val[4] }
;
object : 'O' ':' NUMBER ':' STRING ':' NUMBER ':' '{' attribute_list '}'
{
if eval("defined?(#{val[4]})")
result = Object.const_get(val[4]).new
val[9].each do |(attr_name, value)|
# Protected and private attributes will have a \0..\0 prefix
attr_name = attr_name.gsub(/\A\\0[^\\]+\\0/, '')
result.instance_variable_set("@#{attr_name}", value)
end
else
klass_name = val[4].gsub(/^Struct::/, '')
attr_names, values = [], []
val[9].each do |(attr_name, value)|
# Protected and private attributes will have a \0..\0 prefix
attr_names << attr_name.gsub(/\A\\0[^\\]+\\0/, '')
values << value
end
result = Struct.new(klass_name, *attr_names).new(*values)
result.instance_variable_set("@_php_class", klass_name)
end
}
;
attribute_list : attribute_list attribute { result = val[0] << val[1] }
| { result = [] }
;
attribute : data data { result = val }
;
assoc_array : 'a' ':' NUMBER ':' '{' attribute_list '}'
{
# Checks if the keys are a sequence of integers
idx = -1
arr = val[5].all? { |(k,v)| k == (idx += 1) }
if arr
result = val[5].map { |(k,v)| v }
else
result = Hash[val[5]]
end
}
;
end
---- header ----
require 'php_serialization/tokenizer'
---- inner ----
def initialize(tokenizer_klass = Tokenizer)
@tokenizer_klass = tokenizer_klass
end
def run(string)
@tokenizer = @tokenizer_klass.new(string)
yyparse(@tokenizer, :each)
return @object
ensure
@tokenizer = nil
end
def next_token
@tokenizer.next_token
end