gmSLIntroduction

Introduction to gmSL

The name gmSL stands for Great Migrations Scripting language. It is a high-level programming language that is compiled and executed by gmBasic rather than compiled by the computer's processor as other programming languages (such as C and C#) are. Code written in gmSL can be embedded within gmPL scripts or can be in stand alone source files with the extension gmSL. The gmSL language fully supports gmPL equivalents of the main line gmPL statements and can be used as a substitute for gmPL in most cases. gmSL is a procedural language and does not reproduce the gmPL declaration statements. Finally, gmSL scripts can be converted into gmNI dynamic link libraries that are executed by the tool when certain events occur. The goal of gmSL is to enhance gmPL not to replace it.


First and foremost, gmSL is a compiled language. Its statements are converted into byte codes and those byte codes are then either executed immediately or are saved to be executed or authored at a later time. The byte codes themselves are 100% compatible with those used by gmBasic to compile the various source languages that it processes. The engine used to execute the byte codes is the same as the one used to evaluate constant expressions in source codes.


There are many contexts in which gmSL can be used to enhance a gmPL script. The following topics describe these contexts and are intended to serve as an introduction to the capabilities of gmSL. The remainder of this manual describes the details of the language.


As a simple example consider the following script, "HashTable1.xml", that translates a simple HashTable class written in VB6 into a .NET form.


<gmBasic>
  <Storage Action="Create" Identifier="HashTable1" />
  <Select Dialect="csh" />
  <Select AuthorLibrary="on" />
  <Select BuildFile="on" />
  <Select DeployLocation="\temp" />
  <Compile Project="..\vb6\HashTable.vbp" />
  <Analyse />
  <Output Status="New" Filename="..\csh\HashTable1.bnd" />
  <Author />
  <Storage Action="Close" />
</gmBasic>
This script produces a translation bundle containing the csproj file, the C# source, and the xml interface description file for the class. This discussion assumes that the reader is familiar with the gmPL language used in the above script. The focus of the dicussion here is on how gmSL can be used to enhance and/or change this script.


Note that throughout this discussion the simple notation pBasic command options is used to represent the command line that executes translation scripts. The actual manner in which command options are introduced is dependent upon the particular version/license of the tool set. See the discussion under the page gmCL.pBasic for a general discussion of these options. Also the actual source codes, scripts, and bundles referenced and/or discussed are illustrated in system metalang and the gmStudio Samples.

Embedding gmSL Expressions in gmPL Statements

The notation (%= ... %) is used to embed gmSL expressions in gmPL statements. Consider that except for the name of the code this script is a generic translation script that could be used in other simple contexts like this one. There is a Select attribute SrcPath that can be used to contain user supplied strings. Within gmSL expressions the values of the Select attributes can be referenced via the fully specified identifier "Select.attributeName" or simply "attributeName". The following script "HashTable2.xml"


<gmBasic>
  <Storage Action="Create" Identifier="(%= Select.SrcPath %)2" />
  <Select Dialect="csh" />
  <Select AuthorLibrary="on" />
  <Select BuildFile="on" />
  <Select DeployLocation="\temp" />
  <Compile Project="..\vb6\(%= SrcPath %).vbp" />
  <Analyse />
  <Output Status="New" Filename="..\csh\(%= SrcPath %)2.bnd" />
  <Author />
  <Storage Action="Close" />
</gmBasic>
when executed via the command line


pBasic HashTable2 SrcPath=HashTable
produces the same outputs as the original HashTable1.xml script.

Embedding gmSL Statements in gmPL Scripts

