]> OCCT Git - occt-wok.git/commitdiff
Initial revision
authorcas <cas@opencascade.com>
Fri, 22 Oct 1999 18:05:40 +0000 (18:05 +0000)
committercas <cas@opencascade.com>
Fri, 22 Oct 1999 18:05:40 +0000 (18:05 +0000)
src/TCPPExt/FILES [new file with mode: 0755]
src/TCPPExt/TCPPExt.cxx [new file with mode: 0755]
src/TCPPExt/TCPPExt.hxx [new file with mode: 0755]
src/TCPPExt/TCPPExt_MethodTemplate.edl [new file with mode: 0755]

diff --git a/src/TCPPExt/FILES b/src/TCPPExt/FILES
new file mode 100755 (executable)
index 0000000..177c0c6
--- /dev/null
@@ -0,0 +1,4 @@
+TCPPExt.cxx
+TCPPExt.hxx
+TCPPExt_MethodTemplate.edl
+#TCPPExt.edl
diff --git a/src/TCPPExt/TCPPExt.cxx b/src/TCPPExt/TCPPExt.cxx
new file mode 100755 (executable)
index 0000000..861cdeb
--- /dev/null
@@ -0,0 +1,530 @@
+// CLE : this extractor is a test for the general extraction architecture
+//       for the new DTV tools 
+// SYC : 08/1996
+//
+
+#include <TCPPExt.hxx>
+
+
+#include <MS_HArray1OfParam.hxx>
+
+#include <WOKTools_Messages.hxx>
+
+// Standard Extractor API : list the EDL files used by this program
+//
+Handle(TColStd_HSequenceOfHAsciiString) TCPP_TemplatesUsed()
+{
+  Handle(TColStd_HSequenceOfHAsciiString) result = new TColStd_HSequenceOfHAsciiString;
+
+  result->Append(new TCollection_HAsciiString("TCPPExt_MethodTemplate.edl"));
+
+  return result;
+
+}
+
+Handle(EDL_API)&  TCPP_LoadTemplate(const Handle(TColStd_HSequenceOfHAsciiString)& edlsfullpath,
+                                   const Handle(TCollection_HAsciiString)& outdir)
+{
+  static Handle(EDL_API)  api = new EDL_API;
+  static Standard_Boolean alreadyLoaded = Standard_False;
+
+  api->ClearVariables();
+
+  if (!alreadyLoaded) {
+    alreadyLoaded = Standard_True;
+
+    for(Standard_Integer i = 1; i <= edlsfullpath->Length(); i++) {
+      api->AddIncludeDirectory(edlsfullpath->Value(i)->ToCString());
+    }
+
+    if (api->Execute("TCPPExt_MethodTemplate.edl") != EDL_NORMAL) {
+      ErrorMsg << "TCPPExt" << "unable to load : TCPPExt_MethodTemplate.edl" << endm;
+      Standard_NoSuchObject::Raise();
+    }
+  }
+
+  // templates for methods extraction
+  //
+  api->AddVariable(VMethodHeader,"MethodTemplate");
+  api->AddVariable(VConstructorHeader,"ConstructorTemplate");
+
+  return api;
+}
+
+//  build a return, parameter or field type in c++
+//  return a <type name> or a Handle_<type name>
+//
+Handle(TCollection_HAsciiString) TCPP_BuildType(const Handle(MS_MetaSchema)& aMeta,
+                                               const Handle(TCollection_HAsciiString)& aTypeName,
+                                               const Handle(MS_Class)& aClass)
+{
+  Handle(TCollection_HAsciiString)   result = new TCollection_HAsciiString;
+  Handle(MS_Type)                    aType;
+
+  if (aMeta->IsDefined(aTypeName)) {
+    aType = aMeta->GetType(aTypeName);
+
+    if (aType->IsKind(STANDARD_TYPE(MS_Alias))) {
+      Handle(MS_Alias) analias = Handle(MS_Alias)::DownCast(aType);
+
+      aType = aMeta->GetType(analias->DeepType());
+    }
+    
+    if (aType->IsKind(STANDARD_TYPE(MS_Class))) {
+      Handle(MS_Class) aClass;
+      
+      aClass = Handle(MS_Class)::DownCast(aType);
+      
+      if (aClass->IsPersistent() || aClass->IsTransient()) {
+       result->AssignCat("Handle(");
+       result->AssignCat(aTypeName);
+       result->AssignCat(")");
+      }
+      else {
+       result->AssignCat(aTypeName);
+      } 
+    }
+    else {
+      result->AssignCat(aTypeName);
+    }
+  }
+  else if (( aClass->IsKind(STANDARD_TYPE(MS_GenClass)) ) ||                           // if it's a generic class 
+          ( (aClass->IsKind(STANDARD_TYPE(MS_StdClass))) && (aClass->IsNested()) )) { // or a class nested in a generic class
+    Handle(MS_GenClass) myGenClass;
+
+    // we get the MS_GenClass associated to the class
+    if ( (aClass->IsKind(STANDARD_TYPE(MS_StdClass))) && (aClass->IsNested()) ) {
+      myGenClass = Handle(MS_GenClass)::DownCast(aMeta->GetType(aClass->GetNestingClass()));
+    }
+    if ( aClass->IsKind(STANDARD_TYPE(MS_GenClass)) ) {
+      myGenClass = Handle(MS_GenClass)::DownCast(aClass);
+    }
+
+    // we find the type in the generic types defined in the MS_GenClass
+    Handle(MS_HSequenceOfGenType) myGenTypes = myGenClass->GenTypes();
+    Handle(MS_GenType) myGenType ;
+      
+    for (int i = 1; i <= myGenTypes->Length(); i++) 
+      if ( (strcmp(myGenTypes->Value(i)->Name()->ToCString(),aTypeName->ToCString()) == 0) )
+       myGenType = myGenTypes->Value(i);
+
+    // we process the type
+    if (!myGenType->Any()) {
+      if ( (strcmp(myGenType->TYpeName()->ToCString(),"Transient") == 0)
+         || (strcmp(myGenType->TYpeName()->ToCString(),"Persistent") == 0) ) {
+       result->AssignCat("Handle(");
+       result->AssignCat(aTypeName);
+       result->AssignCat(")");
+      }
+      else {
+       result->AssignCat(aTypeName);
+      } 
+    }
+    else {
+      result->AssignCat(aTypeName);
+    }
+  }
+  else {
+    ErrorMsg << "TCPPExt" << "type " << aType->FullName()->ToCString() << " not defined..." << endm;
+    Standard_NoSuchObject::Raise();
+  }
+  return result;
+}
+
+// Build a parameter list for methods
+//    the output is in C++
+//
+Handle(TCollection_HAsciiString) TCPP_BuildParameterList(const Handle(MS_MetaSchema)& aMeta, 
+                                                        const Handle(MS_HArray1OfParam)& aSeq)
+{
+  Standard_Integer                 i;
+  Handle(TCollection_HAsciiString) result = new TCollection_HAsciiString;
+  Handle(MS_Type)                  aType;
+  Handle(MS_Class)                 aClass;
+
+  if(!aSeq.IsNull()) {
+    for (i = 1; i <= aSeq->Length(); i++) {
+      if (i > 1) {
+       result->AssignCat(",");
+      }
+
+      if (!aSeq->Value(i)->IsOut()) {
+       result->AssignCat("const ");
+      }
+    
+      if (aMeta->IsDefined(aSeq->Value(i)->TypeName())) {
+       aType = aMeta->GetType(aSeq->Value(i)->TypeName());
+      
+       if (aType->IsKind(STANDARD_TYPE(MS_Class))) {
+         aClass = Handle(MS_Class)::DownCast(aType);
+
+         if (aClass->IsPersistent() || aClass->IsTransient()) {
+           result->AssignCat("Handle(");
+           result->AssignCat(aSeq->Value(i)->TypeName());
+           result->AssignCat(")& ");
+           result->AssignCat(aSeq->Value(i)->Name());
+         }
+         else {
+           result->AssignCat(aSeq->Value(i)->TypeName());
+           result->AssignCat("& ");
+           result->AssignCat(aSeq->Value(i)->Name());
+         }
+       } 
+       else if (aType->IsKind(STANDARD_TYPE(MS_Imported)) || aType->IsKind(STANDARD_TYPE(MS_Pointer)) || aSeq->Value(i)->IsItem() || aSeq->Value(i)->IsOut()) {
+         result->AssignCat(aSeq->Value(i)->TypeName());
+         result->AssignCat("& ");
+         result->AssignCat(aSeq->Value(i)->Name());
+       }
+       // WARNING : ALIASES
+       //
+       else if (aType->IsKind(STANDARD_TYPE(MS_Alias))) {
+         Handle(MS_Alias)                 analias  = Handle(MS_Alias)::DownCast(aType);
+         Handle(TCollection_HAsciiString) deeptype = analias->DeepType();
+
+         if (aMeta->IsDefined(deeptype)) {
+           Handle(MS_Type) dt = aMeta->GetType(deeptype);
+
+           if (dt->IsKind(STANDARD_TYPE(MS_Imported)) || dt->IsKind(STANDARD_TYPE(MS_Pointer)) || aSeq->Value(i)->IsItem() || aSeq->Value(i)->IsOut()) {
+             result->AssignCat(aSeq->Value(i)->TypeName());
+             result->AssignCat("& ");
+             result->AssignCat(aSeq->Value(i)->Name());
+           } 
+           else if (dt->IsKind(STANDARD_TYPE(MS_Class))) {
+             aClass = Handle(MS_Class)::DownCast(dt);
+           
+             if (aClass->IsPersistent() || aClass->IsTransient()) {
+               result->AssignCat("Handle(");
+               result->AssignCat(aSeq->Value(i)->TypeName());
+               result->AssignCat(")& ");
+               result->AssignCat(aSeq->Value(i)->Name());
+             }
+             else {
+               result->AssignCat(aSeq->Value(i)->TypeName());
+               result->AssignCat("& ");
+               result->AssignCat(aSeq->Value(i)->Name());
+             }
+           } 
+           else {
+             result->AssignCat(aSeq->Value(i)->TypeName());
+             result->AssignCat(" ");
+             result->AssignCat(aSeq->Value(i)->Name());
+           }
+         }
+         else {
+           ErrorMsg << "TCPPExt" << "incomplete alias deep type in method's parameter..." << endm;
+           Standard_NoSuchObject::Raise();
+         }
+       }
+       else {
+         result->AssignCat(aSeq->Value(i)->TypeName());
+         result->AssignCat(" ");
+         result->AssignCat(aSeq->Value(i)->Name());
+       }
+      }
+      else {
+       result->AssignCat(aSeq->Value(i)->TypeName());
+       result->AssignCat("& ");
+       result->AssignCat(aSeq->Value(i)->Name());
+      }
+    }
+  }
+  return result;
+}
+
+// write the content of a variable into a file
+//
+void TCPP_WriteFile(const Handle(EDL_API)& api,
+                   const Handle(TCollection_HAsciiString)& aFileName,
+                   const Standard_CString var)
+{
+  // ...now we write the result
+  //
+  api->OpenFile("HTFile",aFileName->ToCString());
+  api->WriteFile("HTFile",var);
+  api->CloseFile("HTFile");
+}
+
+// Main phase :
+//    extract template for .gxx, .lxx and .cxx for classes
+//    and packages
+//
+                
+void TCPP_Extract(const Handle(MS_MetaSchema)& aMeta, 
+                 const Handle(TCollection_HAsciiString)& aName,
+                 const Handle(TColStd_HSequenceOfHAsciiString)& edlsfullpath,
+                 const Handle(TCollection_HAsciiString)& outdir,
+                 const Handle(TColStd_HSequenceOfHAsciiString)& outfile,
+                 const Standard_CString)
+{
+  Handle(MS_Type)     srcType;
+  Handle(MS_Class)    srcClass;
+  Handle(MS_Package)  srcPackage;
+
+
+  // before begining, we look if the entity has something to extract...
+  //
+  if (aMeta->IsDefined(aName)) {
+    srcType    = aMeta->GetType(aName); 
+    srcClass   = Handle(MS_Class)::DownCast(srcType); 
+    
+    if (( srcType->IsKind(STANDARD_TYPE(MS_InstClass)) ) || 
+       ( (!srcType->IsKind(STANDARD_TYPE(MS_StdClass))) && (!srcType->IsKind(STANDARD_TYPE(MS_GenClass))) )) {
+      // InfoMsg << "TCPPExt" << " c'est une InstClass ou une Enum " << endm;
+      return;
+    }
+
+    Handle(MS_StdClass) stdClass = Handle(MS_StdClass)::DownCast(srcType);
+    if (!stdClass.IsNull()) {
+      if (!stdClass->GetMyCreator().IsNull()) {
+       // InfoMsg << "TCPPExt" << " c'est une classe instantiee par InstToStd " << endm;
+       return;
+      }
+    }
+  }
+  else if (aMeta->IsPackage(aName)) {
+    srcPackage = aMeta->GetPackage(aName);
+  }
+  else {
+    ErrorMsg << "TCPPExt" << "class " << aName->ToCString() << " not defined..." << endm;
+    Standard_NoSuchObject::Raise();
+  }
+  
+  Handle(MS_HSequenceOfMemberMet) aSeqMemMet;
+  Handle(MS_HSequenceOfExternMet) aSeqExtMet;
+  Standard_Integer                i,
+  seqLen;
+  
+  if (!srcClass.IsNull()) {
+    aSeqMemMet = srcClass->GetMethods();
+    seqLen     = aSeqMemMet->Length();
+  }
+  else if (!srcPackage.IsNull()) {
+    aSeqExtMet = srcPackage->Methods();
+    seqLen     = aSeqExtMet->Length();
+  }
+  
+  if (seqLen == 0) {
+    return;
+  }
+  
+  // ... and we load the templates
+  //
+  Handle(EDL_API)     api = TCPP_LoadTemplate(edlsfullpath,outdir);
+  Handle(MS_Method)   m;
+  Handle(MS_InstMet)  im;
+  Handle(MS_ClassMet) cm;
+  Handle(MS_Construc) ct;
+  Handle(MS_Param)    retType;
+
+  Standard_Boolean HasInlineMethod = Standard_False,
+                   InlineMethod,
+                   noInclude = Standard_False;
+  
+  Handle(TCollection_HAsciiString) CxxFileName = new TCollection_HAsciiString(outdir);
+  Handle(TCollection_HAsciiString) LxxFileName = new TCollection_HAsciiString(outdir);
+  Handle(TCollection_HAsciiString) IncludeName = new TCollection_HAsciiString("#include <");
+  
+  CxxFileName->AssignCat(aName);
+
+  if (!srcClass.IsNull()) {
+    if (( srcClass->IsKind(STANDARD_TYPE(MS_GenClass)) )  ||
+       ( (srcClass->IsKind(STANDARD_TYPE(MS_StdClass))) && (srcClass->IsNested()) )) {
+      CxxFileName->AssignCat(".gxx.template");
+      noInclude = Standard_True;
+    }
+    else {
+      CxxFileName->AssignCat(".cxx.template");
+    }
+  }
+  else {
+    CxxFileName->AssignCat(".cxx.template");
+  }
+
+  LxxFileName->AssignCat(aName);
+  LxxFileName->AssignCat(".lxx.template");
+  
+  IncludeName->AssignCat(aName);
+
+  if (!srcPackage.IsNull()) {
+    IncludeName->AssignCat(".hxx>\n\n");
+  }
+  else {
+    IncludeName->AssignCat(".ixx>\n\n");
+  }
+
+  api->AddVariable(VClass,aName->ToCString());
+
+  api->OpenFile(VCxxFile,CxxFileName->ToCString());
+  outfile->Append(CxxFileName);
+
+  if (!noInclude) {
+    api->AddVariable("%Include",IncludeName->ToCString());
+    api->WriteFile(VCxxFile,"%Include");
+  }
+
+  for (i = 1; i <= seqLen; i++) {
+    
+    if (!srcClass.IsNull()) {
+      m = aSeqMemMet->Value(i);
+    }
+    else if (!srcPackage.IsNull()) {
+      m = aSeqExtMet->Value(i);
+    }
+    else {
+      ErrorMsg << "TCPPExt" << "while extracting " << aName->ToCString()  << endm;
+      Standard_NoSuchObject::Raise();
+    }
+    
+    // here we process all the common attributes of methods
+    //
+
+    // build a c++ declaration method
+    // the result is in the EDL variable VMethod
+    //
+    //   the EDL variables : 
+    //        VMethodHeader : must contains the name of the template used for 
+    //                        methods construction
+    //        VConstructorHeader :  must contains the name of the template used for 
+    //                              constructors construction
+    //
+    Handle(TCollection_HAsciiString) MetTemplate,
+                                     ConTemplate;
+
+    MetTemplate = api->GetVariableValue(VMethodHeader);
+    ConTemplate = api->GetVariableValue(VConstructorHeader);
+    // here we process all the common attributes of methods
+    //
+    api->AddVariable(VMethodName,m->Name()->ToCString());
+    api->AddVariable(VVirtual,"");
+    
+    // it s inline method ?
+    //
+    if (m->IsInline()) {
+      api->AddVariable(VIsInline,"yes");
+      InlineMethod = Standard_True;
+      if (!HasInlineMethod) {
+       HasInlineMethod = Standard_True;
+       api->OpenFile(VLxxFile,LxxFileName->ToCString());
+       outfile->Append(LxxFileName);
+      }
+    }
+    else {
+      InlineMethod = Standard_False;
+      api->AddVariable(VIsInline,"no");
+    }
+    
+    // it s returning const ?
+    //
+    if (m->IsConstReturn()) {
+      api->AddVariable(VRetSpec,"const");
+    }
+    else {
+      api->AddVariable(VRetSpec,"");
+    }
+    
+    // it s returning & ?
+    //
+    if (m->IsRefReturn()) {
+      api->AddVariable(VAnd,"&");
+    }
+    else {
+      api->AddVariable(VAnd,"");
+    }
+    
+    api->AddVariable(VArgument,TCPP_BuildParameterList(aMeta,m->Params())->ToCString());
+    
+    // it s returning a type or void
+    //
+    retType = m->Returns();
+    
+    if (!retType.IsNull()) {
+      Handle(TCollection_HAsciiString) aTypeName = retType->TypeName();
+      api->AddVariable(VReturn,TCPP_BuildType(aMeta,aTypeName,srcClass)->ToCString());
+    }
+    else {
+      api->AddVariable(VReturn,"void");
+    }
+  
+    // now the specials attributes
+    //
+    // instance methods
+    //
+    if (m->IsKind(STANDARD_TYPE(MS_InstMet))) {
+      im = Handle(MS_InstMet)::DownCast(m);
+      
+      api->AddVariable(VIsCreateMethod,"no");
+
+      if (!im->IsDeferred()) {
+       if (im->IsConst()) {
+         api->AddVariable(VMetSpec,"const");
+       }
+       else {
+         api->AddVariable(VMetSpec,"");
+       }
+       api->Apply(VMethod,MetTemplate->ToCString());
+       
+       if (InlineMethod) {
+         api->Apply(VMethod,"InlineMethodTemplate");
+         api->WriteFile(VLxxFile,"%Method");
+       }
+       else {
+         api->WriteFile(VCxxFile,"%Method");
+       }
+      }
+    }
+    //
+    // class methods
+    //
+    else if (m->IsKind(STANDARD_TYPE(MS_ClassMet))) {
+      api->AddVariable(VIsCreateMethod,"no");
+      api->AddVariable(VMetSpec,"");
+      api->Apply(VMethod,MetTemplate->ToCString());
+      
+      if (InlineMethod) {
+       api->Apply(VMethod,"InlineMethodTemplate");
+       api->WriteFile(VLxxFile,"%Method");
+      }
+      else {
+       api->WriteFile(VCxxFile,"%Method");
+      }
+    }
+    //
+    // constructors
+    //
+    else if (m->IsKind(STANDARD_TYPE(MS_Construc))) {
+      api->AddVariable(VIsCreateMethod,"yes");
+      api->Apply(VMethod,ConTemplate->ToCString());
+      
+      if (InlineMethod) {
+       api->Apply(VMethod,"InlineMethodTemplate");
+       api->WriteFile(VLxxFile,"%Method");
+      }
+      else {
+       api->WriteFile(VCxxFile,"%Method");
+      }
+    }
+    //
+    // package methods
+    //
+    else if (m->IsKind(STANDARD_TYPE(MS_ExternMet))) {
+      api->AddVariable(VIsCreateMethod,"no");
+      api->AddVariable(VMetSpec,"");
+      api->Apply(VMethod,MetTemplate->ToCString());
+      if (InlineMethod) {
+       api->Apply(VMethod,"InlineMethodTemplate");
+       api->WriteFile(VLxxFile,"%Method");
+      }
+      else {
+       api->WriteFile(VCxxFile,"%Method");
+      }
+    }
+  }
+  // then, we close the files
+  //   note that inline methods file may be empty
+  //
+  api->CloseFile(VCxxFile);
+  
+  if (HasInlineMethod) {
+    api->CloseFile(VLxxFile);
+    }
+}
diff --git a/src/TCPPExt/TCPPExt.hxx b/src/TCPPExt/TCPPExt.hxx
new file mode 100755 (executable)
index 0000000..8d05505
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef _TCPPExt_HeaderFile
+#define _TCPPExt_HeaderFile
+#include <MS.hxx>
+
+#include <EDL_API.hxx>
+
+#include <MS_MetaSchema.hxx>
+
+#include <MS_Class.hxx>
+#include <MS_GenClass.hxx>
+#include <MS_InstClass.hxx>
+#include <MS_Package.hxx>
+#include <MS_Error.hxx>
+#include <MS_Imported.hxx>
+
+#include <MS_InstMet.hxx>
+#include <MS_ClassMet.hxx>
+#include <MS_Construc.hxx>
+#include <MS_ExternMet.hxx>
+#include <MS_Param.hxx>
+#include <MS_Field.hxx>
+#include <MS_GenType.hxx>
+#include <MS_Enum.hxx>
+#include <MS_PrimType.hxx>
+#include <MS_Alias.hxx>
+#include <MS_Pointer.hxx>
+
+#include <MS_HSequenceOfMemberMet.hxx>
+#include <MS_HSequenceOfExternMet.hxx>
+#include <MS_HSequenceOfParam.hxx>
+#include <MS_HSequenceOfField.hxx>
+#include <MS_HSequenceOfGenType.hxx>
+#include <TColStd_HSequenceOfHAsciiString.hxx>
+#include <TColStd_HSequenceOfInteger.hxx>
+
+#include <TCollection_HAsciiString.hxx>
+
+#include <Standard_NoSuchObject.hxx>
+
+extern "C" {
+
+        Handle(TColStd_HSequenceOfHAsciiString) TCPP_TemplatesUsed();
+
+        void TCPP_Extract(const Handle(MS_MetaSchema)& ams,
+                        const Handle(TCollection_HAsciiString)& aname,
+                        const Handle(TColStd_HSequenceOfHAsciiString)& edlsfullpath,
+                        const Handle(TCollection_HAsciiString)& outdir,
+                        const Handle(TColStd_HSequenceOfHAsciiString)& outfile,
+                        const Standard_CString);
+       
+}
+
+// EDL variables
+//
+Standard_CString VClass              = "%Class",
+                 VRetSpec            = "%RetSpec",
+                 VVirtual            = "%Virtual",
+                 VReturn             = "%Return",
+                 VAnd                = "%And",
+                 VMethodName         = "%MethodName",
+                 VArgument           = "%Arguments",
+                 VMetSpec            = "%MetSpec",
+                 VMethod             = "%Method",
+                 VIsInline           = "%IsInline",
+                 VIsCreateMethod     = "%IsCreateMethod",
+                 VCxxFile            = "CxxFile",
+                 VLxxFile            = "LxxFile",
+                VMethodHeader       = "%MethodHeader",
+                VConstructorHeader  = "%ConstructorHeader";
+
+#endif
diff --git a/src/TCPPExt/TCPPExt_MethodTemplate.edl b/src/TCPPExt/TCPPExt_MethodTemplate.edl
new file mode 100755 (executable)
index 0000000..a8d21e0
--- /dev/null
@@ -0,0 +1,28 @@
+-- File:       TCPPExt_MethodTemplate.edl
+-- Author:     Kernel (CLE)
+-- History:    Thu Sep 14 15:51:01 1995        Kernel  Creation
+-- Copyright:  Matra Datavision 1995
+-- Purpose:     Templates for methods extraction
+
+@verboseoff;
+-- ==============================================
+-- Methods templates
+-- ==============================================
+
+@template ConstructorTemplate(%Class,%Arguments) is
+$%Class::%Class(%Arguments)
+${
+$}
+$
+@end;
+
+@template MethodTemplate(%RetSpec,%Return,%And,%Class,%MethodName,%Arguments,%MetSpec) is
+$%RetSpec %Return%And %Class::%MethodName(%Arguments) %MetSpec
+${
+$}
+$
+@end;
+
+@template InlineMethodTemplate(%Method) is
+$inline %Method 
+@end;