diff --git a/uapi.behavior/src/main/java/uapi/behavior/BehaviorErrors.java b/uapi.behavior/src/main/java/uapi/behavior/BehaviorErrors.java index 79e8ad6..ebf1053 100644 --- a/uapi.behavior/src/main/java/uapi/behavior/BehaviorErrors.java +++ b/uapi.behavior/src/main/java/uapi/behavior/BehaviorErrors.java @@ -50,7 +50,8 @@ public class BehaviorErrors extends FileBasedExceptionErrors public static final int INCOMPATIBLE_ACTION_TYPE = 26; public static final int DUPLICATED_ACTION_LABEL = 27; public static final int GENERATE_ACTION_LABEL_OVER_MAX = 28; - public static final int INVALIDE_ACTION_INPUT_REF = 29; + public static final int INVALID_ACTION_INPUT_REF = 29; + public static final int REF_ACTION_NOT_EXIST_IN_BEHAVIOR = 30; private static final Map keyCodeMapping; @@ -84,7 +85,8 @@ public class BehaviorErrors extends FileBasedExceptionErrors keyCodeMapping.put(INCOMPATIBLE_ACTION_TYPE, IncompatibleActionType.KEY); keyCodeMapping.put(DUPLICATED_ACTION_LABEL, DuplicatedActionLabel.KEY); keyCodeMapping.put(GENERATE_ACTION_LABEL_OVER_MAX, GenerateActionLabelOverMax.KEY); - keyCodeMapping.put(INVALIDE_ACTION_INPUT_REF, InvalidActionInputRef.KEY); + keyCodeMapping.put(INVALID_ACTION_INPUT_REF, InvalidActionInputRef.KEY); + keyCodeMapping.put(REF_ACTION_NOT_EXIST_IN_BEHAVIOR, RefActionNotExistInBehavior.KEY); } public BehaviorErrors() { @@ -827,4 +829,31 @@ public Object[] get() { return new Object[] { this._actionInputRef }; } } + + /** + * Error string template: + * The referenced action [{}] does not exist in behavior [{}] + */ + public static final class RefActionNotExistInBehavior extends IndexedParameters { + + public static final String KEY = "RefActionNotExistInBehavior"; + + private String _actionLabel; + private ActionIdentify _behaviorId; + + public RefActionNotExistInBehavior actionLabel(final String label) { + this._actionLabel = label; + return this; + } + + public RefActionNotExistInBehavior behaviorId(final ActionIdentify id) { + this._behaviorId = id; + return this; + } + + @Override + public Object[] get() { + return new Object[] { this._actionLabel, this._behaviorId.toString() }; + } + } } diff --git a/uapi.behavior/src/main/java/uapi/behavior/internal/ActionHolder.java b/uapi.behavior/src/main/java/uapi/behavior/internal/ActionHolder.java index 94173f5..1a3cdb3 100644 --- a/uapi.behavior/src/main/java/uapi/behavior/internal/ActionHolder.java +++ b/uapi.behavior/src/main/java/uapi/behavior/internal/ActionHolder.java @@ -6,6 +6,7 @@ import uapi.common.ArgumentChecker; import uapi.common.Functionals; import uapi.common.IAttributed; +import uapi.common.StringHelper; import uapi.rx.Looper; import java.util.LinkedList; @@ -20,14 +21,20 @@ class ActionHolder { private final Functionals.Evaluator _evaluator; private final IAction _action; + private final String _label; private final List _nextActions; - ActionHolder(final IAction action) { - this(action, null); + private ActionHolder _previousAction; + + ActionHolder( + final IAction action + ) { + this(action, null, null); } ActionHolder( final IAction action, + final String label, final Functionals.Evaluator evaluator ) { ArgumentChecker.required(action, "action"); @@ -40,9 +47,28 @@ class ActionHolder { this._evaluator = evaluator; } this._action = action; + this._label = label; this._nextActions = new LinkedList<>(); } + /** + * Return previously action + * + * @return Previously action + */ + ActionHolder previous() { + return this._previousAction; + } + + /** + * Return the label that bind on this action. + * + * @return The label of this action + */ + String label() { + return this._label; + } + /** * Set next action by specific evaluator * @@ -55,7 +81,9 @@ class ActionHolder { void next( final ActionHolder actionHolder ) throws BehaviorException { + ArgumentChecker.required(actionHolder, "actionHolder"); this._nextActions.add(actionHolder); + actionHolder._previousAction = this; } boolean hasNext() { diff --git a/uapi.behavior/src/main/java/uapi/behavior/internal/Behavior.java b/uapi.behavior/src/main/java/uapi/behavior/internal/Behavior.java index e389f49..7054146 100644 --- a/uapi.behavior/src/main/java/uapi/behavior/internal/Behavior.java +++ b/uapi.behavior/src/main/java/uapi/behavior/internal/Behavior.java @@ -536,7 +536,6 @@ private void newNextAction( final String label, final String... inputs ) throws BehaviorException { - ActionHolder newAction = new ActionHolder(action, evaluator); String actionLabel = label; if (StringHelper.isNullOrEmpty(label)) { // Generate action label if no label is specified @@ -572,9 +571,27 @@ private void newNextAction( Pair inputRef = ActionInputMeta.parse(input); String refLabel = inputRef.getLeftValue(); String refName = inputRef.getRightValue(); - + if (! this._labeledActions.containsKey(refLabel)) { + throw BehaviorException.builder() + .errorCode(BehaviorErrors.REF_ACTION_NOT_EXIST_IN_BEHAVIOR) + .variables(new BehaviorErrors.RefActionNotExistInBehavior() + .actionLabel(refLabel) + .behaviorId(Behavior.this._actionId)) + .build(); + } + boolean isPrevious = false; + ActionHolder previous = this._current; + while (previous != null) { + if (actionLabel.equals(previous.label())) { + isPrevious = true; + break; + } + previous = previous.previous(); + } }); + ActionHolder newAction = new ActionHolder(action, actionLabel, evaluator); + // Check new action input is matched to current action output // The check only on non-anonymous action if (! this._current.action().isAnonymous() && ! action.isAnonymous()) { diff --git a/uapi.behavior/src/main/resources/behaviorErrors.properties b/uapi.behavior/src/main/resources/behaviorErrors.properties index 4a179ae..ab73c8c 100644 --- a/uapi.behavior/src/main/resources/behaviorErrors.properties +++ b/uapi.behavior/src/main/resources/behaviorErrors.properties @@ -27,3 +27,4 @@ IncompatibleActionType = The Action type is not Action or Behavior DuplicatedActionLabel = The Action label [{}] is duplicated in Behavior [{}] GenerateActionLabelOverMax = Try generate label for action [{}] count over max count [{}] InvalidActionInputRef = The action input reference is invalid - {} +RefActionNotExistInBehavior = The referenced action [{}] does not exist in behavior [{}]