orbacle 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +119 -0
- data/LICENSE +22 -0
- data/Makefile +57 -0
- data/README.md +53 -0
- data/circle.yml +82 -0
- data/exe/orbaclerun +6 -0
- data/index.html +106 -0
- data/lib/orbacle.rb +96 -0
- data/lib/orbacle/ast_utils.rb +35 -0
- data/lib/orbacle/bottom_type.rb +23 -0
- data/lib/orbacle/builder.rb +1414 -0
- data/lib/orbacle/builder/context.rb +71 -0
- data/lib/orbacle/builder/operator_assignment_processors.rb +80 -0
- data/lib/orbacle/class_type.rb +32 -0
- data/lib/orbacle/command_line_interface.rb +107 -0
- data/lib/orbacle/const_name.rb +33 -0
- data/lib/orbacle/const_ref.rb +53 -0
- data/lib/orbacle/constants_tree.rb +73 -0
- data/lib/orbacle/define_builtins.rb +139 -0
- data/lib/orbacle/engine.rb +74 -0
- data/lib/orbacle/find_definition_under_position.rb +76 -0
- data/lib/orbacle/generic_type.rb +35 -0
- data/lib/orbacle/global_tree.rb +280 -0
- data/lib/orbacle/graph.rb +126 -0
- data/lib/orbacle/indexer.rb +151 -0
- data/lib/orbacle/integer_id_generator.rb +13 -0
- data/lib/orbacle/lambda_type.rb +37 -0
- data/lib/orbacle/lang_server.rb +64 -0
- data/lib/orbacle/main_type.rb +23 -0
- data/lib/orbacle/nesting.rb +78 -0
- data/lib/orbacle/node.rb +23 -0
- data/lib/orbacle/nominal_type.rb +32 -0
- data/lib/orbacle/ruby_parser.rb +19 -0
- data/lib/orbacle/scope.rb +63 -0
- data/lib/orbacle/selfie.rb +41 -0
- data/lib/orbacle/type_pretty_printer.rb +24 -0
- data/lib/orbacle/typing_service.rb +816 -0
- data/lib/orbacle/union_type.rb +40 -0
- data/lib/orbacle/uuid_id_generator.rb +11 -0
- data/lib/orbacle/worklist.rb +51 -0
- data/orbacle.gemspec +33 -0
- metadata +258 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orbacle
|
4
|
+
class DefineBuiltins
|
5
|
+
def initialize(graph, tree, id_generator)
|
6
|
+
@graph = graph
|
7
|
+
@tree = tree
|
8
|
+
@id_generator = id_generator
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
add_object_klass
|
13
|
+
add_dir_klass
|
14
|
+
add_file_klass
|
15
|
+
add_integer_klass
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
attr_reader :id_generator
|
20
|
+
|
21
|
+
def add_object_klass
|
22
|
+
klass = @tree.add_klass(nil)
|
23
|
+
@tree.add_constant(
|
24
|
+
GlobalTree::Constant.new("Object", Scope.empty, nil, klass.id))
|
25
|
+
|
26
|
+
# BasicObject
|
27
|
+
template_just_bool(klass, "==")
|
28
|
+
template_just_bool(klass, "!")
|
29
|
+
template_just_bool(klass, "!=")
|
30
|
+
template_just_bool(klass, "equal?")
|
31
|
+
template_just_int(klass, "object_id")
|
32
|
+
template_just_int(klass, "__id__")
|
33
|
+
|
34
|
+
# Object
|
35
|
+
template_just_bool(klass, "!~")
|
36
|
+
template_maybe_int(klass, "<=>")
|
37
|
+
template_just_bool(klass, "===")
|
38
|
+
template_just_nil(klass, "display")
|
39
|
+
template_just_bool(klass, "eql?")
|
40
|
+
template_just_bool(klass, "frozen?")
|
41
|
+
template_just_bool(klass, "instance_of?")
|
42
|
+
template_just_bool(klass, "instance_variable_defined?")
|
43
|
+
template_just_bool(klass, "is_a?")
|
44
|
+
template_just_str(klass, "inspect")
|
45
|
+
template_just_bool(klass, "kind_of?")
|
46
|
+
template_just_bool(klass, "nil?")
|
47
|
+
template_just_bool(klass, "respond_to?")
|
48
|
+
template_just_bool(klass, "respond_to_missing?")
|
49
|
+
template_just_bool(klass, "tainted?")
|
50
|
+
template_just_bool(klass, "untrusted?")
|
51
|
+
template_just_str(klass, "to_s")
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_integer_klass
|
55
|
+
klass = @tree.add_klass(nil)
|
56
|
+
@tree.add_constant(
|
57
|
+
GlobalTree::Constant.new("Integer", Scope.empty, nil, klass.id))
|
58
|
+
|
59
|
+
template_just_int(klass, "succ")
|
60
|
+
template_just_int(klass, "+")
|
61
|
+
template_just_int(klass, "-")
|
62
|
+
template_just_int(klass, "*")
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_dir_klass
|
66
|
+
klass = @tree.add_klass(nil)
|
67
|
+
@tree.add_constant(
|
68
|
+
GlobalTree::Constant.new("Dir", Scope.empty, nil, klass.id))
|
69
|
+
eigenclass = @tree.get_eigenclass_of_definition(klass.id)
|
70
|
+
|
71
|
+
template_just_array_of_str(eigenclass, "glob")
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_file_klass
|
75
|
+
klass = @tree.add_klass(nil)
|
76
|
+
@tree.add_constant(
|
77
|
+
GlobalTree::Constant.new("File", Scope.empty, nil, klass.id))
|
78
|
+
eigenclass = @tree.get_eigenclass_of_definition(klass.id)
|
79
|
+
|
80
|
+
template_just_str(eigenclass, "read")
|
81
|
+
end
|
82
|
+
|
83
|
+
def template_just_int(klass, name)
|
84
|
+
metod = template_args(klass, name)
|
85
|
+
int_node = Node.new(:int, {})
|
86
|
+
@graph.add_edge(int_node, @graph.get_metod_nodes(metod.id).result)
|
87
|
+
end
|
88
|
+
|
89
|
+
def template_maybe_int(klass, name)
|
90
|
+
metod = template_args(klass, name)
|
91
|
+
int_node = Node.new(:int, {})
|
92
|
+
nil_node = Node.new(:nil, {})
|
93
|
+
@graph.add_edge(int_node, @graph.get_metod_nodes(metod.id).result)
|
94
|
+
@graph.add_edge(nil_node, @graph.get_metod_nodes(metod.id).result)
|
95
|
+
end
|
96
|
+
|
97
|
+
def template_just_str(klass, name)
|
98
|
+
metod = template_args(klass, name)
|
99
|
+
str_node = Node.new(:str, {})
|
100
|
+
@graph.add_edge(str_node, @graph.get_metod_nodes(metod.id).result)
|
101
|
+
end
|
102
|
+
|
103
|
+
def template_just_bool(klass, name)
|
104
|
+
metod = template_args(klass, name)
|
105
|
+
str_node = Node.new(:bool, {})
|
106
|
+
@graph.add_edge(str_node, @graph.get_metod_nodes(metod.id).result)
|
107
|
+
end
|
108
|
+
|
109
|
+
def template_just_nil(klass, name)
|
110
|
+
metod = template_args(klass, name)
|
111
|
+
str_node = Node.new(:nil, {})
|
112
|
+
@graph.add_edge(str_node, @graph.get_metod_nodes(metod.id).result)
|
113
|
+
end
|
114
|
+
|
115
|
+
def template_just_array_of_str(klass, name)
|
116
|
+
metod = template_args(klass, name)
|
117
|
+
str_node = Node.new(:str, {})
|
118
|
+
array_node = Node.new(:array, {})
|
119
|
+
@graph.add_edge(str_node, array_node)
|
120
|
+
@graph.add_edge(array_node, @graph.get_metod_nodes(metod.id).result)
|
121
|
+
end
|
122
|
+
|
123
|
+
def template_args(klass, name)
|
124
|
+
metod = @tree.add_method(
|
125
|
+
generate_id,
|
126
|
+
klass.id,
|
127
|
+
name,
|
128
|
+
nil,
|
129
|
+
:public,
|
130
|
+
GlobalTree::ArgumentsTree.new([], []))
|
131
|
+
@graph.store_metod_nodes(metod.id, {})
|
132
|
+
metod
|
133
|
+
end
|
134
|
+
|
135
|
+
def generate_id
|
136
|
+
id_generator.call
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orbacle
|
4
|
+
class Engine
|
5
|
+
def initialize(logger)
|
6
|
+
@logger = logger
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :stats_recorder
|
10
|
+
|
11
|
+
def index(project_root)
|
12
|
+
@stats_recorder = Indexer::StatsRecorder.new
|
13
|
+
service = Indexer.new(logger, stats_recorder)
|
14
|
+
@state, @graph, @worklist = service.(project_root: project_root)
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_type_information(filepath, searched_position)
|
18
|
+
relevant_nodes = @graph
|
19
|
+
.vertices
|
20
|
+
.select {|n| n.location && n.location.uri.eql?(filepath) && n.location.position_range.include_position?(searched_position) }
|
21
|
+
.sort_by {|n| n.location.span }
|
22
|
+
|
23
|
+
pretty_print_type(@state.type_of(relevant_nodes.at(0)))
|
24
|
+
end
|
25
|
+
|
26
|
+
def locations_for_definition_under_position(file_path, file_content, position)
|
27
|
+
result = find_definition_under_position(file_content, position.line, position.character)
|
28
|
+
case result
|
29
|
+
when FindDefinitionUnderPosition::ConstantResult
|
30
|
+
constants = @state.solve_reference2(result.const_ref)
|
31
|
+
constants.map(&:location)
|
32
|
+
when FindDefinitionUnderPosition::MessageResult
|
33
|
+
caller_type = get_type_of_caller_from_message_send(file_path, result.position_range)
|
34
|
+
methods_definitions = get_methods_definitions_for_type(caller_type, result.name)
|
35
|
+
methods_definitions = @state.get_methods(result.name) if methods_definitions.empty?
|
36
|
+
methods_definitions.map(&:location).compact
|
37
|
+
else
|
38
|
+
[]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def get_type_of_caller_from_message_send(file_path, position_range)
|
44
|
+
message_send = @worklist
|
45
|
+
.message_sends
|
46
|
+
.find {|ms| ms.location && ms.location.uri.eql?(file_path) && ms.location.position_range.include_position?(position_range.start) }
|
47
|
+
@state.type_of(message_send.send_obj)
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_methods_definitions_for_type(type, method_name)
|
51
|
+
case type
|
52
|
+
when NominalType
|
53
|
+
@state.get_instance_methods_from_class_name(type.name, method_name)
|
54
|
+
when ClassType
|
55
|
+
@state.get_class_methods_from_class_name(type.name, method_name)
|
56
|
+
when UnionType
|
57
|
+
type.types_set.flat_map {|t| get_methods_definitions_for_type(t, method_name) }
|
58
|
+
else
|
59
|
+
[]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
attr_reader :logger
|
65
|
+
|
66
|
+
def find_definition_under_position(content, line, character)
|
67
|
+
FindDefinitionUnderPosition.new(RubyParser.new).process_file(content, Position.new(line, character))
|
68
|
+
end
|
69
|
+
|
70
|
+
def pretty_print_type(type)
|
71
|
+
TypePrettyPrinter.new.(type)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orbacle
|
4
|
+
class FindDefinitionUnderPosition < Parser::AST::Processor
|
5
|
+
include AstUtils
|
6
|
+
|
7
|
+
ConstantResult = Struct.new(:const_ref)
|
8
|
+
MessageResult = Struct.new(:name, :position_range)
|
9
|
+
|
10
|
+
def initialize(parser)
|
11
|
+
@parser = parser
|
12
|
+
end
|
13
|
+
|
14
|
+
def process_file(file_content, searched_position)
|
15
|
+
ast = parser.parse(file_content)
|
16
|
+
|
17
|
+
@current_nesting = Nesting.empty
|
18
|
+
@searched_position = searched_position
|
19
|
+
|
20
|
+
process(ast)
|
21
|
+
|
22
|
+
@result
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :parser
|
26
|
+
|
27
|
+
def process(ast)
|
28
|
+
new_ast = super
|
29
|
+
raise unless ast.equal?(new_ast)
|
30
|
+
new_ast
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_const(ast)
|
34
|
+
if build_position_range_from_ast(ast).include_position?(@searched_position)
|
35
|
+
@result = ConstantResult.new(ConstRef.from_ast(ast, @current_nesting))
|
36
|
+
end
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_class(ast)
|
41
|
+
klass_name_ast, _ = ast.children
|
42
|
+
klass_name_ref = ConstRef.from_ast(klass_name_ast, @current_nesting)
|
43
|
+
with_new_nesting(@current_nesting.increase_nesting_const(klass_name_ref)) do
|
44
|
+
super
|
45
|
+
end
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def on_module(ast)
|
50
|
+
module_name_ast, _ = ast.children
|
51
|
+
module_name_ref = ConstRef.from_ast(module_name_ast, @current_nesting)
|
52
|
+
with_new_nesting(@current_nesting.increase_nesting_const(module_name_ref)) do
|
53
|
+
super
|
54
|
+
end
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def on_send(ast)
|
59
|
+
if ast.loc.selector && build_position_range_from_parser_range(ast.loc.selector).include_position?(@searched_position)
|
60
|
+
message_name = ast.children.fetch(1).to_s
|
61
|
+
selector_position_range = build_position_range_from_parser_range(ast.loc.selector)
|
62
|
+
@result = MessageResult.new(message_name, selector_position_range)
|
63
|
+
else
|
64
|
+
super
|
65
|
+
end
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def with_new_nesting(new_nesting)
|
70
|
+
previous_nesting = @current_nesting
|
71
|
+
@current_nesting = new_nesting
|
72
|
+
yield
|
73
|
+
@current_nesting = previous_nesting
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orbacle
|
4
|
+
class GenericType
|
5
|
+
def initialize(name, parameters)
|
6
|
+
@name = name
|
7
|
+
@parameters = parameters
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :name, :parameters
|
11
|
+
|
12
|
+
def ==(other)
|
13
|
+
self.class == other.class &&
|
14
|
+
self.name == other.name &&
|
15
|
+
self.parameters == other.parameters
|
16
|
+
end
|
17
|
+
|
18
|
+
def hash
|
19
|
+
[
|
20
|
+
self.class,
|
21
|
+
self.name,
|
22
|
+
self.parameters,
|
23
|
+
].hash ^ BIG_VALUE
|
24
|
+
end
|
25
|
+
alias eql? ==
|
26
|
+
|
27
|
+
def each_possible_type
|
28
|
+
yield self
|
29
|
+
end
|
30
|
+
|
31
|
+
def bottom?
|
32
|
+
false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orbacle
|
4
|
+
class GlobalTree
|
5
|
+
class ArgumentsTree < Struct.new(:args, :kwargs, :blockarg)
|
6
|
+
Regular = Struct.new(:name)
|
7
|
+
Optional = Struct.new(:name)
|
8
|
+
Splat = Struct.new(:name)
|
9
|
+
Nested = Struct.new(:args)
|
10
|
+
end
|
11
|
+
|
12
|
+
class Method
|
13
|
+
def initialize(id, place_of_definition_id, name, location, visibility, args)
|
14
|
+
raise ArgumentError.new(visibility) if ![:public, :private, :protected].include?(visibility)
|
15
|
+
|
16
|
+
@id = id
|
17
|
+
@place_of_definition_id = place_of_definition_id
|
18
|
+
@name = name
|
19
|
+
@location = location
|
20
|
+
@visibility = visibility
|
21
|
+
@args = args
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :id, :name, :location, :args, :place_of_definition_id
|
25
|
+
attr_accessor :visibility
|
26
|
+
end
|
27
|
+
|
28
|
+
class Lambda
|
29
|
+
def initialize(id, args)
|
30
|
+
@id = id
|
31
|
+
@args = args
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :id, :args
|
35
|
+
end
|
36
|
+
|
37
|
+
class Klass
|
38
|
+
def initialize(id, parent_ref, eigenclass_id = nil)
|
39
|
+
@id = id
|
40
|
+
@parent_ref = parent_ref
|
41
|
+
@eigenclass_id = eigenclass_id
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :id, :parent_ref, :eigenclass_id
|
45
|
+
attr_writer :eigenclass_id
|
46
|
+
|
47
|
+
def ==(other)
|
48
|
+
@id == other.id &&
|
49
|
+
@parent_ref == other.parent_ref &&
|
50
|
+
@eigenclass_id == other.eigenclass_id
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Mod
|
55
|
+
def initialize(id, eigenclass_id = nil)
|
56
|
+
@id = id
|
57
|
+
@eigenclass_id = eigenclass_id
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :id, :eigenclass_id
|
61
|
+
attr_writer :eigenclass_id
|
62
|
+
|
63
|
+
def ==(other)
|
64
|
+
@id == other.id &&
|
65
|
+
@eigenclass_id == other.eigenclass_id
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Constant
|
70
|
+
def initialize(name, scope, location, definition_id = nil)
|
71
|
+
@name = name
|
72
|
+
@scope = scope
|
73
|
+
@location = location
|
74
|
+
@definition_id = definition_id
|
75
|
+
end
|
76
|
+
|
77
|
+
attr_reader :name, :scope, :location, :definition_id
|
78
|
+
|
79
|
+
def ==(other)
|
80
|
+
@name == other.name &&
|
81
|
+
@scope == other.scope &&
|
82
|
+
@location == other.location &&
|
83
|
+
@definition_id == other.definition_id
|
84
|
+
end
|
85
|
+
|
86
|
+
def full_name
|
87
|
+
[*scope.elems, @name].join("::")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def initialize(id_generator)
|
92
|
+
@id_generator = id_generator
|
93
|
+
@constants = ConstantsTree.new
|
94
|
+
@classes_by_id = {}
|
95
|
+
@modules_by_id = {}
|
96
|
+
@methods_by_class_id = Hash.new {|h,k| h[k] = Hash.new {|h2, k2| h2[k2] = [] } }
|
97
|
+
@methods_by_id = {}
|
98
|
+
@lambdas_by_id = {}
|
99
|
+
@type_mapping = Hash.new(BottomType.new)
|
100
|
+
end
|
101
|
+
|
102
|
+
### Methods
|
103
|
+
|
104
|
+
def add_method(id, place_of_definition_id, name, location, visibility, args)
|
105
|
+
metod = Method.new(id, place_of_definition_id, name, location, visibility, args)
|
106
|
+
@methods_by_class_id[metod.place_of_definition_id][metod.name] << metod
|
107
|
+
@methods_by_id[metod.id] = metod
|
108
|
+
return metod
|
109
|
+
end
|
110
|
+
|
111
|
+
def find_instance_method_from_class_name(class_name, method_name)
|
112
|
+
get_instance_methods_from_class_name(class_name, method_name).first
|
113
|
+
end
|
114
|
+
|
115
|
+
def find_instance_method_from_class_id(class_id, method_name)
|
116
|
+
get_instance_methods_from_class_id(class_id, method_name).first
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_instance_methods_from_class_id(class_id, method_name)
|
120
|
+
@methods_by_class_id[class_id][method_name]
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_instance_methods_from_class_name(class_name, method_name)
|
124
|
+
klass = find_class_by_name(class_name)
|
125
|
+
return [] if klass.nil?
|
126
|
+
get_instance_methods_from_class_id(klass.id, method_name)
|
127
|
+
end
|
128
|
+
|
129
|
+
def get_class_methods_from_class_name(class_name, method_name)
|
130
|
+
klass = find_class_by_name(class_name)
|
131
|
+
return [] if klass.nil?
|
132
|
+
eigenclass = get_eigenclass_of_definition(klass.id)
|
133
|
+
get_instance_methods_from_class_id(eigenclass.id, method_name)
|
134
|
+
end
|
135
|
+
|
136
|
+
def find_class_method_from_class_name(class_name, method_name)
|
137
|
+
get_class_methods_from_class_name(class_name, method_name).first
|
138
|
+
end
|
139
|
+
|
140
|
+
def get_methods(method_name)
|
141
|
+
@methods_by_id.values.select do |m|
|
142
|
+
m.name.eql?(method_name)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def find_super_method(method_id)
|
147
|
+
analyzed_method = @methods_by_id.fetch(method_id)
|
148
|
+
klass_of_this_method = get_class(analyzed_method.place_of_definition_id)
|
149
|
+
return nil if klass_of_this_method.nil? || klass_of_this_method.parent_ref.nil?
|
150
|
+
parent_klass = solve_reference(klass_of_this_method.parent_ref)
|
151
|
+
return nil if parent_klass.nil?
|
152
|
+
find_instance_method_from_class_name(parent_klass.full_name, analyzed_method.name)
|
153
|
+
end
|
154
|
+
|
155
|
+
def change_method_visibility(klass_id, name, new_visibility)
|
156
|
+
@methods_by_class_id[klass_id][name].each do |m|
|
157
|
+
m.visibility = new_visibility
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
### Definitions
|
162
|
+
|
163
|
+
def add_klass(parent_ref)
|
164
|
+
klass = Klass.new(id_generator.call, parent_ref)
|
165
|
+
@classes_by_id[klass.id] = klass
|
166
|
+
klass
|
167
|
+
end
|
168
|
+
|
169
|
+
def add_mod
|
170
|
+
mod = Mod.new(id_generator.call)
|
171
|
+
@modules_by_id[mod.id] = mod
|
172
|
+
mod
|
173
|
+
end
|
174
|
+
|
175
|
+
def get_class(class_id)
|
176
|
+
@classes_by_id[class_id]
|
177
|
+
end
|
178
|
+
|
179
|
+
def get_module(module_id)
|
180
|
+
@modules_by_id[module_id]
|
181
|
+
end
|
182
|
+
|
183
|
+
def get_definition(definition_id)
|
184
|
+
get_class(definition_id) || get_module(definition_id)
|
185
|
+
end
|
186
|
+
|
187
|
+
def get_eigenclass_of_definition(definition_id)
|
188
|
+
definition = get_definition(definition_id)
|
189
|
+
if definition.eigenclass_id
|
190
|
+
get_class(definition.eigenclass_id)
|
191
|
+
else
|
192
|
+
eigenclass = add_klass(nil)
|
193
|
+
definition.eigenclass_id = eigenclass.id
|
194
|
+
eigenclass
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
### Constants
|
199
|
+
|
200
|
+
def add_constant(constant)
|
201
|
+
@constants.add_element(constant.scope, constant.name, constant)
|
202
|
+
return constant
|
203
|
+
end
|
204
|
+
|
205
|
+
def solve_reference(const_ref)
|
206
|
+
@constants.find_by_const_ref(const_ref)
|
207
|
+
end
|
208
|
+
|
209
|
+
def solve_reference2(const_ref)
|
210
|
+
@constants.select_by_const_ref(const_ref)
|
211
|
+
end
|
212
|
+
|
213
|
+
### Lambdas
|
214
|
+
|
215
|
+
def add_lambda(args)
|
216
|
+
lamba = Lambda.new(id_generator.call, args)
|
217
|
+
@lambdas_by_id[lamba.id] = lamba
|
218
|
+
lamba
|
219
|
+
end
|
220
|
+
|
221
|
+
def get_lambda(lambda_id)
|
222
|
+
@lambdas_by_id[lambda_id]
|
223
|
+
end
|
224
|
+
|
225
|
+
### Other
|
226
|
+
|
227
|
+
def get_parent_of(class_name)
|
228
|
+
return nil if class_name.eql?("Object")
|
229
|
+
|
230
|
+
const = find_constant_by_name(class_name)
|
231
|
+
return "Object" if const.nil?
|
232
|
+
|
233
|
+
klass = get_class(const.definition_id)
|
234
|
+
return "Object" if klass.nil?
|
235
|
+
|
236
|
+
return "Object" if klass.parent_ref.nil?
|
237
|
+
parent_const = solve_reference(klass.parent_ref)
|
238
|
+
if parent_const
|
239
|
+
parent_const.full_name
|
240
|
+
else
|
241
|
+
klass.parent_ref.relative_name
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def find_class_by_name(full_name)
|
246
|
+
const = find_constant_by_name(full_name)
|
247
|
+
return nil if const.nil?
|
248
|
+
get_class(const.definition_id)
|
249
|
+
end
|
250
|
+
|
251
|
+
def find_module_by_name(full_name)
|
252
|
+
const = find_constant_by_name(full_name)
|
253
|
+
return nil if const.nil?
|
254
|
+
get_module(const.definition_id)
|
255
|
+
end
|
256
|
+
|
257
|
+
def find_constant_by_name(full_name)
|
258
|
+
@constants.find_by_const_name(ConstName.from_string(full_name))
|
259
|
+
end
|
260
|
+
|
261
|
+
def find_constant_for_definition(definition_id)
|
262
|
+
@constants.find do |constant|
|
263
|
+
constant.definition_id == definition_id
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
### Types
|
268
|
+
|
269
|
+
def type_of(node)
|
270
|
+
@type_mapping[node]
|
271
|
+
end
|
272
|
+
|
273
|
+
def set_type_of(node, new_type)
|
274
|
+
@type_mapping[node] = new_type
|
275
|
+
end
|
276
|
+
|
277
|
+
private
|
278
|
+
attr_reader :id_generator
|
279
|
+
end
|
280
|
+
end
|