intrude import parser
intrude import semantize::scope
intrude import modelbuilder_base
+intrude import modelize_property
# General factory to build semantic nodes in the AST of expressions
class ASTBuilder
return new ANotExpr.make(expr)
end
+ # Make a new attribute
+ fun make_attribute(name: String,
+ n_type: nullable AType,
+ n_visibility: nullable AVisibility,
+ initial_value: nullable AExpr,
+ n_block: nullable AExpr,
+ m_attributedef: nullable MAttributeDef,
+ m_setterdef: nullable MMethodDef,
+ m_getterdef: nullable MMethodDef): AAttrPropdef
+ do
+ return new AAttrPropdef.make(name, n_type, n_visibility, initial_value, n_block, m_attributedef, m_setterdef, m_getterdef)
+ end
+
+ # Make a new class (AStdClassdef)
+ fun make_class(mclassdef: nullable MClassDef,
+ n_visibility: nullable AVisibility,
+ n_formaldefs : Collection[AFormaldef],
+ n_extern_code_block : nullable AExternCodeBlock,
+ n_propdefs : Collection[APropdef],
+ n_classkind: nullable AClasskind): AStdClassdef
+ do
+ return new AStdClassdef.make(mclassdef, n_visibility, n_formaldefs, n_extern_code_block, n_propdefs, n_classkind)
+ end
+
+ fun make_var(variable: Variable, mtype: MType): AVarExpr
+ do
+ return new AVarExpr.make(variable, mtype)
+ end
+
+ # Make a call assignment i.e `a = 10`
+ fun make_call_assign(recv: AExpr, callsite: CallSite, n_args: nullable Collection[AExpr], n_value: AExpr): ACallAssignExpr
+ do
+ return new ACallAssignExpr.make(recv, callsite, n_args, n_value)
+ end
+
# Build a callsite to call the `mproperty` in the current method `caller_method`.
# `is_self_call` indicate if the method caller is a property of `self`
fun create_callsite(modelbuilder: ModelBuilder, caller_method : AMethPropdef, mproperty: MMethod, is_self_call: Bool): CallSite
end
end
+redef class ACallAssignExpr
+ private init make(recv: AExpr, callsite: CallSite, args: nullable Collection[AExpr], n_value: AExpr)
+ do
+ _callsite = callsite
+ _mtype = callsite.recv
+ _is_typed = true
+ var n_args = new AListExprs
+ if args != null then
+ n_args.n_exprs.add_all(args)
+ end
+ var n_qid = new AQid
+ n_qid.n_id = new TId
+ n_qid.n_id.text = callsite.mproperty.name
+ init_acallassignexpr(recv, n_qid, n_args, new TAssign, n_value)
+ end
+end
+
+redef class AStdClassdef
+ private init make(mclassdef: nullable MClassDef,
+ n_visibility: nullable AVisibility,
+ n_formaldefs : Collection[Object],
+ n_extern_code_block : nullable AExternCodeBlock,
+ n_propdefs : Collection[Object],
+ n_classkind: nullable AClasskind)
+ do
+ if n_visibility == null then n_visibility = new APublicVisibility
+ if n_classkind == null then n_classkind = new AConcreteClasskind.init_aconcreteclasskind(new TKwclass)
+ var n_qid = new AQclassid.init_aqclassid(null, new TClassid)
+ init_astdclassdef(null, null, n_visibility, n_classkind, n_qid, null, n_formaldefs, null, n_extern_code_block, n_propdefs, new TKwend)
+ _mclassdef = mclassdef
+ _mclass = mclassdef.mclass
+ end
+end
+
+redef class AAttrPropdef
+
+ # Create a new `AAttrPropdef`
+ # Note: By default if the `AVisibility` is not given the visibility is set to public
+ private init make(name: String,
+ n_type: nullable AType,
+ n_visibility: nullable AVisibility,
+ initial_value: nullable AExpr,
+ n_block: nullable AExpr,
+ m_attributedef: nullable MAttributeDef,
+ m_setterdef: nullable MMethodDef,
+ m_getterdef: nullable MMethodDef)
+ do
+ # Set the model type
+ if n_type != null then mtype = n_type.mtype
+ # Define the visibility default is public
+ if n_visibility == null then n_visibility = new APublicVisibility
+ init_aattrpropdef(null, null, n_visibility, new TKwvar, new TId, n_type, null, initial_value, null, null , n_block, null)
+ # Set the name of the attribute
+ _n_id2.text = name
+ _mpropdef = m_attributedef
+ _mreadpropdef = m_getterdef
+ _mwritepropdef = m_setterdef
+ if initial_value != null or n_block != null then has_value = true
+ if m_attributedef != null then self.location = m_attributedef.location
+ end
+end
+
redef class ANotExpr
private init make(expr: AExpr)
do
if n_visibility == null then n_visibility = new APublicVisibility
self.init_amethpropdef(null,tk_redef,n_visibility,new TKwmeth,null,null,null,n_methid,n_signature,n_annotations,n_extern_calls,n_extern_code_block,new TKwdo,n_block,new TKwend)
self.mpropdef = mmethoddef
+ if mpropdef != null then self.location = mmethoddef.location
end
end
end
end
-redef class AAsCastExpr
- private init make(n_expr: AExpr, n_type: AType)
- do
- init_aascastexpr(n_expr, new TKwas , null , n_type, null)
- end
-end
-
redef class AAsNotnullExpr
private init make(n_expr: AExpr, t: nullable MType)
do
end
redef class ASignature
+
+ init make_from_msignature(msignature: MSignature)
+ do
+ var nparams = new Array[AParam]
+ for mparam in msignature.mparameters do
+ var variable = new Variable(mparam.name)
+ variable.declared_type = mparam.mtype
+ n_params.add(new AParam.make(variable, new AType.make(mparam.mtype)))
+ end
+ var return_type = null
+ if msignature.return_mtype != null then return_type = new AType.make(msignature.return_mtype)
+ init_asignature(null, nparams, null, return_type)
+ end
+
redef fun clone: SELF
do
var ntype = n_type
private init make(v: nullable Variable, t: nullable AType)
do
_n_id = new TId
+ if v != null then _n_id.text = v.name
_variable = v
_n_type = t
end
v.add_decl("\};")
end
- # Globally compile the table of the class mclass
- # In a link-time optimisation compiler, tables are globally computed
- # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
- fun compile_class_to_c(mclass: MClass)
+ protected fun compile_class_vft(ccinfo: ClassCompilationInfo, v: SeparateCompilerVisitor)
do
- if mclass.is_broken then return
-
- var mtype = mclass.intro.bound_mtype
- var c_name = mclass.c_name
-
- var v = new_visitor
-
+ var mclass = ccinfo.mclass
+ var mtype = ccinfo.mtype
var rta = runtime_type_analysis
- var is_dead = rta != null and not rta.live_classes.has(mclass)
- # While the class may be dead, some part of separately compiled code may use symbols associated to the class, so
- # in order to compile and link correctly the C code, these symbols should be declared and defined.
- var need_corpse = is_dead and mtype.is_c_primitive or mclass.kind == extern_kind or mclass.kind == enum_kind
+ var c_name = ccinfo.mclass.c_name
+ var is_dead = ccinfo.is_dead
+ var need_corpse = ccinfo.need_corpse
v.add_decl("/* runtime class {c_name}: {mclass.full_name} (dead={is_dead}; need_corpse={need_corpse})*/")
v.add_decl("\}")
v.add_decl("\};")
end
+ end
+
+ # Given a `MClass`, if it's a universal class and if it needs to be handle
+ # specifically by the compiler, this function will compile it and return
+ # true. Otherwise, no C code will be written in the visitor and the value
+ # false will be returned.
+ fun compile_class_if_universal(ccinfo: ClassCompilationInfo, v: SeparateCompilerVisitor): Bool
+ do
+ var mclass = ccinfo.mclass
+ var mtype = ccinfo.mtype
+ var c_name = ccinfo.mclass.c_name
+ var is_dead = ccinfo.is_dead
+ var need_corpse = ccinfo.need_corpse
if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then
# Is a primitive type or the Pointer class, not any other extern class
- if mtype.is_tagged then return
+ if mtype.is_tagged then return true
#Build instance struct
self.header.add_decl("struct instance_{c_name} \{")
self.header.add_decl("\};")
# Pointer is needed by extern types, live or not
- if is_dead and mtype.mclass.name != "Pointer" then return
+ if is_dead and mtype.mclass.name != "Pointer" then return true
#Build BOX
self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype_extern});")
v.add("\}")
# A Pointer class also need its constructor
- if mtype.mclass.name != "Pointer" then return
+ if mtype.mclass.name != "Pointer" then return true
v = new_visitor
self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);")
v.add("return {res};")
end
v.add("\}")
- return
+ return true
else if mclass.name == "NativeArray" then
#Build instance struct
self.header.add_decl("struct instance_{c_name} \{")
v.add("{res}->length = length;")
v.add("return (val*){res};")
v.add("\}")
- return
+ return true
else if mclass.name == "RoutineRef" then
self.header.add_decl("struct instance_{c_name} \{")
self.header.add_decl("const struct type *type;")
v.add("{res}->method = method;")
v.add("return (val*){res};")
v.add("\}")
- return
+ return true
else if mtype.mclass.kind == extern_kind and mtype.mclass.name != "CString" then
# Is an extern class (other than Pointer and CString)
# Pointer is caught in a previous `if`, and CString is internal
v.add("return {res};")
end
v.add("\}")
- return
+ return true
end
+ return false
+ end
+
+ protected fun compile_default_new(ccinfo: ClassCompilationInfo, v: SeparateCompilerVisitor)
+ do
+ var mclass = ccinfo.mclass
+ var mtype = ccinfo.mtype
+ var c_name = ccinfo.mclass.c_name
+ var is_dead = ccinfo.is_dead
#Build NEW
self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);")
v.add("return {res};")
end
v.add("\}")
+
+ end
+
+ protected fun build_class_compilation_info(mclass: MClass): ClassCompilationInfo
+ do
+ var mtype = mclass.intro.bound_mtype
+ var rta = runtime_type_analysis
+ var is_dead = rta != null and not rta.live_classes.has(mclass)
+
+ # While the class may be dead, some part of separately compiled code may use symbols associated to the class, so
+ # in order to compile and link correctly the C code, these symbols should be declared and defined.
+ var need_corpse = is_dead and mtype.is_c_primitive or mclass.kind == extern_kind or mclass.kind == enum_kind
+
+ var compilation_info = new ClassCompilationInfo(mclass, is_dead, need_corpse)
+ return compilation_info
+ end
+
+ # Globally compile the table of the class mclass
+ # In a link-time optimisation compiler, tables are globally computed
+ # In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
+ fun compile_class_to_c(mclass: MClass)
+ do
+ var v = new_visitor
+ var class_info = build_class_compilation_info(mclass)
+ compile_class_vft(class_info, v)
+ var is_already_managed = compile_class_if_universal(class_info, v)
+ if not is_already_managed then
+ compile_default_new(class_info, v)
+ end
end
# Compile structures used to map tagged primitive values to their classes and types.
end
end
+# Encapsulates every information needed to compile a class.
+#
+# The compilation of a class is done by several methods, two of those are
+# mandatory :
+# - compile_class_to_c : starts the compilation process
+# - compile_class_vft : generate the virtual function table
+# And one of them is optional :
+# - compile_class_if_universal : compiles the rest of the class if its a universal
+# type. Universal type are handle in a case-basis, this is why they need special treatment.
+# Generally, universal class will have special structure and a custom allocator.
+#
+# Throughout each step of the class compilation process, some information must be share.
+# This class encapsulates the compilation process state.
+# (except vft), eg
+class ClassCompilationInfo
+ var mclass: MClass # class to compile
+ var is_dead: Bool
+ var need_corpse: Bool
+
+ # Shortcut to access the class's bound type.
+ var mtype: MClassType is noinit
+
+ init
+ do
+ mtype = mclass.intro.bound_mtype
+ end
+end
+
class SeparateThunkFunction
super ThunkFunction
super SeparateRuntimeFunction
self.header.add_decl("typedef struct instance \{ const struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
end
- redef fun compile_class_to_c(mclass: MClass)
+ redef fun compile_class_if_universal(ccinfo, v)
do
- var mtype = mclass.intro.bound_mtype
+ var mclass = ccinfo.mclass
+ var mtype = ccinfo.mtype
var c_name = mclass.c_name
-
- var class_table = self.class_tables[mclass]
- var v = self.new_visitor
-
- var rta = runtime_type_analysis
- var is_dead = false # mclass.kind == abstract_kind or mclass.kind == interface_kind
- if not is_dead and rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" then
- is_dead = true
- end
-
- v.add_decl("/* runtime class {c_name} */")
-
- self.provide_declaration("class_{c_name}", "extern const struct class class_{c_name};")
- v.add_decl("extern const struct type_table type_table_{c_name};")
-
- # Build class vft
- v.add_decl("const struct class class_{c_name} = \{")
- v.add_decl("{class_ids[mclass]},")
- v.add_decl("\"{mclass.name}\", /* class_name_string */")
- v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
- v.add_decl("{class_colors[mclass]},")
- if not is_dead then
- if build_class_vts_table(mclass) then
- v.require_declaration("vts_table_{c_name}")
- v.add_decl("&vts_table_{c_name},")
- else
- v.add_decl("NULL,")
- end
- v.add_decl("&type_table_{c_name},")
- v.add_decl("\{")
- var vft = self.method_tables.get_or_null(mclass)
- if vft != null then for i in [0 .. vft.length[ do
- var mpropdef = vft[i]
- if mpropdef == null then
- v.add_decl("NULL, /* empty */")
- else
- assert mpropdef isa MMethodDef
- if rta != null and not rta.live_methoddefs.has(mpropdef) then
- v.add_decl("NULL, /* DEAD {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
- continue
- end
- var rf = mpropdef.virtual_runtime_function
- v.require_declaration(rf.c_name)
- v.add_decl("(nitmethod_t){rf.c_name}, /* pointer to {mpropdef.full_name} */")
- end
- end
- v.add_decl("\}")
- end
- v.add_decl("\};")
-
- # Build class type table
-
- v.add_decl("const struct type_table type_table_{c_name} = \{")
- v.add_decl("{class_table.length},")
- v.add_decl("\{")
- for msuper in class_table do
- if msuper == null then
- v.add_decl("-1, /* empty */")
- else
- v.add_decl("{self.class_ids[msuper]}, /* {msuper} */")
- end
- end
- v.add_decl("\}")
- v.add_decl("\};")
+ var is_dead = ccinfo.is_dead
if mtype.is_c_primitive or mtype.mclass.name == "Pointer" then
#Build instance struct
v.add("return (val*)res;")
v.add("\}")
- if mtype.mclass.name != "Pointer" then return
+ if mtype.mclass.name != "Pointer" then return true
v = new_visitor
self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}();")
v.add("return {res};")
end
v.add("\}")
- return
+ return true
else if mclass.name == "NativeArray" then
#Build instance struct
self.header.add_decl("struct instance_{c_name} \{")
v.add("{res}->length = length;")
v.add("return (val*){res};")
v.add("\}")
- return
+ return true
else if mclass.name == "RoutineRef" then
self.header.add_decl("struct instance_{c_name} \{")
self.header.add_decl("const struct class *class;")
v.add("{res}->method = method;")
v.add("return (val*){res};")
v.add("\}")
- return
+ return true
else if mtype.mclass.kind == extern_kind and mtype.mclass.name != "CString" then
var pointer_type = mainmodule.pointer_type
v.add("return {res};")
end
v.add("\}")
- return
+ return true
end
+ return false
+ end
+
+ redef fun compile_class_vft(ccinfo, v)
+ do
+ var mclass = ccinfo.mclass
+ var mtype = ccinfo.mtype
+ var c_name = mclass.c_name
+ var is_dead = ccinfo.is_dead
+ var rta = runtime_type_analysis
+
+ # Build class vft
+ self.provide_declaration("class_{c_name}", "extern const struct class class_{c_name};")
+
+ v.add_decl("const struct class class_{c_name} = \{")
+ v.add_decl("{class_ids[mclass]},")
+ v.add_decl("\"{mclass.name}\", /* class_name_string */")
+ v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
+ v.add_decl("{class_colors[mclass]},")
+ if not is_dead then
+ if build_class_vts_table(mclass) then
+ v.require_declaration("vts_table_{c_name}")
+ v.add_decl("&vts_table_{c_name},")
+ else
+ v.add_decl("NULL,")
+ end
+ v.add_decl("&type_table_{c_name},")
+ v.add_decl("\{")
+ var vft = self.method_tables.get_or_null(mclass)
+ if vft != null then for i in [0 .. vft.length[ do
+ var mpropdef = vft[i]
+ if mpropdef == null then
+ v.add_decl("NULL, /* empty */")
+ else
+ assert mpropdef isa MMethodDef
+ if rta != null and not rta.live_methoddefs.has(mpropdef) then
+ v.add_decl("NULL, /* DEAD {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
+ continue
+ end
+ var rf = mpropdef.virtual_runtime_function
+ v.require_declaration(rf.c_name)
+ v.add_decl("(nitmethod_t){rf.c_name}, /* pointer to {mpropdef.full_name} */")
+ end
+ end
+ v.add_decl("\}")
+ end
+ v.add_decl("\};")
+ end
+
+ protected fun compile_class_type_table(ccinfo: ClassCompilationInfo, v: SeparateCompilerVisitor)
+ do
+ var mclass = ccinfo.mclass
+ var c_name = mclass.c_name
+ var class_table = self.class_tables[mclass]
+
+ # Build class type table
+ v.add_decl("const struct type_table type_table_{c_name} = \{")
+ v.add_decl("{class_table.length},")
+ v.add_decl("\{")
+ for msuper in class_table do
+ if msuper == null then
+ v.add_decl("-1, /* empty */")
+ else
+ v.add_decl("{self.class_ids[msuper]}, /* {msuper} */")
+ end
+ end
+ v.add_decl("\}")
+ v.add_decl("\};")
+ end
+
+ redef fun compile_default_new(ccinfo, v)
+ do
+ var mclass = ccinfo.mclass
+ var mtype = ccinfo.mtype
+ var c_name = mclass.c_name
+ var is_dead = ccinfo.is_dead
#Build NEW
self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(void);")
v.add("\}")
end
+ redef fun build_class_compilation_info(mclass)
+ do
+ var ccinfo = super
+ var mtype = ccinfo.mtype
+ var rta = runtime_type_analysis
+ var is_dead = false # mclass.kind == abstract_kind or mclass.kind == interface_kind
+ if not is_dead and rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" then
+ is_dead = true
+ end
+ ccinfo.is_dead = is_dead
+ return ccinfo
+ end
+
+ redef fun compile_class_to_c(mclass: MClass)
+ do
+ var ccinfo = build_class_compilation_info(mclass)
+ var v = new_visitor
+ v.add_decl("/* runtime class {mclass.c_name} */")
+ self.provide_declaration("class_{mclass.c_name}", "extern const struct class class_{mclass.c_name};")
+ v.add_decl("extern const struct type_table type_table_{mclass.c_name};")
+ self.compile_class_vft(ccinfo, v)
+ self.compile_class_type_table(ccinfo, v)
+ if not self.compile_class_if_universal(ccinfo, v) then
+ self.compile_default_new(ccinfo, v)
+ end
+ end
+
private fun build_class_vts_table(mclass: MClass): Bool do
if self.vt_tables[mclass].is_empty then return false
# Collect all nodes from the current `model`.
private fun collect_model_nodes(model: Model): Collection[NeoNode] do
for mpackage in model.mpackages do
- to_node(mpackage)
- for mgroup in mpackage.mgroups do to_node(mgroup)
+ mpackage.to_node(nodes, model_name)
+ for mgroup in mpackage.mgroups do mgroup.to_node(nodes, model_name)
end
return nodes.values
end
# Nodes associated with MEntities.
private var nodes = new HashMap[MEntity, NeoNode]
- # Get the `NeoNode` associated with `mentity`.
- # `mentities` are stored locally to avoid duplication.
- fun to_node(mentity: MEntity): NeoNode do
- if nodes.has_key(mentity) then return nodes[mentity]
- if mentity isa MPackage then return mpackage_node(mentity)
- if mentity isa MGroup then return mgroup_node(mentity)
- if mentity isa MModule then return mmodule_node(mentity)
- if mentity isa MClass then return mclass_node(mentity)
- if mentity isa MClassDef then return mclassdef_node(mentity)
- if mentity isa MProperty then return mproperty_node(mentity)
- if mentity isa MPropDef then return mpropdef_node(mentity)
- if mentity isa MType then return mtype_node(mentity)
- if mentity isa MParameter then return mparameter_node(mentity)
- abort
- end
-
# Get the `MEntity` associated with `node`.
fun to_mentity(model: Model, node: NeoNode): MEntity do
if node.labels.has("MPackage") then return to_mpackage(model, node)
abort
end
- # Make a new `NeoNode` based on `mentity`.
- private fun make_node(mentity: MEntity): NeoNode do
- var node = new NeoNode
- nodes[mentity] = node
- node.labels.add "MEntity"
- node.labels.add model_name
- node["name"] = mentity.name
- if not mentity isa MSignature then
- #FIXME: MSignature is a MEntity, but has no model :/
- node["location"] = mentity.location.to_s
- end
- var mdoc = mentity.mdoc
- if mdoc != null then
- node["mdoc"] = new JsonArray.from(mdoc.content)
- node["mdoc_location"] = mdoc.location.to_s
- end
- return node
- end
-
- # Build a `NeoNode` representing `mpackage`.
- private fun mpackage_node(mpackage: MPackage): NeoNode do
- var node = make_node(mpackage)
- node.labels.add "MPackage"
- var root = mpackage.root
- if root != null then
- node.out_edges.add(new NeoEdge(node, "ROOT", to_node(root)))
- end
- return node
- end
-
# Build a new `MPackage` from a `node`.
#
# REQUIRE `node.labels.has("MPackage")`
return mpackage
end
- # Build a `NeoNode` representing `mgroup`.
- private fun mgroup_node(mgroup: MGroup): NeoNode do
- var node = make_node(mgroup)
- node.labels.add "MGroup"
- var parent = mgroup.parent
- node.out_edges.add(new NeoEdge(node, "PROJECT", to_node(mgroup.mpackage)))
- if parent != null then
- node.out_edges.add(new NeoEdge(node, "PARENT", to_node(parent)))
- end
- for mmodule in mgroup.mmodules do
- node.out_edges.add(new NeoEdge(node, "DECLARES", to_node(mmodule)))
- end
- for subgroup in mgroup.in_nesting.direct_smallers do
- node.in_edges.add(new NeoEdge(node, "NESTS", to_node(subgroup)))
- end
- return node
- end
-
# Build a new `MGroup` from a `node`.
#
# REQUIRE `node.labels.has("MGroup")`
return mgroup
end
- # Build a `NeoNode` representing `mmodule`.
- private fun mmodule_node(mmodule: MModule): NeoNode do
- var node = make_node(mmodule)
- node.labels.add "MModule"
- for parent in mmodule.in_importation.direct_greaters do
- node.out_edges.add(new NeoEdge(node, "IMPORTS", to_node(parent)))
- end
- for mclass in mmodule.intro_mclasses do
- node.out_edges.add(new NeoEdge(node, "INTRODUCES", to_node(mclass)))
- end
- for mclassdef in mmodule.mclassdefs do
- node.out_edges.add(new NeoEdge(node, "DEFINES", to_node(mclassdef)))
- end
- return node
- end
-
# Build a new `MModule` from a `node`.
#
# REQUIRE `node.labels.has("MModule")`
return mmodule
end
- # Build a `NeoNode` representing `mclass`.
- private fun mclass_node(mclass: MClass): NeoNode do
- var node = make_node(mclass)
- node.labels.add "MClass"
- 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
-
# Build a new `MClass` from a `node`.
#
# REQUIRE `node.labels.has("MClass")`
return mclass
end
- # Build a `NeoNode` representing `mclassdef`.
- private fun mclassdef_node(mclassdef: MClassDef): NeoNode do
- var node = make_node(mclassdef)
- node.labels.add "MClassDef"
- 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
- node.out_edges.add(new NeoEdge(node, "INTRODUCES", to_node(mproperty)))
- end
- for mpropdef in mclassdef.mpropdefs do
- node.out_edges.add(new NeoEdge(node, "DECLARES", to_node(mpropdef)))
- end
- for sup in mclassdef.supertypes do
- node.out_edges.add(new NeoEdge(node, "INHERITS", to_node(sup)))
- end
- return node
- end
-
# Build a new `MClassDef` from a `node`.
#
# REQUIRE `node.labels.has("MClassDef")`
return mclassdef
end
- # Build a `NeoNode` representing `mproperty`.
- private fun mproperty_node(mproperty: MProperty): NeoNode do
- var node = make_node(mproperty)
- node.labels.add "MProperty"
- node["visibility"] = mproperty.visibility.to_s
- if mproperty isa MMethod then
- node.labels.add "MMethod"
- node["is_init"] = mproperty.is_init
- else if mproperty isa MAttribute then
- 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
- end
-
# Build a new `MProperty` from a `node`.
#
# REQUIRE `node.labels.has("MProperty")`
return mprop
end
- # Build a `NeoNode` representing `mpropdef`.
- private fun mpropdef_node(mpropdef: MPropDef): NeoNode do
- var node = make_node(mpropdef)
- node.labels.add "MPropDef"
- node.out_edges.add(new NeoEdge(node, "DEFINES", to_node(mpropdef.mproperty)))
- if mpropdef isa MMethodDef then
- node.labels.add "MMethodDef"
- node["is_abstract"] = mpropdef.is_abstract
- node["is_intern"] = mpropdef.is_intern
- node["is_extern"] = mpropdef.is_extern
- var msignature = mpropdef.msignature
- if msignature != null then
- node.out_edges.add(new NeoEdge(node, "SIGNATURE", to_node(msignature)))
- end
- else if mpropdef isa MAttributeDef then
- node.labels.add "MAttributeDef"
- var static_mtype = mpropdef.static_mtype
- if static_mtype != null then
- node.out_edges.add(new NeoEdge(node, "TYPE", to_node(static_mtype)))
- end
- else if mpropdef isa MVirtualTypeDef then
- node.labels.add "MVirtualTypeDef"
- var bound = mpropdef.bound
- 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
-
# Build a new `MPropDef` from a `node`.
#
# REQUIRE `node.labels.has("MPropDef")`
return mpropdef
end
- # Build a `NeoNode` representing `mtype`.
- private fun mtype_node(mtype: MType): NeoNode do
- var node = make_node(mtype)
- node.labels.add "MType"
- if mtype isa MClassType then
- node.labels.add "MClassType"
- node.out_edges.add(new NeoEdge(node, "CLASS", to_node(mtype.mclass)))
- for arg in mtype.arguments do
- node.out_edges.add(new NeoEdge(node, "ARGUMENT", to_node(arg)))
- end
- if mtype isa MGenericType then
- node.labels.add "MGenericType"
- end
- else if mtype isa MVirtualType then
- node.labels.add "MVirtualType"
- node.out_edges.add(new NeoEdge(node, "PROPERTY", to_node(mtype.mproperty)))
- else if mtype isa MParameterType then
- node.labels.add "MParameterType"
- node["rank"] = mtype.rank
- node.out_edges.add(new NeoEdge(node, "CLASS", to_node(mtype.mclass)))
- else if mtype isa MNullableType then
- node.labels.add "MNullableType"
- node.out_edges.add(new NeoEdge(node, "TYPE", to_node(mtype.mtype)))
- else if mtype isa MSignature then
- node.labels.add "MSignature"
- var names = new JsonArray
- var rank = 0
- for mparameter in mtype.mparameters do
- names.add mparameter.name
- var pnode = to_node(mparameter)
- pnode["rank"] = rank
- node.out_edges.add(new NeoEdge(node, "PARAMETER", pnode))
- rank += 1
- end
- if not names.is_empty then node["parameter_names"] = names
- var return_mtype = mtype.return_mtype
- if return_mtype != null then
- node.out_edges.add(new NeoEdge(node, "RETURNTYPE", to_node(return_mtype)))
- end
- else if mtype isa MRawType then
- node.labels.add "MRawType"
- var text = new JsonArray
- var rank = 0
- for part in mtype.parts do
- text.add part.text
- if part.target != null then
- var pnode = mtypepart_node(part)
- pnode["rank"] = rank
- node.out_edges.add(new NeoEdge(node, "LINK", pnode))
- end
- rank += 1
- end
- if not text.is_empty then node["text"] = text
- end
- return node
- end
-
- # Build a `NeoNode` representing `mtypepart`.
- private fun mtypepart_node(mtypepart: MTypePart): NeoNode do
- var node = make_node(mtypepart)
- node.labels.add "MTypePart"
- if mtypepart.target != null then
- var target_node = to_node(mtypepart.target.as(not null))
- node.out_edges.add(new NeoEdge(node, "TARGET", target_node))
- end
- return node
- end
-
# Build a new `MType` from a `node`.
#
# REQUIRE `node.labels.has("MType")`
abort
end
- # Build a `NeoNode` representing `mparameter`.
- private fun mparameter_node(mparameter: MParameter): NeoNode do
- var node = make_node(mparameter)
- node.labels.add "MParameter"
- node["name"] = mparameter.name
- node["is_vararg"] = mparameter.is_vararg
- node.out_edges.add(new NeoEdge(node, "TYPE", to_node(mparameter.mtype)))
- return node
- end
-
# Build a new `MParameter` from `node`.
#
# REQUIRE `node.labels.has("MParameter")`
end
end
end
+
+redef class MPackage
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ var root = root
+ if root != null then
+ node.out_edges.add(new NeoEdge(node, "ROOT", root.to_node(nodes, model_name)))
+ end
+ return node
+ end
+end
+
+redef class MGroup
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ var parent = parent
+ node.out_edges.add(new NeoEdge(node, "PROJECT", mpackage.to_node(nodes, model_name)))
+ if parent != null then
+ node.out_edges.add(new NeoEdge(node, "PARENT", parent.to_node(nodes, model_name)))
+ end
+ for mmodule in mmodules do
+ node.out_edges.add(new NeoEdge(node, "DECLARES", mmodule.to_node(nodes, model_name)))
+ end
+ for subgroup in in_nesting.direct_smallers do
+ node.in_edges.add(new NeoEdge(node, "NESTS", subgroup.to_node(nodes, model_name)))
+ end
+ return node
+ end
+end
+
+redef class MModule
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ for parent in in_importation.direct_greaters do
+ node.out_edges.add(new NeoEdge(node, "IMPORTS", parent.to_node(nodes, model_name)))
+ end
+ for mclass in intro_mclasses do
+ node.out_edges.add(new NeoEdge(node, "INTRODUCES", mclass.to_node(nodes, model_name)))
+ end
+ for mclassdef in mclassdefs do
+ node.out_edges.add(new NeoEdge(node, "DEFINES", mclassdef.to_node(nodes, model_name)))
+ end
+ return node
+ end
+end
+
+redef class MClass
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node["kind"] = kind.to_s
+ node["visibility"] = visibility.to_s
+ if not mparameters.is_empty then
+ var parameter_names = new Array[String]
+ for p in mparameters do parameter_names.add(p.name)
+ node["parameter_names"] = new JsonArray.from(parameter_names)
+ end
+ node.out_edges.add(new NeoEdge(node, "CLASSTYPE", mclass_type.to_node(nodes, model_name)))
+ return node
+ end
+end
+
+redef class MClassDef
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node.out_edges.add(new NeoEdge(node, "BOUNDTYPE", bound_mtype.to_node(nodes, model_name)))
+ node.out_edges.add(new NeoEdge(node, "MCLASS", mclass.to_node(nodes, model_name)))
+ for mproperty in intro_mproperties do
+ node.out_edges.add(new NeoEdge(node, "INTRODUCES", mproperty.to_node(nodes, model_name)))
+ end
+ for mpropdef in mpropdefs do
+ node.out_edges.add(new NeoEdge(node, "DECLARES", mpropdef.to_node(nodes, model_name)))
+ end
+ for sup in supertypes do
+ node.out_edges.add(new NeoEdge(node, "INHERITS", sup.to_node(nodes, model_name)))
+ end
+ return node
+ end
+end
+
+redef class MProperty
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = make_node(nodes, model_name)
+ node.labels.add "MProperty"
+ node["visibility"] = visibility.to_s
+ node.out_edges.add(new NeoEdge(node, "INTRO_CLASSDEF", intro_mclassdef.to_node(nodes, model_name)))
+ node.labels.add self.class_name
+ return node
+ end
+end
+
+redef class MMethod
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node["is_init"] = is_init
+ return node
+ end
+end
+
+redef class MInnerClass
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node.out_edges.add(new NeoEdge(node, "NESTS", inner.to_node(nodes, model_name)))
+ return node
+ end
+end
+
+redef class MPropDef
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = make_node(nodes, model_name)
+ node.labels.add "MPropDef"
+ node.out_edges.add(new NeoEdge(node, "DEFINES", mproperty.to_node(nodes, model_name)))
+ node.labels.add self.class_name
+ return node
+ end
+end
+
+redef class MMethodDef
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node["is_abstract"] = is_abstract
+ node["is_intern"] = is_intern
+ node["is_extern"] = is_extern
+ var msignature = msignature
+ if msignature != null then
+ node.out_edges.add(new NeoEdge(node, "SIGNATURE", msignature.to_node(nodes, model_name)))
+ end
+ return node
+ end
+end
+
+redef class MAttributeDef
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ var static_mtype = static_mtype
+ if static_mtype != null then
+ node.out_edges.add(new NeoEdge(node, "TYPE", static_mtype.to_node(nodes, model_name)))
+ end
+ return node
+ end
+end
+
+redef class MVirtualTypeDef
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ var bound = bound
+ if bound != null then
+ node.out_edges.add(new NeoEdge(node, "BOUND", bound.to_node(nodes, model_name)))
+ end
+ return node
+ end
+end
+
+redef class MInnerClassDef
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node.out_edges.add(new NeoEdge(node, "NESTS", inner.to_node(nodes, model_name)))
+ return node
+ end
+end
+
+redef class MTypePart
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ if self.target != null then
+ var target_node = self.target.as(not null).to_node(nodes, model_name)
+ node.out_edges.add(new NeoEdge(node, "TARGET", target_node))
+ end
+ return node
+ end
+end
+
+redef class MParameter
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node["name"] = self.name
+ node["is_vararg"] = self.is_vararg
+ node.out_edges.add(new NeoEdge(node, "TYPE", self.mtype.to_node(nodes, model_name)))
+ return node
+ end
+end
+
+redef class MClassType
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node.labels.add "MClassType"
+ node.out_edges.add(new NeoEdge(node, "CLASS", mclass.to_node(nodes, model_name)))
+ for arg in arguments do
+ node.out_edges.add(new NeoEdge(node, "ARGUMENT", arg.to_node(nodes, model_name)))
+ end
+ return node
+ end
+end
+
+
+redef class MGenericType
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node.labels.add "MGenericType"
+ return node
+ end
+end
+
+redef class MVirtualType
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node.labels.add "MVirtualType"
+ node.out_edges.add(new NeoEdge(node, "PROPERTY", mproperty.to_node(nodes, model_name)))
+ return node
+ end
+end
+
+redef class MParameterType
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node.labels.add "MParameterType"
+ node["rank"] = rank
+ node.out_edges.add(new NeoEdge(node, "CLASS", mclass.to_node(nodes, model_name)))
+ return node
+ end
+end
+
+redef class MNullableType
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node.labels.add "MNullableType"
+ node.out_edges.add(new NeoEdge(node, "TYPE", mtype.to_node(nodes, model_name)))
+ return node
+ end
+end
+
+redef class MSignature
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node.labels.add "MSignature"
+ var names = new JsonArray
+ var rank = 0
+ for mparameter in mparameters do
+ names.add mparameter.name
+ var pnode = mparameter.to_node(nodes, model_name)
+ pnode["rank"] = rank
+ node.out_edges.add(new NeoEdge(node, "PARAMETER", pnode))
+ rank += 1
+ end
+ if not names.is_empty then node["parameter_names"] = names
+ var return_mtype = return_mtype
+ if return_mtype != null then
+ node.out_edges.add(new NeoEdge(node, "RETURNTYPE", return_mtype.to_node(nodes, model_name)))
+ end
+ return node
+ end
+end
+
+redef class MRawType
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = super
+ node.labels.add "MRawType"
+ var text = new JsonArray
+ var rank = 0
+ for part in self.parts do
+ text.add part.text
+ if part.target != null then
+ var pnode = part.to_node(nodes, model_name)
+ pnode["rank"] = rank
+ node.out_edges.add(new NeoEdge(node, "LINK", pnode))
+ end
+ rank += 1
+ end
+ if not text.is_empty then node["text"] = text
+ return node
+ end
+end
+
+redef class MType
+ redef fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = make_node(nodes, model_name)
+ node.labels.add "MType"
+ return node
+ end
+end
+
+redef class MEntity
+ # Build a `NeoNode` representing `self`.
+ private fun to_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ if nodes.has_key(self) then return nodes[self]
+ var node = make_node(nodes, model_name)
+ node.labels.add self.class_name
+ return node
+ end
+
+ # Make a new `NeoNode` based on `mentity`.
+ private fun make_node(nodes: HashMap[MEntity, NeoNode], model_name: nullable String): NeoNode do
+ var node = new NeoNode
+ nodes[self] = node
+ node.labels.add "MEntity"
+ if model_name != null then node.labels.add model_name
+ node["name"] = self.name
+ if not self isa MSignature then
+ #FIXME: MSignature is a MEntity, but has no model :/
+ node["location"] = self.location.to_s
+ end
+ var mdoc = self.mdoc
+ if mdoc != null then
+ node["mdoc"] = new JsonArray.from(mdoc.content)
+ node["mdoc_location"] = mdoc.location.to_s
+ end
+ return node
+ end
+end