CORD-1165: Support native Protobufs for specifying XOS models
Change-Id: I81abda44d164b6adb34e664680cf69a6ba74f353
diff --git a/xos/genx/targets/xproto.xtarget b/xos/genx/targets/xproto.xtarget
new file mode 100644
index 0000000..843d741
--- /dev/null
+++ b/xos/genx/targets/xproto.xtarget
@@ -0,0 +1,18 @@
+{% for k,v in options.iteritems() %}
+option {{ k }} = {{ v }};
+{% endfor %}
+
+{% for m in proto.messages %}
+message {{ m.name }} ({{ m.bases | join(",") }}){
+ {%- for f in m.fields %}
+ {% if not f.link %}
+ {{ f.modifier }} {{f.type}} {{f.name}} = {{ f.id }}{% if f.options %} [{% for k,v in f.options.iteritems() %} {{ k }} = {{ v }}{% if not loop.last %},{% endif %} {% endfor %}]{% endif %};
+ {% endif %}
+ {%- endfor %}
+
+ {%- for l in m.links %}
+ {{ l }}
+ {{ l.modifier }} {{ l.link_type }} {{ l.name }} -> {{ l.peer }}:{{ l.dst_port }} = 1 {% if l.options %} [{% for k,v in l.options.iteritems() %} {{ k }} = {{ v }}{% if not loop.last %},{% endif %} {% endfor %}]{% endif %};
+ {%- endfor -%}
+}
+{% endfor %}
diff --git a/xos/genx/tool/lib.py b/xos/genx/tool/lib.py
index 1c5200e..2230d5c 100644
--- a/xos/genx/tool/lib.py
+++ b/xos/genx/tool/lib.py
@@ -154,3 +154,4 @@
return '_'
return match
+
diff --git a/xos/genx/tool/proto2xproto.py b/xos/genx/tool/proto2xproto.py
index 413ff0a..ad6a21e 100644
--- a/xos/genx/tool/proto2xproto.py
+++ b/xos/genx/tool/proto2xproto.py
@@ -11,14 +11,59 @@
def push(self,x):
self.append(x)
-''' Proto2XProto overrides the underlying visitor pattern to transform the tree
- in addition to traversing it '''
+def replace_link(obj):
+ try:
+ link = obj.link
+ try:
+ through = link['through']
+ except KeyError:
+ through = None
+
+ try:
+ through_str = through[1:-1]
+ except TypeError:
+ through_str = None
+
+ ls = m.LinkSpec(obj, m.LinkDefinition(link['link'][1:-1],obj.name,link['model'][1:-1],link['port'][1:-1],through_str))
+ return ls
+ except:
+ return obj
+
class Proto2XProto(m.Visitor):
stack = Stack()
count_stack = Stack()
content=""
offset=0
statementsChanged=0
+ message_options = {}
+ options = {}
+ current_message_name = None
+
+ xproto_message_options = ['bases']
+ xproto_field_options = ['model']
+
+
+ def proto_to_xproto_field(self, obj):
+ try:
+ opts = {}
+ for fd in obj.fieldDirective:
+ k = fd.pval.name.value.pval
+ v = fd.pval.value.value.pval
+ opts[k]=v
+
+ if ('model' in opts and 'link' in opts and 'port' in opts):
+ obj.link = opts
+ pass
+ except KeyError:
+ raise
+
+ def proto_to_xproto_message(self, obj):
+ try:
+ bases = self.message_options['bases'].split(',')
+ bases = map(lambda x:x[1:-1], bases)
+ obj.bases = bases
+ except KeyError:
+ raise
def map_field(self, obj, s):
if 'model' in s:
@@ -48,7 +93,14 @@
return True
def visit_OptionStatement(self, obj):
- '''Ignore'''
+ if (self.current_message_name):
+ k = obj.name.value.pval
+ self.message_options[k] = obj.value.value.pval
+ if (k in self.xproto_message_options):
+ obj.mark_for_deletion = True
+ else:
+ self.options[obj.name.value.pval] = obj.value.value.pval
+
return True
def visit_LU(self, obj):
@@ -61,20 +113,6 @@
return True
def visit_FieldDirective_post(self, obj):
- try:
- name = obj.name.value.pval
- except AttributeError:
- name = obj.name.value
-
- try:
- value = obj.value.value.pval
- except AttributeError:
- try:
- value = obj.value.value
- except AttributeError:
- value = obj.value.pval
-
- self.stack.push([name,value])
return True
def visit_FieldType(self, obj):
@@ -84,19 +122,10 @@
return True
def visit_FieldDefinition(self, obj):
- self.count_stack.push(len(obj.fieldDirective))
return True
def visit_FieldDefinition_post(self, obj):
- opts = {}
- n = self.count_stack.pop()
- for i in range(0, n):
- k,v = self.stack.pop()
- opts[k] = v
-
- f = self.map_field(obj, opts)
- self.stack.push(f)
- #self.stack::declare.push(f)
+ self.proto_to_xproto_field(obj)
return True
def visit_EnumFieldDefinition(self, obj):
@@ -106,17 +135,17 @@
return True
def visit_MessageDefinition(self, obj):
- self.count_stack.push(len(obj.body))
+ self.current_message_name = obj.name.value.pval
+ self.message_options = {}
+
return True
def visit_MessageDefinition_post(self, obj):
- stack_num = self.count_stack.pop()
- lst = []
+ self.proto_to_xproto_message(obj)
+ obj.body = filter(lambda x:not hasattr(x, 'mark_for_deletion'), obj.body)
+ obj.body = map(replace_link, obj.body)
- for n in range(0,stack_num):
- lst.append(self.stack.pop())
-
- obj.body = lst
+ self.current_message_name = None
return True
def visit_MessageExtension(self, obj):
diff --git a/xos/genx/tool/xos2jinja.py b/xos/genx/tool/xos2jinja.py
index 5af2272..3db2b41 100644
--- a/xos/genx/tool/xos2jinja.py
+++ b/xos/genx/tool/xos2jinja.py
@@ -34,8 +34,6 @@
count_stack = Stack()
content=""
offset=0
- doNameSanitization=False
- statementsChanged=0
prefix=""
current_message_name = None
@@ -58,10 +56,11 @@
return True
def visit_OptionStatement(self, obj):
- if (self.current_message_name):
- self.message_options[obj.name.value.pval] = obj.value.value.pval
- else:
- self.options[obj.name.value.pval] = obj.value.value.pval
+ if not hasattr(obj,'mark_for_deletion'):
+ if (self.current_message_name):
+ self.message_options[obj.name.value.pval] = obj.value.value.pval
+ else:
+ self.options[obj.name.value.pval] = obj.value.value.pval
return True
@@ -99,22 +98,30 @@
def visit_LinkDefinition(self, obj):
s={}
- s['link_type'] = obj.link_type.pval
+ try:
+ s['link_type'] = obj.link_type.pval
+ except AttributeError:
+ s['link_type'] = obj.link_type
+
s['src_port'] = obj.src_port.value.pval
s['name'] = obj.src_port.value.pval
try:
s['dst_port'] = obj.dst_port.value.pval
except AttributeError:
- s['dst_port'] = ''
+ s['dst_port'] = obj.dst_port
try:
s['through'] = obj.through.pval
except AttributeError:
- s['through'] = ''
+ s['through'] = obj.through
- s['peer'] = obj.name.pval
+ try:
+ s['peer'] = obj.name.pval
+ except AttributeError:
+ s['peer'] = obj.name
+
s['_type'] = 'link'
s['options'] = {'modifier':'optional'}
@@ -179,7 +186,10 @@
fields = []
links = []
last_field = None
- obj.bases = map(lambda x:x.pval, obj.bases)
+ try:
+ obj.bases = map(lambda x:x.pval, obj.bases)
+ except AttributeError:
+ pass
for i in range(0,stack_num):
f = self.stack.pop()
diff --git a/xos/genx/tool/xosgen b/xos/genx/tool/xosgen
index addb6ba..ca6f070 100755
--- a/xos/genx/tool/xosgen
+++ b/xos/genx/tool/xosgen
@@ -36,15 +36,16 @@
def main():
try:
- if (not args.rev):
- v = XOS2Jinja()
- else:
- v = Proto2XProto()
parser = plyproto.ProtobufAnalyzer()
input = open(args.input).read()
-
ast = parser.parse_string(input,debug=0)
+
+ if (args.rev):
+ v = Proto2XProto()
+ ast.accept(v)
+
+ v = XOS2Jinja()
ast.accept(v)
template_name = os.path.abspath(args.target)