1367 lines
47 KiB
Plaintext
1367 lines
47 KiB
Plaintext
[#ftl]
|
|
[#--
|
|
ChibiOS - Copyright (C) 2006..2023 Giovanni Di Sirio.
|
|
|
|
This file is part of ChibiOS.
|
|
|
|
ChibiOS is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
ChibiOS is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
--]
|
|
|
|
<#--
|
|
-- Global flag for generated code.
|
|
-->
|
|
[#assign generated = false]
|
|
|
|
[#assign class_suffix = "_c"]
|
|
[#assign interface_suffix = "_i"]
|
|
[#assign xmlcache = {}]
|
|
[#assign classescache={}]
|
|
[#assign ifscache={}]
|
|
|
|
[#--
|
|
-- Resets global variables.
|
|
--]
|
|
[#macro ResetState]
|
|
[#assign generated = false]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- Loads an XML file into the XML cache.
|
|
--]
|
|
[#function LoadXML xmlname=""]
|
|
[#attempt]
|
|
[#-- Trying the default path.--]
|
|
[#return pp.loadData("xml", xmlname)]
|
|
[#recover]
|
|
[#list xml.instance.paths.path as path]
|
|
[#attempt]
|
|
[#return pp.loadData("xml", path[0]?ensure_ends_with("/") + xmlname)]
|
|
[#recover]
|
|
[/#attempt]
|
|
[/#list]
|
|
[/#attempt]
|
|
[@pp.dropOutputFile /]
|
|
[#stop ">>>> Importing '" + xmlname + "' failed!"]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Getting references of all module public classes/interfaces.
|
|
--]
|
|
[#macro ImportModulePublicClasses node=[]]
|
|
[#list node.public.types.interface as interface]
|
|
[#assign ifscache = ifscache + {GetNodeName(interface):interface}]
|
|
[/#list]
|
|
[#list node.public.types.class as class]
|
|
[#assign classescache = classescache + {GetNodeName(class):class}]
|
|
[/#list]
|
|
[#list node.imports.import as import]
|
|
[#local xmlname = import?trim]
|
|
[#if xmlcache[xmlname]??]
|
|
[#-- Already in cache, no need to reimport.--]
|
|
[#else]
|
|
[#local xmldoc = LoadXML(xmlname)]
|
|
[@ImportModulePublicClasses node=xmldoc.module /]
|
|
[#assign xmlcache = xmlcache + {xmlname:xmldoc}]
|
|
[/#if]
|
|
[/#list]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- Getting references of all module private classes/interfaces.
|
|
--]
|
|
[#macro ImportModulePrivateClasses node=[]]
|
|
[#list node.public.types.interface as interface]
|
|
[#assign ifscache = ifscache + {GetNodeName(interface):interface}]
|
|
[/#list]
|
|
[#list node.public.types.class as class]
|
|
[#assign classescache = classescache + {GetNodeName(class):class}]
|
|
[/#list]
|
|
[/#macro]
|
|
|
|
[#macro InitModule node=[]]
|
|
[@ccode.ResetState /]
|
|
[@ResetState /]
|
|
[@ImportModulePrivateClasses node=node /]
|
|
[@ImportModulePublicClasses node=node /]
|
|
[#-- ${xmlcache?keys?join(", ")} - ${classescache?keys?join(", ")} - ${ifscache?keys?join(", ")} --]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- Returns the name attribute from an XML node.
|
|
--]
|
|
[#function GetNodeName node=[] default="no-name"]
|
|
[#return (node.@name[0]!default)?trim]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the namespace attribute from an XML node.
|
|
--]
|
|
[#function GetNodeNamespace node=[] default="no-namespace"]
|
|
[#return (node.@namespace[0]!default)?trim]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the ancestorname attribute from an XML node.
|
|
--]
|
|
[#function GetNodeAncestorName node=[] default=""]
|
|
[#return (node.@ancestorname[0]!default)?trim]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the descr attribute from an XML node.
|
|
--]
|
|
[#function GetNodeDescription node=[] default="no-descr"]
|
|
[#return (node.@descr[0]!default)?trim]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the interface C type from an XML node.
|
|
--]
|
|
[#function GetInterfaceCType node=[] default=""]
|
|
[#local if = node]
|
|
[#local ifname = GetNodeName(if default)]
|
|
[#if ifname?length > 0]
|
|
[#local ifctype = ifname + interface_suffix]
|
|
[#else ]
|
|
[#local ifctype = default]
|
|
[/#if]
|
|
[#return ifctype]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the interface ancestor C type from an XML node.
|
|
--]
|
|
[#function GetInterfaceAncestorCType node=[] default=""]
|
|
[#local if = node]
|
|
[#local ancestorname = GetNodeAncestorName(if default)]
|
|
[#if ancestorname?length > 0]
|
|
[#local ancestorctype = ancestorname + interface_suffix]
|
|
[#else ]
|
|
[#local ancestorctype = default]
|
|
[/#if]
|
|
[#return ancestorctype]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the class C type from an XML node.
|
|
--]
|
|
[#function GetClassCType node=[] default=""]
|
|
[#local class = node]
|
|
[#local classname = GetNodeName(class default)]
|
|
[#if classname?length > 0]
|
|
[#local classctype = classname + class_suffix]
|
|
[#else ]
|
|
[#local classctype = default]
|
|
[/#if]
|
|
[#return classctype]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the class ancestor C type from an XML node.
|
|
--]
|
|
[#function GetClassAncestorCType node=[] default=""]
|
|
[#local class = node]
|
|
[#local ancestorname = GetNodeAncestorName(class default)]
|
|
[#if ancestorname?length > 0]
|
|
[#local ancestorctype = ancestorname + class_suffix]
|
|
[#else ]
|
|
[#local ancestorctype = default]
|
|
[/#if]
|
|
[#return ancestorctype]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the class type from an XML node.
|
|
--]
|
|
[#function GetClassType node=[] default="no-type"]
|
|
[#local class = node]
|
|
[#local classtype = (class.@type[0]!default)?trim]
|
|
[#return classtype]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the method short name from an XML node.
|
|
--]
|
|
[#function GetMethodShortName node=[] default=""]
|
|
[#local method = node]
|
|
[#local methodsname = (method.@shortname[0]!default)?trim]
|
|
[#if methodsname?length == 0]
|
|
[#local methodsname = GetNodeName(method default)?lower_case]
|
|
[/#if]
|
|
[#return methodsname]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the method return C type from an XML node.
|
|
--]
|
|
[#function GetMethodCType node=[] default="void"]
|
|
[#local method = node]
|
|
[#local methodctype = (method.@ctype[0]!default)?trim]
|
|
[#return methodctype]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the method short name from an XML node.
|
|
--]
|
|
[#function GetObjinitCallsuper node=[] default="true"]
|
|
[#return (node.@callsuper[0]!default)?trim]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Get class by name.
|
|
--]
|
|
[#function GetClassByName classname=""]
|
|
[#if classescache[classname]??]
|
|
[#return classescache[classname]]
|
|
[/#if]
|
|
[#stop ">>>> Unknown class '" + classname + "'"]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Get interface by name.
|
|
--]
|
|
[#function GetInterfaceByName ifname=""]
|
|
[#if ifscache[ifname]??]
|
|
[#return ifscache[ifname]]
|
|
[/#if]
|
|
[#stop ">>>> Unknown interface '" + ifname + "'"]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the ancestor of the specified class.
|
|
--]
|
|
[#function GetAncestorClass class=[]]
|
|
[#local ancestorname = GetNodeAncestorName(class)]
|
|
[#if classescache[ancestorname]??]
|
|
[#return classescache[ancestorname]]
|
|
[/#if]
|
|
[#stop ">>>> Unknown class '" + ancestorname + "'"]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns a sequence of class ancestors classes from an XML node.
|
|
--]
|
|
[#function GetClassAncestorsSequence class=[]]
|
|
[#local ancestorname = GetNodeAncestorName(class)]
|
|
[#if ancestorname?length == 0]
|
|
[#return []]
|
|
[/#if]
|
|
[#if classescache[ancestorname]??]
|
|
[#local ancestorclass = classescache[ancestorname]]
|
|
[#return GetClassAncestorsSequence(ancestorclass) + [ancestorclass]]
|
|
[/#if]
|
|
[#stop ">>>> Unknown class '" + ancestorname + "'"]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns a sequence of class virtual methods, including those from
|
|
-- ancestors.
|
|
--]
|
|
[#function GetClassVirtualMethodsSequence node=[]]
|
|
[#local classes = GetClassAncestorsSequence(node) + [node]]
|
|
[#local methods = []]
|
|
[#list classes as class]
|
|
[#list class.methods.virtual.method as method]
|
|
[#local methods = methods + method]
|
|
[/#list]
|
|
[/#list]
|
|
[#return methods]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns a sequence of interface ancestors interfaces from an XML node.
|
|
--]
|
|
[#function GetInterfaceAncestorsSequence if=[]]
|
|
[#local ancestorname = GetNodeAncestorName(if)]
|
|
[#if ancestorname?length == 0]
|
|
[#return []]
|
|
[/#if]
|
|
[#if ifscache[ancestorname]??]
|
|
[#local ancestorif = ifscache[ancestorname]]
|
|
[#return GetInterfaceAncestorsSequence(ancestorif) + [ancestorif]]
|
|
[/#if]
|
|
[#stop ">>>> Unknown interface '" + ancestorname + "'"]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns a sequence of interface methods, including those from
|
|
-- ancestors.
|
|
--]
|
|
[#function GetInterfaceMethodsSequence node=[]]
|
|
[#local ifs = GetInterfaceAncestorsSequence(node) + [node]]
|
|
[#local methods = []]
|
|
[#list ifs as if]
|
|
[#list if.methods.method as method]
|
|
[#local methods = methods + method]
|
|
[/#list]
|
|
[/#list]
|
|
[#return methods]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns a sequence of class ancestors CTypes.
|
|
--]
|
|
[#function GetClassAncestorsCTypes ancestors=[]]
|
|
[#local names = []]
|
|
[#list ancestors as ancestor]
|
|
[#local names = names + [GetClassCType(ancestor)]]
|
|
[/#list]
|
|
[#return names]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns a sequence of interface ancestors CTypes.
|
|
--]
|
|
[#function GetInterfaceAncestorsCTypes ancestors=[]]
|
|
[#local names = []]
|
|
[#list ancestors as ancestor]
|
|
[#local names = names + [GetInterfaceCType(ancestor)]]
|
|
[/#list]
|
|
[#return names]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the closest method implementation name searching in the specified
|
|
-- set of classes.
|
|
--]
|
|
[#function GetMethodNearestImplementation classes=[] method=[]]
|
|
[#local shortname = GetMethodShortName(method)]
|
|
[#list classes?reverse as class]
|
|
[#local classname = GetNodeName(class)
|
|
classnamespace = GetNodeNamespace(class)]
|
|
[#-- The dispose method is a special clase, it is always generated for
|
|
each class so picking the current class one. --]
|
|
[#if shortname == "dispose"]
|
|
[#return "__" + classnamespace + "_" + shortname + "_impl"]
|
|
[/#if]
|
|
[#-- First checking among the current class overrides.--]
|
|
[#local m = class["methods/override/method[@shortname='" + shortname + "']"]]
|
|
[#if m[0]??]
|
|
[#return "__" + classnamespace + "_" + shortname + "_impl"]
|
|
[/#if]
|
|
[#-- Checking if we reached the class where the method was declared.--]
|
|
[#local m = class["methods/virtual/method[@shortname='" + shortname + "']"]]
|
|
[#if m[0]??]
|
|
[#-- If the methods has an original implementation then returning it
|
|
else we return NULL but the system has to generate an error
|
|
because the method has no implementation in any ancestor.--]
|
|
[#if m.implementation[0]??]
|
|
[#return "__" + classnamespace + "_" + shortname + "_impl"]
|
|
[#else]
|
|
[#return "NULL /* Method not found.*/"]
|
|
[/#if]
|
|
[/#if]
|
|
[/#list]
|
|
[#return "NULL"]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- Returns the class in the sequence of ancestors owning the specified
|
|
-- virtual method. Fails if the method is not defined anywere in the
|
|
-- sequence.
|
|
--]
|
|
[#function GetVirtualMethodOwnerClass ancestors=[] shortname=""]
|
|
[#list ancestors as ancestor]
|
|
[#local m = ancestor["methods/virtual/method[@shortname='" + shortname + "']"]]
|
|
[#if m[0]??]
|
|
[#return [ancestor, m]]
|
|
[/#if]]
|
|
[/#list]
|
|
[#stop ">>>> Undefined method '" + shortname + "'"]
|
|
[/#function]
|
|
|
|
[#--
|
|
-- This macro generates a class wrapper from an XML node.
|
|
--]
|
|
[#macro GenerateClass node=[]]
|
|
[#local class = node]
|
|
[#local classname = GetNodeName(class)
|
|
classnamespace = GetNodeNamespace(class)
|
|
classctype = GetClassCType(class)
|
|
classdescr = GetNodeDescription(class)
|
|
ancestorname = GetNodeAncestorName(class, "")]
|
|
[#local ancestors = GetClassAncestorsSequence(class)]
|
|
/**
|
|
[@doxygen.EmitTagVerbatim indent="" tag="class" text=classctype /]
|
|
[#if ancestorname?length > 0]
|
|
[#local ancestorsctypes = GetClassAncestorsCTypes(ancestors)]
|
|
[@doxygen.EmitTagFormattedNoCap indent="" tag="extends"
|
|
text=ancestorsctypes?join(", ") /]
|
|
[/#if]
|
|
[@GenerateClassImplementsTags class.implements /]
|
|
*
|
|
[@doxygen.EmitBriefFromNode node=class /]
|
|
[@doxygen.EmitDetailsFromNode node=class /]
|
|
[@doxygen.EmitPreFromNode node=class /]
|
|
[@doxygen.EmitPostFromNode node=class /]
|
|
[@doxygen.EmitNoteFromNode node=class /]
|
|
*
|
|
[@doxygen.EmitTagVerbatim indent="" tag="name" text="Class @p " + classctype + " structures"/]
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
[@doxygen.EmitBrief "" "Type of a " + classdescr + " class." /]
|
|
*/
|
|
typedef struct ${classname} ${classctype};
|
|
|
|
/**
|
|
[@doxygen.EmitBrief "" "Class @p " + classctype + " virtual methods table." /]
|
|
*/
|
|
struct ${classname?lower_case}_vmt {
|
|
[#list ancestors as ancestor]
|
|
[@ccode.Indent 1 /]/* From ${GetClassCType(ancestor)}.*/
|
|
[@GenerateVMTPointers ancestor.methods.virtual /]
|
|
[/#list]
|
|
[@ccode.Indent 1 /]/* From ${classctype}.*/
|
|
[@GenerateVMTPointers class.methods.virtual /]
|
|
};
|
|
|
|
/**
|
|
[@doxygen.EmitBrief "" "Structure representing a " + classdescr + " class." /]
|
|
*/
|
|
struct ${classname?lower_case} {
|
|
[@ccode.Indent 1 /]/**
|
|
[@doxygen.EmitBrief ccode.indentation "Virtual Methods Table." /]
|
|
[@ccode.Indent 1 /] */
|
|
[#local vmtctype = "const struct " + classname?lower_case + "_vmt$I*$N"]
|
|
${ccode.MakeVariableDeclaration(ccode.indentation "vmt" vmtctype)}
|
|
[#list ancestors as ancestor]
|
|
[@GenerateClassInterfaceFields node = ancestor.implements /]
|
|
[@ccode.GenerateStructureFieldsFromNode indent = ccode.indentation
|
|
fields = ancestor.fields /]
|
|
[/#list]
|
|
[@GenerateClassInterfaceFields node = class.implements /]
|
|
[@ccode.GenerateStructureFieldsFromNode indent = ccode.indentation
|
|
fields = class.fields /]
|
|
};
|
|
/** @} */
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates an interface wrapper from an XML node.
|
|
--]
|
|
[#macro GenerateInterface node=[]]
|
|
[#local if = node]
|
|
[#local ifname = GetNodeName(if)
|
|
ifnamespace = GetNodeNamespace(if)
|
|
ifctype = GetInterfaceCType(if)
|
|
ifdescr = GetNodeDescription(if)
|
|
ancestorname = GetNodeAncestorName(if, "")]
|
|
[#local ancestors = GetInterfaceAncestorsSequence(if)]
|
|
/**
|
|
* @interface ${ifctype}
|
|
[#if ancestorname?length > 0]
|
|
[#local ancestorsctypes = GetInterfaceAncestorsCTypes(ancestors)]
|
|
[@doxygen.EmitTagFormattedNoCap indent="" tag="extends"
|
|
text=ancestorsctypes?join(", ") /]
|
|
[/#if]
|
|
*
|
|
[@doxygen.EmitBriefFromNode node=if /]
|
|
[@doxygen.EmitDetailsFromNode node=if /]
|
|
[@doxygen.EmitPreFromNode node=if /]
|
|
[@doxygen.EmitPostFromNode node=if /]
|
|
[@doxygen.EmitNoteFromNode node=if /]
|
|
*
|
|
[@doxygen.EmitTagVerbatim indent="" tag="name" text="Interface @p " + ifctype + " structures"/]
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
[@doxygen.EmitBrief "" "Type of a " + ifdescr + " interface." /]
|
|
*/
|
|
typedef struct ${ifname} ${ifctype};
|
|
|
|
/**
|
|
[@doxygen.EmitBrief "" "Interface @p " + ifctype + " virtual methods table." /]
|
|
*/
|
|
struct ${ifname?lower_case}_vmt {
|
|
${(ccode.indentation + "/* Memory offset between this interface structure and begin of")}
|
|
${(ccode.indentation + " the implementing class structure.*/")}
|
|
${(ccode.indentation + "size_t instance_offset;")}
|
|
[#list ancestors as ancestor]
|
|
[@ccode.Indent 1 /]/* From ${GetInterfaceCType(ancestor)}.*/
|
|
[@GenerateVMTPointers ancestor.methods /]
|
|
[/#list]
|
|
[@ccode.Indent 1 /]/* From ${ifctype}.*/
|
|
[@GenerateVMTPointers if.methods /]
|
|
};
|
|
|
|
/**
|
|
[@doxygen.EmitBrief "" "Structure representing a " + ifdescr + " interface." /]
|
|
*/
|
|
struct ${ifname?lower_case} {
|
|
[@ccode.Indent 1 /]/**
|
|
[@doxygen.EmitBrief ccode.indentation "Virtual Methods Table." /]
|
|
[@ccode.Indent 1 /] */
|
|
[#local vmtctype = "const struct " + ifname?lower_case + "_vmt$I*$N"]
|
|
${ccode.MakeVariableDeclaration(ccode.indentation "vmt" vmtctype)}
|
|
};
|
|
/** @} */
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- Generates implementation functions for constructor, destructor,
|
|
-- overidden virtual methods and virtual methods.
|
|
--]
|
|
[#macro GenerateClassImplementations node=[] modifiers=[]]
|
|
[#local class = node]
|
|
[#local classname = GetNodeName(class)
|
|
classnamespace = GetNodeNamespace(class)
|
|
classctype = GetClassCType(class)
|
|
classdescr = GetNodeDescription(class)
|
|
ancestorname = GetNodeAncestorName(class, "")]
|
|
[#assign generated = true]
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "name" "Methods implementations of " + classctype /]
|
|
* @{
|
|
*/
|
|
[#-- Constructor.--]
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "memberof" classctype /]
|
|
* @protected
|
|
*
|
|
[@doxygen.EmitBrief "" "Implementation of object creation." /]
|
|
[@doxygen.EmitNote "" "This function is meant to be used by derived classes." /]
|
|
*
|
|
[@doxygen.EmitParam name="ip" dir="out"
|
|
text="Pointer to a @p " + classctype + " instance to be initialized." /]
|
|
[@doxygen.EmitParam name="vmt" dir="in"
|
|
text="VMT pointer for the new object." /]
|
|
[@doxygen.EmitParamFromNode node = class.methods.objinit[0] /]
|
|
[@doxygen.EmitReturn text="A new reference to the object." /]
|
|
*/
|
|
[@ccode.GeneratePrototypeFromNode indent = ""
|
|
name = "__" + classnamespace + "_objinit_impl"
|
|
ctype = "void *"
|
|
modifiers = modifiers
|
|
params = ["void *ip", "const void *vmt"]
|
|
node = class.methods.objinit[0] /] {
|
|
[@ccode.Indent 1 /]${classctype} *self = (${classctype} *)ip;
|
|
|
|
[#if ancestorname?length == 0]
|
|
[@ccode.Indent 1 /]/* This is a root class, initializing the VMT pointer here.*/
|
|
[@ccode.Indent 1 /]self->vmt = (struct base_object_vmt *)vmt;
|
|
|
|
[#else]
|
|
[#local ancestor = GetAncestorClass(class)]
|
|
[#if GetObjinitCallsuper(class.methods.objinit[0]) == "true"]
|
|
[@ccode.Indent 1 /]/* Initialization of the ancestors-defined parts.*/
|
|
[@ccode.GenerateFunctionCall indent = ccode.indentation
|
|
destination = ""
|
|
name = "__" + GetNodeNamespace(ancestor) + "_objinit_impl"
|
|
params = ["self", "vmt"] /]
|
|
|
|
[/#if]
|
|
[/#if]
|
|
[#if class.implements.*?size > 0]
|
|
[@GenerateClassInterfacesInit node = class.implements
|
|
classctype = classctype
|
|
classnamespace = classnamespace /]
|
|
[/#if]
|
|
[#if (class.methods.objinit[0].implementation[0])?? &&
|
|
(class.methods.objinit[0].implementation[0]?trim?length > 0)]
|
|
[@ccode.Indent 1 /]/* Initialization code.*/
|
|
[@ccode.GenerateIndentedCCode indent=ccode.indentation
|
|
ccode=class.methods.objinit[0].implementation[0]?string /]
|
|
[#else]
|
|
[@ccode.Indent 1 /]/* No initialization code.*/
|
|
[/#if]
|
|
|
|
[@ccode.Indent 1 /]return self;
|
|
}
|
|
|
|
[#-- Destructor.--]
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "memberof" classctype /]
|
|
* @protected
|
|
*
|
|
[@doxygen.EmitBrief "" "Implementation of object finalization." /]
|
|
[@doxygen.EmitNote "" "This function is meant to be used by derived classes." /]
|
|
*
|
|
[@doxygen.EmitParam name="ip" dir="both"
|
|
text="Pointer to a @p " + classctype + " instance to be disposed." /]
|
|
*/
|
|
[@ccode.GeneratePrototype indent = ""
|
|
name = "__" + classnamespace + "_dispose_impl"
|
|
ctype = "void"
|
|
modifiers = modifiers
|
|
params = ["void *ip"] /] {
|
|
[@ccode.Indent 1 /]${classctype} *self = (${classctype} *)ip;
|
|
|
|
[#if (class.methods.dispose[0].implementation[0])?? &&
|
|
(class.methods.dispose[0].implementation[0]?trim?length > 0)]
|
|
[@ccode.Indent 1 /]/* Finalization code.*/
|
|
[@ccode.GenerateIndentedCCode indent=ccode.indentation
|
|
ccode=class.methods.dispose[0].implementation[0]?string /]
|
|
[#else]
|
|
[@ccode.Indent 1 /]/* No finalization code.*/
|
|
[@ccode.Indent 1 /](void)self;
|
|
[/#if]
|
|
[#if ancestorname?length > 0]
|
|
[#local ancestor = GetAncestorClass(class)]
|
|
|
|
[@ccode.Indent 1 /]/* Finalization of the ancestors-defined parts.*/
|
|
[@ccode.Indent 1 /]__${GetNodeNamespace(ancestor)}_dispose_impl(self);
|
|
[/#if]
|
|
}
|
|
[#-- Scanning for al method overrides defined in the current class then
|
|
checking in which class the virtual method is defined.--]
|
|
[#local ancestors = GetClassAncestorsSequence(class)]
|
|
[#list class.methods.override.method as method]
|
|
[#local shortname = GetMethodShortName(method)]
|
|
[#local found = GetVirtualMethodOwnerClass(ancestors, shortname)]
|
|
[#local ancestorclass = found[0]]
|
|
[#local ancestormethod = found[1]]
|
|
[#local methodname = GetNodeName(ancestormethod)
|
|
methodsname = GetMethodShortName(ancestormethod)
|
|
methodretctype = GetMethodCType(ancestormethod)
|
|
methodimpl = method.implementation[0]!""]
|
|
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "memberof" classctype /]
|
|
* @protected
|
|
*
|
|
[@doxygen.EmitBrief "" "Override of method @p " + methodname + "()." /]
|
|
*
|
|
[@doxygen.EmitParam name="ip" dir="both"
|
|
text="Pointer to a @p " + classctype + " instance." /]
|
|
[@doxygen.EmitParamFromNode node=ancestormethod /]
|
|
[@doxygen.EmitReturnFromNode node=ancestormethod /]
|
|
*/
|
|
[@ccode.GeneratePrototypeFromNode indent = ""
|
|
name = "__" + classnamespace + "_" + methodsname + "_impl"
|
|
modifiers = modifiers
|
|
params = ["void *ip"]
|
|
node = ancestormethod /] {
|
|
[@ccode.Indent 1 /]${classctype} *self = (${classctype} *)ip;
|
|
[@ccode.GenerateIndentedCCode indent = ccode.indentation
|
|
ccode = methodimpl /]
|
|
}
|
|
[/#list]
|
|
[#-- Scanning for all virtual methods defined in the current class.--]
|
|
[#list class.methods.virtual.method as method]
|
|
[#local methodname = GetNodeName(method)
|
|
methodsname = GetMethodShortName(method)
|
|
methodretctype = GetMethodCType(method)
|
|
methodimpl = method.implementation[0]!""]
|
|
[#if methodimpl?length > 0]
|
|
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "memberof" classctype /]
|
|
* @protected
|
|
*
|
|
[@doxygen.EmitBrief "" "Implementation of method @p " + methodname + "()." /]
|
|
[@doxygen.EmitNote "" "This function is meant to be used by derived classes." /]
|
|
*
|
|
[@doxygen.EmitParam name="ip" dir="both"
|
|
text="Pointer to a @p " + classctype + " instance." /]
|
|
[@doxygen.EmitParamFromNode node=method /]
|
|
[@doxygen.EmitReturnFromNode node=method /]
|
|
*/
|
|
[@ccode.GeneratePrototypeFromNode indent = ""
|
|
name = "__" + classnamespace + "_" + methodsname + "_impl"
|
|
modifiers = modifiers
|
|
params = ["void *ip"]
|
|
node = method /] {
|
|
[@ccode.Indent 1 /]${classctype} *self = (${classctype} *)ip;
|
|
[@ccode.GenerateIndentedCCode indent = ccode.indentation
|
|
ccode = methodimpl /]
|
|
}
|
|
[/#if]
|
|
[/#list]
|
|
/** @} */
|
|
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates regular methods from an XML node.
|
|
--]
|
|
[#macro GenerateMethods node=[] classctype="no-ctype" modifiers=[] nodoc=false]
|
|
[#list node.* as this]
|
|
[#if this?node_name == "method"]
|
|
[#local method = this]
|
|
[#local methodname = GetNodeName(method)
|
|
methodsname = GetMethodShortName(method)
|
|
methodretctype = GetMethodCType(method)
|
|
methodimpl = method.implementation[0]!""]
|
|
[#assign generated = true]
|
|
[#if !nodoc]
|
|
[@doxygen.EmitFullCommentFromNode indent="" node=method
|
|
extraname="ip" extradir="both"
|
|
extratext="Pointer to a @p " + classctype + " instance."
|
|
memberof=classctype /]
|
|
[/#if]
|
|
[#if modifiers?seq_contains("static") && modifiers?seq_contains("inline")]
|
|
CC_FORCE_INLINE
|
|
[/#if]
|
|
[@ccode.GeneratePrototypeFromNode modifiers = modifiers
|
|
params = ["void *ip"]
|
|
node = method /] {
|
|
${classctype} *self = (${classctype} *)ip;
|
|
[@ccode.GenerateIndentedCCode indent=ccode.indentation
|
|
ccode=methodimpl /]
|
|
}
|
|
[#if this?has_next]
|
|
|
|
[/#if]
|
|
[#elseif this?node_name == "condition"]
|
|
[#local condition = this]
|
|
[#local condcheck = (condition.@check[0]!"1")?trim]
|
|
#if (${condcheck}) || defined (__DOXYGEN__)
|
|
[@GenerateMethods node = condition
|
|
classctype = classctype
|
|
modifiers = modifiers
|
|
nodoc = nodoc /]
|
|
#endif /* ${condcheck} */
|
|
[#if this?has_next]
|
|
|
|
[/#if]
|
|
[#elseif this?node_name == "elseif"]
|
|
[#local nodoc = true]
|
|
[#local condcheck = (this.@check[0]!"")?trim]
|
|
[#if condcheck?length == 0]
|
|
#else
|
|
|
|
[#else]
|
|
#elif ${condcheck}
|
|
[/#if]
|
|
[/#if]
|
|
[/#list]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates regular methods from an XML node.
|
|
--]
|
|
[#macro GenerateClassRegularMethods node=[] modifiers=[]]
|
|
[#local class = node]
|
|
[#if class.methods.regular.*?size > 0]
|
|
[#local classctype = GetClassCType(class)]
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "name" "Regular methods of " + classctype /]
|
|
* @{
|
|
*/
|
|
[@GenerateMethods node = class.methods.regular
|
|
classctype = classctype
|
|
modifiers = [] /]
|
|
/** @} */
|
|
|
|
[/#if]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates inline methods from an XML node.
|
|
--]
|
|
[#macro GenerateClassInlineMethods node=[]]
|
|
[#local class = node]
|
|
[#if class.methods.inline.*?size > 0]
|
|
[#local classctype = GetClassCType(class)]
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "name" "Inline methods of " + classctype /]
|
|
* @{
|
|
*/
|
|
[@GenerateMethods node = class.methods.inline
|
|
classctype = classctype
|
|
modifiers = ["static", "inline"] /]
|
|
/** @} */
|
|
|
|
[/#if]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates virtual methods as inline functions
|
|
-- from an XML node.
|
|
--]
|
|
[#macro GenerateVirtualMethods methods=[] ctype="no-ctype" namespace="no-namespace"]
|
|
[#if methods.method?size > 0]
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "name" "Virtual methods of " + ctype /]
|
|
* @{
|
|
*/
|
|
[#list methods.method as method]
|
|
[#local methodsname = GetMethodShortName(method)
|
|
methodretctype = GetMethodCType(method) /]
|
|
[@doxygen.EmitFullCommentFromNode indent="" node=method
|
|
extraname="ip" extradir="both"
|
|
extratext="Pointer to a @p " + ctype + " instance."
|
|
memberof=ctype /]
|
|
CC_FORCE_INLINE
|
|
[@ccode.GeneratePrototypeFromNode modifiers = ["static", "inline"]
|
|
params = ["void *ip"]
|
|
node=method /] {
|
|
[@ccode.Indent 1 /]${ctype} *self = (${ctype} *)ip;
|
|
|
|
[#local callname = "self->vmt->" [#-- + namespace + "."--] + methodsname]
|
|
[#local callparams = ccode.MakeCallParamsSequence(["ip"] method)]
|
|
[#if methodretctype == "void"]
|
|
[@ccode.GenerateFunctionCall ccode.indentation "" callname callparams /]
|
|
[#else]
|
|
[@ccode.GenerateFunctionCall ccode.indentation "return " callname callparams /]
|
|
[/#if]
|
|
}
|
|
[#if method?has_next]
|
|
|
|
[/#if]
|
|
[/#list]
|
|
/** @} */
|
|
|
|
[/#if]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates class virtual methods as inline functions
|
|
-- from an XML node.
|
|
--]
|
|
[#macro GenerateClassVirtualMethods node=[]]
|
|
[#local class = node]
|
|
[#local classnamespace = GetNodeNamespace(class)
|
|
classctype = GetClassCType(class) /]
|
|
[@GenerateVirtualMethods methods = class.methods.virtual
|
|
ctype = classctype
|
|
namespace = classnamespace /]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- Generates extern prototypes for constructor, destructor, overidden
|
|
-- virtual methods, virtual methods and regular methods.
|
|
--]
|
|
[#macro GenerateClassPrototypes node=[]]
|
|
[#local class = node]
|
|
[#local classname = GetNodeName(class)
|
|
classnamespace = GetNodeNamespace(class)]
|
|
[#-- Constructor.--]
|
|
[@ccode.GeneratePrototypeFromNode indent = ccode.indentation
|
|
name = "__" + classnamespace + "_objinit_impl"
|
|
ctype = "void *"
|
|
modifiers = []
|
|
params = ["void *ip", "const void *vmt"]
|
|
node = class.methods.objinit[0] /];
|
|
[#-- Destructor.--]
|
|
[@ccode.GeneratePrototype indent = ccode.indentation
|
|
name = "__" + classnamespace + "_dispose_impl"
|
|
ctype = "void"
|
|
modifiers = []
|
|
params = ["void *ip"] /];
|
|
[#-- Scanning for al method overrides defined in the current class then
|
|
checking in which class the virtual method is defined.--]
|
|
[#local ancestors = GetClassAncestorsSequence(class)]
|
|
[#list class.methods.override.method as method]
|
|
[#local shortname = GetMethodShortName(method)]
|
|
[#local found = GetVirtualMethodOwnerClass(ancestors, shortname)]
|
|
[#local ancestorclass = found[0]]
|
|
[#local ancestormethod = found[1]]
|
|
[#local methodname = GetNodeName(ancestormethod)
|
|
methodsname = GetMethodShortName(ancestormethod)
|
|
methodretctype = GetMethodCType(ancestormethod)
|
|
methodimpl = method.implementation[0]!""]
|
|
[@ccode.GeneratePrototypeFromNode indent = ccode.indentation
|
|
name = "__" + classnamespace + "_" + methodsname + "_impl"
|
|
modifiers = []
|
|
params = ["void *ip"]
|
|
node = ancestormethod /];
|
|
[/#list]
|
|
[#-- Scanning for all virtual methods defined in the current class.--]
|
|
[#list class.methods.virtual.method as method]
|
|
[#local methodname = GetNodeName(method)
|
|
methodsname = GetMethodShortName(method)
|
|
methodretctype = GetMethodCType(method)
|
|
methodimpl = method.implementation[0]!"" /]
|
|
[#if methodimpl?length > 0]
|
|
[@ccode.GeneratePrototypeFromNode indent = ccode.indentation
|
|
name = "__" + classnamespace + "_" + methodsname + "_impl"
|
|
modifiers = []
|
|
params = ["void *ip"]
|
|
node = method /];
|
|
[/#if]
|
|
[/#list]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates regular method prototypes from an XML node.
|
|
--]
|
|
[#macro GenerateClassRegularMethodsPrototypes node=[]]
|
|
[#list node.* as this]
|
|
[#if this?node_name == "method"]
|
|
[#local method = this]
|
|
[#local methodname = GetNodeName(method)
|
|
methodsname = GetMethodShortName(method)
|
|
methodretctype = GetMethodCType(method)]
|
|
[@ccode.GeneratePrototypeFromNode indent = ccode.indentation
|
|
modifiers = []
|
|
params = ["void *ip"]
|
|
node=method /];
|
|
[#elseif this?node_name == "condition"]
|
|
[#local condition = this]
|
|
[#local condcheck = (condition.@check[0]!"1")?trim]
|
|
#if (${condcheck}) || defined (__DOXYGEN__)
|
|
[@GenerateClassRegularMethodsPrototypes node=condition /]
|
|
#endif /* ${condcheck} */
|
|
[/#if]
|
|
[/#list]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates regular method prototypes from a class XML node.
|
|
--]
|
|
[#macro GenerateClassMethodsPrototypes class=[]]
|
|
[#local classctype = GetClassCType(class)]
|
|
[@ccode.Indent 1 /]/* Methods of ${classctype}.*/
|
|
[@GenerateClassPrototypes node=class /]
|
|
[@GenerateClassRegularMethodsPrototypes node=class.methods.regular /]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates virtual methods pointers from a sequence of XML nodes.
|
|
--]
|
|
[#macro GenerateVMTPointers methods=[] ipctype="void *"]
|
|
[#list methods.method as method]
|
|
[#local methodsname = GetMethodShortName(method)
|
|
methodretctype = GetMethodCType(method) /]
|
|
[#local funcptr = ccode.indentation + methodretctype + " (*" + methodsname + ")(" +
|
|
ccode.MakeProtoParamsSequence([ipctype + "ip"], method)?join(", ") +
|
|
");" /]
|
|
${funcptr}
|
|
[/#list]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates a class VMT structure from an XML node.
|
|
--]
|
|
[#macro GenerateClassVMT node=[] modifiers=[]]
|
|
[#local classname = GetNodeName(node)
|
|
classnamespace = GetNodeNamespace(node)
|
|
classtype = GetClassType(node)
|
|
classctype = GetClassCType(node)
|
|
classdescr = GetNodeDescription(node) /]
|
|
[#if classtype == "regular"]
|
|
[#assign generated = true]
|
|
/**
|
|
[@doxygen.EmitBrief "" "VMT structure of " + classdescr + " class." /]
|
|
[@doxygen.EmitNote "" "It is public because accessed by the inlined constructor." /]
|
|
*/
|
|
[#if modifiers?size > 0]
|
|
${modifiers?join(" ") + " "}[#rt]
|
|
[/#if]
|
|
const struct ${classname}_vmt __${classname}_vmt = {
|
|
[#local classes = GetClassAncestorsSequence(node) + [node]]
|
|
[#local methods = GetClassVirtualMethodsSequence(node)]
|
|
[#list methods as method]
|
|
[#local methodimpl = GetMethodNearestImplementation(classes, method)]
|
|
[#local s = (ccode.indentation + "." +
|
|
GetMethodShortName(method))?right_pad(ccode.initializers_align) +
|
|
"= " + methodimpl]
|
|
[#if method?has_next]
|
|
${s},
|
|
[#else]
|
|
${s}
|
|
[/#if]
|
|
[/#list]
|
|
};
|
|
|
|
[/#if]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates class method implementations from an XML node.
|
|
--]
|
|
[#macro GenerateClassInterfacesInit node=[] classctype="no-ctype" classnamespace="no-namespace"]
|
|
[#list node.* as this]
|
|
[#if this?node_name == "if"]
|
|
[#local ifname = GetNodeName(this)]
|
|
[#local if = GetInterfaceByName(ifname)]
|
|
[#local ifnamespace = GetNodeNamespace(if)
|
|
ifctype = GetInterfaceCType(if) /]
|
|
[@ccode.Indent 1 /]/* Initialization of interface ${ifctype}.*/
|
|
[@ccode.Indent 1 /]{
|
|
[@ccode.Indent 2 /]static const struct ${ifname}_vmt ${classnamespace}_${ifnamespace}_vmt = {
|
|
[#local s = (ccode.indentation + ccode.indentation + ccode.indentation +
|
|
".instance_offset")?right_pad(ccode.initializers_align) + "= " +
|
|
"offsetof(" + classctype + ", " + ifnamespace + ")"]
|
|
${s},
|
|
[#local methods = GetInterfaceMethodsSequence(if)]
|
|
[#list methods as method]
|
|
[#local methodshortname = GetMethodShortName(method)]
|
|
[#local s = (ccode.indentation + ccode.indentation + ccode.indentation + "." +
|
|
methodshortname)?right_pad(ccode.initializers_align) + "= "]
|
|
[#local ifmethod = this["method[@shortname='" + methodshortname + "']"]]
|
|
[#if ifmethod[0]??]
|
|
[#local s = s + "__" + classnamespace + "_" + ifnamespace + "_" +
|
|
methodshortname + "_impl"]
|
|
[#else]
|
|
[#local s = s + "NULL /* Missing implementation.*/"]
|
|
[/#if]
|
|
[#if method?has_next]
|
|
${s},
|
|
[#else]
|
|
${s}
|
|
[/#if]
|
|
[/#list]
|
|
[@ccode.Indent 2 /]};
|
|
[@ccode.Indent 2 /]oopIfObjectInit(&self->${ifnamespace}, &${classnamespace}_${ifnamespace}_vmt);
|
|
[@ccode.Indent 1 /]}
|
|
[#if node?node_name != "condition"]
|
|
|
|
[/#if]
|
|
[#elseif this?node_name == "condition"]
|
|
[#local condcheck = (this.@check[0]!"1")?trim]
|
|
#if (${condcheck}) || defined (__DOXYGEN__)
|
|
[@GenerateClassInterfacesInit node=this
|
|
classctype=classctype
|
|
classnamespace=classnamespace /]
|
|
#endif /* ${condcheck} */
|
|
|
|
[/#if]
|
|
[/#list]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates class interface fields from an XML node.
|
|
--]
|
|
[#macro GenerateClassInterfaceFields node=[]]
|
|
[#list node.* as this]
|
|
[#if this?node_name == "if"]
|
|
[#local ifname = GetNodeName(this)
|
|
ifctype = GetInterfaceCType(this) /]
|
|
[#local if = GetInterfaceByName(ifname)]
|
|
[@ccode.Indent 1 /]/**
|
|
[@doxygen.EmitBrief ccode.indentation "Implemented interface @p " + ifctype + "." /]
|
|
[@ccode.Indent 1 /] */
|
|
[@ccode.GenerateVariableDeclaration indent = ccode.indentation
|
|
name = GetNodeNamespace(if)
|
|
ctype = ifctype /]
|
|
|
|
[#elseif this?node_name == "condition"]
|
|
[#local condcheck = (this.@check[0]!"1")?trim]
|
|
#if (${condcheck}) || defined (__DOXYGEN__)
|
|
[@GenerateClassInterfaceFields this /]
|
|
#endif /* ${condcheck} */
|
|
[/#if]
|
|
[/#list]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates a Doxygen list of implemented interfaces from an XML node.
|
|
--]
|
|
[#macro GenerateClassImplementsTags node=[]]
|
|
[#list node.* as this]
|
|
[#if this?node_name == "if"]
|
|
[#local refname = GetNodeName(this)
|
|
refnamespace = GetNodeNamespace(this)
|
|
refctype = GetInterfaceCType(this) /]
|
|
[@doxygen.EmitTagVerbatim indent="" tag="implements" text=refctype /]
|
|
[#elseif this?node_name == "condition"]
|
|
[@GenerateClassImplementsTags this /]
|
|
[/#if]
|
|
[/#list]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates private constructor and destructor from an XML node.
|
|
--]
|
|
[#macro GenerateClassPrivateConstructor node=[]]
|
|
[#local classname = GetNodeName(node)
|
|
classnamespace = GetNodeNamespace(node)
|
|
classtype = GetClassType(node)
|
|
classctype = GetClassCType(node)
|
|
classdescr = GetNodeDescription(node) /]
|
|
[#if classtype == "regular"]
|
|
[#assign generated = true]
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "name" "Default constructor of " + classctype /]
|
|
* @{
|
|
*/
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "memberof" classctype /]
|
|
*
|
|
[@doxygen.EmitBrief "" "Default initialization function of @p " + classctype + "." /]
|
|
*
|
|
[@doxygen.EmitParam name = "self"
|
|
dir = "out"
|
|
text = "Pointer to a @p " + classctype + " instance to be initialized." /]
|
|
[@doxygen.EmitParamFromNode node = node.methods.objinit[0] /]
|
|
[@doxygen.EmitReturn text = "Pointer to the initialized object." /]
|
|
*
|
|
* @objinit
|
|
*/
|
|
[@ccode.GeneratePrototypeFromNode indent = ""
|
|
name = classnamespace + "ObjectInit"
|
|
ctype = classctype + " *"
|
|
modifiers = ["static"]
|
|
params = [classctype + " *self"]
|
|
node = node.methods.objinit[0] /] {
|
|
|
|
[#local params = ccode.MakeCallParamsSequence(["self", "&__" + classname + "_vmt"], node.methods.objinit[0])]
|
|
[@ccode.GenerateFunctionCall indent = ccode.indentation
|
|
destination = "return"
|
|
name = "__" + classnamespace + "_objinit_impl"
|
|
params = params /]
|
|
}
|
|
/** @} */
|
|
|
|
[/#if]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates public constructor and destructor from an XML node.
|
|
--]
|
|
[#macro GenerateClassPublicConstructor node=[]]
|
|
[#local classname = GetNodeName(node)
|
|
classnamespace = GetNodeNamespace(node)
|
|
classtype = GetClassType(node)
|
|
classctype = GetClassCType(node)
|
|
classdescr = GetNodeDescription(node) /]
|
|
[#if classtype == "regular"]
|
|
[#assign generated = true]
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "name" "Default constructor of " + classctype /]
|
|
* @{
|
|
*/
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "memberof" classctype /]
|
|
*
|
|
[@doxygen.EmitBrief "" "Default initialization function of @p " + classctype + "." /]
|
|
*
|
|
[@doxygen.EmitParam name = "self"
|
|
dir = "out"
|
|
text = "Pointer to a @p " + classctype + " instance to be initialized." /]
|
|
[@doxygen.EmitParamFromNode node = node.methods.objinit[0] /]
|
|
[@doxygen.EmitReturn text = "Pointer to the initialized object." /]
|
|
*
|
|
* @objinit
|
|
*/
|
|
CC_FORCE_INLINE
|
|
[@ccode.GeneratePrototypeFromNode indent = ""
|
|
name = classnamespace + "ObjectInit"
|
|
ctype = classctype + " *"
|
|
modifiers = ["static", "inline"]
|
|
params = [classctype + " *self"]
|
|
node = node.methods.objinit[0] /] {
|
|
[@ccode.Indent 1 /]extern const struct ${classname}_vmt __${classname}_vmt;
|
|
|
|
[#local params = ccode.MakeCallParamsSequence(["self", "&__" + classname + "_vmt"], node.methods.objinit[0])]
|
|
[@ccode.GenerateFunctionCall indent = ccode.indentation
|
|
destination = "return"
|
|
name = "__" + classnamespace + "_objinit_impl"
|
|
params = params /]
|
|
}
|
|
/** @} */
|
|
|
|
[/#if]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates interface virtual methods as inline functions
|
|
-- from an XML node.
|
|
--]
|
|
[#macro GenerateInterfaceVirtualMethods if=[]]
|
|
[#local ifnamespace = GetNodeNamespace(if)
|
|
ifctype = GetInterfaceCType(if) /]
|
|
[@GenerateVirtualMethods methods = if.methods
|
|
ctype = ifctype
|
|
namespace = ifnamespace /]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates a class wrapper from an XML node.
|
|
--]
|
|
[#macro GenerateInterfaceWrapper node=[]]
|
|
[#local if = node]
|
|
[#local ifname = GetNodeName(if)
|
|
ifnamespace = GetNodeNamespace(if)
|
|
ifctype = GetInterfaceCType(if)
|
|
ifdescr = GetNodeDescription(if)
|
|
ancestorname = GetNodeAncestorName(if, "")
|
|
ancestorctype = GetInterfaceAncestorCType(if)]
|
|
/**
|
|
* @interface ${ifctype}
|
|
[#if ancestorctype?length > 0]
|
|
* @extends ${ancestorctype}
|
|
[/#if]
|
|
*
|
|
[@doxygen.EmitBriefFromNode node=if /]
|
|
[@doxygen.EmitDetailsFromNode node=if /]
|
|
[@doxygen.EmitPreFromNode node=if /]
|
|
[@doxygen.EmitPostFromNode node=if /]
|
|
[@doxygen.EmitNoteFromNode node=if /]
|
|
[@doxygen.EmitNote text="The interface namespace is <tt>" + ifnamespace + "</tt>, access to " +
|
|
"an implemented interface is done using: " +
|
|
"<tt>&<objp>-><classnamespace>." + ifnamespace + "</tt>"/]
|
|
*
|
|
[@doxygen.EmitTagVerbatim indent="" tag="name" text="Interface @p " + ifctype + " structures"/]
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
[@doxygen.EmitBrief "" "Type of a " + ifdescr + " interface." /]
|
|
*/
|
|
typedef struct ${ifname} ${ifctype};
|
|
|
|
[#local methodsstruct = ifname + "_methods"]
|
|
[#if node.methods.method?size > 0]
|
|
/**
|
|
[@doxygen.EmitBrief "" "Interface @p " + ifctype + " methods as a structure." /]
|
|
*/
|
|
struct ${methodsstruct} {
|
|
[@GenerateVMTPointers methods=if.methods /]
|
|
};
|
|
|
|
[/#if]
|
|
/**
|
|
[@doxygen.EmitBrief "" "Interface @p " + ifctype + " methods." /]
|
|
*/
|
|
[#local methodsdefine = "__" + ifname + "_methods"]
|
|
${("#define " + methodsdefine)?right_pad(ccode.backslash_align) + "\\"}
|
|
[#if ancestorname?length > 0]
|
|
${(ccode.indentation + "__" + ancestorname +
|
|
"_methods")?right_pad(ccode.backslash_align) + "\\"}
|
|
[/#if]
|
|
[#if if.methods.method?size > 0]
|
|
[@ccode.GenerateVariableDeclaration indent=ccode.indentation
|
|
name=ifnamespace
|
|
ctype="struct " + methodsstruct /]
|
|
|
|
|
|
[#else]
|
|
${(ccode.indentation + "/* Memory offset between this interface structure and begin of")}
|
|
${(ccode.indentation + " the implementing class structure.*/")?right_pad(ccode.backslash_align) + "\\"}
|
|
${(ccode.indentation + "size_t instance_offset;")}
|
|
|
|
[/#if]
|
|
/**
|
|
[@doxygen.EmitBrief "" "Interface @p " + ifctype + " VMT initializer." /]
|
|
*
|
|
[@doxygen.EmitParam "" "ns" "" "Namespace of the implementing class." /]
|
|
[@doxygen.EmitParam "" "off" "in" "VMT offset to be stored." /]
|
|
*/
|
|
[#local vmtinitsdefine = "__" + ifname + "_vmt_init(ns, off)"]
|
|
#define ${vmtinitsdefine?right_pad(68) + "\\"}
|
|
[#if ancestorname?length > 0]
|
|
[#local s = " __" + ancestorname + "_vmt_init(ns, off)"]
|
|
[#if node.methods?size > 0]
|
|
[#local s = (s + " ")?right_pad(76) + "\\"]
|
|
[/#if]
|
|
${s}
|
|
[@GenerateVMTInitializers methods=node.methods namespace=ifnamespace /]
|
|
[#else]
|
|
${(ccode.indentation + ".instance_offset")?right_pad(ccode.initializers_align) + "= off,"}
|
|
[/#if]
|
|
|
|
/**
|
|
[@doxygen.EmitBrief "" "Interface @p " + ifctype + " virtual methods table." /]
|
|
*/
|
|
struct ${ifname?lower_case}_vmt {
|
|
${methodsdefine}
|
|
};
|
|
|
|
/**
|
|
[@doxygen.EmitBrief "" "Structure representing a " + ifdescr + "." /]
|
|
*/
|
|
struct ${ifname?lower_case} {
|
|
[@ccode.Indent 1 /]/**
|
|
[@doxygen.EmitBrief ccode.indentation "Virtual Methods Table." /]
|
|
[@ccode.Indent 1 /] */
|
|
[#local vmtctype = "const struct " + ifname?lower_case + "_vmt$I*$N"]
|
|
${ccode.MakeVariableDeclaration(ccode.indentation "vmt" vmtctype)}
|
|
};
|
|
/** @} */
|
|
[/#macro]
|
|
|
|
[#macro GenerateInterfacesImplementations node=[]
|
|
classnamespace="no-namespace"
|
|
classctype="no-ctype"]
|
|
[#list node.* as this]
|
|
[#if this?node_name == "if"]
|
|
[#local if = GetInterfaceByName(GetNodeName(this))
|
|
ifctype = GetInterfaceCType(if)
|
|
ifnamespace = GetNodeNamespace(if)]
|
|
[#list this.method as methodref]
|
|
[#local methodsname = GetMethodShortName(methodref)]
|
|
[#local ifmethods = GetInterfaceMethodsSequence(if)]
|
|
[#local foundmethods = ifmethods?filter(m -> GetMethodShortName(m) == methodsname)]
|
|
[#if !foundmethods[0]??]
|
|
[#stop ">>>> Method '" + methodsname + "' not found."]
|
|
[/#if]
|
|
[#local method = foundmethods[0]]
|
|
[#local methodname = GetNodeName(method)]
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "memberof" classctype /]
|
|
* @private
|
|
*
|
|
[@doxygen.EmitBrief "" "Implementation of interface method @p " + methodname + "()." /]
|
|
*
|
|
[@doxygen.EmitParam name="ip" dir="both"
|
|
text="Pointer to the @p " + ifctype + " class interface." /]
|
|
[@doxygen.EmitParamFromNode node=method /]
|
|
[@doxygen.EmitReturnFromNode node=method /]
|
|
*/
|
|
[@ccode.GeneratePrototypeFromNode indent = ""
|
|
name = "__" + classnamespace + "_" +
|
|
ifnamespace + "_" + methodsname + "_impl"
|
|
modifiers = ["static"]
|
|
params = ["void *ip"]
|
|
node = method /] {
|
|
[@ccode.Indent 1 /]${classctype} *self = oopIfGetOwner(${classctype}, ip);
|
|
[@ccode.GenerateIndentedCCode indent = ccode.indentation
|
|
ccode = methodref.implementation[0] /]
|
|
}
|
|
[#if methodref?has_next]
|
|
|
|
[/#if]
|
|
[/#list]
|
|
[#elseif this?node_name == "condition"]
|
|
[#local condcheck = (this.@check[0]!"1")?trim]
|
|
#if (${condcheck}) || defined (__DOXYGEN__)
|
|
[@GenerateInterfacesImplementations node = this
|
|
classnamespace = classnamespace
|
|
classctype = classctype /]
|
|
#endif /* ${condcheck} */
|
|
[/#if]
|
|
[#if this?has_next]
|
|
|
|
[#elseif (this?parent?node_name != "condition") &&
|
|
(this?parent?node_name != "implements")]
|
|
|
|
[/#if]
|
|
[/#list]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates a class interfaces implementatios from an XML node.
|
|
--]
|
|
[#macro GenerateClassInterfacesImplementations node=[] private=false]
|
|
[#local classnamespace = GetNodeNamespace(node)
|
|
classctype = GetClassCType(node)]
|
|
[#if node.implements.*?size > 0]
|
|
/**
|
|
[@doxygen.EmitTagVerbatim "" "name" "Interfaces implementation of " + classctype /]
|
|
* @{
|
|
*/
|
|
[@GenerateInterfacesImplementations node = node.implements
|
|
classnamespace = classnamespace
|
|
classctype = classctype /]
|
|
/** @} */
|
|
|
|
[/#if]
|
|
[/#macro]
|
|
|
|
[#--
|
|
-- This macro generates the class code from an XML node.
|
|
--]
|
|
[#macro GenerateClassCode class=[] modifiers=[]]
|
|
[@GenerateClassInterfacesImplementations node=class /]
|
|
[@GenerateClassImplementations node=class modifiers=modifiers /]
|
|
[@GenerateClassVMT node=class modifiers=modifiers /]
|
|
[@GenerateClassRegularMethods node=class modifiers=modifiers /]
|
|
[/#macro]
|