It is often convenient to be able to perform simple operations during the execution of a gmPL script that are not directly supported by gmPL. An easy way to do this is to embed gmSL statements in the script. The desired statements are enclosed within <gmSL> and </gmSL> tags or bounded by them. The statements themselves can be either be a simgle statement or multiple if the bounded form is used. They are executed immediately after the closing </gmSL> tag is encountered. The following script "HashTable3.xml"


 <gmBasic>
   <gmSL>System.LogMessage("Starting Translation of HashTable.vbp")</gmSL>
   <Storage Action="Create" Identifier="HashTable3" />
   <Select Dialect="csh" />
   <Select AuthorLibrary="on" />
   <Select BuildFile="on" />
   <Select DeployLocation="\temp" />
   <gmSL>
      System.LogMessage("Starting Compilation of HashTable.vbp")
      if(Select.Progress > 1) System.LogMessage "Compilation consists of two passes through the source code"
   </gmSL>
   <Compile Project="..\vb6\HashTable.vbp" />
   <gmSL>System.LogMessage("Starting Analysis of HashTable.vbp")</gmSL>
   <Analyse />
   <Output Status="New" Filename="..\csh\HashTable3.bnd" />
   <Author />
   <Storage Action="Close" />
   <gmSL>System.LogMessage("Completed Translation of HashTable.vbp")</gmSL>
 </gmBasic>
can be used to add additional progress messages to the processing of the script. The same outputs are produced. When executed via the command line


 pBasic HashTable3.xml Progress=1
gives the following log.


 Starting Translation of HashTable.vbp
 Starting Compilation of HashTable.vbp
 Loading reference:[Language.std] \gmIDF\Language.std.xml
 Reprocessing file: Transform.cls
 Reprocessing file: Transform.cls
 Processing file: ..\vb6\HashTable.vbp
 Loading reference:[StdOle2.tlb] \gmIDF\StdOle2.tlb.xml
 Reprocessing file: ..\vb6\HashTable.cls
 Reprocessing file: ..\vb6\HashTable.cls
 Starting Analysis of HashTable.vbp
 Loading reference:[MigrationSupport.dll] \gmIDF\MigrationSupport.dll.xml
 Completed Translation of HashTable.vbp
When executed via the command line


 pBasic HashTable3.xml progress=2
gives the following log in which the additional message appears.


 Starting Translation of HashTable.vbp
 Starting Compilation of HashTable.vbp
 Compilation consists of two passes through the source code
 Loading reference:[Language.std] \gmIDF\Language.std.xml
 Reprocessing file: Transform.cls
 Reprocessing file: Transform.cls
 Processing file: ..\vb6\HashTable.vbp
 Loading reference:[StdOle2.tlb] \gmIDF\StdOle2.tlb.xml
 Reprocessing file: ..\vb6\HashTable.cls
 Reprocessing file: ..\vb6\HashTable.cls
 Starting Analysis of HashTable.vbp
 Loading reference:[MigrationSupport.dll] \gmIDF\MigrationSupport.dll.xml
 Completed Translation of HashTable.vbp
Note gmSL does require a user storage area to compile; therefore, all such statements must follow gmPL Storage statement in the script.

Embedding gmSL Methods in gmPL Scripts

In addition to being able to introduce simple gmSL statements into a gmPL script, it is also possible introduce methods that perform operations during the execution of the script that are not directly supported by gmPL. The method can then be executed later by the gmPL RunComand statement. In the HashTable example being used in this discussion, everything goes well and the target code builds with no problems, but in examining that code


 int m_PrimaryIndex = 0;
 private int m_SecondaryIndex = 0;
 //  This variable is used to make the GetNextItem faster
 object m_GetNextValue = null;
 HashTableTyp m_HT = new HashTableTyp();
 public bool FindKey(string i_Key)
one wonders if it is possible to add the "private" modifier for some of the fields, that were declared with "Dim" in the original code instead of "Private".


 Dim m_PrimaryIndex As Integer
 Private m_SecondaryIndex As Integer
 ' This variable is used to make the GetNextItem faster
 Dim m_GetNextValue As Object

 Dim m_HT As HashTableTyp
