rsense-core 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +1 -0
- data/README.md +35 -0
- data/Rakefile +84 -0
- data/TypeAnnotation.tokens +41 -0
- data/build.xml +84 -0
- data/build_lib/antlr-3.2.jar +0 -0
- data/lib/jars/ant-1.7.0.jar +0 -0
- data/lib/jars/ant-launcher-1.7.0.jar +0 -0
- data/lib/jars/antlr-runtime-3.2.jar +0 -0
- data/lib/jars/bsf-2.3.0.jar +0 -0
- data/lib/rsense-core.rb +28 -0
- data/lib/rsense.jar +0 -0
- data/lib/rsense/core.rb +5 -0
- data/lib/rsense/core/version.rb +5 -0
- data/lib/rsense/parser.rb +6 -0
- data/lib/rsense/ruby.rb +19 -0
- data/lib/rsense/typing.rb +13 -0
- data/lib/rsense/typing/annotation.rb +20 -0
- data/lib/rsense/typing/runtime.rb +23 -0
- data/lib/rsense/typing/vertex.rb +15 -0
- data/lib/rsense/util.rb +9 -0
- data/rsense-core.gemspec +30 -0
- data/src/org/cx4a/rsense/CodeAssist.java +744 -0
- data/src/org/cx4a/rsense/CodeAssistError.java +31 -0
- data/src/org/cx4a/rsense/CodeAssistResult.java +42 -0
- data/src/org/cx4a/rsense/CodeCompletionResult.java +65 -0
- data/src/org/cx4a/rsense/FindDefinitionResult.java +24 -0
- data/src/org/cx4a/rsense/LoadResult.java +19 -0
- data/src/org/cx4a/rsense/Main.java +916 -0
- data/src/org/cx4a/rsense/Options.java +353 -0
- data/src/org/cx4a/rsense/Project.java +103 -0
- data/src/org/cx4a/rsense/TypeInferenceResult.java +25 -0
- data/src/org/cx4a/rsense/WhereResult.java +19 -0
- data/src/org/cx4a/rsense/parser/TypeAnnotation.g +221 -0
- data/src/org/cx4a/rsense/parser/TypeAnnotationLexer.java +1759 -0
- data/src/org/cx4a/rsense/parser/TypeAnnotationParser.java +2025 -0
- data/src/org/cx4a/rsense/ruby/Block.java +10 -0
- data/src/org/cx4a/rsense/ruby/Context.java +75 -0
- data/src/org/cx4a/rsense/ruby/DynamicMethod.java +10 -0
- data/src/org/cx4a/rsense/ruby/DynamicScope.java +51 -0
- data/src/org/cx4a/rsense/ruby/Frame.java +95 -0
- data/src/org/cx4a/rsense/ruby/IRubyObject.java +17 -0
- data/src/org/cx4a/rsense/ruby/LocalScope.java +43 -0
- data/src/org/cx4a/rsense/ruby/MetaClass.java +50 -0
- data/src/org/cx4a/rsense/ruby/Ruby.java +242 -0
- data/src/org/cx4a/rsense/ruby/RubyClass.java +146 -0
- data/src/org/cx4a/rsense/ruby/RubyModule.java +255 -0
- data/src/org/cx4a/rsense/ruby/RubyObject.java +94 -0
- data/src/org/cx4a/rsense/ruby/Scope.java +7 -0
- data/src/org/cx4a/rsense/ruby/SpecialObject.java +15 -0
- data/src/org/cx4a/rsense/ruby/Visibility.java +17 -0
- data/src/org/cx4a/rsense/typing/Graph.java +1690 -0
- data/src/org/cx4a/rsense/typing/Propagation.java +73 -0
- data/src/org/cx4a/rsense/typing/Template.java +84 -0
- data/src/org/cx4a/rsense/typing/TemplateAttribute.java +158 -0
- data/src/org/cx4a/rsense/typing/TypeSet.java +48 -0
- data/src/org/cx4a/rsense/typing/annotation/ClassType.java +57 -0
- data/src/org/cx4a/rsense/typing/annotation/MethodType.java +79 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeAnnotation.java +4 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeAny.java +7 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeApplication.java +37 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeConstraint.java +29 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeExpression.java +11 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeIdentity.java +59 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeOptional.java +22 -0
- data/src/org/cx4a/rsense/typing/annotation/TypePragma.java +22 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeSplat.java +22 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeTuple.java +35 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeUnion.java +23 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeVariable.java +44 -0
- data/src/org/cx4a/rsense/typing/runtime/AliasMethod.java +94 -0
- data/src/org/cx4a/rsense/typing/runtime/AnnotationHelper.java +69 -0
- data/src/org/cx4a/rsense/typing/runtime/AnnotationResolver.java +523 -0
- data/src/org/cx4a/rsense/typing/runtime/Array.java +84 -0
- data/src/org/cx4a/rsense/typing/runtime/ClassTag.java +27 -0
- data/src/org/cx4a/rsense/typing/runtime/DefaultMethod.java +115 -0
- data/src/org/cx4a/rsense/typing/runtime/Hash.java +131 -0
- data/src/org/cx4a/rsense/typing/runtime/LoopTag.java +21 -0
- data/src/org/cx4a/rsense/typing/runtime/Method.java +32 -0
- data/src/org/cx4a/rsense/typing/runtime/MonomorphicObject.java +77 -0
- data/src/org/cx4a/rsense/typing/runtime/ObjectAllocator.java +40 -0
- data/src/org/cx4a/rsense/typing/runtime/PolymorphicObject.java +90 -0
- data/src/org/cx4a/rsense/typing/runtime/Proc.java +100 -0
- data/src/org/cx4a/rsense/typing/runtime/RuntimeHelper.java +1339 -0
- data/src/org/cx4a/rsense/typing/runtime/SpecialMethod.java +119 -0
- data/src/org/cx4a/rsense/typing/runtime/TypeVarMap.java +112 -0
- data/src/org/cx4a/rsense/typing/runtime/VertexHolder.java +48 -0
- data/src/org/cx4a/rsense/typing/vertex/CallVertex.java +122 -0
- data/src/org/cx4a/rsense/typing/vertex/MultipleAsgnVertex.java +23 -0
- data/src/org/cx4a/rsense/typing/vertex/PassThroughVertex.java +20 -0
- data/src/org/cx4a/rsense/typing/vertex/SValueVertex.java +24 -0
- data/src/org/cx4a/rsense/typing/vertex/SplatVertex.java +24 -0
- data/src/org/cx4a/rsense/typing/vertex/ToAryVertex.java +24 -0
- data/src/org/cx4a/rsense/typing/vertex/TypeVarVertex.java +22 -0
- data/src/org/cx4a/rsense/typing/vertex/Vertex.java +221 -0
- data/src/org/cx4a/rsense/typing/vertex/YieldVertex.java +70 -0
- data/src/org/cx4a/rsense/util/HereDocReader.java +48 -0
- data/src/org/cx4a/rsense/util/Logger.java +111 -0
- data/src/org/cx4a/rsense/util/NodeUtil.java +198 -0
- data/src/org/cx4a/rsense/util/SourceLocation.java +70 -0
- data/src/org/cx4a/rsense/util/StringUtil.java +63 -0
- data/src/resources/org/cx4a/rsense/rsense.properties +1 -0
- data/stubs/1.8/_builtin.rb +3006 -0
- data/stubs/1.8/bigdecimal.rb +131 -0
- data/stubs/1.8/cgi.rb +257 -0
- data/stubs/1.8/date.rb +147 -0
- data/stubs/1.8/optparse.rb +113 -0
- data/stubs/1.8/rational.rb +47 -0
- data/stubs/1.8/set.rb +94 -0
- data/stubs/1.8/socket.rb +461 -0
- data/stubs/1.8/stringio.rb +129 -0
- data/test/data/a file.rb +1 -0
- data/test/data/benchmark.rb +12 -0
- data/test/data/crlf.rb +5 -0
- data/test/data/test.rb +19 -0
- data/test/script/all.rsense +2 -0
- data/test/script/array_dynamic.rsense +25 -0
- data/test/script/block_nested.rsense +7 -0
- data/test/script/builtin.rsense +785 -0
- data/test/script/class_method_partial_update.rsense +52 -0
- data/test/script/class_partial_update.rsense +17 -0
- data/test/script/find-definition.rsense +72 -0
- data/test/script/method_arg_onearg.rsense +6 -0
- data/test/script/method_arg_optional.rsense +7 -0
- data/test/script/method_partial_update.rsense +14 -0
- data/test/script/method_yield_arrayarg.rsense +8 -0
- data/test/script/method_yield_arrayarg_expand.rsense +8 -0
- data/test/script/method_yield_arrayarg_splat.rsense +17 -0
- data/test/script/misc.rsense +2 -0
- data/test/script/proc_higher_order.rsense +22 -0
- data/test/script/regression.rsense +95 -0
- data/test/script/stdlib.rsense +66 -0
- data/test/script/where.rsense +41 -0
- metadata +315 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
package org.cx4a.rsense.typing.runtime;
|
|
2
|
+
|
|
3
|
+
import java.util.Map;
|
|
4
|
+
import java.util.HashMap;
|
|
5
|
+
|
|
6
|
+
import org.cx4a.rsense.ruby.Ruby;
|
|
7
|
+
import org.cx4a.rsense.ruby.RubyClass;
|
|
8
|
+
import org.cx4a.rsense.ruby.RubyObject;
|
|
9
|
+
import org.cx4a.rsense.ruby.IRubyObject;
|
|
10
|
+
import org.cx4a.rsense.typing.annotation.ClassType;
|
|
11
|
+
|
|
12
|
+
public class ObjectAllocator implements Ruby.ObjectAllocator {
|
|
13
|
+
private Map<RubyClass, IRubyObject> instances;
|
|
14
|
+
|
|
15
|
+
public ObjectAllocator() {
|
|
16
|
+
instances = new HashMap<RubyClass, IRubyObject>();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
|
20
|
+
ClassType classType = RuntimeHelper.getClassAnnotation(klass);
|
|
21
|
+
if (classType != null && classType.isPolymorphic()) {
|
|
22
|
+
return newPolymorphicInstance(runtime, klass, classType);
|
|
23
|
+
} else {
|
|
24
|
+
return newMonomorphicInstance(runtime, klass);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public IRubyObject newPolymorphicInstance(Ruby runtime, RubyClass klass, ClassType type) {
|
|
29
|
+
return new PolymorphicObject(runtime, klass);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public IRubyObject newMonomorphicInstance(Ruby runtime, RubyClass klass) {
|
|
33
|
+
IRubyObject instance = instances.get(klass);
|
|
34
|
+
if (instance == null) {
|
|
35
|
+
instance = new RubyObject(runtime, klass);
|
|
36
|
+
instances.put(klass, instance);
|
|
37
|
+
}
|
|
38
|
+
return instance;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
package org.cx4a.rsense.typing.runtime;
|
|
2
|
+
|
|
3
|
+
import org.cx4a.rsense.ruby.Ruby;
|
|
4
|
+
import org.cx4a.rsense.ruby.RubyClass;
|
|
5
|
+
import org.cx4a.rsense.ruby.RubyObject;
|
|
6
|
+
|
|
7
|
+
public class PolymorphicObject extends RubyObject {
|
|
8
|
+
// data polymorphic modified?
|
|
9
|
+
private boolean modified = false;
|
|
10
|
+
private long modifiedTime;
|
|
11
|
+
|
|
12
|
+
public PolymorphicObject(Ruby runtime) {
|
|
13
|
+
this(runtime, runtime.getObject());
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public PolymorphicObject(Ruby runtime, RubyClass metaClass) {
|
|
17
|
+
this(runtime, metaClass, new TypeVarMap());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
protected PolymorphicObject(Ruby runtime, RubyClass metaClass, TypeVarMap tvmap) {
|
|
21
|
+
super(runtime, metaClass);
|
|
22
|
+
setTag(tvmap);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public TypeVarMap getTypeVarMap() {
|
|
26
|
+
return (TypeVarMap) getTag();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public boolean isModified() {
|
|
30
|
+
return modified;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public long getModifiedTime() {
|
|
34
|
+
return modifiedTime;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public void setModified(boolean modified) {
|
|
38
|
+
this.modified = modified;
|
|
39
|
+
this.modifiedTime = System.currentTimeMillis();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public MonomorphicObject[] generateMonomorphicObjects() {
|
|
43
|
+
TypeVarMap[] tvmaps = getTypeVarMap().generateTuples();
|
|
44
|
+
if (tvmaps.length == 0) {
|
|
45
|
+
return new MonomorphicObject[] { new MonomorphicObject(this, getTypeVarMap()) };
|
|
46
|
+
} else {
|
|
47
|
+
MonomorphicObject[] result = new MonomorphicObject[tvmaps.length];
|
|
48
|
+
for (int i = 0; i < tvmaps.length; i++) {
|
|
49
|
+
result[i] = new MonomorphicObject(this, tvmaps[i]);
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public PolymorphicObject clone() {
|
|
56
|
+
return new PolymorphicObject(runtime, metaClass, getTypeVarMap().clone());
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@Override
|
|
60
|
+
public int hashCode() {
|
|
61
|
+
return hashCode(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@Override
|
|
65
|
+
public int hashCode(int depth) {
|
|
66
|
+
if (depth > 2)
|
|
67
|
+
// Approximate hash code for nested polymorphic object
|
|
68
|
+
return getMetaClass().hashCode();
|
|
69
|
+
else
|
|
70
|
+
return getMetaClass().hashCode() ^ getTypeVarMap().hashCode(depth + 1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@Override
|
|
74
|
+
public boolean equals(Object other) {
|
|
75
|
+
if (this == other)
|
|
76
|
+
return true;
|
|
77
|
+
|
|
78
|
+
if (!(other instanceof PolymorphicObject))
|
|
79
|
+
return false;
|
|
80
|
+
|
|
81
|
+
PolymorphicObject o = (PolymorphicObject) other;
|
|
82
|
+
return getMetaClass() == o.getMetaClass()
|
|
83
|
+
&& getTypeVarMap().equals(o.getTypeVarMap());
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@Override
|
|
87
|
+
public String toString() {
|
|
88
|
+
return "<pobj:" + getMetaClass().toString() + getTypeVarMap() + ">";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
package org.cx4a.rsense.typing.runtime;
|
|
2
|
+
|
|
3
|
+
import java.util.Set;
|
|
4
|
+
import java.util.HashSet;
|
|
5
|
+
import java.util.Collections;
|
|
6
|
+
|
|
7
|
+
import org.jrubyparser.ast.Node;
|
|
8
|
+
|
|
9
|
+
import org.cx4a.rsense.ruby.Ruby;
|
|
10
|
+
import org.cx4a.rsense.ruby.Block;
|
|
11
|
+
import org.cx4a.rsense.ruby.Frame;
|
|
12
|
+
import org.cx4a.rsense.ruby.Scope;
|
|
13
|
+
import org.cx4a.rsense.ruby.RubyObject;
|
|
14
|
+
import org.cx4a.rsense.typing.vertex.YieldVertex;
|
|
15
|
+
import org.cx4a.rsense.util.NodeUtil;
|
|
16
|
+
|
|
17
|
+
public class Proc extends RubyObject implements Block {
|
|
18
|
+
private Node varNode;
|
|
19
|
+
private Node bodyNode;
|
|
20
|
+
private Frame frame;
|
|
21
|
+
private Scope scope;
|
|
22
|
+
private Set<YieldVertex> yields;
|
|
23
|
+
private int varNodeHashCode, bodyNodeHashCode;
|
|
24
|
+
|
|
25
|
+
public Proc(Ruby runtime, Node varNode, Node bodyNode, Frame frame, Scope scope) {
|
|
26
|
+
super(runtime, runtime.getProc());
|
|
27
|
+
this.varNode = varNode;
|
|
28
|
+
this.bodyNode = bodyNode;
|
|
29
|
+
this.frame = frame;
|
|
30
|
+
this.scope = scope;
|
|
31
|
+
this.varNodeHashCode = 0;
|
|
32
|
+
this.bodyNodeHashCode = 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public Node getVarNode() {
|
|
36
|
+
return varNode;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public Node getBodyNode() {
|
|
40
|
+
return bodyNode;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public int getVarNodeHashCode() {
|
|
44
|
+
if (varNodeHashCode == 0) {
|
|
45
|
+
varNodeHashCode = NodeUtil.nodeHashCode(varNode);
|
|
46
|
+
}
|
|
47
|
+
return varNodeHashCode;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public int getBodyNodeHashCode() {
|
|
51
|
+
if (bodyNodeHashCode == 0) {
|
|
52
|
+
bodyNodeHashCode = NodeUtil.nodeHashCode(bodyNode);
|
|
53
|
+
}
|
|
54
|
+
return bodyNodeHashCode;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public Frame getFrame() {
|
|
58
|
+
return frame;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public Scope getScope() {
|
|
62
|
+
return scope;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public Set<YieldVertex> getYields() {
|
|
66
|
+
return yields != null ? yields : Collections.<YieldVertex>emptySet();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public boolean recordYield(YieldVertex vertex) {
|
|
70
|
+
if (yields == null) {
|
|
71
|
+
yields = new HashSet<YieldVertex>();
|
|
72
|
+
}
|
|
73
|
+
return yields.add(vertex);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public boolean isApplied(YieldVertex vertex) {
|
|
77
|
+
return yields != null && yields.contains(vertex);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@Override
|
|
81
|
+
public int hashCode() {
|
|
82
|
+
return getVarNodeHashCode() ^ getBodyNodeHashCode();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@Override
|
|
86
|
+
public boolean equals(Object other) {
|
|
87
|
+
if (this == other) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!(other instanceof Proc)) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
Proc o = (Proc) other;
|
|
96
|
+
return hashCode() == o.hashCode()
|
|
97
|
+
&& frame.equals(o.frame)
|
|
98
|
+
&& scope.equals(o.scope);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,1339 @@
|
|
|
1
|
+
package org.cx4a.rsense.typing.runtime;
|
|
2
|
+
|
|
3
|
+
import java.util.ArrayList;
|
|
4
|
+
import java.util.Arrays;
|
|
5
|
+
import java.util.Collection;
|
|
6
|
+
import java.util.Collections;
|
|
7
|
+
import java.util.Iterator;
|
|
8
|
+
import java.util.List;
|
|
9
|
+
import java.util.Map;
|
|
10
|
+
|
|
11
|
+
import org.jrubyparser.LocalStaticScope;
|
|
12
|
+
import org.jrubyparser.SourcePosition;
|
|
13
|
+
import org.jrubyparser.ast.*;
|
|
14
|
+
|
|
15
|
+
import org.cx4a.rsense.ruby.Block;
|
|
16
|
+
import org.cx4a.rsense.ruby.Context;
|
|
17
|
+
import org.cx4a.rsense.ruby.DynamicMethod;
|
|
18
|
+
import org.cx4a.rsense.ruby.DynamicScope;
|
|
19
|
+
import org.cx4a.rsense.ruby.Frame;
|
|
20
|
+
import org.cx4a.rsense.ruby.IRubyObject;
|
|
21
|
+
import org.cx4a.rsense.ruby.LocalScope;
|
|
22
|
+
import org.cx4a.rsense.ruby.MetaClass;
|
|
23
|
+
import org.cx4a.rsense.ruby.Ruby;
|
|
24
|
+
import org.cx4a.rsense.ruby.RubyClass;
|
|
25
|
+
import org.cx4a.rsense.ruby.RubyModule;
|
|
26
|
+
import org.cx4a.rsense.ruby.Scope;
|
|
27
|
+
import org.cx4a.rsense.ruby.Visibility;
|
|
28
|
+
import org.cx4a.rsense.typing.Graph;
|
|
29
|
+
import org.cx4a.rsense.typing.Template;
|
|
30
|
+
import org.cx4a.rsense.typing.TemplateAttribute;
|
|
31
|
+
import org.cx4a.rsense.typing.TypeSet;
|
|
32
|
+
import org.cx4a.rsense.typing.annotation.ClassType;
|
|
33
|
+
import org.cx4a.rsense.typing.annotation.MethodType;
|
|
34
|
+
import org.cx4a.rsense.typing.annotation.TypeAnnotation;
|
|
35
|
+
import org.cx4a.rsense.typing.annotation.TypeExpression;
|
|
36
|
+
import org.cx4a.rsense.typing.annotation.TypeVariable;
|
|
37
|
+
import org.cx4a.rsense.typing.vertex.CallVertex;
|
|
38
|
+
import org.cx4a.rsense.typing.vertex.MultipleAsgnVertex;
|
|
39
|
+
import org.cx4a.rsense.typing.vertex.PassThroughVertex;
|
|
40
|
+
import org.cx4a.rsense.typing.vertex.SValueVertex;
|
|
41
|
+
import org.cx4a.rsense.typing.vertex.SplatVertex;
|
|
42
|
+
import org.cx4a.rsense.typing.vertex.ToAryVertex;
|
|
43
|
+
import org.cx4a.rsense.typing.vertex.TypeVarVertex;
|
|
44
|
+
import org.cx4a.rsense.typing.vertex.Vertex;
|
|
45
|
+
import org.cx4a.rsense.typing.vertex.YieldVertex;
|
|
46
|
+
import org.cx4a.rsense.util.Logger;
|
|
47
|
+
import org.cx4a.rsense.util.SourceLocation;
|
|
48
|
+
import org.jrubyparser.util.diff.Change;
|
|
49
|
+
import org.jrubyparser.util.diff.IsJunk;
|
|
50
|
+
|
|
51
|
+
public class RuntimeHelper {
|
|
52
|
+
public static final String TYPE_INFERENCE_METHOD_NAME = "__rsense_type_inference__";
|
|
53
|
+
public static final String FIND_DEFINITION_METHOD_NAME_PREFIX = "__rsense_find_definition__";
|
|
54
|
+
|
|
55
|
+
private RuntimeHelper() {}
|
|
56
|
+
|
|
57
|
+
public static Vertex assign(Graph graph, Node node) {
|
|
58
|
+
return assign(graph, node);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public static Vertex assign(Graph graph, Node node, Vertex src) {
|
|
62
|
+
switch (node.getNodeType()) {
|
|
63
|
+
case LOCALASGNNODE:
|
|
64
|
+
return localAssign(graph, (LocalAsgnNode) node, src);
|
|
65
|
+
case DASGNNODE:
|
|
66
|
+
return dynamicAssign(graph, (DAsgnNode) node, src);
|
|
67
|
+
case INSTASGNNODE:
|
|
68
|
+
return instanceAssign(graph, (InstAsgnNode) node, src);
|
|
69
|
+
case CONSTDECLNODE:
|
|
70
|
+
return constDeclaration(graph, (ConstDeclNode) node, src);
|
|
71
|
+
case CLASSVARASGNNODE:
|
|
72
|
+
return classVarAssign(graph, (ClassVarAsgnNode) node, src);
|
|
73
|
+
case CLASSVARDECLNODE:
|
|
74
|
+
return classVarDeclaration(graph, (ClassVarDeclNode) node, src);
|
|
75
|
+
case ARGUMENTNODE:
|
|
76
|
+
case RESTARG:
|
|
77
|
+
return argumentAssign(graph, (ArgumentNode) node, src);
|
|
78
|
+
}
|
|
79
|
+
Logger.error("unknown assignable node: %s", node);
|
|
80
|
+
Logger.message("Type: %s", node.getNodeType());
|
|
81
|
+
throw new RuntimeException("Unknown: " + node);
|
|
82
|
+
// return Vertex.EMPTY;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public static Vertex localAssign(Graph graph, LocalAsgnNode node) {
|
|
86
|
+
return localAssign(graph, node, null);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public static Vertex localAssign(Graph graph, LocalAsgnNode node, Vertex src) {
|
|
90
|
+
Scope scope = graph.getRuntime().getContext().getCurrentScope();
|
|
91
|
+
VertexHolder holder = (VertexHolder) scope.getValue(node.getName());
|
|
92
|
+
if (src == null) {
|
|
93
|
+
src = graph.createVertex(node.getValue());
|
|
94
|
+
}
|
|
95
|
+
if (holder == null) {
|
|
96
|
+
holder = graph.createFreeVertexHolder();
|
|
97
|
+
scope.setValue(node.getName(), holder);
|
|
98
|
+
}
|
|
99
|
+
graph.addEdgeAndPropagate(src, holder.getVertex());
|
|
100
|
+
return src;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public static Vertex dynamicAssign(Graph graph, DAsgnNode node) {
|
|
104
|
+
return dynamicAssign(graph, node, null);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public static Vertex dynamicAssign(Graph graph, Node node, Vertex src) {
|
|
108
|
+
Scope scope = graph.getRuntime().getContext().getCurrentScope();
|
|
109
|
+
if (node.getNodeType() == NodeType.DASGNNODE) {
|
|
110
|
+
DAsgnNode dAsgnNode = (DAsgnNode) node;
|
|
111
|
+
|
|
112
|
+
VertexHolder holder = (VertexHolder) scope.getValue(dAsgnNode.getName());
|
|
113
|
+
if (src == null) {
|
|
114
|
+
src = graph.createVertex(dAsgnNode.getValue());
|
|
115
|
+
}
|
|
116
|
+
if (holder == null) {
|
|
117
|
+
holder = graph.createFreeVertexHolder();
|
|
118
|
+
scope.setValue(dAsgnNode.getName(), holder);
|
|
119
|
+
}
|
|
120
|
+
graph.addEdgeAndPropagate(src, holder.getVertex());
|
|
121
|
+
return src;
|
|
122
|
+
|
|
123
|
+
} else {
|
|
124
|
+
ArgumentNode argumentNode = (ArgumentNode) node;
|
|
125
|
+
|
|
126
|
+
VertexHolder holder = (VertexHolder) scope.getValue(argumentNode.getName());
|
|
127
|
+
if (src == null) {
|
|
128
|
+
src = graph.createVertex(null);
|
|
129
|
+
}
|
|
130
|
+
if (holder == null) {
|
|
131
|
+
holder = graph.createFreeVertexHolder();
|
|
132
|
+
scope.setValue(argumentNode.getName(), holder);
|
|
133
|
+
}
|
|
134
|
+
graph.addEdgeAndPropagate(src, holder.getVertex());
|
|
135
|
+
return src;
|
|
136
|
+
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
public static Vertex instanceAssign(Graph graph, InstAsgnNode node) {
|
|
143
|
+
return instanceAssign(graph, node, null);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public static Vertex instanceAssign(Graph graph, InstAsgnNode node, Vertex src) {
|
|
147
|
+
IRubyObject self = graph.getRuntime().getContext().getFrameSelf();
|
|
148
|
+
VertexHolder holder = (VertexHolder) self.getInstVar(node.getName());
|
|
149
|
+
if (src == null) {
|
|
150
|
+
src = graph.createVertex(node.getValue());
|
|
151
|
+
}
|
|
152
|
+
if (holder == null) {
|
|
153
|
+
holder = graph.createFreeVertexHolder();
|
|
154
|
+
self.setInstVar(node.getName(), holder);
|
|
155
|
+
}
|
|
156
|
+
graph.addEdgeAndPropagate(src, holder.getVertex());
|
|
157
|
+
return src;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
public static Vertex instanceVariable(Graph graph, InstVarNode node) {
|
|
162
|
+
IRubyObject self = graph.getRuntime().getContext().getFrameSelf();
|
|
163
|
+
VertexHolder holder = (VertexHolder) self.getInstVar(node.getName());
|
|
164
|
+
if (holder == null) {
|
|
165
|
+
holder = graph.createFreeVertexHolder();
|
|
166
|
+
self.setInstVar(node.getName(), holder);
|
|
167
|
+
}
|
|
168
|
+
return holder.getVertex();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public static Vertex classVarDeclaration(Graph graph, ClassVarDeclNode node) {
|
|
172
|
+
return classVarDeclaration(graph, node, null);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public static Vertex classVarDeclaration(Graph graph, ClassVarDeclNode node, Vertex src) {
|
|
176
|
+
RubyModule klass = graph.getRuntime().getContext().getFrameModule();
|
|
177
|
+
if (src == null) {
|
|
178
|
+
src = graph.createVertex(node.getValue());
|
|
179
|
+
}
|
|
180
|
+
VertexHolder holder = (VertexHolder) klass.getClassVar(node.getName());
|
|
181
|
+
if (holder == null) {
|
|
182
|
+
holder = graph.createFreeVertexHolder();
|
|
183
|
+
klass.setClassVar(node.getName(), holder);
|
|
184
|
+
}
|
|
185
|
+
// Clear older types (performance issue)
|
|
186
|
+
holder.getVertex().getTypeSet().clear();
|
|
187
|
+
graph.addEdgeAndPropagate(src, holder.getVertex());
|
|
188
|
+
return src;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
public static Vertex classVarAssign(Graph graph, ClassVarAsgnNode node) {
|
|
192
|
+
return classVarAssign(graph, node, null);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public static Vertex classVarAssign(Graph graph, ClassVarAsgnNode node, Vertex src) {
|
|
196
|
+
RubyModule klass = graph.getRuntime().getContext().getFrameModule();
|
|
197
|
+
if (src == null) {
|
|
198
|
+
src = graph.createVertex(node.getValue());
|
|
199
|
+
}
|
|
200
|
+
VertexHolder holder = (VertexHolder) klass.getClassVar(node.getName());
|
|
201
|
+
if (holder == null) {
|
|
202
|
+
holder = graph.createFreeVertexHolder();
|
|
203
|
+
klass.setClassVar(node.getName(), holder);
|
|
204
|
+
}
|
|
205
|
+
// Clear older types (performance issue)
|
|
206
|
+
holder.getVertex().getTypeSet().clear();
|
|
207
|
+
graph.addEdgeAndPropagate(src, holder.getVertex());
|
|
208
|
+
return src;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
public static Vertex classVariable(Graph graph, ClassVarNode node) {
|
|
212
|
+
RubyModule klass = graph.getRuntime().getContext().getFrameModule();
|
|
213
|
+
VertexHolder holder = (VertexHolder) klass.getClassVar(node.getName());
|
|
214
|
+
if (holder == null) {
|
|
215
|
+
holder = graph.createFreeVertexHolder();
|
|
216
|
+
klass.setClassVar(node.getName(), holder);
|
|
217
|
+
}
|
|
218
|
+
return holder.getVertex();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
public static Vertex constDeclaration(Graph graph, ConstDeclNode node) {
|
|
222
|
+
return constDeclaration(graph, node, null);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
public static Vertex constDeclaration(Graph graph, ConstDeclNode node, Vertex src) {
|
|
226
|
+
RubyModule module = null;
|
|
227
|
+
String name = null;
|
|
228
|
+
INameNode constNode = (INameNode) node.getConstNode();
|
|
229
|
+
if (constNode == null) {
|
|
230
|
+
name = node.getName();
|
|
231
|
+
module = graph.getRuntime().getContext().getFrameModule();
|
|
232
|
+
} else if (constNode instanceof Colon2Node) {
|
|
233
|
+
Node leftNode = ((Colon2Node) constNode).getLeftNode();
|
|
234
|
+
|
|
235
|
+
Vertex v = graph.createVertex(leftNode);
|
|
236
|
+
for (IRubyObject mod : v.getTypeSet()) {
|
|
237
|
+
if (mod instanceof RubyModule) {
|
|
238
|
+
module = (RubyModule) mod;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
name = constNode.getName();
|
|
243
|
+
} else { // colon3
|
|
244
|
+
module = graph.getRuntime().getObject();
|
|
245
|
+
name = constNode.getName();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (src == null) {
|
|
249
|
+
src = graph.createVertex(node.getValue());
|
|
250
|
+
}
|
|
251
|
+
if (module != null && name != null) {
|
|
252
|
+
module.setConstant(name, graph.createVertexHolder(src));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return src;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
public static Vertex globalAssign(Graph graph, GlobalAsgnNode node) {
|
|
259
|
+
return globalAssign(graph, node, null);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
public static Vertex globalAssign(Graph graph, GlobalAsgnNode node, Vertex src) {
|
|
263
|
+
Ruby runtime = graph.getRuntime();
|
|
264
|
+
VertexHolder holder = (VertexHolder) runtime.getGlobalVar(node.getName());
|
|
265
|
+
if (src == null) {
|
|
266
|
+
src = graph.createVertex(node.getValue());
|
|
267
|
+
}
|
|
268
|
+
if (holder == null) {
|
|
269
|
+
holder = graph.createFreeVertexHolder();
|
|
270
|
+
runtime.setGlobalVar(node.getName(), holder);
|
|
271
|
+
}
|
|
272
|
+
// Clear older types (performance issue)
|
|
273
|
+
holder.getVertex().getTypeSet().clear();
|
|
274
|
+
graph.addEdgeAndPropagate(src, holder.getVertex());
|
|
275
|
+
return src;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
public static Vertex globalVariable(Graph graph, GlobalVarNode node) {
|
|
279
|
+
Ruby runtime = graph.getRuntime();
|
|
280
|
+
VertexHolder holder = (VertexHolder) runtime.getGlobalVar(node.getName());
|
|
281
|
+
if (holder == null) {
|
|
282
|
+
holder = graph.createFreeVertexHolder();
|
|
283
|
+
runtime.setGlobalVar(node.getName(), holder);
|
|
284
|
+
}
|
|
285
|
+
return holder.getVertex();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
public static void aliasGlobalVariables(Graph graph, String newName, String oldName) {
|
|
289
|
+
Ruby runtime = graph.getRuntime();
|
|
290
|
+
VertexHolder holder = (VertexHolder) runtime.getGlobalVar(oldName);
|
|
291
|
+
if (holder == null) {
|
|
292
|
+
holder = graph.createFreeVertexHolder();
|
|
293
|
+
runtime.setGlobalVar(oldName, holder);
|
|
294
|
+
}
|
|
295
|
+
runtime.setGlobalVar(newName, holder); // no propagation ?
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
public static void blockAssign(Graph graph, BlockArgNode node, Block block) {
|
|
299
|
+
if (block == null)
|
|
300
|
+
return;
|
|
301
|
+
|
|
302
|
+
Scope scope = graph.getRuntime().getContext().getCurrentScope();
|
|
303
|
+
VertexHolder holder = (VertexHolder) scope.getValue(node.getName());
|
|
304
|
+
if (holder == null) {
|
|
305
|
+
holder = graph.createFreeVertexHolder();
|
|
306
|
+
scope.setValue(node.getName(), holder);
|
|
307
|
+
}
|
|
308
|
+
holder.getVertex().addType((Proc) block);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
public static int handleOptArgs(OptArgNode optArgs, Graph graph, Vertex[] args, Block block, int num) {
|
|
312
|
+
int argsCount = 0;
|
|
313
|
+
for (Node node: optArgs.childNodes()) {
|
|
314
|
+
assign(graph, node, args[num + argsCount]);
|
|
315
|
+
argsCount++;
|
|
316
|
+
// System.out.println("Debug: " + optArgs);
|
|
317
|
+
}
|
|
318
|
+
return argsCount;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
public static void argsAssign(Graph graph, ArgsNode argsNode, Vertex[] args, Block block) {
|
|
322
|
+
Scope scope = graph.getRuntime().getContext().getCurrentScope();
|
|
323
|
+
ListNode pre = argsNode.getPre();
|
|
324
|
+
ListNode post = argsNode.getPost();
|
|
325
|
+
int preCount = argsNode.getPreCount();
|
|
326
|
+
int postCount = argsNode.getPostCount();
|
|
327
|
+
if (preCount > 0) {
|
|
328
|
+
int size = pre.size();
|
|
329
|
+
for (int i = 0; i < size; i++) {
|
|
330
|
+
Node next = pre.get(i);
|
|
331
|
+
Vertex arg = i < args.length ? args[i] : Vertex.EMPTY;
|
|
332
|
+
assign(graph, next, arg);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (postCount > 0) {
|
|
336
|
+
int size = post.size();
|
|
337
|
+
int argsLength = args.length;
|
|
338
|
+
for (int i = 0; i < size; i++) {
|
|
339
|
+
Node next = post.get(i);
|
|
340
|
+
Vertex arg = argsLength - postCount + i < args.length
|
|
341
|
+
? args[argsLength - postCount + i]
|
|
342
|
+
: Vertex.EMPTY;
|
|
343
|
+
if (next instanceof AssignableNode) {
|
|
344
|
+
assign(graph, next, arg);
|
|
345
|
+
} else {
|
|
346
|
+
//scope.setValue(((INameNode) next).getName(), arg);
|
|
347
|
+
Logger.fixme("argsAssign2");
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
int index = preCount;
|
|
353
|
+
ListNode optArgs = argsNode.getOptional();
|
|
354
|
+
Node restArgNode = argsNode.getRest();
|
|
355
|
+
int restArg = argsNode.getRest() == null ? -1 : argsNode.getRest().getIndex();
|
|
356
|
+
int givenArgsCount = preCount;
|
|
357
|
+
if (optArgs != null) {
|
|
358
|
+
int j = 0;
|
|
359
|
+
for (int i = preCount; i < args.length - postCount && j < optArgs.size(); i++, j++) {
|
|
360
|
+
if (optArgs.get(j).getNodeType() == NodeType.OPTARGNODE) {
|
|
361
|
+
int plusCount = handleOptArgs((OptArgNode)optArgs.get(j), graph, args, block, i);
|
|
362
|
+
givenArgsCount+= plusCount;
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
assign(graph, optArgs.get(j), args[i]);
|
|
366
|
+
givenArgsCount++;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
for (int i = 0; j < optArgs.size(); i++, j++) {
|
|
370
|
+
if (optArgs.get(j).getNodeType() == NodeType.OPTARGNODE) {
|
|
371
|
+
graph.createVertex(optArgs.get(j).childNodes().get(0));
|
|
372
|
+
}
|
|
373
|
+
graph.createVertex(optArgs.get(j));
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (restArg >= 0) {
|
|
377
|
+
int sizeOfRestArg = args.length - postCount - givenArgsCount;
|
|
378
|
+
if (sizeOfRestArg <= 0) {
|
|
379
|
+
assign(graph, restArgNode, createArrayVertex(graph, null, null));
|
|
380
|
+
} else {
|
|
381
|
+
assign(graph, restArgNode, createArrayVertex(graph, null, args, givenArgsCount, sizeOfRestArg));
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (argsNode.getBlock() != null) {
|
|
385
|
+
blockAssign(graph, argsNode.getBlock(), block);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
public static Vertex argumentAssign(Graph graph, ArgumentNode node, Vertex src) {
|
|
390
|
+
Scope scope = graph.getRuntime().getContext().getCurrentScope();
|
|
391
|
+
VertexHolder holder = graph.createFreeVertexHolder();
|
|
392
|
+
scope.setValue(node.getName(), holder);
|
|
393
|
+
if (src != null) {
|
|
394
|
+
graph.addEdgeAndUpdate(src, holder.getVertex());
|
|
395
|
+
}
|
|
396
|
+
return src;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
public static Vertex multipleAssign(Graph graph, MultipleAsgnNode node) {
|
|
400
|
+
return multipleAssign(graph, node, (Vertex) null);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
public static Vertex multipleAssign(Graph graph, MultipleAsgnNode node, Vertex src) {
|
|
404
|
+
if (src == null) {
|
|
405
|
+
src = graph.createVertex(node.getValue());
|
|
406
|
+
}
|
|
407
|
+
MultipleAsgnVertex vertex = new MultipleAsgnVertex(node, src);
|
|
408
|
+
graph.addEdgeAndPropagate(src, vertex);
|
|
409
|
+
return src;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
public static void multiAssignfromArgsNode(Graph graph, ArgsNode node, IRubyObject object) {
|
|
413
|
+
boolean isArray = object instanceof Array;
|
|
414
|
+
Array array = null;
|
|
415
|
+
Vertex element = Vertex.EMPTY;
|
|
416
|
+
|
|
417
|
+
if (isArray) {
|
|
418
|
+
array = (Array) object;
|
|
419
|
+
if (array.isModified()) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
} else {
|
|
423
|
+
TypeVarMap tvmap = getTypeVarMap(object);
|
|
424
|
+
TypeVariable var = TypeVariable.valueOf("t");
|
|
425
|
+
if (tvmap != null && tvmap.containsKey(var)) {
|
|
426
|
+
element = tvmap.get(var);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
int valLen = array != null ? array.length() : 256; // magic number
|
|
431
|
+
int varLen = node.getPre() == null ? 0 : node.getPre().size();
|
|
432
|
+
|
|
433
|
+
int j = 0;
|
|
434
|
+
for (; j < valLen && j < varLen; j++) {
|
|
435
|
+
dynamicAssign(graph, node.getPre().get(j), array != null ? array.getElement(j) : element);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
Node argsNode = node.getRest();
|
|
439
|
+
if (argsNode != null) {
|
|
440
|
+
if (argsNode.getNodeType() == NodeType.STARNODE) {
|
|
441
|
+
// no check for '*'
|
|
442
|
+
} else if (varLen < valLen && array != null) {
|
|
443
|
+
assign(graph, argsNode, createArrayVertex(graph, null, array.getElements(), varLen, valLen - varLen));
|
|
444
|
+
} else {
|
|
445
|
+
Vertex[] elements = null;
|
|
446
|
+
if (element != null) {
|
|
447
|
+
elements = new Vertex[] { element };
|
|
448
|
+
}
|
|
449
|
+
assign(graph, argsNode, createArrayVertex(graph, null, elements));
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
while (j < varLen) {
|
|
454
|
+
assign(graph, node.getPre().get(j++), element);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
public static void multipleAssign(Graph graph, MultipleAsgnNode node, IRubyObject object) {
|
|
459
|
+
boolean isArray = object instanceof Array;
|
|
460
|
+
Array array = null;
|
|
461
|
+
Vertex element = Vertex.EMPTY;
|
|
462
|
+
|
|
463
|
+
if (isArray) {
|
|
464
|
+
array = (Array) object;
|
|
465
|
+
if (array.isModified()) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
} else {
|
|
469
|
+
TypeVarMap tvmap = getTypeVarMap(object);
|
|
470
|
+
TypeVariable var = TypeVariable.valueOf("t");
|
|
471
|
+
if (tvmap != null && tvmap.containsKey(var)) {
|
|
472
|
+
element = tvmap.get(var);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
int valLen = array != null ? array.length() : 256; // magic number
|
|
477
|
+
int varLen = node.getPre() == null ? 0 : node.getPre().size();
|
|
478
|
+
|
|
479
|
+
int j = 0;
|
|
480
|
+
for (; j < valLen && j < varLen; j++) {
|
|
481
|
+
assign(graph, node.getPre().get(j), array != null ? array.getElement(j) : element);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
Node argsNode = node.getRest();
|
|
485
|
+
if (argsNode != null) {
|
|
486
|
+
if (argsNode.getNodeType() == NodeType.STARNODE) {
|
|
487
|
+
// no check for '*'
|
|
488
|
+
} else if (varLen < valLen && array != null) {
|
|
489
|
+
assign(graph, argsNode, createArrayVertex(graph, null, array.getElements(), varLen, valLen - varLen));
|
|
490
|
+
} else {
|
|
491
|
+
Vertex[] elements = null;
|
|
492
|
+
if (element != null) {
|
|
493
|
+
elements = new Vertex[] { element };
|
|
494
|
+
}
|
|
495
|
+
assign(graph, argsNode, createArrayVertex(graph, null, elements));
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
while (j < varLen) {
|
|
500
|
+
assign(graph, node.getPre().get(j++), element);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
public static Vertex[] setupCallArgs(Graph graph, Node argsNode) {
|
|
505
|
+
List<Vertex> args = new ArrayList<Vertex>();
|
|
506
|
+
if (argsNode != null) {
|
|
507
|
+
switch (argsNode.getNodeType()) {
|
|
508
|
+
case ARGSCATNODE:
|
|
509
|
+
case SPLATNODE: {
|
|
510
|
+
Vertex arrayVertex = graph.createVertex(argsNode);
|
|
511
|
+
for (IRubyObject object : arrayVertex.getTypeSet()) {
|
|
512
|
+
if (object instanceof Array) {
|
|
513
|
+
Array array = (Array) object;
|
|
514
|
+
if (array.getElements() != null) {
|
|
515
|
+
for (Vertex element : array.getElements()) {
|
|
516
|
+
args.add(element);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
default:
|
|
524
|
+
for (Node arg : argsNode.childNodes()) {
|
|
525
|
+
args.add(graph.createVertex(arg));
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return args.isEmpty() ? null : args.toArray(new Vertex[0]);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
public static Block setupCallBlock(Graph graph, Node iterNode) {
|
|
533
|
+
Context context = graph.getRuntime().getContext();
|
|
534
|
+
Block block = null;
|
|
535
|
+
if (iterNode != null) {
|
|
536
|
+
switch (iterNode.getNodeType()) {
|
|
537
|
+
case ITERNODE: {
|
|
538
|
+
IterNode inode = (IterNode) iterNode;
|
|
539
|
+
DynamicScope scope = new DynamicScope(context.getCurrentScope().getModule(), context.getCurrentScope());
|
|
540
|
+
block = new Proc(graph.getRuntime(), inode.getVar(), inode.getBody(), context.getCurrentFrame(), scope);
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
case BLOCKPASSNODE:
|
|
544
|
+
block = context.getFrameBlock();
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return block;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
public static Vertex call(Graph graph, CallVertex vertex) {
|
|
552
|
+
return call(graph, vertex, false);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
public static Vertex callSuper(Graph graph, CallVertex vertex) {
|
|
556
|
+
return call(graph, vertex, true);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
private static Vertex call(Graph graph, CallVertex vertex, boolean callSuper) {
|
|
560
|
+
if (vertex.isApplicable() && vertex.isChanged()) {
|
|
561
|
+
vertex.markUnchanged();
|
|
562
|
+
|
|
563
|
+
String name = vertex.getName();
|
|
564
|
+
TypeSet receivers = vertex.getReceiverVertex().getTypeSet();
|
|
565
|
+
Block block = vertex.getBlock();
|
|
566
|
+
boolean noReturn = false;
|
|
567
|
+
Vertex[] argVertices = vertex.getArgVertices();
|
|
568
|
+
SpecialMethod.Result prevResult = null;
|
|
569
|
+
TypeSet accumulator = new TypeSet();
|
|
570
|
+
|
|
571
|
+
while (!receivers.isEmpty()) {
|
|
572
|
+
SpecialMethod.Result result = new SpecialMethod.Result(prevResult, accumulator);
|
|
573
|
+
prevResult = result;
|
|
574
|
+
SpecialMethod spec = graph.getSpecialMethod(name);
|
|
575
|
+
if (spec != null) {
|
|
576
|
+
spec.call(graph.getRuntime(), receivers, argVertices, block, result);
|
|
577
|
+
if (result.getResultTypeSet() != null) {
|
|
578
|
+
accumulator.addAll(result.getResultTypeSet());
|
|
579
|
+
}
|
|
580
|
+
if (result.hasPrivateVisibility()) {
|
|
581
|
+
vertex.setPrivateVisibility(true);
|
|
582
|
+
}
|
|
583
|
+
if (result.isNeverCallAgain()) {
|
|
584
|
+
vertex.cutout();
|
|
585
|
+
} else if (!result.isCallNextMethod()) {
|
|
586
|
+
break;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
List<Collection<IRubyObject>> args = new ArrayList<Collection<IRubyObject>>();
|
|
591
|
+
if (vertex.getArgVertices() != null) {
|
|
592
|
+
for (Vertex v : argVertices) {
|
|
593
|
+
args.add(v.getTypeSet());
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
List<TemplateAttribute> attrs = generateTemplateAttributes(receivers, args, block);
|
|
598
|
+
boolean applied = false;
|
|
599
|
+
for (TemplateAttribute attr : attrs) {
|
|
600
|
+
Vertex returnVertex = applyTemplateAttribute(graph, vertex, name, attr, callSuper);
|
|
601
|
+
if (returnVertex != null) {
|
|
602
|
+
applied = true;
|
|
603
|
+
if (!noReturn)
|
|
604
|
+
accumulator.addAll(returnVertex.getTypeSet());
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
if (!applied)
|
|
608
|
+
graph.notifyMethodMissingEvent(vertex);
|
|
609
|
+
if (result.isNextMethodChange()) {
|
|
610
|
+
name = result.getNextMethodName();
|
|
611
|
+
receivers = result.getNextMethodReceivers();
|
|
612
|
+
block = result.getNextMethodBlock();
|
|
613
|
+
noReturn = result.isNextMethodNoReturn();
|
|
614
|
+
} else {
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
vertex.addTypes(accumulator);
|
|
620
|
+
}
|
|
621
|
+
return vertex;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
public static void methodPartialUpdate(Graph graph, MethodDefNode node, DynamicMethod newMethod, DynamicMethod oldMethod, IRubyObject receiver) {
|
|
625
|
+
if (newMethod instanceof Method && oldMethod instanceof Method) {
|
|
626
|
+
Method newmeth = (Method) newMethod;
|
|
627
|
+
Method oldmeth = (Method) oldMethod;
|
|
628
|
+
|
|
629
|
+
if (shouldShare(node, oldmeth)) {
|
|
630
|
+
newmeth.shareTemplates(oldmeth);
|
|
631
|
+
} else {
|
|
632
|
+
Logger.debug(SourceLocation.of(node), "templates not shared: %s", newmeth);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
public static boolean shouldShare(MethodDefNode node, Method oldmeth) {
|
|
639
|
+
|
|
640
|
+
if ((node.getArgs() != null && oldmeth.getArgsNode() != null) && (node.getBody() != null && oldmeth.getBodyNode() != null)) {
|
|
641
|
+
Node nodeArgs = node.getArgs();
|
|
642
|
+
Node omethArgs = oldmeth.getArgsNode();
|
|
643
|
+
Node nodeBody = skipNewLines(node.getBody());
|
|
644
|
+
Node omethBody = skipNewLines(oldmeth.getBodyNode());
|
|
645
|
+
|
|
646
|
+
if ((isRsenseCallNode(nodeArgs)) || (isRsenseCallNode(nodeBody))) {
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if ((nodeArgs.isSame(omethArgs)) && (nodeBody.isSame(omethBody))) {
|
|
651
|
+
return true;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
return false;
|
|
656
|
+
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
public static boolean isRsenseCallNode(Node a) {
|
|
660
|
+
if (a.getNodeType() == NodeType.CALLNODE) {
|
|
661
|
+
String name = ((INameNode) a).getName();
|
|
662
|
+
if (name.equals(TYPE_INFERENCE_METHOD_NAME)
|
|
663
|
+
|| name.startsWith(FIND_DEFINITION_METHOD_NAME_PREFIX)) {
|
|
664
|
+
// scratch!
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
public static Node skipNewLines(Node node) {
|
|
672
|
+
if (node.getNodeType() == NodeType.NEWLINENODE) {
|
|
673
|
+
return ((NewlineNode) node).getNextNode();
|
|
674
|
+
} else {
|
|
675
|
+
return node;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
public static void classPartialUpdate(Graph graph, RubyModule klass, Node bodyNode) {
|
|
680
|
+
|
|
681
|
+
if (bodyNode != null) {
|
|
682
|
+
ClassTag oldTag = getClassTag(klass);
|
|
683
|
+
if (oldTag != null) {
|
|
684
|
+
ArrayList<Node> partialDiff = addToUndiff(bodyNode, oldTag.getBodyNode());
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
if ((partialDiff != null) && !(partialDiff.isEmpty())) {
|
|
688
|
+
Logger.debug(SourceLocation.of(bodyNode), "class partial update: %s %s", klass, partialDiff.size());
|
|
689
|
+
for (Node dirty : partialDiff) {
|
|
690
|
+
graph.createVertex(dirty);
|
|
691
|
+
}
|
|
692
|
+
} else {
|
|
693
|
+
graph.createVertex(bodyNode);
|
|
694
|
+
}
|
|
695
|
+
} else {
|
|
696
|
+
graph.createVertex(bodyNode);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
public static ArrayList<Node> addToUndiff(Node node, Node tagNode) {
|
|
702
|
+
if ((node == null) || (tagNode == null)) return null;
|
|
703
|
+
|
|
704
|
+
ArrayList<Node> undiff = new ArrayList<Node>();
|
|
705
|
+
|
|
706
|
+
List<Node> nkids = node.childNodes();
|
|
707
|
+
List<Node> tkids = tagNode.childNodes();
|
|
708
|
+
|
|
709
|
+
if ((nkids.isEmpty()) || (tkids.isEmpty())) return null;
|
|
710
|
+
|
|
711
|
+
if (nkids.size() == tkids.size()) {
|
|
712
|
+
for (int i = 0; i < nkids.size(); i++) {
|
|
713
|
+
Node nchild = nkids.get(i);
|
|
714
|
+
Node tchild = tkids.get(i);
|
|
715
|
+
|
|
716
|
+
if ((nchild == null) || (tchild == null)) continue;
|
|
717
|
+
|
|
718
|
+
if ((nchild instanceof ILocalScope && !(nchild instanceof RootNode))) {
|
|
719
|
+
if (nchild.isSame(tchild)) {
|
|
720
|
+
undiff.add(nchild);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return undiff;
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
public static void dummyCall(Graph graph, MethodDefNode node, Method method, IRubyObject receiver) {
|
|
733
|
+
if (node.getBody() != null) {
|
|
734
|
+
Context context = graph.getRuntime().getContext();
|
|
735
|
+
context.pushFrame(context.getFrameModule(), node.getName(), receiver, null, Visibility.PUBLIC);
|
|
736
|
+
context.pushScope(new LocalScope(method.getModule()));
|
|
737
|
+
graph.createVertex(node.getBody());
|
|
738
|
+
context.popScope();
|
|
739
|
+
context.popFrame();
|
|
740
|
+
}
|
|
741
|
+
Logger.debug(SourceLocation.of(node), "dummy call: %s", method);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
public static void dummyCallForTemplates(Graph graph, MethodDefNode node, Method method, Collection<TemplateAttribute> templateAttributes) {
|
|
745
|
+
String name = node.getName();
|
|
746
|
+
for (TemplateAttribute attr : templateAttributes) {
|
|
747
|
+
createTemplate(graph, null, name, method, attr);
|
|
748
|
+
}
|
|
749
|
+
Logger.debug(SourceLocation.of(node), "template dummy call: %s", method);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
private static Vertex applyTemplateAttribute(Graph graph, CallVertex vertex, String name, TemplateAttribute attr, boolean callSuper) {
|
|
753
|
+
IRubyObject receiver = attr.getReceiver();
|
|
754
|
+
IRubyObject[] args = attr.getArgs();
|
|
755
|
+
RubyClass receiverType = null;
|
|
756
|
+
if (callSuper) {
|
|
757
|
+
RubyModule module = graph.getRuntime().getContext().getFrameModule();
|
|
758
|
+
if (module instanceof RubyClass) {
|
|
759
|
+
RubyClass klass = (RubyClass) module;
|
|
760
|
+
receiverType = klass.getSuperClass();
|
|
761
|
+
} else {
|
|
762
|
+
Logger.error("Cannot call super in module");
|
|
763
|
+
return null;
|
|
764
|
+
}
|
|
765
|
+
} else if (receiver != null) {
|
|
766
|
+
receiverType = receiver.getMetaClass();
|
|
767
|
+
}
|
|
768
|
+
if (receiverType != null) {
|
|
769
|
+
Method method = (Method) receiverType.searchMethod(name);
|
|
770
|
+
if (method != null
|
|
771
|
+
&& (method.getVisibility() != Visibility.PRIVATE
|
|
772
|
+
|| vertex.hasPrivateVisibility())) {
|
|
773
|
+
Template template = method.getTemplate(attr);
|
|
774
|
+
if (template == null) {
|
|
775
|
+
template = createTemplate(graph, vertex, name, method, attr);
|
|
776
|
+
Logger.debug(SourceLocation.of(vertex), "template created: %s", method);
|
|
777
|
+
} else {
|
|
778
|
+
template.reproduceSideEffect(graph, receiver, args, vertex.getBlock());
|
|
779
|
+
Logger.debug(SourceLocation.of(vertex), "template reused: %s", method);
|
|
780
|
+
}
|
|
781
|
+
return template.getReturnVertex();
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
return null;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
private static Template createTemplate(Graph graph, CallVertex vertex, String name, Method method, TemplateAttribute attr) {
|
|
788
|
+
IRubyObject receiver = attr.getReceiver();
|
|
789
|
+
IRubyObject[] args = attr.getArgs();
|
|
790
|
+
Vertex[] argVertices = new Vertex[args.length];
|
|
791
|
+
for (int i = 0; i < argVertices.length; i++) {
|
|
792
|
+
argVertices[i] = graph.createFreeSingleTypeVertex(args[i]);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
Ruby runtime = graph.getRuntime();
|
|
796
|
+
Context context = runtime.getContext();
|
|
797
|
+
|
|
798
|
+
Block block = attr.getBlock();
|
|
799
|
+
Scope scope = new LocalScope(method.getModule());
|
|
800
|
+
context.pushFrame(context.getFrameModule(), name, receiver, block, Visibility.PUBLIC);
|
|
801
|
+
context.pushScope(scope);
|
|
802
|
+
|
|
803
|
+
Template template = new Template(method, context.getCurrentFrame(), scope, attr);
|
|
804
|
+
method.addTemplate(attr, template);
|
|
805
|
+
|
|
806
|
+
Vertex returnVertex = template.getReturnVertex();
|
|
807
|
+
setFrameTemplate(context.getCurrentFrame(), template);
|
|
808
|
+
|
|
809
|
+
AnnotationResolver.Result result = AnnotationHelper.resolveMethodAnnotation(graph, template);
|
|
810
|
+
|
|
811
|
+
if (result == AnnotationResolver.Result.UNRESOLVED) {
|
|
812
|
+
Logger.warn(SourceLocation.of(vertex), "annotation unmatched: %s", method);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
Vertex ret = method.call(graph, template, receiver, args, argVertices, block);
|
|
816
|
+
if (ret != null && result != AnnotationResolver.Result.RESOLVED) {
|
|
817
|
+
graph.addEdgeAndUpdate(ret, returnVertex);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
context.popScope();
|
|
821
|
+
context.popFrame();
|
|
822
|
+
|
|
823
|
+
return template;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
private static List<TemplateAttribute> generateTemplateAttributes(Collection<IRubyObject> receivers, List<Collection<IRubyObject>> args, Block block) {
|
|
827
|
+
int size = 1;
|
|
828
|
+
for (Collection<IRubyObject> c : args) {
|
|
829
|
+
size *= c.size();
|
|
830
|
+
}
|
|
831
|
+
if (size == 0) {
|
|
832
|
+
return Collections.emptyList();
|
|
833
|
+
} else if (size >= 128) {
|
|
834
|
+
Logger.warn("too big application: %s", size);
|
|
835
|
+
return Collections.emptyList();
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
int unit = size;
|
|
839
|
+
List<TemplateAttribute> result = new ArrayList<TemplateAttribute>(size);
|
|
840
|
+
for (int i = 0; i < size; i++) {
|
|
841
|
+
result.add(new TemplateAttribute(new IRubyObject[args.size()]));
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
for (int i = 0; i < args.size(); i++) {
|
|
845
|
+
Collection<IRubyObject> c = args.get(i);
|
|
846
|
+
Iterator<IRubyObject> ite = c.iterator();
|
|
847
|
+
int k = 0, n = c.size();
|
|
848
|
+
int newUnit = unit / n;
|
|
849
|
+
IRubyObject v = ite.next();
|
|
850
|
+
for (int j = 0; j < size; j++) {
|
|
851
|
+
result.get(j).setArg(i, v);
|
|
852
|
+
if (++k == newUnit) {
|
|
853
|
+
k = 0;
|
|
854
|
+
if (!ite.hasNext()) {
|
|
855
|
+
ite = c.iterator();
|
|
856
|
+
}
|
|
857
|
+
v = ite.next();
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
unit = newUnit;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// handle receiver polymorphic and data polymorphic
|
|
864
|
+
int resultSize = result.size();
|
|
865
|
+
for (int i = 0; i < resultSize; i++) {
|
|
866
|
+
TemplateAttribute base = result.get(i);
|
|
867
|
+
boolean first = true;
|
|
868
|
+
for (IRubyObject recv : receivers) {
|
|
869
|
+
base.setReceiver(recv);
|
|
870
|
+
base.setBlock(block);
|
|
871
|
+
if (recv instanceof PolymorphicObject) {
|
|
872
|
+
for (PolymorphicObject mrecv : ((PolymorphicObject) recv).generateMonomorphicObjects()) {
|
|
873
|
+
base.setReceiver(mrecv);
|
|
874
|
+
if (!first) {
|
|
875
|
+
result.add(base);
|
|
876
|
+
}
|
|
877
|
+
first = false;
|
|
878
|
+
base = base.clone();
|
|
879
|
+
}
|
|
880
|
+
} else {
|
|
881
|
+
if (!first) {
|
|
882
|
+
result.add(base);
|
|
883
|
+
}
|
|
884
|
+
first = false;
|
|
885
|
+
base = base.clone();
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// handle arguments data polymorphic
|
|
891
|
+
for (int i = 0; i < args.size(); i++) {
|
|
892
|
+
resultSize = result.size();
|
|
893
|
+
for (int j = 0; j < resultSize; j++) {
|
|
894
|
+
TemplateAttribute base = result.get(j);
|
|
895
|
+
IRubyObject arg = base.getArg(i);
|
|
896
|
+
if (arg instanceof PolymorphicObject) {
|
|
897
|
+
boolean first = true;
|
|
898
|
+
for (PolymorphicObject marg : ((PolymorphicObject) arg).generateMonomorphicObjects()) {
|
|
899
|
+
base.setArg(i, marg);
|
|
900
|
+
if (!first) {
|
|
901
|
+
result.add(base);
|
|
902
|
+
}
|
|
903
|
+
first = false;
|
|
904
|
+
base = base.clone();
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
return result;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
public static Vertex yield(Graph graph, Block block, IRubyObject arg, boolean expanded, Vertex returnVertex) {
|
|
914
|
+
return yield(graph, block, Arrays.asList(arg), expanded, returnVertex);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
public static Vertex yield(Graph graph, Block block, IRubyObject[] args, boolean expanded, Vertex returnVertex) {
|
|
918
|
+
return yield(graph, block, Arrays.asList(args), expanded, returnVertex);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
public static Vertex yield(Graph graph, Block block, Collection<IRubyObject> args, boolean expanded, Vertex returnVertex) {
|
|
922
|
+
if (block == null) {
|
|
923
|
+
return Vertex.EMPTY;
|
|
924
|
+
}
|
|
925
|
+
Ruby runtime = graph.getRuntime();
|
|
926
|
+
Context context = runtime.getContext();
|
|
927
|
+
|
|
928
|
+
Node varNode = block.getVarNode();
|
|
929
|
+
|
|
930
|
+
boolean noargblock = false;
|
|
931
|
+
boolean multiAssign = false;
|
|
932
|
+
MultipleAsgnNode masgn = null;
|
|
933
|
+
int preCount = 0;
|
|
934
|
+
boolean isRest = false;
|
|
935
|
+
Node rest = null;
|
|
936
|
+
ListNode pre = null;
|
|
937
|
+
Vertex vertex = graph.createFreeVertex();
|
|
938
|
+
|
|
939
|
+
if (varNode == null || varNode instanceof ZeroArgNode) {
|
|
940
|
+
noargblock = true;
|
|
941
|
+
} else if (varNode instanceof MultipleAsgnNode) {
|
|
942
|
+
masgn = (MultipleAsgnNode) varNode;
|
|
943
|
+
multiAssign = true;
|
|
944
|
+
preCount = masgn.getPre().size();
|
|
945
|
+
isRest = masgn.getRest() != null;
|
|
946
|
+
rest = masgn.getRest();
|
|
947
|
+
pre = masgn.getPre();
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
if (args != null && !args.isEmpty()) {
|
|
951
|
+
for (IRubyObject value : args) {
|
|
952
|
+
pushLoopFrame(context, block.getFrame(), returnVertex, vertex);
|
|
953
|
+
context.pushScope(block.getScope());
|
|
954
|
+
|
|
955
|
+
if (noargblock) {}
|
|
956
|
+
else if (multiAssign) {
|
|
957
|
+
Array array;
|
|
958
|
+
if (!expanded) {
|
|
959
|
+
array = to_ary(value, graph);
|
|
960
|
+
|
|
961
|
+
} else {
|
|
962
|
+
array = to_ary(value, graph);
|
|
963
|
+
}
|
|
964
|
+
multipleAssign(graph, masgn, array);
|
|
965
|
+
} else {
|
|
966
|
+
// TODO what do we do here?
|
|
967
|
+
if (varNode.getNodeType() == NodeType.ARGSNODE ) {
|
|
968
|
+
//debug
|
|
969
|
+
ArgsNode argsFromBlock = (ArgsNode) varNode;
|
|
970
|
+
|
|
971
|
+
if (argsFromBlock.getPre() != null) {
|
|
972
|
+
isRest = argsFromBlock.getRest() != null;
|
|
973
|
+
rest = argsFromBlock.getRest();
|
|
974
|
+
pre = argsFromBlock.getPre();
|
|
975
|
+
preCount = pre.size();
|
|
976
|
+
if (preCount > 1 || isRest) {
|
|
977
|
+
multiAssignfromArgsNode(graph, argsFromBlock, to_ary(value, graph));
|
|
978
|
+
} else {
|
|
979
|
+
dynamicAssign(graph, pre.get(0), graph.createFreeSingleTypeVertex(value));
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
} else {
|
|
983
|
+
argsAssign(graph, argsFromBlock, new Vertex[]{graph.createFreeSingleTypeVertex(value)}, block);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
} else {
|
|
987
|
+
assign(graph, varNode, graph.createFreeSingleTypeVertex(value));
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
if (block.getBodyNode() != null) {
|
|
992
|
+
Vertex v = graph.createVertex(block.getBodyNode());
|
|
993
|
+
graph.addEdgeAndPropagate(v, vertex);
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
context.popScope();
|
|
997
|
+
popLoopFrame(context);
|
|
998
|
+
}
|
|
999
|
+
} else {
|
|
1000
|
+
pushLoopFrame(context, block.getFrame(), returnVertex, vertex);
|
|
1001
|
+
context.pushScope(block.getScope());
|
|
1002
|
+
|
|
1003
|
+
if (block.getBodyNode() != null) {
|
|
1004
|
+
Vertex v = graph.createVertex(block.getBodyNode());
|
|
1005
|
+
graph.addEdgeAndPropagate(v, vertex);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
context.popScope();
|
|
1009
|
+
popLoopFrame(context);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
return vertex;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
public static Vertex yield(Graph graph, YieldVertex vertex) {
|
|
1016
|
+
Vertex returnVertex = null;
|
|
1017
|
+
if (vertex.getTemplate() != null)
|
|
1018
|
+
returnVertex = vertex.getTemplate().getReturnVertex();
|
|
1019
|
+
|
|
1020
|
+
// return immediately if no need to apply
|
|
1021
|
+
Proc block = (Proc) vertex.getBlock();
|
|
1022
|
+
Vertex argsVertex = vertex.getArgsVertex();
|
|
1023
|
+
if (block != null
|
|
1024
|
+
&& block.isApplied(vertex)
|
|
1025
|
+
&& (argsVertex == null
|
|
1026
|
+
|| !argsVertex.isChanged())) {
|
|
1027
|
+
return vertex;
|
|
1028
|
+
}
|
|
1029
|
+
if (argsVertex != null)
|
|
1030
|
+
argsVertex.markUnchanged();
|
|
1031
|
+
|
|
1032
|
+
if (block != null)
|
|
1033
|
+
block.recordYield(vertex);
|
|
1034
|
+
returnVertex = yield(graph, block, (argsVertex != null ? argsVertex.getTypeSet() : TypeSet.EMPTY), vertex.getExpandArguments(), returnVertex);
|
|
1035
|
+
if (returnVertex != null)
|
|
1036
|
+
graph.addEdgeAndUpdate(returnVertex, vertex);
|
|
1037
|
+
|
|
1038
|
+
return vertex;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
public static void splatValue(Graph graph, SplatVertex vertex) {
|
|
1042
|
+
vertex.addTypes(arrayValue(graph, vertex.getValueVertex()));
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
public static void toAryValue(Graph graph, ToAryVertex vertex) {
|
|
1046
|
+
vertex.addTypes(arrayValue(graph, vertex.getValueVertex()));
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
public static TypeSet arrayValue(Graph graph, Vertex vertex) {
|
|
1050
|
+
Ruby runtime = graph.getRuntime();
|
|
1051
|
+
TypeSet typeSet = new TypeSet();
|
|
1052
|
+
for (IRubyObject object : vertex.getTypeSet()) {
|
|
1053
|
+
if (object.isKindOf(runtime.getArray())) {
|
|
1054
|
+
typeSet.add(object);
|
|
1055
|
+
} else {
|
|
1056
|
+
CallVertex callVertex = new CallVertex(vertex.getNode(), "to_a", vertex, null, null);
|
|
1057
|
+
for (IRubyObject array : call(graph, callVertex).getTypeSet()) {
|
|
1058
|
+
if (array.isKindOf(runtime.getArray())) {
|
|
1059
|
+
typeSet.add(array);
|
|
1060
|
+
} else {
|
|
1061
|
+
Logger.warn("to_a should be return Array");
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
return typeSet;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
public static Array to_ary(IRubyObject value, Graph graph) {
|
|
1070
|
+
Array array;
|
|
1071
|
+
|
|
1072
|
+
if (value instanceof Array) {
|
|
1073
|
+
array = (Array) value;
|
|
1074
|
+
} else {
|
|
1075
|
+
array = createArray(graph, new Vertex[] { graph.createFreeSingleTypeVertex(value) });
|
|
1076
|
+
}
|
|
1077
|
+
return array;
|
|
1078
|
+
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
public static void aValueSplat(Graph graph, SValueVertex vertex) {
|
|
1082
|
+
for (IRubyObject object : vertex.getValueVertex().getTypeSet()) {
|
|
1083
|
+
if (object.isKindOf(graph.getRuntime().getArray())) {
|
|
1084
|
+
if (object instanceof Array) {
|
|
1085
|
+
Array array = (Array) object;
|
|
1086
|
+
if (!array.isModified()) {
|
|
1087
|
+
if (array.length() == 1) {
|
|
1088
|
+
vertex.update(array.getElement(0));
|
|
1089
|
+
} else {
|
|
1090
|
+
vertex.addType(object);
|
|
1091
|
+
}
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
TypeVariable var = TypeVariable.valueOf("t");
|
|
1096
|
+
TypeVarMap tvmap = getTypeVarMap(object);
|
|
1097
|
+
if (tvmap != null && tvmap.containsKey(var)) {
|
|
1098
|
+
vertex.update(tvmap.get(var));
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
public static RubyModule getNamespace(Graph graph, Colon3Node node) {
|
|
1105
|
+
if (node instanceof Colon2ImplicitNode) {
|
|
1106
|
+
return graph.getRuntime().getContext().getFrameModule();
|
|
1107
|
+
} else if (node instanceof Colon2Node) {
|
|
1108
|
+
Vertex left = graph.createVertex(((Colon2Node) node).getLeftNode());
|
|
1109
|
+
IRubyObject object = left.singleType();
|
|
1110
|
+
if (object instanceof RubyModule) {
|
|
1111
|
+
return (RubyModule) object;
|
|
1112
|
+
} else {
|
|
1113
|
+
return null;
|
|
1114
|
+
}
|
|
1115
|
+
} else if (node instanceof Colon3Node) {
|
|
1116
|
+
return graph.getRuntime().getObject();
|
|
1117
|
+
}
|
|
1118
|
+
Logger.fixme("Namespace unresolved: %s", node);
|
|
1119
|
+
return null;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
public static Template getFrameTemplate(Frame frame) {
|
|
1123
|
+
Object tag;
|
|
1124
|
+
while (frame != null) {
|
|
1125
|
+
tag = frame.getTag();
|
|
1126
|
+
if (tag instanceof Template) {
|
|
1127
|
+
return (Template) tag;
|
|
1128
|
+
}
|
|
1129
|
+
frame = frame.getPrevious();
|
|
1130
|
+
}
|
|
1131
|
+
return null;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
public static void setFrameTemplate(Frame frame, Template template) {
|
|
1135
|
+
frame.setTag(template);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
public static LoopTag getFrameLoopTag(Frame frame) {
|
|
1139
|
+
Object tag = frame.getTag();
|
|
1140
|
+
if (tag instanceof LoopTag) {
|
|
1141
|
+
return (LoopTag) tag;
|
|
1142
|
+
} else {
|
|
1143
|
+
return null;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
public static void pushLoopFrame(Context context, Vertex returnVertex, Vertex yieldVertex) {
|
|
1148
|
+
pushLoopFrame(context, context.getCurrentFrame(), returnVertex, yieldVertex);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
public static void pushLoopFrame(Context context, Frame prev, Vertex returnVertex, Vertex yieldVertex) {
|
|
1152
|
+
Frame frame = context.pushFrame(prev.getModule(), prev.getName(), prev.getSelf(), prev.getBlock(), prev.getVisibility());
|
|
1153
|
+
frame.setTag(new LoopTag(returnVertex, yieldVertex));
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
public static void popLoopFrame(Context context) {
|
|
1157
|
+
context.popFrame();
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
public static ClassTag getClassTag(RubyModule klass) {
|
|
1161
|
+
if (klass instanceof MetaClass) {
|
|
1162
|
+
MetaClass metaClass = (MetaClass) klass;
|
|
1163
|
+
if (metaClass.getAttached() instanceof RubyModule) {
|
|
1164
|
+
klass = (RubyModule) metaClass.getAttached();
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
if (klass != null && klass.getTag() instanceof ClassTag) {
|
|
1168
|
+
return (ClassTag) klass.getTag();
|
|
1169
|
+
} else {
|
|
1170
|
+
return null;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
public static ClassType getClassAnnotation(RubyModule klass) {
|
|
1175
|
+
ClassTag tag = getClassTag(klass);
|
|
1176
|
+
return tag != null ? tag.getType() : null;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
public static void setClassTag(RubyModule klass, Node node, List<TypeAnnotation> annotations) {
|
|
1180
|
+
if (getClassAnnotation(klass) == null) {
|
|
1181
|
+
ClassType type = null;
|
|
1182
|
+
for (TypeAnnotation annot : annotations) {
|
|
1183
|
+
if (annot instanceof ClassType) {
|
|
1184
|
+
type = (ClassType) annot;
|
|
1185
|
+
break;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
klass.setTag(new ClassTag(node, type));
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
public static void setMethodTag(Method method, /*unused*/Node node, List<TypeAnnotation> annotations) {
|
|
1193
|
+
if (!annotations.isEmpty()) {
|
|
1194
|
+
List<MethodType> types = new ArrayList<MethodType>();
|
|
1195
|
+
for (TypeAnnotation annot : annotations) {
|
|
1196
|
+
if (annot instanceof MethodType) {
|
|
1197
|
+
types.add((MethodType) annot);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
method.setAnnotations(types);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
public static ClassTag getEnclosingClassTag(RubyModule module) {
|
|
1205
|
+
ClassTag tag;
|
|
1206
|
+
while (module != null) {
|
|
1207
|
+
tag = getClassTag(module);
|
|
1208
|
+
if (tag != null) {
|
|
1209
|
+
return tag;
|
|
1210
|
+
}
|
|
1211
|
+
module = module.getParent();
|
|
1212
|
+
}
|
|
1213
|
+
return null;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
public static ClassType getEnclosingClassAnnotation(RubyModule module) {
|
|
1217
|
+
ClassTag tag = getEnclosingClassTag(module);
|
|
1218
|
+
return tag != null ? tag.getType() : null;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
public static TypeVarMap getTypeVarMap(IRubyObject object) {
|
|
1222
|
+
if (object.getTag() instanceof TypeVarMap) {
|
|
1223
|
+
return (TypeVarMap) object.getTag();
|
|
1224
|
+
} else {
|
|
1225
|
+
return null;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
public static Array createArray(Graph graph, Vertex[] elements) {
|
|
1230
|
+
Array array = new Array(graph.getRuntime(), elements);
|
|
1231
|
+
TypeVarVertex t = new TypeVarVertex(array);
|
|
1232
|
+
array.setTypeVarVertex(t);
|
|
1233
|
+
return array;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
public static Vertex createArrayVertex(Graph graph, Node node, Vertex[] elements) {
|
|
1237
|
+
Array array = createArray(graph, elements);
|
|
1238
|
+
Vertex vertex = new PassThroughVertex(node);
|
|
1239
|
+
vertex.addType(array);
|
|
1240
|
+
array.getTypeVarVertex().addEdge(vertex);
|
|
1241
|
+
return vertex;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
public static Vertex createArrayVertex(Graph graph, Node node, Vertex[] elements, int offset, int length) {
|
|
1245
|
+
Vertex[] newElements = new Vertex[length];
|
|
1246
|
+
System.arraycopy(elements, offset, newElements, 0, length);
|
|
1247
|
+
return createArrayVertex(graph, node, newElements);
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
public static Hash createHash(Graph graph, Vertex[] elements) {
|
|
1251
|
+
Hash hash = new Hash(graph.getRuntime(), elements);
|
|
1252
|
+
TypeVarVertex k = new TypeVarVertex(hash);
|
|
1253
|
+
TypeVarVertex v = new TypeVarVertex(hash);
|
|
1254
|
+
hash.setKeyTypeVarVertex(k);
|
|
1255
|
+
hash.setValueTypeVarVertex(v);
|
|
1256
|
+
return hash;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
public static Vertex createHashVertex(Graph graph, Node node, Vertex[] elements) {
|
|
1261
|
+
Hash hash = createHash(graph, elements);
|
|
1262
|
+
Vertex vertex = new PassThroughVertex(node);
|
|
1263
|
+
vertex.addType(hash);
|
|
1264
|
+
hash.getKeyTypeVarVertex().addEdge(vertex);
|
|
1265
|
+
hash.getValueTypeVarVertex().addEdge(vertex);
|
|
1266
|
+
return vertex;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
public static Vertex[] toVertices(Graph graph, ListNode node) {
|
|
1270
|
+
Vertex[] vertices = new Vertex[node.size()];
|
|
1271
|
+
for (int i = 0; i < vertices.length; i++) {
|
|
1272
|
+
vertices[i] = graph.createVertex(node.get(i));
|
|
1273
|
+
}
|
|
1274
|
+
return vertices;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
public static void setMethodsVisibility(Graph graph, TypeSet receivers, Vertex[] args, Visibility visibility) {
|
|
1278
|
+
if (args == null || args.length == 0) {
|
|
1279
|
+
// FIXME module check
|
|
1280
|
+
graph.getRuntime().getContext().getCurrentFrame().setVisibility(visibility);
|
|
1281
|
+
} else {
|
|
1282
|
+
for (IRubyObject receiver : receivers) {
|
|
1283
|
+
if (receiver.isKindOf(graph.getRuntime().getModule())) {
|
|
1284
|
+
RubyModule module = (RubyModule) receiver;
|
|
1285
|
+
for (Vertex arg : args) {
|
|
1286
|
+
String name = Vertex.getStringOrSymbol(arg);
|
|
1287
|
+
if (name != null) {
|
|
1288
|
+
DynamicMethod method = module.getMethod(name);
|
|
1289
|
+
if (method != null) {
|
|
1290
|
+
method.setVisibility(visibility);
|
|
1291
|
+
if (visibility == Visibility.MODULE_FUNCTION) {
|
|
1292
|
+
module.getSingletonClass().addMethod(name, method);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
public static void defineAttrs(Graph graph, TypeSet receivers, Vertex[] args, boolean reader, boolean writer) {
|
|
1303
|
+
if (args != null && args.length > 0) {
|
|
1304
|
+
for (IRubyObject receiver : receivers) {
|
|
1305
|
+
if (receiver.isKindOf(graph.getRuntime().getModule())) {
|
|
1306
|
+
for (Vertex arg : args) {
|
|
1307
|
+
String name = Vertex.getStringOrSymbol(arg);
|
|
1308
|
+
if (name != null) {
|
|
1309
|
+
if (reader) {
|
|
1310
|
+
defineAttrReader(graph, name);
|
|
1311
|
+
}
|
|
1312
|
+
if (writer) {
|
|
1313
|
+
defineAttrWriter(graph, name);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
public static void defineAttrReader(Graph graph, String name) {
|
|
1323
|
+
SourcePosition pos = new SourcePosition("(generated)", 0, 0);
|
|
1324
|
+
graph.createVertex(new DefnNode(pos,
|
|
1325
|
+
new MethodNameNode(pos, name),
|
|
1326
|
+
new ArgsNode(pos, null, null, null, null, null, null, null),
|
|
1327
|
+
new LocalStaticScope(null),
|
|
1328
|
+
new InstVarNode(pos, "@" + name)));
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
public static void defineAttrWriter(Graph graph, String name) {
|
|
1332
|
+
SourcePosition pos = new SourcePosition("(generated)", 0, 0);
|
|
1333
|
+
graph.createVertex(new DefnNode(pos,
|
|
1334
|
+
new MethodNameNode(pos, name + "="),
|
|
1335
|
+
new ArgsNode(pos, new ListNode(null, new ArgumentNode(null, name)), null, null, null, null, null, null),
|
|
1336
|
+
new LocalStaticScope(null),
|
|
1337
|
+
new InstAsgnNode(pos, "@" + name, new LocalVarNode(null, 0, name))));
|
|
1338
|
+
}
|
|
1339
|
+
}
|