package org.eclipse.dltk.xotcl.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.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.tcl.ast.TclStatement;
import org.eclipse.dltk.tcl.core.ITclCommandDetector;
import org.eclipse.dltk.tcl.core.ITclCommandDetectorExtension;
import org.eclipse.dltk.tcl.core.TclParseUtil;
import org.eclipse.dltk.xotcl.core.IXOTclModifiers;
import org.eclipse.dltk.xotcl.core.XOTclParseUtil;
import org.eclipse.dltk.xotcl.core.ast.xotcl.XOTclObjectDeclaration;
import org.eclipse.dltk.xotcl.internal.core.XOTclKeywords;
import org.eclipse.dltk.xotcl.internal.core.search.mixin.model.XOTclClass;
public class XOTclCommandDetector implements ITclCommandDetector,
ITclCommandDetectorExtension {
// Options
public static boolean INTERPRET_CLASS_UNKNOWN_AS_CREATE = true;
public static boolean INTERPRET_OBJECT_UNKNOWN_AS_CREATE = true;
private boolean runtimeModel = false;
private Set names = new HashSet();
public static class XOTclGlobalClassParameter {
private String name;
public XOTclGlobalClassParameter(String name) {
this.name = name;
}
public IModelElement resolveElement() {
XOTclClass e = XOTclMixinUtils.findMixinElement(name, null);
if (e != null) {
return e.getModelElement();
}
return null;
}
public String getClassName() {
return this.name;
}
}
public XOTclCommandDetector() {
}
public CommandInfo detectCommand(TclStatement statement,
ModuleDeclaration module, ASTNode parent) {
if (statement.getCount() == 0) {
return null;
}
Expression commandName = statement.getAt(0);
if (commandName instanceof SimpleReference) {
String value = ((SimpleReference) commandName).getName();
if (value.equals("Class") || value.equals("::xotcl::Class")
|| value.equals("xotcl::Class")) {
return checkClass(statement, module, parent);
} else if (value.equals("Object")
|| value.equals("::xotcl::Object")
|| value.equals("xotcl::Object")) {
return checkObject(statement, module, parent);
} else {
return checkInstanceOperations(module, parent, statement);
}
}
return null;
}
private CommandInfo checkInstanceOperations(ModuleDeclaration module,
ASTNode parent, TclStatement statement) {
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 (statement.getCount() == 1) {
return null;
}
Expression arg = statement.getAt(1);
if (found) {
TypeDeclaration type = TclParseUtil.findXOTclTypeDeclarationFrom(
module, parent, commandNameValue);
if (type != null) {
if (arg instanceof SimpleReference) {
return check(type, (SimpleReference) arg);
}
}
// Find Object instance
XOTclObjectDeclaration decl = XOTclParseUtil
.findXOTclObjectInstanceFrom(module, parent,
commandNameValue);
if (decl != null) {
if (arg instanceof SimpleReference) {
String value = ((SimpleReference) arg).getName();
if (value.equals("proc")) {
return new CommandInfo("#Class#proc", decl);
}
}
// Method call
return new CommandInfo("#Class#$ProcCall", type);
}
}
// Lets check possibly this is method call for existing instance
// variable.
if (found) {
FieldDeclaration variable = XOTclParseUtil
.findXOTclInstanceVariableDeclarationFrom(module, parent,
commandNameValue);
if (variable != null) {
// Add support of procs etc.
return new CommandInfo("#Class#$MethodCall", variable);
}
}
// Class instance field declaration
if (statement.getCount() < 3) {
return null;
}
if (!(arg instanceof SimpleReference)) {
return null;
}
String argumentValue = ((SimpleReference) arg).getName();
if (commandNameValue.length() >= 3) {
if (commandNameValue.startsWith("::")) {
commandNameValue = commandNameValue.substring(2);
}
boolean isUpper = Character.isUpperCase(commandNameValue.charAt(0));
if (commandNameValue.indexOf("::") > 0 || isUpper) {
if (argumentValue.equals("create")) {
XOTclGlobalClassParameter param = new XOTclGlobalClassParameter(
commandNameValue);
return new CommandInfo("#Class#$newInstance", param);
}
}
}
return null;
}
private CommandInfo check(TypeDeclaration type, SimpleReference arg) {
if ((type.getModifiers() & IXOTclModifiers.AccXOTcl) == 0) {
return null;
}
String value = arg.getName();
if (!value.equals("create")) {
CommandInfo info = checkCommands(value, type);
if (info != null) {
return info;
}
} else {
return new CommandInfo("#Class#$newInstance", type);
}
return new CommandInfo("#Class#$ProcCall", type);
}
private CommandInfo checkCommands(String value, Object decl) {
CommandInfo info = checkClassOperator(decl, value,
XOTclKeywords.XOTclCommandClassArgs, "#Class#");
if (info != null) {
return info;
}
info = checkClassOperator(decl, value,
XOTclKeywords.XOTclCommandObjectArgs, "#Object#");
if (info != null) {
return info;
}
return null;
}
private CommandInfo checkClassOperator(Object type, String value,
String[] commands, String prefix) {
for (int q = 0; q < commands.length; q++) {
if (value.equals(commands[q])) {
return new CommandInfo(prefix + value, type);
}
}
return null;
}
private CommandInfo checkClass(TclStatement statement,
ModuleDeclaration module, ASTNode parent) {
Expression arg = statement.getAt(1);
if (arg instanceof SimpleReference) {
String value = ((SimpleReference) arg).getName();
if (true) {// !runtimeModel
TypeDeclaration type = TclParseUtil
.findXOTclTypeDeclarationFrom(module, parent, "Class");
// if (type != null) {
for (int i = 0; i < XOTclKeywords.XOTclCommandClassArgs.length; i++) {
if (value.equals(XOTclKeywords.XOTclCommandClassArgs[i])) {
return new CommandInfo("#Class#" + value, type);
}
}
// }
}
CommandInfo info = checkCreateType(statement, parent, arg, value);
if (info != null) {
return info;
}
// Else unknown command or create command.
if (INTERPRET_CLASS_UNKNOWN_AS_CREATE) {
return new CommandInfo("#Class#create", null);
}
return null;
}
return null;
}
private CommandInfo checkObject(TclStatement statement,
ModuleDeclaration module, ASTNode parent) {
Expression arg = statement.getAt(1);
if (arg instanceof SimpleReference) {
String value = ((SimpleReference) arg).getName();
TypeDeclaration type = TclParseUtil.findXOTclTypeDeclarationFrom(
module, parent, "Object");
// if (type != null) {
for (int i = 0; i < XOTclKeywords.XOTclCommandObjectArgs.length; i++) {
if (value.equals(XOTclKeywords.XOTclCommandObjectArgs[i])) {
return new CommandInfo("#Object#" + value, type);
}
}
// }
CommandInfo info = checkCreateType(statement, parent, arg, value);
if (info != null) {
return info;
}
// // Else unknown command or create command.
if (INTERPRET_OBJECT_UNKNOWN_AS_CREATE) {
return new CommandInfo("#Object#create", null);
}
return null;
}
return null;
}
private CommandInfo checkCreateType(TclStatement statement, ASTNode parent,
Expression arg, String value) {
if (value.equals("instproc") || value.equals("proc")
|| value.equals("set")) {
String name = TclParseUtil.getNameFromNode(statement.getAt(0));
TypeDeclaration decl = createTypeAdd(statement, parent, statement
.getAt(0), name);
CommandInfo info = checkCommands(value, decl);
if (info != null) {
return info;
}
}
return null;
}
private TypeDeclaration createTypeAdd(TclStatement statement,
ASTNode parent, Expression arg, String value) {
TypeDeclaration decl = new TypeDeclaration(value, arg.sourceStart(),
arg.sourceEnd(), arg.sourceStart(), arg.sourceEnd());
TclParseUtil.addToDeclaration(parent, decl);
return decl;
}
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;
if (name.startsWith("::")) {
names = name.substring(2).split("::");
} else {
names = name.split("::");
}
for (int i = 0; i < names.length; i++) {
this.names.add(names[i]);
}
}
}
}