-
Notifications
You must be signed in to change notification settings - Fork 227
Expand file tree
/
Copy pathNSubscript.java
More file actions
128 lines (112 loc) · 4.1 KB
/
NSubscript.java
File metadata and controls
128 lines (112 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/**
* 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.Scope;
import org.python.indexer.types.NFuncType;
import org.python.indexer.types.NListType;
import org.python.indexer.types.NType;
import org.python.indexer.types.NUnknownType;
public class NSubscript extends NNode {
static final long serialVersionUID = -493854491438387425L;
public NNode value;
public NNode slice; // an NIndex or NSlice
public NSubscript(NNode value, NNode slice) {
this(value, slice, 0, 1);
}
public NSubscript(NNode value, NNode slice, int start, int end) {
super(start, end);
this.value = value;
this.slice = slice;
addChildren(value, slice);
}
@Override
public NType resolve(Scope s) throws Exception {
NType vt = resolveExpr(value, s);
NType st = resolveExpr(slice, s);
// slicing
if (vt.isUnknownType()) {
if (st.isListType()) {
return setType(vt);
}
return setType(new NUnknownType());
}
if (st.isListType()) {
NType getslice_type = vt.getTable().lookupTypeAttr("__getslice__");
if (getslice_type == null) {
addError("The type can't be sliced: " + vt);
return setType(new NUnknownType());
}
if (!getslice_type.isFuncType()) {
addError("The type's __getslice__ method is not a function: "
+ getslice_type);
return setType(new NUnknownType());
}
return setType(getslice_type.asFuncType().getReturnType().follow());
}
// subscription
if (slice instanceof NIndex) {
if (vt.isListType()) {
warnUnlessNumIndex(st);
return setType(vt.asListType().getElementType());
}
if (vt.isTupleType()) {
warnUnlessNumIndex(st);
return setType(vt.asTupleType().toListType().getElementType());
}
if (vt.isStrType()) {
warnUnlessNumIndex(st);
return setType(Indexer.idx.builtins.BaseStr);
}
// XXX: unicode, buffer, xrange
if (vt.isDictType()) {
if (!st.follow().equals(vt.asDictType().getKeyType())) {
addWarning("Possible KeyError (wrong type for subscript)");
}
return setType(vt.asDictType().getValueType()); // infer it regardless
}
// else fall through
}
// subscription via delegation
if (vt.isUnionType()) {
for (NType u : vt.asUnionType().getTypes()) {
NType gt = vt.getTable().lookupTypeAttr("__getitem__");
if (gt != null) {
return setType(get__getitem__type(gt, gt));
}
}
}
NType gt = vt.getTable().lookupTypeAttr("__getitem__");
return setType(get__getitem__type(gt, vt));
}
private void warnUnlessNumIndex(NType subscriptType) {
NType follow = subscriptType.follow();
if (!follow.isNumType() && !follow.isUnknownType()) {
addWarning("Possible KeyError: subscript should be a number; found " + follow);
}
}
private NType get__getitem__type(NType gt, NType vt) {
if (gt == null) {
addError("indexing type without __getitem__ method: " + vt);
return new NUnknownType();
}
if (!gt.isFuncType()) {
addError("The type's __getitem__ method is not a function: " + gt);
return new NUnknownType();
}
return gt.asFuncType().getReturnType().follow();
}
@Override
public String toString() {
return "<Subscript:" + value + ":" + slice + ">";
}
@Override
public void visit(NNodeVisitor v) {
if (v.visit(this)) {
visitNode(value, v);
visitNode(slice, v);
}
}
}