194 lines
5.6 KiB
Java
Executable File
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;
|
|
}
|
|
}
|