Code Generation

Preview:

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

Code Generation

SuperSet 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

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

Text Template

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 { }

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(~~~~~~~~~~~~~~~~~~~~);}

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);

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>

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()%>; } <%}%>

Scripted TemplatesBenefits:

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

• Standardized substitution mechanism.

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.

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; } } } } }

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.

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.

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

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

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

)

{

..

}

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

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%>

)

{

}

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.

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

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.

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.

<#@ 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

<#@ 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

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

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; } } <# } #> }

<# } #>

}

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$.

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.

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 #>

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

Abstract Template

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

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.

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.

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; } } } }

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; } } ] } ] }

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$] } ] }

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

Instance separator

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

Instance separator

Optional variable

Optional block

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.

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

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

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] ) ]

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

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

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$

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’;

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

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’;

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.

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;

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.

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

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

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

Aonix Text Template Example 1

L3L4L4/L3

Characters14799050.611

Lines35216

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

• Clearer code

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

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

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

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.

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