From 0120cd772a77697b94f7d30abfa9a011b0e6b452 Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Tue, 1 Nov 2022 02:12:26 +0100 Subject: [PATCH 1/3] glib-mkenums: feature use of previous symbols in evaluation Enum symbols can be defined with a value computed from previously defined enum symbols. The current evaluator does not support this and requires a literal integer expression. This commit introduces a C symbol namespace that is filled along code generation and provided as a local namespace for new symbols evaluation, effectively allowing definitions such as: typedef enum { a = 4; b = a + 2; } myenum; to be successfully processed. --- gobject/glib-mkenums.in | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gobject/glib-mkenums.in b/gobject/glib-mkenums.in index 632ba5d51a..7658a82763 100755 --- a/gobject/glib-mkenums.in +++ b/gobject/glib-mkenums.in @@ -143,7 +143,7 @@ enumname_prefix = '' # prefix of $enumname enumindex = 0 # Global enum counter firstenum = 1 # Is this the first enumeration per file? entries = [] # [ name, val ] for each entry -sandbox = None # sandbox for safe evaluation of expressions +c_namespace = {} # C symbols namespace. output = '' # Filename to write result into @@ -489,7 +489,7 @@ if len(fhead) > 0: write_output(prod) def process_file(curfilename): - global entries, flags, seenbitshift, seenprivate, enum_prefix + global entries, flags, seenbitshift, seenprivate, enum_prefix, c_namespace firstenum = True try: @@ -729,7 +729,7 @@ def process_file(curfilename): if num is not None: # use sandboxed evaluation as a reasonable # approximation to C constant folding - inum = eval(num, {}, {}) + inum = eval(num, {}, c_namespace) # make sure it parsed to an integer if not isinstance(inum, int): @@ -738,6 +738,7 @@ def process_file(curfilename): else: num = next_num + c_namespace[name] = num tmp_prod = tmp_prod.replace('\u0040valuenum\u0040', str(num)) next_num = int(num) + 1 -- GitLab From 96fa9752b2137b4de2bb8c64cc9348999b0eb00b Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Tue, 1 Nov 2022 15:46:13 +0100 Subject: [PATCH 2/3] glib-mkenums: evaluate private symbols too This allows them to be referenced in other symbols value computation. In addition, this fixes the automatically assigned value of a public symbol that is preceded by a private one: typedef enum { /*< private >*/ ENUM_VALUE_PRIVATE, /*< public >*/ ENUM_VALUE_PUBLIC, <--- value is 1, not 0. } SomeExampleEnum; --- gobject/glib-mkenums.in | 19 ++++++++++--------- gobject/tests/mkenums.py | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/gobject/glib-mkenums.in b/gobject/glib-mkenums.in index 7658a82763..e0c0b39aff 100755 --- a/gobject/glib-mkenums.in +++ b/gobject/glib-mkenums.in @@ -247,15 +247,12 @@ def parse_entries(file, file_name): if flags is None and value is not None and '<<' in value: seenbitshift = 1 - if seenprivate: - continue - if options is not None: options = parse_trigraph(options) if 'skip' not in options: - entries.append((name, value, options.get('nick'))) + entries.append((name, value, seenprivate, options.get('nick'))) else: - entries.append((name, value)) + entries.append((name, value, seenprivate)) else: m = re.match(r'''\s* /\*< (([^*]|\*(?!/))*) >\s*\*/ @@ -580,7 +577,7 @@ def process_file(curfilename): # Autogenerate a prefix if enum_prefix is None: for entry in entries: - if len(entry) < 3 or entry[2] is None: + if not entry[2] and (len(entry) < 4 or entry[3] is None): name = entry[0] if enum_prefix is not None: enum_prefix = os.path.commonprefix([name, enum_prefix]) @@ -601,10 +598,11 @@ def process_file(curfilename): for e in entries: name = e[0] num = e[1] - if len(e) < 3 or e[2] is None: + private = e[2] + if len(e) < 4 or e[3] is None: nick = re.sub(r'^' + enum_prefix, '', name) nick = nick.replace('_', '-').lower() - e = (name, num, nick) + e = (name, num, private, nick) fixed_entries.append(e) entries = fixed_entries @@ -720,7 +718,7 @@ def process_file(curfilename): next_num = 0 prod = replace_specials(prod) - for name, num, nick in entries: + for name, num, private, nick in entries: tmp_prod = prod if '\u0040valuenum\u0040' in prod: @@ -742,6 +740,9 @@ def process_file(curfilename): tmp_prod = tmp_prod.replace('\u0040valuenum\u0040', str(num)) next_num = int(num) + 1 + if private: + continue + tmp_prod = tmp_prod.replace('\u0040VALUENAME\u0040', name) tmp_prod = tmp_prod.replace('\u0040valuenick\u0040', nick) if flags: diff --git a/gobject/tests/mkenums.py b/gobject/tests/mkenums.py index 09b7702811..51424e29e1 100644 --- a/gobject/tests/mkenums.py +++ b/gobject/tests/mkenums.py @@ -649,7 +649,7 @@ comment: {standard_bottom_comment} "ENUM", "ENUM_VALUE_PUBLIC2", "public2", - "0", + "1", ) def test_available_in(self): -- GitLab From f2c590f494ff3812227b56f3e917ada53c9e911a Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Tue, 1 Nov 2022 16:06:20 +0100 Subject: [PATCH 3/3] tests/mkenums.py: add a test case for symbolic expression evaluation --- gobject/tests/mkenums.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/gobject/tests/mkenums.py b/gobject/tests/mkenums.py index 51424e29e1..b58d23e799 100644 --- a/gobject/tests/mkenums.py +++ b/gobject/tests/mkenums.py @@ -730,6 +730,35 @@ comment: {standard_bottom_comment} "4", ) + def test_enum_symbolic_expression(self): + """Test use of symbol in value expression.""" + h_contents = """ + typedef enum { + /*< private >*/ + ENUM_VALUE_PRIVATE = 5, + /*< public >*/ + ENUM_VALUE_PUBLIC = ENUM_VALUE_PRIVATE + 2, + } TestSymbolicEnum; + """ + + result = self.runMkenumsWithHeader(h_contents) + self.assertEqual("", result.err) + self.assertSingleEnum( + result, + "TestSymbolicEnum", + "test_symbolic_enum", + "TEST_SYMBOLIC_ENUM", + "SYMBOLIC_ENUM", + "TEST", + "", + "enum", + "Enum", + "ENUM", + "ENUM_VALUE_PUBLIC", + "public", + "7", + ) + class TestRspMkenums(TestMkenums): """Run all tests again in @rspfile mode""" -- GitLab