blob: 34a71c1ab6124c6a4d6ef436913211a25acad37e [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):
Patrick Williams18b29ba2020-01-24 16:09:06 -06008 self.enum = False
Patrick Williamsf79f3582016-10-09 16:12:26 -05009 self.typeName = kwargs.pop('type', None)
Patrick Williamsd0cd9662016-11-14 21:55:07 -060010 self.cppTypeName = self.parse_cpp_type(self.typeName)
Patrick Williamsf79f3582016-10-09 16:12:26 -050011 self.defaultValue = kwargs.pop('default', None)
Adriana Kobylak69425eb2018-08-17 13:55:19 -050012 self.flags = kwargs.pop('flags', [])
Adriana Kobylak75a2e252018-06-06 10:49:24 -050013 self.errors = kwargs.pop('errors', [])
Patrick Williamsf79f3582016-10-09 16:12:26 -050014
Matthew Barthf0dd3b52019-02-07 11:08:15 -060015 if (self.defaultValue is not None):
16 if (isinstance(self.defaultValue, bool)):
17 # Convert True/False to 'true'/'false'
18 # because it will be rendered as C++ code
19 self.defaultValue = 'true' if self.defaultValue else 'false'
20 elif(isinstance(self.defaultValue, str) and
21 self.typeName.lower() == "string"):
22 # Wrap string type default values with double-quotes
23 self.defaultValue = "\"" + self.defaultValue + "\""
Lei YU4d741892019-01-14 09:59:10 +080024
Patrick Williamsf79f3582016-10-09 16:12:26 -050025 super(Property, self).__init__(**kwargs)
Patrick Williams62c3f272016-10-09 16:21:34 -050026
Patrick Williams2adcefa2016-11-16 08:23:12 -060027 def is_enum(self):
Patrick Williams18b29ba2020-01-24 16:09:06 -060028 return self.enum
Patrick Williams2adcefa2016-11-16 08:23:12 -060029
Patrick Williams0aa0dde2016-11-16 08:14:33 -060030 """ Return a conversion of the cppTypeName valid as a function parameter.
31 Currently only 'enum' requires conversion.
32 """
Patrick Williamsf7e21592020-01-24 15:43:08 -060033 def cppTypeParam(self, interface, full=False, server=True):
Patrick Williamsa163b172020-01-24 16:34:02 -060034 r = self.cppTypeName
Patrick Williams0aa0dde2016-11-16 08:14:33 -060035
Patrick Williamsa163b172020-01-24 16:34:02 -060036 if self.is_enum():
Patrick Williamsf7e21592020-01-24 15:43:08 -060037 if "." not in r and full:
38 r = interface + "." + r
Patrick Williamsa163b172020-01-24 16:34:02 -060039 if "." in r:
40 r = r.split('.')
41 r.insert(-2, "server" if server else "client")
42 r = "::".join(r)
43
44 return r
Patrick Williams0aa0dde2016-11-16 08:14:33 -060045
Patrick Williams0ad505c2016-11-16 16:17:02 -060046 def enum_namespace(self, interface):
47 if not self.is_enum():
48 return ""
49 l = self.cppTypeParam(interface).split("::")[0:-1]
50 if len(l) != 0:
51 return "::".join(l) + "::"
52 return ""
53
54 def enum_name(self, interface):
55 if not self.is_enum():
56 return ""
57 return self.cppTypeParam(interface).split("::")[-1]
58
Patrick Williamsd0cd9662016-11-14 21:55:07 -060059 def parse_cpp_type(self, typeName):
60 if not typeName:
61 return None
62
63 """ typeNames are _almost_ valid YAML. Insert a , before each [
64 and then wrap it in a [ ] and it becomes valid YAML. (assuming
65 the user gave us a valid typename)
66 """
Christian Andersene4163982016-12-09 11:24:03 +010067 typeArray = yaml.safe_load("[" + ",[".join(typeName.split("[")) + "]")
68 typeTuple = self.__preprocess_yaml_type_array(typeArray).pop(0)
Patrick Williams18b29ba2020-01-24 16:09:06 -060069 return self.__parse_cpp_type__(typeTuple, top_type=True)
Christian Andersene4163982016-12-09 11:24:03 +010070
71 """ Take a list of dbus types from YAML and convert it to a recursive data
72 structure. Each entry of the original list gets converted into a tuple
73 consisting of the type name and a list with the params for this type,
74 e.g.
75 ['dict', ['string', 'dict', ['string', 'int64']]]
76 is converted to
Patrick Williams3f67eed2016-12-12 12:22:03 -060077 [('dict', [('string', []), ('dict', [('string', []),
78 ('int64', [])]]]
Christian Andersene4163982016-12-09 11:24:03 +010079 """
80 def __preprocess_yaml_type_array(self, typeArray):
81 result = []
82
83 for i in range(len(typeArray)):
84 # Ignore lists because we merge them with the previous element
85 if type(typeArray[i]) is list:
86 continue
87
Patrick Williams3f67eed2016-12-12 12:22:03 -060088 # If there is a next element and it is a list, merge it with the
89 # current element.
Christian Andersene4163982016-12-09 11:24:03 +010090 if i < len(typeArray)-1 and type(typeArray[i+1]) is list:
Patrick Williams3f67eed2016-12-12 12:22:03 -060091 result.append(
92 (typeArray[i],
93 self.__preprocess_yaml_type_array(typeArray[i+1])))
Christian Andersene4163982016-12-09 11:24:03 +010094 else:
95 result.append((typeArray[i], []))
96
97 return result
Patrick Williamsd0cd9662016-11-14 21:55:07 -060098
99 """ Take a list of dbus types and perform validity checking, such as:
100 [ variant [ dict [ int32, int32 ], double ] ]
101 This function then converts the type-list into a C++ type string.
102 """
Patrick Williams18b29ba2020-01-24 16:09:06 -0600103 def __parse_cpp_type__(self, typeTuple, top_type=False):
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600104 propertyMap = {
105 'byte': {'cppName': 'uint8_t', 'params': 0},
106 'boolean': {'cppName': 'bool', 'params': 0},
107 'int16': {'cppName': 'int16_t', 'params': 0},
108 'uint16': {'cppName': 'uint16_t', 'params': 0},
109 'int32': {'cppName': 'int32_t', 'params': 0},
110 'uint32': {'cppName': 'uint32_t', 'params': 0},
111 'int64': {'cppName': 'int64_t', 'params': 0},
112 'uint64': {'cppName': 'uint64_t', 'params': 0},
113 'double': {'cppName': 'double', 'params': 0},
Waqar Hameed596a2232018-10-05 15:42:20 +0200114 'unixfd': {'cppName': 'sdbusplus::message::unix_fd', 'params': 0},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600115 'string': {'cppName': 'std::string', 'params': 0},
Patrick Williams8a30a8f2017-01-06 16:29:05 -0600116 'path': {'cppName': 'sdbusplus::message::object_path',
117 'params': 0},
118 'signature': {'cppName': 'sdbusplus::message::signature',
119 'params': 0},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600120 'array': {'cppName': 'std::vector', 'params': 1},
121 'struct': {'cppName': 'std::tuple', 'params': -1},
William A. Kennington III4274c112018-11-26 09:50:13 -0800122 'variant': {'cppName': 'std::variant', 'params': -1},
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600123 'dict': {'cppName': 'std::map', 'params': 2},
Patrick Williams18b29ba2020-01-24 16:09:06 -0600124 'enum': {'cppName': 'enum', 'params': 1}}
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600125
Christian Andersene4163982016-12-09 11:24:03 +0100126 if len(typeTuple) != 2:
127 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
128
129 first = typeTuple[0]
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600130 entry = propertyMap[first]
131
132 result = entry['cppName']
133
134 # Handle 0-entry parameter lists.
135 if (entry['params'] == 0):
Christian Andersene4163982016-12-09 11:24:03 +0100136 if (len(typeTuple[1]) != 0):
137 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600138 else:
139 return result
140
Christian Andersene4163982016-12-09 11:24:03 +0100141 # Get the parameter list
142 rest = typeTuple[1]
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600143
144 # Confirm parameter count matches.
145 if (entry['params'] != -1) and (entry['params'] != len(rest)):
146 raise RuntimeError("Invalid entry count for %s : %s" %
147 (first, rest))
148
Patrick Williams18b29ba2020-01-24 16:09:06 -0600149 # Switch enum for proper type.
150 if result == 'enum':
151 if top_type:
152 self.enum = True
Patrick Williamsa163b172020-01-24 16:34:02 -0600153 result = rest[0][0]
154
155 # self. means local type.
156 if result.startswith("self."):
157 return result[5:] # "self." is 5 characters
158 return result
Patrick Williams18b29ba2020-01-24 16:09:06 -0600159
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600160 # Parse each parameter entry, if appropriate, and create C++ template
161 # syntax.
162 result += '<'
Patrick Williams18b29ba2020-01-24 16:09:06 -0600163 result += ", ".join(map(lambda e: self.__parse_cpp_type__(e),
164 rest))
Patrick Williamsd0cd9662016-11-14 21:55:07 -0600165 result += '>'
166
167 return result
168
Patrick Williams62c3f272016-10-09 16:21:34 -0500169 def markdown(self, loader):
Patrick Williamse70f0e82016-10-14 22:24:17 -0500170 return self.render(loader, "property.mako.md", property=self,
Patrick Williamsf5c3cde2016-10-21 11:49:01 -0500171 post=str.strip)
Adriana Kobylakee6ac692018-06-06 09:36:51 -0500172
173 def cpp_prototype(self, loader, interface, ptype):
174 return self.render(loader, "property.mako.prototype.hpp", property=self,
175 interface=interface, ptype=ptype, post=str.rstrip)