Skip to content

Commit 14a5933

Browse files
committed
Fixed parsing strings within interpolated strings: no longer requires backslash-escaping strings within interpolated strings to more closely match C#'s interpolated strings
1 parent c1717ce commit 14a5933

File tree

6 files changed

+9
-93
lines changed

6 files changed

+9
-93
lines changed

AssemblyCopyright.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
using System;
22
using System.Reflection;
33

4-
[assembly: AssemblyCopyright("Copyright © Hex Innovation 2014")]
4+
[assembly: AssemblyCopyright("Copyright © Hex Innovation 2017")]

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright 2015 Hex Innovation, LLC
1+
Copyright 2017 Hex Innovation, LLC
22

33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.

MathConverter/MathConverter.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
<AppDesignerFolder>Properties</AppDesignerFolder>
1010
<RootNamespace>HexInnovation</RootNamespace>
1111
<AssemblyName>MathConverter</AssemblyName>
12-
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
12+
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
1313
<FileAlignment>512</FileAlignment>
14+
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
1415
</PropertyGroup>
1516
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
1617
<DebugSymbols>true</DebugSymbols>

MathConverter/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
// You can specify all the values or you can default the Build and Revision Numbers
5252
// by using the '*' as shown below:
5353
// [assembly: AssemblyVersion("1.0.*")]
54-
[assembly: AssemblyVersion("1.1.1.0")]
55-
[assembly: AssemblyFileVersion("1.1.1.0")]
54+
[assembly: AssemblyVersion("1.2.0.0")]
55+
[assembly: AssemblyFileVersion("1.2.0.0")]
5656

5757
[assembly: XmlnsPrefix("http://hexinnovation.com/math", "math")]
5858
[assembly: XmlnsDefinition("http://hexinnovation.com/math", "HexInnovation")]

MathConverter/Scanner.cs

Lines changed: 2 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ public Scanner(Parser parser, StringReader reader)
2323
private TextReader _reader;
2424
private Token _lastToken;
2525
private bool _needsToken;
26-
private Stack<ScannerState> _parsingDollarStrings = new Stack<ScannerState>();
2726
public int Position { get; private set; }
2827

2928