There is presently no refactoring statement that can change the accessibility of a field to private; however, it can be done easily using an embedded gmSL method. Consider the following revised "HashTable4.xml" script.


 <gmBasic>
   <Storage Action="Create" Identifier="HashTable4" />
   <Select Dialect="csh" />
   <Select AuthorLibrary="on" />
   <Select BuildFile="on" />
   <Select DeployLocation="\temp" />
   <gmSL Class="Demo" >
   void MakePrivate(string identifier)
   {
      int iRoot;
      tVariable varInfo;

      iRoot = Symbol.FindIdentifier(identifier);
      if(iRoot)
      {
         varInfo = Store.DeltaVector(iRoot);
         varInfo.Private = True;
         System.LogMessage("Changed status of " + Symbol.FullName(iRoot,1) + " to Private") ;
      }
      else System.LogMessage("Could not locate " + identifier);
   }
   </gmSL>
   <Compile Project="..\vb6\HashTable.vbp" />
   <RunCommand id="MakePrivate" Prams="HashTableProject.HashTable.m_PrimaryIndex" />
   <RunCommand id="MakePrivate" Prams="HashTableProject.HashTable.m_GetNextValue" />
   <RunCommand id="MakePrivate" Prams="HashTableProject.HashTable.HelpFile" />
   <RunCommand id="MakePrivate" Prams="HashTableProject.HashTable.m_HT" />
   <Analyse />
   <Output Status="New" Filename="..\csh\HashTable4.bnd" />
   <Author />
   <Storage Action="Close" />
 </gmBasic>
The MakePrivate method is the one that will set the private attribute for the specified fields to true. It is this change that is needed so that the target declarations for these symbols will be "private". If the method finds the symbol whose fully qualified identifier is in the parameter identifier then it also logs a success message to the log file; else it logs a failure message. The RunCommand statement needed has its id attribute set to the name of the method and its Prams attribute set to the identifiers of the fields to be changed. Note that the HelpFile field does not exist. The resultant log file is as expected


Setting components to Private
Changed status of HashTableProject.HashTable.m_PrimaryIndex to Private
Changed status of HashTableProject.HashTable.m_GetNextValue to Private
Could not locate HashTableProject.HashTable.HelpFile
Changed status of HashTableProject.HashTable.m_HT to Private
Comparing the two translation bundles


 ***** HashTable4.bnd
    <class id="HashTable" parent="IDispatch" default="Value">
       <method id="FindKey" type="Boolean">
 ***** HASHTABLE1.BND
    <class id="HashTable" parent="IDispatch" default="Value">
       <field id="m_PrimaryIndex" type="Integer" status="InOut"/>
       <field id="m_GetNextValue" type="Object" status="InOut"/>
       <field id="m_HT" type="HashTableProject.HashTable.HashTableTyp" status="InOut"/>
       <method id="FindKey" type="Boolean">
 ***** HashTable4.bnd
       }
       private int m_PrimaryIndex = 0;
       private int m_SecondaryIndex = 0;
 ***** HASHTABLE1.BND
       }
       int m_PrimaryIndex = 0;
       private int m_SecondaryIndex = 0;
 ***** HashTable4.bnd
       //  This variable is used to make the GetNextItem faster
       private object m_GetNextValue = null;
       private HashTableTyp m_HT = new HashTableTyp();
       public bool FindKey(string i_Key)
 ***** HASHTABLE1.BND
       //  This variable is used to make the GetNextItem faster
       object m_GetNextValue = null;
       HashTableTyp m_HT = new HashTableTyp();
       public bool FindKey(string i_Key)
does show that the accessibility of the three fields has been changed. Notice in particular that the declarations of the now private fields have also been removed from the interface description of the class.

Writing Stand Alone gmSL Methods

Methods written in gmSL do not have to be embedded directly in the gmPL scripts. They can be entered in stand alone files with the extension gmSL which can be loaded into the script. Consider this file "MakePrivate.gmsl"


void MakePrivate(string identifier)
{
  int iRoot;
  tVariable varInfo;

  iRoot = Symbol.FindIdentifier(identifier);
  if(iRoot)
  {
     varInfo = Store.DeltaVector(iRoot);
     varInfo.Private = True;
     System.LogMessage("Changed status of " + Symbol.FullName(iRoot,1) + " to Private") ;
  }
  else System.LogMessage("Could not locate " + identifier);
}
which contains the same method as defined in the previous example. It can then be used by this script "HashTable5.xml".


