Full list of in-depth articles -
Feedback and questions -
Request demo -
A programmer's introduction to Tefigel
|
|
|
|
5
| Control flow and data constructs |
|
6
| Subroutines and functions |
|
7
| Tefigel sections and text sections |
|
8
| Basic template-driven code generation |
|
|
10
| Native CSV file processing |
|
|
Tefigel is a language expressly
designed for code and documentation generation.
The current version (103) of Tefigel
represents a major step forward in terms of usability of this
generation-oriented language. "Tefigel" stands for text file generation language.
This 10-step introduction will show you simple examples of
the main features of Tefigel. You can freely download
the Community Edition of SoProMach, which
includes the Tefigel language processor. The Community Edition
packages provide full-fledged examples of
the software that you can generate with
SoProMach.
Enough said, let's get down to programming in Tefigel.
Input files to Tefigel are plain text files. Input files with
no instructions are copied unaltered to output.
Input to Tefigel [ File "01_plain_text" ]
|
Hello, my role here is that of presenting Tefigel templates.
I look like a simple plain text file. Most of the time white is
WHITE, black is BLACK, and grey is GREY. But sometimes things get
mixed up. For instance, two plus two usually yields four, but that
may also depend on the context.
|
Output from "/opt/somusar/bin/tefigel 01_plain_text" [ File "output/01_plain_text.out" ]
|
Hello, my role here is that of presenting Tefigel templates.
I look like a simple plain text file. Most of the time white is
WHITE, black is BLACK, and grey is GREY. But sometimes things get
mixed up. For instance, two plus two usually yields four, but that
may also depend on the context.
|
The other type of input files to Tefigel are scripts with variables,
control structures, and subprograms, both built-in and user-defined.
Input to Tefigel [ File "02_simple_script" ]
|
@ tefigel
loop i=1,3
echo Hello, world! (i)
endloop
for fruit=apple,orange,strawberry
echo Fruit fruit_counter of fruit_loops is fruit
endfor
echo Today is ~date and it is now ~time
|
Output from "/opt/somusar/bin/tefigel 02_simple_script" [ File "output/02_simple_script.out" ]
|
Hello, world! (1)
Hello, world! (2)
Hello, world! (3)
Fruit 1 of 3 is apple
Fruit 2 of 3 is orange
Fruit 3 of 3 is strawberry
Today is Tue Nov 02 2004 and it is now 11:14:11.109
|
Scripts can use both external scripts and external text files
as subprograms in a broad sense.
Input to Tefigel [ File "03_script_and_text" ]
|
@ tefigel
echo -------------- Use text as a subroutine
01_plain_text
echo -------------- Set some placeholders to new values, then reuse text
set two=4
set four=8
set context=circumstances
set BLACK="#000000"
set WHITE="#FFFFFF"
set GREY="#888888"
01_plain_text
echo -------------- Use text without modifying its contents
attach 01_plain_text
|
Output from "/opt/somusar/bin/tefigel 03_script_and_text" [ File "output/03_script_and_text.out" ]
|
-------------- Use text as a subroutine
Hello, my role here is that of presenting Tefigel templates.
I look like a simple plain text file. Most of the time white is
WHITE, black is BLACK, and grey is GREY. But sometimes things get
mixed up. For instance, two plus two usually yields four, but that
may also depend on the context.
-------------- Set some placeholders to new values, then reuse text
Hello, my role here is that of presenting Tefigel templates.
I look like a simple plain text file. Most of the time white is
"#FFFFFF", black is "#000000", and grey is "#888888". But sometimes things get
mixed up. For instance, 4 plus 4 usually yields 8, but that
may also depend on the circumstances.
-------------- Use text without modifying its contents
Hello, my role here is that of presenting Tefigel templates.
I look like a simple plain text file. Most of the time white is
WHITE, black is BLACK, and grey is GREY. But sometimes things get
mixed up. For instance, two plus two usually yields four, but that
may also depend on the context.
|
Tefigel variables are loosely typed. All variables can be used as
string placeholders.
Input to Tefigel [ File "04_data" ]
|
@ tefigel
# Plain variables
set string=Hello, world!
set integer=123
set float=123.5
eval boolean float>integer
set result=integer
add result float
echo Some plain variables: "string", integer + float = result, and boolean.
|
Output from "/opt/somusar/bin/tefigel 04_data" [ File "output/04_data.out" ]
|
Some plain variables: "Hello, world!", 123 + 123.5 = 246.500000000000000, and 1.
|
All most common control structures are available (if, case, several
loop types). Main data structures are lists and data groups. The latter
is a sort of last-minute data record. Several operators can be dynamically
defined.
Input to Tefigel [ File "05_constructs_and_flow" ]
|
@ tefigel
# Data groups and lists
new_list(fruit_colors)
# Fill up the list
for fruit=apple,chestnut,strawberry
for color=green,reddish-brown,red
# Build a |-separated record and add it to the list
set dg=~group(|,color,fruit)
add_item(fruit_colors,dg)
endfor
endfor
# Expand and print list contents
echo The fruit/color list contains
# Define a content concatenation operator
dash +
for item=~list_contents(fruit_colors)
case item
when=green|strawberry
set opinion=immature
when=green|chestnut
set opinion=rather unlikely
otherwise
set opinion=ok
endcase
# Expand the |-separated record
ungroup(item,|,color,fruit)
if opinion=ok
set recommendation=, you can eat it
else
set recommendation=
endif
# Use concatenation operator
echo Item item_counter/item_loops: color fruit: opinion+recommendation.
endfor
dash
|
Output from "/opt/somusar/bin/tefigel 05_constructs_and_flow" [ File "output/05_constructs_and_flow.out" ]
|
The fruit/color list contains
Item 1/9: green apple: ok, you can eat it.
Item 2/9: reddish-brown apple: ok, you can eat it.
Item 3/9: red apple: ok, you can eat it.
Item 4/9: green chestnut: rather unlikely.
Item 5/9: reddish-brown chestnut: ok, you can eat it.
Item 6/9: red chestnut: ok, you can eat it.
Item 7/9: green strawberry: immature.
Item 8/9: reddish-brown strawberry: ok, you can eat it.
Item 9/9: red strawberry: ok, you can eat it.
|
External user-defined functions and subroutines are called by means of
their path name. Arguments are associated with positional parameters.
The number of arguments can vary. Return values are strings.
Input to Tefigel [ File "06_subprograms" ]
|
@ tefigel
echo This is main, calling subprogram/greeting_f(Hello,Welcome!,Goodbye)
echo that returns ~subprogram/greeting_f(Hello,Welcome!,Goodbye)
echo
echo This is main, calling subprogram/greeting_s(Hello,Welcome!,Goodbye)
echo that prints out:
subprogram/greeting_s(Hello,Welcome!,Goodbye)
|
Output from "/opt/somusar/bin/tefigel 06_subprograms" [ File "output/06_subprograms.out" ]
|
This is main, calling subprogram/greeting_f(Hello,Welcome!,Goodbye)
that returns "Goodbye - Welcome! - Hello"
This is main, calling subprogram/greeting_s(Hello,Welcome!,Goodbye)
that prints out:
Greeting you with "Hello"
Greeting you with "Welcome!"
Greeting you with "Goodbye"
|
A function returning a string [ File "subprogram/greeting_f" ]
|
@ tefigel
interface(greetingA,greetingB,greetingC)
retvalue="greetingC - greetingB - greetingA"
|
A subprogram generating text [ File "subprogram/greeting_s" ]
|
@ tefigel
interface(...)
while REG_COUNT>0
echo Greeting you with "REG_0"
shift
endwhile
|
Generating software often requires to switch between scripting mode
and text mode. Tefigel provides ad-hoc constructs for this purpose.
Input to Tefigel [ File "07_file_sections" ]
|
By default, Tefigel input files are processed as text files.
Blanks and quotes are treated as letters and numbers:
leading blanks, quoted tabs ' ' , quoted quotes: "'",
are copied unmodified.
But input files may contain Tefigel sections, and Tefigel sections
may contain in turn text sections:
@ tefigel
loop i=1,3
echo We are now in a Tefigel section
if i=3
echo ...and this was the last loop.
endif
endloop
echo Start a text section with some Tefigel commands embedded
@ text
Back to plain text, but you can still use Tefigel code:
@ set greeting=Hello!
Greet you with "greeting"
@ unset greeting
Greet you with "greeting"
Close text section, switch back to Tefigel section.
@ endtext
echo Back to Tefigel, but you can still produce text:
set greeting=Hello!
echo Greet you with "greeting"
unset greeting
echo Greet you with "greeting"
echo Close Tefigel section, switch back to text section.
@ endtefigel
That's all for script "~cur_input()".
|
Output from "/opt/somusar/bin/tefigel 07_file_sections" [ File "output/07_file_sections.out" ]
|
By default, Tefigel input files are processed as text files.
Blanks and quotes are treated as letters and numbers:
leading blanks, quoted tabs ' ' , quoted quotes: "'",
are copied unmodified.
But input files may contain Tefigel sections, and Tefigel sections
may contain in turn text sections:
We are now in a Tefigel section
We are now in a Tefigel section
We are now in a Tefigel section
...and this was the last loop.
Start a text section with some Tefigel commands embedded
Back to plain text, but you can still use Tefigel code:
Greet you with "Hello!"
Greet you with "greeting"
Close text section, switch back to Tefigel section.
Back to Tefigel, but you can still produce text:
Greet you with "Hello!"
Greet you with "greeting"
Close Tefigel section, switch back to text section.
That's all for script "07_file_sections".
|
Complex generators take advantage of the file-system-oriented
design of Tefigel, that allows to map complex template hierarchies
directly onto the file-system's hierarchy. Internal hierarchical structures
(for instance, metadata) are generally stored in lists.
Input to Tefigel [ File "08_templates" ]
|
@ tefigel
# Define two simple classes. All members are strings
new_list(Customer,name,address,email)
new_list(Product,code,description)
# Create a list of the classes
new_list(Classes,Customer,Product)
# Generate a Java and a C# class file for each class in the list
for ThisClass=~list_contents(Classes)
for language=java,cs
# Expand the appropriate template for each language into
# a different class file under directory "output"
output output/ThisClass.language
template/language(ThisClass)
endfor
endfor
|
A simple Java template [ File "template/java" ]
|
@ interface(ThisClass)
@ set Attributes=~list_contents(ThisClass)
public class ThisClass {
@ for Attribute=Attributes
private String Attribute;
@ endfor
@ for Attribute=Attributes
public String get~to_Upper(Attribute)() {
return Attribute;
}
public void set~to_Upper(Attribute)(String Attribute) {
this.Attribute = Attribute;
}
@ endfor
}
|
A simple C# template [ File "template/cs" ]
|
@ interface(ThisClass)
@ set Properties=~list_contents(ThisClass)
public class ThisClass {
@ for Property=Properties
private string Property;
@ endfor
@ for Property=Properties
public string ~to_Upper(Property) {
get {
return Property;
}
set {
Property = value;
}
}
@ endfor
}
|
Output from "/opt/somusar/bin/tefigel 08_templates" [ File "output/Customer.java" ]
|
public class Customer {
private String name;
private String address;
private String email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
|
Output from "/opt/somusar/bin/tefigel 08_templates" [ File "output/Customer.cs" ]
|
public class Customer {
private string name;
private string address;
private string email;
public string Name {
get {
return name;
}
set {
name = value;
}
}
public string Address {
get {
return address;
}
set {
address = value;
}
}
public string Email {
get {
return email;
}
set {
email = value;
}
}
}
|
Output from "/opt/somusar/bin/tefigel 08_templates" [ File "output/Product.java" ]
|
public class Product {
private String code;
private String description;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
|
Output from "/opt/somusar/bin/tefigel 08_templates" [ File "output/Product.cs" ]
|
public class Product {
private string code;
private string description;
public string Code {
get {
return code;
}
set {
code = value;
}
}
public string Description {
get {
return description;
}
set {
description = value;
}
}
}
|
Tefigel processes XML files using callbacks to user-provided
functions. Complex XML hierarchies can be mapped onto corresponding
file-system hierarchies of element processors, possibly grouped together.
XML is one of the favorite sources of metadata for SoProMach.
Input to Tefigel [ File "09_xml_process" ]
|
@ tefigel
new_list(Classes)
# Read a list of simple metadata from an XML model file
set TARGET_TAG_PATH=model/class
tag_file_process(model.xml,subprogram)
for ThisClass=~list_contents(Classes)
echo Class ThisClass contains:~list_contents(ThisClass, )
endfor
|
XML input to Tefigel [ File "model.xml" ]
|
<model>
<class name="Customer">
<attribute>
<name>name</name>
</attribute>
<attribute>
<name>address</name>
</attribute>
<attribute>
<name>email</name>
</attribute>
</class>
<class name="Product">
<attribute>
<name>code</name>
</attribute>
<attribute>
<name>description</name>
</attribute>
</class>
</model>
|
Output from "/opt/somusar/bin/tefigel 09_xml_process" [ File "output/09_xml_process.out" ]
|
Class Customer contains: name, address, email
Class Product contains: code, description
|
Entering a tag [ File "subprogram/tag_node.in" ]
|
@ tefigel
if TAG_ID=class
globset Class=tp_name
new_list(Class)
endif
|
Processing a tag's content [ File "subprogram/tag_node.tval" ]
|
@ tefigel
if TAG_PATH~class/attribute/name
add_item(Class,TAG_TEXT)
endif
|
Exiting from a tag [ File "subprogram/tag_node.out" ]
|
@ tefigel
if TAG_ID=class
add_item(Classes,Class)
unset Class
endif
|
Tefigel processes CSV files using a callback to a user-provided
function, which receives the data values from the CSV file as call
arguments. CSV files are also one of the favorite sources of metadata
for SoProMach.
Input to Tefigel [ File "10_csv_process" ]
|
@ tefigel
new_list(Classes)
# Read a list of simple metadata from a CSV model file
escape \
csv_file_process(model.csv,subprogram/mk_class_list,\,)
escape
for ThisClass=~list_contents(Classes)
echo Class ThisClass contains:~list_contents(ThisClass, )
endfor
|
CSV input file to Tefigel [ File "model.csv" ]
|
Customer,name,address,email
Product,code,description
|
Output from "/opt/somusar/bin/tefigel 10_csv_process" [ File "output/10_csv_process.out" ]
|
Class Customer contains: name, address, email
Class Product contains: code, description
|
Processing a CSV record [ File "subprogram/mk_class_list" ]
|
@ tefigel
interface(...)
set Class=REG_0
shift
new_list(Class)
while REG_COUNT>0
add_item(Class,REG_0)
shift
endwhile
add_item(Classes,Class)
|
Download the source code of this page from here:
The free Community Edition of SoProMach
and the proofs-of-concept (POCs) provide extensive
examples of use of Tefigel. You can download both SoProMach
and the POCs from the download page.
All electronic booklets on Tefigel are freely available on line: see in
particular the reference guide and a
tutorial. Error and warning messages are
described in the User's guide.
Tefigel is one half of SoProMach.
The other half, Sisendel, is a higher-level
metadata definition language that uses Tefigel to
generate software. Several POCs make use of Sisendel.
"Sisendel" stands for simple software entity design language.
All documentation on SoProMach is available on line.
For more information please contact us.
Written on 2 November 2004
Full list of in-depth articles -
Feedback and questions -
Request demo -
|