package org.eclipse.dltk.itcl.internal.core.parser; import java.util.HashSet; import java.util.Set; import org.eclipse.dltk.ast.ASTNode; import org.eclipse.dltk.ast.declarations.FieldDeclaration; import org.eclipse.dltk.ast.declarations.MethodDeclaration; import org.eclipse.dltk.ast.declarations.ModuleDeclaration; import org.eclipse.dltk.ast.declarations.TypeDeclaration; import org.eclipse.dltk.ast.expressions.Expression; import org.eclipse.dltk.ast.references.SimpleReference; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.mixin.IMixinElement; import org.eclipse.dltk.core.mixin.IMixinRequestor; import org.eclipse.dltk.itcl.internal.core.IIncrTclModifiers; import org.eclipse.dltk.itcl.internal.core.classes.IncrTclClassesManager; import org.eclipse.dltk.itcl.internal.core.search.mixin.model.IncrTclClass; import org.eclipse.dltk.tcl.ast.TclStatement; import org.eclipse.dltk.tcl.core.ITclCommandDetector; import org.eclipse.dltk.tcl.core.ITclCommandDetectorExtension; import org.eclipse.dltk.tcl.core.ITclParser; import org.eclipse.dltk.tcl.core.TclParseUtil; import org.eclipse.dltk.tcl.internal.core.search.mixin.TclMixinModel; public class IncrTclCommandDetector implements ITclCommandDetector, ITclCommandDetectorExtension { private final static String[] itclCommands = new String[] { "class", "body", "code", "configbody", "delete", "ensemble", "find", "local", "scope" }; private String prefix = "itcl::"; private boolean runtimeModel = false; private Set names = new HashSet(); public static class IncrTclGlobalClassParameter { private String name; public IncrTclGlobalClassParameter(String name) { this.name = name; } public IModelElement resolveElement() { IMixinElement[] find = TclMixinModel .getInstance() .getMixin(null) .find( name.replaceAll("::", IMixinRequestor.MIXIN_NAME_SEPARATOR), 1000); if (find.length > 0) { for (int i = 0; i < find.length; i++) { Object[] allObjects = find[i].getAllObjects(); for (int j = 0; j < allObjects.length; j++) { if (allObjects[j] != null && allObjects[j] instanceof IncrTclClass) { IncrTclClass class_ = (IncrTclClass) allObjects[j]; return class_.getModelElement(); } } } } return null; } public String getClassName() { return this.name; } } public IncrTclCommandDetector() { } /** * 1) Detect of core itcl commands * * 2) Detect itcl class access * * 3) Detect itcl object creations * * 4) Detect itcl instances method access, etc. * */ public CommandInfo detectCommand(TclStatement statement, ModuleDeclaration module, ASTNode decl) { if (statement.getCount() == 0) { return null; } Expression commandName = statement.getAt(0); if (commandName instanceof SimpleReference) { String value = ((SimpleReference) commandName).getName(); for (int i = 0; i < itclCommands.length; i++) { if (itclCommands[i].equals(value) || (prefix + itclCommands[i]).equals(value) || ("::" + prefix + itclCommands[i]).equals(value)) { return new CommandInfo("#itcl#" + itclCommands[i], null); } } return checkInstanceOperations(module, decl, statement); } return null; } private CommandInfo checkInstanceOperations(ModuleDeclaration module, ASTNode parent, TclStatement statement) { if (runtimeModel) { return null; } Expression commandName = statement.getAt(0); if (!(commandName instanceof SimpleReference)) { return null; } String commandNameValue = ((SimpleReference) commandName).getName(); String[] names = null; names = TclParseUtil.tclSplit(commandNameValue); boolean found = false; for (int i = 0; i < names.length; i++) { if (this.names.contains(names[i])) { found = true; break; } } if (found) { TypeDeclaration type = TclParseUtil.findXOTclTypeDeclarationFrom( module, parent, commandNameValue); if (statement.getCount() == 1) { return null; } Expression arg = statement.getAt(1); if (type != null) { if (arg instanceof SimpleReference) { return check(type, (SimpleReference) arg); } } } // Lets check possibly this is method call for existing instance // variable. if (found) { FieldDeclaration variable = IncrTclParseUtil .findInstanceVariableDeclarationFrom(module, parent, commandNameValue); if (variable != null) { // Add support of procs etc. return new CommandInfo("#itcl#$methodCall", variable); } } // class list check operation. if (IncrTclClassesManager.getDefault().isClass(commandNameValue)) { IncrTclGlobalClassParameter param = new IncrTclGlobalClassParameter( commandNameValue); return new CommandInfo("#itcl#$newInstance", param); } return null; } private CommandInfo check(TypeDeclaration type, SimpleReference arg) { if ((type.getModifiers() & IIncrTclModifiers.AccIncrTcl) == 0) { return null; } // We need to understand what specified type has't contain method or // proc with argument name String value = arg.getName(); MethodDeclaration[] methods = type.getMethods(); for (int i = 0; i < methods.length; i++) { if ((methods[i].getModifiers() & IIncrTclModifiers.AccIncrTclProc) != 0) { if (methods[i].getName().equals(value)) { return new CommandInfo("#itcl#$methodCall", type); } } } // String value = ((SimpleReference) arg).getName(); return new CommandInfo("#itcl#$newInstance", type); } public void setBuildRuntimeModelFlag(boolean value) { this.runtimeModel = value; } public void processASTNode(ASTNode node) { String name = null; if (node instanceof FieldDeclaration) { FieldDeclaration decl = (FieldDeclaration) node; name = decl.getName(); } else if (node instanceof TypeDeclaration) { TypeDeclaration decl = (TypeDeclaration) node; name = decl.getName(); } if (name != null) { String[] names = null; names = TclParseUtil.tclSplit(name); for (int i = 0; i < names.length; i++) { this.names.add(names[i]); } } } }