/* * 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.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 { static final String ruleReferencedOneDescription = "The rule is only referenced by one other rule"; static final String passthroughRuleDescription = "The rule is a passthrough rule"; static final String unreferencedPassthroughRuleDescription = "The rule is an unreferenced passthrough rule"; static final String unusedRuleDescription = "The rule is not referenced anywhere"; static final String equalAlternativeDescription = "The rule contains equal alternatives"; static final String duplicateRulesDescription = "The rule is a duplicate"; // static final String duplicateSubRulesDescription = "A part the of rule is a duplicate"; 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); } } // ---------------------------------------------------------------------------------------------------- /*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); } } } } // ---------------------------------------------------------------------------------------------------- /*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); } // ---------------------------------------------------------------------------------------------------- /*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); } } } } // ---------------------------------------------------------------------------------------------------- /* 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)) { if (references.size() == 0) { warning(unreferencedPassthroughRuleDescription, EbnfPackage$Literals::RULE__NAME); } else { warning(passthroughRuleDescription, EbnfPackage$Literals::RULE__NAME,passthroughRuleDescription); } } } // ---------------------------------------------------------------------------------------------------- /* 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]", ""); // // } // } // } }