/*******************************************************************************
* Copyright (c) 2009 xored software, Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.tcl.structure;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.dltk.ast.Modifiers;
import org.eclipse.dltk.compiler.IElementRequestor.FieldInfo;
import org.eclipse.dltk.compiler.IElementRequestor.MethodInfo;
import org.eclipse.dltk.compiler.ISourceElementRequestor;
import org.eclipse.dltk.compiler.problem.ProblemSeverity;
import org.eclipse.dltk.compiler.util.Util;
import org.eclipse.dltk.tcl.ast.Node;
import org.eclipse.dltk.tcl.ast.StringArgument;
import org.eclipse.dltk.tcl.ast.TclArgument;
import org.eclipse.dltk.tcl.ast.TclArgumentList;
import org.eclipse.dltk.tcl.ast.TclCommand;
import org.eclipse.dltk.tcl.ast.TclConstants;
import org.eclipse.dltk.tcl.core.TclParseUtil;
import org.eclipse.dltk.tcl.internal.core.codeassist.TclVisibilityUtils;
import org.eclipse.dltk.tcl.parser.TclParser;
import org.eclipse.dltk.tcl.parser.printer.SimpleCodePrinter;
import org.eclipse.emf.common.util.EList;
/**
* @since 2.0
*/
public abstract class AbstractTclCommandModelBuilder extends
TclModelBuilderUtil implements ITclModelBuilder {
protected static abstract class FieldInitializer {
public abstract void initialize(FieldInfo info);
}
/**
* @param node
* @param message
* @param severity
*/
protected void report(ITclModelBuildContext context, Node node,
String message, ProblemSeverity severity) {
// TODO Auto-generated method stub
}
protected void processField(TclCommand command, TclArgument nameArg,
String varName, final int modifiers, ITclModelBuildContext context) {
processField(command, nameArg, varName, modifiers, context, null, null);
}
protected void processField(TclCommand command, TclArgument nameArg,
String varName, final int modifiers, ITclModelBuildContext context,
ITclTypeHandler exit, FieldInitializer initializer) {
if (varName == null) {
varName = asSymbol(nameArg);
}
FieldInfo fi = new FieldInfo();
fi.nameSourceStart = nameArg.getStart();
fi.nameSourceEnd = nameArg.getEnd() - 1;
fi.declarationStart = fi.nameSourceStart;
fi.modifiers = modifiers;
String arrayIndex = null;
if (TclParseUtil.isArrayVariable(varName)) {
arrayIndex = TclParseUtil.extractArrayIndex(varName);
varName = TclParseUtil.extractArrayName(varName);
}
fi.name = varName;
if (initializer != null) {
initializer.initialize(fi);
}
String fullName = TclParseUtil.escapeName(varName);
// TODO for (int i = 0; i < extensions.length; i++) {
// if ((exit = extensions[i].processField(decl, this)) != null) {
// continue;
// }
// }
if (exit == null) {
exit = context.get(ITclTypeResolver.class).resolveMemberType(fi,
command.getEnd(), fullName);
}
boolean needExit = context.getRequestor().enterFieldCheckDuplicates(fi);
if (needExit) {
if (arrayIndex != null) {
ISourceElementRequestor.FieldInfo fiIndex = new ISourceElementRequestor.FieldInfo();
fiIndex.name = varName + "(" + arrayIndex + ")";
fiIndex.nameSourceStart = fi.nameSourceStart;
fiIndex.nameSourceEnd = fi.nameSourceEnd;
fiIndex.declarationStart = fi.declarationStart;
fiIndex.modifiers = TclConstants.TCL_FIELD_TYPE_INDEX
| fi.modifiers;
if (context.getRequestor().enterFieldCheckDuplicates(fiIndex)) {
context.getRequestor().exitField(command.getEnd());
}
}
context.getRequestor().exitField(command.getEnd());
}
exit.leave(context.getRequestor());
}
protected void processField(TclCommand command, final TclArgument nameArg,
ITclModelBuildContext context) {
if (!isSymbol(nameArg)) {
return;
}
final String varName = asSymbol(nameArg);
final int modifiers = TclVisibilityUtils.isPrivate(varName) ? Modifiers.AccPrivate
: Modifiers.AccPublic;
processField(command, nameArg, varName, modifiers, context);
}
public static class Parameter {
final String name;
final String defaultValue;
final int start;
final int end;
public Parameter(TclArgument argument) {
this.name = asSymbol(argument);
this.start = argument.getStart();
this.end = argument.getEnd();
this.defaultValue = null;
}
public Parameter(String name, int start, int end) {
this.name = name;
this.start = start;
this.end = end;
this.defaultValue = null;
}
public Parameter(String name, int start, int end, String defaultValue) {
this.name = name;
this.start = start;
this.end = end;
this.defaultValue = defaultValue;
}
public String getName() {
return name;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
}
protected List<Parameter> parseParameters(TclArgument argument) {
if (argument instanceof StringArgument) {
return Collections.singletonList(new Parameter(argument));
} else if (argument instanceof TclArgumentList) {
final TclArgumentList list = (TclArgumentList) argument;
final List<Parameter> parameters = new ArrayList<Parameter>(list
.getArguments().size());
for (TclArgument arg : list.getArguments()) {
if (arg instanceof StringArgument) {
parameters.add(new Parameter(arg));
} else if (arg instanceof TclArgumentList) {
final EList<TclArgument> argWithInitializer = ((TclArgumentList) arg)
.getArguments();
final TclArgument pName = argWithInitializer.get(0);
if (argWithInitializer.size() >= 2) {
parameters.add(new Parameter(asSymbol(pName), pName
.getStart(), pName.getEnd(), TclProcessorUtil
.asString(argWithInitializer.get(1), false)));
} else if (argWithInitializer.size() == 1) {
parameters.add(new Parameter(pName));
} else {
parameters.add(new Parameter(Util.EMPTY_STRING, arg
.getStart(), arg.getEnd()));
}
} else {
parameters.add(new Parameter(arg));
}
}
return parameters;
} else {
return Collections.singletonList(new Parameter(argument));
}
}
protected void parseRawParameters(TclArgument args,
List<Parameter> parameters) {
for (TclArgument a : toWords(args)) {
if (a instanceof StringArgument) {
String aa = ((StringArgument) a).getValue();
if (aa.startsWith("{") && aa.endsWith("}")
|| aa.startsWith("\"") && aa.endsWith("\"")) {
List<TclArgument> parts = toWords(a);
if (!parts.isEmpty()) {
TclArgument first = parts.get(0);
if (first instanceof StringArgument) {
parameters.add(new Parameter(first));
}
}
} else {
parameters.add(new Parameter(a));
}
}
}
}
protected void fillParameters(MethodInfo mi, List<Parameter> parameters) {
if (parameters.isEmpty()) {
return;
}
mi.parameterNames = new String[parameters.size()];
mi.parameterInitializers = new String[parameters.size()];
for (int i = 0; i < parameters.size(); ++i) {
Parameter parameter = parameters.get(i);
mi.parameterNames[i] = parameter.name;
mi.parameterInitializers[i] = parameter.defaultValue;
}
}
private List<TclArgument> toWords(TclArgument argument) {
int offset = argument.getStart();
final String content;
if (argument instanceof StringArgument) {
final String value = ((StringArgument) argument).getValue();
int len = value.length();
if (len >= 2) {
if (value.charAt(0) == '{' && value.charAt(len - 1) == '}') {
content = value.substring(1, len - 1);
++offset;
} else if (value.charAt(0) == '"'
&& value.charAt(len - 1) == '"') {
content = value.substring(1, len - 1);
++offset;
} else {
content = value;
}
} else {
content = value;
}
} else {
content = SimpleCodePrinter.getArgumentString(argument, argument
.getStart());
}
TclParser parser = new TclParser();
parser.setGlobalOffset(offset);
List<TclCommand> commands = parser.parse(content);
List<TclArgument> result = new ArrayList<TclArgument>();
for (TclCommand c : commands) {
result.add(c.getName());
result.addAll(c.getArguments());
}
return result;
}
}