59
Code Generation SuperSet Code Generation

Code Generation

  • Upload
    reegan

  • View
    29

  • Download
    2

Embed Size (px)

DESCRIPTION

Code Generation. SuperSet Code Generation. Template Definition. A pattern or gauge, such as a thin metal plate with a cut pattern, used as a guide in making something accurately, as in woodworking or the carving of architectural profiles (the free Online Dictionary). Text Template. - PowerPoint PPT Presentation

Citation preview

Page 1: Code Generation

Code Generation

SuperSet Code Generation

Page 2: Code Generation

A pattern or gauge, such as a thin metal plate with a cut pattern, used as a guide in making something accurately, as in woodworking or the carving of architectural profiles (the free Online Dictionary).

Template Definition

Page 3: Code Generation

A textual pattern used as a guide the generation of text.

Text Template

Page 4: Code Generation

A textual pattern used as a guide the generation of text.

Text Template

<#foreach(System.Data.DataRow row in schema.Rows){ #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { }<#} #>

public class A1 { } public class A2 { } public class A3 { }

Page 5: Code Generation

Template EvolutionLevel 0: no template mechanism

A function or group of functions generatecode through a set of print statements basedon configurative information.

- Hard to change both text structure and meta-data

Output.print_line(~~~~~~~~~~~~~~~~~~~~);Output.print_line(~~~~~~~~~~~~~~~~~~~~);Output.print_line(~~~~~~~~~~~~~~~~~~~~);If (~~~~) then { Output.print_line(~~~~~~~~~~~~~~~~~~~~); Output.print_line(~~~~~~~~~~~~~~~~~~~~);}

Page 6: Code Generation

Template EvolutionLevel 1: accidental templates

A function or group of functions generatecode by applying substitution to stringtemplate fragmented throughout theprogram

- Still hard to change the model or the template.

- Inferring the target code’s structure requires understanding of the program’s logic.

String s = “~~~~~~~~%name%~~~~~~~~~”Output.print_line(s1.Replace(“%name%”,name);

Page 7: Code Generation

Template EvolutionLevel 2: Place Holder Templates

The textual annotative code is organized astemplates in files external to the generationengine that substitute variables for contentin a generator specific way

+ Template can be changed without changing the generator

- Proprietary template syntax - Proprietary substitution mechanism- Model extensions may require generator changes.

<html>!!Header_Content!!!!Body!!</html>

Page 8: Code Generation

Template EvolutionLevel 3: Scripted Templates

code generators support templates thatinclude scripting for accessing andsubstituting template variables.

class <%=xo.GetName()%> {<% foreach x in xo.getList()%> <%=x.GetDataType()%> v<%=x.GetName()%>; <%=x.GetDataType()%> get<%=x.GetName()%>{ return v<%=x.GetName()%>; } void set<%=x.GetName(<%=x.GetDataType()%> p<%=x.GetName()%>) { v<%=x.GetName()%>=p<%=x.GetName()%>; } <%}%>

Page 9: Code Generation

Scripted TemplatesBenefits:

• Both model and template can be changed without affecting the generator.

• Standardized substitution mechanism.

Page 10: Code Generation

Scripted TemplatesHowever, the template and the model access code are stillintermixed:

• Miscoding pitfalls due to the superposition of the codes .

• Incomprehensible and incoherent code.

• Cumbersome development, test and debug process.

• Restricted flexibility of the generated text’s structure.

• Limited textual expressive power.

• Unnecessary dependency on model access code changes.

• Replicated code that burdens the development process.

Page 11: Code Generation

Scripted TemplatesMiscoding pitfalls due to the superposition of the code.

using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); … SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } } } }

Page 12: Code Generation

Scripted Templates

using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); … SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } } does not belong to the code but rather to the model access code. } }

Miscoding pitfalls due to the superposition of the code.

Page 13: Code Generation

Scripted Templates

using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); … SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } }

Miscoding pitfalls due to the superposition of the code.

Page 14: Code Generation

Scripted TemplatesIncomprehensible and incoherent code.

<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #> <#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}

C# code that belongs to the mode access code

Sql code in the data model code

Textual code

Formatting code

Page 15: Code Generation

Scripted TemplatesCumbersome development and debug process.

<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #> <#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}

C# debugging goes here

Sql query debugging here

Text issues addressed here

Wrong format in here

Page 16: Code Generation

Scripted TemplatesRestricted flexibility of the generated text’s structure.

Function <%=X%> (

<%foreach …prm….%>

<%=prm.datatype%> <%=prm.name%>

<% if ….. %> , <%endif%>

<%endif%>

)

{

}

