1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Save and load `Model` from/to Neo4j base.
17 # Nit models are composed by MEntities.
18 # This module creates NeoNode for each MEntity found in a `Model` and save them into Neo4j database.
22 # NeoNodes can also be translated back to MEntities to rebuild a Nit `Model`.
24 # Structure of the nit `Model` in base:
28 # * labels: `model_name`, `MEntity`, `MProject`
29 # * `(:MProject)-[:ROOT]->(:MGroup)`
33 # * labels: `model_name`, `MEntity`, `MGroup`
34 # * `(:MGroup)-[:PROJECT]->(:MProject)`
35 # * `(:MGroup)-[:PARENT]->(:MGroup)`
39 # * labels: `model_name`, `MEntity`, `MModule`
40 # * `(:MModule)-[:IMPORTS]->(:MModule)`
41 # * `(:MModule)-[:INTRODUCES]->(:MClass)`
42 # * `(:MModule)-[:DEFINES]->(:MClassDef)`
46 # * labels: `model_name`, `MEntity`, `MClass`
47 # * `(:MClass)-[:CLASSTYPE]->(:MClassType)`
51 # * labels: `model_name`, `MEntity`, `MClassDef`
52 # * `(:MClassDef)-[:BOUNDTYPE]->(:MClassType)`
53 # * `(:MClassDef)-[:MCLASS]->(:MClass)`
54 # * `(:MClassDef)-[:INTRODUCES]->(:MProperty)`
55 # * `(:MClassDef)-[:DECLARES]->(:MPropDef)`
59 # * labels: `model_name`, `MEntity`, `MProperty`
60 # * `(:MProperty)-[:INTRO_CLASSDEF]->(:MClassDef)`
62 # MProperties can also have labels `MMethod`, `MAttribute`, `MVirtualTypeProp`.
66 # * labels: `model_name`, `MEntity`, `MPropDef`
67 # * `(:MPropDef)-[:DEFINES]->(:MProperty)`
69 # MPropdefs can also have labels `MMethodDef`, `MAttributeDef`, `MVirtualTypeDef`.
71 # `MMethodDef` are linked to a `MSignature`:
73 # * `(:MMethodDef)-[:SIGNATURE]->(:MSignature)`
75 # `MVirtualTypeDef` are linked to a `MType` (its `bound`):
77 # * `(:MVirtualTypeDef)-[:BOUND]->(:MType)`
81 # * labels: `model_name`, `MEntity`, `MType`
83 # MTypes can also have labels `MClassType`, `MGenericType`, `MNullableType`, `MVirtualType`
86 # `MClassType` and `MGenericType` both point to a `MClass` and have type `arguments`:
88 # * `(:MClassType)-[:CLASS]->(:MClass)`
89 # * `(:MClassType)-[:ARGUMENT]->(:MType)`
91 # `MVirtualType` points to its introducing `MProperty`:
93 # * `(:MVirtualType)-[:PROPERTY]->(:MVirtualTypeDef)`
95 # `MParameterType` points to its introducing `MClass`:
97 # * `(:MParameterType)-[:CLASS]->(:MClass)`
99 # `MNullableType` points to its non-nullable `MType`:
101 # * `(:MNullableType)-[:TYPE]->(:MType)`
103 # `MSignature` can have `parameters` and a `return_mtype`:
105 # * `(:MSignature)-[:PARAMETER]->(:MParameter)`
106 # * `(:MSignature)-[:RETURNTYPE]->(:MType)`
110 # * labels: `model_name`, `MEntity`, `MParameter`
111 # * `(:MParameter)-[:TYPE]->(:MType)`
118 # Helper class that can save and load a `Model` into a Neo4j database.
123 # Because we use only one Neo4j instance to store all the models,
124 # we need to mark their appartenance to a particular model and avoid loading all models.
126 # The name is used as a Neo label on each created nodes and used to load nodes from base.
127 var model_name
: String
129 # The toolcontext used to init the `NeoModel` tool.
130 var toolcontext
: ToolContext
132 # The Neo4j `client` used to communicate with the Neo4j instance.
133 var client
: Neo4jClient
135 # Fill `model` using base pointed by `client`.
136 fun load
(model
: Model): Model do
137 toolcontext
.info
("Locate all mentities...", 1)
138 var nodes
= client
.nodes_with_label
(model_name
)
140 toolcontext
.info
("Preload nodes...", 1)
141 pull_all_nodes
(nodes
)
142 toolcontext
.info
("Preload edges...", 1)
143 pull_all_edges
(nodes
)
145 toolcontext
.info
("Build model...", 1)
146 nodes
= client
.nodes_with_labels
([model_name
, "MProject"])
147 for node
in nodes
do to_mproject
(model
, node
)
148 nodes
= client
.nodes_with_labels
([model_name
, "MGroup"])
149 for node
in nodes
do to_mgroup
(model
, node
)
150 nodes
= client
.nodes_with_labels
([model_name
, "MModule"])
151 for node
in nodes
do to_mmodule
(model
, node
)
152 nodes
= client
.nodes_with_labels
([model_name
, "MClass"])
153 for node
in nodes
do to_mclass
(model
, node
)
154 nodes
= client
.nodes_with_labels
([model_name
, "MClassDef"])
155 for node
in nodes
do to_mclassdef
(model
, node
)
156 nodes
= client
.nodes_with_labels
([model_name
, "MProperty"])
157 for node
in nodes
do to_mproperty
(model
, node
)
158 nodes
= client
.nodes_with_labels
([model_name
, "MPropDef"])
159 for node
in nodes
do to_mpropdef
(model
, node
)
163 # Save `model` in the base pointed by `client`.
164 fun save
(model
: Model) do
165 var nodes
= collect_model_nodes
(model
)
166 toolcontext
.info
("Save {nodes.length} nodes...", 1)
168 var edges
= collect_model_edges
(model
)
169 toolcontext
.info
("Save {edges.length} edges...", 1)
173 # Save `neo_entities` in base using batch mode.
174 private fun push_all
(neo_entities
: Collection[NeoEntity]) do
175 var batch
= new NeoBatch(client
)
176 var len
= neo_entities
.length
179 for nentity
in neo_entities
do
180 batch
.save_entity
(nentity
)
181 if i
== batch_max_size
then
183 sum
+= batch_max_size
184 toolcontext
.info
(" {sum * 100 / len}% done", 1)
185 batch
= new NeoBatch(client
)
194 # Load content for all `nodes` from base.
196 # Content corresponds to properties and labels that are loaded in batch mode.
197 private fun pull_all_nodes
(nodes
: Collection[NeoNode]) do
198 var batch
= new NeoBatch(client
)
199 var len
= nodes
.length
203 batch
.load_node
(node
)
204 if i
== batch_max_size
then
206 sum
+= batch_max_size
207 toolcontext
.info
(" {sum * 100 / len}% done", 1)
208 batch
= new NeoBatch(client
)
217 # Load all edges from base linked to `nodes`.
219 # Edges are loaded in batch mode.
220 private fun pull_all_edges
(nodes
: Collection[NeoNode]) do
221 var batch
= new NeoBatch(client
)
222 var len
= nodes
.length
226 batch
.load_node_edges
(node
)
227 if i
== batch_max_size
then
229 sum
+= batch_max_size
230 toolcontext
.info
(" {sum * 100 / len}% done", 1)
231 batch
= new NeoBatch(client
)
240 # How many operation can be executed in one batch?
241 private var batch_max_size
= 1000
243 # Execute `batch` and check for errors.
245 # Abort if `batch.execute` returns errors.
246 private fun do_batch
(batch
: NeoBatch) do
247 var errors
= batch
.execute
248 if not errors
.is_empty
then
254 # Collect all nodes from the current `model`.
255 private fun collect_model_nodes
(model
: Model): Collection[NeoNode] do
256 for mproject
in model
.mprojects
do
258 for mgroup
in mproject
.mgroups
do to_node
(mgroup
)
263 # Collect all edges from the current `model`.
265 # Actually collect all out_edges from all nodes.
266 private fun collect_model_edges
(model
: Model): Collection[NeoEdge] do
267 var edges
= new HashSet[NeoEdge]
268 for node
in nodes
.values
do edges
.add_all
(node
.out_edges
)
272 # Mentities associated to nodes.
273 private var mentities
= new HashMap[NeoNode, MEntity]
275 # Nodes associated with MEntities.
276 private var nodes
= new HashMap[MEntity, NeoNode]
278 # Get the `NeoNode` associated with `mentity`.
279 # `mentities` are stored locally to avoid duplication.
280 fun to_node
(mentity
: MEntity): NeoNode do
281 if nodes
.has_key
(mentity
) then return nodes
[mentity
]
282 if mentity
isa MProject then return mproject_node
(mentity
)
283 if mentity
isa MGroup then return mgroup_node
(mentity
)
284 if mentity
isa MModule then return mmodule_node
(mentity
)
285 if mentity
isa MClass then return mclass_node
(mentity
)
286 if mentity
isa MClassDef then return mclassdef_node
(mentity
)
287 if mentity
isa MProperty then return mproperty_node
(mentity
)
288 if mentity
isa MPropDef then return mpropdef_node
(mentity
)
289 if mentity
isa MType then return mtype_node
(mentity
)
290 if mentity
isa MParameter then return mparameter_node
(mentity
)
294 # Make a new `NeoNode` based on `mentity`.
295 private fun make_node
(mentity
: MEntity): NeoNode do
296 var node
= new NeoNode
297 nodes
[mentity
] = node
298 node
.labels
.add
"MEntity"
299 node
.labels
.add model_name
300 node
["name"] = mentity
.name
301 if mentity
.mdoc
!= null then node
["mdoc"] = new JsonArray.from
(mentity
.mdoc
.content
)
305 # Build a `NeoNode` representing `mproject`.
306 private fun mproject_node
(mproject
: MProject): NeoNode do
307 var node
= make_node
(mproject
)
308 node
.labels
.add
"MProject"
309 var root
= mproject
.root
311 node
.out_edges
.add
(new NeoEdge(node
, "ROOT", to_node
(root
)))
316 # Build a new `MProject` from a `node`.
318 # REQUIRE `node.labels.has("MProject")`
319 private fun to_mproject
(model
: Model, node
: NeoNode): MProject do
320 if mentities
.has_key
(node
) then return mentities
[node
].as(MProject)
321 assert node
.labels
.has
("MProject")
322 var mproject
= new MProject(node
["name"].to_s
, model
)
323 mentities
[node
] = mproject
324 set_doc
(node
, mproject
)
325 mproject
.root
= to_mgroup
(model
, node
.out_nodes
("ROOT").first
)
329 # Build a `NeoNode` representing `mgroup`.
330 private fun mgroup_node
(mgroup
: MGroup): NeoNode do
331 var node
= make_node
(mgroup
)
332 node
.labels
.add
"MGroup"
333 node
["full_name"] = mgroup
.full_name
334 var parent
= mgroup
.parent
335 node
.out_edges
.add
(new NeoEdge(node
, "PROJECT", to_node
(mgroup
.mproject
)))
336 if parent
!= null then
337 node
.out_edges
.add
(new NeoEdge(node
, "PARENT", to_node
(parent
)))
339 for mmodule
in mgroup
.mmodules
do
340 node
.out_edges
.add
(new NeoEdge(node
, "DECLARES", to_node
(mmodule
)))
342 for subgroup
in mgroup
.in_nesting
.direct_smallers
do
343 node
.in_edges
.add
(new NeoEdge(node
, "NESTS", to_node
(subgroup
)))
348 # Build a new `MGroup` from a `node`.
350 # REQUIRE `node.labels.has("MGroup")`
351 private fun to_mgroup
(model
: Model, node
: NeoNode): MGroup do
352 if mentities
.has_key
(node
) then return mentities
[node
].as(MGroup)
353 assert node
.labels
.has
("MGroup")
354 var mproject
= to_mproject
(model
, node
.out_nodes
("PROJECT").first
)
355 var parent
: nullable MGroup = null
356 var out
= node
.out_nodes
("PARENT")
357 if not out
.is_empty
then
358 parent
= to_mgroup
(model
, out
.first
)
360 var mgroup
= new MGroup(node
["name"].to_s
, mproject
, parent
)
361 mentities
[node
] = mgroup
362 set_doc
(node
, mgroup
)
366 # Build a `NeoNode` representing `mmodule`.
367 private fun mmodule_node
(mmodule
: MModule): NeoNode do
368 var node
= make_node
(mmodule
)
369 node
.labels
.add
"MModule"
370 node
["full_name"] = mmodule
.full_name
371 node
["location"] = mmodule
.location
.to_s
372 var mgroup
= mmodule
.mgroup
373 for parent
in mmodule
.in_importation
.direct_greaters
do
374 node
.out_edges
.add
(new NeoEdge(node
, "IMPORTS", to_node
(parent
)))
376 for mclass
in mmodule
.intro_mclasses
do
377 node
.out_edges
.add
(new NeoEdge(node
, "INTRODUCES", to_node
(mclass
)))
379 for mclassdef
in mmodule
.mclassdefs
do
380 node
.out_edges
.add
(new NeoEdge(node
, "DEFINES", to_node
(mclassdef
)))
385 # Build a new `MModule` from a `node`.
387 # REQUIRE `node.labels.has("MModule")`
388 private fun to_mmodule
(model
: Model, node
: NeoNode): MModule do
389 if mentities
.has_key
(node
) then return mentities
[node
].as(MModule)
390 assert node
.labels
.has
("MModule")
391 var ins
= node
.in_nodes
("DECLARES")
392 var mgroup
: nullable MGroup = null
393 if not ins
.is_empty
then
394 mgroup
= to_mgroup
(model
, ins
.first
)
396 var name
= node
["name"].to_s
397 var location
= to_location
(node
["location"].to_s
)
398 var mmodule
= new MModule(model
, mgroup
, name
, location
)
399 mentities
[node
] = mmodule
400 set_doc
(node
, mmodule
)
401 var imported_mmodules
= new Array[MModule]
402 for smod
in node
.out_nodes
("IMPORTS") do
403 imported_mmodules
.add to_mmodule
(model
, smod
)
405 mmodule
.set_imported_mmodules
(imported_mmodules
)
409 # Build a `NeoNode` representing `mclass`.
410 private fun mclass_node
(mclass
: MClass): NeoNode do
411 var node
= make_node
(mclass
)
412 node
.labels
.add
"MClass"
413 node
["arity"] = mclass
.arity
414 node
["full_name"] = mclass
.full_name
415 node
["kind"] = mclass
.kind
.to_s
416 node
["visibility"] = mclass
.visibility
.to_s
417 node
.out_edges
.add
(new NeoEdge(node
, "CLASSTYPE", to_node
(mclass
.mclass_type
)))
421 # Build a new `MClass` from a `node`.
423 # REQUIRE `node.labels.has("MClass")`
424 private fun to_mclass
(model
: Model, node
: NeoNode): MClass do
425 if mentities
.has_key
(node
) then return mentities
[node
].as(MClass)
426 assert node
.labels
.has
("MClass")
427 var mmodule
= to_mmodule
(model
, node
.in_nodes
("INTRODUCES").first
)
428 var name
= node
["name"].to_s
429 var arity
= node
["arity"].to_s
.to_i
430 var kind
= to_kind
(node
["kind"].to_s
)
431 var visibility
= to_visibility
(node
["visibility"].to_s
)
432 var mclass
= new MClass(mmodule
, name
, arity
, kind
, visibility
)
433 mentities
[node
] = mclass
434 set_doc
(node
, mclass
)
438 # Build a `NeoNode` representing `mclassdef`.
439 private fun mclassdef_node
(mclassdef
: MClassDef): NeoNode do
440 var node
= make_node
(mclassdef
)
441 node
.labels
.add
"MClassDef"
442 node
["is_intro"] = mclassdef
.is_intro
443 node
["location"] = mclassdef
.location
.to_s
444 if not mclassdef
.parameter_names
.is_empty
then
445 node
["parameter_names"] = new JsonArray.from
(mclassdef
.parameter_names
)
447 node
.out_edges
.add
(new NeoEdge(node
, "BOUNDTYPE", to_node
(mclassdef
.bound_mtype
)))
448 node
.out_edges
.add
(new NeoEdge(node
, "MCLASS", to_node
(mclassdef
.mclass
)))
449 for mproperty
in mclassdef
.intro_mproperties
do
450 node
.out_edges
.add
(new NeoEdge(node
, "INTRODUCES", to_node
(mproperty
)))
452 for mpropdef
in mclassdef
.mpropdefs
do
453 node
.out_edges
.add
(new NeoEdge(node
, "DECLARES", to_node
(mpropdef
)))
455 for sup
in mclassdef
.supertypes
do
456 node
.out_edges
.add
(new NeoEdge(node
, "INHERITS", to_node
(sup
)))
461 # Build a new `MClassDef` from a `node`.
463 # REQUIRE `node.labels.has("MClassDef")`
464 private fun to_mclassdef
(model
: Model, node
: NeoNode): MClassDef do
465 if mentities
.has_key
(node
) then return mentities
[node
].as(MClassDef)
466 assert node
.labels
.has
("MClassDef")
467 var mmodule
= to_mmodule
(model
, node
.in_nodes
("DEFINES").first
)
468 var mtype
= to_mtype
(model
, node
.out_nodes
("BOUNDTYPE").first
).as(MClassType)
469 var location
= to_location
(node
["location"].to_s
)
470 var parameter_names
= new Array[String]
471 if node
.has_key
("parameter_names") then
472 for e
in node
["parameter_names"].as(JsonArray) do
473 parameter_names
.add e
.to_s
476 var mclassdef
= new MClassDef(mmodule
, mtype
, location
, parameter_names
)
477 mentities
[node
] = mclassdef
478 set_doc
(node
, mclassdef
)
479 var supertypes
= new Array[MClassType]
480 for sup
in node
.out_nodes
("INHERITS") do
481 supertypes
.add to_mtype
(model
, sup
).as(MClassType)
483 mclassdef
.set_supertypes
(supertypes
)
484 mclassdef
.add_in_hierarchy
488 # Build a `NeoNode` representing `mproperty`.
489 private fun mproperty_node
(mproperty
: MProperty): NeoNode do
490 var node
= make_node
(mproperty
)
491 node
.labels
.add
"MProperty"
492 node
["full_name"] = mproperty
.full_name
493 node
["visibility"] = mproperty
.visibility
.to_s
494 if mproperty
isa MMethod then
495 node
.labels
.add
"MMethod"
496 node
["is_init"] = mproperty
.is_init
497 else if mproperty
isa MAttribute then
498 node
.labels
.add
"MAttribute"
499 else if mproperty
isa MVirtualTypeProp then
500 node
.labels
.add
"MVirtualTypeProp"
502 node
.out_edges
.add
(new NeoEdge(node
, "INTRO_CLASSDEF", to_node
(mproperty
.intro_mclassdef
)))
506 # Build a new `MProperty` from a `node`.
508 # REQUIRE `node.labels.has("MProperty")`
509 private fun to_mproperty
(model
: Model, node
: NeoNode): MProperty do
510 if mentities
.has_key
(node
) then return mentities
[node
].as(MProperty)
511 assert node
.labels
.has
("MProperty")
512 var intro_mclassdef
= to_mclassdef
(model
, node
.out_nodes
("INTRO_CLASSDEF").first
)
513 var name
= node
["name"].to_s
514 var visibility
= to_visibility
(node
["visibility"].to_s
)
515 var mprop
: nullable MProperty = null
516 if node
.labels
.has
("MMethod") then
517 mprop
= new MMethod(intro_mclassdef
, name
, visibility
)
518 mprop
.is_init
= node
["is_init"].as(Bool)
519 else if node
.labels
.has
("MAttribute") then
520 mprop
= new MAttribute(intro_mclassdef
, name
, visibility
)
521 else if node
.labels
.has
("MVirtualTypeProp") then
522 mprop
= new MVirtualTypeProp(intro_mclassdef
, name
, visibility
)
524 if mprop
== null then
525 print
"not yet implemented to_mproperty for {node.labels.join(",")}"
528 mentities
[node
] = mprop
530 for npropdef
in node
.in_nodes
("DEFINES") do
531 var mpropdef
= to_mpropdef
(model
, npropdef
)
532 if npropdef
["is_intro"].as(Bool) then
533 mprop
.mpropdefs
.unshift mpropdef
535 mprop
.mpropdefs
.add mpropdef
541 # Build a `NeoNode` representing `mpropdef`.
542 private fun mpropdef_node
(mpropdef
: MPropDef): NeoNode do
543 var node
= make_node
(mpropdef
)
544 node
.labels
.add
"MPropDef"
545 node
["is_intro"] = mpropdef
.is_intro
546 node
["location"] = mpropdef
.location
.to_s
547 node
.out_edges
.add
(new NeoEdge(node
, "DEFINES", to_node
(mpropdef
.mproperty
)))
548 if mpropdef
isa MMethodDef then
549 node
.labels
.add
"MMethodDef"
550 node
["is_abstract"] = mpropdef
.is_abstract
551 node
["is_intern"] = mpropdef
.is_intern
552 node
["is_extern"] = mpropdef
.is_extern
553 var msignature
= mpropdef
.msignature
554 if msignature
!= null then
555 node
.out_edges
.add
(new NeoEdge(node
, "SIGNATURE", to_node
(msignature
)))
557 else if mpropdef
isa MAttributeDef then
558 node
.labels
.add
"MAttributeDef"
559 else if mpropdef
isa MVirtualTypeDef then
560 node
.labels
.add
"MVirtualTypeDef"
561 var bound
= mpropdef
.bound
562 if bound
!= null then
563 node
.out_edges
.add
(new NeoEdge(node
, "BOUND", to_node
(bound
)))
569 # Build a new `MPropDef` from a `node`.
571 # REQUIRE `node.labels.has("MPropDef")`
572 private fun to_mpropdef
(model
: Model, node
: NeoNode): MPropDef do
573 if mentities
.has_key
(node
) then return mentities
[node
].as(MPropDef)
574 assert node
.labels
.has
("MPropDef")
575 var mclassdef
= to_mclassdef
(model
, node
.in_nodes
("DECLARES").first
)
576 var mproperty
= to_mproperty
(model
, node
.out_nodes
("DEFINES").first
)
577 var location
= to_location
(node
["location"].to_s
)
578 var mpropdef
: nullable MPropDef = null
579 if node
.labels
.has
("MMethodDef") then
580 mpropdef
= new MMethodDef(mclassdef
, mproperty
.as(MMethod), location
)
581 mpropdef
.is_abstract
= node
["is_abstract"].as(Bool)
582 mpropdef
.is_intern
= node
["is_intern"].as(Bool)
583 mpropdef
.is_extern
= node
["is_extern"].as(Bool)
584 mentities
[node
] = mpropdef
585 mpropdef
.msignature
= to_mtype
(model
, node
.out_nodes
("SIGNATURE").first
).as(MSignature)
586 else if node
.labels
.has
("MAttributeDef") then
587 mpropdef
= new MAttributeDef(mclassdef
, mproperty
.as(MAttribute), location
)
588 mentities
[node
] = mpropdef
589 else if node
.labels
.has
("MVirtualTypeDef") then
590 mpropdef
= new MVirtualTypeDef(mclassdef
, mproperty
.as(MVirtualTypeProp), location
)
591 mentities
[node
] = mpropdef
592 var bound
= node
.out_nodes
("BOUND")
593 if not bound
.is_empty
then mpropdef
.bound
= to_mtype
(model
, bound
.first
)
595 if mpropdef
== null then
596 print
"not yet implemented to_mpropdef for {node.labels.join(",")}"
599 set_doc
(node
, mpropdef
)
603 # Build a `NeoNode` representing `mtype`.
604 private fun mtype_node
(mtype
: MType): NeoNode do
605 var node
= make_node
(mtype
)
606 node
.labels
.add
"MType"
607 if mtype
isa MClassType then
608 node
.labels
.add
"MClassType"
609 node
.out_edges
.add
(new NeoEdge(node
, "CLASS", to_node
(mtype
.mclass
)))
610 for arg
in mtype
.arguments
do
611 node
.out_edges
.add
(new NeoEdge(node
, "ARGUMENT", to_node
(arg
)))
613 if mtype
isa MGenericType then
614 node
.labels
.add
"MGenericType"
616 else if mtype
isa MVirtualType then
617 node
.labels
.add
"MVirtualType"
618 node
.out_edges
.add
(new NeoEdge(node
, "PROPERTY", to_node
(mtype
.mproperty
)))
619 else if mtype
isa MParameterType then
620 node
.labels
.add
"MParameterType"
621 node
["rank"] = mtype
.rank
622 node
.out_edges
.add
(new NeoEdge(node
, "CLASS", to_node
(mtype
.mclass
)))
623 else if mtype
isa MNullableType then
624 node
.labels
.add
"MNullableType"
625 node
.out_edges
.add
(new NeoEdge(node
, "TYPE", to_node
(mtype
.mtype
)))
626 else if mtype
isa MSignature then
627 node
.labels
.add
"MSignature"
628 for mparameter
in mtype
.mparameters
do
629 node
.out_edges
.add
(new NeoEdge(node
, "PARAMETER", to_node
(mparameter
)))
631 var return_mtype
= mtype
.return_mtype
632 if return_mtype
!= null then
633 node
.out_edges
.add
(new NeoEdge(node
, "RETURNTYPE", to_node
(return_mtype
)))
639 # Build a new `MType` from a `node`.
641 # REQUIRE `node.labels.has("MType")`
642 private fun to_mtype
(model
: Model, node
: NeoNode): MType do
643 if mentities
.has_key
(node
) then return mentities
[node
].as(MType)
644 assert node
.labels
.has
("MType")
645 if node
.labels
.has
("MClassType") then
646 var mclass
= to_mclass
(model
, node
.out_nodes
("CLASS").first
)
647 var args
= new Array[MType]
648 for narg
in node
.out_nodes
("ARGUMENT") do
649 args
.add to_mtype
(model
, narg
)
651 var mtype
= mclass
.get_mtype
(args
)
652 mentities
[node
] = mtype
654 else if node
.labels
.has
("MParameterType") then
655 var mclass
= to_mclass
(model
, node
.out_nodes
("CLASS").first
)
656 var rank
= node
["rank"].to_s
.to_i
657 var mtype
= new MParameterType(mclass
, rank
)
658 mentities
[node
] = mtype
660 else if node
.labels
.has
("MNullableType") then
661 var intype
= to_mtype
(model
, node
.out_nodes
("TYPE").first
)
662 var mtype
= new MNullableType(intype
)
663 mentities
[node
] = mtype
665 else if node
.labels
.has
("MVirtualType") then
666 var mproperty
= to_mproperty
(model
, node
.out_nodes
("PROPERTY").first
)
667 var mtype
= new MVirtualType(mproperty
)
668 mentities
[node
] = mtype
670 else if node
.labels
.has
("MSignature") then
671 var mparameters
= new Array[MParameter]
672 for pnode
in node
.out_nodes
("PARAMETER") do
673 mparameters
.add to_mparameter
(model
, pnode
)
675 var return_mtype
: nullable MType = null
676 var ret_nodes
= node
.out_nodes
("RETURNTYPE")
677 if not ret_nodes
.is_empty
then
678 return_mtype
= to_mtype
(model
, ret_nodes
.first
)
680 var mtype
= new MSignature(mparameters
, return_mtype
)
681 mentities
[node
] = mtype
684 print
"not yet implemented to_mtype for {node.labels.join(",")}"
688 # Build a `NeoNode` representing `mparameter`.
689 private fun mparameter_node
(mparameter
: MParameter): NeoNode do
690 var node
= make_node
(mparameter
)
691 node
.labels
.add
"MParameter"
692 node
["name"] = mparameter
.name
693 node
["is_vararg"] = mparameter
.is_vararg
694 node
.out_edges
.add
(new NeoEdge(node
, "TYPE", to_node
(mparameter
.mtype
)))
698 # Build a new `MParameter` from `node`.
700 # REQUIRE `node.labels.has("MParameter")`
701 private fun to_mparameter
(model
: Model, node
: NeoNode): MParameter do
702 if mentities
.has_key
(node
) then return mentities
[node
].as(MParameter)
703 assert node
.labels
.has
("MParameter")
704 var name
= node
["name"].to_s
705 var mtype
= to_mtype
(model
, node
.out_nodes
("TYPE").first
)
706 var is_vararg
= node
["is_vararg"].as(Bool)
707 var mparameter
= new MParameter(name
, mtype
, is_vararg
)
708 mentities
[node
] = mparameter
712 # Get a `Location` from its string representation.
713 private fun to_location
(loc
: String): Location do
715 var parts
= loc
.split_with
(":")
716 var file
= new SourceFile.from_string
(parts
[0], "")
717 var pos
= parts
[1].split_with
("--")
718 var pos1
= pos
[0].split_with
(",")
719 var pos2
= pos
[1].split_with
(",")
720 var line_s
= pos1
[0].to_i
721 var line_e
= pos2
[0].to_i
722 var column_s
= pos1
[1].to_i
724 if pos2
.length
== 2 then pos2
[1].to_i
725 return new Location(file
, line_s
, line_e
, column_s
, column_e
)
728 # Get a `MVisibility` from its string representation.
729 private fun to_visibility
(vis
: String): MVisibility do
730 if vis
== intrude_visibility
.to_s
then
731 return intrude_visibility
732 else if vis
== public_visibility
.to_s
then
733 return public_visibility
734 else if vis
== protected_visibility
.to_s
then
735 return protected_visibility
736 else if vis
== private_visibility
.to_s
then
737 return private_visibility
739 return none_visibility
743 # Get a `MKind` from its string representation.
744 private fun to_kind
(kind
: String): MClassKind do
745 if kind
== abstract_kind
.to_s
then
747 else if kind
== concrete_kind
.to_s
then
749 else if kind
== interface_kind
.to_s
then
750 return interface_kind
751 else if kind
== enum_kind
.to_s
then
753 else if kind
== extern_kind
.to_s
then
759 # Extract the `MDoc` from `node` and link it to `mentity`.
760 private fun set_doc
(node
: NeoNode, mentity
: MEntity) do
761 if node
.has_key
("mdoc") then
762 var lines
= new Array[String]
763 for e
in node
["mdoc"].as(JsonArray) do
764 lines
.add e
.to_s
#.replace("\n", "\\n")
767 mdoc
.content
.add_all
(lines
)
768 mdoc
.original_mentity
= mentity