Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit 3cdb085

Browse files
author
fred-labs
authored
Add support for expressions (#157)
1 parent 7532420 commit 3cdb085

File tree

12 files changed

+462
-78
lines changed

12 files changed

+462
-78
lines changed

docs/openscenario2.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ Element Tag Support Notes
6666
``enum`` :raw-html:`✅`
6767
``event`` :raw-html:`✅`
6868
``every`` :raw-html:`❌`
69-
``expression`` :raw-html:`❌`
69+
``expression`` :raw-html:`✅`
7070
``extend`` :raw-html:`❌`
7171
``external`` :raw-html:`❌`
7272
``fall`` :raw-html:`❌`

scenario_coverage/scenario_coverage/scenario_variation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import py_trees
2626
from scenario_execution.model.osc2_parser import OpenScenario2Parser
2727
from scenario_execution.model.model_resolver import resolve_internal_model
28-
from scenario_execution.model.types import RelationExpression, ListExpression, FieldAccessExpression, Expression, print_tree, serialize, to_string
28+
from scenario_execution.model.types import RelationExpression, ListExpression, FieldAccessExpression, ModelExpression, print_tree, serialize, to_string
2929
from scenario_execution.utils.logging import Logger
3030

3131

@@ -138,7 +138,7 @@ def save_resulting_scenarios(self, models):
138138
# create description
139139
variation_descriptions = []
140140
for descr, entry in model[1]:
141-
if isinstance(entry, Expression):
141+
if isinstance(entry, ModelExpression):
142142
val = None
143143
for child in entry.get_children():
144144
if not isinstance(child, FieldAccessExpression):

scenario_execution/scenario_execution/model/model_to_py_tree.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@
1818
import py_trees
1919
from py_trees.common import Access, Status
2020
from pkg_resources import iter_entry_points
21-
2221
import inspect
2322

24-
from scenario_execution.model.types import ActionDeclaration, EventReference, FunctionApplicationExpression, ModifierInvocation, ScenarioDeclaration, DoMember, WaitDirective, EmitDirective, BehaviorInvocation, EventCondition, EventDeclaration, RelationExpression, LogicalExpression, ElapsedExpression, PhysicalLiteral, ModifierDeclaration
23+
from scenario_execution.model.types import KeepConstraintDeclaration, visit_expression, ActionDeclaration, BinaryExpression, EventReference, Expression, FunctionApplicationExpression, ModifierInvocation, ScenarioDeclaration, DoMember, WaitDirective, EmitDirective, BehaviorInvocation, EventCondition, EventDeclaration, RelationExpression, LogicalExpression, ElapsedExpression, PhysicalLiteral, ModifierDeclaration
2524
from scenario_execution.model.model_base_visitor import ModelBaseVisitor
2625
from scenario_execution.model.error import OSC2ParsingError
2726
from scenario_execution.actions.base_action import BaseAction
@@ -103,6 +102,20 @@ def update(self):
103102
return Status.SUCCESS
104103

105104

105+
class ExpressionBehavior(py_trees.behaviour.Behaviour):
106+
107+
def __init__(self, name: "ExpressionBehavior", expression: Expression):
108+
super().__init__(name)
109+
110+
self.expression = expression
111+
112+
def update(self):
113+
if self.expression.eval():
114+
return Status.SUCCESS
115+
else:
116+
return Status.RUNNING
117+
118+
106119
class ModelToPyTree(object):
107120

108121
def __init__(self, logger):
@@ -122,6 +135,7 @@ class BehaviorInit(ModelBaseVisitor):
122135
def __init__(self, logger, tree) -> None:
123136
super().__init__()
124137
self.logger = logger
138+
self.blackboard = None
125139
if not isinstance(tree, py_trees.composites.Sequence):
126140
raise ValueError("ModelToPyTree requires a py-tree sequence as input")
127141
self.tree = tree
@@ -348,19 +362,25 @@ def visit_event_reference(self, node: EventReference):
348362
def visit_event_condition(self, node: EventCondition):
349363
expression = ""
350364
for child in node.get_children():
351-
if isinstance(child, RelationExpression):
352-
raise NotImplementedError()
353-
elif isinstance(child, LogicalExpression):
354-
raise NotImplementedError()
365+
if isinstance(child, (RelationExpression, LogicalExpression)):
366+
expression = ExpressionBehavior(name=node.get_ctx()[2], expression=self.visit(child))
355367
elif isinstance(child, ElapsedExpression):
356368
elapsed_condition = self.visit_elapsed_expression(child)
357-
expression = py_trees.timers.Timer(
358-
name=f"wait {elapsed_condition}s", duration=float(elapsed_condition))
369+
expression = py_trees.timers.Timer(name=f"wait {elapsed_condition}s", duration=float(elapsed_condition))
359370
else:
360371
raise OSC2ParsingError(
361372
msg=f'Invalid event condition {child}', context=node.get_ctx())
362373
return expression
363374

375+
def visit_relation_expression(self, node: RelationExpression):
376+
return visit_expression(node, self.blackboard)
377+
378+
def visit_logical_expression(self, node: LogicalExpression):
379+
return visit_expression(node, self.blackboard)
380+
381+
def visit_binary_expression(self, node: BinaryExpression):
382+
return visit_expression(node, self.blackboard)
383+
364384
def visit_elapsed_expression(self, node: ElapsedExpression):
365385
elem = node.find_first_child_of_type(PhysicalLiteral)
366386
if not elem:
@@ -389,3 +409,7 @@ def visit_modifier_invocation(self, node: ModifierInvocation):
389409
self.create_decorator(node.modifier, resolved_values)
390410
except ValueError as e:
391411
raise OSC2ParsingError(msg=f'ModifierDeclaration {e}.', context=node.get_ctx()) from e
412+
413+
def visit_keep_constraint_declaration(self, node: KeepConstraintDeclaration):
414+
# skip relation-expression
415+
pass

0 commit comments

Comments
 (0)