org.python.indexer.ast.NAttribute Maven / Gradle / Ivy
Show all versions of jython-slim Show documentation
/**
* Copyright 2009, Google Inc. All rights reserved.
* Licensed to PSF under a Contributor Agreement.
*/
package org.python.indexer.ast;
import org.python.indexer.Indexer;
import org.python.indexer.NBinding;
import org.python.indexer.Scope;
import org.python.indexer.types.NType;
import org.python.indexer.types.NUnionType;
import org.python.indexer.types.NUnknownType;
import static org.python.indexer.NBinding.Kind.ATTRIBUTE;
public class NAttribute extends NNode {
static final long serialVersionUID = -1120979305017812255L;
public NNode target;
public NName attr;
public NAttribute(NNode target, NName attr) {
this(target, attr, 0, 1);
}
public NAttribute(NNode target, NName attr, int start, int end) {
super(start, end);
setTarget(target);
setAttr(attr);
addChildren(target, attr);
}
public String getAttributeName() {
return attr.id;
}
/**
* Sets the attribute node. Used when constructing the AST.
* @throws IllegalArgumentException if the param is null
*/
public void setAttr(NName attr) {
if (attr == null) {
throw new IllegalArgumentException("param cannot be null");
}
this.attr = attr;
}
public NName getAttr() {
return attr;
}
/**
* Sets the target node. Used when constructing the AST.
* @throws IllegalArgumentException if the param is null
*/
public void setTarget(NNode target) {
if (target == null) {
throw new IllegalArgumentException("param cannot be null");
}
this.target = target;
}
public NNode getTarget() {
return target;
}
/**
* Assign some definite value to the attribute. Used during the name
* resolution pass. This method is called when this node is in the lvalue of
* an assignment, in which case it is called in lieu of {@link #resolve}.
*/
public void setAttr(Scope s, NType v) throws Exception {
setType(new NUnknownType());
NType targetType = resolveExpr(target, s);
if (targetType.isUnionType()) {
targetType = targetType.asUnionType().firstKnownNonNullAlternate();
if (targetType == null) {
return;
}
}
targetType = targetType.follow();
if (targetType == Indexer.idx.builtins.None) {
return;
}
NBinding b = targetType.getTable().putAttr(attr.id, attr, v, ATTRIBUTE);
if (b != null) {
setType(attr.setType(b.followType()));
}
}
@Override
public NType resolve(Scope s) throws Exception {
setType(new NUnknownType());
NType targetType = resolveExpr(target, s);
if (targetType.isUnionType()) {
NType ret = new NUnknownType();
for (NType tp : targetType.asUnionType().getTypes()) {
resolveAttributeOnType(tp);
ret = NUnionType.union(ret, getType());
}
setType(attr.setType(ret.follow()));
} else {
resolveAttributeOnType(targetType);
}
return getType();
}
private void resolveAttributeOnType(NType targetType) {
NType ttype = targetType.follow();
NBinding b = ttype.getTable().lookupAttr(attr.id);
if (b == null) {
b = makeProvisionalBinding(ttype);
}
if (b != null) {
Indexer.idx.putLocation(attr, b);
setType(attr.setType(b.getType()));
}
}
/**
* If we can't find the attribute in the target type, create a temp binding
* for the attribute. If later on the target type defines the attribute,
* that definition replaces the temp binding, and any references to the temp
* binding are updated to refer to the new definition.
*
*
We never create temp bindings for attributes of native types, as
* the attributes of native types are expected to be fully resolved.
*
*
This strategy is a temporary solution for inferring the types of
* attributes on targets that are not yet resolved. This whole approach
* needs to be replaced by dataflow analysis.
*/
private NBinding makeProvisionalBinding(NType targetType) {
if (targetType.isNative()) {
return null;
}
Scope targetScope = targetType.getTable();
// XXX: Eventually we need to fix out all the cases where the path is
// is empty here. For now, avoid an IndexingException.
if ("".equals(targetScope.getPath())) {
return null;
}
NType utype = new NUnknownType();
NBinding b = targetScope.putAttr(attr.id, null, utype, ATTRIBUTE);
if (b != null) {
b.setProvisional(true);
utype.getTable().setPath(b.getQname());
}
return b;
}
@Override
public String toString() {
return "";
}
@Override
public void visit(NNodeVisitor v) {
if (v.visit(this)) {
visitNode(target, v);
visitNode(attr, v);
}
}
}