+ int TokenizeInterpolatedString (bool quoted)
+ {
+ int pos = 0;
+ var start_location = Location;
+
+ while (true) {
+ var ch = get_char ();
+ switch (ch) {
+ case '"':
+ if (quoted && peek_char () == '"') {
+ get_char ();
+ break;
+ }
+
+ val = new StringLiteral (context.BuiltinTypes, CreateStringFromBuilder (pos), start_location);
+ return Token.INTERPOLATED_STRING_END;
+ case '{':
+ if (peek_char () == '{') {
+ value_builder [pos++] = (char)ch;
+ get_char ();
+ break;
+ }
+
+ ++parsing_string_interpolation;
+ if (quoted) {
+ if (parsing_string_interpolation_quoted == null)
+ parsing_string_interpolation_quoted = new Stack<bool> ();
+ }
+
+ if (parsing_string_interpolation_quoted != null) {
+ parsing_string_interpolation_quoted.Push (quoted);
+ }
+
+ val = new StringLiteral (context.BuiltinTypes, CreateStringFromBuilder (pos), start_location);
+ return Token.INTERPOLATED_STRING;
+ case '\\':
+ if (quoted)
+ break;
+
+ ++col;
+ int surrogate;
+ ch = escape (ch, out surrogate);
+ if (ch == -1)
+ return Token.ERROR;
+
+ if (ch == '{' || ch == '}') {
+ Report.Error (8087, Location, "A `{0}' character may only be escaped by doubling `{0}{0}' in an interpolated string", ((char) ch).ToString ());
+ }
+
+ if (surrogate != 0) {
+ if (pos == value_builder.Length)
+ Array.Resize (ref value_builder, pos * 2);
+
+ if (pos == value_builder.Length)
+ Array.Resize (ref value_builder, pos * 2);
+
+ value_builder [pos++] = (char)ch;
+ ch = surrogate;
+ }
+
+ break;
+ case -1:
+ return Token.EOF;
+ }
+
+ ++col;
+ if (pos == value_builder.Length)
+ Array.Resize (ref value_builder, pos * 2);
+
+ value_builder[pos++] = (char) ch;
+ }
+ }
+
+ int TokenizeInterpolationFormat ()
+ {
+ int pos = 0;
+ int braces = 0;
+ while (true) {
+ var ch = get_char ();
+ switch (ch) {
+ case '{':
+ ++braces;
+ break;
+ case '}':
+ if (braces == 0) {
+ putback_char = ch;
+ if (pos == 0) {
+ Report.Error (8089, Location, "Empty interpolated expression format specifier");
+ } else if (Array.IndexOf (simple_whitespaces, value_builder [pos - 1]) >= 0) {
+ Report.Error (8088, Location, "A interpolated expression format specifier may not contain trailing whitespace");
+ }
+
+ val = CreateStringFromBuilder (pos);
+ return Token.LITERAL;
+ }
+
+ --braces;
+ break;
+ case '\\':
+ ++col;
+ int surrogate;
+ ch = escape (ch, out surrogate);
+ if (ch == -1)
+ return Token.ERROR;
+
+ if (ch == '{' || ch == '}') {
+ Report.Error (8087, Location, "A `{0}' character may only be escaped by doubling `{0}{0}' in an interpolated string", ((char) ch).ToString ());
+ }
+
+ if (surrogate != 0) {
+ if (pos == value_builder.Length)
+ Array.Resize (ref value_builder, pos * 2);
+
+ value_builder [pos++] = (char)ch;
+ ch = surrogate;
+ }
+
+ break;
+ case -1:
+ return Token.EOF;
+ }
+
+ ++col;
+ value_builder[pos++] = (char) ch;
+ }
+ }
+
+ string CreateStringFromBuilder (int pos)
+ {
+ if (pos == 0)
+ return string.Empty;
+ if (pos <= 4)
+ return InternIdentifier (value_builder, pos);
+
+ return new string (value_builder, 0, pos);
+ }
+