uCalc API Version: 2.1.3-preview.2 Released: 6/16/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.
ExpressionTransformer = [Transformer]
Property
Product:
Class:
Returns the singleton transformer instance used to pre-process expressions before they are parsed.
Remarks
Returns the singleton Transformer instance dedicated to pre-processing expressions before they are parsed by functions like Eval, EvalStr, and Parse.
This powerful feature allows you to define structural, token-aware rewrite rules to create custom syntax, simplify complex expressions, or transpile constructs from other languages.
⚙️ How It Works
When you define a rule on the ExpressionTransformer, any expression string passed to the parser is first processed by these rules. This happens before the expression is evaluated.
For example, you can create a rule to automatically convert x^y into pow(x,y), effectively adding a new operator to the language without using DefineOperator.
💡 Common Use Cases
- Creating syntactic sugar:
Avg(1,2,3)->(1+2+3)/3 - Transpiling operators:
a ? b : c->iif(a, b, c) - Adding domain-specific keywords:
CalculateYield(rate, time)->rate * (1 + time)^2 - Enforcing coding standards: Rewriting deprecated function names to their modern equivalents.
Comparative Analysis
ExpressionTransformer vs. Alias
| Feature | ExpressionTransformer | Alias |
|---|---|---|
| Mechanism | Textual transformation (slower) | Internal symbol table pointer (faster) |
| Flexibility | Can change structure, add/remove arguments | Simple 1-to-1 name replacement only |
| Use Case | Use for changing syntax or structure. | Use for creating simple synonyms (Log -> Ln). |
Choose Alias for simple renaming; it's significantly more performant as it avoids the entire transformation step.
ExpressionTransformer vs. NewTransformer
ExpressionTransformer(): Modifies the built-in parsing pipeline. Rules defined here affect all subsequent calls toEval,Parse, etc., within thatuCalcinstance.- NewTransformer(): Creates a standalone, independent
Transformerobject. It does not affect the built-in parser and is used for general-purpose text transformation tasks.
ExpressionTransformer vs. Standard Regex
A Transformer is superior to regular expressions for language constructs because it operates on tokens, not just characters. It inherently understands concepts like nested parentheses, quoted strings, and numbers, which are notoriously difficult to handle correctly with regex.
⚠️ Performance Considerations
A Transformer object is not created for a uCalc instance until ExpressionTransformer() is called for the first time. Once created, it introduces a small overhead to every parse operation, even if no rules are defined. For performance-critical applications where transformations are not needed, avoid calling this method.
For more targeted, token-level transformations (like defining hex 0xFF notation or string interpolation), consider using TokenTransformer, which is only triggered when a specific token type is matched.
The returned Transformer object should not be released manually. It is owned by the parent uCalc instance.
Examples
Demonstrates using `RewindOnChange(true)` to perform recursive-style transformations, such as creating a variadic `AddUp` function.
using uCalcSoftware;
var uc = new uCalc();
var t = uc.ExpressionTransformer;
// Base case: a single argument
t.FromTo("AddUp({x})", "{x}");
// Recursive case: multiple arguments
// RewindOnChange(true) causes the transformer to re-scan the string after a replacement.
// This allows AddUp(1,2,3) -> (1 + AddUp(2,3)) -> (1 + (2 + AddUp(3))) -> (1 + (2 + 3))
t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").RewindOnChange = true;
Console.WriteLine("Input: AddUp(1, 2, 3, 4)");
Console.WriteLine($"Result: {uc.Eval("AddUp(1, 2, 3, 4)")}");
Input: AddUp(1, 2, 3, 4)
Result: 10 using uCalcSoftware; var uc = new uCalc(); var t = uc.ExpressionTransformer; // Base case: a single argument t.FromTo("AddUp({x})", "{x}"); // Recursive case: multiple arguments // RewindOnChange(true) causes the transformer to re-scan the string after a replacement. // This allows AddUp(1,2,3) -> (1 + AddUp(2,3)) -> (1 + (2 + AddUp(3))) -> (1 + (2 + 3)) t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").RewindOnChange = true; Console.WriteLine("Input: AddUp(1, 2, 3, 4)"); Console.WriteLine($"Result: {uc.Eval("AddUp(1, 2, 3, 4)")}");
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
auto t = uc.ExpressionTransformer();
// Base case: a single argument
t.FromTo("AddUp({x})", "{x}");
// Recursive case: multiple arguments
// RewindOnChange(true) causes the transformer to re-scan the string after a replacement.
// This allows AddUp(1,2,3) -> (1 + AddUp(2,3)) -> (1 + (2 + AddUp(3))) -> (1 + (2 + 3))
t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").RewindOnChange(true);
cout << "Input: AddUp(1, 2, 3, 4)" << endl;
cout << "Result: " << uc.Eval("AddUp(1, 2, 3, 4)") << endl;
}
Input: AddUp(1, 2, 3, 4)
Result: 10 #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; auto t = uc.ExpressionTransformer(); // Base case: a single argument t.FromTo("AddUp({x})", "{x}"); // Recursive case: multiple arguments // RewindOnChange(true) causes the transformer to re-scan the string after a replacement. // This allows AddUp(1,2,3) -> (1 + AddUp(2,3)) -> (1 + (2 + AddUp(3))) -> (1 + (2 + 3)) t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").RewindOnChange(true); cout << "Input: AddUp(1, 2, 3, 4)" << endl; cout << "Result: " << uc.Eval("AddUp(1, 2, 3, 4)") << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Dim t = uc.ExpressionTransformer
'// Base case: a single argument
t.FromTo("AddUp({x})", "{x}")
'// Recursive case: multiple arguments
'// RewindOnChange(true) causes the transformer to re-scan the string after a replacement.
'// This allows AddUp(1,2,3) -> (1 + AddUp(2,3)) -> (1 + (2 + AddUp(3))) -> (1 + (2 + 3))
t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").RewindOnChange = true
Console.WriteLine("Input: AddUp(1, 2, 3, 4)")
Console.WriteLine($"Result: {uc.Eval("AddUp(1, 2, 3, 4)")}")
End Sub
End Module
Input: AddUp(1, 2, 3, 4)
Result: 10 Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Dim t = uc.ExpressionTransformer '// Base case: a single argument t.FromTo("AddUp({x})", "{x}") '// Recursive case: multiple arguments '// RewindOnChange(true) causes the transformer to re-scan the string after a replacement. '// This allows AddUp(1,2,3) -> (1 + AddUp(2,3)) -> (1 + (2 + AddUp(3))) -> (1 + (2 + 3)) t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").RewindOnChange = true Console.WriteLine("Input: AddUp(1, 2, 3, 4)") Console.WriteLine($"Result: {uc.Eval("AddUp(1, 2, 3, 4)")}") End Sub End Module
Internal Test: Verifies that multi-pass transformations work correctly when `RewindOnChange` is enabled for the entire rule set.
using uCalcSoftware;
var uc = new uCalc();
var t = uc.ExpressionTransformer;
// Enable RewindOnChange for all subsequently added rules
t.DefaultRuleSet.RewindOnChange = true;
// Define a chain of simple transformations
t.FromTo("A", "B");
t.FromTo("B", "C");
t.FromTo("C", "D");
// The transformer should apply all rules in sequence: A -> B -> C -> D
var result = t.Transform("A").Text;
Console.WriteLine($"Transform('A') -> {result}");
Console.WriteLine($"Is correct: {result == "D"}");
Transform('A') -> D
Is correct: True using uCalcSoftware; var uc = new uCalc(); var t = uc.ExpressionTransformer; // Enable RewindOnChange for all subsequently added rules t.DefaultRuleSet.RewindOnChange = true; // Define a chain of simple transformations t.FromTo("A", "B"); t.FromTo("B", "C"); t.FromTo("C", "D"); // The transformer should apply all rules in sequence: A -> B -> C -> D var result = t.Transform("A").Text; Console.WriteLine($"Transform('A') -> {result}"); Console.WriteLine($"Is correct: {result == "D"}");
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
#define tf(IsTrue) ((IsTrue) ? "True" : "False")
int main() {
uCalc uc;
auto t = uc.ExpressionTransformer();
// Enable RewindOnChange for all subsequently added rules
t.DefaultRuleSet().RewindOnChange(true);
// Define a chain of simple transformations
t.FromTo("A", "B");
t.FromTo("B", "C");
t.FromTo("C", "D");
// The transformer should apply all rules in sequence: A -> B -> C -> D
auto result = t.Transform("A").Text();
cout << "Transform('A') -> " << result << endl;
cout << "Is correct: " << tf(result == "D") << endl;
}
Transform('A') -> D
Is correct: True #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; #define tf(IsTrue) ((IsTrue) ? "True" : "False") int main() { uCalc uc; auto t = uc.ExpressionTransformer(); // Enable RewindOnChange for all subsequently added rules t.DefaultRuleSet().RewindOnChange(true); // Define a chain of simple transformations t.FromTo("A", "B"); t.FromTo("B", "C"); t.FromTo("C", "D"); // The transformer should apply all rules in sequence: A -> B -> C -> D auto result = t.Transform("A").Text(); cout << "Transform('A') -> " << result << endl; cout << "Is correct: " << tf(result == "D") << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Dim t = uc.ExpressionTransformer
'// Enable RewindOnChange for all subsequently added rules
t.DefaultRuleSet.RewindOnChange = true
'// Define a chain of simple transformations
t.FromTo("A", "B")
t.FromTo("B", "C")
t.FromTo("C", "D")
'// The transformer should apply all rules in sequence: A -> B -> C -> D
Dim result = t.Transform("A").Text
Console.WriteLine($"Transform('A') -> {result}")
Console.WriteLine($"Is correct: {result = "D"}")
End Sub
End Module
Transform('A') -> D
Is correct: True Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Dim t = uc.ExpressionTransformer '// Enable RewindOnChange for all subsequently added rules t.DefaultRuleSet.RewindOnChange = true '// Define a chain of simple transformations t.FromTo("A", "B") t.FromTo("B", "C") t.FromTo("C", "D") '// The transformer should apply all rules in sequence: A -> B -> C -> D Dim result = t.Transform("A").Text Console.WriteLine($"Transform('A') -> {result}") Console.WriteLine($"Is correct: {result = "D"}") End Sub End Module
Using ExpressionTransformer to transform expressions before they are parsed
using uCalcSoftware;
var uc = new uCalc();
var ExprT = uc.ExpressionTransformer; // Transformer used for Eval() and Evaluate()
var p1 = ExprT.FromTo("AddUp({x})", "{x}"); // RewindOnChange False by default
var p2 = ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").SetRewindOnChange(true);
Console.WriteLine($"p1 RewindOnChange: {p1.RewindOnChange}");
Console.WriteLine($"p2 RewindOnChange: {p2.RewindOnChange}");
Console.WriteLine("");
Console.WriteLine($"Input: AddUp(1,2,3,4)");
Console.WriteLine($"Transform: {ExprT.Transform("AddUp(1,2,3,4)")}");
Console.WriteLine($"Eval: {uc.Eval("AddUp(1,2,3,4)")}");
p1 RewindOnChange: False
p2 RewindOnChange: True
Input: AddUp(1,2,3,4)
Transform: (1 + (2 + (3 + 4)))
Eval: 10 using uCalcSoftware; var uc = new uCalc(); var ExprT = uc.ExpressionTransformer; // Transformer used for Eval() and Evaluate() var p1 = ExprT.FromTo("AddUp({x})", "{x}"); // RewindOnChange False by default var p2 = ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").SetRewindOnChange(true); Console.WriteLine($"p1 RewindOnChange: {p1.RewindOnChange}"); Console.WriteLine($"p2 RewindOnChange: {p2.RewindOnChange}"); Console.WriteLine(""); Console.WriteLine($"Input: AddUp(1,2,3,4)"); Console.WriteLine($"Transform: {ExprT.Transform("AddUp(1,2,3,4)")}"); Console.WriteLine($"Eval: {uc.Eval("AddUp(1,2,3,4)")}");
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
#define tf(IsTrue) ((IsTrue) ? "True" : "False")
int main() {
uCalc uc;
auto ExprT = uc.ExpressionTransformer(); // Transformer used for Eval() and Evaluate()
auto p1 = ExprT.FromTo("AddUp({x})", "{x}"); // RewindOnChange False by default
auto p2 = ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").SetRewindOnChange(true);
cout << "p1 RewindOnChange: " << tf(p1.RewindOnChange()) << endl;
cout << "p2 RewindOnChange: " << tf(p2.RewindOnChange()) << endl;
cout << "" << endl;
cout << "Input: " << "AddUp(1,2,3,4)" << endl;
cout << "Transform: " << ExprT.Transform("AddUp(1,2,3,4)") << endl;
cout << "Eval: " << uc.Eval("AddUp(1,2,3,4)") << endl;
}
p1 RewindOnChange: False
p2 RewindOnChange: True
Input: AddUp(1,2,3,4)
Transform: (1 + (2 + (3 + 4)))
Eval: 10 #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; #define tf(IsTrue) ((IsTrue) ? "True" : "False") int main() { uCalc uc; auto ExprT = uc.ExpressionTransformer(); // Transformer used for Eval() and Evaluate() auto p1 = ExprT.FromTo("AddUp({x})", "{x}"); // RewindOnChange False by default auto p2 = ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").SetRewindOnChange(true); cout << "p1 RewindOnChange: " << tf(p1.RewindOnChange()) << endl; cout << "p2 RewindOnChange: " << tf(p2.RewindOnChange()) << endl; cout << "" << endl; cout << "Input: " << "AddUp(1,2,3,4)" << endl; cout << "Transform: " << ExprT.Transform("AddUp(1,2,3,4)") << endl; cout << "Eval: " << uc.Eval("AddUp(1,2,3,4)") << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Dim ExprT = uc.ExpressionTransformer '// Transformer used for Eval() and Evaluate()
Dim p1 = ExprT.FromTo("AddUp({x})", "{x}") '// RewindOnChange False by default
Dim p2 = ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").SetRewindOnChange(true)
Console.WriteLine($"p1 RewindOnChange: {p1.RewindOnChange}")
Console.WriteLine($"p2 RewindOnChange: {p2.RewindOnChange}")
Console.WriteLine("")
Console.WriteLine($"Input: AddUp(1,2,3,4)")
Console.WriteLine($"Transform: {ExprT.Transform("AddUp(1,2,3,4)")}")
Console.WriteLine($"Eval: {uc.Eval("AddUp(1,2,3,4)")}")
End Sub
End Module
p1 RewindOnChange: False
p2 RewindOnChange: True
Input: AddUp(1,2,3,4)
Transform: (1 + (2 + (3 + 4)))
Eval: 10 Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Dim ExprT = uc.ExpressionTransformer '// Transformer used for Eval() and Evaluate() Dim p1 = ExprT.FromTo("AddUp({x})", "{x}") '// RewindOnChange False by default Dim p2 = ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))").SetRewindOnChange(true) Console.WriteLine($"p1 RewindOnChange: {p1.RewindOnChange}") Console.WriteLine($"p2 RewindOnChange: {p2.RewindOnChange}") Console.WriteLine("") Console.WriteLine($"Input: AddUp(1,2,3,4)") Console.WriteLine($"Transform: {ExprT.Transform("AddUp(1,2,3,4)")}") Console.WriteLine($"Eval: {uc.Eval("AddUp(1,2,3,4)")}") End Sub End Module
RewindOnChange
using uCalcSoftware;
var uc = new uCalc();
var ExprT = uc.ExpressionTransformer; // Transformer used for Eval() and Evaluate()
ExprT.DefaultRuleSet.RewindOnChange = true;
ExprT.FromTo("AddUp({x})", "{x}");
ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))");
ExprT.FromTo("ArgCount({x})", "1");
ExprT.FromTo("ArgCount({x}, {y})", "(1 + ArgCount({y}))");
ExprT.FromTo("Average({x}, {y})", "AddUp({x}, {y}) / ArgCount({x}, {y})");
var Expression = "Average(1, 2, 3, 4)";
Console.WriteLine($"Input: {Expression}");
Console.WriteLine($"Transform: {ExprT.Transform(Expression)}");
Console.WriteLine($"Eval: {uc.Eval(Expression)}");
Input: Average(1, 2, 3, 4)
Transform: (1 + (2 + (3 + 4))) / (1 + (1 + (1 + 1)))
Eval: 2.5 using uCalcSoftware; var uc = new uCalc(); var ExprT = uc.ExpressionTransformer; // Transformer used for Eval() and Evaluate() ExprT.DefaultRuleSet.RewindOnChange = true; ExprT.FromTo("AddUp({x})", "{x}"); ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))"); ExprT.FromTo("ArgCount({x})", "1"); ExprT.FromTo("ArgCount({x}, {y})", "(1 + ArgCount({y}))"); ExprT.FromTo("Average({x}, {y})", "AddUp({x}, {y}) / ArgCount({x}, {y})"); var Expression = "Average(1, 2, 3, 4)"; Console.WriteLine($"Input: {Expression}"); Console.WriteLine($"Transform: {ExprT.Transform(Expression)}"); Console.WriteLine($"Eval: {uc.Eval(Expression)}");
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
auto ExprT = uc.ExpressionTransformer(); // Transformer used for Eval() and Evaluate()
ExprT.DefaultRuleSet().RewindOnChange(true);
ExprT.FromTo("AddUp({x})", "{x}");
ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))");
ExprT.FromTo("ArgCount({x})", "1");
ExprT.FromTo("ArgCount({x}, {y})", "(1 + ArgCount({y}))");
ExprT.FromTo("Average({x}, {y})", "AddUp({x}, {y}) / ArgCount({x}, {y})");
auto Expression = "Average(1, 2, 3, 4)";
cout << "Input: " << Expression << endl;
cout << "Transform: " << ExprT.Transform(Expression) << endl;
cout << "Eval: " << uc.Eval(Expression) << endl;
}
Input: Average(1, 2, 3, 4)
Transform: (1 + (2 + (3 + 4))) / (1 + (1 + (1 + 1)))
Eval: 2.5 #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; auto ExprT = uc.ExpressionTransformer(); // Transformer used for Eval() and Evaluate() ExprT.DefaultRuleSet().RewindOnChange(true); ExprT.FromTo("AddUp({x})", "{x}"); ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))"); ExprT.FromTo("ArgCount({x})", "1"); ExprT.FromTo("ArgCount({x}, {y})", "(1 + ArgCount({y}))"); ExprT.FromTo("Average({x}, {y})", "AddUp({x}, {y}) / ArgCount({x}, {y})"); auto Expression = "Average(1, 2, 3, 4)"; cout << "Input: " << Expression << endl; cout << "Transform: " << ExprT.Transform(Expression) << endl; cout << "Eval: " << uc.Eval(Expression) << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Dim ExprT = uc.ExpressionTransformer '// Transformer used for Eval() and Evaluate()
ExprT.DefaultRuleSet.RewindOnChange = true
ExprT.FromTo("AddUp({x})", "{x}")
ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))")
ExprT.FromTo("ArgCount({x})", "1")
ExprT.FromTo("ArgCount({x}, {y})", "(1 + ArgCount({y}))")
ExprT.FromTo("Average({x}, {y})", "AddUp({x}, {y}) / ArgCount({x}, {y})")
Dim Expression = "Average(1, 2, 3, 4)"
Console.WriteLine($"Input: {Expression}")
Console.WriteLine($"Transform: {ExprT.Transform(Expression)}")
Console.WriteLine($"Eval: {uc.Eval(Expression)}")
End Sub
End Module
Input: Average(1, 2, 3, 4)
Transform: (1 + (2 + (3 + 4))) / (1 + (1 + (1 + 1)))
Eval: 2.5 Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Dim ExprT = uc.ExpressionTransformer '// Transformer used for Eval() and Evaluate() ExprT.DefaultRuleSet.RewindOnChange = true ExprT.FromTo("AddUp({x})", "{x}") ExprT.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))") ExprT.FromTo("ArgCount({x})", "1") ExprT.FromTo("ArgCount({x}, {y})", "(1 + ArgCount({y}))") ExprT.FromTo("Average({x}, {y})", "AddUp({x}, {y}) / ArgCount({x}, {y})") Dim Expression = "Average(1, 2, 3, 4)" Console.WriteLine($"Input: {Expression}") Console.WriteLine($"Transform: {ExprT.Transform(Expression)}") Console.WriteLine($"Eval: {uc.Eval(Expression)}") End Sub End Module