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

Last change on this file since 17 was 17, checked in by zeiss, 14 years ago

sdfsd

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