/* * generated by Xtext */ package de.ugoe.cs.swe.bnftools.validation import de.ugoe.cs.swe.bnftools.ebnf.EbnfPackage import java.util.List import org.eclipse.xtext.validation.Check import de.ugoe.cs.swe.bnftools.ebnf.Rule import org.eclipse.xtext.nodemodel.util.NodeModelUtils import org.eclipse.xtext.nodemodel.ICompositeNode import de.ugoe.cs.swe.bnftools.ebnf.EtsiBnf import de.ugoe.cs.swe.bnftools.ebnf.RuleReference import de.ugoe.cs.swe.bnftools.ebnf.DefinitionList import de.ugoe.cs.swe.bnftools.ebnf.SingleDefinition import java.util.ArrayList //import java.util.HashMap //import java.util.Set //import java.util.HashSet //import org.eclipse.xtext.validation.Check /** * Custom validation rules. * * see http://www.eclipse.org/Xtext/documentation.html#validation */ class EbnfValidator extends AbstractEbnfValidator { public static final String ruleReferencedOneDescription = "The rule is only referenced by one other rule"; public static final String passthroughRuleDescription = "The rule is a passthrough rule"; public static final String unreferencedPassthroughRuleDescription = "The rule is an unreferenced passthrough rule"; public static final String unusedRuleDescription = "The rule is not referenced anywhere"; public static final String equalAlternativeDescription = "The rule contains equal alternatives"; public static final String duplicateRulesDescription = "The rule is a duplicate"; //public static final String duplicateSubRulesDescription = "A part the of rule is a duplicate"; public static final String nonUniqueNameDescription = "The rule has the same Name as the Rule in Line "; // ---------------------------------------------------------------------------------------------------- /* Checks if a rule is only referenced by one other Rule, e.g.: * a ::= b * b ::= "foo" */ @Check def void checkReferencedOnlyOnce(Rule rule) { if (EbnfAnalysisUtils.isTokenRule(rule)) return; var List references = EbnfAnalysisUtils.findReferences(rule); if (references.size() == 1 && rule.rulenumber != 1) { warning(ruleReferencedOneDescription, EbnfPackage$Literals::RULE__NAME, ruleReferencedOneDescription, rule.name); } } // ---------------------------------------------------------------------------------------------------- /*Checks if a a rule has the same definition as another rule e.g.: * a ::= "test" * b ::= "test" * (Problem: does not check if there is a permutation) */ @Check def void checkDuplicateRules(Rule rule) { //load bnf var EtsiBnf etsiBnf = rule.eContainer().eContainer() as EtsiBnf; // find the rule in the parsetree var ICompositeNode definitionList = NodeModelUtils.findActualNodeFor(rule.getDefinitionList()); //get the definitionList as formatted string var String rightHandSideText = definitionList.text.trim().replaceAll("[ \t\n\r]", ""); //get All Rules var List allRules = EbnfAnalysisUtils.getAllRules(etsiBnf); // run through all Rules for (currentRule : allRules) { if (currentRule != rule) { var ICompositeNode currentRuleDefinitionList = NodeModelUtils.findActualNodeFor( currentRule.getDefinitionList()); var String currentRuleRightHandSideText = currentRuleDefinitionList.text.trim().replaceAll("[ \t\n\r]", ""); if (currentRuleRightHandSideText.equals(rightHandSideText)) { var String description = duplicateRulesDescription + " with rule \"" + currentRule.getName() + "\" (Line " + NodeModelUtils.findActualNodeFor(currentRule).getStartLine() + ")"; warning(description, EbnfPackage$Literals::RULE__NAME); } } } // //get all Single Definitions as Trimmed Strings // var List singleDefsAsString = new ArrayList(); // // for (SingleDefinition s : (rule.definitionList).singleDefinition) { // singleDefsAsString.add(NodeModelUtils.findActualNodeFor(s).text.trim().replaceAll("[ \t\n\r]", "")); // } // // // for every rule get the single definitions as Strings // var int j = 0; // while (j singleDefsAsString1 = new ArrayList(); // // for (SingleDefinition s : ( currentRule.definitionList).singleDefinition) { // singleDefsAsString1.add(NodeModelUtils.findActualNodeFor(s).text.trim().replaceAll("[ \t\n\r]", "")); // } // // //for every String SingleDefinition find a corresponding ind the current rule // if (singleDefsAsString.size == singleDefsAsString1.size) { // var List singleDefsAsStringCpy = singleDefsAsString.clone; // var boolean equal = true; // while (equal) { // var String momentaryString = singleDefsAsStringCpy.get(0); // var int i = 0; // var boolean found = false; // while (i < singleDefsAsString1.size && !found) { // if (singleDefsAsString1.get(i).equals(momentaryString)) { // singleDefsAsStringCpy.remove(0); // singleDefsAsString1.remove(i); // found = true // } // i++; // } // if (!found) { // equal = false; // } // if (singleDefsAsStringCpy.empty) { // var String description = duplicateRulesDescription + " with rule \"" + currentRule.getName() + // "\" (Line " + NodeModelUtils.findActualNodeFor(currentRule).getStartLine() + ")"; // warning(description, EbnfPackage$Literals::RULE__NAME) // } // } // } // // } // j++; // } } // ---------------------------------------------------------------------------------------------------- /*Checks if a Rule got the same Name as another Rule, e.g.: * a ::= "foo" * a ::= "bar" */ @Check def void checkNameIsUnique(Rule rule) { val EtsiBnf bnf = rule.eContainer.eContainer as EtsiBnf; for (r : EbnfAnalysisUtils.getAllRules(bnf)) { if (rule.name.equals(r.name)) { if (!r.equals(rule)) { error(nonUniqueNameDescription + NodeModelUtils.findActualNodeFor(r).startLine, EbnfPackage$Literals::RULE__NAME) } } } } // ---------------------------------------------------------------------------------------------------- /*Checks if a Rule, except for the #1 is not referenced, e.g.: * a::= b * b::="foo" * c ::= "bar" */ @Check def void checkUnusedRule(Rule rule) { var List references = EbnfAnalysisUtils.findReferences(rule); if ((references.size() == 0) && (rule.getRulenumber() != 1)) warning(unusedRuleDescription, EbnfPackage$Literals::RULE__NAME, unusedRuleDescription, rule.name); } // ---------------------------------------------------------------------------------------------------- /*Checks if a rule got two equal alternatives, e.g.: * a ::= b | "foo" | b *(Problem:ignores whitespaces in literals) */ @Check def void checkEqualAlternative(Rule rule) { var DefinitionList definitionList = rule.definitionList; var List singleDefinitions = definitionList.singleDefinition; for (sDef1 : singleDefinitions) { for (sDef2 : singleDefinitions) { if (!sDef1.equals(sDef2)) { var String d1 = NodeModelUtils.findActualNodeFor(sDef1).text.trim.replaceAll("[ \t\n\r]", ""); var String d2 = NodeModelUtils.findActualNodeFor(sDef2).text.trim.replaceAll("[ \t\n\r]", ""); if (d1.equals(d2)) warning(equalAlternativeDescription, EbnfPackage$Literals::RULE__NAME, equalAlternativeDescription, rule.name); } } } } // ---------------------------------------------------------------------------------------------------- /* Checks if a rule gets just passed through, e.g.: * a ::= b | "literal" * b ::= c * c ::= "foo.bar" */ @Check def void checkPassthroughRule(Rule rule) { var List references = EbnfAnalysisUtils.findReferences(rule); if (EbnfAnalysisUtils.isPassthroughRule(rule) && rule.rulenumber != 1) { if (references.size() == 0) { warning(unreferencedPassthroughRuleDescription, EbnfPackage$Literals::RULE__NAME); } else { warning(passthroughRuleDescription, EbnfPackage$Literals::RULE__NAME, passthroughRuleDescription, rule.name); } } } // ---------------------------------------------------------------------------------------------------- /* Checks if a subrule is used more then once, e.g.: * a ::= (a b) e * b ::= (a b) d * _____ * (Not working, under construction) */ // @Check // def void checkSubruleDuplicates(EtsiBnf bnf){ // var HashMap dupesMap = new HashMap(); // var Set taggedEntries = new HashSet(); // // var List allRules = EbnfAnalysisUtils.getAllRules(bnf); // // for(rule: allRules){ // var List subrules = rule.definitionList.singleDefinition // for(subrule:subrules){ // var String subruleText = NodeModelUtils.findActualNodeFor(subrule).text.trim.replaceAll("[ \t\n\r]", ""); // // } // } // } }