Hello,
See the model below:
package CalcTypingTest {
part def A {
attribute b : ScalarValues::Real;
attribute c : ScalarValues::Real = 5.0;
attribute d : ScalarValues::Real = b * c;
}
part a : A {
:>> b = 3.0;
assert constraint { d == 15.0 }
}
}
When I try to load the model and evaluate the constraint in part a, I get the following error:
<source>:5:44: error (type-error): Invalid operator '*' for types 'element' and 'rational'
What I would have expected is that the constraint evaluates to true, because b is redefined in the part usage.
I used the following code:
import syside
model, _ = syside.load_model(['calc_typing.sysml'])
with model.documents[0].lock() as doc:
# Get the constraint in part a
package: syside.Package = doc.root_node.children.elements[0]
part_a: syside.PartUsage = package.children.elements[1]
constraint: syside.AssertConstraintUsage = part_a.children.elements[1]
assert isinstance(constraint, syside.AssertConstraintUsage)
# Evaluate the expression
expression = constraint.asserted_constraint.result_expression
evaluated_value, report = syside.Compiler().evaluate(expression, model.environment.lib)
print(evaluated_value)
if report.fatal:
print('\n'.join([str(diag) for diag in report.diagnostics]))
Greetings,
Jasper
Hi Jasper,
This happens because d is being evaluated in the scope of A (technically in the scope of constraint) which has no b value. You need to add scope=part_a to Compiler().evaluate(...), e.g.
evaluated_value, report = syside.Compiler().evaluate(
expression, scope=part_a, stdlib=model.environment.lib
)
It then prints True.
Hi Daumantas,
Ah I missed that, this indeed fixes it but it is quite non-intuitive.
Also, if I for example change the SysML model to:
package CalcTypingTest {
part def A {
attribute b : ScalarValues::Real;
attribute c : ScalarValues::Real = 5.0;
attribute d : ScalarValues::Real = b * c;
}
part a : A {
:>> b = 3.0;
}
assert constraint { a.d == 15.0 }
}
And the Python script to:
import syside
model, _ = syside.load_model(['model.sysml'])
with model.documents[0].lock() as doc:
# Get the constraint in part a
package: syside.Package = doc.root_node.children.elements[0]
part_a: syside.PartUsage = package.children.elements[1]
constraint: syside.AssertConstraintUsage = package.children.elements[2]
assert isinstance(constraint, syside.AssertConstraintUsage)
# Evaluate the expression
expression = constraint.asserted_constraint.result_expression
evaluated_value, report = syside.Compiler().evaluate(expression, model.environment.lib)
print(evaluated_value)
if report.fatal:
print('\n'.join([str(diag) for diag in report.diagnostics]))
Then I have the same problem. Also this one is fixed by adding the scope, however you can imagine that there will be cases where there will be constraints that reference something somewhere else in the model, or even involve multiple elements (multiple scopes), and then I cannot use this scope mechanism anymore.
Best would be if Syside automatically determines which elements are involved and automatically applies redefinitions, without the user needing to add the scope.
Greetings,
Jasper
Best would be if Syside automatically determines which elements are involved and automatically applies redefinitions, without the user needing to add the scope.
I will see if we can figure something out.
Otherwise, assert constraint { a.d == 15.0 } evaluating d not in the scope of a looks like a separate bug.
I will see if we can figure something out.
Changed the search to consider owning types if a match was not found in current scope. Will be in either 0.8.2 release or the next after.
Otherwise, assert constraint { a.d == 15.0 } evaluating d not in the scope of a looks like a separate bug.
Already fixed for the next release, for Mass rollup example from Introduction to the SysML v2 Language - #15 by Daumantas
Ah cool, I’ll try it out once the next release is ready 