1 package org.antlr.works.editor; 2 3 import org.antlr.works.ate.syntax.generic.ATESyntaxLexer; 4 import org.antlr.works.ate.syntax.misc.ATEToken; 5 import org.antlr.works.grammar.RefactorEngine; 6 import org.antlr.works.grammar.decisiondfa.DecisionDFAEngine; 7 import org.antlr.works.idea.IdeaAction; 8 import org.antlr.works.syntax.GrammarSyntax; 9 import org.antlr.works.syntax.element.ElementGrammarName; 10 import org.antlr.works.syntax.element.ElementReference; 11 import org.antlr.works.syntax.element.ElementRule; 12 import org.antlr.works.syntax.element.ElementToken; 13 import org.antlr.xjlib.foundation.XJUtils; 14 15 import java.awt.*; 16 import java.util.ArrayList ; 17 import java.util.List ; 18 import java.util.Set ; 19 49 50 public class EditorInspector { 51 52 private GrammarSyntax syntax; 53 private DecisionDFAEngine decisionDFAEngine; 54 private InspectorDelegate delegate; 55 56 public EditorInspector(GrammarSyntax syntax, DecisionDFAEngine decisionDFAEngine, InspectorDelegate delegate) { 57 this.syntax = syntax; 58 this.decisionDFAEngine = decisionDFAEngine; 59 this.delegate = delegate; 60 } 61 62 public List <EditorInspectorItem> getErrors() { 63 List <EditorInspectorItem> errors = new ArrayList <EditorInspectorItem>(); 64 discoverInvalidGrammarName(errors); 65 discoverInvalidCharLiteralTokens(errors); 66 discoverUndefinedReferences(errors); 67 discoverDuplicateRules(errors); 68 return errors; 69 } 70 71 public List <EditorInspectorItem> getWarnings() { 72 List <EditorInspectorItem> warnings = new ArrayList <EditorInspectorItem>(); 73 discoverLeftRecursionRules(warnings); 74 discoverLeftRecursiveRulesSet(warnings); 75 return warnings; 76 } 77 78 public List <EditorInspectorItem> getDecisionDFAs() { 79 List <EditorInspectorItem> items = new ArrayList <EditorInspectorItem>(); 80 discoverDecisionDFAs(items); 81 return items; 82 } 83 84 protected List <EditorInspectorItem> getAllItemsAtIndex(int index) { 85 List <EditorInspectorItem> items = new ArrayList <EditorInspectorItem>(); 86 items.addAll(getItemsAtIndex(getErrors(), index)); 87 items.addAll(getItemsAtIndex(getWarnings(), index)); 88 items.addAll(getItemsAtIndex(getDecisionDFAs(), index)); 89 return items; 90 } 91 92 protected List <EditorInspectorItem> getItemsAtIndex(List <EditorInspectorItem> items, int index) { 93 List <EditorInspectorItem> filteredItems = new ArrayList <EditorInspectorItem>(); 94 for (EditorInspectorItem item : items) { 95 if (index >= item.startIndex && index <= item.endIndex) 96 filteredItems.add(item); 97 } 98 return filteredItems; 99 } 100 101 protected void discoverInvalidGrammarName(List <EditorInspectorItem> items) { 102 ElementGrammarName n = getGrammarName(); 103 String grammarFileName = getGrammarNameFromFile(); 104 if(n != null && grammarFileName != null && !grammarFileName.equals(n.getName())) { 105 ATEToken t = n.name; 106 EditorInspectorItem item = new ItemInvalidGrammarName(); 107 item.setAttributes(t, t.getStartIndex(), t.getEndIndex(), 108 t.startLineNumber, Color.red, 109 "Invalid grammar name '"+t.getAttribute()+"'"); 110 items.add(item); 111 } 112 } 113 114 private ElementGrammarName getGrammarName() { 115 return syntax.getParserEngine().getName(); 116 } 117 118 private String getGrammarNameFromFile() { 119 String filename = delegate.getFileName(); 120 if(filename == null) { 121 return null; 122 } 123 return XJUtils.getPathByDeletingPathExtension(filename); 124 } 125 126 protected void discoverInvalidCharLiteralTokens(List <EditorInspectorItem> items) { 127 List <ATEToken> tokens = syntax.getParserEngine().getTokens(); 128 if(tokens == null) 129 return; 130 131 for (ATEToken t : tokens) { 132 if (t.type == ATESyntaxLexer.TOKEN_DOUBLE_QUOTE_STRING) { 133 if (RefactorEngine.ignoreScopeForDoubleQuoteLiteral(t.scope)) continue; 134 135 EditorInspectorItem item = new ItemInvalidCharLiteral(); 136 item.setAttributes(t, t.getStartIndex(), t.getEndIndex(), 137 t.startLineNumber, Color.red, 138 "Invalid character literal '" + t.getAttribute() + "' - must use single quote"); 139 items.add(item); 140 } 141 } 142 } 143 144 protected void discoverUndefinedReferences(List <EditorInspectorItem> items) { 145 List <ElementReference> undefinedRefs = syntax.getUndefinedReferences(); 146 if(undefinedRefs == null) 147 return; 148 149 for (ElementReference ref : undefinedRefs) { 150 EditorInspectorItem item = new ItemUndefinedReference(); 151 item.setAttributes(ref.token, ref.token.getStartIndex(), ref.token.getEndIndex(), 152 ref.token.startLineNumber, Color.red, 153 "Undefined reference \"" + ref.token.getAttribute() + "\""); 154 items.add(item); 155 } 156 } 157 158 protected void discoverDuplicateRules(List <EditorInspectorItem> items) { 159 List <ElementRule> rules = syntax.getDuplicateRules(); 160 if(rules == null) 161 return; 162 163 for (ElementRule rule : rules) { 164 EditorInspectorItem item = new ItemDuplicateRule(); 165 item.setAttributes(rule.start, rule.start.getStartIndex(), rule.start.getEndIndex(), 166 rule.start.startLineNumber, Color.red, 167 "Duplicate rule \"" + rule.name + "\""); 168 items.add(item); 169 } 170 } 171 172 protected void discoverLeftRecursionRules(List <EditorInspectorItem> items) { 173 List <ElementRule> rules = syntax.getParserEngine().getRules(); 174 if(rules == null) 175 return; 176 177 for (ElementRule rule : rules) { 178 if (!rule.hasLeftRecursion()) 179 continue; 180 181 EditorInspectorItem item = new ItemLeftRecursion(); 182 item.setAttributes(rule.start, rule.start.getStartIndex(), rule.start.getEndIndex(), 183 rule.start.startLineNumber, Color.blue, 184 "Rule \"" + rule.name + "\" is left-recursive"); 185 items.add(item); 186 } 187 } 188 189 protected void discoverLeftRecursiveRulesSet(List <EditorInspectorItem> items) { 190 List <ElementRule> rules = syntax.getParserEngine().getRules(); 191 if(rules == null) 192 return; 193 194 for (ElementRule rule : rules) { 195 Set rulesSet = rule.getLeftRecursiveRulesSet(); 196 if (rulesSet == null || rulesSet.size() < 2) 197 continue; 198 199 EditorInspectorItem item = new EditorInspectorItem(); 200 item.setAttributes(rule.start, rule.start.getStartIndex(), rule.start.getEndIndex(), 201 rule.start.startLineNumber, Color.blue, 202 "Rule \"" + rule.name + "\" is mutually left-recursive with other rules (see Console)"); 203 items.add(item); 204 } 205 } 206 207 protected void discoverDecisionDFAs(List <EditorInspectorItem> items) { 208 items.addAll(decisionDFAEngine.getDecisionDFAItems()); 209 } 210 211 public class ItemUndefinedReference extends EditorInspectorItem { 212 213 public List <IdeaAction> getIdeaActions() { 214 List <IdeaAction> actions = new ArrayList <IdeaAction>(); 215 actions.add(new IdeaAction("Create rule '"+token.getAttribute()+"'", this, IDEA_CREATE_RULE, token)); 216 return actions; 217 } 218 219 public void ideaActionFire(IdeaAction action, int actionID) { 220 switch(actionID) { 221 case IDEA_CREATE_RULE: 222 delegate.createRuleAtIndex(((ElementToken)action.token).lexer, action.token.getAttribute(), null); 223 break; 224 } 225 } 226 227 } 228 229 public class ItemDuplicateRule extends EditorInspectorItem { 230 231 public List <IdeaAction> getIdeaActions() { 232 List <IdeaAction> actions = new ArrayList <IdeaAction>(); 233 actions.add(new IdeaAction("Delete rule '"+token.getAttribute()+"'", this, IDEA_DELETE_RULE, token)); 234 return actions; 235 } 236 237 public void ideaActionFire(IdeaAction action, int actionID) { 238 switch(actionID) { 239 case IDEA_DELETE_RULE: 240 delegate.deleteRuleAtCurrentPosition(); 241 break; 242 } 243 } 244 } 245 246 public class ItemLeftRecursion extends EditorInspectorItem { 247 248 public List <IdeaAction> getIdeaActions() { 249 List <IdeaAction> actions = new ArrayList <IdeaAction>(); 250 actions.add(new IdeaAction("Remove left recursion of rule '"+token.getAttribute()+"'", this, IDEA_REMOVE_LEFT_RECURSION, token)); 251 return actions; 252 } 253 254 public void ideaActionFire(IdeaAction action, int actionID) { 255 switch(actionID) { 256 case IDEA_REMOVE_LEFT_RECURSION: 257 delegate.removeLeftRecursion(); 258 break; 259 } 260 } 261 } 262 263 public class ItemInvalidCharLiteral extends EditorInspectorItem { 264 265 public List <IdeaAction> getIdeaActions() { 266 List <IdeaAction> actions = new ArrayList <IdeaAction>(); 267 actions.add(new IdeaAction("Convert literals to single quote", this, IDEA_CONVERT_TO_SINGLE_QUOTE, token)); 268 return actions; 269 } 270 271 public void ideaActionFire(IdeaAction action, int actionID) { 272 switch(actionID) { 273 case IDEA_CONVERT_TO_SINGLE_QUOTE: 274 delegate.convertLiteralsToSingleQuote(); 275 break; 276 } 277 } 278 } 279 280 public class ItemInvalidGrammarName extends EditorInspectorItem { 281 282 public List <IdeaAction> getIdeaActions() { 283 List <IdeaAction> actions = new ArrayList <IdeaAction>(); 284 actions.add(new IdeaAction("Change grammar name to '"+getGrammarNameFromFile()+"'", this, IDEA_FIX_GRAMMAR_NAME, token)); 285 return actions; 286 } 287 288 public void ideaActionFire(IdeaAction action, int actionID) { 289 switch(actionID) { 290 case IDEA_FIX_GRAMMAR_NAME: 291 ElementGrammarName n = getGrammarName(); 292 ATEToken name = n.name; 293 delegate.replaceText(name.start, name.end, getGrammarNameFromFile()); 294 break; 295 } 296 } 297 } 298 299 } 300 | Popular Tags |