codemodels 0.2.2-java → 0.2.3-java
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.
- data/LICENSE +191 -20
- data/README.md +2 -2
- data/codemodels.gemspec +2 -3
- data/lib/codemodels/info_extraction.rb +0 -4
- data/lib/codemodels/language.rb +11 -29
- data/lib/codemodels/metamodel.rb +11 -3
- data/lib/codemodels/model_building.rb +47 -51
- data/lib/codemodels/navigation.rb +121 -0
- data/lib/codemodels/parsing.rb +8 -155
- data/lib/codemodels/rgen_ext.rb +31 -84
- data/lib/codemodels/serialization.rb +46 -41
- data/lib/codemodels/source_info.rb +192 -0
- data/lib/codemodels/version.rb +1 -1
- data/lib/codemodels.rb +1 -3
- data/test/test_foreign_navigation.rb +71 -0
- data/test/test_info_extraction.rb +1 -1
- data/test/test_language.rb +34 -4
- data/test/test_metamodel.rb +102 -0
- data/test/test_model_building.rb +12 -0
- data/test/test_rgen_ext.rb +4 -4
- data/test/test_serialization.rb +19 -19
- metadata +11 -9
- data/lib/codemodels/foreign_ast.rb +0 -11
- data/lib/codemodels/query_serialized.rb +0 -81
- data/test/test_foreign_ast.rb +0 -28
- data/test/test_query_serialized.rb +0 -40
data/lib/codemodels/parsing.rb
CHANGED
@@ -2,6 +2,14 @@ require 'codemodels/monkey_patching'
|
|
2
2
|
|
3
3
|
module CodeModels
|
4
4
|
|
5
|
+
class Parser
|
6
|
+
|
7
|
+
def parse_file(path)
|
8
|
+
parse_code(IO.read(path))
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
5
13
|
class ParsingError < Exception
|
6
14
|
attr_reader :node
|
7
15
|
attr_reader :line
|
@@ -26,159 +34,4 @@ class UnknownNodeType < ParsingError
|
|
26
34
|
|
27
35
|
end
|
28
36
|
|
29
|
-
module ParserWrapper
|
30
|
-
|
31
|
-
@@verbose = false
|
32
|
-
|
33
|
-
JavaCollection = ::Java::JavaClass.for_name("java.util.Collection")
|
34
|
-
|
35
|
-
def adapter(model_class,ref)
|
36
|
-
if adapter_specific_class(model_class,ref)
|
37
|
-
adapter_specific_class(model_class,ref)
|
38
|
-
else
|
39
|
-
if model_class.superclass!=Object
|
40
|
-
adapter(model_class.superclass,ref)
|
41
|
-
else
|
42
|
-
nil
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def reference_to_method(model_class,ref)
|
48
|
-
s = ref.name
|
49
|
-
#s = 'value' if s=='body'
|
50
|
-
adapted = adapter(model_class,ref)
|
51
|
-
s = adapted if adapted
|
52
|
-
s.to_sym
|
53
|
-
end
|
54
|
-
|
55
|
-
def attribute_to_method(model_class,att)
|
56
|
-
s = att.name
|
57
|
-
adapted = adapter(model_class,att)
|
58
|
-
s = adapted if adapted
|
59
|
-
s.to_sym
|
60
|
-
end
|
61
|
-
|
62
|
-
def assign_ref_to_model(model,ref,value)
|
63
|
-
return unless value==nil # we do not need to assign a nil...
|
64
|
-
if ref.many
|
65
|
-
adder_method = :"add#{ref.name.capitalize}"
|
66
|
-
value.each {|el| model.send(adder_method,node_to_model(el))}
|
67
|
-
else
|
68
|
-
setter_method = :"#{ref.name}="
|
69
|
-
raise "Trying to assign an array to a single property. Class #{model.class}, property #{ref.name}" if value.is_a?(::Array)
|
70
|
-
model.send(setter_method,node_to_model(value))
|
71
|
-
end
|
72
|
-
rescue Object => e
|
73
|
-
puts "Problem while assigning ref #{ref.name} (many? #{ref.many}) to #{model.class}. Value: #{value.class}"
|
74
|
-
puts "\t<<#{e}>>"
|
75
|
-
raise e
|
76
|
-
end
|
77
|
-
|
78
|
-
def assign_att_to_model(model,att,value)
|
79
|
-
if att.many
|
80
|
-
adder_method = :"add#{att.name.capitalize}"
|
81
|
-
value.each {|el| model.send(adder_method,el)}
|
82
|
-
else
|
83
|
-
setter_method = :"#{att.name}="
|
84
|
-
raise "Trying to assign an array to a single property. Class #{model.class}, property #{att.name}" if value.is_a?(::Array)
|
85
|
-
model.send(setter_method,value)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def populate_attr(node,att,model)
|
90
|
-
value = get_feature_value(node,att)
|
91
|
-
model.send(:"#{att.name}=",value) if value!=nil
|
92
|
-
rescue Object => e
|
93
|
-
puts "Problem while populating attribute #{att.name} of #{model} from #{node}. Value: #{value}"
|
94
|
-
raise e
|
95
|
-
end
|
96
|
-
|
97
|
-
def populate_ref(node,ref,model)
|
98
|
-
log("populate ref #{ref.name}, node: #{node.class}, model: #{model.class}")
|
99
|
-
value = get_feature_value(node,ref)
|
100
|
-
log("\tvalue=#{value.class}")
|
101
|
-
if value!=nil
|
102
|
-
if value==node
|
103
|
-
puts "avoiding loop... #{ref.name}, class #{node.class}"
|
104
|
-
return
|
105
|
-
end
|
106
|
-
if JavaCollection.assignable_from?(value.java_class)
|
107
|
-
log("\tvalue is a collection")
|
108
|
-
capitalized_name = ref.name.proper_capitalize
|
109
|
-
value.each do |el|
|
110
|
-
unless el.respond_to?(:parent)
|
111
|
-
class << el
|
112
|
-
attr_accessor :parent
|
113
|
-
end
|
114
|
-
end
|
115
|
-
el.parent = node
|
116
|
-
model.send(:"add#{capitalized_name}",node_to_model(el))
|
117
|
-
end
|
118
|
-
else
|
119
|
-
log("\tvalue is not a collection")
|
120
|
-
unless value.respond_to?(:parent)
|
121
|
-
value.class.__persistent__ = true
|
122
|
-
class << value
|
123
|
-
attr_accessor :parent
|
124
|
-
end
|
125
|
-
end
|
126
|
-
value.parent = node
|
127
|
-
model.send(:"#{ref.name}=",node_to_model(value))
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def log(msg)
|
133
|
-
puts msg if @@verbose
|
134
|
-
end
|
135
|
-
|
136
|
-
def node_to_model(node)
|
137
|
-
log("node_to_model #{node.class}")
|
138
|
-
metaclass = get_corresponding_metaclass(node)
|
139
|
-
instance = metaclass.new
|
140
|
-
metaclass.ecore.eAllAttributes.each do |attr|
|
141
|
-
populate_attr(node,attr,instance)
|
142
|
-
end
|
143
|
-
metaclass.ecore.eAllReferences.each do |ref|
|
144
|
-
populate_ref(node,ref,instance)
|
145
|
-
end
|
146
|
-
instance
|
147
|
-
end
|
148
|
-
|
149
|
-
def transform_enum_values(value)
|
150
|
-
if value.respond_to?(:java_class) && value.java_class.enum?
|
151
|
-
value.name
|
152
|
-
else
|
153
|
-
value
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def get_feature_value_through_getter(node,feat_name)
|
158
|
-
capitalized_name = feat_name.proper_capitalize
|
159
|
-
methods = [:"get#{capitalized_name}",:"is#{capitalized_name}"]
|
160
|
-
|
161
|
-
methods.each do |m|
|
162
|
-
if node.respond_to?(m)
|
163
|
-
begin
|
164
|
-
return transform_enum_values(node.send(m))
|
165
|
-
rescue Object => e
|
166
|
-
raise "Problem invoking #{m} on #{node.class}: #{e}"
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
raise "how should I get this... #{feat_name} on #{node.class}. It does not respond to #{methods}"
|
171
|
-
end
|
172
|
-
|
173
|
-
def get_feature_value(node,feat)
|
174
|
-
adapter = adapter(node.class,feat)
|
175
|
-
if adapter
|
176
|
-
adapter[:adapter].call(node)
|
177
|
-
else
|
178
|
-
get_feature_value_through_getter(node,feat.name)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
end
|
183
|
-
|
184
37
|
end
|
data/lib/codemodels/rgen_ext.rb
CHANGED
@@ -12,17 +12,12 @@ class RGen::MetamodelBuilder::MMBase
|
|
12
12
|
values.each do |k,v|
|
13
13
|
attribute = self.ecore.eAllAttributes.find {|x| x.name==k.to_s}
|
14
14
|
reference = self.ecore.eAllReferences.find {|x| x.name==k.to_s}
|
15
|
-
raise
|
15
|
+
raise "UnexistingFeature #{k}" unless (attribute or reference)
|
16
16
|
setter = (k.to_s+'=').to_sym
|
17
17
|
instance.send setter, v
|
18
18
|
end
|
19
19
|
else
|
20
|
-
|
21
|
-
self.ecore.eAllAttributes.each {|a| has_dynamic|=a.name=='dynamic'}
|
22
|
-
d = 0
|
23
|
-
d = 1 if has_dynamic
|
24
|
-
|
25
|
-
raise EMF::SingleAttributeRequired.new(self.ecore.name,self.ecore.eAllAttributes) if self.ecore.eAllAttributes.count!=1+d
|
20
|
+
raise "SingleAttributeRequired" if self.ecore.eAllAttributes.count!=1
|
26
21
|
attribute = self.ecore.eAllAttributes[0]
|
27
22
|
set_attr(instance,attribute,values)
|
28
23
|
end
|
@@ -45,12 +40,9 @@ class RGen::MetamodelBuilder::MMBase
|
|
45
40
|
return false unless self.class==other.class
|
46
41
|
self.class.ecore.eAllAttributes.each do |attrib|
|
47
42
|
raise "Attrib <nil> for class #{self.class.ecore.name}" unless attrib
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
#puts "returning false on #{attrib.name}" unless self_value.eql?(other_value)
|
52
|
-
return false unless self_value == other_value
|
53
|
-
end
|
43
|
+
self_value = self.get(attrib)
|
44
|
+
other_value = other.get(attrib)
|
45
|
+
return false unless self_value == other_value
|
54
46
|
end
|
55
47
|
true
|
56
48
|
end
|
@@ -95,92 +87,47 @@ class RGen::MetamodelBuilder::MMBase
|
|
95
87
|
send getter
|
96
88
|
end
|
97
89
|
|
98
|
-
def
|
99
|
-
|
90
|
+
def features_by_name(name)
|
91
|
+
features = []
|
100
92
|
ecore = self.class.ecore
|
101
|
-
ecore.
|
102
|
-
|
103
|
-
if ref.many
|
104
|
-
d = arr.count
|
105
|
-
res.each do |el|
|
106
|
-
arr << el unless res==nil
|
107
|
-
end
|
108
|
-
elsif res!=nil
|
109
|
-
d = arr.count
|
110
|
-
arr << res
|
111
|
-
end
|
112
|
-
end
|
113
|
-
arr
|
114
|
-
end
|
115
|
-
|
116
|
-
def all_children_deep
|
117
|
-
arr = []
|
118
|
-
all_children.each do |c|
|
119
|
-
arr << c
|
120
|
-
c.all_children_deep.each do |cc|
|
121
|
-
arr << cc
|
122
|
-
end
|
93
|
+
ecore.eAllAttributes.select {|a| a.name==name}.each do |a|
|
94
|
+
features << a
|
123
95
|
end
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
def traverse(&op)
|
128
|
-
op.call(self)
|
129
|
-
all_children_deep.each do |c|
|
130
|
-
op.call(c)
|
96
|
+
ecore.eAllReferences.select {|r| r.name==name}.each do |r|
|
97
|
+
features << r
|
131
98
|
end
|
99
|
+
features
|
132
100
|
end
|
133
101
|
|
134
|
-
|
135
|
-
values = Hash.new {|h,k| h[k]=0}
|
136
|
-
self.class.ecore.eAllAttributes.each do |a|
|
137
|
-
v = self.send(:"#{a.name}")
|
138
|
-
if v!=nil
|
139
|
-
if a.many
|
140
|
-
v.each {|el| values[el]+=1}
|
141
|
-
else
|
142
|
-
values[v]+=1
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
values
|
147
|
-
end
|
148
|
-
|
149
|
-
def collect_values_with_count_subtree
|
150
|
-
values = collect_values_with_count
|
151
|
-
all_children_deep.each do |c|
|
152
|
-
c.collect_values_with_count.each do |k,v|
|
153
|
-
values[k]+=v
|
154
|
-
end
|
155
|
-
end
|
156
|
-
values
|
157
|
-
end
|
102
|
+
end
|
158
103
|
|
159
|
-
|
160
|
-
|
104
|
+
module FixingCollidingFeatureAddOn
|
105
|
+
def has_attr(role, target_class=nil, raw_props={}, &block)
|
106
|
+
raise "Role already used #{role}" if self.ecore.eAllAttributes.find {|a| a.name==role.to_s}
|
107
|
+
raise "Role already used #{role}" if self.ecore.eAllReferences.find {|r| r.name==role.to_s}
|
108
|
+
super(role,target_class,raw_props,block)
|
161
109
|
end
|
162
|
-
|
163
|
-
|
164
|
-
|
110
|
+
def has_many_attr(role, target_class=nil, raw_props={}, &block)
|
111
|
+
raise "Role already used #{role}" if self.ecore.eAllAttributes.find {|a| a.name==role.to_s}
|
112
|
+
raise "Role already used #{role}" if self.ecore.eAllReferences.find {|r| r.name==role.to_s}
|
113
|
+
super(role,target_class,raw_props,block)
|
165
114
|
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
selected[0]
|
115
|
+
def contains_many_uni(role, target_class=nil, raw_props={}, &block)
|
116
|
+
raise "Role already used #{role}" if self.ecore.eAllAttributes.find {|a| a.name==role.to_s}
|
117
|
+
raise "Role already used #{role}" if self.ecore.eAllReferences.find {|r| r.name==role.to_s}
|
118
|
+
super(role,target_class,raw_props,block)
|
171
119
|
end
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
selected[0]
|
120
|
+
def contains_one_uni(role, target_class=nil, raw_props={}, &block)
|
121
|
+
raise "Role already used #{role}" if self.ecore.eAllAttributes.find {|a| a.name==role.to_s}
|
122
|
+
raise "Role already used #{role}" if self.ecore.eAllReferences.find {|r| r.name==role.to_s}
|
123
|
+
super(role,target_class,raw_props,block)
|
177
124
|
end
|
178
|
-
|
179
125
|
end
|
180
126
|
|
181
127
|
class << self
|
182
128
|
include ClassAddOn
|
183
129
|
end
|
184
130
|
|
131
|
+
include FixingCollidingFeatureAddOn
|
185
132
|
include SingletonAddOn
|
186
133
|
end
|
@@ -10,38 +10,16 @@ module Serialization
|
|
10
10
|
|
11
11
|
module SerializationFunctionalities
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
def initialize
|
18
|
-
@next_id = 1
|
19
|
-
@id_map = {}
|
20
|
-
end
|
21
|
-
|
22
|
-
def id(rgen_object)
|
23
|
-
unless @id_map[rgen_object]
|
24
|
-
@id_map[rgen_object] = @next_id
|
25
|
-
@next_id += 1
|
26
|
-
end
|
27
|
-
@id_map[rgen_object]
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
13
|
+
def to_json(params={})
|
14
|
+
serialization_memory = params.fetch(:memory,SerializationMemory.new)
|
15
|
+
adapters = params.fetch(:adapters,{})
|
16
|
+
with_source_info = params.fetch(:source_info,true)
|
31
17
|
|
32
|
-
def to_json(serialization_memory=SerializationMemory.new,adapters={},with_source_info=true)
|
33
18
|
e_object = self
|
34
|
-
map = { 'type' =>
|
19
|
+
map = { 'type' => type, 'id' => serialization_memory.id(e_object) }
|
35
20
|
if with_source_info
|
36
|
-
if self.respond_to?(:source) && self.source
|
37
|
-
|
38
|
-
if self.source.begin_pos
|
39
|
-
source_map['begin_pos'] = {'line'=> self.source.begin_pos.line, 'column'=>self.source.begin_pos.column}
|
40
|
-
end
|
41
|
-
if self.source.end_pos
|
42
|
-
source_map['end_pos'] = {'line'=> self.source.end_pos.line, 'column'=>self.source.end_pos.column}
|
43
|
-
end
|
44
|
-
map['source'] = source_map
|
21
|
+
if self.respond_to?(:source) && self.source
|
22
|
+
map['source'] = source_info_to_json(self.source)
|
45
23
|
end
|
46
24
|
end
|
47
25
|
e_class = e_object.class.ecore
|
@@ -51,21 +29,32 @@ module SerializationFunctionalities
|
|
51
29
|
e_class.eAllReferences.each do |r|
|
52
30
|
id = jsonize_ref_value(map,r,adapters,serialization_memory)
|
53
31
|
end
|
54
|
-
if adapters.has_key?
|
55
|
-
adapters[
|
32
|
+
if adapters.has_key? type
|
33
|
+
adapters[type].adapt(self,map)
|
56
34
|
end
|
57
35
|
map
|
58
36
|
end
|
59
37
|
|
60
38
|
private
|
61
39
|
|
62
|
-
def
|
40
|
+
def source_info_to_json(source_info)
|
41
|
+
source_map = {}
|
42
|
+
if self.source.begin_pos
|
43
|
+
source_map['begin_pos'] = {'line'=> self.source.begin_pos.line, 'column'=>self.source.begin_pos.column}
|
44
|
+
end
|
45
|
+
if self.source.end_pos
|
46
|
+
source_map['end_pos'] = {'line'=> self.source.end_pos.line, 'column'=>self.source.end_pos.column}
|
47
|
+
end
|
48
|
+
source_map
|
49
|
+
end
|
50
|
+
|
51
|
+
def type
|
63
52
|
self.class.to_s
|
64
53
|
end
|
65
54
|
|
66
55
|
def jsonize_attr_value(map,e_attr)
|
67
56
|
value = self.send(e_attr.name.to_sym)
|
68
|
-
|
57
|
+
unless e_attr.many
|
69
58
|
map["attr_#{e_attr.name}"] = value
|
70
59
|
else
|
71
60
|
l = []
|
@@ -82,7 +71,7 @@ module SerializationFunctionalities
|
|
82
71
|
propname = "relcont_#{e_ref.name}" if e_ref.containment
|
83
72
|
propname = "relnoncont_#{e_ref.name}" if not e_ref.containment
|
84
73
|
|
85
|
-
|
74
|
+
unless e_ref.many
|
86
75
|
map[propname] = jsonize_ref_single_el(value,e_ref.containment,adapters,serialization_memory)
|
87
76
|
else
|
88
77
|
l = []
|
@@ -95,23 +84,38 @@ module SerializationFunctionalities
|
|
95
84
|
|
96
85
|
def jsonize_ref_single_el(single_value,containment,adapters,serialization_memory)
|
97
86
|
if containment
|
98
|
-
single_value.to_json(serialization_memory,adapters)
|
87
|
+
single_value.to_json(memory:serialization_memory,adapters:adapters)
|
99
88
|
else
|
100
89
|
serialization_memory.id(single_value)
|
101
90
|
end
|
102
91
|
end
|
103
92
|
|
104
|
-
|
93
|
+
# It could be a simple hash with a block passed to the
|
94
|
+
# constructor...
|
95
|
+
class SerializationMemory
|
96
|
+
|
97
|
+
def initialize
|
98
|
+
@next_id = 1
|
99
|
+
@id_map = {}
|
100
|
+
end
|
101
|
+
|
102
|
+
def id(rgen_object)
|
103
|
+
unless @id_map[rgen_object]
|
104
|
+
@id_map[rgen_object] = @next_id
|
105
|
+
@next_id += 1
|
106
|
+
end
|
107
|
+
@id_map[rgen_object]
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
105
111
|
|
106
|
-
class ::RGen::MetamodelBuilder::MMBase
|
107
|
-
include SerializationFunctionalities
|
108
112
|
end
|
109
113
|
|
110
114
|
def self.load_file(path,max_nesting=500)
|
111
115
|
JSON.parse(File.read(path),{max_nesting: max_nesting})
|
112
116
|
end
|
113
117
|
|
114
|
-
def self.save_model(model,model_path,
|
118
|
+
def self.save_model(model,model_path,max_nesting=500)
|
115
119
|
dir = File.dirname(model_path)
|
116
120
|
FileUtils.mkdir_p(dir)
|
117
121
|
|
@@ -125,10 +129,10 @@ def self.rgenobject_to_model(root,adapters={})
|
|
125
129
|
external_elements = []
|
126
130
|
|
127
131
|
sm = SerializationFunctionalities::SerializationMemory.new
|
128
|
-
model['root'] = root.to_json(sm,adapters)
|
132
|
+
model['root'] = root.to_json(memory:sm,adapters:adapters)
|
129
133
|
model['external_elements'] = []
|
130
134
|
external_elements.each do |ee|
|
131
|
-
model['external_elements'] << ee.to_json(sm,adapters)
|
135
|
+
model['external_elements'] << ee.to_json(memory:sm,adapters:adapters)
|
132
136
|
end
|
133
137
|
model
|
134
138
|
end
|
@@ -139,4 +143,5 @@ def self.save_as_model(root,model_path)
|
|
139
143
|
end
|
140
144
|
|
141
145
|
end # module
|
146
|
+
|
142
147
|
end # module
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require 'rgen/metamodel_builder'
|
2
|
+
require 'codemodels/language'
|
3
|
+
|
4
|
+
module CodeModels
|
5
|
+
|
6
|
+
class AbstractArtifact
|
7
|
+
|
8
|
+
def point_to_absolute(point)
|
9
|
+
offset = absolute_start
|
10
|
+
p = SourcePoint.new
|
11
|
+
p.line = point.line + offset.line - 1
|
12
|
+
p.column = point.column
|
13
|
+
p.column += offset.column-1 if point.line==1
|
14
|
+
p
|
15
|
+
end
|
16
|
+
|
17
|
+
def position_to_absolute(position)
|
18
|
+
pos = SourcePosition.new
|
19
|
+
pos.begin_point = point_to_absolute(position.begin_point)
|
20
|
+
pos.end_point = point_to_absolute(position.end_point)
|
21
|
+
pos
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class EmbeddedArtifact < AbstractArtifact
|
27
|
+
attr_accessor :host_artifact
|
28
|
+
attr_accessor :position_in_host
|
29
|
+
|
30
|
+
def absolute_start
|
31
|
+
p = host_artifact.absolute_start
|
32
|
+
p.line += position_in_host.begin_point.line-1
|
33
|
+
if position_in_host.begin_point.line==1
|
34
|
+
# if I am on the first line of my "host", its column
|
35
|
+
# matters because there are not newlines to reset the column
|
36
|
+
# counter
|
37
|
+
p.column += position_in_host.begin_point.column-1
|
38
|
+
else
|
39
|
+
p.column = position_in_host.begin_point.column
|
40
|
+
end
|
41
|
+
p
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
class FileArtifact < AbstractArtifact
|
47
|
+
attr_accessor :filename
|
48
|
+
|
49
|
+
def absolute_start
|
50
|
+
sp = SourcePoint.new
|
51
|
+
sp.line = 1
|
52
|
+
sp.column = 1
|
53
|
+
sp
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class SourcePoint
|
58
|
+
attr_accessor :line, :column
|
59
|
+
|
60
|
+
def initialize(line=nil,column=nil)
|
61
|
+
@line = line
|
62
|
+
@column = column
|
63
|
+
end
|
64
|
+
|
65
|
+
def eql?(other)
|
66
|
+
other.line==line && other.column==column
|
67
|
+
end
|
68
|
+
|
69
|
+
def ==(other)
|
70
|
+
self.eql?(other)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class SourcePosition
|
75
|
+
attr_accessor :begin_point, :end_point
|
76
|
+
|
77
|
+
def initialize(begin_point=nil,end_point=nil)
|
78
|
+
@begin_point = begin_point
|
79
|
+
@end_point = end_point
|
80
|
+
end
|
81
|
+
|
82
|
+
def begin_line=(line)
|
83
|
+
@begin_point=SourcePoint.new unless @begin_point
|
84
|
+
@begin_point.line = line
|
85
|
+
end
|
86
|
+
|
87
|
+
def begin_column=(column)
|
88
|
+
@begin_point=SourcePoint.new unless @begin_point
|
89
|
+
@begin_point.column = column
|
90
|
+
end
|
91
|
+
|
92
|
+
def eql?(other)
|
93
|
+
other.begin_point==begin_point && other.end_point==end_point
|
94
|
+
end
|
95
|
+
|
96
|
+
def ==(other)
|
97
|
+
self.eql?(other)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class SourceInfo
|
102
|
+
attr_accessor :artifact
|
103
|
+
attr_accessor :position
|
104
|
+
|
105
|
+
def to_code
|
106
|
+
raise "Unimplemented"
|
107
|
+
end
|
108
|
+
|
109
|
+
def begin_point=(data)
|
110
|
+
point = data_to_point(data)
|
111
|
+
@position = SourcePosition.new unless @position
|
112
|
+
@position.begin_point = point
|
113
|
+
end
|
114
|
+
|
115
|
+
def end_point=(data)
|
116
|
+
point = data_to_point(data)
|
117
|
+
@position = SourcePosition.new unless @position
|
118
|
+
@position.end_point = point
|
119
|
+
end
|
120
|
+
|
121
|
+
def begin_line
|
122
|
+
position.begin_point.line
|
123
|
+
end
|
124
|
+
|
125
|
+
def end_line
|
126
|
+
position.end_point.line
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def data_to_point(data)
|
132
|
+
if data.is_a? Hash
|
133
|
+
point = SourcePoint.new
|
134
|
+
point.line = data[:line]
|
135
|
+
point.column = data[:column]
|
136
|
+
elsif data.is_a? SourcePoint
|
137
|
+
point = data
|
138
|
+
else
|
139
|
+
raise "Expected Hash or SourcePoint"
|
140
|
+
end
|
141
|
+
point
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
# This extension give all the information about the source
|
147
|
+
# from which the node was derived
|
148
|
+
module SourceInfoExtensions
|
149
|
+
attr_accessor :language
|
150
|
+
attr_accessor :source
|
151
|
+
|
152
|
+
def set_start_point(data)
|
153
|
+
@source = SourceInfo.new unless @source
|
154
|
+
@source.set_start_point(data)
|
155
|
+
end
|
156
|
+
|
157
|
+
def set_end_point(data)
|
158
|
+
@source = SourceInfo.new unless @source
|
159
|
+
@source.set_end_point(data)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Inside an host language snippet of other languages can be hosted
|
164
|
+
# For example Java code could contain in a string literal a sql statement
|
165
|
+
# or an Html file can contain CSS or Javascript code.
|
166
|
+
# In those cases an AST is inserted inside the AST of the host language.
|
167
|
+
module ForeignAstExtensions
|
168
|
+
|
169
|
+
attr_accessor :foreign_container
|
170
|
+
|
171
|
+
def addForeign_asts(foreign_ast)
|
172
|
+
foreign_asts << foreign_ast
|
173
|
+
foreign_ast.foreign_container = self
|
174
|
+
end
|
175
|
+
|
176
|
+
def foreign_asts
|
177
|
+
@foreign_asts=[] unless @foreign_asts
|
178
|
+
@foreign_asts
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
module HostPositionExtensions
|
183
|
+
|
184
|
+
def absolute_position
|
185
|
+
artifact = source.artifact
|
186
|
+
artifact.absolute_position(source.position)
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
end
|
data/lib/codemodels/version.rb
CHANGED
data/lib/codemodels.rb
CHANGED