-- -- Copyright 2014 Alessandro Gerlinger Romero -- -- This file is part of Hybrid fUML. -- -- Hybrid fUML is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- Hybrid fUML is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with Hybrid fUML. If not, see . -- ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- APPROACH -- operation is a Rule -- attribute is a function -- all elements needed are mapped as is -- the methods fire, sendOffers, terminate from ActivityNodeActivation are implemented in the context of activityexecution. therefore, the idea of activity execution -- as a scheduler coordinator of executions... -- -- the scheduler (activityexecution) give preference for fire nodes, after to take offer , finally, sendOffers (considering nodes that can suspende the activity execution as last) -- -- ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- CLASS FUML_Semantics_Classes_Kernel_Value -- RULES DEFINITION ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ACTIVITY EXECUTION - AGENT RULE operatio_Value_Execution_execute :: FUML_Semantics_Classes_Kernel_Value -> Rule () operatio_Value_Execution_execute v = do operatio_Value_ActivityExecution_execute v operatio_Value_OpaqueBehaviorExecution_execute v ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- OPAQUE BEHAVIOR EXECUTION - EMBEDDED VERSION operatio_Value_OpaqueBehaviorExecution_execute :: FUML_Semantics_Classes_Kernel_Value -> Rule() operatio_Value_OpaqueBehaviorExecution_execute v = let vt = function_Value_type(v) in -- it is not an activityexecution, therefore, it is an opaquebehaviorexecution -- should be not initialized if vt /= FUML_Semantics_Activities_IntermediateActivities_ActivityExecution && function_fUML_Agents_mode(v) == FUML_Status_NotInitialized then do case vt of FUML_Implementation_Reals_RealNegExecution -> operatio_Neg v FUML_Implementation_Reals_RealMinusExecution -> operatio_minus v FUML_Implementation_Reals_RealMultExecution -> operatio_times v FUML_Implementation_Reals_RealAddExecution -> operatio_plus v FUML_Implementation_Reals_RealLessThanOrEqualExecution -> operatio_le v FUML_Implementation_Booleans_BooleanAndExecution -> operatio_And v FUML_Implementation_Booleans_BooleanNotExecution -> operatio_Not v _ -> skip -- terminated function_fUML_Agents_mode(v) := FUML_Status_Undef else skip ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ACTIVITY EXECUTION - EMBEDDED VERSION operatio_Value_ActivityExecution_execute :: FUML_Semantics_Classes_Kernel_Value -> Rule() operatio_Value_ActivityExecution_execute v = let vt = function_Value_type(v) in if vt == FUML_Semantics_Activities_IntermediateActivities_ActivityExecution then do -- using iterate to run this agent until pause, accept or termination iterate (rule_fUML_activityExecution_executeOneStep v) -- if it is waiting signal, the signal was not previously defined so the activity shall run again to check if the signal exists if (function_fUML_Agents_mode(v) == FUML_Status_WaitingSignal) then -- checking causal analysis -- check if the set of all agents and nodes running is different from the previous evaluation if lastTimeAgsRunning /= agsRunning then -- no problem do function_fUML_Agents_causalAnalysis(v) := agsRunning rule_fUML_activityExecution_resume v else -- causality problem error("operatio_Value_ActivityExecution_execute - Causality problem. Activities are not causal. " ++ " Agents: " ++ show curShow ++ " Me: " ++ show me ) else skip else skip where -- support causality analysis lastTimeAgsRunning = function_fUML_Agents_causalAnalysis v -- logical time lc = function_Locus_logicalClock (function_Value_ExtensionalValue_locus v) lt = function_fUML_Clock_currentTimeInt lc -- loading all other agents ags = expr2list $ function_fUML_Agents_runnableInThisDiscreteEvaluation `difference` {v} getNodeRunningForAgent ag = filter (\(vi,n) -> vi == ag) $ expr2list $ dom function_ActivityNodeActivation_isRunning agsRunning = (lt, map (\ag -> if length (getNodeRunningForAgent ag) > 0 then head (getNodeRunningForAgent ag) else (ag,FUML_Syntax_Activities_IntermediateActivities_ActivityNodeEmpty)) ags) -- for show (_,cur) = agsRunning curShow = map (\(v,n) -> (function_fUML_oneClassifierType (v),n)) cur me = (function_fUML_oneClassifierType (v),nr) (vi,nr) = head $ filter (\(vi,n) -> vi == v) $ expr2list $ dom function_ActivityNodeActivation_isRunning ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ACTIVITY EXECUTION - EMBEDDED VERSION rule_fUML_activityExecution_executeOneStep :: FUML_Semantics_Classes_Kernel_Value -> Rule() rule_fUML_activityExecution_executeOneStep v = do rule_fUML_activityExecution_fire v rule_fUML_activityExecution_takeOffer v rule_fUML_activityExecution_sendOffers v rule_fUML_activityExecution_terminate v rule_fUML_activityExecution_createInitialControlTokens v ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ACTIVITY EXECUTION - FIRE NODES rule_fUML_activityExecution_fire :: FUML_Semantics_Classes_Kernel_Value -> Rule () rule_fUML_activityExecution_fire v = if function_Value_type(v) == FUML_Semantics_Activities_IntermediateActivities_ActivityExecution && function_fUML_Agents_mode(v) == FUML_Status_Running then if not (null ns) then do -- RUN -- marking as running function_ActivityNodeActivation_isRunning(v,n) := True -- executing control node operatio_MergeNodeActivation_fire (v,n) operatio_FlowFinalNodeActivation_fire (v,n) operatio_ForkNodeActivation_fire (v,n) operatio_DecisionNodeActivation_fire (v,n) operatio_InitialNodeActivation_fire (v,n) -- executing actions operatio_ValueSpecificationActionActivation_doAction (v,n) operatio_AddStructuralFeatureValueActionActivation_doAction (v,n) operatio_ReadStructuralFeatureActionActivation_doAction (v,n) operatio_ClearStructuralFeatureActionActivation_doAction (v,n) operatio_StartObjectBehaviorActionActivation_doAction (v,n) operatio_CallBehaviorActionActivation_doAction (v,n) operatio_CreateObjectActionActivation_doAction (v,n) operatio_ReadSelfActionActivation_doAction (v,n) operatio_SendSignalActionActivation_doAction (v,n) operatio_AcceptEventActionActivation_doAction (v,n) -- check if should remove control token or "create" if (card (function_ActivityNode_outgoing(n))) > 0 && function_ActivityNode_type(n) /= FUML_Syntax_Activities_IntermediateActivities_DecisionNode && function_ActivityNode_type(n) /= FUML_Syntax_Activities_IntermediateActivities_ForkNode then if function_fUML_isAction(n) && card (function_ActivityNodeActivation_heldTokens(v,n)) == 0 then -- if the action was triggered by object flows it guarantees that a control token exists do nct <- (rule_FUML_Semantics_Activities_IntermediateActivities_Token_create FUML_Semantics_Activities_IntermediateActivities_ControlToken) function_ActivityNodeActivation_heldTokens(v,n) := {nct} else -- do not change current configuration of tokens skip else do -- remove tokens function_ActivityNodeActivation_heldTokens(v,n) := {} forall t <- expr2list(function_ActivityNodeActivation_heldTokens(v,n)) do function_Token_ObjectToken_value(t) := FUML_Semantics_Classes_Kernel_ValueEmpty -- check if the node is marked as pausable if (function_fUML_stereotypedActivityNode Pausable n) then rule_fUML_activityExecution_suspend v FUML_Status_Paused n else skip -- stdout -- rule_fUML_out $ "rule_fUML_activityExecution_fire - fired " ++ show n else skip else skip where ns = expr2list $ function_fUML_shouldFire v (vns,n) = head ns ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ACTIVITY EXECUTION - TAKE OFFER rule_fUML_activityExecution_takeOffer :: FUML_Semantics_Classes_Kernel_Value -> Rule () rule_fUML_activityExecution_takeOffer v = if function_Value_type(v) == FUML_Semantics_Activities_IntermediateActivities_ActivityExecution && function_fUML_Agents_mode(v) == FUML_Status_Running then -- it will not take offer when there is one or more firing to be done if not (null ns2) && (null ns) then -- should TAKE OFFER do -- checking : the semantics defines behavior for nodes with only one incoming -- exception are: -- MergeNode that propagates first token that arrives -- DecisionNode when one is a controlflow and another is objectflow if not (function_fUML_maxOneIncomingEdge n2) && function_ActivityNode_type(n2) /= FUML_Syntax_Activities_IntermediateActivities_MergeNode && function_ActivityNode_type(n2) /= FUML_Syntax_Activities_IntermediateActivities_DecisionNode then error("rule_fUML_activityExecution_takeOffer - The semantics defines behavior for nodes with only one incoming. However, the following node has more than one. " ++ show n2 ++ show (function_ActivityNode_incoming n2)) else skip -- checking : the semantics defines behavior for nodes with only one outgoing -- exception are: -- ForkNode that offer one token to multiple edges -- DecisionNode if not (function_fUML_maxOneOutgoingEdge n2) && function_ActivityNode_type(n2) /= FUML_Syntax_Activities_IntermediateActivities_ForkNode && function_ActivityNode_type(n2) /= FUML_Syntax_Activities_IntermediateActivities_DecisionNode then error("rule_fUML_activityExecution_takeOffer - The semantics defines behavior for nodes with only one outgoing. However, the following node has more than one. " ++ show n2 ++ show (function_ActivityNode_outgoing n2)) else skip -- remove offer function_ActivityEdgeInstance_offers(v,e2) := {} forall off <- expr2list(function_ActivityEdgeInstance_offers(v,e2)) do function_Offer_offeredTokens(off) := {} -- remove token from previous function_ActivityNodeActivation_heldTokens(v,nsource) := function_ActivityNodeActivation_heldTokens(v,nsource) `difference` t -- enabling previous to run again (with other token) function_ActivityNodeActivation_isRunning(v,nsource) := False -- add token to the next function_ActivityNodeActivation_heldTokens(v,n2) := function_ActivityNodeActivation_heldTokens(v,n2) `union` t else skip else skip where ns = expr2list $ function_fUML_shouldFire v ns2 = expr2list $ function_fUML_shouldTakeOffer v (vns2,n2) = head ns2 -- retrieving each edge has the offering e2 = head $ filter (\e -> function_ActivityEdgeInstance_offers(v,e) /= {}) (expr2list (function_ActivityNode_incoming n2)) nsource = function_ActivityEdge_source e2 t = function_Offer_offeredTokens $ (one (function_ActivityEdgeInstance_offers(v,e2))) ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ACTIVITY EXECUTION - SEND OFFERS rule_fUML_activityExecution_sendOffers :: FUML_Semantics_Classes_Kernel_Value -> Rule () rule_fUML_activityExecution_sendOffers v = if function_Value_type(v) == FUML_Semantics_Activities_IntermediateActivities_ActivityExecution && function_fUML_Agents_mode(v) == FUML_Status_Running then -- it does not offer until there are fires or possibility of take offer if not (null es) && (null ns2) && (null ns) then -- OFFER create off do function_Offer_offeredTokens(off) := function_ActivityNodeActivation_heldTokens(v, function_ActivityEdge_source(e)) function_ActivityEdgeInstance_offers(v,e) := {off} else skip else skip where ns = expr2list $ function_fUML_shouldFire v ns2 = expr2list $ function_fUML_shouldTakeOffer v es = function_fUML_shouldOfferPrioritized v (ve,e) = head es ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ACTIVITY EXECUTION - TERMINATE rule_fUML_activityExecution_terminate :: FUML_Semantics_Classes_Kernel_Value -> Rule () rule_fUML_activityExecution_terminate v = if function_Value_type(v) == FUML_Semantics_Activities_IntermediateActivities_ActivityExecution && function_fUML_Agents_mode(v) == FUML_Status_Running then -- it terminates when there is nothing to do if (null es) && (null ns2) && (null ns) then if function_fUML_Agents_parent v == FUML_Semantics_Classes_Kernel_ValueEmpty then -- removing object, if it has no parent operatio_Value_Object_destroy v else -- marking as terminated terminated function_fUML_Agents_mode(v) := FUML_Status_Undef else skip else skip where ns = expr2list $ function_fUML_shouldFire v ns2 = expr2list $ function_fUML_shouldTakeOffer v es = function_fUML_shouldOfferPrioritized v ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ACTIVITY EXECUTION - INITIAL CONTROL TOKENS rule_fUML_activityExecution_createInitialControlTokens :: FUML_Semantics_Classes_Kernel_Value -> Rule () rule_fUML_activityExecution_createInitialControlTokens v = let vt = function_Value_type(v) in if function_Value_type(v) == FUML_Semantics_Activities_IntermediateActivities_ActivityExecution && function_fUML_Agents_mode(v) == FUML_Status_NotInitialized then let cl = function_fUML_oneClassifierType v in let acs = function_fUML_actionsToBeInitiallyTriggered cl ++ function_fUML_initialNodes cl in do -- put control token at initial nodes and executable nodes without incomming and without input forall n <- acs do nct <- (rule_FUML_Semantics_Activities_IntermediateActivities_Token_create FUML_Semantics_Activities_IntermediateActivities_ControlToken) function_ActivityNodeActivation_heldTokens(v,n) := {nct} -- marking as running function_fUML_Agents_mode(v) := FUML_Status_Running else skip ------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ACTIONS ------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- APPROACH vide mapping_actions -- these two actions define new AGENTS -- this is the reason to be here ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- CLASS FUML_Semantics_Actions_CompleteActions_StartObjectBehaviorActionActivation -- FUML_Syntax_Actions_CompleteActions_StartObjectBehaviorAction -- operatio_StartObjectBehaviorActionActivation_doAction :: FUML_Semantics_Activities_IntermediateActivities_ActivityNodeActivation -> Rule () operatio_StartObjectBehaviorActionActivation_doAction (vl, soba) = let sobab = (function_ActivityNode_type(soba) == FUML_Syntax_Actions_CompleteActions_StartObjectBehaviorAction) in let acsobab = function_fUML_activityHasNode (function_fUML_activity vl) soba in let on = function_ActivityNode_StartObjectBehaviorAction_object soba in -- checking -- it is a StartObjectBehaviorAction, is for the classifier from the value, and has an object if sobab && acsobab && on /= FUML_Syntax_Activities_IntermediateActivities_ActivityNodeEmpty then -- tokens let oto = one $ function_ActivityNodeActivation_heldTokens (vl,on) in -- values let val = function_Token_ObjectToken_value oto in let obj = function_Value_Reference_referent val in -- classifier behavior let cl = function_fUML_oneClassifierType obj in let clb = function_Classifier_BehavioredClassifier_classifierBehavior cl in -- checking -- it has token in the inputpin, the token has value, -- it has a control token, -- and has a classifier behavior if oto /= FUML_Semantics_Activities_IntermediateActivities_TokenEmpty && val /= FUML_Semantics_Classes_Kernel_ValueEmpty && function_ActivityNodeActivation_isReady(vl, soba) && clb /= FUML_Syntax_Classes_Kernel_ClassifierEmpty then do -- remove token from input function_ActivityNodeActivation_heldTokens(vl,on) := function_ActivityNodeActivation_heldTokens(vl,on) `difference` {oto} function_Token_ObjectToken_value(oto):= FUML_Semantics_Classes_Kernel_ValueEmpty -- checking if it is an active class, and is not running if (function_Classifier_Class_isActive cl) && (not $ function_fUML_classifierBehaviorIsRunning obj) then do -- creating a new agent, without parent - it is independent ex <- (operatio_ExecutionFactory_createExecution (function_Locus_factory (function_Value_ExtensionalValue_locus vl)) clb obj) function_fUML_Agents(ex):= operatio_Value_Execution_execute function_fUML_Agents_mode(ex) := FUML_Status_NotInitialized else skip else -- stdout rule_fUML_out $ "operatio_StartObjectBehaviorActionActivation_doAction - partially evaluated " ++ show (function_fUML_activity vl) ++ show soba ++ show val ++ show oto else if sobab && acsobab then -- stdout rule_fUML_out $ "operatio_StartObjectBehaviorActionActivation_doAction - partially evaluated " ++ show (function_fUML_activity vl) ++ show soba else skip ------------------------------------------------------------------------------------------------------------------------------------------------------------ -- CLASS FUML_Semantics_Actions_BasicActions_CallBehaviorActionActivation -- FUML_Syntax_Actions_BasicActions_CallBehaviorAction -- operatio_CallBehaviorActionActivation_doAction :: FUML_Semantics_Activities_IntermediateActivities_ActivityNodeActivation -> Rule () operatio_CallBehaviorActionActivation_doAction (vl, cba) = let cbab = (function_ActivityNode_type(cba) == FUML_Syntax_Actions_BasicActions_CallBehaviorAction) in let accbab = function_fUML_activityHasNode (function_fUML_activity vl) cba in let ac = function_ActivityNode_CallBehaviorAction_behavior cba in -- checking -- it is a CallBehaviorAction, and is for the classifier from the value, and has a behavior if cbab && accbab && ac /= FUML_Syntax_Classes_Kernel_ClassifierEmpty then do if function_ActivityNode_CallAction_isSynchronous cba == False then error("operatio_CallBehaviorActionActivation_doAction - unsupported asynchronous call. " ++ show cba ) else skip -- creating an agent ex <- (operatio_ExecutionFactory_createExecution (function_Locus_factory (function_Value_ExtensionalValue_locus vl)) ac (function_Value_Execution_context vl)) if ex /= FUML_Semantics_Classes_Kernel_ValueEmpty then do function_fUML_Agents(ex):= operatio_Value_Execution_execute function_fUML_Agents_mode(ex) := FUML_Status_NotInitialized function_fUML_Agents_parent(ex):= vl function_fUML_Agents_mode(vl) := FUML_Status_WaitingExecution -- creating values pvs <- rforall p <- expr2list(function_Classifier_Behavior_ownedParameter ac) do let ips = filter (\n -> function_ActivityNode_NamedElement_name(n) == function_Parameter_NamedElement_name(p)) $ expr2list $ function_ActivityNode_Action_input cba let ip = (head ips) let ipots = function_ActivityNodeActivation_heldTokens (vl, ip) let ipot = one ipots let ipvl = function_Token_ObjectToken_value ipot create pv do function_ParameterValue_parameter(pv):= p -- propagating values -- if it is an input pin and has a value if length ips > 0 && card ipots > 0 then do -- remove token from input function_ActivityNodeActivation_heldTokens(vl,ip) := function_ActivityNodeActivation_heldTokens(vl,ip) `difference` {ipot} function_Token_ObjectToken_value(ipot):= FUML_Semantics_Classes_Kernel_ValueEmpty -- setting value function_ParameterValue_values(pv):= {ipvl} else skip result(pv) -- setting values function_Value_Execution_parameterValues(ex):= mkSet pvs else skip `seq` -- running it let acr = (expr2list $ function_fUML_Agents_childs_notInitialized vl) in let bc = head acr in if (length acr) == 0 then skip else do operatio_Value_Execution_execute bc if function_ActivityNode_InvocationAction_argument cba /= {FUML_Syntax_Activities_IntermediateActivities_ActivityNodeEmpty} && function_Value_type(bc) == FUML_Semantics_Activities_IntermediateActivities_ActivityExecution then error("operatio_CallBehaviorActionActivation_doAction - unsupported arguments for activityexecution. " ++ show cba ) else skip `seq` -- propagating results let acr = (expr2list $ function_fUML_Agents_childs_terminated vl) in let bc = head acr in if (length acr) == 0 then skip else do -- creating return values forall p <- expr2list(function_Classifier_Behavior_ownedParameter ac) do if (p /= FUML_Syntax_Classes_Kernel_ParameterEmpty && (function_Parameter_direction p == FUML_Syntax_Classes_Kernel_ParameterDirectionKind_inout || function_Parameter_direction p == FUML_Syntax_Classes_Kernel_ParameterDirectionKind_out || function_Parameter_direction p == FUML_Syntax_Classes_Kernel_ParameterDirectionKind_return)) then let ops = filter (\n -> function_ActivityNode_NamedElement_name(n) == function_Parameter_NamedElement_name(p)) $ expr2list $ function_ActivityNode_Action_output cba in let op = (head ops) in let pres = filter(\pv -> function_Parameter_NamedElement_name(function_ParameterValue_parameter pv) == function_Parameter_NamedElement_name p) $ expr2list(function_Value_Execution_parameterValues(bc)) in let pres1 = head pres in if length pres > 0 && length ops > 0 && card (function_ParameterValue_values pres1) == 1 then do not <- (rule_FUML_Semantics_Activities_IntermediateActivities_Token_create FUML_Semantics_Activities_IntermediateActivities_ObjectToken) function_Token_ObjectToken_value(not):= one (function_ParameterValue_values pres1) function_ActivityNodeActivation_heldTokens(vl,op) := {not} else skip else skip -- allowing main to run function_fUML_Agents_mode(vl) := FUML_Status_Running -- removing object operatio_Value_Object_destroy bc else if cbab && accbab then -- stdout rule_fUML_out $ "operatio_CallBehaviorActionActivation_doAction - partially evaluated " ++ show (function_fUML_activity vl) ++ show cba else skip