uCalc API Version: 2.1.3-preview.2 Released: 6/17/2026
Warning
uCalc API Preview Release Notice:The documentation describes the intended behavior of the API. The current preview build contains incomplete features, unoptimized performance, and is subject to breaking changes.
Project: Creating a Basic Template Engine (like Liquid or Jinja)
Product:
Class:
A step-by-step project to build a simple but powerful template engine, similar to Liquid or Jinja, using uCalc's Transformer and callback system.
Remarks
💡 Project: Creating a Basic Template Engine
This project will guide you through building a simple but powerful text template engine, similar to popular libraries like Shopify's Liquid or Python's Jinja. A template engine allows you to generate dynamic content by processing a template string with placeholders and logic, and filling it with data.
This is a perfect real-world showcase of how uCalc's Transformer and expression parser work together to create a custom Domain-Specific Language (DSL).
The Goal: Our Template Syntax
We want to create a system that can process a template like this:
Hello, {{ user_name }}!{% if is_premium_user %}Your premium access is active.{% endif %}Your items:{% for item in items %}- {{ item }}{% endfor %}Our engine will need to understand three constructs:
- Variable Placeholders:
{{ ... }}to insert data. - Conditional Blocks:
{% if ... %}...{% endif %}to show content based on a condition. - Loop Blocks:
{% for ... %}...{% endfor %}to iterate over a collection.
Step 1: Setting Up the Data Context
First, we need some data for our template to use. We'll define these as standard variables in our uCalc instance.
// The data model for our templateuc.DefineVariable("user_name = 'Alice'");uc.DefineVariable("is_premium_user = true");uc.DefineVariable("items[] = {'Book', 'Pen', 'Paper'}");Step 2: Simple Variable Placeholders {{ ... }}
This is a simple find-and-replace task. We'll use a Transformer rule to find any content inside {{ }} and evaluate it.
// The {@@Eval} directive evaluates the captured 'expr' string.t.FromTo("'{' '{' {expr} '}' '}'", "{@@Eval: expr}");Step 3: Conditional Logic {% if ... %}
For conditional blocks, we need to capture the condition and the body. We can then use the built-in IIf() function within an {@Eval} block to conditionally include the body.
Crucially, we must set RewindOnChange(true) on this rule. This tells the transformer to re-scan the output. Without it, any {{...}} placeholders inside the if block would not be processed.
// The RewindOnChange is essential for processing nested placeholders.t.FromTo("{% if {cond} %}{body}{% endif %}", "{@@Eval: IIf({cond}, '{body}', '')}").RewindOnChange = true;Step 4: Loops {% for ... %} via a Callback
A simple replacement can't handle loops. This requires a callback function that integrates with the host application's logic. We'll define a custom function, RenderLoop, that the transformer can call.
Our transformer rule will convert the {% for %} syntax into a call to this function:t.FromTo("{% for {var} in {collection} %}{body}{% endfor %}", "{@Eval: RenderLoop('{collection}', '{var}', '{body}')}").RewindOnChange = true;
The RenderLoop callback is the engine of our loop. It will:
- Get the collection array from the
uCalcinstance. - Loop through each item in the collection.
- For each item, define a temporary variable with the loop variable's name (e.g.,
item). - Process the template body for that single iteration using a temporary transformer.
- Append the result to a final output string.
This powerful pattern allows the flexible script engine to drive complex, high-performance logic in the host application.
💡 Why uCalc? (Comparative Analysis)
Dedicated template libraries like Scriban (.NET) or Jinja (Python) are powerful, but they come with a fixed, predefined syntax. You must use {{...}} or their specific keywords.
The uCalc Advantage is Flexibility. We just invented our own template language. With uCalc, the syntax is entirely under your control. You could just as easily define the syntax to be <%= ... %> or $VarName$ by simply changing the patterns in your transformer rules. This makes uCalc an ideal tool for not just using a language, but for building one tailored to your exact needs.
Examples
A succinct example demonstrating simple variable replacement in a template.
using uCalcSoftware;
var uc = new uCalc();
var t = uc.NewTransformer();
// Define the data
uc.DefineVariable("user_name = 'Alice'");
// Define the placeholder rule
// '{' is a special character and must be escaped
t.FromTo("'{' '{' {expr} '}' '}'", "{@@Eval: expr}");
// Process the template
Console.WriteLine(t.Transform("Hello, {{ user_name }}!"));
Hello, Alice! using uCalcSoftware; var uc = new uCalc(); var t = uc.NewTransformer(); // Define the data uc.DefineVariable("user_name = 'Alice'"); // Define the placeholder rule // '{' is a special character and must be escaped t.FromTo("'{' '{' {expr} '}' '}'", "{@@Eval: expr}"); // Process the template Console.WriteLine(t.Transform("Hello, {{ user_name }}!"));
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
auto t = uc.NewTransformer();
// Define the data
uc.DefineVariable("user_name = 'Alice'");
// Define the placeholder rule
// '{' is a special character and must be escaped
t.FromTo("'{' '{' {expr} '}' '}'", "{@@Eval: expr}");
// Process the template
cout << t.Transform("Hello, {{ user_name }}!") << endl;
}
Hello, Alice! #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; auto t = uc.NewTransformer(); // Define the data uc.DefineVariable("user_name = 'Alice'"); // Define the placeholder rule // '{' is a special character and must be escaped t.FromTo("'{' '{' {expr} '}' '}'", "{@@Eval: expr}"); // Process the template cout << t.Transform("Hello, {{ user_name }}!") << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Dim t = uc.NewTransformer()
'// Define the data
uc.DefineVariable("user_name = 'Alice'")
'// Define the placeholder rule
'// '{' is a special character and must be escaped
t.FromTo("'{' '{' {expr} '}' '}'", "{@@Eval: expr}")
'// Process the template
Console.WriteLine(t.Transform("Hello, {{ user_name }}!"))
End Sub
End Module
Hello, Alice! Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Dim t = uc.NewTransformer() '// Define the data uc.DefineVariable("user_name = 'Alice'") '// Define the placeholder rule '// '{' is a special character and must be escaped t.FromTo("'{' '{' {expr} '}' '}'", "{@@Eval: expr}") '// Process the template Console.WriteLine(t.Transform("Hello, {{ user_name }}!")) End Sub End Module