How to intercept, parse and compile?

553 views Asked by At

This is a problem I've been struggling to solve for a while. I need a way to either replace code in the method with a parsed code from the template at compile time (PostSharp comes to mind) or to create a dynamic proxy (Linfu or Castle). So given a source code like this

[Template]

private string GetSomething()

{

var template = [%=Customer.Name%]

}

I need it to be compiled into this

private string GetSomething()

{

MemoryStream mStream = new MemoryStream();

            StreamWriter writer = new StreamWriter(mStream,System.Text.Encoding.UTF8);

writer.Write(@"" );

writer.Write(Customer.Name);

StreamReader sr = new StreamReader(mStream); 

writer.Flush();

mStream.Position = 0; 

return sr.ReadToEnd();

}

It is not important what technology is used. I tried with PostSharp's ImplementMethodAspect but got nowhere (due to lack of experience with it). I also looked into Linfu framework. Can somebody suggest some other approach or way to do this, I would really appreciate. My whole project depends on this.

Assumptions:

  1. Code can appear in any class.
  2. Template code will always be annotated with attribute [Template]
  3. Template method will always return string.

Parsing of the code from one form to another is already done. Now I just need a way to replace it.

"Beefer" example:

  [Test]
        public void can_parse_csharp_code_template3()
        {
            var template = @"<template> [%= GetUsing() %]
    namespace [%= GetModelNamespaceName(.metaPackage) %]
    {
    [%= .visibility.ToString().ToLower() %] class [%= .Name %] : INotifyPropertyChanged [%= If(.IsPersistent, "", PersistenObject"", """") %]
        {
            #region Constructors
            [%= ConstructorTemplate.Create(metaObject).GetParameterlessConstructorCode %]
            #endregion

            #region Attributes

            [%= From attribute In metaObject.attributes _
                Select (AttributeTemplate.Create(attribute).GetSourceCode) %]
            #endregion

            #region Relationships
            [%= From relationship As Relationship In metaObject.relationships _
                Select (RelationshipTemplateFactory.CreateFor(relationship).GetSourceCode()) %]
            #endregion

            #region Methods
            [%= From operation In metaObject.operations _
                Select (MethodTemplate.Create(operation).GetSourceCode) %]
            #endregion

            #region ""INotifyPropertyChanged""
            [%= GetOnPropertyChanged() %]
            #endregion
            }
        }</template>";

            Console.WriteLine(TemplateParser.GetParsedResult(template));

        }
2

There are 2 answers

4
dtb On BEST ANSWER

Have a look at T4 (Text Template Transformation Toolkit).

<#@ template language="C#v3.5" #>
<#@ assembly name="System.Core" #>
<#@ output extension=".cs" encoding="utf-8" #>

private string GetSomething()
{
    <# Generate("Customer.Name"); #>
}

<#+
private void Generate(string s)
{
    WriteLine(@"MemoryStream mStream = new MemoryStream();");
    // ...
}
#>
1
Ira Baxter On

A tool that can parse C#, pick out attributes, and transform that code any way you'd like, is the DMS Software Reengineering Toolkit and its C# Front End.

DMS parses your files, builds full abstact syntax trees, and allows you to write custom transformations that can expand a point in the text (what most code generators like T4 do) or more importantly replace any construct (both local and/or distributed across the set of files that make up the application) with any other code you might like to generate.

You appear to have some idea about the metalanguage for producing code fragments, e.g.,

  From operation In metaObject.operations _ 
            Select (MethodTemplate.Create(operation).GetSourceCode) 

That metalanguage AFAIK isn't C#. With DMS, you can define a parser for the metalanguage, and process the meta langauge into trees as the code generator encounters the constructs. With a small interpreter over such trees, you can convert metalnguage text into generator actions producing the text of interest.

[I'm the CTO behind DMS].