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.

ContextSwitch(Tokens, string, string)

Method

Product: 

Transformer Library

Class: 

Tokens

Temporarily replaces the active token set when a start pattern is matched, until an end pattern is found.

Syntax

ContextSwitch(Tokens, string, string)

Parameters

newTokenSet
Tokens
The `Tokens` collection to activate when the `startPattern` is matched.
startPattern
string
A regular expression that defines the token that triggers the switch to the `newTokenSet`.
endPattern
string
A regular expression that defines the token that ends the context switch and reverts to the original token set.

Return

Tokens

Returns the current Tokens object to allow for a fluent, chainable interface.

Remarks

⚙️ Parsing Embedded Languages with ContextSwitch

The ContextSwitch method is an advanced feature for parsing documents that contain multiple, distinct syntaxes, such as an embedded language. It dynamically swaps the tokenizer's rule set when a specific boundary is crossed.

How It Works

When you call ContextSwitch, you are defining a special, high-precedence rule. During parsing:

  1. The tokenizer scans text using the main Tokens collection.
  2. If it finds a match for startPattern, it immediately suspends the main token set and begins using newTokenSet.
  3. It continues using newTokenSet until it finds a match for endPattern.
  4. Once endPattern is found, it reverts to the original token set.

A classic real-world analogy is parsing HTML with embedded JavaScript:

  • The main token set would define HTML tags (<, >).
  • startPattern would be <script>.
  • newTokenSet would contain tokens for JavaScript (keywords, operators, etc.).
  • endPattern would be </script>.

This allows the same Transformer to correctly parse both languages in a single pass.

⚠️ Non-Nesting Behavior

By default, context switches are not nestable. If the tokenizer is already inside a context switch and encounters another startPattern, the second pattern is ignored. The context switch is only terminated by the first endPattern it finds. See the internal test example for a demonstration of this behavior.


💡 ContextSwitch vs. LocalTransformer

Both ContextSwitch and Rule.LocalTransformer handle nested or scoped parsing, but they operate at different stages of the process. LocalTransformer is the tool for hierarchical, nestable parsing.

FeatureTokens.ContextSwitch (This Topic)Rule.LocalTransformer
StageLexical (Tokenizer)Syntactic (Parser)
What it DoesSwaps the entire set of token definitions. Changes how text is broken into tokens.Applies a new set of grammar rules to a block of already-tokenized text.
AnalogySwitching from the English alphabet to the Greek alphabet mid-sentence.Applying different sentence diagramming rules to a specific paragraph.
NestingNo. Switches are not nestable by default.Yes. Local transformers can be nested to any depth, creating a true hierarchy.
Use CaseParsing completely different, embedded languages (e.g., <script> in HTML, SQL in a string literal).Recursively parsing nested structures within the same language (e.g., finding <img> tags only within <div> tags).

When to Use Which

  • Use ContextSwitch when you encounter a block of text that follows entirely different lexical rules from the surrounding document.
  • Use LocalTransformer when you want to apply a more specific set of find/replace patterns only within a region that has already been matched by a parent rule, using the same lexical rules.

🆚 Comparative Analysis

  • vs. Regular Expressions: Regex has no built-in concept of lexical states. Handling embedded syntaxes would require complex lookarounds or multiple, separate parsing passes managed by your application's code, which is inefficient and error-prone.

  • vs. Parser Generators (ANTLR, Flex/Bison): Traditional compiler tools handle this with "lexical modes" or "states" defined within a static grammar file. The key advantage of uCalc is its dynamic, programmatic nature. You can define, modify, and apply these context switches at runtime without any external tools or recompilation, allowing for highly adaptable and user-configurable parsers.

Examples

A succinct example that uses a context switch to prevent transformations inside a designated `[RAW]` block.
				
					using uCalcSoftware;

var uc = new uCalc();
var t = new uCalc.Transformer();
string text = "Replace config, but not the one inside [RAW]this config is raw[/RAW].";

// Create a token set for the raw block that only tokenizes single characters.
var rawTransformer = new uCalc.Transformer();
var rawTokens = rawTransformer.Tokens;
rawTokens.Clear();
rawTokens.Add("."); // Match any single character

// Switch to rawTokens when [RAW] is found, and switch back at [/RAW].
t.Tokens.ContextSwitch(rawTokens, """
\[RAW\]
""", """
\[/RAW\]
""");

