diff options
Diffstat (limited to 'tools/InterfaceGenerator/generator/parsers/RPCBase.py')
-rwxr-xr-x | tools/InterfaceGenerator/generator/parsers/RPCBase.py | 913 |
1 files changed, 0 insertions, 913 deletions
diff --git a/tools/InterfaceGenerator/generator/parsers/RPCBase.py b/tools/InterfaceGenerator/generator/parsers/RPCBase.py deleted file mode 100755 index ac5bb4c858..0000000000 --- a/tools/InterfaceGenerator/generator/parsers/RPCBase.py +++ /dev/null @@ -1,913 +0,0 @@ -"""RPC XML base parser. - -Contains base parser for SDLRPC v1/v2 and JSON RPC XML format. - -""" - -import collections -import xml.etree.ElementTree -import re -from generator import Model - - -class ParseError(Exception): - - """Parse error. - - This exception is raised when XML contains errors and can't be parsed. - - """ - - pass - - -class Parser(object): - - """RPC XML Parser base. - - This class must not be used directly. One of its subclasses must be used - instead. - - """ - - def __init__(self): - """Constructor.""" - self._types = {} - self._enums = collections.OrderedDict() - self._structs = collections.OrderedDict() - self._functions = collections.OrderedDict() - self._params = {} - - def parse(self, filename): - """Parse XML. - - Returns an instance of generator.Model.Interface containing parsed - interface or raises ParseError if input XML contains errors - and can't be parsed. - - Keyword arguments: - filename -- name of input XML file. - - """ - - tree = xml.etree.ElementTree.parse(filename) - root = tree.getroot() - - self._enums = self._initialize_enums() - self._structs = collections.OrderedDict() - self._functions = collections.OrderedDict() - self._params = {} - - self._types = dict(self._enums.items()) - - self._parse_root(root) - - return Model.Interface(enums=self._enums, structs=self._structs, - functions=self._functions, params=self._params) - - def _initialize_enums(self): - """Initialize enums. - - The default implementation returns an OrderedDict with two empty - enums: "FunctionID" and "messageType". Required for formats where - these enums must be generated automatically according to the declared - in the XML functions. - - These enums are filled during the parsing of the functions. - - """ - return collections.OrderedDict( - [("FunctionID", Model.Enum(name="FunctionID")), - ("messageType", Model.Enum(name="messageType"))]) - - def _check_enum_name(self, enum): - """Check enum name. - - This method is called to check whether the newly parsed enum's name - conflicts with some predefined enum. - - This implementation raises an error if enum name is one of the - predefined enums "FunctionID" or "messageType" which must not be - declared explicitly in the XML. - - """ - if enum.name in ["FunctionID", "messageType"]: - raise ParseError( - "Enum '" + enum.name + - "' is generated automatically in SDLRPCV1 and" - " must not be declared in xml file") - - def _check_function_param_name(self, function_param_name): - """Check function param name. - - This method is called to check whether the newly parsed function - parameter name conflicts with some predefined name. - - This implementation doesn't check anything because there is no - predefined names in base RPC XML. - """ - - pass - - def _parse_root(self, root): - """Parse root XML element. - - Default implementation parses root as interface element without a - prefix. - - Keyword arguments: - root -- root element. - - """ - - self._parse_interface(root, "") - - def _parse_interface(self, interface, prefix): - """Parse interface element. - - Keyword arguments: - interface -- interface element. - prefix -- string prefix for all types of the interface. - - """ - if interface.tag != "interface": - raise ParseError("Invalid interface tag: " + interface.tag) - - params, subelements, attrib = self._parse_base_item(interface, "") - - for param in ["description", "design_description", "todos"]: - if 0 != len(params[param]): - attrib[param] = "\n".join(params[param]) - - if 0 != len(params["issues"]): - attrib["issues"] = "\n".join(i.value for i in params["issues"]) - - self._params = dict( - self._params.items() + - [(prefix + p[0], p[1]) for p in attrib.items()]) - - for element in subelements: - if element.tag == "enum": - enum = self._parse_enum(element, prefix) - self._check_enum_name(enum) - self._add_item(self._enums, enum) - self._add_type(enum) - elif element.tag == "struct": - struct = self._parse_struct(element, prefix) - self._add_item(self._structs, struct) - self._add_type(struct) - elif element.tag == "function": - function = self._parse_function(element, prefix) - self._add_item(self._functions, function, - (function.function_id, function.message_type)) - else: - raise ParseError("Unexpected element: " + element.tag) - - @staticmethod - def _add_item(items, item, key=None): - """Add new item in the items dictionary with given key. - - Performs additional check for presence in the dictionary and throws - ParseError exception if key already exist. - - """ - if key is None: - key = item.name - - if key in items: - raise ParseError(type(item).__name__ + " '" + str(key) + - "' is declared more than once") - items[key] = item - - def _add_type(self, _type): - """Add new type in the internal types dictionary. - - Performs additional check for presence type with same name in the - dictionary and throws ParseError exception if key already exist. - - """ - if _type.name in self._types: - raise ParseError("Type '" + _type.name + - "' is declared as both struct and enum") - - self._types[_type.name] = _type - - def _parse_enum(self, element, prefix): - """Parse element as enumeration. - - Returns an instance of generator.Model.Enum - - """ - params, subelements, attributes = \ - self._parse_base_item(element, prefix) - - internal_scope = None - scope = None - since = None - until = None - deprecated = None - removed = None - result = None - for attribute in attributes: - if attribute == "internal_scope": - internal_scope = attributes[attribute] - elif attribute == "scope": - scope = attributes[attribute] - elif attribute == "since": - result = self._parse_version(attributes[attribute]) - since = result - elif attribute == "until": - result = self._parse_version(attributes[attribute]) - until = result - elif attribute == "deprecated": - deprecated = attributes[attribute] - elif attribute == "removed": - removed = attributes[attribute] - else: - raise ParseError("Unexpected attribute '" + attribute + - "' in enum '" + params["name"] + "'") - params["internal_scope"] = internal_scope - params["scope"] = scope - params["since"] = since - params["until"] = until - params["deprecated"] = deprecated - params["removed"] = removed - - elements = collections.OrderedDict() - for subelement in subelements: - if subelement.tag == "element": - self._add_item(elements, self._parse_enum_element(subelement)) - else: - raise ParseError("Unexpected element '" + subelement.tag + - "' in enum '" + params["name"] + "'") - params["elements"] = elements - - # Magic usage is correct - # pylint: disable=W0142 - return Model.Enum(**params) - - def _parse_struct(self, element, prefix): - """Parse element as structure. - - Returns an instance of generator.Model.Struct - - """ - params, subelements, attrib = self._parse_base_item(element, prefix) - - scope = None - since = None - until = None - deprecated = None - removed = None - result = None - for attribute in attrib: - if attribute == "scope": - scope = attrib[attribute] - elif attribute == "since": - result = self._parse_version(attrib[attribute]) - since = result - elif attribute == "until": - result = self._parse_version(attrib[attribute]) - until = result - elif attribute == "deprecated": - deprecated = attrib[attribute] - elif attribute == "removed": - removed = attrib[attribute] - else: - raise ParseError("Unexpected attribute '" + attribute + - "' in struct '" + params["name"] + "'") - params["scope"] = scope - params["since"] = since - params["until"] = until - params["deprecated"] = deprecated - params["removed"] = removed - - members = collections.OrderedDict() - for subelement in subelements: - if subelement.tag == "param": - self._add_item(members, self._parse_param(subelement, prefix)) - else: - raise ParseError("Unexpected subelement '" + subelement.name + - "' in struct '" + params["name"] + "'") - params["members"] = members - - # Magic usage is correct - # pylint: disable=W0142 - return Model.Struct(**params) - - def _parse_function(self, element, prefix): - """Parse element as function. - - Returns an instance of generator.Model.Function - - """ - params, subelements, attributes = \ - self._parse_base_item(element, prefix) - - function_id, message_type = self._parse_function_id_type( - params["name"], - attributes) - - scope = None - since = None - until = None - deprecated = None - removed = None - result = None - for attribute in attributes: - if attribute == "scope": - scope = attributes[attribute] - elif attribute == "since": - result = self._parse_version(attributes[attribute]) - since = result - elif attribute == "until": - result = self._parse_version(attributes[attribute]) - until = result - elif attribute == "deprecated": - deprecated = attributes[attribute] - elif attribute == "removed": - removed = attributes[attribute] - - params["function_id"] = function_id - params["message_type"] = message_type - params["scope"] = scope - params["since"] = since - params["until"] = until - params["deprecated"] = deprecated - params["removed"] = removed - - function_params = collections.OrderedDict() - for subelement in subelements: - if subelement.tag == "param": - function_param = self._parse_function_param(subelement, - prefix) - self._check_function_param_name(function_param.name) - if function_param.name in function_params: - raise ParseError("Parameter '" + function_param.name + - "' is specified more than once" + - " for function '" + params["name"] + "'") - function_params[function_param.name] = function_param - else: - raise ParseError("Unexpected subelement '" + subelement.tag + - "' in function '" + params["name"] + "'") - params["params"] = function_params - - # Magic usage is correct - # pylint: disable=W0142 - return Model.Function(**params) - - def _parse_function_id_type(self, function_name, attrib): - """Parse function id and message type according to XML format. - - This implementation takes function name as function id and extracts - attribute "messagetype" as message type and searches them in enums - "FunctionID" and "messageType" adding the missing elements if - necessary. - - Returns function id and message type as an instances of EnumElement. - - """ - if "messagetype" not in attrib: - raise ParseError("No messagetype specified for function '" + - function_name + "'") - - function_id = self._provide_enum_element_for_function( - "FunctionID", - function_name) - - message_type = self._provide_enum_element_for_function( - "messageType", - self._extract_attrib(attrib, "messagetype")) - - return function_id, message_type - - def _provide_enum_element_for_function(self, enum_name, element_name): - """Provide enum element for functions. - - Search an element in an enum and add it if it is missing. - - Returns EnumElement. - - """ - if enum_name not in self._types: - raise ParseError("Enum '" + enum_name + - "' is not initialized") - - enum = self._types[enum_name] - - if not isinstance(enum, Model.Enum): - raise ParseError("'" + enum_name + "' is not an enum") - - if element_name not in enum.elements: - enum.elements[element_name] = Model.EnumElement(name=element_name) - - return enum.elements[element_name] - - def _parse_base_item(self, element, prefix): - """Parse element as base item. - - Returns an params, sub-elements and attributes of the element - - """ - params = {} - - description = [] - design_description = [] - issues = [] - todos = [] - subelements = [] - history = None - warnings = [] - - if "name" not in element.attrib: - raise ParseError("Name is not specified for " + element.tag) - - params["name"] = prefix + element.attrib["name"] - attrib = dict(element.attrib.items()) - del attrib["name"] - - params["platform"] = self._extract_attrib(attrib, "platform") - - for subelement in element: - if subelement.tag == "description": - description.append(self._parse_simple_element(subelement)) - elif subelement.tag == "designdescription": - design_description.append( - self._parse_simple_element(subelement)) - elif subelement.tag == "todo": - todos.append(self._parse_simple_element(subelement)) - elif subelement.tag == "issue": - issues.append(self._parse_issue(subelement)) - elif subelement.tag == "history": - if history is not None: - raise ParseError("Elements can only have one history tag: " + element.tag) - history = self._parse_history(subelement, prefix, element) - elif subelement.tag == "warning": - warnings.append(self._parse_simple_element(subelement)) - else: - subelements.append(subelement) - - params["description"] = description - params["design_description"] = design_description - params["issues"] = issues - params["todos"] = todos - params["history"] = history - - return params, subelements, attrib - - @staticmethod - def _parse_simple_element(element): - """Parse element as simple element and returns it's text. - - Element is simple when it contains no subelements and attributes. - - Returns element text if present or empty string if not - - """ - if len(element) != 0: - raise ParseError("Unexpected subelements in '" + - element.tag + "'") - if len(element.attrib) != 0: - raise ParseError("Unexpected attributes in '" + - element.tag + "'") - return element.text if element.text is not None else "" - - @staticmethod - def _parse_issue(element): - """Parse element as issue. - - Issue must not contain subelements and attributes. - - Returns an instance of generator.Model.Issue - - """ - if len(element) != 0: - raise ParseError("Unexpected subelements in issue") - if "creator" not in element.attrib: - raise ParseError("No creator in issue") - if len(element.attrib) != 1: - raise ParseError("Unexpected attributes in issue") - - return Model.Issue( - creator=element.attrib["creator"], - value=element.text if element.text is not None else "") - - def _parse_enum_element(self, element): - """Parse element as element of enumeration. - - Returns an instance of generator.Model.EnumElement - - """ - params, subelements, attributes = self._parse_base_item(element, "") - - if len(subelements) != 0: - raise ParseError("Unexpected subelements in enum element") - - self._ignore_attribute(attributes, "hexvalue") - self._ignore_attribute(attributes, "scope") - self._ignore_attribute(attributes, "rootscreen") - - internal_name = None - value = None - since = None - until = None - deprecated = None - removed = None - result = None - for attribute in attributes: - if attribute == "internal_name": - internal_name = attributes[attribute] - elif attribute == "value": - try: - value = int(attributes[attribute]) - except: - raise ParseError("Invalid value for enum element: '" + - attributes[attribute] + "'") - elif attribute == "since": - result = self._parse_version(attributes[attribute]) - since = result - elif attribute == "until": - result = self._parse_version(attributes[attribute]) - until = result - elif attribute == "deprecated": - deprecated = attributes[attribute] - elif attribute == "removed": - removed = attributes[attribute] - params["internal_name"] = internal_name - params["value"] = value - params["since"] = since - params["until"] = until - params["deprecated"] = deprecated - params["removed"] = removed - # Magic usage is correct - # pylint: disable=W0142 - return Model.EnumElement(**params) - - def _parse_param(self, element, prefix): - """Parse element as structure parameter. - - Returns an instance of generator.Model.Param - - """ - params, subelements, attrib = \ - self._parse_param_base_item(element, prefix) - - if len(attrib) != 0: - raise ParseError("""Unknown attribute(s) {0} in param {1} - """.format(attrib, params["name"])) - - if len(subelements) != 0: - raise ParseError("Unknown subelements in param '" + - params["name"] + "'") - - # Magic usage is correct - # pylint: disable=W0142 - return Model.Param(**params) - - def _parse_function_param(self, element, prefix): - """Parse element as function parameter. - - Returns an instance of generator.Model.FunctionParam - - """ - params, subelements, attrib = \ - self._parse_param_base_item(element, prefix) - - default_value = None - default_value_string = self._extract_attrib(attrib, "defvalue") - if default_value_string is not None: - param_type = params["param_type"] - if type(param_type) is Model.Boolean: - default_value = \ - self._get_bool_from_string(default_value_string) - elif type(param_type) is Model.Integer: - try: - default_value = int(default_value_string) - except: - raise ParseError("Invalid value for integer: '" + - default_value_string + "'") - elif type(param_type) is Model.Double: - try: - default_value = float(default_value_string) - except: - raise ParseError("Invalid value for float: '" + - default_value_string + "'") - elif type(param_type) is Model.String: - default_value = default_value_string - elif type(param_type) is Model.Enum or \ - type(param_type) is Model.EnumSubset: - if type(param_type) is Model.EnumSubset: - allowed_elements = param_type.allowed_elements - else: - allowed_elements = param_type.elements - if default_value_string not in allowed_elements: - raise ParseError("Default value '" + default_value_string + - "' for parameter '" + params["name"] + - "' is not a member of " + - type(param_type).__name__ + - "'" + params["name"] + "'") - default_value = allowed_elements[default_value_string] - else: - raise ParseError("Default value specified for " + - type(param_type).__name__) - params["default_value"] = default_value - - if len(attrib) != 0: - raise ParseError("Unexpected attributes in parameter '" + - params["name"] + "'") - - if len(subelements) != 0: - raise ParseError("Unexpected subelements in parameter '" + - params["name"] + "'") - - # Magic usage is correct - # pylint: disable=W0142 - return Model.FunctionParam(**params) - - def _parse_param_base_item(self, element, prefix): - """Parse base param items. - - Returns params, other subelements and attributes. - - """ - params, subelements, attrib = self._parse_base_item(element, "") - - since_version = self._extract_attrib(attrib, "since") - if since_version is not None: - result = self._parse_version(since_version) - params["since"] = result - - until_version = self._extract_attrib(attrib, "until") - if until_version is not None: - result = self._parse_version(until_version) - params["until"] = result - - deprecated = self._extract_attrib(attrib, "deprecated") - if deprecated is not None: - params["deprecated"] = deprecated - - removed = self._extract_attrib(attrib, "removed") - if removed is not None: - params["removed"] = removed - - - is_mandatory = self._extract_attrib(attrib, "mandatory") - if is_mandatory is None: - raise ParseError("'mandatory' is not specified for parameter '" + - params["name"] + "'") - - params["is_mandatory"] = self._get_bool_from_string(is_mandatory) - - scope = self._extract_attrib(attrib, "scope") - if scope is not None: - params["scope"] = scope - - default_value = None; - param_type = None - type_name = self._extract_attrib(attrib, "type") - if type_name is None: - raise ParseError("Type is not specified for parameter '" + - params["name"] + "'") - if type_name == "Boolean": - default_value = self._extract_attrib( - attrib, "defvalue") - if default_value != None: - default_value = self._get_bool_from_string(default_value); - param_type = Model.Boolean(default_value=default_value) - elif type_name == "Integer" or \ - type_name == "Float" or \ - type_name == "Double" : - min_value = self._extract_optional_number_attrib( - attrib, "minvalue", int if type_name == "Integer" else float) - max_value = self._extract_optional_number_attrib( - attrib, "maxvalue", int if type_name == "Integer" else float) - default_value = self._extract_optional_number_attrib( - attrib, "defvalue", int if type_name == "Integer" else float) - - param_type = \ - (Model.Integer if type_name == "Integer" else Model.Double)( - min_value=min_value, - max_value=max_value, - default_value=default_value) - elif type_name == "String": - min_length = self._extract_optional_number_attrib( - attrib, "minlength") - # if minlength is not defined default value is 1 - if min_length is None: - min_length = 1 - max_length = self._extract_optional_number_attrib( - attrib, "maxlength") - default_value = self._extract_attrib(attrib, "defvalue") - param_type = Model.String(min_length=min_length, max_length=max_length, default_value=default_value) - else: - if 1 == type_name.count("."): - custom_type_name = type_name.replace(".", "_") - else: - custom_type_name = prefix + type_name - - if custom_type_name in self._types: - param_type = self._types[custom_type_name] - default_value = self._extract_attrib(attrib, "defvalue") - if default_value != None: - if default_value not in param_type.elements: - raise ParseError("Default value '" + default_value + - "' for parameter '" + params["name"] + - "' is not a member of " + - type(param_type).__name__ + - "'" + params["name"] + "'") - default_value = param_type.elements[default_value] - else: - raise ParseError("Unknown type '" + type_name + "'") - - if self._extract_optional_bool_attrib(attrib, "array", False): - min_size = self._extract_optional_number_attrib(attrib, - "minsize") - max_size = self._extract_optional_number_attrib(attrib, - "maxsize") - param_type = Model.Array(element_type=param_type, - min_size=min_size, - max_size=max_size) - - base_type = \ - param_type.element_type if isinstance(param_type, Model.Array) \ - else param_type - - other_subelements = [] - for subelement in subelements: - if subelement.tag == "element": - if type(base_type) is not Model.Enum and \ - type(base_type) is not Model.EnumSubset: - raise ParseError("Elements specified for parameter '" + - params["name"] + "' of type " + - type(base_type).__name__) - if type(base_type) is Model.Enum: - base_type = Model.EnumSubset( - name=params["name"], - enum=base_type, - description=params["description"], - design_description=params["design_description"], - issues=params["issues"], - todos=params["todos"], - allowed_elements={}) - if "name" not in subelement.attrib: - raise ParseError( - "Element name is not specified for parameter '" + - params["name"] + "'") - element_name = subelement.attrib["name"] - if len(subelement.attrib) != 1: - raise ParseError("Unexpected attributes for element '" + - element_name + "' of parameter '" + - params["name"]) - children = subelement.getchildren() - for child in children: - if child.tag == "description": - children.remove(child) - if len(children) != 0: - raise ParseError("Unexpected subelements for element '" + - element_name + "' of parameter '" + - params["name"]) - if element_name in base_type.allowed_elements: - raise ParseError("Element '" + element_name + - "' is specified more than once for" + - " parameter '" + params["name"] + "'") - if element_name not in base_type.enum.elements: - raise ParseError("Element '" + element_name + - "' is not a member of enum '" + - base_type.enum.name + "'") - base_type.allowed_elements[element_name] = \ - base_type.enum.elements[element_name] - else: - other_subelements.append(subelement) - - if isinstance(param_type, Model.Array): - param_type.element_type = base_type - else: - param_type = base_type - - params["param_type"] = param_type - if default_value is not None: - params["default_value"] = default_value - - return params, other_subelements, attrib - - def _extract_optional_bool_attrib(self, attrib, name, default): - """Extract boolean attribute with given name. - - Returns value of the attribute. - - """ - value = self._extract_attrib(attrib, name) - - if value is None: - value = default - else: - value = self._get_bool_from_string(value) - - return value - - def _extract_optional_number_attrib(self, attrib, name, _type=int): - """Extract number attribute with given name. - - Returns value of the attribute. - - """ - value = self._extract_attrib(attrib, name) - - if value is not None: - try: - value = _type(value) - except: - raise ParseError("Invlaid value for " + _type.__name__ + - ": '" + value + "'") - - return value - - @staticmethod - def _extract_attrib(attrib, name): - """Extract attribute with given name. - - Returns value of the attribute. - - """ - value = None - - if name in attrib: - value = attrib[name] - del attrib[name] - - return value - - @staticmethod - def _get_bool_from_string(bool_string): - """Convert string representation of boolean to real bool value. - - Returns converted value. - - """ - value = None - - if bool_string in ['0', 'false']: - value = False - elif bool_string in ['1', 'true']: - value = True - else: - raise ParseError("Invalid value for bool: '" + - bool_string + "'") - - return value - - def _ignore_attribute(self, attrib, name): - """To be called when attribute is meaningless in terms - of code generation but it's presence is not issue. - - Removes this attribute from attribute list. - - """ - if name in attrib: - del attrib[name] - return True - - def _parse_version(self, version): - """ - Validates if a version supplied is in the correct - format of Major.Minor.Patch. If Major.Minor format - is supplied, a patch version of 0 will be added to - the end. - """ - p = re.compile('\d+\\.\d+\\.\d+|\d+\\.\d+') - result = p.match(version) - if result == None or (result.end() != len(version)): - raise RPCBase.ParseError("Incorrect format of version please check MOBILE_API.xml. " - "Need format of major_version.minor_version or major_version.minor_version.patch_version") - - version_array = version.split(".") - if (len(version_array) == 2): - version_array.append("0") - dot_str = "." - return dot_str.join(version_array) - - def _parse_history(self, history, prefix, parent): - if history.tag != "history": - raise ParseError("Invalid history tag: " + interface.tag) - - items = [] - - for subelement in history: - if subelement.tag == "enum" and parent.tag == "enum": - items.append(self._parse_enum(subelement, prefix)) - elif subelement.tag == "element" and parent.tag == "element": - items.append(self._parse_enum_element(subelement)) - elif subelement.tag == "description" and parent.tag == "description": - items.append(self._parse_simple_element(subelement)) - elif subelement.tag == "struct" and parent.tag == "struct": - items.append(self._parse_struct(subelement, prefix)) - elif subelement.tag == "param" and parent.tag == "param": - items.append(self._parse_function_param(subelement, prefix)) - elif subelement.tag == "function" and parent.tag == "function": - items.append(self._parse_function(subelement, prefix)) - else: - raise ParseError("A history tag must be nested within the element it notes the history for. Fix item: '" + - parent.attrib["name"] + "'") - - return items - |