spice-common/python_modules/codegen.py
Marc-André Lureau 1cd26b87c1 Revert "Remove files moved to spice-protocol"
This reverts commit 7665dcf1bb.

Also revert the related build-sys changes to fix the build.

codegen generated code depends on spice-common code (marshaller,
messages etc), it makes more sense to keep the generator along
this. Otherwise a newer protocol release will fail to build older
projects.

*.proto files are required as well, since it generates code that parent
modules depend on unconditionnaly.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-10 16:01:36 +01:00

381 lines
10 KiB
Python

import six
from io import StringIO
def camel_to_underscores(s, upper = False):
res = ""
for i in range(len(s)):
c = s[i]
if i > 0 and c.isupper():
res = res + "_"
if upper:
res = res + c.upper()
else:
res = res + c.lower()
return res
def underscores_to_camel(s):
res = ""
do_upper = True
for i in range(len(s)):
c = s[i]
if c == "_":
do_upper = True
else:
if do_upper:
res = res + c.upper()
else:
res = res + c
do_upper = False
return res
proto_prefix = "Temp"
def set_prefix(prefix):
global proto_prefix
global proto_prefix_upper
global proto_prefix_lower
proto_prefix = prefix
proto_prefix_upper = prefix.upper()
proto_prefix_lower = prefix.lower()
def prefix_underscore_upper(*args):
s = proto_prefix_upper
for arg in args:
s = s + "_" + arg
return s
def prefix_underscore_lower(*args):
s = proto_prefix_lower
for arg in args:
s = s + "_" + arg
return s
def prefix_camel(*args):
s = proto_prefix
for arg in args:
s = s + underscores_to_camel(arg)
return s
def increment_identifier(idf):
v = idf[-1:]
if v.isdigit():
return idf[:-1] + str(int(v) + 1)
return idf + "2"
def sum_array(array):
if len(array) == 0:
return 0
return " + ".join(array)
class CodeWriter:
def __init__(self):
self.out = StringIO()
self.contents = [self.out]
self.indentation = 0
self.at_line_start = True
self.indexes = ["i", "j", "k", "ii", "jj", "kk"]
self.current_index = 0
self.generated = {}
self.vars = []
self.has_error_check = False
self.options = {}
self.function_helper_writer = None
self.index_type = 'uint32_t'
def set_option(self, opt, value = True):
self.options[opt] = value
def has_option(self, opt):
return opt in self.options
def set_is_generated(self, kind, name):
if kind not in self.generated:
v = {}
self.generated[kind] = v
else:
v = self.generated[kind]
v[name] = 1
def is_generated(self, kind, name):
if kind not in self.generated:
return False
v = self.generated[kind]
return name in v
def getvalue(self):
strs = [writer.getvalue() for writer in self.contents]
return "".join(strs)
def get_subwriter(self):
writer = CodeWriter()
self.contents.append(writer)
self.out = StringIO()
self.contents.append(self.out)
writer.indentation = self.indentation
writer.at_line_start = self.at_line_start
writer.index_type = self.index_type
writer.generated = self.generated
writer.options = self.options
writer.public_prefix = self.public_prefix
return writer
def write(self, s):
# Ensure its a unicode string
if six.PY3:
s = str(s)
else:
s = unicode(s)
if len(s) == 0:
return
if self.at_line_start:
self.out.write(u" " * self.indentation)
self.at_line_start = False
self.out.write(s)
return self
def newline(self):
self.out.write(u"\n")
self.at_line_start = True
return self
def writeln(self, s):
self.write(s)
self.newline()
return self
def label(self, s):
self.indentation = self.indentation - 1
self.write(s + ":")
self.indentation = self.indentation + 1
self.newline()
def statement(self, s):
self.write(s)
self.write(";")
self.newline()
return self
def assign(self, var, val):
self.write("%s = %s" % (var, val))
self.write(";")
self.newline()
return self
def increment(self, var, val):
self.write("%s += %s" % (var, val))
self.write(";")
self.newline()
return self
def comment(self, str):
self.write("/* " + str + " */")
return self
def todo(self, str):
self.comment("TODO: *** %s ***" % str).newline()
return self
def error_check(self, check, label = "error"):
self.has_error_check = True
with self.block("if (SPICE_UNLIKELY(%s))" % check):
if self.has_option("print_error"):
self.statement('printf("%%s: Caught error - %s", __PRETTY_FUNCTION__)' % check)
if self.has_option("assert_on_error"):
self.statement("assert(0)")
self.statement("goto %s" % label)
def indent(self):
self.indentation += 4
def unindent(self):
self.indentation -= 4
if self.indentation < 0:
self.indentation = 0
def begin_block(self, prefix= "", comment = ""):
if len(prefix) > 0:
self.write(prefix)
if self.at_line_start:
self.write("{")
else:
self.write(" {")
if len(comment) > 0:
self.write(" ")
self.comment(comment)
self.newline()
self.indent()
def end_block(self, semicolon=False, newline=True):
self.unindent()
if self.at_line_start:
self.write("}")
else:
self.write(" }")
if semicolon:
self.write(";")
if newline:
self.newline()
class Block:
def __init__(self, writer, semicolon, newline):
self.writer = writer
self.semicolon = semicolon
self.newline = newline
def __enter__(self):
return self.writer.get_subwriter()
def __exit__(self, exc_type, exc_value, traceback):
self.writer.end_block(self.semicolon, self.newline)
class PartialBlock:
def __init__(self, writer, scope, semicolon, newline):
self.writer = writer
self.scope = scope
self.semicolon = semicolon
self.newline = newline
def __enter__(self):
return self.scope
def __exit__(self, exc_type, exc_value, traceback):
self.writer.end_block(self.semicolon, self.newline)
class NoBlock:
def __init__(self, scope):
self.scope = scope
def __enter__(self):
return self.scope
def __exit__(self, exc_type, exc_value, traceback):
pass
def block(self, prefix= "", comment = "", semicolon=False, newline=True):
self.begin_block(prefix, comment)
return self.Block(self, semicolon, newline)
def partial_block(self, scope, semicolon=False, newline=True):
return self.PartialBlock(self, scope, semicolon, newline)
def no_block(self, scope):
return self.NoBlock(scope)
def optional_block(self, scope):
if scope != None:
return self.NoBlock(scope)
return self.block()
def for_loop(self, index, limit):
return self.block("for (%s = 0; %s < %s; %s++)" % (index, index, limit, index))
def while_loop(self, expr):
return self.block("while (%s)" % (expr))
def if_block(self, check, elseif=False, newline=True):
s = "if (%s)" % (check)
if elseif:
s = " else " + s
self.begin_block(s, "")
return self.Block(self, False, newline)
def variable_defined(self, name):
for n in self.vars:
if n == name:
return True
return False
def variable_def(self, ctype, *names):
for n in names:
# Strip away initialization
i = n.find("=")
if i != -1:
n = n[0:i]
self.vars.append(n.strip())
# only add space for non-pointer types
if ctype[-1] == "*":
ctype = ctype[:-1].rstrip()
self.writeln("%s *%s;"%(ctype, ", *".join(names)))
else:
self.writeln("%s %s;"%(ctype, ", ".join(names)))
return self
def function_helper(self):
if self.function_helper_writer != None:
writer = self.function_helper_writer.get_subwriter()
self.function_helper_writer.newline()
else:
writer = self.get_subwriter()
return writer
def function(self, name, return_type, args, static = False):
self.has_error_check = False
self.function_helper_writer = self.get_subwriter()
if static:
self.write("static ")
self.write(return_type)
self.write(" %s(%s)"% (name, args)).newline()
self.begin_block()
self.function_variables_writer = self.get_subwriter()
self.function_variables = {}
return self.function_variables_writer
def macro(self, name, args, define):
self.write("#define %s(%s) %s" % (name, args, define)).newline()
def ifdef(self, name):
indentation = self.indentation
self.indentation = 0;
self.write("#ifdef %s" % (name)).newline()
self.indentation = indentation
def ifdef_else(self, name):
indentation = self.indentation
self.indentation = 0;
self.write("#else /* %s */" % (name)).newline()
self.indentation = indentation
def endif(self, name):
indentation = self.indentation
self.indentation = 0;
self.write("#endif /* %s */" % (name)).newline()
self.indentation = indentation
def add_function_variable(self, ctype, name):
if name in self.function_variables:
assert(self.function_variables[name] == ctype)
else:
self.function_variables[name] = ctype
self.function_variables_writer.variable_def(ctype, name)
def pop_index(self):
index = self.indexes[self.current_index]
self.current_index = self.current_index + 1
self.add_function_variable(self.index_type, index)
return index
def push_index(self):
assert self.current_index > 0
self.current_index = self.current_index - 1
class Index:
def __init__(self, writer, val):
self.writer = writer
self.val = val
def __enter__(self):
return self.val
def __exit__(self, exc_type, exc_value, traceback):
self.writer.push_index()
def index(self, no_block = False):
if no_block:
return self.no_block(None)
val = self.pop_index()
return self.Index(self, val)