rsense-core 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +1 -0
  5. data/README.md +35 -0
  6. data/Rakefile +84 -0
  7. data/TypeAnnotation.tokens +41 -0
  8. data/build.xml +84 -0
  9. data/build_lib/antlr-3.2.jar +0 -0
  10. data/lib/jars/ant-1.7.0.jar +0 -0
  11. data/lib/jars/ant-launcher-1.7.0.jar +0 -0
  12. data/lib/jars/antlr-runtime-3.2.jar +0 -0
  13. data/lib/jars/bsf-2.3.0.jar +0 -0
  14. data/lib/rsense-core.rb +28 -0
  15. data/lib/rsense.jar +0 -0
  16. data/lib/rsense/core.rb +5 -0
  17. data/lib/rsense/core/version.rb +5 -0
  18. data/lib/rsense/parser.rb +6 -0
  19. data/lib/rsense/ruby.rb +19 -0
  20. data/lib/rsense/typing.rb +13 -0
  21. data/lib/rsense/typing/annotation.rb +20 -0
  22. data/lib/rsense/typing/runtime.rb +23 -0
  23. data/lib/rsense/typing/vertex.rb +15 -0
  24. data/lib/rsense/util.rb +9 -0
  25. data/rsense-core.gemspec +30 -0
  26. data/src/org/cx4a/rsense/CodeAssist.java +744 -0
  27. data/src/org/cx4a/rsense/CodeAssistError.java +31 -0
  28. data/src/org/cx4a/rsense/CodeAssistResult.java +42 -0
  29. data/src/org/cx4a/rsense/CodeCompletionResult.java +65 -0
  30. data/src/org/cx4a/rsense/FindDefinitionResult.java +24 -0
  31. data/src/org/cx4a/rsense/LoadResult.java +19 -0
  32. data/src/org/cx4a/rsense/Main.java +916 -0
  33. data/src/org/cx4a/rsense/Options.java +353 -0
  34. data/src/org/cx4a/rsense/Project.java +103 -0
  35. data/src/org/cx4a/rsense/TypeInferenceResult.java +25 -0
  36. data/src/org/cx4a/rsense/WhereResult.java +19 -0
  37. data/src/org/cx4a/rsense/parser/TypeAnnotation.g +221 -0
  38. data/src/org/cx4a/rsense/parser/TypeAnnotationLexer.java +1759 -0
  39. data/src/org/cx4a/rsense/parser/TypeAnnotationParser.java +2025 -0
  40. data/src/org/cx4a/rsense/ruby/Block.java +10 -0
  41. data/src/org/cx4a/rsense/ruby/Context.java +75 -0
  42. data/src/org/cx4a/rsense/ruby/DynamicMethod.java +10 -0
  43. data/src/org/cx4a/rsense/ruby/DynamicScope.java +51 -0
  44. data/src/org/cx4a/rsense/ruby/Frame.java +95 -0
  45. data/src/org/cx4a/rsense/ruby/IRubyObject.java +17 -0
  46. data/src/org/cx4a/rsense/ruby/LocalScope.java +43 -0
  47. data/src/org/cx4a/rsense/ruby/MetaClass.java +50 -0
  48. data/src/org/cx4a/rsense/ruby/Ruby.java +242 -0
  49. data/src/org/cx4a/rsense/ruby/RubyClass.java +146 -0
  50. data/src/org/cx4a/rsense/ruby/RubyModule.java +255 -0
  51. data/src/org/cx4a/rsense/ruby/RubyObject.java +94 -0
  52. data/src/org/cx4a/rsense/ruby/Scope.java +7 -0
  53. data/src/org/cx4a/rsense/ruby/SpecialObject.java +15 -0
  54. data/src/org/cx4a/rsense/ruby/Visibility.java +17 -0
  55. data/src/org/cx4a/rsense/typing/Graph.java +1690 -0
  56. data/src/org/cx4a/rsense/typing/Propagation.java +73 -0
  57. data/src/org/cx4a/rsense/typing/Template.java +84 -0
  58. data/src/org/cx4a/rsense/typing/TemplateAttribute.java +158 -0
  59. data/src/org/cx4a/rsense/typing/TypeSet.java +48 -0
  60. data/src/org/cx4a/rsense/typing/annotation/ClassType.java +57 -0
  61. data/src/org/cx4a/rsense/typing/annotation/MethodType.java +79 -0
  62. data/src/org/cx4a/rsense/typing/annotation/TypeAnnotation.java +4 -0
  63. data/src/org/cx4a/rsense/typing/annotation/TypeAny.java +7 -0
  64. data/src/org/cx4a/rsense/typing/annotation/TypeApplication.java +37 -0
  65. data/src/org/cx4a/rsense/typing/annotation/TypeConstraint.java +29 -0
  66. data/src/org/cx4a/rsense/typing/annotation/TypeExpression.java +11 -0
  67. data/src/org/cx4a/rsense/typing/annotation/TypeIdentity.java +59 -0
  68. data/src/org/cx4a/rsense/typing/annotation/TypeOptional.java +22 -0
  69. data/src/org/cx4a/rsense/typing/annotation/TypePragma.java +22 -0
  70. data/src/org/cx4a/rsense/typing/annotation/TypeSplat.java +22 -0
  71. data/src/org/cx4a/rsense/typing/annotation/TypeTuple.java +35 -0
  72. data/src/org/cx4a/rsense/typing/annotation/TypeUnion.java +23 -0
  73. data/src/org/cx4a/rsense/typing/annotation/TypeVariable.java +44 -0
  74. data/src/org/cx4a/rsense/typing/runtime/AliasMethod.java +94 -0
  75. data/src/org/cx4a/rsense/typing/runtime/AnnotationHelper.java +69 -0
  76. data/src/org/cx4a/rsense/typing/runtime/AnnotationResolver.java +523 -0
  77. data/src/org/cx4a/rsense/typing/runtime/Array.java +84 -0
  78. data/src/org/cx4a/rsense/typing/runtime/ClassTag.java +27 -0
  79. data/src/org/cx4a/rsense/typing/runtime/DefaultMethod.java +115 -0
  80. data/src/org/cx4a/rsense/typing/runtime/Hash.java +131 -0
  81. data/src/org/cx4a/rsense/typing/runtime/LoopTag.java +21 -0
  82. data/src/org/cx4a/rsense/typing/runtime/Method.java +32 -0
  83. data/src/org/cx4a/rsense/typing/runtime/MonomorphicObject.java +77 -0
  84. data/src/org/cx4a/rsense/typing/runtime/ObjectAllocator.java +40 -0
  85. data/src/org/cx4a/rsense/typing/runtime/PolymorphicObject.java +90 -0
  86. data/src/org/cx4a/rsense/typing/runtime/Proc.java +100 -0
  87. data/src/org/cx4a/rsense/typing/runtime/RuntimeHelper.java +1339 -0
  88. data/src/org/cx4a/rsense/typing/runtime/SpecialMethod.java +119 -0
  89. data/src/org/cx4a/rsense/typing/runtime/TypeVarMap.java +112 -0
  90. data/src/org/cx4a/rsense/typing/runtime/VertexHolder.java +48 -0
  91. data/src/org/cx4a/rsense/typing/vertex/CallVertex.java +122 -0
  92. data/src/org/cx4a/rsense/typing/vertex/MultipleAsgnVertex.java +23 -0
  93. data/src/org/cx4a/rsense/typing/vertex/PassThroughVertex.java +20 -0
  94. data/src/org/cx4a/rsense/typing/vertex/SValueVertex.java +24 -0
  95. data/src/org/cx4a/rsense/typing/vertex/SplatVertex.java +24 -0
  96. data/src/org/cx4a/rsense/typing/vertex/ToAryVertex.java +24 -0
  97. data/src/org/cx4a/rsense/typing/vertex/TypeVarVertex.java +22 -0
  98. data/src/org/cx4a/rsense/typing/vertex/Vertex.java +221 -0
  99. data/src/org/cx4a/rsense/typing/vertex/YieldVertex.java +70 -0
  100. data/src/org/cx4a/rsense/util/HereDocReader.java +48 -0
  101. data/src/org/cx4a/rsense/util/Logger.java +111 -0
  102. data/src/org/cx4a/rsense/util/NodeUtil.java +198 -0
  103. data/src/org/cx4a/rsense/util/SourceLocation.java +70 -0
  104. data/src/org/cx4a/rsense/util/StringUtil.java +63 -0
  105. data/src/resources/org/cx4a/rsense/rsense.properties +1 -0
  106. data/stubs/1.8/_builtin.rb +3006 -0
  107. data/stubs/1.8/bigdecimal.rb +131 -0
  108. data/stubs/1.8/cgi.rb +257 -0
  109. data/stubs/1.8/date.rb +147 -0
  110. data/stubs/1.8/optparse.rb +113 -0
  111. data/stubs/1.8/rational.rb +47 -0
  112. data/stubs/1.8/set.rb +94 -0
  113. data/stubs/1.8/socket.rb +461 -0
  114. data/stubs/1.8/stringio.rb +129 -0
  115. data/test/data/a file.rb +1 -0
  116. data/test/data/benchmark.rb +12 -0
  117. data/test/data/crlf.rb +5 -0
  118. data/test/data/test.rb +19 -0
  119. data/test/script/all.rsense +2 -0
  120. data/test/script/array_dynamic.rsense +25 -0
  121. data/test/script/block_nested.rsense +7 -0
  122. data/test/script/builtin.rsense +785 -0
  123. data/test/script/class_method_partial_update.rsense +52 -0
  124. data/test/script/class_partial_update.rsense +17 -0
  125. data/test/script/find-definition.rsense +72 -0
  126. data/test/script/method_arg_onearg.rsense +6 -0
  127. data/test/script/method_arg_optional.rsense +7 -0
  128. data/test/script/method_partial_update.rsense +14 -0
  129. data/test/script/method_yield_arrayarg.rsense +8 -0
  130. data/test/script/method_yield_arrayarg_expand.rsense +8 -0
  131. data/test/script/method_yield_arrayarg_splat.rsense +17 -0
  132. data/test/script/misc.rsense +2 -0
  133. data/test/script/proc_higher_order.rsense +22 -0
  134. data/test/script/regression.rsense +95 -0
  135. data/test/script/stdlib.rsense +66 -0
  136. data/test/script/where.rsense +41 -0
  137. 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
+ }