Eclipse-PyUML/pyUml/src/pyUML/pythonTree/PythonTreeAttribute.java

194 lines
5.6 KiB
Java
Executable File

package pyUML.pythonTree;
import java.util.List;
import java.util.Vector;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.VisibilityKind;
import org.python.pydev.parser.jython.ast.Assign;
import org.python.pydev.parser.jython.ast.Attribute;
import org.python.pydev.parser.jython.ast.Call;
import org.python.pydev.parser.jython.ast.Name;
import org.python.pydev.parser.jython.ast.NameTok;
import org.python.pydev.parser.jython.ast.exprType;
import pyUML.backend.GlobalConstants;
import pyUML.backend.ParseHelpers;
/**
* This PythonTree member represents a python attribute.
* It can represent static attributes (defined outside any method)
* or object attributes (defined with "self." inside __init__()
*/
public class PythonTreeAttribute extends PythonTreeNode {
private Assign astNode;
private boolean valid;
private boolean staticAtt;
private String value;
private String fullValue;
private int line;
private int col;
private int nextLine;
/**
* @param parent the parent in the PythonTree
* @param astNode the corresponding Python AST node
* @param staticAtt true, if this is an attribute outside a
* function definition
* @param nextLine the line of the next Python statement. This
* is needed to extract multi-line-attributes
*/
public PythonTreeAttribute(PythonTreeNode parent, Assign astNode, boolean staticAtt, int nextLine) {
super(parent);
this.astNode = astNode;
this.staticAtt = staticAtt;
this.nextLine = nextLine;
this.valid = this.initAttribute();
}
/**
* @return false, if this is no valid attribute
*/
private boolean initAttribute(){
exprType left = this.astNode.targets[0];
exprType right = this.astNode.value;
// analyze the left side of the assign and see
// if this might be a valid attribute
try {
if (staticAtt) { //static: attr without "self"
this.name = ((Name)left).id;
this.line = ((Name)left).beginLine;
this.col = ((Name)left).beginColumn;
}
else{ // object attr: begins with "self."
Attribute leftAtt = (Attribute)left;
if (! ((Name)leftAtt.value).id.equals("self"))
return false;
this.name =((NameTok)(leftAtt).attr).id;
this.line = ((NameTok)(leftAtt).attr).beginLine;
this.col = ((NameTok)(leftAtt).attr).beginColumn;
}
}
catch (ClassCastException e) {
// if anything is not like expected, this is not a
// att=value
// or self.att=value
// attribute -> this is not considered a valid attribute!
return false;
}
// now, look at the right side
if (right instanceof Call)
return false;
this.value = ParseHelpers.getStringOfExpr(right, this.getParent().getInFile(), true, true, this.nextLine);
// if the value was abbreviated, save full value, also.
if (this.value.endsWith("(...)")) {
this.fullValue = ParseHelpers.getStringOfExpr(right, this.getParent().getInFile(), true, false, this.nextLine);
}
// if everything went right, this is considered a valid attribute!
return true;
}
/**
* A PythonTreeAttribute is created always when an Assign
* is found in the class body or the constructor.
* Sometimes an assign does not declare an attribute; then,
* this object should not be added to the PythonTreeClass
* attributes and be left for the garbage collector.
*
* @return if this astNode really represents a python
* static/object attribute and shall be saved
*/
public boolean isValid() {
return this.valid;
}
public boolean isStatic() {
return staticAtt;
}
/**
* @return this attribute's (default) value
*/
public String getValue() {
return value;
}
public boolean synchronizeModel(NamedElement modelElement) {
Property modelProperty = (Property) modelElement;
// set this attribute private in model, if its name starts with "__"
// use protected, if class starts with "_" (this is only python convention)
if (this.getName().startsWith("__")) {
modelProperty.setVisibility(VisibilityKind.PRIVATE_LITERAL);
} else if (this.getName().startsWith("_")) {
modelProperty.setVisibility(VisibilityKind.PROTECTED_LITERAL);
}
String defVal = this.getValue();
if (! "None".equals(defVal))
modelProperty.setDefault(this.getValue());
// if default value was abbreviated ->
// save full default value as comment,
// beginning with a PyUML Marker
if (this.fullValue != null) {
Comment fullValueComment = null;
for (Comment comment : modelProperty.getOwnedComments()) {
if (comment.getBody().startsWith(GlobalConstants.getFullDefault())) {
fullValueComment=comment;
break;
}
}
if (fullValueComment == null)
fullValueComment = modelProperty.createOwnedComment();
fullValueComment.setBody(GlobalConstants.getFullDefault()
+ this.fullValue);
} else {
// there is no "full" value -> delete all comments
// that save a full value
List<Comment> commentList = new Vector<Comment>();
commentList.addAll(modelProperty.getOwnedComments());
for (Comment comment : commentList) {
if (comment.getBody().startsWith(GlobalConstants.getFullDefault())) {
comment.destroy();
}
}
}
modelProperty.setIsStatic(this.isStatic());
return true;
}
public int getLine() {
return line;
}
public int getCol() {
return col;
}
public PythonTreeClass getParent() {
return (PythonTreeClass) super.getParent();
}
/**
* @return the un-abbreviated attribute (default) value
* for this attribute
*/
public String getFullValue() {
return fullValue;
}
public int getNextLine() {
return nextLine;
}
}