Skip to content

Commit

Permalink
Single julia file implementation for Datatypes and Components
Browse files Browse the repository at this point in the history
  • Loading branch information
Ananya2003Gupta committed Aug 16, 2023
1 parent 2769661 commit 0adcef9
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 138 deletions.
97 changes: 45 additions & 52 deletions python/podio_class_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,30 +107,20 @@ def __init__(self, yamlfile, install_dir, package_name, io_handlers, verbose, dr
def _get_namespace_dict(self):
"""generate the dictionary of parent namespaces"""
namespace = {}
namespace['class'] = DataType(self.package_name.capitalize())
namespace['Components'] = []
namespace['Datatypes'] = []
for component_name in self.datamodel.components.keys():
component = DataType(component_name)
parent_namespace, child = component.namespace, component.bare_type
if parent_namespace not in namespace:
namespace[parent_namespace] = {'Components': [], 'Datatypes': [], 'Collections': []}
namespace[parent_namespace]['Components'].append(child)
namespace['Components'].append(child)

for datatype_name in self.datamodel.datatypes.keys():
datatype = DataType(datatype_name)
parent_namespace, child = datatype.namespace, datatype.bare_type
if parent_namespace not in namespace:
namespace[parent_namespace] = {'Components': [], 'Datatypes': [], 'Collections': []}
namespace[parent_namespace]['Datatypes'].append(child)
namespace[parent_namespace]['Collections'].append(child + 'Collection')

namespace_dict = {}
namespace_dict['class'] = DataType(self.package_name.capitalize())
namespace_dict['children'] = []
for parent, child in namespace.items():
if(parent!=""):
namespace_dict['children'].append({'parent' : parent, 'child' : child})
else:
namespace_dict['children'].append({'parent' : self.package_name, 'child' : child})
self._fill_templates("ParentModule", namespace_dict)
namespace['Datatypes'].append(child)

self._fill_templates("ParentModule", namespace)

def process(self):
"""Run the actual generation"""
Expand Down Expand Up @@ -200,9 +190,7 @@ def get_fn_format(tmpl):
'Obj': 'Obj',
'SIOBlock': 'SIOBlock',
'Collection': 'Collection',
'CollectionData': 'CollectionData',
'MutableStruct': 'Struct',
'JuliaCollection': 'Collection'
'CollectionData': 'CollectionData'
}

return f'{prefix.get(tmpl, "")}{{name}}{postfix.get(tmpl, "")}.{{end}}'
Expand All @@ -211,9 +199,8 @@ def get_fn_format(tmpl):
'Data': ('h',),
'Component': ('h',),
'PrintInfo': ('h',),
'MutableStruct': ('jl',),
'Constructor': ('jl',),
'JuliaCollection': ('jl',),
'ComponentJulia': ('jl',),
'DatatypeJulia': ('jl',),
'ParentModule': ('jl',),
}.get(template_base, ('h', 'cc'))

Expand All @@ -237,23 +224,24 @@ def _fill_templates(self, template_base, data):

def _process_component(self, name, component):
"""Process one component"""
includes, includes_jl = set(), set()
includes, includes_jl, using_jl = set(), set(), set()
includes.update(*(m.includes for m in component['Members']))
includes_jl.update(*(m.jl_imports for m in component['Members']))
for member in component['Members']:
if not (member.is_builtin or member.is_builtin_array):
includes.add(self._build_include(member))
includes_jl.add(self._build_julia_include(member))
file_include, using_include = self._build_julia_include(member)
includes_jl.add(file_include)
using_jl.add(using_include)

includes.update(component.get("ExtraCode", {}).get("includes", "").split('\n'))

component['includes'] = self._sort_includes(includes)
component['includes_jl'] = {'struct': includes_jl, 'constructor': includes_jl}
component['includes_jl'] = {'fileinclude': includes_jl, 'usinginclude': using_jl}
component['class'] = DataType(name)

self._fill_templates('Component', component)
self._fill_templates('MutableStruct', component)
self._fill_templates('Constructor', component)
self._fill_templates('ComponentJulia', component)

