uCalc API Version: 5.7.0-preview.1 Released: 7/30/2026
Warning
uCalc API Preview Release Notice:This preview documentation describes the intended behavior of the API. It is not fully accurate or complete.The current preview build contains incomplete features, unoptimized performance, and is subject to breaking changes.Use of the preview version in your production code is not recommended.
A step-by-step project to build a static analysis tool (validator) for a custom INI-style configuration file using the uCalc Transformer.
This project will guide you through building a simple but powerful linter/validator for a custom INI-style configuration file. It's a perfect real-world example of how the declarative power of the uCalc.Transformer can solve complex validation problems more safely and readably than manual string parsing or traditional Regular Expressions.
We'll create a validator that scans a configuration file and reports whether it adheres to a strict set of structural rules.
Our linter will analyze a simple INI-style format with sections (e.g., [Server]), key-value pairs (Host = db1), and comments (lines starting with ;).
Example config.ini:
; Main server settings[Server]Host = main_serverPort = 8080Our validator must enforce the following rules:
[Server] section.[Server] section must contain exactly one Host key.[Server] section must contain at least one Port key.; are comments and should be ignored.Instead of writing complex, imperative code to loop through lines and maintain state, we will use the Transformer to define our rules declaratively.
[Server] section and a LocalTransformer to validate the keys only within that section.First, we create a Transformer instance. Since INI files are multi-line, we must disable StatementSensitive to allow patterns to match across newlines. We also add a rule to ignore comments.
csharp
using (var validator = new uCalc.Transformer()) {
validator.DefaultRuleSet.StatementSensitive = false;
validator.SkipOver(";{line}");
// ... rules go here ...
}
[Server] SectionWe define a Pattern to find the [Server] section. We then chain the Minimum(1) and Maximum(1) methods to enforce that it must appear exactly once.
### Step 3: Validate Keys within the SectionThis is where the hierarchy comes in. We get the [LocalTransformer](/Reference/uCalcBase/Rule/LocalTransformer) for our `serverRule`. Any rules defined on this local transformer will only run on the text captured by the `{body}` variable of the parent rule.```csharp
var local_t = serverRule.LocalTransformer;
// Rule for 'Host' key (must be exactly one)
var hostRule = local_t.Pattern("Host = {@Alpha}")
.SetMinimum(1)
.SetMaximum(1);
// Rule for 'Port' key (must be at least one)
var portRule = local_t.Pattern("Port = {@Number}")
.SetMinimum(1);
```### Step 4: Run the ValidationWith all rules defined, we call [Find()](/Reference/uCalcBase/Transformer/Find) on the transformer. After it runs, we can inspect the [Matches().Count()](/Reference/uCalcBase/Matches/Count) for each rule. Because of our `Minimum` and `Maximum` constraints, a rule's match count will be `0` if its validation condition was not met, making the check simple.---## ⚖️ Why uCalc? (Comparative Analysis)Without uCalc, you would write imperative code:1. Read the file line by line.2. Use `string.StartsWith()` to check for comments or sections.3. Use `string.Split('=')` to parse key-value pairs.4. Maintain manual counters and boolean flags (`foundServerSection`, `hostCount`, etc.) to track state.This approach is brittle, hard to read, and difficult to maintain. uCalc's declarative model is superior because you simply **describe the rules of a valid file**, and the engine handles the complex state management and validation logic for you.ID: 1449
using uCalcSoftware;
var uc = new uCalc();
using (var t = new uCalc.Transformer()) {
var text_ok = "Header: OK";
var text_fail = "Header: ERROR";
// This rule only matches if the status is "OK"
t.Pattern("Header: OK");
// Find() returns the transformer, so we can chain Matches().Count()
if (t.SetText(text_ok).Find().Matches.Count() > 0) {
Console.WriteLine("text_ok is valid.");
}
if (t.SetText(text_fail).Find().Matches.Count() == 0) {
Console.WriteLine("text_fail is invalid.");
}
}
text_ok is valid.
text_fail is invalid. using uCalcSoftware; var uc = new uCalc(); using (var t = new uCalc.Transformer()) { var text_ok = "Header: OK"; var text_fail = "Header: ERROR"; // This rule only matches if the status is "OK" t.Pattern("Header: OK"); // Find() returns the transformer, so we can chain Matches().Count() if (t.SetText(text_ok).Find().Matches.Count() > 0) { Console.WriteLine("text_ok is valid."); } if (t.SetText(text_fail).Find().Matches.Count() == 0) { Console.WriteLine("text_fail is invalid."); } }
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
{
uCalc::Transformer t;
t.Owned(); // Causes t to be released when it goes out of scope
auto text_ok = "Header: OK";
auto text_fail = "Header: ERROR";
// This rule only matches if the status is "OK"
t.Pattern("Header: OK");
// Find() returns the transformer, so we can chain Matches().Count()
if (t.SetText(text_ok).Find().Matches().Count() > 0) {
cout << "text_ok is valid." << endl;
}
if (t.SetText(text_fail).Find().Matches().Count() == 0) {
cout << "text_fail is invalid." << endl;
}
}
}
text_ok is valid.
text_fail is invalid. #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; { uCalc::Transformer t; t.Owned(); // Causes t to be released when it goes out of scope auto text_ok = "Header: OK"; auto text_fail = "Header: ERROR"; // This rule only matches if the status is "OK" t.Pattern("Header: OK"); // Find() returns the transformer, so we can chain Matches().Count() if (t.SetText(text_ok).Find().Matches().Count() > 0) { cout << "text_ok is valid." << endl; } if (t.SetText(text_fail).Find().Matches().Count() == 0) { cout << "text_fail is invalid." << endl; } } }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Using t As New uCalc.Transformer()
Dim text_ok = "Header: OK"
Dim text_fail = "Header: ERROR"
'// This rule only matches if the status is "OK"
t.Pattern("Header: OK")
'// Find() returns the transformer, so we can chain Matches().Count()
If t.SetText(text_ok).Find().Matches.Count() > 0 Then
Console.WriteLine("text_ok is valid.")
End If
If t.SetText(text_fail).Find().Matches.Count() = 0 Then
Console.WriteLine("text_fail is invalid.")
End If
End Using
End Sub
End Module
text_ok is valid.
text_fail is invalid. Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Using t As New uCalc.Transformer() Dim text_ok = "Header: OK" Dim text_fail = "Header: ERROR" '// This rule only matches if the status is "OK" t.Pattern("Header: OK") '// Find() returns the transformer, so we can chain Matches().Count() If t.SetText(text_ok).Find().Matches.Count() > 0 Then Console.WriteLine("text_ok is valid.") End If If t.SetText(text_fail).Find().Matches.Count() = 0 Then Console.WriteLine("text_fail is invalid.") End If End Using End Sub End Module
ID: 1450
using uCalcSoftware;
var uc = new uCalc();
using (var validator = new uCalc.Transformer()) {
// 1. Configure the transformer
validator.DefaultRuleSet.StatementSensitive = false;
validator.SkipOver(";{line}"); // Ignore comments
// 2. Define rules with validation constraints
var serverRule = validator.Pattern("'['Server']' {body}").SetMinimum(1).SetMaximum(1);
serverRule.Description = "Server Section";
var local_t = serverRule.LocalTransformer;
var hostRule = local_t.Pattern("Host = {@Alpha}").SetMinimum(1).SetMaximum(1);
hostRule.Description = "Host Key";
var portRule = local_t.Pattern("Port = {@Number}").SetMinimum(1);
portRule.Description = "Port Key";
// --- Test Data ---
var validConfig = "[Server]\nHost = db1\nPort = 1433";
var invalidConfig = "Host = web1\nPort = 80"; // Missing [Server] section
// --- Validate validConfig ---
Console.WriteLine("--- Validating valid_config.ini ---");
validator.SetText(validConfig).Find();
Console.WriteLine($" Server section check passed: {serverRule.Matches.Count() == 1}");
Console.WriteLine($" Host key check passed: {hostRule.Matches.Count() == 1}");
Console.WriteLine($" Port key check passed: {portRule.Matches.Count() >= 1}");
Console.WriteLine("");
// --- Validate invalidConfig ---
Console.WriteLine("--- Validating invalid_config.ini ---");
validator.SetText(invalidConfig).Find();
Console.WriteLine($" Server section check passed: {serverRule.Matches.Count() == 1}");
// The host and port rules will have 0 matches because their parent rule (serverRule) failed.
Console.WriteLine($" Host key check passed: {hostRule.Matches.Count() == 1}");
Console.WriteLine($" Port key check passed: {portRule.Matches.Count() >= 1}");
}
--- Validating valid_config.ini ---
Server section check passed: True
Host key check passed: True
Port key check passed: True
--- Validating invalid_config.ini ---
Server section check passed: False
Host key check passed: False
Port key check passed: False using uCalcSoftware; var uc = new uCalc(); using (var validator = new uCalc.Transformer()) { // 1. Configure the transformer validator.DefaultRuleSet.StatementSensitive = false; validator.SkipOver(";{line}"); // Ignore comments // 2. Define rules with validation constraints var serverRule = validator.Pattern("'['Server']' {body}").SetMinimum(1).SetMaximum(1); serverRule.Description = "Server Section"; var local_t = serverRule.LocalTransformer; var hostRule = local_t.Pattern("Host = {@Alpha}").SetMinimum(1).SetMaximum(1); hostRule.Description = "Host Key"; var portRule = local_t.Pattern("Port = {@Number}").SetMinimum(1); portRule.Description = "Port Key"; // --- Test Data --- var validConfig = "[Server]\nHost = db1\nPort = 1433"; var invalidConfig = "Host = web1\nPort = 80"; // Missing [Server] section // --- Validate validConfig --- Console.WriteLine("--- Validating valid_config.ini ---"); validator.SetText(validConfig).Find(); Console.WriteLine($" Server section check passed: {serverRule.Matches.Count() == 1}"); Console.WriteLine($" Host key check passed: {hostRule.Matches.Count() == 1}"); Console.WriteLine($" Port key check passed: {portRule.Matches.Count() >= 1}"); Console.WriteLine(""); // --- Validate invalidConfig --- Console.WriteLine("--- Validating invalid_config.ini ---"); validator.SetText(invalidConfig).Find(); Console.WriteLine($" Server section check passed: {serverRule.Matches.Count() == 1}"); // The host and port rules will have 0 matches because their parent rule (serverRule) failed. Console.WriteLine($" Host key check passed: {hostRule.Matches.Count() == 1}"); Console.WriteLine($" Port key check passed: {portRule.Matches.Count() >= 1}"); }
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
#define tf(IsTrue) ((IsTrue) ? "True" : "False")
int main() {
uCalc uc;
{
uCalc::Transformer validator;
validator.Owned(); // Causes validator to be released when it goes out of scope
// 1. Configure the transformer
validator.DefaultRuleSet().StatementSensitive(false);
validator.SkipOver(";{line}"); // Ignore comments
// 2. Define rules with validation constraints
auto serverRule = validator.Pattern("'['Server']' {body}").SetMinimum(1).SetMaximum(1);
serverRule.Description("Server Section");
auto local_t = serverRule.LocalTransformer();
auto hostRule = local_t.Pattern("Host = {@Alpha}").SetMinimum(1).SetMaximum(1);
hostRule.Description("Host Key");
auto portRule = local_t.Pattern("Port = {@Number}").SetMinimum(1);
portRule.Description("Port Key");
// --- Test Data ---
auto validConfig = "[Server]\nHost = db1\nPort = 1433";
auto invalidConfig = "Host = web1\nPort = 80"; // Missing [Server] section
// --- Validate validConfig ---
cout << "--- Validating valid_config.ini ---" << endl;
validator.SetText(validConfig).Find();
cout << " Server section check passed: " << tf(serverRule.Matches().Count() == 1) << endl;
cout << " Host key check passed: " << tf(hostRule.Matches().Count() == 1) << endl;
cout << " Port key check passed: " << tf(portRule.Matches().Count() >= 1) << endl;
cout << "" << endl;
// --- Validate invalidConfig ---
cout << "--- Validating invalid_config.ini ---" << endl;
validator.SetText(invalidConfig).Find();
cout << " Server section check passed: " << tf(serverRule.Matches().Count() == 1) << endl;
// The host and port rules will have 0 matches because their parent rule (serverRule) failed.
cout << " Host key check passed: " << tf(hostRule.Matches().Count() == 1) << endl;
cout << " Port key check passed: " << tf(portRule.Matches().Count() >= 1) << endl;
}
}
--- Validating valid_config.ini ---
Server section check passed: True
Host key check passed: True
Port key check passed: True
--- Validating invalid_config.ini ---
Server section check passed: False
Host key check passed: False
Port key check passed: False #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; #define tf(IsTrue) ((IsTrue) ? "True" : "False") int main() { uCalc uc; { uCalc::Transformer validator; validator.Owned(); // Causes validator to be released when it goes out of scope // 1. Configure the transformer validator.DefaultRuleSet().StatementSensitive(false); validator.SkipOver(";{line}"); // Ignore comments // 2. Define rules with validation constraints auto serverRule = validator.Pattern("'['Server']' {body}").SetMinimum(1).SetMaximum(1); serverRule.Description("Server Section"); auto local_t = serverRule.LocalTransformer(); auto hostRule = local_t.Pattern("Host = {@Alpha}").SetMinimum(1).SetMaximum(1); hostRule.Description("Host Key"); auto portRule = local_t.Pattern("Port = {@Number}").SetMinimum(1); portRule.Description("Port Key"); // --- Test Data --- auto validConfig = "[Server]\nHost = db1\nPort = 1433"; auto invalidConfig = "Host = web1\nPort = 80"; // Missing [Server] section // --- Validate validConfig --- cout << "--- Validating valid_config.ini ---" << endl; validator.SetText(validConfig).Find(); cout << " Server section check passed: " << tf(serverRule.Matches().Count() == 1) << endl; cout << " Host key check passed: " << tf(hostRule.Matches().Count() == 1) << endl; cout << " Port key check passed: " << tf(portRule.Matches().Count() >= 1) << endl; cout << "" << endl; // --- Validate invalidConfig --- cout << "--- Validating invalid_config.ini ---" << endl; validator.SetText(invalidConfig).Find(); cout << " Server section check passed: " << tf(serverRule.Matches().Count() == 1) << endl; // The host and port rules will have 0 matches because their parent rule (serverRule) failed. cout << " Host key check passed: " << tf(hostRule.Matches().Count() == 1) << endl; cout << " Port key check passed: " << tf(portRule.Matches().Count() >= 1) << endl; } }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Using validator As New uCalc.Transformer()
'// 1. Configure the transformer
validator.DefaultRuleSet.StatementSensitive = false
validator.SkipOver(";{line}") '// Ignore comments
'// 2. Define rules with validation constraints
Dim serverRule = validator.Pattern("'['Server']' {body}").SetMinimum(1).SetMaximum(1)
serverRule.Description = "Server Section"
Dim local_t = serverRule.LocalTransformer
Dim hostRule = local_t.Pattern("Host = {@Alpha}").SetMinimum(1).SetMaximum(1)
hostRule.Description = "Host Key"
Dim portRule = local_t.Pattern("Port = {@Number}").SetMinimum(1)
portRule.Description = "Port Key"
'// --- Test Data ---
Dim validConfig = "[Server]" & vbNewLine & "Host = db1" & vbNewLine & "Port = 1433"
Dim invalidConfig = "Host = web1" & vbNewLine & "Port = 80" '// Missing [Server] section
'// --- Validate validConfig ---
Console.WriteLine("--- Validating valid_config.ini ---")
validator.SetText(validConfig).Find()
Console.WriteLine($" Server section check passed: {serverRule.Matches.Count() = 1}")
Console.WriteLine($" Host key check passed: {hostRule.Matches.Count() = 1}")
Console.WriteLine($" Port key check passed: {portRule.Matches.Count() >= 1}")
Console.WriteLine("")
'// --- Validate invalidConfig ---
Console.WriteLine("--- Validating invalid_config.ini ---")
validator.SetText(invalidConfig).Find()
Console.WriteLine($" Server section check passed: {serverRule.Matches.Count() = 1}")
'// The host and port rules will have 0 matches because their parent rule (serverRule) failed.
Console.WriteLine($" Host key check passed: {hostRule.Matches.Count() = 1}")
Console.WriteLine($" Port key check passed: {portRule.Matches.Count() >= 1}")
End Using
End Sub
End Module
--- Validating valid_config.ini ---
Server section check passed: True
Host key check passed: True
Port key check passed: True
--- Validating invalid_config.ini ---
Server section check passed: False
Host key check passed: False
Port key check passed: False Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Using validator As New uCalc.Transformer() '// 1. Configure the transformer validator.DefaultRuleSet.StatementSensitive = false validator.SkipOver(";{line}") '// Ignore comments '// 2. Define rules with validation constraints Dim serverRule = validator.Pattern("'['Server']' {body}").SetMinimum(1).SetMaximum(1) serverRule.Description = "Server Section" Dim local_t = serverRule.LocalTransformer Dim hostRule = local_t.Pattern("Host = {@Alpha}").SetMinimum(1).SetMaximum(1) hostRule.Description = "Host Key" Dim portRule = local_t.Pattern("Port = {@Number}").SetMinimum(1) portRule.Description = "Port Key" '// --- Test Data --- Dim validConfig = "[Server]" & vbNewLine & "Host = db1" & vbNewLine & "Port = 1433" Dim invalidConfig = "Host = web1" & vbNewLine & "Port = 80" '// Missing [Server] section '// --- Validate validConfig --- Console.WriteLine("--- Validating valid_config.ini ---") validator.SetText(validConfig).Find() Console.WriteLine($" Server section check passed: {serverRule.Matches.Count() = 1}") Console.WriteLine($" Host key check passed: {hostRule.Matches.Count() = 1}") Console.WriteLine($" Port key check passed: {portRule.Matches.Count() >= 1}") Console.WriteLine("") '// --- Validate invalidConfig --- Console.WriteLine("--- Validating invalid_config.ini ---") validator.SetText(invalidConfig).Find() Console.WriteLine($" Server section check passed: {serverRule.Matches.Count() = 1}") '// The host and port rules will have 0 matches because their parent rule (serverRule) failed. Console.WriteLine($" Host key check passed: {hostRule.Matches.Count() = 1}") Console.WriteLine($" Port key check passed: {portRule.Matches.Count() >= 1}") End Using End Sub End Module