diff --git a/src/WpfMath.Example/MainWindow.xaml.cs b/src/WpfMath.Example/MainWindow.xaml.cs index a91ce77f..d42822f6 100644 --- a/src/WpfMath.Example/MainWindow.xaml.cs +++ b/src/WpfMath.Example/MainWindow.xaml.cs @@ -96,7 +96,7 @@ private void Window_Loaded(object sender, RoutedEventArgs e) var testFormula1 = "\\int_0^{\\infty}{x^{2n} e^{-a x^2} dx} = \\frac{2n-1}{2a} \\int_0^{\\infty}{x^{2(n-1)} e^{-a x^2} dx} = \\frac{(2n-1)!!}{2^{n+1}} \\sqrt{\\frac{\\pi}{a^{2n+1}}}"; var testFormula2 = "\\int_a^b{f(x) dx} = (b - a) \\sum_{n = 1}^{\\infty} {\\sum_{m = 1}^{2^n - 1} { ( { - 1} )^{m + 1} } } 2^{ - n} f(a + m ( {b - a} )2^{-n} )"; - var testFormula3 = @"L = \int_a^b \sqrt[4]{ \left| \sum_{i,j=1}^ng_{ij}\left(\gamma(t)\right) \left[\frac{d}{dt}x^i\circ\gamma(t) \right] \left{\frac{d}{dt}x^j\circ\gamma(t) \right} \right|}dt"; + var testFormula3 = @"L = \int_a^\infty \sqrt[4]{ \left\vert \sum_{i,j=1}^ng_{ij}\left\(\gamma(t)\right\) \left\[\frac{d}{dt}x^i\circ\gamma(t) \right\] \left\{\frac{d}{dt}x^j\circ\gamma(t) \right\} \right\|}dt"; //matrix examples var testFormula4 = @"\matrix{4&78&3 \\ 5 & 9 & 82 }"; var testFormula5 = @"\cases{x,&if x > 0;\cr -x,& otherwise.}"; diff --git a/src/WpfMath/Parsers/Matrices/MatrixCommandParser.cs b/src/WpfMath/Parsers/Matrices/MatrixCommandParser.cs index 00ac207b..7b0e7883 100644 --- a/src/WpfMath/Parsers/Matrices/MatrixCommandParser.cs +++ b/src/WpfMath/Parsers/Matrices/MatrixCommandParser.cs @@ -30,7 +30,7 @@ public CommandProcessingResult ProcessCommand(CommandContext context) if (position == source.Length) throw new TexParseException("illegal end!"); - var cellsSource = TexFormulaParser.ReadElement(source, ref position); + var cellsSource = TexFormulaParser.ReadArgument(source, ref position); var matrixSource = context.CommandSource.Segment( context.CommandNameStartPosition, position - context.CommandNameStartPosition); diff --git a/src/WpfMath/Parsers/StandardCommands.cs b/src/WpfMath/Parsers/StandardCommands.cs index 546ef2e1..fe2daede 100644 --- a/src/WpfMath/Parsers/StandardCommands.cs +++ b/src/WpfMath/Parsers/StandardCommands.cs @@ -13,7 +13,7 @@ public CommandProcessingResult ProcessCommand(CommandContext context) var source = context.CommandSource; var position = context.ArgumentsStartPosition; var underlineFormula = context.Parser.Parse( - TexFormulaParser.ReadElement(source, ref position), + TexFormulaParser.ReadArgument(source, ref position), context.Formula.TextStyle, context.Environment); var start = context.CommandNameStartPosition; @@ -30,11 +30,11 @@ public CommandProcessingResult ProcessCommand(CommandContext context) var source = context.CommandSource; var position = context.ArgumentsStartPosition; var topFormula = context.Parser.Parse( - TexFormulaParser.ReadElement(source, ref position), + TexFormulaParser.ReadArgument(source, ref position), context.Formula.TextStyle, context.Environment.CreateChildEnvironment()); var bottomFormula = context.Parser.Parse( - TexFormulaParser.ReadElement(source, ref position), + TexFormulaParser.ReadArgument(source, ref position), context.Formula.TextStyle, context.Environment.CreateChildEnvironment()); var start = context.CommandNameStartPosition; diff --git a/src/WpfMath/TexFormulaParser.cs b/src/WpfMath/TexFormulaParser.cs index 9b92e36f..c6e38821 100644 --- a/src/WpfMath/TexFormulaParser.cs +++ b/src/WpfMath/TexFormulaParser.cs @@ -104,7 +104,7 @@ internal static string GetDelimeterMapping(char character) } catch (KeyNotFoundException) { - throw new DelimiterMappingNotFoundException(character); + throw new TexParseException(new DelimiterMappingNotFoundException(character).Message); } } @@ -253,7 +253,7 @@ private TexFormula Parse( } else if (ch == leftGroupChar) { - var groupValue = ReadElement(value, ref position); + var groupValue = ReadArgument(value, ref position); var parsedGroup = Parse(groupValue, textStyle, environment.CreateChildEnvironment()); var innerGroupAtom = parsedGroup.RootAtom ?? new RowAtom(groupValue); var groupAtom = new TypedAtom( @@ -318,7 +318,7 @@ private static TexFormula ConvertRawText(SourceSpan value, string textStyle) return formula; } - internal static SourceSpan ReadElementGroup(SourceSpan value, ref int position, char openChar, char closeChar) + internal static SourceSpan ReadArgumentGroup(SourceSpan value, ref int position, char openChar, char closeChar) { if (position == value.Length || value[position] != openChar) throw new TexParseException("missing '" + openChar + "'!"); @@ -356,24 +356,55 @@ private static SourceSpan ReadElementGroupOptional( if (value[position] != openChar) return null; - return ReadElementGroup(value, ref position, openChar, closeChar); + return ReadArgumentGroup(value, ref position, openChar, closeChar); } - /// Reads an element: typically, a curly brace-enclosed value group or a singular value. + /// Reads an argument: typically, a curly brace-enclosed value group, a singular value or an escaped sequence of letters/a character. /// Will be thrown for ill-formed groups. - internal static SourceSpan ReadElement(SourceSpan value, ref int position) + internal static SourceSpan ReadArgument(SourceSpan value, ref int position) { - SkipWhiteSpace(value, ref position); - - if (position == value.Length) - throw new TexParseException("An element is missing"); - - if (value[position] == leftGroupChar) + if (position < value.Length) { - return ReadElementGroup(value, ref position, leftGroupChar, rightGroupChar); - } + if (value[position] == leftGroupChar) + return ReadArgumentGroup(value, ref position, leftGroupChar, rightGroupChar); + else if (value[position] == escapeChar) + { + position++; + var start = position; - return value.Segment(position++, 1); + if (position < value.Length) + { + if (!Char.IsLetter(value[position])) + { + position++; + return value.Segment(start, 1); + } + else + { + bool elementfound = false; + while (position < value.Length && elementfound == false) + { + if (!Char.IsLetter(value[position])) + { + elementfound = true; + position--; + } + position++; + } + if (elementfound) + return value.Segment(start-1, position - start+1); + else + throw new TexParseException("An argument is missing"); + } + } + else + throw new TexParseException("An argument is missing"); + } + else + return value.Segment(position++, 1); + } + else + throw new TexParseException("An argument is missing"); } private TexFormula ReadScript( @@ -381,7 +412,7 @@ private TexFormula ReadScript( SourceSpan value, ref int position, ICommandEnvironment environment) => - Parse(ReadElement(value, ref position), formula.TextStyle, environment.CreateChildEnvironment()); + Parse(ReadArgument(value, ref position), formula.TextStyle, environment.CreateChildEnvironment()); /// May return null for commands that produce no atoms. private Atom ProcessCommand( @@ -401,11 +432,11 @@ private Atom ProcessCommand( case "frac": { var numeratorFormula = Parse( - ReadElement(value, ref position), + ReadArgument(value, ref position), formula.TextStyle, environment.CreateChildEnvironment()); var denominatorFormula = Parse( - ReadElement(value, ref position), + ReadArgument(value, ref position), formula.TextStyle, environment.CreateChildEnvironment()); source = value.Segment(start, position - start); @@ -417,50 +448,7 @@ private Atom ProcessCommand( if (position == value.Length) throw new TexParseException("`left` command should be passed a delimiter"); - string delimiter = ""; - if (value[position] == escapeChar) - { - position++; - if (position == value.Length) - throw new TexParseException("`left` command should be passed a delimiter"); - - if (Char.IsLetter(value[position]) == false) - { - delimiter = value[position].ToString(); - position++; - } - else - { - StringBuilder sb = new StringBuilder(); - bool leftSymbolFound = false; - while (position < value.Length && leftSymbolFound == false) - { - if (IsWhiteSpace(value[position]) || Char.IsLetter(value[position]) == false) - { - leftSymbolFound = true; - } - if (leftSymbolFound == false) - { - sb.Append(value[position].ToString()); - position++; - } - } - if (leftSymbolFound == true) - { - var grouplength = sb.Length; - delimiter = value.Segment(position - grouplength, grouplength).ToString(); - } - else - { - throw new TexParseException("left symbol is incomplete"); - } - } - } - else - { - delimiter = value[position].ToString(); - position++; - } + string delimiter = ReadArgument(value, ref position).ToString().Trim(); var left = position; @@ -476,7 +464,7 @@ private Atom ProcessCommand( if (delimiter.Length > 1) { opening = GetDelimiterSymbol( - delimiter, value.Segment(start, left - start)); + delimiter.Replace('\\', ' ').Trim(), value.Segment(start, left - start)); } if (opening == null) throw new TexParseException($"Cannot find delimiter named {delimiter}"); @@ -488,7 +476,7 @@ private Atom ProcessCommand( case "overline": { var overlineFormula = Parse( - ReadElement(value, ref position), + ReadArgument(value, ref position), formula.TextStyle, environment.CreateChildEnvironment()); source = value.Segment(start, position - start); @@ -503,50 +491,7 @@ private Atom ProcessCommand( if (position == value.Length) throw new TexParseException("`right` command should be passed a delimiter"); - string delimiter = ""; - if (value[position] == escapeChar) - { - position++; - if (position == value.Length) - throw new TexParseException("`right` command should be passed a delimiter"); - - if (Char.IsLetter(value[position]) == false) - { - delimiter = value[position].ToString(); - position++; - } - else - { - StringBuilder sb = new StringBuilder(); - bool rightSymbolFound = false; - while (position < value.Length && rightSymbolFound == false) - { - if (IsWhiteSpace(value[position]) || Char.IsLetter(value[position]) == false) - { - rightSymbolFound = true; - } - if (rightSymbolFound == false) - { - sb.Append(value[position].ToString()); - position++; - } - } - if (rightSymbolFound) - { - var grouplength = sb.Length; - delimiter = value.Segment(position - grouplength, grouplength).ToString(); - } - else - { - throw new TexParseException("right symbol is incomplete"); - } - } - } - else - { - delimiter = value[position].ToString(); - position++; - } + string delimiter = ReadArgument(value, ref position).ToString().Trim(); SymbolAtom closing = null; if (delimiter.Length == 1) @@ -558,7 +503,7 @@ private Atom ProcessCommand( if (delimiter.Length > 1) { closing = GetDelimiterSymbol( - delimiter, value.Segment(start, position - start)); + delimiter.Replace('\\', ' ').Trim(), value.Segment(start, position - start)); } if (closing == null) throw new TexParseException($"Cannot find delimiter named {delimiter}"); @@ -576,13 +521,13 @@ private Atom ProcessCommand( { // Degree of radical is specified. degreeFormula = Parse( - ReadElementGroup(value, ref position, leftBracketChar, rightBracketChar), + ReadArgumentGroup(value, ref position, leftBracketChar, rightBracketChar), formula.TextStyle, environment.CreateChildEnvironment()); } var sqrtFormula = this.Parse( - ReadElement(value, ref position), + ReadArgument(value, ref position), formula.TextStyle, environment.CreateChildEnvironment()); @@ -593,7 +538,7 @@ private Atom ProcessCommand( { var color = ReadColorModelData(value, ref position); - var bodyValue = ReadElement(value, ref position); + var bodyValue = ReadArgument(value, ref position); var bodyFormula = Parse(bodyValue, formula.TextStyle, environment.CreateChildEnvironment()); source = value.Segment(start, position - start); @@ -603,7 +548,7 @@ private Atom ProcessCommand( { var color = ReadColorModelData(value, ref position); - var bodyValue = ReadElement(value, ref position); + var bodyValue = ReadArgument(value, ref position); var bodyFormula = Parse(bodyValue, formula.TextStyle, environment.CreateChildEnvironment()); source = value.Segment(start, position - start); @@ -637,7 +582,7 @@ private Color ReadColorModelData(SourceSpan value, ref int position) ref position, leftBracketChar, rightBracketChar)?.ToString(); - var colorDefinition = ReadElement(value, ref position).ToString(); + var colorDefinition = ReadArgument(value, ref position).ToString(); var colorComponents = colorDefinition.Split(',').Select(c => c.Trim()); var colorParser = string.IsNullOrEmpty(colorModelName) @@ -727,8 +672,8 @@ private void ProcessEscapeSequence(TexFormula formula, SkipWhiteSpace(value, ref position); var styledFormula = command == TexUtilities.TextStyleName - ? ConvertRawText(ReadElement(value, ref position), command) - : Parse(ReadElement(value, ref position), command, environment.CreateChildEnvironment()); + ? ConvertRawText(ReadArgument(value, ref position), command) + : Parse(ReadArgument(value, ref position), command, environment.CreateChildEnvironment()); var source = value.Segment(start, position - start); var atom = styledFormula.RootAtom ?? new NullAtom(source);