Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions tests-system/unresolved-1/foo.rsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package Example

type T {
linked optional ReqId
}

tuple ReqId {
item T
separator @
LinkVersion Integer
}
5 changes: 5 additions & 0 deletions tests-system/unresolved-1/foo.trlc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package Example

T Test {

}
1 change: 1 addition & 0 deletions tests-system/unresolved-1/output
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
1 change: 1 addition & 0 deletions tests-system/unresolved-1/output.brief
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
6 changes: 6 additions & 0 deletions tests-system/unresolved-1/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"Test": {
"linked": null
}
}
Processed 1 model and 1 requirement file and found no issues
1 change: 1 addition & 0 deletions tests-system/unresolved-1/output.smtlib
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
11 changes: 11 additions & 0 deletions tests-system/unresolved-2/foo.rsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package Example

type T {
linked ReqId
}

tuple ReqId {
item T
separator @
LinkVersion Integer
}
9 changes: 9 additions & 0 deletions tests-system/unresolved-2/foo.trlc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package Example

T Test_1 {
linked = Test_2@1
}

T Test_2 {
linked = Test_1@1
}
1 change: 1 addition & 0 deletions tests-system/unresolved-2/output
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
1 change: 1 addition & 0 deletions tests-system/unresolved-2/output.brief
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
15 changes: 15 additions & 0 deletions tests-system/unresolved-2/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"Test_1": {
"linked": {
"LinkVersion": 1,
"item": "Example.Test_2"
}
},
"Test_2": {
"linked": {
"LinkVersion": 1,
"item": "Example.Test_1"
}
}
}
Processed 1 model and 1 requirement file and found no issues
1 change: 1 addition & 0 deletions tests-system/unresolved-2/output.smtlib
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
11 changes: 11 additions & 0 deletions tests-system/unresolved-3/foo.rsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package Example

type Requirement {
linked ReqId[0 .. *]
}

tuple ReqId {
item Requirement
separator @
LinkVersion Integer
}
9 changes: 9 additions & 0 deletions tests-system/unresolved-3/foo.trlc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package Example

Requirement Test_1 {
linked = []
}

Requirement Test_2 {
linked = [Test_1@1]
}
3 changes: 3 additions & 0 deletions tests-system/unresolved-3/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
linked = [Test_1@1]
^ unresolved-3/foo.trlc:8: error: unknown symbol ReqId
Processed 1 model and 1 requirement file and found 1 error
2 changes: 2 additions & 0 deletions tests-system/unresolved-3/output.brief
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
unresolved-3/foo.trlc:8:14: trlc error: unknown symbol ReqId
Processed 1 model and 1 requirement file and found 1 error
3 changes: 3 additions & 0 deletions tests-system/unresolved-3/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
linked = [Test_1@1]
^ unresolved-3/foo.trlc:8: error: unknown symbol ReqId
Processed 1 model and 1 requirement file and found 1 error
3 changes: 3 additions & 0 deletions tests-system/unresolved-3/output.smtlib
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
linked = [Test_1@1]
^ unresolved-3/foo.trlc:8: error: unknown symbol ReqId
Processed 1 model and 1 requirement file and found 1 error
11 changes: 11 additions & 0 deletions tests-system/unresolved-4/foo.rsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package Example

tuple ReqId {
item Requirement
separator @
LinkVersion Integer
}

type Requirement {
linked ReqId
}
9 changes: 9 additions & 0 deletions tests-system/unresolved-4/foo.trlc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package Example

Requirement Test_1 {
linked = Test_2@2
}

Requirement Test_2 {
linked = Test_1@1
}
1 change: 1 addition & 0 deletions tests-system/unresolved-4/output
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
1 change: 1 addition & 0 deletions tests-system/unresolved-4/output.brief
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
15 changes: 15 additions & 0 deletions tests-system/unresolved-4/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"Test_1": {
"linked": {
"LinkVersion": 2,
"item": "Example.Test_2"
}
},
"Test_2": {
"linked": {
"LinkVersion": 1,
"item": "Example.Test_1"
}
}
}
Processed 1 model and 1 requirement file and found no issues
1 change: 1 addition & 0 deletions tests-system/unresolved-4/output.smtlib
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
11 changes: 11 additions & 0 deletions tests-system/unresolved-5/foo.rsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package Example

tuple ReqId {
item Requirement
separator @
LinkVersion Integer
}

type Requirement {
linked ReqId[0 .. *]
}
9 changes: 9 additions & 0 deletions tests-system/unresolved-5/foo.trlc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package Example

Requirement Test_1 {
linked = []
}

Requirement Test_2 {
linked = [Test_1@1]
}
1 change: 1 addition & 0 deletions tests-system/unresolved-5/output
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
1 change: 1 addition & 0 deletions tests-system/unresolved-5/output.brief
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
14 changes: 14 additions & 0 deletions tests-system/unresolved-5/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Test_1": {
"linked": []
},
"Test_2": {
"linked": [
{
"LinkVersion": 1,
"item": "Example.Test_1"
}
]
}
}
Processed 1 model and 1 requirement file and found no issues
1 change: 1 addition & 0 deletions tests-system/unresolved-5/output.smtlib
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Processed 1 model and 1 requirement file and found no issues
118 changes: 112 additions & 6 deletions trlc/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,10 @@ def to_python_object(self):
def can_be_null(self):
return False