t.FromTo("config", "SETTING");

Console.WriteLine(t.Transform(text));
				
			
Replace SETTING, but not the one inside [RAW]this config is raw[/RAW].
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   uCalc::Transformer t;
   string text = "Replace config, but not the one inside [RAW]this config is raw[/RAW].";

   // Create a token set for the raw block that only tokenizes single characters.
   uCalc::Transformer rawTransformer;
   auto rawTokens = rawTransformer.Tokens();
   rawTokens.Clear();
   rawTokens.Add("."); // Match any single character

   // Switch to rawTokens when [RAW] is found, and switch back at [/RAW].
   t.Tokens().ContextSwitch(rawTokens, R"(\[RAW\])", R"(\[/RAW\])");

   t.FromTo("config", "SETTING");

   cout << t.Transform(text) << endl;
}
				
			
Replace SETTING, but not the one inside [RAW]this config is raw[/RAW].
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t As New uCalc.Transformer()
      Dim text As String = "Replace config, but not the one inside [RAW]this config is raw[/RAW]."
      
      '// Create a token set for the raw block that only tokenizes single characters.
      Dim rawTransformer As New uCalc.Transformer()
      Dim rawTokens = rawTransformer.Tokens
      rawTokens.Clear()
      rawTokens.Add(".") '// Match any single character
      
      '// Switch to rawTokens when [RAW] is found, and switch back at [/RAW].
      t.Tokens.ContextSwitch(rawTokens, "\[RAW\]", "\[/RAW\]")
      
      t.FromTo("config", "SETTING")
      
      Console.WriteLine(t.Transform(text))
   End Sub
End Module
				
			
Replace SETTING, but not the one inside [RAW]this config is raw[/RAW].
Token Context switch
				
					using uCalcSoftware;

var uc = new uCalc();
var CommentTransform = uc.NewTransformer();
var CommentTokens = CommentTransform.Tokens;
CommentTokens.Add(".");
CommentTokens.Add("[a-z]+");

var txt = "'This is it' /* 'This is it' This is it */ This is it";

var t = uc.NewTransformer();
t.FromTo("is", "<is>");
Console.WriteLine(t.Transform(txt).Text);

// Now the context will switch between /* and */
// In that context there's no quoted text token,
t.Tokens.ContextSwitch(CommentTokens, "/\\*", "\\*/");
t.FromTo("is", "<is>");
Console.WriteLine(t.Transform(txt).Text);

				
			
'This is it' /* 'This is it' This <is> it */ This <is> it
'This is it' /* 'This <is> it' This <is> it */ This <is> it
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   auto CommentTransform = uc.NewTransformer();
   auto CommentTokens = CommentTransform.Tokens();
   CommentTokens.Add(".");
   CommentTokens.Add("[a-z]+");

   auto txt = "'This is it' /* 'This is it' This is it */ This is it";

   auto t = uc.NewTransformer();
   t.FromTo("is", "<is>");
   cout << t.Transform(txt).Text() << endl;

   // Now the context will switch between /* and */
   // In that context there's no quoted text token,
   t.Tokens().ContextSwitch(CommentTokens, "/\\*", "\\*/");
   t.FromTo("is", "<is>");
   cout << t.Transform(txt).Text() << endl;

}
				
			
'This is it' /* 'This is it' This <is> it */ This <is> it
'This is it' /* 'This <is> it' This <is> it */ This <is> it
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim CommentTransform = uc.NewTransformer()
      Dim CommentTokens = CommentTransform.Tokens
      CommentTokens.Add(".")
      CommentTokens.Add("[a-z]+")
      
      Dim txt = "'This is it' /* 'This is it' This is it */ This is it"
      
      Dim t = uc.NewTransformer()
      t.FromTo("is", "<is>")
      Console.WriteLine(t.Transform(txt).Text)
      
      '// Now the context will switch between /* and */
      '// In that context there's no quoted text token,
      t.Tokens.ContextSwitch(CommentTokens, "/\*", "\*/")
      t.FromTo("is", "<is>")
      Console.WriteLine(t.Transform(txt).Text)
      
   End Sub
End Module
				
			
'This is it' /* 'This is it' This <is> it */ This <is> it
'This is it' /* 'This <is> it' This <is> it */ This <is> it