@@ -111,57 +110,20 @@ private Token NextToken()
111110
sb.Append('.');
112111
break;
113112
case '"':
114-
if (_parsingDollarStrings.Any(p => p == ScannerState.DoubleQuoteString))
115-
{
116-
throw new ParsingException(Position, "You must backslash-escape a \" character embedded in another double-quote-enclosed string.");
117-
}
118113
state = ScannerState.DoubleQuoteString;
119114
break;
120115
case '`':
121-
if (_parsingDollarStrings.Any(p => p == ScannerState.CaretString))
122-
{
123-
throw new ParsingException(Position, "You must backslash-escape a ` character embedded in another caret-enclosed string.");
124-
}
125116
state = ScannerState.CaretString;
126117
break;
127118
case '$':
128119
Position++;
129120
ch = _reader.Read();
130121
switch (ch)
131122
{
132-
case '\\':
133-
if (_parsingDollarStrings.Any())
134-
{
135-
Position++;
136-
switch (ch = _reader.Read())
137-
{
138-
case '`':
139-
state = ScannerState.DollarString | ScannerState.CaretString;
140-
break;
141-
case '"':
142-
state = ScannerState.DollarString | ScannerState.DoubleQuoteString;
143-
break;
144-
default:
145-
throw new ParsingException(Position, $"The character \'\\{(char)ch}\' is not a valid backslash-escaped character.");
146-
}
147-
}
148-
else
149-
{
150-
throw new ParsingException(Position, "A '$' character must be proceeded by a caret (`) or double-quote (\") character.");
151-
}
152-
break;
153123
case '`':
154-
if (_parsingDollarStrings.Any(p => p == ScannerState.CaretString))
155-
{
156-
throw new ParsingException(Position, "You must backslash-escape a ` character embedded in another caret-enclosed string.");
157-
}
158124
state = ScannerState.DollarString | ScannerState.CaretString;
159125
break;
160126
case '"':
161-
if (_parsingDollarStrings.Any(p => p == ScannerState.DoubleQuoteString))
162-
{
163-
throw new ParsingException(Position, "You must backslash-escape a \" character embedded in another double-quote-enclosed string.");
164-
}
165127
state = ScannerState.DollarString | ScannerState.DoubleQuoteString;
166128
break;
167129
default:
@@ -213,25 +175,6 @@ private Token NextToken()
213175
if (_reader.Read() != '&')
214176
throw new ParsingException(Position, "'&' signs are only valid in pairs of two.");
215177
return new Token(TokenType.And);
216-
case '\\':
217-
if (!_parsingDollarStrings.Any())
218-
{
219-
// backslashes are allowed only to start a string in an embedded string.
220-
throw new ParsingException(Position, $"Found invalid token '{(char)ch}'");
221-
}
222-
Position++;
223-
switch (ch = _reader.Read())
224-
{
225-
case '`':
226-
state = ScannerState.CaretString;
227-
break;
228-
case '"':
229-
state = ScannerState.DoubleQuoteString;
230-
break;
231-
default:
232-
throw new ParsingException(Position, $"The character \'\\{(char)ch}\' is not a valid backslash-escaped character.");
233-
}
234-
break;
235178
default:
236179
if (char.IsDigit((char)ch))
237180
{
@@ -341,7 +284,6 @@ private Token NextToken()
341284
*/
342285

343286
sb.Append(Arguments.Count);
344-
_parsingDollarStrings.Push(state & ~ScannerState.DollarString);
345287
try
346288
{
347289
Arguments.Add(_parser.ParseDollarStringArg());
@@ -419,16 +361,12 @@ private Token NextToken()
419361
}
420362
break;
421363
case '`':
422-
if (_parsingDollarStrings.Any(q => q == ScannerState.CaretString))
423-
throw new ParsingException(Position, "You must baskslash-escape ` characters embedded in `-enclosed strings.");
424-
else if ((state & ~ScannerState.DollarString) == ScannerState.CaretString)
364+
if ((state & ~ScannerState.DollarString) == ScannerState.CaretString)
425365
throw new ParsingException(Position, "Missing close delimiter '}' for interpolated expression started with '{'.");
426366
sb.Append('`');
427367
break;
428368
case '"':
429-
if (_parsingDollarStrings.Any(q => q == ScannerState.DoubleQuoteString))
430-
throw new ParsingException(Position, "You must baskslash-escape \" characters embedded in \"-enclosed strings.");
431-
else if ((state & ~ScannerState.DollarString) == ScannerState.DoubleQuoteString)
369+
if ((state & ~ScannerState.DollarString) == ScannerState.DoubleQuoteString)
432370
throw new ParsingException(Position, "Missing close delimiter '}' for interpolated expression started with '{'.");
433371
sb.Append('"');
434372
break;
@@ -449,7 +387,6 @@ private Token NextToken()
449387
{
450388
throw new ParsingException(Position, "Failed to parse the $-string to a call to String.Format. See the inner exception.", e);
451389
}
452-
_parsingDollarStrings.Pop();
453390
}
454391
}
455392
break;
@@ -482,31 +419,9 @@ private Token NextToken()
482419
sb.Append('\\');
483420
break;
484421
case '`':
485-
if (_parsingDollarStrings.Any(p => p == ScannerState.CaretString))
486-
{
487-
if ((state & ~ScannerState.DollarString) == ScannerState.CaretString)
488-
{
489-
// Close the string.
490-
if (isDollarString)
491-
return new DollarStringToken(sb.ToString(), Arguments);
492-
else
493-
return new LexicalToken(TokenType.String, sb.ToString());
494-
}
495-
}
496422
sb.Append('`');
497423
break;
498424
case '"':
499-
if (_parsingDollarStrings.Any(p => p == ScannerState.DoubleQuoteString))
500-
{
501-
if ((state & ~ScannerState.DollarString) == ScannerState.DoubleQuoteString)
502-
{
503-
// Close the string.
504-
if (isDollarString)
505-
return new DollarStringToken(sb.ToString(), Arguments);
506-
else
507-
return new LexicalToken(TokenType.String, sb.ToString());
508-
}
509-
}
510425
sb.Append('"');
511426
break;
512427
default:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ In the previous example, we used `ConverterParameter="format(&quot;Language {0}:
345345

346346
In C#, you can simplify the call to string.Format by using an interpolated string. In this case, that would be `$"Language {x+1}: {y}"`. Similarly, in `MathConverter`, we can use ``ConverterParameter="$`Language {x+1}: {y}`"``. This will be converted by `MathConverter`'s compiler into a call to `string.Format("Language {0}: {1}", x+1, y)`.
347347

348-
Just like in C#, you can embed strings within in an interpolated string. So `MathConverter`'s interpolated strings can be just as complex as C#'s. For example, you can simplify the expression `ConverterParameter='format(&quot;{0} apple&quot; + (x == 1 ? &quot;&quot; : &quot;s&quot;), x)'` to simply be ```ConverterParameter='$&quot;{x} apple{(x==1 ? `` : `s`)}&quot;'```.
348+
Just like in C#, you can embed strings within in an interpolated string. So `MathConverter`'s interpolated strings can be just as complex as C#'s. For example, you can simplify the expression `ConverterParameter='format(&quot;{0} apple&quot; + (x == 1 ? &quot;&quot; : &quot;s&quot;), x)'` to simply be ```ConverterParameter='$`{x} apple{(x==1 ? `` : `s`)}`'```.
349349

350350

351351

0 commit comments

Comments
 (0)