The CodeDOM and the Delphi IDE

The CodeDOM and the Delphi IDE By Corbin Dunn

Borland R&D Software Engineer

cdunn@borland.com

 

What is the CodeDOM?

 

The Code Document Object Model (CodeDOM) allows .NET developers to generate and compile source code at run time in a variety of languages. The CodeDOM is a collection of classes used to represent source code. Once source code is represented in a CodeDOM, it can then be printed, compiled to an assembly, or compiled to memory and executed. An application can also use the CodeDOM as an abstract layer for reading source code without having intrinsic knowledge of the underlying language.

 

The WinForms / WebForms Designers

 

The most predominant uses of the CodeDOM are in the WinForms and WebForms designers of the .NET Framework. These designers require a CodeDOM to be provided for them, and walk the DOM looking for types that can be designed. Once a type is found, they look for the InitializeComponents method and walk each statement in the method, executing them as it does along. The end result is a deserialized form (or web) designer.

 

When changes are made to the form designer, the current state of the designer is flushed out to a CodeDOM object. This object can then be injected back into the original source code. By using an abstract set of classes, the WinForms and WebForms designers do not need to know anything about the underlying programming language.

 

ASP.NET

 

ASP.NET also uses the CodeDOM. When ASPX pages have source code mixed in, the ASP.NET engine must some how compile this source. One of the underlying problems stems from the fact that someone can write an ASPX page in a variety of different languages. In order to keep it well abstracted, the ASP.NET engine creates a CodeDOM for the page. The CodeDOM is language independent, making the engine able to manipulate any language that has a CodeDOM provider. It can then compile the CodeDOM to an assembly, execute it, and return the resulting HTML.

 

CodeDOM Basics

 

Using the CodeDOM is fairly straightforward. To get a better grasp of it, I highly recommend reading the help:

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconGeneratingCompilingSourceCodeDynamicallyInMultipleLanguages.asp

 

Plus, the CodeDOM Quick Reference is indispensable:

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconCodeDOMQuickReference.asp

 

General CodeDOM Overview

 

The System.CodeDom namespace contains all the classes used to construct a CodeDOM. The basic containership is as follows:

 

CodeCompileUnit

Contains everything and is the top level CodeDOM object. It primarily contains one or more CodeNamespace objects.

CodeNamespace

Represents a namespace in source code. The namespace can contain types that are in that namespace. Each type is a CodeTypeDeclaration or a descendant thereof.

CodeTypeDeclaration

The basic CodeTypeDeclaration is used to represent classes, enumerations, interfaces, and structures (records). A CodeTypeDelegate is used to represent a delegate (which is an event declaration). The CodeTypeDeclaration contains CodeTypeMembers to represent the members in the type.

CodeTypeMember

This is the base abstract class for all type members. There are things to represent all basic code members, including: CodeMemberMethod, CodeMemberField, CodeMemberProperty, CodeConstructor, and a CodeTypeConstructor (a class constructor). Most CodeTypeMembers can have attributes applied to them; this is done via a CodeAttributeDeclaration, which, unlike most all the other classes, does not descend from CodeObject.

CodeAttributeDeclaration

This class allows you to specify an attribute. It basically contains the name of the attribute, and any arguments passed to it (which are also represented by CodeDOM objects).

CodeMemberMethod

The CodeMemberMethod  contains Statements each of which are an instance of a CodeStatement object.

CodeStatement

The CodeStatement is the base class for all statements. There are CodeAssignStatement,  CodeConditionStatement (used for if or while) along with many others. Each statement is generally made of up expressions (or it is an expression, with the CodeExpressionStatement), represented by the CodeExpression abstract class.

CodeExpression

Represents all expressions. Expressions include ways of referencing fields, properties, and variables (CodeFieldReferenceExpression, CodePropertyReferenceExpression, and CodeVariableReferenceExpression), along with ways of invoking events, or referencing primitive values (such as integers, or strings).

CodeSnippetXXX

The CodeSnippetXXX classes (such as CodeSnippetExpression) are useful for representing a snippet of source code that cannot be represented in the CodeDOM. The problem with snippets is that they are language dependent.

CodeObject

The CodeObject class is the base abstract class for most all of the other CodeDOM classes. The main thing that it introduces is the UserData property; allowing a user of the CodeDOM to store information in a particular CodeObject.

 

But what can you do with CodeDOM objects once you have created them? The System.CodeDom.Compiler namespace has most of the classes and interfaces used to do things with a CodeDOM.

 

