[#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 . --] <#-- -- 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 " + ifnamespace + ", access to " + "an implemented interface is done using: " + "&->." + ifnamespace + ""/] * [@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]