Skip to content

Commit 0ac7cb4

Browse files
committed
Add some validation in parse_specs.py for the struct/range/handle thing
1 parent e6d5b0e commit 0ac7cb4

File tree

3 files changed

+61
-14
lines changed

3 files changed

+61
-14
lines changed

scripts/core/CONTRIB.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,9 @@ they are preventing you from implementing a feature please open an issue and we
214214
will be happy to try and accommodate your use case. Otherwise beware of the
215215
following:
216216

217-
* A function parameter which is a struct type that has any of the following
218-
members in its type definition must not have the ``[range]`` tag:
217+
* A function parameter or struct member which is a struct type that has any of
218+
the following members in its type definition must not have the ``[range]``
219+
tag:
219220

220221
* An object handle with the ``[range]`` tag
221222

scripts/parse_specs.py

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def _get_etor_value(value, prev):
8383
"""
8484
validate documents meet some basic (easily detectable) requirements of code generation
8585
"""
86-
def _validate_doc(f, d, tags, line_num):
86+
def _validate_doc(f, d, tags, line_num, meta):
8787
is_iso = lambda x : re.match(r"[_a-zA-Z][_a-zA-Z0-9]{0,30}", x)
8888

8989
def __validate_ordinal(d):
@@ -265,7 +265,35 @@ def __validate_base(d):
265265
elif type_traits.is_properties(d['name']) and not d.get('base', "").endswith("base_properties_t"):
266266
raise Exception("'base' must be '%s_base_properties_t': %s"%(namespace, d['name']))
267267

268-
def __validate_members(d, tags):
268+
def __validate_struct_range_members(name, members, meta):
269+
def has_handle(members, meta):
270+
for m in members:
271+
if type_traits.is_handle(m):
272+
return True
273+
if type_traits.is_struct(m, meta):
274+
return has_handle(
275+
type_traits.get_struct_members(m['type']), meta)
276+
return False
277+
278+
for m in members:
279+
if param_traits.is_range(m) and type_traits.is_handle(m['type']):
280+
raise Exception(
281+
f"struct range {name} must not contain range of object handles {m['name']}"
282+
)
283+
if type_traits.is_struct(m['type'], meta):
284+
member_members = type_traits.get_struct_members(
285+
m['type'], meta)
286+
# We can't handle a range of structs with handles within a range of structs
287+
if param_traits.is_range(m) and has_handle(
288+
member_members, meta):
289+
raise Exception(
290+
f"struct range {m['name']} is already within struct range {name}, and must not contain an object handle"
291+
)
292+
# We keep passing the original name so we can report it in
293+
# exception messages.
294+
__validate_struct_range_members(name, member_members, meta)
295+
296+
def __validate_members(d, tags, meta):
269297
if 'members' not in d:
270298
raise Exception("'%s' requires the following sequence of mappings: {`members`}"%d['type'])
271299

@@ -295,12 +323,19 @@ def __validate_members(d, tags):
295323
if d['type'] == 'union'and item.get('tag') is None:
296324
raise Exception(prefix + f"union member {item['name']} must include a 'tag' annotation")
297325

326+
if type_traits.is_struct(item['type'],
327+
meta) and param_traits.is_range(item):
328+
member_members = type_traits.get_struct_members(
329+
item['type'], meta)
330+
__validate_struct_range_members(item['name'], member_members,
331+
meta)
332+
298333
ver = __validate_version(item, prefix=prefix, base_version=d_ver)
299334
if ver < max_ver:
300335
raise Exception(prefix+"'version' must be increasing: %s"%item['version'])
301336
max_ver = ver
302337

303-
def __validate_params(d, tags):
338+
def __validate_params(d, tags, meta):
304339
if 'params' not in d:
305340
raise Exception("'function' requires the following sequence of mappings: {`params`}")
306341

