// copy all data from template except transition because its a reference of PetriNet (just init overridedName) internal void import(TransitionLink template) { this.links = new List <Link>(); foreach (Link l in template.links) { this.links.Add(new Link(l)); } this.transition.overridedLabel = template.transition.overridedLabel; this.isSystemAction = template.isSystemAction; this.isEndAction = template.isEndAction; this.logic = template.logic; }
internal List <List <string> > getPossibleSetOfLinks(string actionName, string exceptionStackTrace) { TransitionLink transitionLink = getTransitionLinkByTransitionLabel(actionName); if (transitionLink != null) { string logic = transitionLink.logic; // Check logic expression if (ExpressionParser.isValid(transitionLink)) { string[] exp = ExpressionParser.getDistribution(logic); List <string> groupLinksByAnd = new List <string> (); List <List <string> > groupAndByOr = new List <List <string> > (); foreach (string s in exp) { if (!s.Equals("+") && !s.Equals("*")) { groupLinksByAnd.Add(s); } else if (s.Equals("+")) { groupAndByOr.Add(groupLinksByAnd); groupLinksByAnd = new List <string> (); } } groupAndByOr.Add(groupLinksByAnd); return(groupAndByOr); } else { throw new TraceAborted("Logic expression for \"" + actionName + "\" action in \"" + this.gameObject.name + "\" Game Object is not valid.", exceptionStackTrace); } } else { throw new TraceAborted("Action \"" + actionName + "\" is not monitored by \"" + this.gameObject.name + "\" Game Object.", exceptionStackTrace); } }
internal string getInternalName(string actionName, string exceptionStackTrace, bool processLinks = true, params string[] linksConcerned) { TransitionLink transitionLink = getTransitionLinkByTransitionLabel(actionName); if (transitionLink != null) { string logic = transitionLink.logic; // Check logic expression if (ExpressionParser.isValid(transitionLink)) { List <List <string> > groupAndByOr = getPossibleSetOfLinks(actionName, exceptionStackTrace); // If we have to process links and linksConcerned is empty and we have at least one OR statement into logic expression (i.e. at least 2 AND groups) => problem, developer has to specify the set of links concerned by this transition. if (processLinks && linksConcerned.Length == 0 && groupAndByOr.Count > 1) { string availableCombination = "\nAvailable combination of links:\n"; foreach (List <string> ands in groupAndByOr) { availableCombination = availableCombination + " -"; foreach (string token in ands) { availableCombination = availableCombination + " " + token; } availableCombination = availableCombination + "\n"; } throw new TraceAborted("Distributed logic expression for \"" + actionName + "\" action in \"" + this.gameObject.name + "\" Game Object contains \"+\" operator. You have to specify which links are concerned to perform this game action. " + availableCombination, exceptionStackTrace); } else { string prefix = this.gameObject.name + "_"; bool linksFound = false; if (groupAndByOr.Count <= 1) { // If logic expression is empty or contains only AND operators, linksConcerned parameter is not useful because there is no ambiguity on this transition. linksFound = true; if (linksConcerned.Length > 0) { WarningException we = new WarningException("Because logic expression includes only \"*\" operators, \"linksConcerned\" parameters are ignored. You can remove them to the call.", exceptionStackTrace); Debug.LogException(we); } } else { if (!processLinks) { // Developer wants to ignore linksConcerned. So we trace the first one (From Laalys point of view this is not a problem because all or actions have the same public name). prefix = "or0_" + prefix; linksFound = true; } else { // Look for links concerned into distributed logic expression List <string> linksConcerned_sorted = linksConcerned.ToList(); linksConcerned_sorted.Sort(); for (int i = 0; i < groupAndByOr.Count; i++) { groupAndByOr [i].Sort(); if (groupAndByOr [i].SequenceEqual(linksConcerned_sorted)) { if (i > 0) { prefix = "or" + (i - 1) + "_" + prefix; } linksFound = true; break; } } } } if (linksFound) { return(prefix + actionName + "_" + this.id); } else { string debug = ""; foreach (string link in linksConcerned) { debug = debug + " \"" + link + "\""; } string availableCombination = "\nAvailable combination of links:\n"; foreach (List <string> ands in groupAndByOr) { availableCombination = availableCombination + " -"; foreach (string token in ands) { availableCombination = availableCombination + " " + token; } availableCombination = availableCombination + "\n"; } throw new TraceAborted(debug + " not found into distributed logic expression for \"" + actionName + "\" action in \"" + this.gameObject.name + "\" Game Object. " + availableCombination, exceptionStackTrace); } } } else { throw new TraceAborted("Logic expression for \"" + actionName + "\" action in \"" + this.gameObject.name + "\" Game Object is not valid.", exceptionStackTrace); } } else { throw new TraceAborted("Action \"" + actionName + "\" is not monitored by \"" + this.gameObject.name + "\" Game Object.", exceptionStackTrace); } }
/// <summary>Check if a transitionLink contains a valid logix expression.</summary> public static bool isValid(TransitionLink tLink) { string exp = tLink.logic; if (exp == null || exp.Length == 0) { return(true); } // Change all known link with true foreach (Link l in tLink.links) { if (!checkPrerequisite(l.label)) { return(false); } exp = Regex.Replace(exp, "^" + l.label + "$", "true"); exp = Regex.Replace(exp, "^" + l.label + "([*+ ])", "true$1"); exp = Regex.Replace(exp, "([(*+ ])(" + l.label + ")([)*+ ])", "$1true$3"); exp = Regex.Replace(exp, "([(*+ ])(" + l.label + ")([)*+ ])", "$1true$3"); // need to be done twice in case of (l1+l1) in this case "+" has to be used to replace "(l1+" and "+l1)" but Regex.Replace can't do this in a same replacement, only the first one is replaced. exp = Regex.Replace(exp, "([*+ ])" + l.label + "$", "$1true"); } // Remove all spaces exp = exp.Replace(" ", ""); // Try to resolve expression bool stable = false; do { string prevExp = exp; exp = exp.Replace("true+true", "true"); exp = exp.Replace("true*true", "true"); exp = exp.Replace("(true)", "true"); stable = prevExp == exp; } while (!stable); return(exp == "true"); // Previous solution /* * int po = 0; * int pf = 0; * bool badOp = false; * char precedent = ' '; * * //manque vérif cohérence parenthèses * //vérif label ne peut pas être suivi ou précédé par un label * * foreach (char c in ari) { * * if (!char.IsWhiteSpace (c)) { * if (c == '(') { * po++; * } * if (c == ')') { * pf++; * } * if (((precedent == '(' || precedent == '*' || precedent == '+') && (c == '*' || c == '+')) || ((precedent == '*' || precedent == '+') && (c == ')' || c == '+' || c == '*'))) { * badOp = true; * } * precedent = c; * } * } * * //Le début et la fin ne doivent pas être des opérateurs * if (ari[(ari.Length - 1)] == '+' || ari[(ari.Length - 1)] == '*' || ari[0] == '+' || ari[0] == '*') * badOp = true; * * return po == pf && !badOp;*/ }