def update_fields(self, parent):
for value in self.value:
if isinstance(value, (Tuple_Aggregate, Array_Aggregate)):
value.update_fields(parent)

class Tuple_Aggregate(Expression):
"""Instances of a tuple
Expand Down Expand Up @@ -1020,6 +1024,69 @@ def to_python_object(self):
def can_be_null(self):
return False

def update_fields(self, parent):
"""
Update `self.value` dictionary with resolved values for each optional field
that has a valid `description` in `self.typ`.

Resolution supports:
- Nested paths using '@' as a separator.
- Special reference `$parent` pointing to the parent object.

Example for two supported forms::
type A {
field int
}
tuple LinkB2A {
derived A
separator @
field_A "derived@field" optional int
^^^^^^^^^^^^^1
separator @
field_B "$parent@field" optional int
^^^^^^^^^^^^^2
}
type B {
field int
derived_from LinkB2A[1 .. *]
}

:form 1: `<type name>@<field name>` (see 1)
`field_A` resolves to the referenced field in type A.

:form 2: `$parent@<field name>` (see 2)
`field_B` resolves to the field in the parent type B.

Note that only fields with valid `description` are eligible for this resolution,
and shall be declared as "optional".

"""
for n_item in self.typ.iter_sequence():
if not isinstance(n_item, Composite_Component):
continue
desc = n_item.description
if desc is None or ("@" not in desc and "$parent" not in desc):
continue

current = self.value
parts = desc.split("@")
if parts[0] == "$parent":
current, parts = parent, parts[1:]
elif "$parent" in parts:
raise KeyError(f"Invalid description '{desc}': $parent only allowed at beginning")

for part in parts:
if isinstance(current, dict):
current = current.get(part)
elif isinstance(current, Record_Object):
current = current.field.get(part)
else:
raise KeyError(f"Invalid traversal at '{part}' in {desc}")
if current is None:
raise KeyError(f"Cannot resolve '{part}' in '{desc}'")
if isinstance(current, Record_Reference):
current = current.target
self.value[n_item.name] = current

class Record_Reference(Expression):
"""Reference to another record object
Expand Down Expand Up @@ -1087,6 +1154,11 @@ def resolve_references(self, mh):
name = self.name,
error_location = self.location,
required_subclass = Record_Object)
if isinstance(self.target, Unresolved_Type):
mh.error(
self.location,
self.target.error_msg
)
if self.typ is None:
self.typ = self.target.n_typ
elif not self.target.n_typ.is_subclass_of(self.typ):
Expand Down Expand Up @@ -2820,6 +2892,13 @@ def get_example_value(self):
else:
return "(%s)" % ", ".join(parts)

class Unresolved_Type(Composite_Type):
def __init__(self, name, description, location, package):
super().__init__(name, description, location, package)
self.error_msg = None

def dump(self):
pass

class Separator(Node):
# lobster-trace: LRM.Tuple_Declaration
Expand Down Expand Up @@ -3028,6 +3107,11 @@ def resolve_references(self, mh):
for val in self.field.values():
val.resolve_references(mh)

def update_items(self):
for value in self.field.values():
if isinstance(value, (Tuple_Aggregate, Array_Aggregate)):
value.update_fields(self)

def perform_checks(self, mh):
# lobster-trace: LRM.Check_Evaluation_Order
# lobster-trace: LRM.Evaluation_Of_Checks
Expand Down Expand Up @@ -3382,13 +3466,35 @@ def lookup_direct(self,
n = 1)

if matches:
mh.error(error_location,
"unknown symbol %s, did you mean %s?" %
(name,
matches[0]))
pkg_dummy = Package(
"__unresolved__",
error_location,
Symbol_Table(),
declared_late=True
)
n_unresolved = Unresolved_Type(
name=name,
description=None,
location=error_location,
package=pkg_dummy
)
n_unresolved.error_msg = "unknown symbol %s, did you mean %s?" % (name, matches[0])
return n_unresolved
else:
mh.error(error_location,
"unknown symbol %s" % name)
pkg_dummy = Package(
"__unresolved__",
error_location,
Symbol_Table(),
declared_late=True
)
n_unresolved = Unresolved_Type(
name=name,
description=None,
location=error_location,
package=pkg_dummy
)
n_unresolved.error_msg = "unknown symbol %s" % name
return n_unresolved

def lookup(self, mh, referencing_token, required_subclass=None):
# lobster-trace: LRM.Described_Name_Equality
Expand Down
2 changes: 1 addition & 1 deletion trlc/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def verify_record_type(self, n_record_type):
if n_record_type.is_abstract:
if n_record_type not in self.abstract_extensions:
self.abstract_extensions[n_record_type] = set()
elif n_record_type.parent and n_record_type.parent.is_abstract:
if n_record_type.parent and n_record_type.parent.is_abstract:
if n_record_type.parent not in self.abstract_extensions:
self.abstract_extensions[n_record_type.parent] = set()
self.abstract_extensions[n_record_type.parent].add(n_record_type)
Expand Down
Loading