package org.yinwang.pysonar.ast;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.yinwang.pysonar.Binding;
import org.yinwang.pysonar.Indexer;
import org.yinwang.pysonar.Scope;
import org.yinwang.pysonar.types.ListType;
import org.yinwang.pysonar.types.ModuleType;
import org.yinwang.pysonar.types.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
public class ImportFrom extends Node {
public List<Name> module;
public List<Alias> names;
public int level;
public ImportFrom(List<Name> module, List<Alias> names, int level, int start, int end) {
super(start, end);
this.module = module;
this.level = level;
this.names = names;
addChildren(names);
}
@Override
public boolean bindsName() {
return true;
}
@NotNull
@Override
public Type resolve(@NotNull Scope s, int tag) {
if (module == null) {
return Indexer.idx.builtins.Cont;
}
ModuleType mod = Indexer.idx.loadModule(module, s, tag);
if (mod == null) {
Indexer.idx.putProblem(this, "Cannot load module");
} else if (isImportStar()) {
importStar(s, mod, tag);
} else {
for (Alias a : names) {
Type t = mod.getTable().lookupType(a.name.get(0).id);
if (t == null) return Indexer.idx.builtins.Cont;
if (a.asname != null) {
s.put(a.asname.id, a.asname, t, Binding.Kind.VARIABLE, tag);
} else {
Binding b = mod.getTable().lookup(a.name.get(0).id);
if (b != null) {
s.update(a.name.get(0).id, b);
}
}
}
}
return Indexer.idx.builtins.Cont;
}
public boolean isImportStar() {
return names.size() == 1 && "*".equals(names.get(0).name.get(0).id);
}
private void importStar(@NotNull Scope s, @Nullable ModuleType mt, int tag) {
if (mt == null || mt.getFile() == null) {
return;
}
Module mod = Indexer.idx.getAstForFile(mt.getFile());
if (mod == null) {
return;
}
List<String> names = new ArrayList<>();
Type allType = mt.getTable().lookupType("__all__");
if (allType != null && allType.isListType()) {
ListType lt = allType.asListType();
for (Object o: lt.values) {
if (o instanceof String) {
names.add((String) o);
}
}
}
if (!names.isEmpty()) {
for (String name : names) {
Binding b = mt.getTable().lookupLocal(name);
if (b != null) {
s.update(name, b);
} else {
List<Name> m2 = new ArrayList<>(module);
m2.add(new Name(name));
ModuleType mod2 = Indexer.idx.loadModule(m2, s, tag);
if (mod2 != null) {
s.put(name, null, mod2, Binding.Kind.VARIABLE, tag);
}
}
}
} else {
// Fall back to importing all names not starting with "_".
for (Entry<String, Binding> e : mt.getTable().entrySet()) {
if (!e.getKey().startsWith("_")) {
s.update(e.getKey(), e.getValue());
}
}
}
}
@NotNull
@Override
public String toString() {
return "<FromImport:" + module + ":" + names + ">";
}
@Override
public void visit(@NotNull NodeVisitor v) {
if (v.visit(this)) {
visitNodeList(names, v);
}
}
}