Skip to content

Commit

Permalink
Refactor the \left and \right commands (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Jan 3, 2020
1 parent 54d5911 commit 923e898
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 61 deletions.
32 changes: 13 additions & 19 deletions src/WpfMath/Atoms/SymbolAtom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,31 +35,25 @@ static SymbolAtom()
validSymbolTypes.Set((int)TexAtomType.Accent, true);
}

public static SymbolAtom GetAtom(string name, SourceSpan source)
public static bool TryGetAtom(string name, SourceSpan source, out SymbolAtom atom)
{
try
if (!symbols.TryGetValue(name, out var factory))
{
var symbol = symbols[name](source);
return new SymbolAtom(source, symbol, symbol.Type);
atom = null;
return false;
}
catch (KeyNotFoundException)
{
throw new SymbolNotFoundException(name);
}
}

public static bool TryGetAtom(SourceSpan name, out SymbolAtom atom)
{
if (symbols.TryGetValue(name.ToString(), out var temp))
{
var symbol = temp(name);
atom = new SymbolAtom(name, symbol, symbol.Type);
return true;
}
atom = null;
return false;
var symbol = factory(source);
atom = new SymbolAtom(source, symbol, symbol.Type);
return true;
}

public static SymbolAtom GetAtom(string name, SourceSpan source) =>
TryGetAtom(name, source, out var atom) ? atom : throw new SymbolNotFoundException(name);

public static bool TryGetAtom(SourceSpan name, out SymbolAtom atom) =>
TryGetAtom(name.ToString(), name, out atom);

public SymbolAtom(SourceSpan source, SymbolAtom symbolAtom, TexAtomType type)
: base(source, type)
{
Expand Down
76 changes: 34 additions & 42 deletions src/WpfMath/TexFormulaParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,8 @@ private static SourceSpan ReadElementGroupOptional(

private static SourceSpan ReadEscapeSequence(SourceSpan value, ref int position)
{
if (value[position] != escapeChar)
var initialPosition = position;
if (value[initialPosition] != escapeChar)
throw new Exception($"Invalid state: {nameof(ReadEscapeSequence)} called for a value without escape character ({value})");

position++;
Expand All @@ -384,11 +385,37 @@ private static SourceSpan ReadEscapeSequence(SourceSpan value, ref int position)
position++;
}

var length = position - start;
if (length == 0)
var length = position - initialPosition;
if (length <= 1)
throw new TexParseException($"Unfinished escape sequence (value: \"{value}\", index {position})");

return value.Segment(start, length);
return value.Segment(initialPosition, length);
}

private SymbolAtom ParseDelimiter(SourceSpan value, int start, ref int position)
{
var delimiter = ReadElement(value, ref position);

string delimiterName;
if (delimiter.Length == 1)
delimiterName = GetDelimeterMapping(delimiter[0]);
else
{
if (delimiter[0] != escapeChar)
throw new Exception($"Incorrect parser state: delimiter should start from {escapeChar}: {delimiter}");

// Here goes the fancy business: for non-alphanumeric commands (e.g. \{, \\ etc.) we need to pass them
// through GetDelimeterMapping, but for alphanumeric ones, we don't.
delimiterName = delimiter.Segment(1).ToString(); // skip an escape character
if (delimiterName.Length == 1 && !char.IsLetterOrDigit(delimiterName[0]))
delimiterName = GetDelimeterMapping(delimiterName[0]);
}

var delimiterSource = value.Segment(start, position - start); // will map the whole "\left(" to a delimiter atom created
if (delimiterName == null || !SymbolAtom.TryGetAtom(delimiterName, delimiterSource, out var atom) || !atom.IsDelimeter)
throw new TexParseException($"Cannot find delimiter {delimiter}");

return atom;
}

/// <summary>
Expand Down Expand Up @@ -452,27 +479,8 @@ private Atom ProcessCommand(
if (position == value.Length)
throw new TexParseException("`left` command should be passed a delimiter");

string delimiter = ReadElement(value, ref position).ToString().Trim();

var left = position;

var opening = ParseDelimiter(value, start, ref position);
var internals = ParseUntilDelimiter(value, ref position, formula.TextStyle, environment);

SymbolAtom opening = null;
if (delimiter.Length == 1)
{
opening = GetDelimiterSymbol(
GetDelimeterMapping(delimiter[0]),
value.Segment(start, left - start));
}
if (delimiter.Length > 1)
{
opening = GetDelimiterSymbol(
delimiter.Replace('\\', ' ').Trim(), value.Segment(start, left - start));
}
if (opening == null)
throw new TexParseException($"Cannot find delimiter named {delimiter}");

var closing = internals.ClosingDelimiter;
source = value.Segment(start, position - start);
return new FencedAtom(source, internals.Body, opening, closing);
Expand All @@ -495,22 +503,7 @@ private Atom ProcessCommand(
if (position == value.Length)
throw new TexParseException("`right` command should be passed a delimiter");

string delimiter = ReadElement(value, ref position).ToString().Trim();

SymbolAtom closing = null;
if (delimiter.Length == 1)
{
closing = GetDelimiterSymbol(
GetDelimeterMapping(delimiter[0]),
value.Segment(start, position - start));
}
if (delimiter.Length > 1)
{
closing = GetDelimiterSymbol(
delimiter.Replace('\\', ' ').Trim(), value.Segment(start, position - start));
}
if (closing == null)
throw new TexParseException($"Cannot find delimiter named {delimiter}");
var closing = ParseDelimiter(value, start, ref position);

closedDelimiter = true;
return closing;
Expand Down Expand Up @@ -611,8 +604,7 @@ private void ProcessEscapeSequence(TexFormula formula,
ICommandEnvironment environment)
{
var initialSrcPosition = position;
var commandSpan = ReadEscapeSequence(value, ref position);
var commandNameStart = position + 1; // 1 for backslash
var commandSpan = ReadEscapeSequence(value, ref position).Segment(1);
var command = commandSpan.ToString();
var formulaSource = new SourceSpan(value.Source, initialSrcPosition, commandSpan.End);

Expand Down

0 comments on commit 923e898

Please sign in to comment.