def _process_datatype(self, name, definition):
"""Process one datatype"""
Expand All @@ -264,28 +252,31 @@ def _process_datatype(self, name, definition):
self._fill_templates('Obj', datatype)
self._fill_templates('Collection', datatype)
self._fill_templates('CollectionData', datatype)
self._fill_templates('MutableStruct', datatype)
self._fill_templates('Constructor', datatype)
self._fill_templates('JuliaCollection', datatype)
self._fill_templates('DatatypeJulia', datatype)

if 'SIO' in self.io_handlers:
self._fill_templates('SIOBlock', datatype)

def _preprocess_for_julia(self, datatype):
"""Do the preprocessing that is necessary for Julia code generation"""
includes_jl, includes_jl_struct = set(), set()
includes_jl, using_jl = set(), set()
for relation in datatype['OneToManyRelations'] + datatype['OneToOneRelations']:
includes_jl.add(self._build_julia_include(relation, is_struct=True))
file_include, using_include = self._build_julia_include(relation)
includes_jl.add(file_include)
using_jl.add(using_include)
for member in datatype['VectorMembers']:
if not member.is_builtin:
includes_jl_struct.add(self._build_julia_include(member, is_struct=True))
includes_jl.add(self._build_julia_include(member))
file_include, using_include = self._build_julia_include(member)
includes_jl.add(file_include)
using_jl.add(using_include)
try:
includes_jl.remove(self._build_julia_include(datatype['class'], is_struct=True))
file_include, using_include = self._build_julia_include(datatype['class'])
includes_jl.remove(file_include)
using_jl.remove(using_include)
except KeyError:
pass
datatype['includes_jl']['constructor'].update((includes_jl))
datatype['includes_jl']['struct'].update((includes_jl_struct))
datatype['includes_jl']['fileinclude'].update((includes_jl))
datatype['includes_jl']['usinginclude'].update((using_jl))

@staticmethod
def _get_julia_params(datatype):
Expand Down Expand Up @@ -429,8 +420,9 @@ def _preprocess_datatype(self, name, definition):
data = deepcopy(definition)
data['class'] = DataType(name)
data['includes_data'] = self._get_member_includes(definition["Members"])
data['includes_jl'] = {'constructor': self._get_member_includes(definition["Members"], julia=True),
'struct': self._get_member_includes(definition["Members"], julia=True)}
file_include, using_include = self._get_member_includes(definition["Members"], julia=True)
data['includes_jl'] = {'fileinclude': file_include,
'usinginclude': using_include}
data['params_jl'] = self._get_julia_params(data)
self._preprocess_for_class(data)
self._preprocess_for_obj(data)
Expand All @@ -441,7 +433,7 @@ def _preprocess_datatype(self, name, definition):

def _get_member_includes(self, members, julia=False):
"""Process all members and gather the necessary includes"""
includes, includes_jl = set(), set()
includes, includes_jl, using_jl = set(), set(), set()
includes.update(*(m.includes for m in members))
includes_jl.update(*(m.jl_imports for m in members))
for member in members:
Expand All @@ -450,14 +442,18 @@ def _get_member_includes(self, members, julia=False):
if self.upstream_edm and member.array_type in self.upstream_edm.components:
include_from = IncludeFrom.EXTERNAL
includes.add(self._build_include_for_class(member.array_bare_type, include_from))
includes_jl.add(self._build_julia_include_for_class(member.array_bare_type, include_from))
file_include, using_include = self._build_julia_include_for_class(member.array_bare_type, include_from)
includes_jl.add(file_include)
using_jl.add(using_include)

includes.add(self._build_include(member))
includes_jl.add(self._build_julia_include(member))
file_include, using_include = self._build_julia_include(member)
includes_jl.add(file_include)
using_jl.add(using_include)

if not julia:
return self._sort_includes(includes)
return includes_jl
return includes_jl,using_jl

def _write_cmake_lists_file(self):
"""Write the names of all generated header and src files into cmake lists"""
Expand Down Expand Up @@ -527,11 +523,11 @@ def _build_include_for_class(self, classname, include_from: IncludeFrom) -> str:
# the generated code)
return ''

def _build_julia_include(self, member, is_struct=False) -> str:
def _build_julia_include(self, member):
"""Return the include statement for julia"""
return self._build_julia_include_for_class(member.bare_type, self._needs_include(member.full_type), is_struct)
return self._build_julia_include_for_class(member.bare_type, self._needs_include(member.full_type))

