X-Git-Url: http://nitlanguage.org diff --git a/src/neo.nit b/src/neo.nit index cf775a8..32fab5d 100644 --- a/src/neo.nit +++ b/src/neo.nit @@ -43,7 +43,6 @@ # `MGroup` # # * labels: `MGroup`, `model_name` and `MEntity`. -# * `full_name`: fully qualified name. # * `(:MGroup)-[:PROJECT]->(:MProject)`: associated project. # * `(:MGroup)-[:PARENT]->(:MGroup)`: parent group. Does not exist for the root # group. @@ -55,7 +54,6 @@ # `MModule` # # * labels: `MModule`, `model_name` and `MEntity`. -# * `full_name`: fully qualified name. # * `location`: origin of the definition. SEE: `Location.to_s` # * `(:MModule)-[:IMPORTS]->(:MModule)`: modules that are imported directly. # * `(:MModule)-[:INTRODUCES]->(:MClass)`: all by classes introduced by this @@ -66,7 +64,6 @@ # `MClass` # # * labels: `MClass`, `model_name` and `MEntity`. -# * `full_name`: fully qualified name. # * `kind`: kind of the class (`interface`, `abstract class`, etc.) # * `visibility`: visibility of the class. # * `parameter_names`: JSON array listing the name of each formal generic @@ -94,20 +91,23 @@ # `MProperty` # # * labels: `MProperty`, `model_name` and `MEntity`. Must also have `MMethod`, -# `MAttribute` or `MVirtualTypeProp`, depending on the class of the represented -# entity. -# * `full_name`: fully qualified name. +# `MAttribute` `MVirtualTypeProp` or `MInnerClass`, depending on the class of +# the represented entity. # * `visibility`: visibility of the property. # * `is_init`: Indicates if the property is a constructor. Exists only if the # node is a `MMethod`. # * `(:MProperty)-[:INTRO_CLASSDEF]->(:MClassDef)`: classdef that introduces # the property. # +# Additional relationship for `MInnerClass`: +# +# * `(:MInnerClassDef)-[:NESTS]->(:MClass)`: actual inner class. +# # `MPropDef` # # * labels: `MPropDef`, `model_name` and `MEntity`. Must also have `MMethodDef`, -# `MAttributeDef` or `MVirtualTypeDef`, depending on the class of the -# represented entity. +# `MAttributeDef`, `MVirtualTypeDef` or `MInnerClassDef`, depending on the +# class of the represented entity. # * `location`: origin of the definition. SEE: `Location.to_s`. # * `(:MPropDef)-[:DEFINES]->(:MProperty)`: associated property. # @@ -130,6 +130,11 @@ # is bound in this definition. Exists only if this definition bound the virtual # type to an effective type. # +# Additional relationship for `MInnerClassDef`: +# +# * `(:MInnerClassDef)-[:NESTS]->(:MClassDef)`: actual inner class' +# definition. +# # `MType` # # * labels: `MType`, `model_name` and `MEntity`. Must also have `MClassType`, @@ -178,7 +183,9 @@ # # For example, if the source code contains: # +# ~~~nitish # fun foo(a: A, b: B, c: C) +# ~~~ # # The `MSignature` node will contain a property # `parameter_names = ["a", "b", "c"]` so the MSignature can be reconstructed @@ -224,27 +231,27 @@ class NeoModel # Fill `model` using base pointed by `client`. fun load(model: Model): Model do - toolcontext.info("Locate all mentities...", 1) - var nodes = client.nodes_with_label(model_name) - - toolcontext.info("Preload nodes...", 1) - pull_all_nodes(nodes) - toolcontext.info("Preload edges...", 1) - pull_all_edges(nodes) + var nodes: Array[NeoNode] - toolcontext.info("Build model...", 1) + toolcontext.info("Loading project node...", 1) nodes = client.nodes_with_labels([model_name, "MProject"]) for node in nodes do to_mproject(model, node) + toolcontext.info("Loading groups...", 1) nodes = client.nodes_with_labels([model_name, "MGroup"]) for node in nodes do to_mgroup(model, node) + toolcontext.info("Loading modules...", 1) nodes = client.nodes_with_labels([model_name, "MModule"]) for node in nodes do to_mmodule(model, node) + toolcontext.info("Loading classes...", 1) nodes = client.nodes_with_labels([model_name, "MClass"]) for node in nodes do to_mclass(model, node) + toolcontext.info("Loading class definitions...", 1) nodes = client.nodes_with_labels([model_name, "MClassDef"]) for node in nodes do to_mclassdef(model, node) + toolcontext.info("Loading properties...", 1) nodes = client.nodes_with_labels([model_name, "MProperty"]) for node in nodes do to_mproperty(model, node) + toolcontext.info("Loading property definitions...", 1) nodes = client.nodes_with_labels([model_name, "MPropDef"]) for node in nodes do to_mpropdef(model, node) return model @@ -281,52 +288,6 @@ class NeoModel do_batch(batch) end - # Load content for all `nodes` from base. - # - # Content corresponds to properties and labels that are loaded in batch mode. - private fun pull_all_nodes(nodes: Collection[NeoNode]) do - var batch = new NeoBatch(client) - var len = nodes.length - var sum = 0 - var i = 1 - for node in nodes do - batch.load_node(node) - if i == batch_max_size then - do_batch(batch) - sum += batch_max_size - toolcontext.info(" {sum * 100 / len}% done", 1) - batch = new NeoBatch(client) - i = 1 - else - i += 1 - end - end - do_batch(batch) - end - - # Load all edges from base linked to `nodes`. - # - # Edges are loaded in batch mode. - private fun pull_all_edges(nodes: Collection[NeoNode]) do - var batch = new NeoBatch(client) - var len = nodes.length - var sum = 0 - var i = 1 - for node in nodes do - batch.load_node_edges(node) - if i == batch_max_size then - do_batch(batch) - sum += batch_max_size - toolcontext.info(" {sum * 100 / len}% done", 1) - batch = new NeoBatch(client) - i = 1 - else - i += 1 - end - end - do_batch(batch) - end - # How many operation can be executed in one batch? private var batch_max_size = 1000 @@ -360,7 +321,9 @@ class NeoModel end # Mentities associated to nodes. - private var mentities = new HashMap[NeoNode, MEntity] + # + # The key is the node’s id. + private var mentities = new HashMap[Int, MEntity] # Nodes associated with MEntities. private var nodes = new HashMap[MEntity, NeoNode] @@ -402,7 +365,10 @@ class NeoModel node.labels.add "MEntity" node.labels.add model_name node["name"] = mentity.name - if mentity.mdoc != null then node["mdoc"] = new JsonArray.from(mentity.mdoc.content) + if mentity.mdoc != null then + node["mdoc"] = new JsonArray.from(mentity.mdoc.content) + node["mdoc_location"] = mentity.mdoc.location.to_s + end return node end @@ -421,10 +387,12 @@ class NeoModel # # REQUIRE `node.labels.has("MProject")` private fun to_mproject(model: Model, node: NeoNode): MProject do - if mentities.has_key(node) then return mentities[node].as(MProject) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MProject then return m + assert node.labels.has("MProject") var mproject = new MProject(node["name"].to_s, model) - mentities[node] = mproject + mentities[node.id.as(Int)] = mproject set_doc(node, mproject) mproject.root = to_mgroup(model, node.out_nodes("ROOT").first) return mproject @@ -434,7 +402,6 @@ class NeoModel private fun mgroup_node(mgroup: MGroup): NeoNode do var node = make_node(mgroup) node.labels.add "MGroup" - node["full_name"] = mgroup.full_name var parent = mgroup.parent node.out_edges.add(new NeoEdge(node, "PROJECT", to_node(mgroup.mproject))) if parent != null then @@ -453,7 +420,9 @@ class NeoModel # # REQUIRE `node.labels.has("MGroup")` private fun to_mgroup(model: Model, node: NeoNode): MGroup do - if mentities.has_key(node) then return mentities[node].as(MGroup) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MGroup then return m + assert node.labels.has("MGroup") var mproject = to_mproject(model, node.out_nodes("PROJECT").first) var parent: nullable MGroup = null @@ -462,7 +431,7 @@ class NeoModel parent = to_mgroup(model, out.first) end var mgroup = new MGroup(node["name"].to_s, mproject, parent) - mentities[node] = mgroup + mentities[node.id.as(Int)] = mgroup set_doc(node, mgroup) return mgroup end @@ -471,7 +440,6 @@ class NeoModel private fun mmodule_node(mmodule: MModule): NeoNode do var node = make_node(mmodule) node.labels.add "MModule" - node["full_name"] = mmodule.full_name node["location"] = mmodule.location.to_s for parent in mmodule.in_importation.direct_greaters do node.out_edges.add(new NeoEdge(node, "IMPORTS", to_node(parent))) @@ -489,7 +457,9 @@ class NeoModel # # REQUIRE `node.labels.has("MModule")` private fun to_mmodule(model: Model, node: NeoNode): MModule do - if mentities.has_key(node) then return mentities[node].as(MModule) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MModule then return m + assert node.labels.has("MModule") var ins = node.in_nodes("DECLARES") var mgroup: nullable MGroup = null @@ -499,7 +469,7 @@ class NeoModel var name = node["name"].to_s var location = to_location(node["location"].to_s) var mmodule = new MModule(model, mgroup, name, location) - mentities[node] = mmodule + mentities[node.id.as(Int)] = mmodule set_doc(node, mmodule) var imported_mmodules = new Array[MModule] for smod in node.out_nodes("IMPORTS") do @@ -513,7 +483,6 @@ class NeoModel private fun mclass_node(mclass: MClass): NeoNode do var node = make_node(mclass) node.labels.add "MClass" - node["full_name"] = mclass.full_name node["kind"] = mclass.kind.to_s node["visibility"] = mclass.visibility.to_s if not mclass.mparameters.is_empty then @@ -529,7 +498,9 @@ class NeoModel # # REQUIRE `node.labels.has("MClass")` private fun to_mclass(model: Model, node: NeoNode): MClass do - if mentities.has_key(node) then return mentities[node].as(MClass) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MClass then return m + assert node.labels.has("MClass") var mmodule = to_mmodule(model, node.in_nodes("INTRODUCES").first) var name = node["name"].to_s @@ -542,7 +513,7 @@ class NeoModel end end var mclass = new MClass(mmodule, name, parameter_names, kind, visibility) - mentities[node] = mclass + mentities[node.id.as(Int)] = mclass set_doc(node, mclass) return mclass end @@ -570,13 +541,15 @@ class NeoModel # # REQUIRE `node.labels.has("MClassDef")` private fun to_mclassdef(model: Model, node: NeoNode): MClassDef do - if mentities.has_key(node) then return mentities[node].as(MClassDef) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MClassDef then return m + assert node.labels.has("MClassDef") var mmodule = to_mmodule(model, node.in_nodes("DEFINES").first) var mtype = to_mtype(model, node.out_nodes("BOUNDTYPE").first).as(MClassType) var location = to_location(node["location"].to_s) var mclassdef = new MClassDef(mmodule, mtype, location) - mentities[node] = mclassdef + mentities[node.id.as(Int)] = mclassdef set_doc(node, mclassdef) var supertypes = new Array[MClassType] for sup in node.out_nodes("INHERITS") do @@ -591,7 +564,6 @@ class NeoModel private fun mproperty_node(mproperty: MProperty): NeoNode do var node = make_node(mproperty) node.labels.add "MProperty" - node["full_name"] = mproperty.full_name node["visibility"] = mproperty.visibility.to_s if mproperty isa MMethod then node.labels.add "MMethod" @@ -600,6 +572,9 @@ class NeoModel node.labels.add "MAttribute" else if mproperty isa MVirtualTypeProp then node.labels.add "MVirtualTypeProp" + else if mproperty isa MInnerClass then + node.labels.add "MInnerClass" + node.out_edges.add(new NeoEdge(node, "NESTS", to_node(mproperty.inner))) end node.out_edges.add(new NeoEdge(node, "INTRO_CLASSDEF", to_node(mproperty.intro_mclassdef))) return node @@ -609,7 +584,9 @@ class NeoModel # # REQUIRE `node.labels.has("MProperty")` private fun to_mproperty(model: Model, node: NeoNode): MProperty do - if mentities.has_key(node) then return mentities[node].as(MProperty) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MProperty then return m + assert node.labels.has("MProperty") var intro_mclassdef = to_mclassdef(model, node.out_nodes("INTRO_CLASSDEF").first) var name = node["name"].to_s @@ -622,12 +599,15 @@ class NeoModel mprop = new MAttribute(intro_mclassdef, name, visibility) else if node.labels.has("MVirtualTypeProp") then mprop = new MVirtualTypeProp(intro_mclassdef, name, visibility) + else if node.labels.has("MInnerClass") then + var inner = to_mclass(model, node.out_nodes("NESTS").first) + mprop = new MInnerClass(intro_mclassdef, name, visibility, inner) end if mprop == null then print "not yet implemented to_mproperty for {node.labels.join(",")}" abort end - mentities[node] = mprop + mentities[node.id.as(Int)] = mprop set_doc(node, mprop) return mprop end @@ -659,6 +639,9 @@ class NeoModel if bound != null then node.out_edges.add(new NeoEdge(node, "BOUND", to_node(bound))) end + else if mpropdef isa MInnerClassDef then + node.labels.add "MInnerClassDef" + node.out_edges.add(new NeoEdge(node, "NESTS", to_node(mpropdef.inner))) end return node end @@ -667,7 +650,9 @@ class NeoModel # # REQUIRE `node.labels.has("MPropDef")` private fun to_mpropdef(model: Model, node: NeoNode): MPropDef do - if mentities.has_key(node) then return mentities[node].as(MPropDef) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MPropDef then return m + assert node.labels.has("MPropDef") var mclassdef = to_mclassdef(model, node.in_nodes("DECLARES").first) var mproperty = to_mproperty(model, node.out_nodes("DEFINES").first) @@ -678,18 +663,23 @@ class NeoModel mpropdef.is_abstract = node["is_abstract"].as(Bool) mpropdef.is_intern = node["is_intern"].as(Bool) mpropdef.is_extern = node["is_extern"].as(Bool) - mentities[node] = mpropdef + mentities[node.id.as(Int)] = mpropdef mpropdef.msignature = to_mtype(model, node.out_nodes("SIGNATURE").first).as(MSignature) else if node.labels.has("MAttributeDef") then mpropdef = new MAttributeDef(mclassdef, mproperty.as(MAttribute), location) - mentities[node] = mpropdef + mentities[node.id.as(Int)] = mpropdef var static_mtype = node.out_nodes("TYPE") if not static_mtype.is_empty then mpropdef.static_mtype = to_mtype(model, static_mtype.first) else if node.labels.has("MVirtualTypeDef") then mpropdef = new MVirtualTypeDef(mclassdef, mproperty.as(MVirtualTypeProp), location) - mentities[node] = mpropdef + mentities[node.id.as(Int)] = mpropdef var bound = node.out_nodes("BOUND") if not bound.is_empty then mpropdef.bound = to_mtype(model, bound.first) + else if node.labels.has("MInnerClassDef") then + var inner = to_mclassdef(model, node.out_nodes("NESTS").first) + mpropdef = new MInnerClassDef(mclassdef, + mproperty.as(MInnerClass), location, inner) + mentities[node.id.as(Int)] = mpropdef end if mpropdef == null then print "not yet implemented to_mpropdef for {node.labels.join(",")}" @@ -771,7 +761,9 @@ class NeoModel # # REQUIRE `node.labels.has("MType")` private fun to_mtype(model: Model, node: NeoNode): MType do - if mentities.has_key(node) then return mentities[node].as(MType) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MType then return m + assert node.labels.has("MType") if node.labels.has("MClassType") then var mclass = to_mclass(model, node.out_nodes("CLASS").first) @@ -780,24 +772,24 @@ class NeoModel args.add to_mtype(model, narg) end var mtype = mclass.get_mtype(args) - mentities[node] = mtype + mentities[node.id.as(Int)] = mtype return mtype else if node.labels.has("MParameterType") then var mclass = to_mclass(model, node.out_nodes("CLASS").first) var rank = node["rank"].to_s.to_i var mtype = mclass.mparameters[rank] - mentities[node] = mtype + mentities[node.id.as(Int)] = mtype return mtype else if node.labels.has("MNullableType") then var intype = to_mtype(model, node.out_nodes("TYPE").first) var mtype = intype.as_nullable - mentities[node] = mtype + mentities[node.id.as(Int)] = mtype return mtype else if node.labels.has("MVirtualType") then var mproperty = to_mproperty(model, node.out_nodes("PROPERTY").first) assert mproperty isa MVirtualTypeProp var mtype = mproperty.mvirtualtype - mentities[node] = mtype + mentities[node.id.as(Int)] = mtype return mtype else if node.labels.has("MSignature") then # Get all param nodes @@ -821,7 +813,7 @@ class NeoModel return_mtype = to_mtype(model, ret_nodes.first) end var mtype = new MSignature(mparameters, return_mtype) - mentities[node] = mtype + mentities[node.id.as(Int)] = mtype return mtype else if node.labels.has("MRawType") then var mtype = new MRawType(model) @@ -840,7 +832,7 @@ class NeoModel end end end - mentities[node] = mtype + mentities[node.id.as(Int)] = mtype return mtype end print "not yet implemented to_mtype for {node.labels.join(",")}" @@ -861,13 +853,15 @@ class NeoModel # # REQUIRE `node.labels.has("MParameter")` private fun to_mparameter(model: Model, node: NeoNode): MParameter do - if mentities.has_key(node) then return mentities[node].as(MParameter) + var m = mentities.get_or_null(node.id.as(Int)) + if m isa MParameter then return m + assert node.labels.has("MParameter") var name = node["name"].to_s var mtype = to_mtype(model, node.out_nodes("TYPE").first) var is_vararg = node["is_vararg"].as(Bool) var mparameter = new MParameter(name, mtype, is_vararg) - mentities[node] = mparameter + mentities[node.id.as(Int)] = mparameter return mparameter end @@ -876,6 +870,9 @@ class NeoModel #TODO filepath var parts = loc.split_with(":") var file = new SourceFile.from_string(parts[0], "") + if parts.length == 1 then + return new Location(file, 0, 0, 0, 0) + end var pos = parts[1].split_with("--") var pos1 = pos[0].split_with(",") var pos2 = pos[1].split_with(",") @@ -928,7 +925,8 @@ class NeoModel for e in node["mdoc"].as(JsonArray) do lines.add e.to_s#.replace("\n", "\\n") end - var mdoc = new MDoc + var location = to_location(node["mdoc_location"].to_s) + var mdoc = new MDoc(location) mdoc.content.add_all(lines) mdoc.original_mentity = mentity mentity.mdoc = mdoc