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: Implementing a Strict Configuration File Validator

Product: 

Class: 

A step-by-step project to build a static analysis tool (validator) for a custom INI-style configuration file using the uCalc Transformer.

Remarks

🛡️ Project: Implementing a Strict Configuration File Validator

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.

The Goal

We'll create a validator that scans a configuration file and reports whether it adheres to a strict set of structural rules.

The Configuration File Format

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 = 8080

The Validation Rules

Our validator must enforce the following rules:

  1. The file must contain exactly one [Server] section.
  2. The [Server] section must contain exactly one Host key.
  3. The [Server] section must contain at least one Port key.
  4. Lines starting with ; are comments and should be ignored.

The Strategy: Declarative Validation

Instead of writing complex, imperative code to loop through lines and maintain state, we will use the Transformer to define our rules declaratively.

  • Hierarchical Parsing: We'll use a parent Rule to find the [Server] section and a LocalTransformer to validate the keys only within that section.
  • Occurrence Constraints: We'll use the Minimum and Maximum properties on our rules to enforce the "exactly one" and "at least one" constraints.
  • Ignoring Comments: A simple SkipOver rule will make comments invisible to our validation logic.

Step-by-Step Implementation

Step 1: Configure the Transformer

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.

using (var validator = new uCalc.Transformer()) {    validator.DefaultRuleSet.StatementSensitive = false;    validator.SkipOver(";{line}");    // ... rules go here ...}

Step 2: Validate the [Server] Section

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

var serverRule = validator.Pattern("'['Server']' {body}")    .SetMinimum(1)    .SetMaximum(1);

Step 3: Validate Keys within the Section

This is where the hierarchy comes in. We get the 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.

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 Validation

With all rules defined, we call Find() on the transformer. After it runs, we can inspect the 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.

Examples

Checks for the existence of a required header in a string.
				
					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.
				
					#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;
      }
   }
}
				
			
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
				
			
text_ok is valid.
text_fail is invalid.
Validates a configuration file format by enforcing the number of times specific keys must appear.
				
					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
				
					#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;
   }
}
				
			
--- 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
				
			
--- 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