parseGroup method
parseGroup Return a row if encounters [] or {}. Returns single function node or a single symbol otherwise.
If optional
is false or absent, this parses an ordinary group,
which is either a single nucleus (like "x") or an expression
in braces (like "{x+y}") or an implicit group, a group that starts
at the current position, and ends right before a higher explicit
group ends, or at EOF.
If optional
is true, it parses either a bracket-delimited expression
(like "x+y
") or returns null to indicate the absence of a
bracket-enclosed group.
If mode
is present, switches to that mode while parsing the group,
and switches back after.
Implementation
GreenNode? parseGroup(
String name, {
required bool optional,
int? greediness,
String? breakOnTokenText,
Mode? mode,
bool consumeSpaces = false,
}) {
// Save current mode and restore after completion
final outerMode = this.mode;
if (mode != null) {
this.switchMode(mode);
}
// Consume spaces if requested, crucially *after* we switch modes,
// so that the next non-space token is parsed in the correct mode.
if (consumeSpaces == true) {
this.consumeSpaces();
}
// Get first token
final firstToken = this.fetch();
final text = firstToken.text;
GreenNode? result;
// Try to parse an open brace or \begingroup
if (optional ? text == '[' : text == '{' || text == '\\begingroup') {
this.consume();
final groupEnd = endOfGroup[text]!;
// Start a new group namespace
this.macroExpander.beginGroup();
// If we get a brace, parse an expression
final expression =
this.parseExpression(breakOnInfix: false, breakOnTokenText: groupEnd);
// final lastToken = this.fetch();
// Check that we got a matching closing brace
this.expect(groupEnd);
this.macroExpander.endGroup();
result = expression.wrapWithEquationRow();
} else if (optional) {
// Return nothing for an optional group
result = null;
} else {
// If there exists a function with this name, parse the function.
// Otherwise, just return a nucleus
result = this.parseFunction(breakOnTokenText, name, greediness) ??
this._parseSymbol();
if (result == null &&
text[0] == '\\' &&
!implicitCommands.contains(text)) {
if (this.settings.throwOnError) {
throw ParseException('Undefined control sequence: $text', firstToken);
}
result = this._formatUnsuppotedCmd(text);
this.consume();
}
}
if (mode != null) {
this.switchMode(outerMode);
}
return result;
}