Function Fnc1 (string prm1 , string prm2 , integer prm3 )

{

..

}

Function Fnc1 (

string prm1 ,

string prm2 ,

int prm3

)

{

..

}

Page 17: Code Generation

Scripted TemplatesLimited textual expressive power.

Create procedure getT1RowValues(

@Key1 int in, @Key2 varhcar in,

@val1 int out, @val2 varchar(20) out = ‘world’, @val3 varchar(20) out )

as

Select @val1=val1, @val2=val2, @val3=val3

From T1

Where key1=@key1 and key2=@key2

Page 18: Code Generation

Scripted TemplatesUnnecessary dependency on model access code changes

Function <%=X%> (

<%foreach …prm…in (select …from A) .%>

<%=prm.datatype%> <%=prm.name%>

<% if ….. %> , <%endif%>

<%endif%>

)

{

}

Function <%=X%> (

<%foreach …prm…in (select … from b) .%>

<%=prm.datatype%> <%=prm.name%>

<% if ….. %> , <%endif%>

<%endif%>

)

{

}

Page 19: Code Generation

Scripted TemplatesReplicated code that burdens the development process.

private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(),dc.ColumnName[0].ToString().ToLower()) #>;public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; }}

- Replicated code in the same template as well as code replication that is caused by copying data access code into several templates.

- Designing, testing, debugging and correcting anything but very trivial model access code becomes a prohibitively costly effort.

Page 20: Code Generation

Separation of ConcernsAnnotative information and model accesscode are separated aspects of codegeneration. Mixing them makes it difficult tomaintain both.

Page 21: Code Generation

Separation of Concerns• Makes it possible to view a description as a set of

coherent and focused concerns.

• Different concerns may require different approaches.

• Different concerns may require different skill sets.

Page 22: Code Generation

Separation of Concerns• Makes it possible to view a description as a set of

coherent and focused concerns.

• Different concerns may require different approaches.

• Different concerns may require different skill sets.

Page 23: Code Generation

<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}

Template Separation of Concerns

Page 24: Code Generation

<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}

Template Separation of Concerns

Page 25: Code Generation

Template Separation of Concerns<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}

=>Model access code block

=>Model access code block

=>Model access code block

Page 26: Code Generation

Template Separation of Concerns<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>

using System;namespace MyProject.Entities{

<# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #>

public class <#= row["TABLE_NAME"].ToString().Trim('s') #> {

<# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #>

private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return xxx ;} _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set ={ value = xxx ; } _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> }

<# } #>

}

Page 27: Code Generation

Encapsulationusing System;namespace MyProject.Entities{ public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } } }

<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>

The expression is replaced with $ColName$.

Page 28: Code Generation

