From ad15258516a42d1d70801c0b2cca55fec77037a2 Mon Sep 17 00:00:00 2001 From: Philipp Wullstein-Kammler Date: Thu, 12 Dec 2024 11:52:53 +0100 Subject: [PATCH] Detecting duplicated components Add check to detect duplicated components of a record when parsing a TRLC file. Example: ``` Something duplicated { description = "This is fine!" description = "This is the duplicate." } ``` The behavior of the `Record_Object` class is changed such that the `assign` method only assigns components to the record if it has not been assigned already. This is implemented by checking if the field type is different from `Implicit_Null`. The `Parser` class asks the `Record_Object` if the component is `Implicit_Null`. If no, then an error is sent to the message handler. --- trlc/ast.py | 5 +++++ trlc/parser.py | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/trlc/ast.py b/trlc/ast.py index d36900c..b51db9a 100644 --- a/trlc/ast.py +++ b/trlc/ast.py @@ -2998,6 +2998,9 @@ def to_python_dict(self): """ return {name: value.to_python_object() for name, value in self.field.items()} + + def is_component_implicit_null(self, component) -> bool: + return not isinstance(self.field[component.name], Implicit_Null) def assign(self, component, value): assert isinstance(component, Composite_Component) @@ -3008,6 +3011,8 @@ def assign(self, component, value): Implicit_Null, Unary_Expression)), \ "value is %s" % value.__class__.__name__ + if self.is_component_implicit_null(component): + raise KeyError(f"Component {component.name} already assigned to {self.n_typ.name} {self.name}!") self.field[component.name] = value def dump(self, indent=0): # pragma: no cover diff --git a/trlc/parser.py b/trlc/parser.py index c227ee0..387b308 100644 --- a/trlc/parser.py +++ b/trlc/parser.py @@ -1810,11 +1810,19 @@ def parse_record_object_declaration(self): comp = r_typ.components.lookup(self.mh, self.ct, ast.Composite_Component) + + if obj.is_component_implicit_null(comp): + self.mh.error(self.ct.location, + "component '%s' already assigned at line %i" % + (comp.name, + obj.field[comp.name].location.line_no)) + comp.set_ast_link(self.ct) if r_typ.is_frozen(comp): self.mh.error(self.ct.location, "cannot overwrite frozen component %s" % comp.name) + self.match("ASSIGN") comp.set_ast_link(self.ct) value = self.parse_value(comp.n_typ)