class ProtocolBuffers::TextParser
token identifier string integer bool float rule
message : /* none */ { result = current_message } | message field field : field_name ':' primitive_value { set_field(val[0], val[2]) } | field_name ':' identifier { field, enum_symbol = val[0], val[2] unless field.kind_of?(ProtocolBuffers::Field::EnumField) raise Racc::ParseError, "not a enum field: %s" % field.name end value = field.value_from_name(enum_symbol) unless value raise Racc::ParseError, "enum type %s has no value named %s" % [field.name, enum_symbol] end set_field(field, value) } | message_field_head '<' { field = _values[-2] push_message(field.proxy_class.new) } message '>' { pop_message set_field(val[0], val[3]) } | message_field_head '{' { field = _values[-2] push_message(field.proxy_class.new) } message '}' { pop_message set_field(val[0], val[3]) } message_field_head : field_name | field_name ':' field_name : identifier { field = current_message.class.field_for_name(val[0]) if field return field end # fallback for case mismatch in group fields. field = current_message.fields.find { |tag,field| field.name.to_s.downcase == val[0].downcase } field &&= field.last if field && field.kind_of?(ProtocolBuffers::Field::GroupField) return field end raise Racc::ParseError, "no such field %s in %s" % [val[0], current_message.class] } | '[' qualified_name ']' { raise NotImplementedError, "extension is not yet supported" } qualified_name : identifier { result = [val[0]] } | qualified_name '.' identifier { result = (val[0] << val[2]) } primitive_value : concat_string | integer | float | bool concat_string : string | concat_string string { result = val[0] + val[1] }
end
—- header require ‘protocol_buffers/runtime/text_scanner’
—- inner def initialize
@msgstack = []
end
attr_accessor :yydebug
def parse_text(text, message)
scanner = ProtocolBuffers::TextScanner.new(text) parse_from_scanner(scanner.enum_for(:scan), message)
end
def parse_from_scanner(scanner, message)
@msgstack.clear push_message(message) yyparse(scanner, :each) pop_message
end
private :yyparse, :do_parse private def current_message
@msgstack.last
end
def push_message(message)
@msgstack.push(message)
end
def pop_message
@msgstack.pop
end
def set_field(field, value)
msg = current_message if field.repeated? msg.value_for_tag(field.tag) << value else msg.set_value_for_tag(field.tag, value) end msg
end