def _build_julia_include_for_class(self, classname, include_from: IncludeFrom, is_struct=False) -> str:
def _build_julia_include_for_class(self, classname, include_from: IncludeFrom):
"""Return the include statement for julia for this specific class"""
if include_from == IncludeFrom.INTERNAL:
# If we have an internal include all includes should be relative
Expand All @@ -540,11 +536,8 @@ def _build_julia_include_for_class(self, classname, include_from: IncludeFrom, i
inc_folder = f'{self.upstream_edm.options["includeSubfolder"]}'
if include_from == IncludeFrom.NOWHERE:
# We don't need an include in this case
return ''

if is_struct:
return f'include("{inc_folder}{classname}Struct.jl")'
return f'include("{inc_folder}{classname}.jl")\nusing .{classname}Module: {classname}'
return '',''
return f'include("{inc_folder}{classname}.jl")', f'using ..{classname}Module'

def _sort_includes(self, includes):
"""Sort the includes in order to try to have the std includes at the bottom"""
Expand Down
76 changes: 76 additions & 0 deletions python/templates/ComponentJulia.jl.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{% import "macros/params.jinja2" as params %}
{% for include in includes_jl['fileinclude'] %}
{{ include }}
{% endfor %}

module {{ class.bare_type }}Module
export {{ class.bare_type }}
export {{ class.bare_type }}Struct

{% for include in includes_jl['usinginclude'] %}
{{ include }}
{% endfor %}

mutable struct {{ class.bare_type }}Struct{{ params.julia_parameters(params_jl,"" ,"T" ) }}
{% for member in Members %}
{% if member.is_array or member.is_builtin %}
{{ member.name }}::{{ member.julia_type }}
{% else %}
{{ member.name }}::{{ member.julia_type }}Struct
{% endif %}
{% endfor %}
{% for relation in OneToManyRelations %}
{{ relation.name }}::Vector{ {{ relation.julia_type }}T }
{% endfor %}
{% for relation in OneToOneRelations %}
{{ relation.name }}::Union{Nothing, {{ relation.julia_type }}T }
{% endfor %}
{% for member in VectorMembers %}
{% if member.is_builtin %}
{{ member.name }}::Vector{ {{ member.julia_type }} }
{% else %}
{{ member.name }}::Vector{ {{ member.julia_type }}Struct }
{% endif %}
{% endfor %}
end

function {{ class.bare_type }}(
{% for member in Members %}
{% if member.is_array %}
{{ member.name }}::{{ member.julia_type }} = {{ member.julia_type }}(undef),
{% elif member.is_builtin %}
{{ member.name }}::{{ member.julia_type }} = {{ member.julia_type }}(0),
{% else %}
{{ member.name }}::{{ member.julia_type }}Struct = {{ member.julia_type }}(),
{% endif %}
{% endfor %}
{% for relation in OneToManyRelations %}
{{ relation.name }}::Vector{ {{ relation.julia_type }}Struct } = Vector{ {{ relation.julia_type }}Struct }(),
{% endfor %}
{% for relation in OneToOneRelations %}
{{ relation.name }}::Union{Nothing, {{ relation.julia_type }}Struct } = nothing,
{% endfor %}
{% for member in VectorMembers %}
{% if member.is_builtin %}
{{ member.name }}::Vector{ {{ member.julia_type }} } = Vector{ {{ member.julia_type }} }([]),
{% else %}
{{ member.name }}::Vector{ {{ member.julia_type }}Struct } = Vector{ {{ member.julia_type }}Struct }([]),
{% endif %}
{% endfor %}
)
return {{ class.bare_type }}Struct{{ params.julia_parameters(params_jl, "", "Struct") }}(
{% for member in Members %}
{{ member.name }},
{% endfor %}
{% for relation in OneToManyRelations %}
{{ relation.name }},
{% endfor %}
{% for relation in OneToOneRelations %}
{{ relation.name }},
{% endfor %}
{% for member in VectorMembers %}
{{ member.name }},
{% endfor %}
)
end
end
49 changes: 0 additions & 49 deletions python/templates/Constructor.jl.jinja2

This file was deleted.

Loading

0 comments on commit 0adcef9

Please sign in to comment.