<gmBasic>
  <Storage Action="Create" Identifier="HashTable5" />
  <Select Dialect="csh" />
  <Select AuthorLibrary="on" />
  <Select BuildFile="on" />
  <Select DeployLocation="\temp" />
  <gmSL Class="Demo" source="..\gmsl\MakePrivate.gmsl" />
  <Compile Project="..\vb6\HashTable.vbp" />
  <RunCommand id="MakePrivate" Prams="HashTableProject.HashTable.m_PrimaryIndex" />
  <RunCommand id="MakePrivate" Prams="HashTableProject.HashTable.m_GetNextValue" />
  <RunCommand id="MakePrivate" Prams="HashTableProject.HashTable.HelpFile" />
  <RunCommand id="MakePrivate" Prams="HashTableProject.HashTable.m_HT" />
  <Analyse />
  <Output Status="New" Filename="..\csh\HashTable5.bnd" />
  <Author />
  <Storage Action="Close" />
</gmBasic>
to produce the identical result as in the previous example.

Writing Stand Alone gmSL scripts

Not just methods, but entire stand alone scripts can be written using gmSL. The following file "HashTable.gmsl"


Execute.Storage Action := "Create", Identifier := "HashTable"
Select.Dialect = Dialects.csh
Select.AuthorLibrary = AuthorLibType.On
Select.BuildFile = BuildFileStatus.On
Select.DeployLocation = "\temp"
Execute.Compile Project := "..\vb6\HashTable.vbp"
Execute.Analyse
Execute.Output Status := "New", Filename := "..\csh\HashTable.bnd"
Execute.Author
Execute.Storage Action := "Close"
contains gmSL statements that perform the same operations as those presented in the original translation scripts. The Select attributes are fields in a Select class and the various gmPL mainline execution statements are methods in an Execute class. The gmSL language supports named arguments so that the calls to methods can look more like their original gmPL forms. For example the Execute.Storage method is defined as follows in the language files.


<Method id="Storage" type="void" opcode="SCM.Execute_Storage" >
   <Argument id="action" type="String" status="ByVal" optional="NULL" />
   <Argument id="identifier" type="String" status="ByVal" optional="NULL" />
   <Argument id="startup" type="String" status="ByVal" optional="NULL" />
 </Method>
When executed via the command line


pBasic HashTable.gmsl
the resultant bundle file "HashTable.bnd" is identical to the one produced by the original "HashTable1.xml".

Saving gmSL Methods in a Virtual Binary Information File

Previous examples have shown various ways in which gmSL source code can be introduced into translation scripts or executed directly. Methods written in gmSL can also be precompiled and stored in a virtual binary information file. In fact many of the operations performed by the tool set are actually implemented via gmSL methods stored in the vb7Lang.vbi language information file.


Consider the following script "HashTable6.xml" which contains the same gmSL statements discussed above, except that the name of the output file is specified via the field Select.BndPath.


<gmBasic>
<Storage Action="Create" Identifier="HashTable6" />
<gmSL namespace="RuntimeDll" class="Methods" >
void HashTable6()
{
   Execute.Storage Action := "Create", Identifier := "HashTable"
   Select.Dialect = Dialects.csh
   Select.AuthorLibrary = AuthorLibType.On
   Select.BuildFile = BuildFileStatus.On
   Select.DeployLocation = "\temp"
   Execute.Compile Project := "..\vb6\HashTable.vbp"
   Execute.Analyse
   Execute.Output Status := "New", Filename := Select.BndPath
   Execute.Author
   Execute.Storage Action := "Close"
}
</gmSL>
<Storage Action="Close" />
</gmBasic>
When processed by the tool this script creates a file "HashTable6.vbi" that contains the compiled form of the method. Here is the audit of the content of this information file.


