X-Git-Url: http://nitlanguage.org diff --git a/src/neo.nit b/src/neo.nit index 9ebdd01..a45c91c 100644 --- a/src/neo.nit +++ b/src/neo.nit @@ -15,7 +15,8 @@ # Save and load `Model` from/to Neo4j base. # # Nit models are composed by MEntities. -# This module creates NeoNode for each MEntity found in a `Model` and save them into Neo4j database. +# This module creates NeoNode for each MEntity found in a `Model` and save them +# into Neo4j database. # # see `Neo4jClient`. # @@ -23,102 +24,165 @@ # # Structure of the nit `Model` in base: # +# Note : Any null or empty attribute will not be saved in the database. +# +# For any `MEntity` (in addition to specific data): +# +# * labels: model name (`model_name`) and `MEntity`. +# * `name`: short (unqualified) name. +# * `mdoc`: JSON array representing the associated Markdown documentation +# (one item by line). +# +# Note : All nodes described here are MEntities. +# # `MProject` # -# * labels: `model_name`, `MEntity`, `MProject` -# * `(:MProject)-[:ROOT]->(:MGroup)` +# * labels: `MProject`, `model_name` and `MEntity`. +# * `(:MProject)-[:ROOT]->(:MGroup)`: root of the group tree. # # `MGroup` # -# * labels: `model_name`, `MEntity`, `MGroup` -# * `(:MGroup)-[:PROJECT]->(:MProject)` -# * `(:MGroup)-[:PARENT]->(: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. +# * `(:MGroup)-[:DECLARES]->(:MModule)`: modules that are direct children of +# this group. +# * `(:MGroup)-[:NESTS]->(:MGroup)`: nested groups that are direct children of +# this group. # # `MModule` # -# * labels: `model_name`, `MEntity`, `MModule` -# * `(:MModule)-[:IMPORTS]->(:MModule)` -# * `(:MModule)-[:INTRODUCES]->(:MClass)` -# * `(:MModule)-[:DEFINES]->(:MClassDef)` +# * 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 +# module. +# * `(:MModule)-[:DEFINES]->(:MClassDef)`: all class definitons contained in +# this module. # # `MClass` # -# * labels: `model_name`, `MEntity`, `MClass` -# * `(:MClass)-[:CLASSTYPE]->(:MClassType)` +# * labels: `MClass`, `model_name` and `MEntity`. +# * `full_name`: fully qualified name. +# * `arity`: number of generic formal parameters. 0 if the class is not generic. +# * `kind`: kind of the class (`interface`, `abstract class`, etc.) +# * `visibility`: visibility of the class. +# * `(:MClass)-[:CLASSTYPE]->(:MClassType)`: SEE: `MClass.mclass_type` +# +# Arguments in the `CLASSTYPE` are named following the `parameter_names` +# attribute of the `MClassDef` that introduces the class. A class definition +# introduces a class if and only if it has this class as `MCLASS` and +# has `is_intro` set to `true`. # # `MClassDef` # -# * labels: `model_name`, `MEntity`, `MClassDef` -# * `(:MClassDef)-[:BOUNDTYPE]->(:MClassType)` -# * `(:MClassDef)-[:MCLASS]->(:MClass)` -# * `(:MClassDef)-[:INTRODUCES]->(:MProperty)` -# * `(:MClassDef)-[:DECLARES]->(:MPropDef)` +# * labels: `MClassDef`, `model_name` and `MEntity`. +# * `is_intro`: Does this definition introduce the class? +# * `location`: origin of the definition. SEE: `Location.to_s` +# * `parameter_names`: JSON array listing the name of each formal generic +# parameter (in order of declaration). +# * `(:MClassDef)-[:BOUNDTYPE]->(:MClassType)`: bounded type associated to the +# classdef. +# * `(:MClassDef)-[:MCLASS]->(:MClass)`: associated `MClass`. +# * `(:MClassDef)-[:INTRODUCES]->(:MProperty)`: all properties introduced by +# the classdef. +# * `(:MClassDef)-[:DECLARES]->(:MPropDef)`: all property definitions in the +# classdef (introductions and redefinitions). +# * `(:MClassDef)-[:INHERITS]->(:MClassType)`: all declared super-types # # `MProperty` # -# * labels: `model_name`, `MEntity`, `MProperty` -# * `(:MProperty)-[:INTRO_CLASSDEF]->(:MClassDef)` -# -# MProperties can also have labels `MMethod`, `MAttribute`, `MVirtualTypeProp`. +# * 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. +# * `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. # # `MPropDef` # -# * labels: `model_name`, `MEntity`, `MPropDef` -# * `(:MPropDef)-[:DEFINES]->(:MProperty)` +# * labels: `MPropDef`, `model_name` and `MEntity`. Must also have `MMethodDef`, +# `MAttributeDef` or `MVirtualTypeDef`, depending on the class of the +# represented entity. +# * `is_intro`: Does this definition introduce the property? +# * `location`: origin of the definition. SEE: `Location.to_s`. +# * `(:MPropDef)-[:DEFINES]->(:MProperty)`: associated property. # -# MPropdefs can also have labels `MMethodDef`, `MAttributeDef`, `MVirtualTypeDef`. +# Additional attributes and relationship for `MMethodDef`: # -# `MMethodDef` are linked to a `MSignature`: +# * `is_abstract`: Is the method definition abstract? +# * `is_intern`: Is the method definition intern? +# * `is_extern`: Is the method definition extern? +# * `(:MMethodDef)-[:SIGNATURE]->(:MSignature)`: signature attached to the +# property definition. # -# * `(:MMethodDef)-[:SIGNATURE]->(:MSignature)` +# Additional relationship for `MVirtualTypeDef`: # -# `MVirtualTypeDef` are linked to a `MType` (its `bound`): -# -# * `(:MVirtualTypeDef)-[:BOUND]->(:MType)` +# * `(:MVirtualTypeDef)-[:BOUND]->(:MType)`: type to which the virtual type +# is bound in this definition. Exists only if this definition bound the virtual +# type to an effective type. # # `MType` # -# * labels: `model_name`, `MEntity`, `MType` +# * labels: `MType`, `model_name` and `MEntity`. Must also have `MClassType`, +# `MNullableType`, `MVirtualType` or `MSignature`, depending on the class of +# the represented entity. # -# MTypes can also have labels `MClassType`, `MGenericType`, `MNullableType`, `MVirtualType` -# and `MSignature`. +# Additional label and relationships for `MClassType`: # -# `MClassType` and `MGenericType` both point to a `MClass` and have type `arguments`: +# * If it is a `MGenericType`, also has the `MGenericType` label. +# * `(:MClassType)-[:CLASS]->(:MClass)`: SEE: `MClassType.mclass` +# * `(:MClassType)-[:ARGUMENT]->(:MType)`: type arguments. # -# * `(:MClassType)-[:CLASS]->(:MClass)` -# * `(:MClassType)-[:ARGUMENT]->(:MType)` +# Arguments are named following the `parameter_names` attribute of the +# `MClassDef` that introduces the class referred by `CLASS`. # -# `MVirtualType` points to its introducing `MProperty`: +# Additional relationship for `MVirtualType`: # -# * `(:MVirtualType)-[:PROPERTY]->(:MVirtualTypeDef)` +# * `(:MVirtualType)-[:PROPERTY]->(:MProperty)`: associated property that +# determines the type (usually a `MVirtualTypeProp`). # -# `MParameterType` points to its introducing `MClass`: +# Additional attribute and relationship for `MParameterType`: # -# * `(:MParameterType)-[:CLASS]->(:MClass)` +# * `rank`: position of the parameter (0 for the first parameter). +# * `(:MParameterType)-[:CLASS]->(:MClass)`: generic class where the parameter +# belong. # -# `MNullableType` points to its non-nullable `MType`: +# Additional relationship for `MNullableType`: # -# * `(:MNullableType)-[:TYPE]->(:MType)` +# * `(:MNullableType)-[:TYPE]->(:MType)`: base type of the nullable type. # -# `MSignature` can have `parameters` and a `return_mtype`: +# Additional attribute and relationships for `MSignature`: # -# * `(:MSignature)-[:PARAMETER]->(:MParameter)` -# * `(:MSignature)-[:RETURNTYPE]->(:MType)` +# * `parameter_names`: JSON array representing the list of the parameter names. +# * `(:MSignature)-[:PARAMETER]->(:MParameter)`: parameters. +# * `(:MSignature)-[:RETURNTYPE]->(:MType)`: return type. Does not exist for +# procedures. # -# In order to maintain the correct parameters order, each `MSignature` node contains -# an array of parameter names corresponding to the parameter order in the signature. +# In order to maintain the correct parameters order, each `MSignature` node +# contains an array of parameter names corresponding to the parameter order in +# the signature. # # For example, if the source code contains: # # 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 with the parameters in the correct order. +# The `MSignature` node will contain a property +# `parameter_names = ["a", "b", "c"]` so the MSignature can be reconstructed +# with the parameters in the correct order. # # `MParameter` # -# * labels: `model_name`, `MEntity`, `MParameter` -# * `(:MParameter)-[:TYPE]->(:MType)` +# * labels: `MParameter`, `model_name` and `MEntity`. +# * `is_vararg`: Is the parameter a vararg? +# * `rank`: position of the parameter (0 for the first parameter). +# * `(:MParameter)-[:TYPE]->(:MType)`: static type of the parameter. # # MParameters are also ranked by their position in the corresponding signature. # Rank 0 for the first parameter, 1 for the next one and etc. @@ -382,7 +446,6 @@ class NeoModel node.labels.add "MModule" node["full_name"] = mmodule.full_name node["location"] = mmodule.location.to_s - var mgroup = mmodule.mgroup for parent in mmodule.in_importation.direct_greaters do node.out_edges.add(new NeoEdge(node, "IMPORTS", to_node(parent))) end @@ -423,10 +486,14 @@ class NeoModel private fun mclass_node(mclass: MClass): NeoNode do var node = make_node(mclass) node.labels.add "MClass" - node["arity"] = mclass.arity 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 + var parameter_names = new Array[String] + for p in mclass.mparameters do parameter_names.add(p.name) + node["parameter_names"] = new JsonArray.from(parameter_names) + end node.out_edges.add(new NeoEdge(node, "CLASSTYPE", to_node(mclass.mclass_type))) return node end @@ -439,10 +506,15 @@ class NeoModel assert node.labels.has("MClass") var mmodule = to_mmodule(model, node.in_nodes("INTRODUCES").first) var name = node["name"].to_s - var arity = node["arity"].to_s.to_i var kind = to_kind(node["kind"].to_s) var visibility = to_visibility(node["visibility"].to_s) - var mclass = new MClass(mmodule, name, arity, kind, visibility) + var parameter_names = new Array[String] + if node.has_key("parameter_names") then + for e in node["parameter_names"].as(JsonArray) do + parameter_names.add e.to_s + end + end + var mclass = new MClass(mmodule, name, parameter_names, kind, visibility) mentities[node] = mclass set_doc(node, mclass) return mclass @@ -454,9 +526,6 @@ class NeoModel node.labels.add "MClassDef" node["is_intro"] = mclassdef.is_intro node["location"] = mclassdef.location.to_s - if not mclassdef.parameter_names.is_empty then - node["parameter_names"] = new JsonArray.from(mclassdef.parameter_names) - end node.out_edges.add(new NeoEdge(node, "BOUNDTYPE", to_node(mclassdef.bound_mtype))) node.out_edges.add(new NeoEdge(node, "MCLASS", to_node(mclassdef.mclass))) for mproperty in mclassdef.intro_mproperties do @@ -480,13 +549,7 @@ class NeoModel 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 parameter_names = new Array[String] - if node.has_key("parameter_names") then - for e in node["parameter_names"].as(JsonArray) do - parameter_names.add e.to_s - end - end - var mclassdef = new MClassDef(mmodule, mtype, location, parameter_names) + var mclassdef = new MClassDef(mmodule, mtype, location) mentities[node] = mclassdef set_doc(node, mclassdef) var supertypes = new Array[MClassType] @@ -673,17 +736,18 @@ class NeoModel 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 = new MParameterType(mclass, rank) + var mtype = mclass.mparameters[rank] mentities[node] = mtype return mtype else if node.labels.has("MNullableType") then var intype = to_mtype(model, node.out_nodes("TYPE").first) - var mtype = new MNullableType(intype) + var mtype = intype.as_nullable mentities[node] = mtype return mtype else if node.labels.has("MVirtualType") then var mproperty = to_mproperty(model, node.out_nodes("PROPERTY").first) - var mtype = new MVirtualType(mproperty) + assert mproperty isa MVirtualTypeProp + var mtype = mproperty.mvirtualtype mentities[node] = mtype return mtype else if node.labels.has("MSignature") then