@@ -347,6 +382,11 @@ def __validate_params(d, tags):
347382
if not has_queue:
348383
raise Exception(prefix+"bounds must only be used on entry points which take a `hQueue` parameter")
349384

385+
if type_traits.is_struct(item['type'],
386+
meta) and param_traits.is_range(item):
387+
members = type_traits.get_struct_members(item['type'], meta)
388+
__validate_struct_range_members(item['name'], members, meta)
389+
350390
ver = __validate_version(item, prefix=prefix, base_version=d_ver)
351391
if ver < max_ver:
352392
raise Exception(prefix+"'version' must be increasing: %s"%item['version'])
@@ -421,7 +461,7 @@ def __validate_union_tag(d):
421461
__validate_union_tag(d)
422462
__validate_type(d, 'name', tags)
423463
__validate_base(d)
424-
__validate_members(d, tags)
464+
__validate_members(d, tags, meta)
425465
__validate_details(d)
426466
__validate_ordinal(d)
427467
__validate_version(d)
@@ -435,7 +475,7 @@ def __validate_union_tag(d):
435475
else:
436476
__validate_name(d, 'name', tags, case='camel')
437477

438-
__validate_params(d, tags)
478+
__validate_params(d, tags, meta)
439479
__validate_details(d)
440480
__validate_ordinal(d)
441481
__validate_version(d)
@@ -893,7 +933,7 @@ def parse(section, version, tags, meta, ref):
893933

894934
for i, d in enumerate(docs):
895935
d = _preprocess(d)
896-
if not _validate_doc(f, d, tags, line_nums[i]):
936+
if not _validate_doc(f, d, tags, line_nums[i], meta):
897937
continue
898938

899939
d = _filter_version(d, float(version))

scripts/templates/helper.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,14 @@ def get_array_element_type(cls, name):
248248
match = re.match(cls.RE_ARRAY, name)
249249
return match.groups()[0]
250250

251+
@staticmethod
252+
def get_struct_members(type_name, meta):
253+
struct_type = _remove_const_ptr(type_name)
254+
if not struct_type in meta['struct']:
255+
raise Exception(
256+
f"Cannot return members of non-struct type {struct_type}")
257+
return meta['struct'][struct_type]['members']
258+
251259
"""
252260
Extracts traits from a value name
253261
"""
@@ -1305,9 +1313,8 @@ def get_struct_handle_members(namespace,
13051313
'optional': param_traits.is_optional(m)
13061314
})
13071315
elif type_traits.is_struct(m['type'], meta):
1308-
member_struct_type = _remove_const_ptr(m['type'])
1309-
member_struct_members = meta['struct'][member_struct_type][
1310-
'members']
1316+
member_struct_members = type_traits.get_struct_members(
1317+
m['type'], meta)
13111318
if param_traits.is_range(m):
13121319
# If we've hit a range of structs we need to start a new recursion looking
13131320
# for handle members. We do not support range within range, so skip that
@@ -1319,7 +1326,7 @@ def get_struct_handle_members(namespace,
13191326
handle_members.append({
13201327
'parent': parent,
13211328
'name': m['name'],
1322-
'type': subt(namespace, tags, member_struct_type),
1329+
'type': subt(namespace, tags, _remove_const_ptr(m['type'])),
13231330
'range_start': param_traits.range_start(m),
13241331
'range_end': param_traits.range_end(m),
13251332
'handle_members': range_handle_members
@@ -1363,8 +1370,7 @@ def get_object_handle_structs_to_convert(namespace, tags, obj, meta):
13631370

13641371
for item in params:
13651372
if type_traits.is_struct(item['type'], meta):
1366-
members = meta['struct'][_remove_const_ptr(
1367-
item['type'])]['members']
1373+
members = type_traits.get_struct_members(item['type'], meta)
13681374
handle_members = get_struct_handle_members(namespace, tags, meta,
13691375
members)
13701376
if handle_members:

0 commit comments

Comments
 (0)