One thing you may want to do, is print the CodeDOM in a particular language. To do this, you must get a code generator (ICodeGenerator) for that particular language. An ICodeGenerator is generally acquired through a CodeDomProvider. A CodeDomProvider also allows you to create a code compiler (ICodeCompiler) to compile the code.

 

For example of this, see the included source code.

 

Creating a CodeDOM in Delphi Code

 

Create a CodeDOM is very easy. You first create a CodeCompileUnit (since it contains everything else) and then add a namespace to it. The namespace can then specify what other namespaces (or units) that it uses:

 

var

  Namespace: CodeNamespace;

begin

  // Create the primary code unit that contains everything

  FCodeUnit := CodeCompileUnit.Create;

  // Create a namespace and add it to that unit

  Namespace := CodeNamespace.Create(‘MyUnitName’);

  FCodeUnit.Namespaces.Add(Namespace);

  // Add a few items to the "uses" clause

  Namespace.Imports.Add(

    CodeNamespaceImport.Create(‘System.Collections’));

  Namespace.Imports.Add(

    CodeNamespaceImport.Create(‘System.Data’));

  Namespace.Imports.Add(

     CodeNamespaceImport.Create(‘System.Xml’));

 

Unfortunately, one of the drawbacks of using the CodeDOM is that it doesn’t know about the Delphi language. There is no way to specify for a CodeNamespaceImport to be in the implementation section’s uses clause.

 

The next thing you will want to do is add one ore more types to the CodeDOM. The CodeDOM has no knowledge of global procedures or units, so unfortunately there is no way of adding them at this time (although, this may change at some later time).

 

var

 

  MyType: CodeTypeDeclaration;

begin

 

  // Create a type and add it to the namespace

  MyType := CodeTypeDeclaration.Create(‘TMyClass’);

  Namespace.Types.Add(MyType);

 

A blank type isn’t very interesting, so you probably should add some members to it:

 

var

 

  MyMethod: CodeMemberMethod;

  MyField: CodeMemberField;

begin

 

  // Now add a field to the members in the type

  MyField := CodeMemberField.Create(‘Integer’, ‘FInt’);

  MyType.Members.Add(MyField);

  // Create method to put in this type

  MyMethod := CodeMemberMethod.Create;

  MyMethod.Name := ‘MyMethod’;

  MyType.Members.Add(MyMethod);

 

The real interesting part is adding statements and expressions to the method:

 

var

 

  Statement: CodeStatement;

  LeftExpr, RightExpr: CodeExpression;

  MethodExpr: CodeExpression;

  Target: CodeTypeReferenceExpression;

  VarReference: CodeVariableReferenceExpression;

begin

   

  // Create a variable, and assign a value to it.

  Statement := CodeVariableDeclarationStatement.Create(’string’, 

‘LocalStr’);

  MyMethod.Statements.Add(Statement);

  // Assign a value to that variable

  LeftExpr := CodeVariableReferenceExpression.Create(‘LocalStr’);

  RightExpr := CodePrimitiveExpression.Create(‘LocalValue’);

  Statement := CodeAssignStatement.Create(LeftExpr, RightExpr);

  MyMethod.Statements.Add(Statement);

 

  // Write it out to the console

  Target := CodeTypeReferenceExpression.Create(‘System.Console’);

  VarReference := CodeVariableReferenceExpression.Create(‘LocalStr’);

  MethodExpr := CodeMethodInvokeExpression.Create(

    Target, // The thing we are calling on

    ‘WriteLine’, // The method we are going to call

    [VarReference]); // Parameters

  MyMethod.Statements.Add(MethodExpr);

Posted by Corbin Dunn on September 30th, 2004 under Uncategorized |



5 Responses to “The CodeDOM and the Delphi IDE”

  1. Joe White Says:

    Does the Open Tools API provide CodeDOM even for Win32 projects? Or is it just for .NET projects?

  2. Corbin Dunn Says:

    for native too.

  3. chest-pains-o-t- Says:

    <a href=http://chest-pains9197.blogspot.com/&gt;chest pains</a>

  4. clive henson Says:

    Are there utilities that will convert a CodeDOM back to a target language. I am going to need to convert existing code from Delphi to C# in order to compile for the Compact Framework which Delphi does not currently support.

  5. Corbin Dunn Says:

    i don’t think that is true; delphi apps can compile to the compact framework. the vcl isn’t on there, however.


Server Response from: blogs2.codegear.com

 
Copyright© 1994 - 2008 Embarcadero Technologies, Inc. All rights reserved. Contact Us   Legal Notices   Privacy Policy   Report Software Piracy