Audit of Symbol tree in HashTable6.vbi storage area:
Lev |  Address |   Parent | Symbol Type                    | Full Symbol Identifier
--- |  ------- |   ------ | -----------                    | ----------------------
  1 |     2119 |        0 | ProjectFile                    | RuntimeDll.Methods.slp
  2 |     3240 |     2119 | ClassFile                      | Methods.cls
  3 |     3423 |     3240 | Subprogram                     | RuntimeDll.Methods.HashTable6
  2 |     3342 |     2119 | Vb_Name                        | RuntimeDll.Methods
  1 |     3382 |        0 | Vb_Name                        | RuntimeDll
The compiled form of gmSL uses the same gmIL intermediate language as is used to compile the other source languages processed via this tool set. The operations themselves are executed via the same engine and the operations can be authored in the same way as well. To review here is the start of the actual codeblock showing the compiled form of the first statement.


Actual csh Codeblock Associated with HashTable6:
Offset |  Sl.Start |  Ql.Start | Quantity type        | Opcode | Operation support information
------ |  -------- |  -------- | -------------        | ------ | -----------------------------
     0 |           |           |                      | LEV    | Nest0
     2 |       1.2 |       1.2 | String               | LSC    | 6:Create
     7 |       1.2 |           |                      | ARG    | String
     9 |       1.2 |           |                      | LEV    | Nest0
    11 |      2.11 |      1.11 | String               | LSC    | 24:\gmManual\csh\HashTable6
    16 |      2.11 |           |                      | ARG    | String
    18 |      2.11 |           |                      | LEV    | Nest0
    20 |      3.20 |      1.20 | Variant              | SPV    | Null
    22 |      3.20 |           |                      | ARG    | String
    24 |           |      1.24 | Void                 | SCM    | Execute_Storage
The following script "HashTable7.xml" can be used to execute this method.


<gmBasic>
   <gmSL>Store.Open("HashTable6.vbi",StorageUnit.METHODS,0)</gmSL>
   <Select BndPath="..\csh\HashTable7.bnd" />
   <RunCommand id="HashTable6" />
</gmBasic>
When executed via the command line


pBasic HashTable7.xml
the resultant bundle file "HashTable7.bnd" is identical to the one produced by the original "HashTable1.xml" script.

Converting gmSL Methods in gmNI Runtime Libraries

The same binary information file whose "HashTable6" method was executed above can also be used to create a gmNI runtime library. The "Hashtable8.xml" script below uses a method Gemini.AuthorExecuteCommandDll stored in the vb7Lang.vbi language information file to produce a file "gmNI\Hashtable.bnd. It should be noted that all methods stored in the language file are written in gmSL


<gmBasic>
   <Storage Action="Create" />
   <Select DeployLocation="..\gmNI" />
   <Select Library="\gmTools\gmnidll" />
   <Select BuildFile="on" />
   <RunCommand Id="Gemini.AuthorExecuteCommandDll" Prams="HashTable6;..\gmNI\HashTable.bnd" />
   <Storage Action="Close" />
</gmBasic>
The bundle file produced contains the following files and instructions.


HashTable6Migration.c
HashTable6Migration.lnk
HashTable6.c
EXECUTE instructions to do the build
The gmPL documentation contains details about these files. To summarize they contain the code needed to implement an ExecuteCommand event handler; the linkage instructions needed to build the runtime dll; the actual code needed to execute a HashTable6 command; the actual implementation of the HashTable6() method; and finally the build commands needed to create the runtime dll. The following deployment command then


Deploy HashTable.bnd DEPLOY
creates the file "gmni\HashTable6Migration.dll" which can then be used to do the same translation as produced by "HashTable7.xml" above. The file "HashTable9.xml" below does this.


<gmBasic>
  <LoadRuntime FileName="..\gmNI\HashTable6Migration.dll" />
  <Select BndPath="..\csh\HashTable9.bnd" />
  <HashTable6 />
/gmBasic>
Remember that the gmPL processor, when it sees a command like "HashTable6" that it does not recognize, checks to see if it names a currently loaded ExecuteCommand event handler. When executing this script


pBasic HashTable9.xml
the resultant bundle file "HashTable9.bnd" is identical to the one produced by the original "HashTable1.xml" script.
Table of Contents