Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for expressions #157

Merged
merged 6 commits into from
Aug 14, 2024
Merged
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
2 changes: 1 addition & 1 deletion docs/openscenario2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Element Tag Support Notes
``enum`` :raw-html:`✅`
``event`` :raw-html:`✅`
``every`` :raw-html:`❌`
``expression`` :raw-html:`❌`
``expression`` :raw-html:`✅`
``extend`` :raw-html:`❌`
``external`` :raw-html:`❌`
``fall`` :raw-html:`❌`
Expand Down
4 changes: 2 additions & 2 deletions scenario_coverage/scenario_coverage/scenario_variation.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import py_trees
from scenario_execution.model.osc2_parser import OpenScenario2Parser
from scenario_execution.model.model_resolver import resolve_internal_model
from scenario_execution.model.types import RelationExpression, ListExpression, FieldAccessExpression, Expression, print_tree, serialize, to_string
from scenario_execution.model.types import RelationExpression, ListExpression, FieldAccessExpression, ModelExpression, print_tree, serialize, to_string
from scenario_execution.utils.logging import Logger


Expand Down Expand Up @@ -138,7 +138,7 @@ def save_resulting_scenarios(self, models):
# create description
variation_descriptions = []
for descr, entry in model[1]:
if isinstance(entry, Expression):
if isinstance(entry, ModelExpression):
val = None
for child in entry.get_children():
if not isinstance(child, FieldAccessExpression):
Expand Down
40 changes: 32 additions & 8 deletions scenario_execution/scenario_execution/model/model_to_py_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@
import py_trees
from py_trees.common import Access, Status
from pkg_resources import iter_entry_points

import inspect

from scenario_execution.model.types import ActionDeclaration, EventReference, FunctionApplicationExpression, ModifierInvocation, ScenarioDeclaration, DoMember, WaitDirective, EmitDirective, BehaviorInvocation, EventCondition, EventDeclaration, RelationExpression, LogicalExpression, ElapsedExpression, PhysicalLiteral, ModifierDeclaration
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
from scenario_execution.model.model_base_visitor import ModelBaseVisitor
from scenario_execution.model.error import OSC2ParsingError
from scenario_execution.actions.base_action import BaseAction
Expand Down Expand Up @@ -103,6 +102,20 @@ def update(self):
return Status.SUCCESS


class ExpressionBehavior(py_trees.behaviour.Behaviour):

def __init__(self, name: "ExpressionBehavior", expression: Expression):
super().__init__(name)

self.expression = expression

def update(self):
if self.expression.eval():
return Status.SUCCESS
else:
return Status.RUNNING


class ModelToPyTree(object):

def __init__(self, logger):
Expand All @@ -122,6 +135,7 @@ class BehaviorInit(ModelBaseVisitor):
def __init__(self, logger, tree) -> None:
super().__init__()
self.logger = logger
self.blackboard = None
if not isinstance(tree, py_trees.composites.Sequence):
raise ValueError("ModelToPyTree requires a py-tree sequence as input")
self.tree = tree
Expand Down Expand Up @@ -348,19 +362,25 @@ def visit_event_reference(self, node: EventReference):
def visit_event_condition(self, node: EventCondition):
expression = ""
for child in node.get_children():
if isinstance(child, RelationExpression):
raise NotImplementedError()
elif isinstance(child, LogicalExpression):
raise NotImplementedError()
if isinstance(child, (RelationExpression, LogicalExpression)):
expression = ExpressionBehavior(name=node.get_ctx()[2], expression=self.visit(child))
elif isinstance(child, ElapsedExpression):
elapsed_condition = self.visit_elapsed_expression(child)
expression = py_trees.timers.Timer(
name=f"wait {elapsed_condition}s", duration=float(elapsed_condition))
expression = py_trees.timers.Timer(name=f"wait {elapsed_condition}s", duration=float(elapsed_condition))
else:
raise OSC2ParsingError(
msg=f'Invalid event condition {child}', context=node.get_ctx())
return expression

def visit_relation_expression(self, node: RelationExpression):
return visit_expression(node, self.blackboard)

def visit_logical_expression(self, node: LogicalExpression):
return visit_expression(node, self.blackboard)

def visit_binary_expression(self, node: BinaryExpression):
return visit_expression(node, self.blackboard)

def visit_elapsed_expression(self, node: ElapsedExpression):
elem = node.find_first_child_of_type(PhysicalLiteral)
if not elem:
Expand Down Expand Up @@ -389,3 +409,7 @@ def visit_modifier_invocation(self, node: ModifierInvocation):
self.create_decorator(node.modifier, resolved_values)
except ValueError as e:
raise OSC2ParsingError(msg=f'ModifierDeclaration {e}.', context=node.get_ctx()) from e

def visit_keep_constraint_declaration(self, node: KeepConstraintDeclaration):
# skip relation-expression
pass
Loading