source: default/trunk/de.ugoe.cs.swe.bnftools.ebnf/src/de/ugoe/cs/swe/bnftools/validation/EbnfJavaValidator.java @ 19

Last change on this file since 19 was 19, checked in by zeiss, 14 years ago
  • Property svn:mime-type set to text/plain
File size: 12.4 KB
Line 
1package de.ugoe.cs.swe.bnftools.validation;
2
3import java.util.ArrayList;
4import java.util.List;
5
6import org.eclipse.emf.common.util.EList;
7import org.eclipse.emf.common.util.URI;
8import org.eclipse.emf.ecore.resource.Resource;
9import org.eclipse.xtext.parsetree.AbstractNode;
10import org.eclipse.xtext.parsetree.CompositeNode;
11import org.eclipse.xtext.parsetree.LeafNode;
12import org.eclipse.xtext.parsetree.NodeUtil;
13import org.eclipse.xtext.resource.IResourceDescriptions;
14import org.eclipse.xtext.resource.XtextResource;
15import org.eclipse.xtext.resource.XtextResourceSet;
16import org.eclipse.xtext.validation.Check;
17import org.eclipse.xtext.validation.CheckType;
18
19import com.google.inject.Inject;
20
21import de.ugoe.cs.swe.bnftools.analysis.EbnfAnalysisUtils;
22import de.ugoe.cs.swe.bnftools.ebnf.BnfEntry;
23import de.ugoe.cs.swe.bnftools.ebnf.DefinitionList;
24import de.ugoe.cs.swe.bnftools.ebnf.EtsiBnf;
25import de.ugoe.cs.swe.bnftools.ebnf.ExtRule;
26import de.ugoe.cs.swe.bnftools.ebnf.Import;
27import de.ugoe.cs.swe.bnftools.ebnf.Rule;
28import de.ugoe.cs.swe.bnftools.ebnf.SingleDefinition;
29
30public class EbnfJavaValidator extends AbstractEbnfJavaValidator {
31
32        @Inject
33        IResourceDescriptions resourceDescriptions;
34
35        public static final String ruleReferencedOneDescription = "The rule is only referenced by one other rule";
36        public static final String passthroughRuleDescription = "The rule is a passthrough rule";
37        public static final String unreferencedPassthroughRuleDescription = "The rule is an unreferenced passthrough rule";
38        public static final String unusedRuleDescription = "The rule is not referenced anywhere";
39        public static final String equalAlternativeDescription = "The rule contains equal alternatives";
40        public static final String duplicateRulesDescription = "The rule is a duplicate";
41        public static final String duplicateSubRulesDescription = "A part of rule is a duplicate";
42        public static final String packageConsistencyCheckRuleMissingDescription = "Rule has been removed or renamed in the updated grammar. The package rule is therefore now an additional rule instead of a replacement rule. The package rule might therefore be inconsistent with the updated core grammar.";
43        public static final String packageConsistencyCheckRuleDifferentDescription = "Corresponding core grammar rule has been changed in updated grammar. The package rule might have become inconsistent with the updated core grammar.";
44        public static final String packageConsistencyCheckCorrespondingRuleMissingDescription = "Corresponding rule is missing in core grammar. Rule has been manually altered in the delta grammar (delta grammar is outdated) or the /core and /update flags are somehow switched.";
45
46        public static boolean checkReferencedOnlyOnce = false;
47        public static boolean checkPassthroughRule = false;
48        public static boolean checkUnusedRule = false;
49        public static boolean checkEqualAlternative = false;
50        public static boolean checkDuplicateRules = false;
51        public static boolean checkSubruleDuplicates = false;
52        public static boolean checkUpdatedGrammarConsistency = false;
53
54        // ----------------------------------------------------------------------------------------------------
55
56        @Check(CheckType.EXPENSIVE)
57        public void checkUpdateGrammarConsistency(EtsiBnf bnf) {
58                if (!checkUpdatedGrammarConsistency)
59                        return;
60
61                CompositeNode compNode = NodeUtil.getRootNode(bnf);
62                XtextResourceSet set = new XtextResourceSet();
63                URI uri = compNode.getElement().eResource().getURI();
64                Iterable<AbstractNode> allNodes = NodeUtil.getAllContents(compNode);
65                if(!bnf.getType().equals("/delta"))
66                        return;
67               
68                Resource coreRes = null;
69                Resource updatedRes = null;
70                EList<Import> imports = bnf.getImportSection().getImports();
71
72                for(int j=0; j<imports.size(); j++) {
73                        if(imports.get(j).getGrammarType().equals("core")) {
74                                String packageUri = uri.trimSegments(1).toPlatformString(true);
75                                String fullUri = packageUri + "/" +imports.get(j).getImportURI();
76                                coreRes= set.getResource( URI.createPlatformResourceURI(fullUri, true), true);
77                        }
78                        if(imports.get(j).getGrammarType().equals("update")) {
79                                String packageUri = uri.trimSegments(1).toPlatformString(true);
80                                String fullUri = packageUri + "/" +imports.get(j).getImportURI();
81                                updatedRes= set.getResource( URI.createPlatformResourceURI(fullUri, true), true);
82                        }
83                }
84               
85                if( (coreRes==null) || (updatedRes==null))
86                        return;
87
88                XtextResource coreResource = null;
89                XtextResource updatedResource = null;
90
91                if(coreRes instanceof XtextResource)
92                        coreResource = (XtextResource) coreRes;
93                if(updatedRes instanceof XtextResource)
94                        updatedResource = (XtextResource) updatedRes;
95
96                /*
97                 * the idea: get the core grammar and the updated grammar
98                 * for each extension rule in the delta grammar,
99                 *              find the corresponding rule in the updated grammar and the core grammar
100                 *              if it doesn't exist in the updated grammar write the inconsistency
101                 *              if it exists, compare to the rule in the core grammar
102                 */
103                for(AbstractNode node: allNodes) {
104                        if(node.getElement() instanceof ExtRule) {
105                                checkForConsistency(node, coreResource, updatedResource, compNode);
106                        }
107                }
108        }
109       
110        private boolean checkForConsistency(AbstractNode node, XtextResource coreResource, XtextResource updatedResource, CompositeNode compNode) {
111                //updated grammar:
112                AbstractNode updatedRule = null;
113                AbstractNode coreRule = null;
114                Rule currentRule = null;
115                for(AbstractNode uNode : NodeUtil.getAllContents(updatedResource.getParseResult().getRootNode())) {
116                        if (uNode.getElement() instanceof Rule) {
117                                currentRule  = (Rule) uNode.getElement();
118                                if (currentRule.getName().equals(((ExtRule) node.getElement()).getName())) {
119                                        updatedRule = uNode;
120                                        break;
121                                }
122                        }
123                }
124               
125                if(updatedRule == null) {
126                        warning(EbnfJavaValidator.packageConsistencyCheckRuleMissingDescription, node.getElement(), 1);
127                        return false;
128                } else { //core grammar
129                        for(AbstractNode cNode : NodeUtil.getAllContents(coreResource.getParseResult().getRootNode())) {
130                                if(cNode.getElement() instanceof Rule)
131                                        if(((Rule) cNode.getElement()).getName().equals(((ExtRule) node.getElement()).getName())) {
132                                                coreRule = cNode;
133                                                break;
134                                        }
135                        }
136                       
137                        if(coreRule == null){
138                                warning(EbnfJavaValidator.packageConsistencyCheckCorrespondingRuleMissingDescription, node.getElement(), 1);
139                                return false;
140                        }
141                       
142                        if (compareRules(coreRule, updatedRule)) {
143                                return true;
144                        } else {
145                                warning(EbnfJavaValidator.packageConsistencyCheckRuleDifferentDescription, node.getElement(), 1);
146                                return false;
147                        }
148                       
149                }
150        }
151
152        // returns true, if the rules are equal
153        private boolean compareRules(AbstractNode cNode, AbstractNode uNode) {
154                EList<LeafNode> cLeaves = removeWS(cNode.getLeafNodes());
155                EList<LeafNode> uLeaves = removeWS(uNode.getLeafNodes());
156                if (cLeaves.size() != uLeaves.size())
157                        return false;
158               
159                for(int i=0; i < cLeaves.size(); i++) {
160                        if(!(cLeaves.get(i).serialize().equals(uLeaves.get(i).serialize())))
161                                return false;
162                       
163                }
164                return true;
165        }
166
167        private EList<LeafNode> removeWS(EList<LeafNode> leaves) {
168                for(int i=0; i < leaves.size(); i++) {
169                        if(!(leaves.get(i).getGrammarElement() instanceof org.eclipse.xtext.impl.TerminalRuleImpl))
170                                leaves.remove(i);
171                }
172                return leaves;
173        }
174       
175        // ----------------------------------------------------------------------------------------------------
176
177        @Check(CheckType.EXPENSIVE)
178        public void checkReferencedOnlyOnce(Rule rule) {
179                if (!checkReferencedOnlyOnce)
180                        return;
181
182                if (EbnfAnalysisUtils.isTokenRule(rule))
183                        return;
184
185                List<Rule> references = EbnfAnalysisUtils.findReferences(rule,
186                                resourceDescriptions);
187
188                if (references.size() == 1) {
189                        warning(EbnfJavaValidator.ruleReferencedOneDescription, 1,
190                                        EbnfJavaValidator.ruleReferencedOneDescription);
191                }
192        }
193
194        // ----------------------------------------------------------------------------------------------------
195
196        @Check(CheckType.EXPENSIVE)
197        public void checkPassthroughRule(Rule rule) {
198                if (!checkPassthroughRule)
199                        return;
200
201                List<Rule> references = EbnfAnalysisUtils.findReferences(rule,
202                                resourceDescriptions);
203
204                if (EbnfAnalysisUtils.isPassthroughRule(rule)) {
205                        if (references.size() == 0) {
206                                warning(
207                                                EbnfJavaValidator.unreferencedPassthroughRuleDescription,
208                                                1,
209                                                EbnfJavaValidator.unreferencedPassthroughRuleDescription);
210                        } else {
211                                warning(EbnfJavaValidator.passthroughRuleDescription, 1,
212                                                EbnfJavaValidator.passthroughRuleDescription);
213                        }
214                }
215        }
216
217        // ----------------------------------------------------------------------------------------------------
218
219        @Check(CheckType.EXPENSIVE)
220        public void checkUnusedRule(Rule rule) {
221                if (!checkUnusedRule)
222                        return;
223
224                List<Rule> references = EbnfAnalysisUtils.findReferences(rule,
225                                resourceDescriptions);
226
227                if ((references.size() == 0) && (rule.getRulenumber() != 1))
228                        warning(EbnfJavaValidator.unusedRuleDescription, 1,
229                                        EbnfJavaValidator.unusedRuleDescription);
230        }
231
232        // ----------------------------------------------------------------------------------------------------
233
234        private List<DefinitionList> collectDefinitionLists(CompositeNode o) {
235                List<DefinitionList> list = new ArrayList<DefinitionList>();
236
237                for (int i = 0; i < o.getChildren().size(); i++) {
238                        AbstractNode child = o.getChildren().get(i);
239                        if (child.getElement() instanceof DefinitionList) {
240                                list.add((DefinitionList) child.getElement());
241                        }
242
243                        if (child instanceof CompositeNode) {
244                                list.addAll(collectDefinitionLists((CompositeNode) child));
245                        }
246                }
247
248                return list;
249        }
250
251        // ----------------------------------------------------------------------------------------------------
252
253        @Check(CheckType.EXPENSIVE)
254        public void checkEqualAlternative(Rule rule) {
255                if (!checkEqualAlternative)
256                        return;
257
258                // TODO: is not per rule, but global!
259
260                // quadratic!
261                CompositeNode startNode = NodeUtil.getNodeAdapter(rule).getParserNode();
262
263                List<DefinitionList> definitionLists = collectDefinitionLists(startNode);
264
265                for (int k = 0; k < definitionLists.size(); k++) {
266
267                        EList<SingleDefinition> singleDefinitions = definitionLists.get(k)
268                                        .getSingleDefinition();
269                        for (int i = 0; i < singleDefinitions.size(); i++) {
270                                for (int j = 0; j < singleDefinitions.size(); j++) {
271                                        if (i == j)
272                                                continue;
273
274                                        SingleDefinition upper = singleDefinitions.get(i);
275                                        SingleDefinition lower = singleDefinitions.get(j);
276                                        CompositeNode upperNode = NodeUtil.getNodeAdapter(upper)
277                                                        .getParserNode();
278                                        CompositeNode lowerNode = NodeUtil.getNodeAdapter(lower)
279                                                        .getParserNode();
280
281                                        String upperString = upperNode.serialize().trim()
282                                                        .replaceAll("[ \t\n\r]", "");
283                                        String lowerString = lowerNode.serialize().trim()
284                                                        .replaceAll("[ \t\n\r]", "");
285
286                                        if (lowerString.equals(upperString))
287                                                warning(EbnfJavaValidator.equalAlternativeDescription,
288                                                                1,
289                                                                EbnfJavaValidator.equalAlternativeDescription);
290                                }
291                        }
292                }
293
294        }
295
296        // ----------------------------------------------------------------------------------------------------
297
298        @Check(CheckType.EXPENSIVE)
299        public void checkDuplicateRules(Rule rule) {
300                if (!checkDuplicateRules)
301                        return;
302
303                EtsiBnf etsiBnfNode = (EtsiBnf) rule.eContainer().eContainer();
304               
305                CompositeNode definitionList = NodeUtil.getNodeAdapter(rule.getDefinitionList()).getParserNode();
306               
307                String rightHandSideText = definitionList.serialize().trim()
308                                .replaceAll("[ \t\n\r]", "");
309
310                for (int i = 0; i < etsiBnfNode.getBnfEntry().size(); i++) {
311                        BnfEntry currentNode = etsiBnfNode.getBnfEntry().get(i);
312                        if (currentNode == null)
313                                continue;
314                        if (currentNode.getRule() == null)
315                                continue;
316                        if (currentNode.getRule() == rule)
317                                continue;
318
319                        Rule currentRule = currentNode.getRule();
320                        CompositeNode currentRuleDefinitionList = NodeUtil.getNodeAdapter(currentRule.getDefinitionList()).getParserNode();
321                        String currentRuleRightHandSideText = currentRuleDefinitionList.serialize().trim()
322                        .replaceAll("[ \t\n\r]", "");
323
324                        if (currentRuleRightHandSideText.equals(rightHandSideText)) {
325                                        String description = EbnfJavaValidator.duplicateRulesDescription
326                                                        + " with rule \""
327                                                        + currentRule.getName()
328                                                        + "\" (Line "
329                                                        + NodeUtil.getNodeAdapter(currentRule).getParserNode().getLine() + ")";
330                                        warning(description, 1, description);
331                                }
332                        }
333        }
334       
335        // ----------------------------------------------------------------------------------------------------
336       
337        @Check(CheckType.EXPENSIVE)
338        public void checkSubruleDuplicates(Rule rule) {
339                if (!checkSubruleDuplicates)
340                        return;
341
342                //TODO: currently compares complete rules and not subrules
343               
344        }
345       
346}
Note: See TracBrowser for help on using the repository browser.