Skip to content

Commit

Permalink
Work on conditions and transformation
Browse files Browse the repository at this point in the history
  • Loading branch information
klpanagi committed Dec 30, 2024
1 parent 6a74ab7 commit 3c3119f
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 40 deletions.
9 changes: 8 additions & 1 deletion examples/advanced_conditions/scenario.goal
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@ end

Goal<EntityStateCondition> Goal_2
condition: (mean(TempSensor1.temp, 10) > 0.5 ) and
(mean(TempSensor2.temp, 10) > 30)
(std(TempSensor2.temp, 5) < 1) and (TempSensor3.temp > 10)
end


Goal<EntityStateCondition> Goal_3
condition: (mean(TempSensor1.temp, 5) > 0.5 ) and
(std(TempSensor2.temp, 3) < 1)
end


Scenario MyScenario
goals:
- Goal_1 -> 0.6
Expand Down
13 changes: 5 additions & 8 deletions goal_dsl/grammar/condition.tx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import types
import utils

// === Conditions ===
// Condition: AdvancedCondition | PrimitiveCondition | ConditionGroup ;
Condition: ConditionList;

ConditionList:
Condition:
r1=ConditionGroup (operator=LogicalOperator r2=ConditionGroup)*
;

Expand Down Expand Up @@ -43,15 +41,14 @@ MathTerm:
MathFactor:
(sign=PlusOrMinus)?
(
op=MathOperand
| '(' op=MathExpression ')'
op=MathOperand | '(' op=MathExpression ')'
)
;

MathOperand:
op=NUMBER
| op=AugmentedNumericAttr
| op=AttributeValue
op=NUMBER |
op=AugmentedNumericAttr |
op=AttributeValue
;

AttributeValue:
Expand Down
105 changes: 74 additions & 31 deletions goal_dsl/language.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
from os.path import join
from textx import metamodel_from_file, get_children_of_type, metamodel_for_language, get_location
import textx.scoping.providers as scoping_providers
from textx import language, get_model
import statistics
from textx import language, get_model, textx_isinstance, TextXSemanticError, get_parent_of_type, get_children

from goal_dsl.logging import default_logger as logger

from goal_dsl.definitions import THIS_DIR, MODEL_REPO_PATH, BUILTIN_MODELS

Expand Down Expand Up @@ -109,8 +110,8 @@ def model_proc(model, metamodel):


def condition_processor(cond):
# Adds a cond.cond_expr property to the Condition instance
build_cond_expr(cond)
# build_cond_expr(cond)
pass


def nid_processor(nid):
Expand All @@ -119,8 +120,8 @@ def nid_processor(nid):


obj_processors = {
# 'Condition': condition_processor,
'ConditionList': condition_processor,
"Condition": condition_processor,
# 'ConditionList': condition_processor,
# 'ConditionGroup': condition_processor,
# 'PrimitiveCondition': condition_processor,
# 'AdvancedCondition': condition_processor,
Expand Down Expand Up @@ -180,20 +181,52 @@ def build_model(model_path):
Returns:
model: The built model object representing the goal-driven CPS Behavior Verification language.
"""
entity_attr_buffs = []
mm = get_metamodel(debug=False) # Get the metamodel for the language
model = mm.model_from_file(model_path) # Parse the model from the file
conds = get_top_level_condition(model) # Get the top-level conditions from the model
for cond in conds:
build_cond_expr(cond) # Build the condition expressions for each top-level condition
goals = get_model_goals(model) # Get the goals from the model
entities = get_model_entities(model) # Get the entities from the model

logger.info(f"Goals: {goals}")
logger.info(f"Entities: {entities}")

build_condition_expressions(conds) # Build the condition expressions for each top-level condition
entity_attr_buffs = build_entity_attr_buff_tuples(conds) # Build the entity attribute buffer tuples
update_entity_attributes(entities, entity_attr_buffs) # Update the entity attributes with buffer values

logger.info(entity_attr_buffs)
return model # Return the built model


def build_condition_expressions(conds):
for cond in conds:
build_condition(cond)


def update_entity_attributes(entities, entity_attr_buffs):
for entity in entities:
update_entity_attributes_for_buffer(entity, entity_attr_buffs)


def update_entity_attributes_for_buffer(entity, entity_attr_buffs):
for c in entity_attr_buffs:
if c[0] == entity.name:
for attr in entity.attributes:
if attr.name == c[1]:
if not hasattr(attr, "buffer") or attr.buffer < c[2]:
setattr(attr, "buffer", c[2])


def get_model_entities(model):
return get_children_of_type("Entity", model)
entities = []
for m in model._tx_model_repository.all_models:
entities += m.entities
return entities


def get_model_conditions(model):
conds = get_children_of_type("ConditionList", model)
conds = get_children_of_type("Condition", model)
return conds


Expand All @@ -208,30 +241,36 @@ def get_top_level_condition(model):


def get_model_goals(model):
goals = get_children_of_type("Goal", model)
goals = []
for m in model._tx_model_repository.all_models:
goals += m.goals
return goals


def build_cond_expr(cond):
def build_entity_attr_buff_tuples(cond):
pattern = r'(?:mean|std)\((\w+)\.(\w+), (\d+)\)'
matches = re.findall(pattern, cond.cond_def)
result = [(entity, attribute, int(number)) for entity, attribute, number in matches]
return result


def build_condition(cond):
cond_def = get_cond_definition(cond)
cond.cond_expr = cond_def
transform_cond(cond)


def transform_cond(cond):
pattern = r'\b\w+\.\w+\b'
matches = re.findall(pattern, cond.cond_expr)
for m in matches:
if is_float(m):
continue
entity, attr = m.split(".")
attr_ref = f"entities['{entity}'].attributes['{attr}']"
cond.cond_expr = cond.cond_expr.replace(m, attr_ref)
cond.cond_expr = cond.cond_expr.replace("condition:", "")
if cond.cond_expr.startswith(" "):
cond.cond_expr = cond.cond_expr[1:]
if "mean" in cond.cond_expr:
pass
cond.cond_def = cond_def
cond.cond_py = transform_cond_py(cond)


def transform_cond_py(cond):
cond_def = cond.cond_def
cond_def = cond_def.replace("condition:", "").lstrip().rstrip()
logger.info(f"Transforming Condition: {cond_def}")
cond_py = cond_def
cond_py = re.sub(r'mean\(([^,]+)\.([^,]+), [^)]*\)', r'mean(entities["\1"].get_buffer["\2"])', cond_py)
cond_py = re.sub(r'std\(([^,]+)\.([^,]+), [^)]*\)', r'std(entities["\1"].get_buffer["\2"])', cond_py)
cond_py = re.sub(r'var\(([^,]+)\.([^,]+), [^)]*\)', r'var(entities["\1"].get_buffer["\2"])', cond_py)
cond_py = re.sub(r'(\b\w+)\.(?!\d)(\w+\b)', r'entities["\1"].attributes["\2"]', cond_py)
logger.info(f"Transformed Condition: {cond_py}")
return cond_py


def is_float(string):
Expand All @@ -256,11 +295,15 @@ def get_cond_definition(cond):

@language('goal_dsl', '*.goal')
def goaldsl_language():
"Goal-driven CPS Behavior Verification language"
"Goal-driven Behavior Verification DSL for CPSs"
return get_metamodel()


def get_model_grammar(model_path):
mm = get_metamodel()
grammar_model = mm.grammar_model_from_file(model_path)
return grammar_model


def is_instance_textx(obj, type_name):
return obj.__class__.__name__ == type_name

0 comments on commit 3c3119f

Please sign in to comment.