blob: 33c7e25c91e708f09c1aa03eecd30e2f1c4ae302 [file] [log] [blame]
Patrick Williamsf79f3582016-10-09 16:12:26 -05001from .namedelement import NamedElement
Patrick Williams52dd41e2016-10-14 18:41:27 -05002from .renderer import Renderer
Patrick Williamsd0cd9662016-11-14 21:55:07 -06003import yaml
Patrick Williamsf79f3582016-10-09 16:12:26 -05004
Patrick Williamsf5c3cde2016-10-21 11:49:01 -05005
Patrick Williams52dd41e2016-10-14 18:41:27 -05006class Property(NamedElement, Renderer):
Patrick Williamsf79f3582016-10-09 16:12:26 -05007 def __init__(self, **kwargs):
8 self.typeName = kwargs.pop('type', None)
Patrick Williamsd0cd9662016-11-14 21:55:07 -06009 self.cppTypeName = self.parse_cpp_type(self.typeName)
Patrick Williamsf79f3582016-10-09 16:12:26 -050010 self.defaultValue = kwargs.pop('default', None)
Adriana Kobylak69425eb2018-08-17 13:55:19 -050011 self.flags = kwargs.pop('flags', [])
Adriana Kobylak75a2e252018-06-06 10:49:24 -050012 self.errors = kwargs.pop('errors', [])
Patrick Williamsf79f3582016-10-09 16:12:26 -050013
14 super(Property, self).__init__(**kwargs)
Patrick Williams62c3f272016-10-09 16:21:34 -050015
Patrick Williams2adcefa2016-11-16 08:23:12 -060016 def is_enum(self):
17 if not self.cppTypeName:
18 return False
19 if self.cppTypeName.startswith("enum<"):
20 return True
21 return False
22
Patrick Williams0aa0dde2016-11-16 08:14:33 -060023 """ Return a conversion of the cppTypeName valid as a function parameter.
24 Currently only 'enum' requires conversion.
25 """
26 def cppTypeParam(self, interface, server=True):
Patrick Williams2adcefa2016-11-16 08:23:12 -060027 if self.is_enum():
Patrick Williams0aa0dde2016-11-16 08:14:33 -060028 # strip off 'enum<' and '>'
29 r = self.cppTypeName.split('>')[0].split('<')[1]
30
31 # self. means local type.
32 if r.startswith("self."):
33 return r.split('self.')[1]
34
35 r = r.split('.')
36 r.insert(-2, "server" if server else "client")
37 r = "::".join(r)
38 return r
39 return self.cppTypeName
40
41 """ Return a conversion of the cppTypeName valid as it is read out of a
42 message. Currently only 'enum' requires conversion.
43 """
44 def cppTypeMessage(self, interface):
Patrick Williams2adcefa2016-11-16 08:23:12 -060045 if self.is_enum():
Patrick Williams0aa0dde2016-11-16 08:14:33 -060046 return "std::string"
47 return self.cppTypeName
48
Patrick Williams0ad505c2016-11-16 16:17:02 -060049 def enum_namespace(self, interface):
50 if not self.is_enum():
51 return ""
52 l = self.cppTypeParam(interface).split("::")[0:-1]
53 if len(l) != 0:
54 return "::".join(l) + "::"
55 return ""
56
57 def enum_name(self, interface):
58 if not self.is_enum():
59 return ""
60 return self.cppTypeParam(interface).split("::")[-1]
61
Patrick Williamsd0cd9662016-11-14 21:55:07 -060062 def parse_cpp_type(self, typeName):
63 if not typeName:
64 return None
65
66 """ typeNames are _almost_ valid YAML. Insert a , before each [
67 and then wrap it in a [ ] and it becomes valid YAML. (assuming
68 the user gave us a valid typename)
69 """
Christian Andersene4163982016-12-09 11:24:03 +010070 typeArray = yaml.safe_load("[" + ",[".join(typeName.split("[")) + "]")
71 typeTuple = self.__preprocess_yaml_type_array(typeArray).pop(0)
72 return self.__parse_cpp_type__(typeTuple)
73
74 """ Take a list of dbus types from YAML and convert it to a recursive data
75 structure. Each entry of the original list gets converted into a tuple
76 consisting of the type name and a list with the params for this type,
77 e.g.
78 ['dict', ['string', 'dict', ['string', 'int64']]]
79 is converted to
Patrick Williams3f67eed2016-12-12 12:22:03 -060080 [('dict', [('string', []), ('dict', [('string', []),
81 ('int64', [])]]]
Christian Andersene4163982016-12-09 11:24:03 +010082 """
83 def __preprocess_yaml_type_array(self, typeArray):
84 result = []
85
86 for i in range(len(typeArray)):
87 # Ignore lists because we merge them with the previous element
88 if type(typeArray[i]) is list:
89 continue
90
Patrick Williams3f67eed2016-12-12 12:22:03 -060091 # If there is a next element and it is a list, merge it with the
92 # current element.
Christian Andersene4163982016-12-09 11:24:03 +010093 if i < len(typeArray)-1 and type(typeArray[i+1]) is list:
Patrick Williams3f67eed2016-12-12 12:22:03 -060094 result.append(
95 (typeArray[i],
96 self.__preprocess_yaml_type_array(typeArray[i+1])))
Christian Andersene4163982016-12-09 11:24:03 +010097 else:
98 result.append((typeArray[i], []))
99
100 return result
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600101
102 """ Take a list of dbus types and perform validity checking, such as:
103 [ variant [ dict [ int32, int32 ], double ] ]
104 This function then converts the type-list into a C++ type string.
105 """
Christian Andersene4163982016-12-09 11:24:03 +0100106 def __parse_cpp_type__(self, typeTuple):
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600107 propertyMap = {
108 'byte': {'cppName': 'uint8_t', 'params': 0},
109 'boolean': {'cppName': 'bool', 'params': 0},
110 'int16': {'cppName': 'int16_t', 'params': 0},
111 'uint16': {'cppName': 'uint16_t', 'params': 0},
112 'int32': {'cppName': 'int32_t', 'params': 0},
113 'uint32': {'cppName': 'uint32_t', 'params': 0},
114 'int64': {'cppName': 'int64_t', 'params': 0},
115 'uint64': {'cppName': 'uint64_t', 'params': 0},
116 'double': {'cppName': 'double', 'params': 0},
117 'string': {'cppName': 'std::string', 'params': 0},
Patrick Williams8a30a8f2017-01-06 16:29:05 -0600118 'path': {'cppName': 'sdbusplus::message::object_path',
119 'params': 0},
120 'signature': {'cppName': 'sdbusplus::message::signature',
121 'params': 0},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600122 'array': {'cppName': 'std::vector', 'params': 1},
123 'struct': {'cppName': 'std::tuple', 'params': -1},
Patrick Williamsabf5f782016-12-12 12:13:40 -0600124 'variant': {'cppName': 'sdbusplus::message::variant',
125 'params': -1},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600126 'dict': {'cppName': 'std::map', 'params': 2},
127 'enum': {'cppName': 'enum', 'params': 1, 'noparse': True}}
128
Christian Andersene4163982016-12-09 11:24:03 +0100129 if len(typeTuple) != 2:
130 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
131
132 first = typeTuple[0]
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600133 entry = propertyMap[first]
134
135 result = entry['cppName']
136
137 # Handle 0-entry parameter lists.
138 if (entry['params'] == 0):
Christian Andersene4163982016-12-09 11:24:03 +0100139 if (len(typeTuple[1]) != 0):
140 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600141 else:
142 return result
143
Christian Andersene4163982016-12-09 11:24:03 +0100144 # Get the parameter list
145 rest = typeTuple[1]
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600146
147 # Confirm parameter count matches.
148 if (entry['params'] != -1) and (entry['params'] != len(rest)):
149 raise RuntimeError("Invalid entry count for %s : %s" %
150 (first, rest))
151
152 # Parse each parameter entry, if appropriate, and create C++ template
153 # syntax.
154 result += '<'
155 if entry.get('noparse'):
Christian Andersen768f1282016-12-09 15:48:50 +0100156 # Do not parse the parameter list, just use the first element
157 # of each tuple and ignore possible parameters
158 result += ", ".join([e[0] for e in rest])
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600159 else:
Christian Andersene4163982016-12-09 11:24:03 +0100160 result += ", ".join(map(lambda e: self.__parse_cpp_type__(e),
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600161 rest))
162 result += '>'
163
164 return result
165
Patrick Williams62c3f272016-10-09 16:21:34 -0500166 def markdown(self, loader):
Patrick Williamse70f0e82016-10-14 22:24:17 -0500167 return self.render(loader, "property.mako.md", property=self,
Patrick Williamsf5c3cde2016-10-21 11:49:01 -0500168 post=str.strip)
Adriana Kobylakee6ac692018-06-06 09:36:51 -0500169
170 def cpp_prototype(self, loader, interface, ptype):
171 return self.render(loader, "property.mako.prototype.hpp", property=self,
172 interface=interface, ptype=ptype, post=str.rstrip)