package org.yinwang.pysonar.ast;
import org.jetbrains.annotations.NotNull;
import org.yinwang.pysonar.Binding;
import org.yinwang.pysonar.Indexer;
import org.yinwang.pysonar.Scope;
import org.yinwang.pysonar.types.Type;
public class Name extends Node {
@NotNull
public final String id; // identifier
public Name(String id) {
this(id, -1, -1);
}
public Name(@NotNull String id, int start, int end) {
super(start, end);
this.id = id;
}
/**
* Returns {@code true} if this name is structurally in a call position.
*/
@Override
public boolean isCall() {
// foo(...)
if (parent != null && parent.isCall() && this == ((Call)parent).func) {
return true;
}
// <expr>.foo(...)
Node gramps;
return parent instanceof Attribute
&& this == ((Attribute)parent).attr
&& (gramps = parent.parent) instanceof Call
&& parent == ((Call)gramps).func;
}
@NotNull
@Override
public Type resolve(@NotNull Scope s, int tag) {
Binding b = s.lookup(id);
if (b != null) {
Indexer.idx.putRef(this, b);
Indexer.idx.stats.inc("resolved");
return b.getType();
} else if (id.equals("True") || id.equals("False")) {
return Indexer.idx.builtins.BaseBool;
} else {
Indexer.idx.putProblem(this, "unbound variable " + getId());
Indexer.idx.stats.inc("unresolved");
Type t = Indexer.idx.builtins.unknown;
t.getTable().setPath(s.extendPath(getId()));
return t;
}
}
/**
* Returns {@code true} if this name node is the {@code attr} child
* (i.e. the attribute being accessed) of an {@link Attribute} node.
*/
public boolean isAttribute() {
return parent instanceof Attribute
&& ((Attribute)parent).getAttr() == this;
}
@NotNull
public String getId() {
return id;
}
@NotNull
@Override
public String toString() {
return "<Name:" + start + ":" + id + ">";
}
@Override
public void visit(@NotNull NodeVisitor v) {
v.visit(this);
}
}