Encapsulationusing System;namespace MyProject.Entities{ public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { private <#= dc.DataType.Name #> _$ColName$; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _$ColName$; } set { _$ColName$ = value; } } } }

<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>

$ColName$ encapsulates the substitution expression that belongs to the transformation layer rather than the template.

Page 29: Code Generation

Encapsulationusing System;namespace MyProject.Entities{ public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { private <#= dc.DataType.Name #> _$ColName$; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _$ColName$; } set { _$ColName$ = value; } } } }

Replace $TableName$ for <#= row["TABLE_NAME"].ToString().Trim('s') #> $DataType$ for <#= dc.DataType.Name #> $CSharpAttributeName$ for <#= dc.ColumnName #>

Page 30: Code Generation

Abstract Templateusing System;namespace MyProject.Entities{ public class $TableName$ {[ private $DataType$ _$ColName$; ^\n][ public $DataType$ $CSharpAttributeName$ { get { return _$ColName$; } set { _$ColName$ = value; } } ^\n] } }

Page 31: Code Generation

Abstract Template

• Structural Clarity• Abstraction of Text• Readability• Model Access Code Reuse• Transformational Error Reduction • Textual Expressive Power• Traceability• Analyzability

Page 32: Code Generation

Abstract Template<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}

using System;namespace MyProject.Entities{ public class $TableName$ { private $DataType$ _$ColName$ public $DataType$ $CSharpAttributeName$ { get { return _$ColName$; } set { _$ColName$ = value; } } } }

model content provided as a relational set.

Page 33: Code Generation

Abstract TemplateLevel 4: Abstract Templates

abstract, coherent, template centric representation of text.

• Annotated Models: models with annotative information. • Text centric: do not include model access code.• Abstract: represents a meta-description of the text.

Page 34: Code Generation

Template Structure

Hidden Assumptions: • DataType, ColName and CSharpAttributeName are in

the context of TableName.• The annotative text is at a line boundary • There are no separators such as “and” or “,”.

using System;namespace MyProject.Entities{ public class $TableName$ { private $DataType$ _$ColName$ public $DataType$ $CSharpAttributeName$ { get { return _$ColName$; } set { _$ColName$ = value; } } } }

Page 35: Code Generation

Template Structure

The partition of the text to blocks clarifies the containment relationship between the attribute sets

using System;namespace MyProject.Entities{[ public class $TableName$ {[ private $DataType$ _$ColName$ public $DataType$ $CSharpAttributeName$ { get { return _$ColName$; } set { _$ColName$ = value; } } ] } ] }

Page 36: Code Generation

Attributes and Blocks

• A block is instantiated for every unique set of its attributes values.

• An attribute is required by default. • A block is a multi-segment, multi-instance

attribute of its container block. • A block is optional by default.

using System;namespace MyProject.Entities{[ public class $TableName$ {[ private $DataType$ _$ColName$ public $DataType$ $CSharpAttributeName$] } ] }

Page 37: Code Generation

Template Structure[ create table $TableName$ ([ $ColName$ $DataType$ ^,\n] ) ]

Instance separator

Page 38: Code Generation

Template Structure[ create table $TableName$ ([ $ColName$ $DataType$ [ = $Default$ ] $*Comment$ ^,\n] ) ]

Instance separator

Optional variable

Optional block

Page 39: Code Generation

Template Structure

[ select [ $AttName$ ^,] from $TableName$[ where ![ $KeyAttName$= @$KeyAttName$ ^ and ] ]]

Instance separatorRequired block

The block containing “where” requires at least one instance in its internal block in order to be generated.

Page 40: Code Generation

Template as Textual ProjectorA template is a projector of a hierarchical model portion or modelon

[ create table $TableName$ ([ $ColName$ $DataType$ [ = $Default$ ] $*Comment$ ^,\n] ) ]

Page 41: Code Generation

Template as Textual Projector

…{ColName,DataType,*Comment}

{TableName}

1 2 3

*{Default}

T(TableName,+C(ColName,DataType,*Comment,*D(Default))

A template is a projector of a hierarchical model portion or modelon

[ create table $TableName$ ([ $ColName$ $DataType$ [ = $Default$ ] $*Comment$ ^,\n] ) ]

Page 42: Code Generation

Template as Textual Projector{TableName}

{ColName,DataType,*Comment}

*{Default}21 3

[ create table $TableName$ ([ $ColName$ $DataType$ [ = $Default$ ] $*Comment$ ^,\n] ) ]

TableName

ColNameDataTypeDefault

T1C1Varchar(8)

T1C2Int0

T1C3Int

T2C4Varchar(8)

T2C5int

TableName(+C(ColName,DataType,*Comment,*D(Default)))

create table T1(C1 varchar(8) , C2 int = 0 ,C3 int) create table T2(C4 varchar(8),C5 int)

Meta Model

Abstract Model

HierarchicalRelational

Annotated Meta Model = Template

Annotated Model Code

C3C1

T1

C2

{C1,varchar(8)} {C2,int} {C3,int}

0C4 C5

T2

{C4,varchar(8)} {C5,int}

root

Page 43: Code Generation

Template Structural Aspect

An entity has zero or more attributes. [ xxx $att1$ yyy $att2$ zzz ]

Attributes can be required or optional. $reqAtt$ $*OptAtt$

An entity is a composite attribute.Hence, an it can be required or optionalAn entity is optional by default. ![ xxx $att1$ yyy $att2$ zzz ] – required

A (simple) attribute is required by default. $*OptAtt$ - optional

Page 44: Code Generation

Template Structural Aspect

An instance of an entity is a unique set of attributes such that all required values are provided, recursively.

The order of the instances is according to the value of the attributes based on the attributes sort level or order of appearance.

Attributes are visible by default $~NonVisible$

Page 45: Code Generation

Conditional Attribute

A conditional generation implies generating text conditionally or generating text for a subset of instances that meet the condition.

The classify statement derives a subset of attributes from base attributes:

Classify BaseTable isa Table where TableType=‘Base’;

Page 46: Code Generation

Conditional Attribute

A conditional generation implies generating text conditionally or generating text for a subset of instances that meet the condition.

The classify statement derives a subset of attributes from base attributes:

Classify BaseTable isa Table where TableType=‘Base’;

[ create procedure Insert_$BaseTable$ …… ]

[ create procedure Insert_$Table$[ @$Column$ $DataType$ ^,\n][ insert $Table$ ( [ $Column$ ^,] ) values ( [ @$Column$ ^,] )][ insert LOG ( TableName, Content ) values ( “@$BaseTable$” , [ “$Column$=”+@$Column$ ^+] )]

Generated only for base tables

Page 47: Code Generation

Distinct Partitioning ChoiceAttributes Di | i=1..n are classification of base attribute B such that an instance that have attribute Dx does not have attribute Dy unless x=y.

Classify LongEntityName isa EntityName where LengthFlag=‘Y’; Classify ShortEntityName isa EntityName where LengthFlag=‘N’;

Page 48: Code Generation

Distinct Partitioning ChoiceAttributes Di | i=1..n are classification of base attribute B such that an instance that have attribute Dx does not have attribute Dy unless x=y.

Classify LongEntityName isa EntityName where LengthFlag=‘Y’; Classify ShortEntityName isa EntityName where LengthFlag=‘N’;

[$~EntityName$ ….. [ Entity $LongEntityName$ is a long entity and hence has this code ][ Entity $ShortEntityName$ is a short entity only ]]

Only one block is generated. Each instance is separated by the separator of the enclosing block.

Page 49: Code Generation

Overlapping Partitioning ChoiceAttributes Di | i=1..n are classification of base attribute B such that an instance that have attribute Dx may have attribute Dy where x<>y.

Classify L1EntityName isa EntityName where L<1; Classify L2EntityName isa EntityName where L<2;

Page 50: Code Generation

Overlapping Partitioning ChoiceAttributes Di | i=1..n are classification of base attribute B such that an instance that have attribute Dx may have attribute Dy where x<>y.

Classify L1EntityName isa EntityName where L<1; Classify L2EntityName isa EntityName where L<2;

[$~EntityName$ ….. [ Entity $L1EntityName$ has level 1 and up associated information ][ Entity $L2EntityName$ has level 2 and up content ]]

Only one block is generated. Each instance is separated by the separator of the enclosing block.

Page 51: Code Generation

Aonix Text Template Example 1template genDragDropDecls(MClass)//--helper functions for drag&drop-----------------------------------------virtual bool canAcceptDragDrop(int, int, bool = false);virtual bool acceptDragDrop(int, int, bool = false);virtual bool unplugDragDrop();virtual bool aggregationCycleDragDrop(int, int);end templatetemplate genDragDropFunctions(MClass)//--test if drag&drop object could be accepted-----------------------------------------bool [MClass.name]::canAcceptDragDrop(int cid, int oid, bool clone){ [udOut("UDDDT","","Test drag and drop")] if( ! clone && myMetaClass()->isA(cid) && getKey() == oid) return false; // cannot drop on self if( ! clone && aggregationCycleDragDrop(cid, oid)) return false; // avoid cyclic aggregations [loop(Instances->MClass([MClass.id] " " getBaseClassList([MClass])) as Super)] [loop(Super->Role as FromRole->MAssociation->MAssociationEnd as ToRole->MClass as Partner Where [FromRole.id] != [ToRole.id])] [if([FromRole.aggregation] == "Aggregation")] if(DbMetaClass<[Partner.name]>::metaInstance()->isKindOf(cid)) return true; [else] [if([ToRole.aggregation] == "Aggregation")] [insert("include",[Partner.name])] { Ptr<[Partner.name]> owner = to_[ToRole.name].navigate(this).first(); if(owner.valid() && owner->canAcceptDragDrop(cid, oid)) return true; } [end if] [end if] [end loop] [end loop]return false;}... 80 more lines for three more function bodies

Page 52: Code Generation

Aonix Text Template Example 1 template genDragDropDecls(MClass)//--helper functions for drag&drop-----------------------------------------virtual bool canAcceptDragDrop(int, int, bool = false);virtual bool acceptDragDrop(int, int, bool = false);virtual bool unplugDragDrop();virtual bool aggregationCycleDragDrop(int, int);end templatetemplate genDragDropFunctions(MClass)//--test if drag&drop object could be accepted-----------------------------------------bool [MClass.name]::canAcceptDragDrop(int cid, int oid, bool clone){ [udOut("UDDDT","","Test drag and drop")] if( ! clone && myMetaClass()->isA(cid) && getKey() == oid) return false; // cannot drop on self if( ! clone && aggregationCycleDragDrop(cid, oid)) return false; // avoid cyclic aggregations [loop(Instances->MClass([MClass.id] " " getBaseClassList([MClass])) as Super)] [loop(Super->Role as FromRole->MAssociation->MAssociationEnd as ToRole->MClass as Partner Where [FromRole.id] != [ToRole.id])] [if([FromRole.aggregation] == "Aggregation")] if(DbMetaClass<[Partner.name]>::metaInstance()->isKindOf(cid)) return true; [else] [if([ToRole.aggregation] == "Aggregation")] [insert("include",[Partner.name])] { Ptr<[Partner.name]> owner = to_[ToRole.name].navigate(this).first(); if(owner.valid() && owner->canAcceptDragDrop(cid, oid)) return true; } [end if] [end if] [end loop] [end loop]return false;}... 80 more lines for three more function bodies

Page 53: Code Generation

Aonix Text Template Example 1[//--helper functions for drag&drop-----------------------------------------virtual bool canAcceptDragDrop(int, int, bool = false);virtual bool acceptDragDrop(int, int, bool = false);virtual bool unplugDragDrop();virtual bool aggregationCycleDragDrop(int, int); ][//--test if drag&drop object could be accepted-----------------------------------------bool [MClass.name]::canAcceptDragDrop(int cid, int oid, bool clone){ if( ! clone && myMetaClass()->isA(cid) && getKey() == oid) return false; // cannot drop on self if( ! clone && aggregationCycleDragDrop(cid, oid)) return false; // avoid cyclic aggregations[$~Partner.name$[ if(DbMetaClass<$Partner.name$>::metaInstance()->isKindOf(cid)) return true; ] [ { Ptr<$Partner.name$> owner = to_$ToRole.name$.navigate(this).first(); if(owner.valid() && owner->canAcceptDragDrop(cid, oid)) return true; } ] ^\n] return false;} ^\n]... 80 more lines for three more function bodies

Page 54: Code Generation

Aonix Text Template Example 1

L3L4L4/L3

Characters14799050.611

Lines35216

• Total of 115 lines vs. 71 or 3380 characters vs. 2068.

• Clearer code

Page 55: Code Generation

Aonix Text Template 2a template genAccessMethod(MClass) [loop(MClass->MAttribute)] [MAttribute.access] [getDataType([MAttribute.type])] get[string_capitalize(MAttribute.name)]() { return [MAttribute.name]; } [MAttribute.access] void set[string_capitalize(MAttribute.name)]([getDataType([MAttribute.type])] value) { [MAttribute.name] = value; } [end loop] end template

[$access$ $dataType$ get$capName$() { return $Name$; } $access$ void set$capName$($dataType$ value) { $name$ = value; } ^\n]

L3L4L4/L3

Characters3451240.35

Lines1480.57

Page 56: Code Generation

Aonix Text Template Example 3template BufferAssoc (MAssociation) [loop (MAssociation->MAssociationEnd As FromRole->MClass As SenderCl )] [loop (MAssociation->MAssociationEnd As ToRole->MClass As ReceiverCl Where [ToRole.id] != [FromRole.id])] import com.aonix.hidoors.tools.ApexBuffer; public class [SenderCl.name][ReceiverCl.name]Buffer { [loop (MAssociation->AssociationClass As MessageCl)] // New buffer queue [loop(MAssociation->TaggedValue As TV Where [TV.tag] == "HIBufferSize")] private ApexBuffer queue = new ApexBuffer([TV.value]); [end loop] // send and receive methods public [MessageCl.name] receive() { return ([MessageCl.name]) queue.get(); } public void send ([MessageCl.name] element) { queue.put(element); } } [end loop end loop end loop] end template

Page 57: Code Generation

Aonix Text Template Example 3import com.aonix.hidoors.tools.ApexBuffer; [public class $SenderCl.name$$ReceiverCl.name$Buffer { // New buffer queue [private ApexBuffer queue = new ApexBuffer($TV.value$); ^\n]// send and receive methods public $MessageCl.name$ receive() { return ($MessageCl.name$) queue.get(); } public void send ($MessageCl.name$ element) { queue.put(element); } }^\n]

L3L4L4/L3

Characters7393560.481

Lines24120.5

Page 58: Code Generation

Aonix Text Template Example 3import com.aonix.hidoors.tools.ApexBuffer; [public class $SenderCl$$ReceiverCl$Buffer { // New buffer queue [private ApexBuffer queue = new ApexBuffer($TV$); ]// send and receive methods public $MessageCl$ receive() { return ($MessageCl$) queue.get(); } public void send ($MessageCl$ element) { queue.put(element); } }]

L3L4L4/L3

Characters7393200.433

Lines24120.5

Use aliased names and default line separator.

Page 59: Code Generation

PHP, Smarty, Comparison

<?php foreach ($items as $item): ?><div><?php echo $item; ?></div><?php endforeach; ?>

{foreach from=$myArray item=foo} <div>{$foo}</div>{/foreach}

PHP

Smarty

[<div>$foo$</div> ^\n] Smarty