private void ScanCharacter(LineProgress p, bool skipOnly = false)
        {
            while (!p.EndOfLine)
            {
                if (p.Char() == '\\') // escaped character. Skip over it.
                {
                    p.Advance(2);
                }
                else if (p.Char() == '\'') // end of char
                {
                    p.Advance();
                    if (!skipOnly)
                    {
                        p.State = State.Default;
                    }
                    return;
                }
                else
                {
                    p.Advance();
                }
            }

            if (!skipOnly)
            {
                // End of line.  Char wasn't closed.  Oh well.  Revert to Default state.
                p.State = State.Default;
            }
        }
        private void ScanInterpolation(LineProgress p, bool skipOnly)
        {
            while (!p.EndOfLine)
            {
                if (p.Char() == '$' && p.NextChar() == '@' && p.NextNextChar() == '"') // interpolated multiline string
                {
                    p.Advance(3);
                    ScanMultiLineString(p, true, true);
                }
                else if (p.Char() == '$' && p.NextChar() == '"') // interpolated string
                {
                    p.Advance(2);
                    ScanString(p, true, true);
                }
                else
                if (p.Char() == '@' && p.NextChar() == '"') // multi-line string
                {
                    p.Advance(2);
                    ScanMultiLineString(p, false, true);
                }
                else if (p.Char() == '"') // single-line string
                {
                    p.Advance();
                    ScanString(p, false, true);
                }
                else if (p.Char() == '\'') // character
                {
                    p.Advance();
                    ScanCharacter(p, true);
                }
                else if (p.Char() == '/' && p.NextChar() == '*') // multiline comment
                {
                    p.Advance();
                    ScanMultiLineComment(p, true); // note we do not support multiline comments spanning muliple lines.
                }
                else if (p.Char() == '}')          // end of interpolation.
                {
                    p.Advance();
                    if (!skipOnly)
                    {
                        p.EndStringInterpolation();
                    }
                    return;
                }
                else
                {
                    p.Advance();
                }
            }

            if (!skipOnly)
            {
                // end of line: note that we do not support interpolations spanning muliple lines.
                p.EndStringInterpolation();
            }
        }
 private void ScanMultiLineComment(LineProgress p, bool skipOnly = false)
 {
     while (!p.EndOfLine)
     {
         if (p.Char() == '*' && p.NextChar() == '/')
         {
             p.Advance(2);
             if (!skipOnly)
             {
                 p.State = State.Default;
             }
             return;
         }
         else
         {
             p.Advance();
         }
     }
 }
        private void ScanMultiLineString(LineProgress p, bool isInterpolated, bool skipOnly = false)
        {
            while (!p.EndOfLine)
            {
                if (p.Char() == '"' && p.NextChar() == '"')                 // "" is allowed within multiline string
                {
                    p.Advance(2);
                }
                else if (isInterpolated && p.Char() == '{' && p.NextChar() == '{') // escaped interpolation
                {
                    p.Advance(2);
                }
                else if (isInterpolated && p.Char() == '{' && p.NextChar() != '{') // interpolation.
                {
                    if (!skipOnly)
                    {
                        p.StartStringInterpolation();
                    }
                    p.Advance();
                    ScanInterpolation(p, skipOnly);
                }
                else if (p.Char() == '"') // end of multi-line string
                {
                    if (!skipOnly)
                    {
                        p.EndString();
                    }

                    p.Advance();
                    return;
                }
                else
                {
                    p.Advance();
                }
            }

            if (!skipOnly)
            {
                // End of line. Emit as string, but remain in MultiLineString state
                p.EndString(p.State);
            }
        }
        private void ScanString(LineProgress p, bool isInterpolated, bool skipOnly = false)
        {
            while (!p.EndOfLine)
            {
                if (p.Char() == '\\')                 // escaped character. Skip over it.
                {
                    p.Advance(2);
                }
                else if (isInterpolated && p.Char() == '{' && p.NextChar() == '{') // escaped interpolation
                {
                    p.Advance(2);
                }
                else if (isInterpolated && p.Char() == '{' && p.NextChar() != '{') // interpolation.
                {
                    if (!skipOnly)
                    {
                        p.StartStringInterpolation();
                    }
                    p.Advance();
                    ScanInterpolation(p, skipOnly);
                }
                else if (p.Char() == '"') // end of string.
                {
                    if (!skipOnly)
                    {
                        p.EndString();
                    }
                    p.Advance();
                    return;
                }
                else
                {
                    p.Advance();
                }
            }

            // End of line.  String wasn't closed.  Oh well.  Revert to Default state.
            if (!skipOnly)
            {
                p.EndString();
            }
        }
 private void ScanDefault(LineProgress p)
 {
     while (!p.EndOfLine)
     {
         if (p.Char() == '$' && p.NextChar() == '@' && p.NextNextChar() == '"') // interpolated multiline string
         {
             p.Advance(3);
             p.StartString(State.InterpolatedMultiLineString);
             ScanMultiLineString(p, true);
         }
         else if (p.Char() == '$' && p.NextChar() == '"') // interpolated string
         {
             p.Advance(2);
             p.StartString(State.InterpolatedString);
             ScanString(p, true);
         }
         else
         if (p.Char() == '@' && p.NextChar() == '"') // multi-line string
         {
             p.Advance(2);
             p.StartString(State.MultiLineString);
             ScanMultiLineString(p, false);
         }
         else if (p.Char() == '"') // single-line string
         {
             p.Advance();
             p.StartString(State.String);
             ScanString(p, false);
         }
         else if (p.Char() == '\'') // character
         {
             p.Advance();
             ScanCharacter(p);
         }
         else if (p.Char() == '/' && p.NextChar() == '*') // multiline comment
         {
             p.Advance(2);
             p.State = State.MultilineComment;
             ScanMultiLineComment(p);
         }
         else if (p.Char() == '/' && p.NextChar() == '/') // single-line comment
         {
             p.AdvanceToEndOfLine();
         }
         else
         {
             p.Advance();
         }
     }
 }