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.
StatementSensitive = [bool]
Property
Product:
Class:
Controls whether a pattern rule respects statement separators (like semicolons or newlines), preventing matches from crossing structural boundaries.
Remarks
🛡️ Structural Integrity: The StatementSensitive Property
The StatementSensitive property controls whether a pattern is aware of statement separators, preventing a variable capture from spanning across multiple distinct statements. When enabled (the default), it acts as a crucial safety feature, ensuring that a pattern like "start {body} end" doesn't accidentally consume an entire file if the "end" token is missing.
This property provides per-rule control, overriding the global setting inherited from the Transformer's DefaultRuleSet.
⚙️ How It Works
This property acts as a switch for an individual rule's parsing logic.
| Setting | Behavior |
|---|---|
true (Default) | Structurally Aware. The parser treats tokens categorized as TokenType::StatementSep (by default, newlines and semicolons) as hard boundaries for variable captures. A pattern like if {etc} will match only up to the end of the line or the next semicolon. |
false | Structurally Unaware. Statement separators are treated like any other generic token. This is essential for parsing multi-line content such as HTML/XML blocks or free-form text where newlines are simply formatting. |
By default, the uCalc expression engine defines the newline (_token_newline) and semicolon (_token_semicolon) tokens as statement separators. You can customize this by modifying the token definitions using the Transformer.Tokens property.
💡 Why uCalc? (Comparative Analysis)
In traditional regular expressions, handling multi-line text is notoriously tricky.
- The dot
.meta-character, by default, does not match newlines. To match across lines, you often have to enable a special "dotall" or "single-line" mode (e.g., the/sflag). This is a global switch for the entire regex. - Alternatively, you must use complex character classes like
[\s\S]to match any character including newlines.
This is a blunt, all-or-nothing approach that lacks structural awareness.
uCalc's StatementSensitive property is more sophisticated because it is based on the semantic role of tokens, not just character types:
- Tokenizer Awareness: The tokenizer runs first and identifies tokens with the
TokenType::StatementSepproperty. - Safe Matching by Default: When
StatementSensitiveistrue, the parser respects these separators as boundaries, preventing greedy variable captures from "leaking" across statements. This provides a much safer default behavior for parsing structured code or data. - Granular Control: You can disable this safety feature on a per-rule basis, allowing you to have some rules that respect statement boundaries and others that don't, all within the same
Transformerand running concurrently.
This gives you the flexibility to parse complex, mixed-content documents in a way that is far more robust and maintainable than with regex alone.
Examples
Succinct: Demonstrates the difference in variable capture behavior when StatementSensitive is enabled versus disabled.
using uCalcSoftware;
var uc = new uCalc();
var t = new uCalc.Transformer();
string txt = "start one; two end";
// Default behavior is StatementSensitive(true), so {body} stops at the semicolon
// and the 'end' anchor is never found. The transform fails.
var rule = t.FromTo("start {body} end", "[{body}]");
Console.WriteLine($"Sensitive (default): {t.Transform(txt)}");
rule.StatementSensitive = false;
// With StatementSensitive(false), {body} captures across the semicolon.
Console.WriteLine($"Insensitive: {t.Transform(txt)}");
Sensitive (default): start one; two end
Insensitive: [one; two] using uCalcSoftware; var uc = new uCalc(); var t = new uCalc.Transformer(); string txt = "start one; two end"; // Default behavior is StatementSensitive(true), so {body} stops at the semicolon // and the 'end' anchor is never found. The transform fails. var rule = t.FromTo("start {body} end", "[{body}]"); Console.WriteLine($"Sensitive (default): {t.Transform(txt)}"); rule.StatementSensitive = false; // With StatementSensitive(false), {body} captures across the semicolon. Console.WriteLine($"Insensitive: {t.Transform(txt)}");
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
uCalc::Transformer t;
string txt = "start one; two end";
// Default behavior is StatementSensitive(true), so {body} stops at the semicolon
// and the 'end' anchor is never found. The transform fails.
auto rule = t.FromTo("start {body} end", "[{body}]");
cout << "Sensitive (default): " << t.Transform(txt) << endl;
rule.StatementSensitive(false);
// With StatementSensitive(false), {body} captures across the semicolon.
cout << "Insensitive: " << t.Transform(txt) << endl;
}
Sensitive (default): start one; two end
Insensitive: [one; two] #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; uCalc::Transformer t; string txt = "start one; two end"; // Default behavior is StatementSensitive(true), so {body} stops at the semicolon // and the 'end' anchor is never found. The transform fails. auto rule = t.FromTo("start {body} end", "[{body}]"); cout << "Sensitive (default): " << t.Transform(txt) << endl; rule.StatementSensitive(false); // With StatementSensitive(false), {body} captures across the semicolon. cout << "Insensitive: " << t.Transform(txt) << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Dim t As New uCalc.Transformer()
Dim txt As String = "start one; two end"
'// Default behavior is StatementSensitive(true), so {body} stops at the semicolon
'// and the 'end' anchor is never found. The transform fails.
Dim rule = t.FromTo("start {body} end", "[{body}]")
Console.WriteLine($"Sensitive (default): {t.Transform(txt)}")
rule.StatementSensitive = false
'// With StatementSensitive(false), {body} captures across the semicolon.
Console.WriteLine($"Insensitive: {t.Transform(txt)}")
End Sub
End Module
Sensitive (default): start one; two end
Insensitive: [one; two] Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Dim t As New uCalc.Transformer() Dim txt As String = "start one; two end" '// Default behavior is StatementSensitive(true), so {body} stops at the semicolon '// and the 'end' anchor is never found. The transform fails. Dim rule = t.FromTo("start {body} end", "[{body}]") Console.WriteLine($"Sensitive (default): {t.Transform(txt)}") rule.StatementSensitive = false '// With StatementSensitive(false), {body} captures across the semicolon. Console.WriteLine($"Insensitive: {t.Transform(txt)}") End Sub End Module
Practical: Shows how disabling statement sensitivity is essential for parsing multi-line HTML/XML blocks.
using uCalcSoftware;
var uc = new uCalc();
var t = new uCalc.Transformer();
var source = """
content spans
multiple lines
""";
// This rule must disable StatementSensitive to capture the multi-line body,
// otherwise the first newline would terminate the {body} variable.
var rule = t.FromTo("{body}", "Body: [{body}]");
rule.StatementSensitive = false;
Console.WriteLine(t.Transform(source));
Body: [
content spans
multiple lines
] using uCalcSoftware; var uc = new uCalc(); var t = new uCalc.Transformer(); var source = """ <data> content spans multiple lines </data> """; // This rule must disable StatementSensitive to capture the multi-line body, // otherwise the first newline would terminate the {body} variable. var rule = t.FromTo("<data>{body}</data>", "Body: [{body}]"); rule.StatementSensitive = false; Console.WriteLine(t.Transform(source));
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
uCalc::Transformer t;
auto source = R"(
content spans
multiple lines
)";
// This rule must disable StatementSensitive to capture the multi-line body,
// otherwise the first newline would terminate the {body} variable.
auto rule = t.FromTo("{body}", "Body: [{body}]");
rule.StatementSensitive(false);
cout << t.Transform(source) << endl;
}
Body: [
content spans
multiple lines
] #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; uCalc::Transformer t; auto source = R"(<data> content spans multiple lines </data>)"; // This rule must disable StatementSensitive to capture the multi-line body, // otherwise the first newline would terminate the {body} variable. auto rule = t.FromTo("<data>{body}</data>", "Body: [{body}]"); rule.StatementSensitive(false); cout << t.Transform(source) << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Dim t As New uCalc.Transformer()
Dim source = "
content spans
multiple lines
"
'// This rule must disable StatementSensitive to capture the multi-line body,
'// otherwise the first newline would terminate the {body} variable.
Dim rule = t.FromTo("{body}", "Body: [{body}]")
rule.StatementSensitive = false
Console.WriteLine(t.Transform(source))
End Sub
End Module
Body: [
content spans
multiple lines
] Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Dim t As New uCalc.Transformer() Dim source = "<data> content spans multiple lines </data>" '// This rule must disable StatementSensitive to capture the multi-line body, '// otherwise the first newline would terminate the {body} variable. Dim rule = t.FromTo("<data>{body}</data>", "Body: [{body}]") rule.StatementSensitive = false Console.WriteLine(t.Transform(source)) End Sub End Module
Using SkipOver() to ignore XML-style comments
using uCalcSoftware;
var uc = new uCalc();
// StatementSensitive() is set to false so that ";" and newline are not treated as special
var t = uc.NewTransformer();
Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}");
Console.WriteLine("Setting StatementSensitive to False");
t.DefaultRuleSet.StatementSensitive = false; // so that newline does not behave as a statement separator
Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}");
Console.WriteLine("");
var Content =
"""
""";
t.Str(Content);
var Pattern = t.Pattern(" {item} ");
t.Find();
Console.WriteLine(t.Matches.Text);
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("----------------------------------");
t.SkipOver("");
t.Find();
Console.WriteLine(t.Matches.Text);
Console.WriteLine("");
StatementSensitive: True
Setting StatementSensitive to False
StatementSensitive: False
<li><a href="#intro">Intro</a></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#contact">Contact</a></li>
<li>3 cups flour</li>
<li>1.5 cups water</li>
<li>1 tsp salt</li>
<li><a href="#one">One</a></li>
<li><a href="#two">Two</a></li>
<li><a href="#three">Three</a></li>
<!-- Skip over commented lines -->
----------------------------------
<li><a href="#intro">Intro</a></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#one">One</a></li>
<li><a href="#two">Two</a></li>
<li><a href="#three">Three</a></li> using uCalcSoftware; var uc = new uCalc(); // StatementSensitive() is set to false so that ";" and newline are not treated as special var t = uc.NewTransformer(); Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}"); Console.WriteLine("Setting StatementSensitive to False"); t.DefaultRuleSet.StatementSensitive = false; // so that newline does not behave as a statement separator Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}"); Console.WriteLine(""); var Content = """ <nav aria-label="Main navigation"> <ul> <li><a href="#intro">Intro</a></li> <li><a href="#examples">Examples</a></li> <!-- <li><a href="#contact">Contact</a></li> --> </ul> </nav> <!-- <h2>Ingredients</h2> <ul> <li>3 cups flour</li> <li>1.5 cups water</li> <li>1 tsp salt</li> </ul> --> <nav aria-label="Chapter navigation"> <ul> <li><a href="#one">One</a></li> <li><a href="#two">Two</a></li> <li><a href="#three">Three</a></li> </ul> </nav> """; t.Str(Content); var Pattern = t.Pattern("<li>{item}</li>"); t.Find(); Console.WriteLine(t.Matches.Text); Console.WriteLine(""); Console.WriteLine("<!-- Skip over commented lines -->"); Console.WriteLine("----------------------------------"); t.SkipOver("<!-- {comment} -->"); t.Find(); Console.WriteLine(t.Matches.Text); Console.WriteLine("");
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
#define tf(IsTrue) ((IsTrue) ? "True" : "False")
int main() {
uCalc uc;
// StatementSensitive() is set to false so that ";" and newline are not treated as special
auto t = uc.NewTransformer();
cout << "StatementSensitive: " << tf(t.DefaultRuleSet().StatementSensitive()) << endl;
cout << "Setting StatementSensitive to False" << endl;
t.DefaultRuleSet().StatementSensitive(false); // so that newline does not behave as a statement separator
cout << "StatementSensitive: " << tf(t.DefaultRuleSet().StatementSensitive()) << endl;
cout << "" << endl;
auto Content =
R"(
)";
t.Str(Content);
auto Pattern = t.Pattern("{item} ");
t.Find();
cout << t.Matches().Text() << endl;
cout << "" << endl;
cout << "" << endl;
cout << "----------------------------------" << endl;
t.SkipOver("");
t.Find();
cout << t.Matches().Text() << endl;
cout << "" << endl;
}
StatementSensitive: True
Setting StatementSensitive to False
StatementSensitive: False
<li><a href="#intro">Intro</a></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#contact">Contact</a></li>
<li>3 cups flour</li>
<li>1.5 cups water</li>
<li>1 tsp salt</li>
<li><a href="#one">One</a></li>
<li><a href="#two">Two</a></li>
<li><a href="#three">Three</a></li>
<!-- Skip over commented lines -->
----------------------------------
<li><a href="#intro">Intro</a></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#one">One</a></li>
<li><a href="#two">Two</a></li>
<li><a href="#three">Three</a></li> #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; #define tf(IsTrue) ((IsTrue) ? "True" : "False") int main() { uCalc uc; // StatementSensitive() is set to false so that ";" and newline are not treated as special auto t = uc.NewTransformer(); cout << "StatementSensitive: " << tf(t.DefaultRuleSet().StatementSensitive()) << endl; cout << "Setting StatementSensitive to False" << endl; t.DefaultRuleSet().StatementSensitive(false); // so that newline does not behave as a statement separator cout << "StatementSensitive: " << tf(t.DefaultRuleSet().StatementSensitive()) << endl; cout << "" << endl; auto Content = R"( <nav aria-label="Main navigation"> <ul> <li><a href="#intro">Intro</a></li> <li><a href="#examples">Examples</a></li> <!-- <li><a href="#contact">Contact</a></li> --> </ul> </nav> <!-- <h2>Ingredients</h2> <ul> <li>3 cups flour</li> <li>1.5 cups water</li> <li>1 tsp salt</li> </ul> --> <nav aria-label="Chapter navigation"> <ul> <li><a href="#one">One</a></li> <li><a href="#two">Two</a></li> <li><a href="#three">Three</a></li> </ul> </nav> )"; t.Str(Content); auto Pattern = t.Pattern("<li>{item}</li>"); t.Find(); cout << t.Matches().Text() << endl; cout << "" << endl; cout << "<!-- Skip over commented lines -->" << endl; cout << "----------------------------------" << endl; t.SkipOver("<!-- {comment} -->"); t.Find(); cout << t.Matches().Text() << endl; cout << "" << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
'// StatementSensitive() is set to false so that ";" and newline are not treated as special
Dim t = uc.NewTransformer()
Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}")
Console.WriteLine("Setting StatementSensitive to False")
t.DefaultRuleSet.StatementSensitive = false '// so that newline does not behave as a statement separator
Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}")
Console.WriteLine("")
Dim Content =
"
"
t.Str(Content)
Dim Pattern = t.Pattern(" {item} ")
t.Find()
Console.WriteLine(t.Matches.Text)
Console.WriteLine("")
Console.WriteLine("")
Console.WriteLine("----------------------------------")
t.SkipOver("")
t.Find()
Console.WriteLine(t.Matches.Text)
Console.WriteLine("")
End Sub
End Module
StatementSensitive: True
Setting StatementSensitive to False
StatementSensitive: False
<li><a href="#intro">Intro</a></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#contact">Contact</a></li>
<li>3 cups flour</li>
<li>1.5 cups water</li>
<li>1 tsp salt</li>
<li><a href="#one">One</a></li>
<li><a href="#two">Two</a></li>
<li><a href="#three">Three</a></li>
<!-- Skip over commented lines -->
----------------------------------
<li><a href="#intro">Intro</a></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#one">One</a></li>
<li><a href="#two">Two</a></li>
<li><a href="#three">Three</a></li> Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() '// StatementSensitive() is set to false so that ";" and newline are not treated as special Dim t = uc.NewTransformer() Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}") Console.WriteLine("Setting StatementSensitive to False") t.DefaultRuleSet.StatementSensitive = false '// so that newline does not behave as a statement separator Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}") Console.WriteLine("") Dim Content = " <nav aria-label=""Main navigation""> <ul> <li><a href=""#intro"">Intro</a></li> <li><a href=""#examples"">Examples</a></li> <!-- <li><a href=""#contact"">Contact</a></li> --> </ul> </nav> <!-- <h2>Ingredients</h2> <ul> <li>3 cups flour</li> <li>1.5 cups water</li> <li>1 tsp salt</li> </ul> --> <nav aria-label=""Chapter navigation""> <ul> <li><a href=""#one"">One</a></li> <li><a href=""#two"">Two</a></li> <li><a href=""#three"">Three</a></li> </ul> </nav> " t.Str(Content) Dim Pattern = t.Pattern("<li>{item}</li>") t.Find() Console.WriteLine(t.Matches.Text) Console.WriteLine("") Console.WriteLine("<!-- Skip over commented lines -->") Console.WriteLine("----------------------------------") t.SkipOver("<!-- {comment} -->") t.Find() Console.WriteLine(t.Matches.Text) Console.WriteLine("") End Sub End Module
StatementSensitive()
using uCalcSoftware;
var uc = new uCalc();
var t = uc.NewTransformer();
t.Text = "x = 1; if (true) func1(3+4); else func2(x*y); y = x + 2";
var p = t.Pattern("if {etc}");
Console.WriteLine($"Input: {t.Text}");
Console.WriteLine($"Pattern: {p.Pattern}");
Console.WriteLine("");
t.Find();
Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}");
Console.WriteLine(t.Matches.Text);
Console.WriteLine("");
t.DefaultRuleSet.StatementSensitive = false;
t.Find();
Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}");
Console.WriteLine(t.Matches.Text);
Input: x = 1; if (true) func1(3+4); else func2(x*y); y = x + 2
Pattern: if {etc}
StatementSensitive: True
if (true) func1(3+4)
StatementSensitive: False
if (true) func1(3+4); else func2(x*y); y = x + 2 using uCalcSoftware; var uc = new uCalc(); var t = uc.NewTransformer(); t.Text = "x = 1; if (true) func1(3+4); else func2(x*y); y = x + 2"; var p = t.Pattern("if {etc}"); Console.WriteLine($"Input: {t.Text}"); Console.WriteLine($"Pattern: {p.Pattern}"); Console.WriteLine(""); t.Find(); Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}"); Console.WriteLine(t.Matches.Text); Console.WriteLine(""); t.DefaultRuleSet.StatementSensitive = false; t.Find(); Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}"); Console.WriteLine(t.Matches.Text);
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
#define tf(IsTrue) ((IsTrue) ? "True" : "False")
int main() {
uCalc uc;
auto t = uc.NewTransformer();
t.Text("x = 1; if (true) func1(3+4); else func2(x*y); y = x + 2");
auto p = t.Pattern("if {etc}");
cout << "Input: " << t.Text() << endl;
cout << "Pattern: " << p.Pattern() << endl;
cout << "" << endl;
t.Find();
cout << "StatementSensitive: " << tf(t.DefaultRuleSet().StatementSensitive()) << endl;
cout << t.Matches().Text() << endl;
cout << "" << endl;
t.DefaultRuleSet().StatementSensitive(false);
t.Find();
cout << "StatementSensitive: " << tf(t.DefaultRuleSet().StatementSensitive()) << endl;
cout << t.Matches().Text() << endl;
}
Input: x = 1; if (true) func1(3+4); else func2(x*y); y = x + 2
Pattern: if {etc}
StatementSensitive: True
if (true) func1(3+4)
StatementSensitive: False
if (true) func1(3+4); else func2(x*y); y = x + 2 #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; #define tf(IsTrue) ((IsTrue) ? "True" : "False") int main() { uCalc uc; auto t = uc.NewTransformer(); t.Text("x = 1; if (true) func1(3+4); else func2(x*y); y = x + 2"); auto p = t.Pattern("if {etc}"); cout << "Input: " << t.Text() << endl; cout << "Pattern: " << p.Pattern() << endl; cout << "" << endl; t.Find(); cout << "StatementSensitive: " << tf(t.DefaultRuleSet().StatementSensitive()) << endl; cout << t.Matches().Text() << endl; cout << "" << endl; t.DefaultRuleSet().StatementSensitive(false); t.Find(); cout << "StatementSensitive: " << tf(t.DefaultRuleSet().StatementSensitive()) << endl; cout << t.Matches().Text() << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Dim t = uc.NewTransformer()
t.Text = "x = 1; if (true) func1(3+4); else func2(x*y); y = x + 2"
Dim p = t.Pattern("if {etc}")
Console.WriteLine($"Input: {t.Text}")
Console.WriteLine($"Pattern: {p.Pattern}")
Console.WriteLine("")
t.Find()
Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}")
Console.WriteLine(t.Matches.Text)
Console.WriteLine("")
t.DefaultRuleSet.StatementSensitive = false
t.Find()
Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}")
Console.WriteLine(t.Matches.Text)
End Sub
End Module
Input: x = 1; if (true) func1(3+4); else func2(x*y); y = x + 2
Pattern: if {etc}
StatementSensitive: True
if (true) func1(3+4)
StatementSensitive: False
if (true) func1(3+4); else func2(x*y); y = x + 2 Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Dim t = uc.NewTransformer() t.Text = "x = 1; if (true) func1(3+4); else func2(x*y); y = x + 2" Dim p = t.Pattern("if {etc}") Console.WriteLine($"Input: {t.Text}") Console.WriteLine($"Pattern: {p.Pattern}") Console.WriteLine("") t.Find() Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}") Console.WriteLine(t.Matches.Text) Console.WriteLine("") t.DefaultRuleSet.StatementSensitive = false t.Find() Console.WriteLine($"StatementSensitive: {t.DefaultRuleSet.StatementSensitive}") Console.WriteLine(t.Matches.Text) End Sub End Module