-
Notifications
You must be signed in to change notification settings - Fork 35
Description
Mimi currently represents components by a ComponentId
that contains two Symbols, a module name and a component name. This was adequate in our prior implementation, which maintained a global dict of components keyed by this id. The use of the global dictionary defeated module compilation, so we now look for the module name in Main
(unless it's :Mimi
, which we recognize internally as the current Mimi
module.)
This is not a general solution, however, because modules aren't necessarily known in Main
when we need to reference them. Some calls are processed while the module is being defined, so while the Module exists, it's not available in Main
until the definition is complete, which is too late for our purposes.
More generally, a single symbol is inadequate to identify a module. Nested modules can be represented by a module "path", e.g., (:Main, :MimiDICE, :Mimi)
, but the full path isn't findable via Main
until the module (in this example, MimiDICE
) definition is complete.
In the class-based
branch, ComponentId
now includes the path to the module:
struct ComponentId <: MimiStruct
module_path::Union{Nothing, NTuple{N, Symbol} where N}
module_name::Symbol
comp_name::Symbol
end
Internally in @defcomponent
, I pass the Module
instance itself to allow a component to be added, avoiding module lookup:
function find_module(path::NTuple{N, Symbol} where N)
m = Main
for name in path
try
m = getfield(m, name)
catch
error("Module name $name was not found in module $m")
end
end
return m
end
function compdef(comp_id::ComponentId; module_obj::Union{Nothing, Module}=nothing)
if module_obj === nothing
path = @or(comp_id.module_path, (:Main, comp_id.module_name))
module_obj = find_module(path)
end
return getfield(module_obj, comp_id.comp_name)
end
At this point, I'd rather finish testing/debugging the component revisions and not attempt to back-port this stuff to the current branch.