Hi,
I was trying to use Galois.Net to specify code generators and I had to look for
some text template tool to simplify the syntax. I was looking for something similar
to the syntax of an Asp.Net page; for example, a template file could look like
the following:
<%@ Assembly Name="ReturnStr ing.dll" %>
<html>
<title>Testin g generator</title>
<body>
<p>
Hello <%= ReturnString.Va l() %>
<p>
</body>
</html>
and if the ReturnString.dl l is compiled from the following code:
public class ReturnString {
public static string Val() {
return "World";
}
}
we should expect the output to be:
<html>
<title>Testin g generator</title>
<body>
<p>
Hello World
<p>
</body>
</html>
I wrote such a tool and I decided to post here because it might save
other people a few hours of works since it was not completely trivial.
Galois.Net can be found at http://www.a2ii.com/galois/index.htm .And
using it to specify code generators, I have the impression that "I'm going
places".
I haven't done much testing but it was sufficient for my need. To use
it, you should compile the code below e.g. "csc TextTemplateToo l.cs".
And run it, with the command: "TextTemplateTo ol hello.txt" where
you saved the template text above in a file named "hello.txt" . (You
should also have compiled the ReturnString.dl l assembly i.e.
csc /out:library ReturnString.cs ). NOTE: the "code behind" facility
expect the dll to be in the same directory as the application).
I have tried to keep the code to a strict minimum. You shouldn't
have problems extend it to suit your needs.
Cheers,
-daniel
=============== =========
Daniel Perron, Ph.D.
Lead Developer, Galois.Net
+++++++++++++++ +++++++++++++++ +++++++++++++++ ++
using System;
using System.Text;
using System.Text.Reg ularExpressions ;
using System.IO;
using System.Collecti ons;
using System.Reflecti on;
using System.CodeDom. Compiler;
using Microsoft.CShar p;
class TextTemplateToo l {
//the code that is included at the beginning of
//every program
static string prologue = @"
using System;
using System.Collecti ons.Specialized ;
public class _templateGenera tion
{
public static void Main()
{
";
//the code that is included at the end of
//every program
static string epilogue = @"
}
}
";
public static void Main( string [] argv ) {
StreamReader rd = new StreamReader( argv[0] );
string input = rd.ReadToEnd();
StringBuilder buffer = new StringBuilder() ;
buffer.Append( prologue );
//assemblies will contain the list of referenced
//assemblies used in the template
ArrayList assemblies = new ArrayList();
//This regex will be used to identify the processing code
//in the template; we'll be looking for the string <% ... %>.
//To allow for code spanning multiple lines, we want to let
// the . in a regex to match a end of line so we use the given option
Regex exp = new Regex( "(<%.*?%>)" , RegexOptions.Si ngleline );
string [] chunks = exp.Split( input );
string cleanup;
for( int i = 0; i < chunks.Length; i++ )
{
if( chunks[i].StartsWith("<% =") )
{
cleanup = chunks[i];
cleanup = cleanup.Substri ng(3,cleanup.Le ngth-5);
buffer.Append( string.Format(" Console.Write({ 0});", cleanup.Trim() ));
}
else if( chunks[i].StartsWith("<% @" ) )
{
//we want to get the name of the assembly
//inside the "..."
Regex asm = new Regex( "\".*\"" );
cleanup = asm.Match( chunks[i] ).Value;
cleanup = cleanup.Substri ng(1,cleanup.Le ngth-2);
//we allow to use "code behind" from assembly in
//the same directory as the application
string path = AppDomain.Curre ntDomain.BaseDi rectory;
assemblies.Add( path + cleanup.Trim() );
}
else if( chunks[i].StartsWith("<% ") )
{
cleanup = chunks[i];
cleanup = cleanup.Substri ng(2,cleanup.Le ngth-4);
buffer.Append( cleanup.Trim() );
}
else
{
buffer.Append( string.Format(" Console.Write(@ \"{0}\");", chunks[i] ));
}
}
buffer.Append( epilogue );
//get ready to generate an assembly
CSharpCodeProvi der provider = new CSharpCodeProvi der();
ICodeCompiler compiler = provider.Create Compiler();
CompilerParamet ers options = new CompilerParamet ers();
options.Generat eInMemory = true;
options.Generat eExecutable = true;
options.Referen cedAssemblies.A dd("System.dll" );
if( assemblies.Coun t > 0 )
foreach( object asm in assemblies )
options.Referen cedAssemblies.A dd( (string)asm );
CompilerResults results = compiler.Compil eAssemblyFromSo urce(options,
buffer.ToString ());
if (results.Errors .Count == 0)
//if there is no error run the generated program
//that will write to the console the template with
//the given substitution
results.Compile dAssembly.Entry Point.Invoke(nu ll, null);
else
Console.WriteLi ne("*** Syntax Errors ***");
}
}