Support post actions in visitor, fixes to the grammar
diff --git a/plyproto/model.py b/plyproto/model.py
index 802cf47..bfa5e95 100644
--- a/plyproto/model.py
+++ b/plyproto/model.py
@@ -185,6 +185,7 @@
if visitor.visit_FieldDirective(self):
self.v(self.name, visitor)
self.v(self.value, visitor)
+ visitor.visit_FieldDirective_post(self)
class FieldType(SourceElement):
def __init__(self, name, linespan=None, lexspan=None, p=None):
@@ -197,6 +198,22 @@
if visitor.visit_FieldType(self):
self.v(self.name, visitor)
+class LinkDefinition(SourceElement):
+ def __init__(self, link_type, src_port, name, dst_port, linespan=None, lexspan=None, p=None):
+ super(LinkDefinition, self).__init__(linespan=linespan, lexspan=lexspan, p=p)
+ self._fields += ['link_type', 'src_port', 'name', 'dst_port']
+ self.link_type = link_type
+ Base.p(self.link_type, self)
+ self.src_port = src_port
+ Base.p(self.src_port, self)
+ self.name = name
+ Base.p(self.name, self)
+ self.dst_port = dst_port
+ Base.p(self.dst_port, self)
+
+ def accept(self, visitor):
+ visitor.visit_LinkDefinition(self)
+
class FieldDefinition(SourceElement):
def __init__(self, field_modifier, ftype, name, fieldId, fieldDirective, linespan=None, lexspan=None, p=None):
super(FieldDefinition, self).__init__(linespan=linespan, lexspan=lexspan, p=p)
@@ -219,6 +236,7 @@
self.v(self.ftype, visitor)
self.v(self.fieldId, visitor)
self.v(self.fieldDirective, visitor)
+ visitor.visit_FieldDefinition_post(self)
class EnumFieldDefinition(SourceElement):
def __init__(self, name, fieldId, linespan=None, lexspan=None, p=None):
@@ -248,6 +266,41 @@
self.v(self.name, visitor)
self.v(self.body, visitor)
+class LinkSpec(SourceElement):
+ def __init__(self, field_spec, link_spec, linespan=None, lexspan=None, p=None):
+ super(LinkSpec, self).__init__(linespan=linespan, lexspan=lexspan, p=p)
+ self._fields += ['link_def', 'field_def']
+ self.link_def = link_spec
+ Base.p(self.link_def, self)
+ self.field_def = field_spec
+ Base.p(self.field_def, self)
+
+ def accept(self, visitor):
+ if visitor.visit_LinkSpec(self):
+ self.v(self.link_def, visitor)
+ self.v(self.field_def, visitor)
+ visitor.visit_LinkSpec_post(self)
+
+class MessageDefinition(SourceElement):
+ def __init__(self, name, bclass, body, linespan=None, lexspan=None, p=None):
+ super(MessageDefinition, self).__init__(linespan=linespan, lexspan=lexspan, p=p)
+ self._fields += ['name', 'bclass', 'body']
+ self.name = name
+ Base.p(self.name, self)
+ self.bclass = bclass
+ Base.p(self.bclass, self)
+ self.body = body
+ Base.p(self.body, self)
+
+ def accept(self, visitor):
+ if visitor.visit_MessageDefinition(self):
+ self.v(self.name, visitor)
+ self.v(self.bclass, visitor)
+ self.v(self.body, visitor)
+ visitor.visit_MessageDefinition_post(self)
+
+
+"""
class MessageDefinition(SourceElement):
def __init__(self, name, body, linespan=None, lexspan=None, p=None):
super(MessageDefinition, self).__init__(linespan=linespan, lexspan=lexspan, p=p)
@@ -261,6 +314,8 @@
if visitor.visit_MessageDefinition(self):
self.v(self.name, visitor)
self.v(self.body, visitor)
+ visitor.visit_MessageDefinition_post(self)
+"""
class MessageExtension(SourceElement):
def __init__(self, name, body, linespan=None, lexspan=None, p=None):
@@ -275,6 +330,7 @@
if visitor.visit_MessageExtension(self):
self.v(self.name, visitor)
self.v(self.body, visitor)
+ visitor.visit_MessageExtension_post(self)
class MethodDefinition(SourceElement):
def __init__(self, name, name2, name3, linespan=None, lexspan=None, p=None):
@@ -292,6 +348,7 @@
self.v(self.name, visitor)
self.v(self.name2, visitor)
self.v(self.name3, visitor)
+ visitor.visit_MethodDefinition_post(self)
class ServiceDefinition(SourceElement):
def __init__(self, name, body, linespan=None, lexspan=None, p=None):
@@ -306,6 +363,7 @@
if visitor.visit_ServiceDefinition(self):
self.v(self.name, visitor)
self.v(self.body, visitor)
+ visitor.visit_ServiceDefinition_post(self)
class ExtensionsMax(SourceElement):
pass
@@ -323,6 +381,7 @@
if visitor.visit_ExtensionsDirective(self):
self.v(self.fromVal, visitor)
self.v(self.toVal, visitor)
+ visitor.visit_ExtensionsDirective_post(self)
class Literal(SourceElement):
@@ -393,3 +452,4 @@
if visitor.visit_Proto(self):
self.v(self.pkg, visitor)
self.v(self.body, visitor)
+ visitor.visit_Proto_post(self)
diff --git a/plyproto/parser.py b/plyproto/parser.py
index e75eb52..eb2d776 100755
--- a/plyproto/parser.py
+++ b/plyproto/parser.py
@@ -1,4 +1,5 @@
__author__ = "Dusan (Ph4r05) Klinec"
+
__copyright__ = "Copyright (C) 2014 Dusan (ph4r05) Klinec"
__license__ = "Apache License, Version 2.0"
__version__ = "1.0"
@@ -7,11 +8,13 @@
import ply.yacc as yacc
from .model import *
+import pdb
+
class ProtobufLexer(object):
keywords = ('double', 'float', 'int32', 'int64', 'uint32', 'uint64', 'sint32', 'sint64',
'fixed32', 'fixed64', 'sfixed32', 'sfixed64', 'bool', 'string', 'bytes',
'message', 'required', 'optional', 'repeated', 'enum', 'extensions', 'max', 'extends', 'extend',
- 'to', 'package', 'service', 'rpc', 'returns', 'true', 'false', 'option', 'import')
+ 'to', 'package', '_service', 'rpc', 'returns', 'true', 'false', 'option', 'import', 'manytoone', 'manytomany', 'onetoone')
tokens = [
'NAME',
@@ -21,6 +24,7 @@
'LBRACE', 'RBRACE', 'LBRACK', 'RBRACK',
'LPAR', 'RPAR', 'EQ', 'SEMI', 'DOT',
+ 'ARROW', 'COLON', 'COMMA',
'STARTTOKEN'
] + [k.upper() for k in keywords]
@@ -42,6 +46,9 @@
t_RPAR = '\\)'
t_EQ = '='
t_SEMI = ';'
+ t_ARROW = '\\-\\>'
+ t_COLON = '\\:'
+ t_COMMA = '\\,'
t_DOT = '\\.'
t_ignore = ' \t\f'
t_STARTTOKEN = '\\+'
@@ -105,6 +112,13 @@
dst.setLexData(linespan=self.get_max_linespan(p), lexspan=self.get_max_lexspan(p))
dst.setLexObj(p)
+def srcPort(x):
+ if (x):
+ return [FieldDirective(Name('port'),x)]
+ else:
+ return []
+
+
class ProtobufParser(object):
tokens = ProtobufLexer.tokens
offset = 0
@@ -142,6 +156,12 @@
| BYTES'''
p[0] = LU.i(p,1)
+ def p_link_type(self, p):
+ '''link_type : ONETOONE
+ | MANYTOONE
+ | MANYTOMANY'''
+ p[0] = LU.i(p,1)
+
def p_field_id(self, p):
'''field_id : NUM'''
p[0] = LU.i(p,1)
@@ -152,15 +172,30 @@
| FALSE'''
p[0] = LU.i(p,1)
+ def p_rvalue3(self, p):
+ '''rvalue : STRING_LITERAL'''
+ p[0] = Name(LU.i(p, 1))
+ self.lh.set_parse_object(p[0], p)
+ p[0].deriveLex()
+
def p_rvalue2(self, p):
'''rvalue : NAME'''
p[0] = Name(LU.i(p, 1))
self.lh.set_parse_object(p[0], p)
p[0].deriveLex()
+ def p_field_directives2(self, p):
+ '''field_directives : empty'''
+ p[0] = []
+
+ def p_field_directives(self, p):
+ '''field_directives : LBRACK field_directive_times RBRACK'''
+ p[0] = p[2]
+ #self.lh.set_parse_object(p[0], p)
+
def p_field_directive(self, p):
- '''field_directive : LBRACK NAME EQ rvalue RBRACK'''
- p[0] = FieldDirective(Name(LU.i(p, 2)), LU.i(p,4))
+ '''field_directive : NAME EQ rvalue'''
+ p[0] = FieldDirective(Name(LU.i(p, 1)), LU.i(p, 3))
self.lh.set_parse_object(p[0], p)
def p_field_directive_times(self, p):
@@ -173,11 +208,11 @@
def p_field_directive_plus(self, p):
'''field_directive_plus : field_directive
- | field_directive_plus field_directive'''
+ | field_directive_plus COMMA field_directive'''
if len(p) == 2:
p[0] = [LU(p,1)]
else:
- p[0] = p[1] + [LU(p,2)]
+ p[0] = p[1] + [LU(p,3)]
def p_dotname(self, p):
'''dotname : NAME
@@ -207,9 +242,27 @@
self.lh.set_parse_object(p[0], p)
p[0].deriveLex()
+ def p_colon_fieldname(self, p):
+ '''colon_fieldname : COLON field_name'''
+ p[0] = p[2]
+ self.lh.set_parse_object(p[0], p)
+
+ def p_colon_fieldname2(self, p):
+ '''colon_fieldname : empty'''
+ p[0] = None
+
+ # TODO: Add directives to link definition
+ def p_link_definition(self, p):
+ '''link_definition : field_modifier link_type field_name ARROW NAME colon_fieldname EQ field_id field_directives SEMI'''
+ p[0] = LinkSpec(
+ FieldDefinition(LU.i(p,1), Name('int32'), LU.i(p, 3), LU.i(p, 8), [FieldDirective(Name('type'), Name('link')), FieldDirective(Name('model'),LU.i(p, 5))] + srcPort(LU.i(p,6)) + LU.i(p,9)),
+ LinkDefinition(LU.i(p,2), LU.i(p,3), LU.i(p,5), LU.i(p,6)))
+
+ self.lh.set_parse_object(p[0], p)
+
# Root of the field declaration.
def p_field_definition(self, p):
- '''field_definition : field_modifier field_type field_name EQ field_id field_directive_times SEMI'''
+ '''field_definition : field_modifier field_type field_name EQ field_id field_directives SEMI'''
p[0] = FieldDefinition(LU.i(p,1), LU.i(p,2), LU.i(p, 3), LU.i(p,5), LU.i(p,6))
self.lh.set_parse_object(p[0], p)
@@ -270,6 +323,7 @@
def p_message_body_part(self, p):
'''message_body_part : field_definition
+ | link_definition
| enum_definition
| message_definition
| extensions_definition
@@ -290,11 +344,19 @@
else:
p[0] = p[1] + [p[2]]
+ def p_base_definition(self, p):
+ '''base_definition : LPAR NAME RPAR'''
+ p[0] = p[2]
+
+ def p_base_definition2(self, p):
+ '''base_definition : empty'''
+ p[0] = None
+
# Root of the message declaration.
# message_definition = MESSAGE_ - ident("messageId") + LBRACE + message_body("body") + RBRACE
def p_message_definition(self, p):
- '''message_definition : MESSAGE NAME LBRACE message_body RBRACE'''
- p[0] = MessageDefinition(Name(LU.i(p, 2)), LU.i(p,4))
+ '''message_definition : MESSAGE NAME base_definition LBRACE message_body RBRACE'''
+ p[0] = MessageDefinition(Name(LU.i(p, 2)), LU.i(p, 3), LU.i(p,5))
self.lh.set_parse_object(p[0], p)
# method_definition ::= 'rpc' ident '(' [ ident ] ')' 'returns' '(' [ ident ] ')' ';'
@@ -318,7 +380,7 @@
# service_definition ::= 'service' ident '{' method_definition* '}'
# service_definition = SERVICE_ - ident("serviceName") + LBRACE + ZeroOrMore(Group(method_definition)) + RBRACE
def p_service_definition(self, p):
- '''service_definition : SERVICE NAME LBRACE method_definition_opt RBRACE'''
+ '''service_definition : _SERVICE NAME LBRACE method_definition_opt RBRACE'''
p[0] = ServiceDefinition(Name(LU.i(p, 2)), LU.i(p,4))
self.lh.set_parse_object(p[0], p)
@@ -401,8 +463,8 @@
class ProtobufAnalyzer(object):
def __init__(self):
- self.lexer = lex.lex(module=ProtobufLexer(), optimize=1)
- self.parser = yacc.yacc(module=ProtobufParser(), start='goal', optimize=1)
+ self.lexer = lex.lex(module=ProtobufLexer())#, optimize=1)
+ self.parser = yacc.yacc(module=ProtobufParser(), start='goal', debug=0)#optimize=1)
def tokenize_string(self, code):
self.lexer.input(code)