src.org.python.indexer.ast.NFunctionDef Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython-standalone Show documentation
Show all versions of jython-standalone Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
/**
* Copyright 2009, Google Inc. All rights reserved.
* Licensed to PSF under a Contributor Agreement.
*/
package org.python.indexer.ast;
import org.python.indexer.Builtins;
import org.python.indexer.Indexer;
import org.python.indexer.NBinding;
import org.python.indexer.Scope;
import org.python.indexer.types.NDictType;
import org.python.indexer.types.NFuncType;
import org.python.indexer.types.NListType;
import org.python.indexer.types.NTupleType;
import org.python.indexer.types.NType;
import org.python.indexer.types.NUnknownType;
import java.util.ArrayList;
import java.util.List;
import static org.python.indexer.NBinding.Kind.ATTRIBUTE;
import static org.python.indexer.NBinding.Kind.CLASS;
import static org.python.indexer.NBinding.Kind.CONSTRUCTOR;
import static org.python.indexer.NBinding.Kind.FUNCTION;
import static org.python.indexer.NBinding.Kind.METHOD;
import static org.python.indexer.NBinding.Kind.PARAMETER;
public class NFunctionDef extends NNode {
static final long serialVersionUID = 5495886181960463846L;
public NName name;
public List args;
public List defaults;
public NName varargs; // *args
public NName kwargs; // **kwargs
public NNode body;
private List decoratorList;
public NFunctionDef(NName name, List args, NBlock body, List defaults,
NName varargs, NName kwargs) {
this(name, args, body, defaults, kwargs, varargs, 0, 1);
}
public NFunctionDef(NName name, List args, NBlock body, List defaults,
NName varargs, NName kwargs, int start, int end) {
super(start, end);
this.name = name;
this.args = args;
this.body = body != null ? new NBody(body) : new NBlock(null);
this.defaults = defaults;
this.varargs = varargs;
this.kwargs = kwargs;
addChildren(name);
addChildren(args);
addChildren(defaults);
addChildren(varargs, kwargs, this.body);
}
public void setDecoratorList(List decoratorList) {
this.decoratorList = decoratorList;
addChildren(decoratorList);
}
public List getDecoratorList() {
if (decoratorList == null) {
decoratorList = new ArrayList();
}
return decoratorList;
}
@Override
public boolean isFunctionDef() {
return true;
}
@Override
public boolean bindsName() {
return true;
}
/**
* Returns the name of the function for indexing/qname purposes.
* Lambdas will return a generated name.
*/
protected String getBindingName(Scope s) {
return name.id;
}
@Override
protected void bindNames(Scope s) throws Exception {
Scope owner = s.getScopeSymtab(); // enclosing class, function or module
setType(new NFuncType());
Scope funcTable = new Scope(s.getEnclosingLexicalScope(), Scope.Type.FUNCTION);
getType().setTable(funcTable);
funcTable.setPath(owner.extendPath(getBindingName(owner)));
// If we already defined this function in this scope, don't try it again.
NType existing = owner.lookupType(getBindingName(owner), true /* local scope */);
if (existing != null && existing.isFuncType()) {
return;
}
bindFunctionName(owner);
bindFunctionParams(funcTable);
bindFunctionDefaults(s);
bindMethodAttrs(owner);
}
protected void bindFunctionName(Scope owner) throws Exception {
NBinding.Kind funkind = FUNCTION;
if (owner.getScopeType() == Scope.Type.CLASS) {
if ("__init__".equals(name.id)) {
funkind = CONSTRUCTOR;
} else {
funkind = METHOD;
}
}
NameBinder.make(funkind).bindName(owner, name, getType());
}
protected void bindFunctionParams(Scope funcTable) throws Exception {
NameBinder param = NameBinder.make(PARAMETER);
for (NNode a : args) {
param.bind(funcTable, a, new NUnknownType());
}
if (varargs != null) {
param.bind(funcTable, varargs, new NListType());
}
if (kwargs != null) {
param.bind(funcTable, kwargs, new NDictType());
}
}
/**
* Processes any name-binding constructs appearing as parameter defaults.
* For instance, in {@code def foo(converter=lambda name: name.upper()): ...}
* the lambda is a name-binding construct.
*/
protected void bindFunctionDefaults(Scope s) throws Exception {
for (NNode n : defaults) {
if (n.bindsName()) {
n.bindNames(s);
}
}
}
protected void bindMethodAttrs(Scope owner) throws Exception {
NType cls = Indexer.idx.lookupQnameType(owner.getPath());
if (cls == null || !cls.isClassType()) {
return;
}
// We don't currently differentiate between classes and instances.
addReadOnlyAttr("im_class", cls, CLASS);
addReadOnlyAttr("__class__", cls, CLASS);
addReadOnlyAttr("im_self", cls, ATTRIBUTE);
addReadOnlyAttr("__self__", cls, ATTRIBUTE);
}
protected NBinding addSpecialAttr(String name, NType atype, NBinding.Kind kind) {
NBinding b = getTable().update(name,
Builtins.newDataModelUrl("the-standard-type-hierarchy"),
atype, kind);
b.markSynthetic();
b.markStatic();
return b;
}
protected NBinding addReadOnlyAttr(String name, NType type, NBinding.Kind kind) {
NBinding b = addSpecialAttr(name, type, kind);
b.markReadOnly();
return b;
}
@Override
public NType resolve(Scope outer) throws Exception {
resolveList(defaults, outer);
resolveList(decoratorList, outer);
Scope funcTable = getTable();
NBinding selfBinding = funcTable.lookup("__self__");
if (selfBinding != null && !selfBinding.getType().isClassType()) {
selfBinding = null;
}
if (selfBinding != null) {
if (args.size() < 1) {
addWarning(name, "method should have at least one argument (self)");
} else if (!(args.get(0) instanceof NName)) {
addError(name, "self parameter must be an identifier");
}
}
NTupleType fromType = new NTupleType();
bindParamsToDefaults(selfBinding, fromType);
if (varargs != null) {
NBinding b = funcTable.lookupLocal(varargs.id);
if (b != null) {
fromType.add(b.getType());
}
}
if (kwargs != null) {
NBinding b = funcTable.lookupLocal(kwargs.id);
if (b != null) {
fromType.add(b.getType());
}
}
NType toType = resolveExpr(body, funcTable);
getType().asFuncType().setReturnType(toType);
return getType();
}
private void bindParamsToDefaults(NBinding selfBinding, NTupleType fromType) throws Exception {
NameBinder param = NameBinder.make(PARAMETER);
Scope funcTable = getTable();
for (int i = 0; i < args.size(); i++) {
NNode arg = args.get(i);
NType argtype = ((i == 0 && selfBinding != null)
? selfBinding.getType()
: getArgType(args, defaults, i));
param.bind(funcTable, arg, argtype);
fromType.add(argtype);
}
}
static NType getArgType(List args, List defaults, int argnum) {
if (defaults == null) {
return new NUnknownType();
}
int firstDefault = args.size() - defaults.size();
if (firstDefault >= 0 && argnum >= firstDefault) {
return defaults.get(argnum - firstDefault).getType();
}
return new NUnknownType();
}
@Override
public String toString() {
return "";
}
@Override
public void visit(NNodeVisitor v) {
if (v.visit(this)) {
visitNode(name, v);
visitNodeList(args, v);
visitNodeList(defaults, v);
visitNode(kwargs, v);
visitNode(varargs, v);
visitNode(body, v);
}
}
}