Index: cs-tokenizer.cs
===================================================================
--- cs-tokenizer.cs	(revision 148775)
+++ cs-tokenizer.cs	(working copy)
@@ -221,6 +221,16 @@
 		//
 		bool any_token_seen = false;
 
+		//
+		// Set when the tokenizer is parsing a string with interpolated
+		// expressions: 'Hello {name}, welcome', the tokenizer will return
+		// STRING_INTERPOLATION_START with a value set to
+		// "Hello " followed by IDENTIFIER with value name followed
+		// by a StringLiteral with value ", welcome" and
+		// STRING_INTERPOLATION_END
+		//
+		bool interpolating = false;
+		
 		static readonly char[] simple_whitespaces = new char[] { ' ', '\t' };
 
 		public bool PropertyParsing {
@@ -2439,6 +2449,44 @@
 			return Token.EOF;
 		}
 
+		int consume_interpolation (int prepend)
+		{
+			int c;
+			string_builder.Length = 0;
+			if (prepend != -1)
+				string_builder.Append ((char) prepend);
+			
+			while ((c = get_char ()) != -1){
+				if (c == '\"'){
+					if (string_builder.Length != 0)
+						putback_char = c;
+					val =  new StringLiteral (string_builder.ToString (), Location);
+					return Token.LITERAL;
+				}
+				
+				if (c == '{'){
+					val = new StringLiteral (string_builder.ToString (), Location);
+					return Token.LITERAL;
+				}
+
+				if (c == '\n')
+					Report.Error (1010, Location, "Newline in constant");
+
+				int surrogate;
+				c = escape (c, out surrogate);
+				if (c == -1)
+					return Token.ERROR;
+				if (surrogate != 0) {
+					string_builder.Append ((char) c);
+					c = surrogate;
+				}
+				string_builder.Append ((char) c);
+			}
+
+			Report.Error (1039, Location, "Unterminated string literal");
+			return Token.EOF;
+		}
+		
 		private int consume_identifier (int s)
 		{
 			int res = consume_identifier (s, false);
@@ -2603,8 +2651,12 @@
 					val = LocatedToken.Create (ref_line, col);
 					return Token.OPEN_BRACE;
 				case '}':
-					val = LocatedToken.Create (ref_line, col);
-					return Token.CLOSE_BRACE;
+					if (interpolating)
+						return consume_interpolation (-1);
+					else {
+						val = LocatedToken.Create (ref_line, col);
+						return Token.CLOSE_BRACE;
+					}
 				case '[':
 					// To block doccomment inside attribute declaration.
 					if (doc_state == XmlCommentState.Allowed)
@@ -2934,7 +2986,11 @@
 					return Token.EOF;
 				
 				case '"':
-					return consume_string (false);
+					if (interpolating){
+						interpolating = false;
+						return Token.STRING_INTERPOLATION_END;
+					} else
+						return consume_string (false);
 
 				case '\'':
 					return TokenizeBackslash ();
@@ -2953,6 +3009,19 @@
 					Report.Error (1646, Location, "Keyword, identifier, or string expected after verbatim specifier: @");
 					return Token.ERROR;
 
+				case '$':
+					if (RootContext.Version == LanguageVersion.Future){
+						c = get_char ();
+						if (c == '"'){
+							interpolating = true;
+							tokens_seen = true;
+							int ret = consume_interpolation (-1);
+							if (ret == Token.LITERAL)
+								return Token.STRING_INTERPOLATION_START;
+						}
+					}
+					return Token.ERROR;
+					
 				case EvalStatementParserCharacter:
 					return Token.EVAL_STATEMENT_PARSER;
 				case EvalCompilationUnitParserCharacter:
@@ -3003,6 +3072,16 @@
 			if (d != 0)
 				throw new NotImplementedException ();
 
+			if (peek_char () != '\''){
+				if (RootContext.Version == LanguageVersion.Future){
+					interpolating = true;
+					int ret = consume_interpolation (c);
+					if (ret == Token.LITERAL)
+						return Token.STRING_INTERPOLATION_START;
+					return Token.ERROR;
+				}
+			}
+			
 			val = new CharLiteral ((char) c, Location);
 			c = get_char ();
 
Index: argument.cs
===================================================================
--- argument.cs	(revision 148775)
+++ argument.cs	(working copy)
@@ -19,8 +19,7 @@
 	//
 	// Argument expression used for invocation
 	//
-	public class Argument
-	{
+	public class Argument  	{
 		public enum AType : byte
 		{
 			None = 0,
Index: Makefile
===================================================================
--- Makefile	(revision 148775)
+++ Makefile	(working copy)
@@ -119,4 +119,6 @@
 	echo -e 'var a = new int[]{1,2,3};\nfrom x in a select x;' | mono csharp.exe
 	echo -e 'var a = from f in System.IO.Directory.GetFiles ("/tmp") where f == "passwd" select f;' | mono csharp.exe
 
+qh: cs-parser.cs 
+	gmcs /codepage:65001  -optimize -d:NET_1_1 -d:NET_2_0 -debug -target:exe -out:gmcs.exe cs-parser.cs  @gmcs.exe.sources
 
Index: rootcontext.cs
===================================================================
--- rootcontext.cs	(revision 148775)
+++ rootcontext.cs	(working copy)
@@ -23,8 +23,8 @@
 	{
 		ISO_1		= 1,
 		ISO_2		= 2,
-		V_3			= 3,
-		V_4			= 4,
+		V_3		= 3,
+		V_4		= 4,
 		Future		= 100,
 
 		Default		= LanguageVersion.V_4,
@@ -165,7 +165,8 @@
 			Target = Target.Exe;
 			TargetExt = ".exe";
 			Platform = Platform.AnyCPU;
-			Version = LanguageVersion.Default;
+			//Version = LanguageVersion.Default;
+			Version = LanguageVersion.Future;
 			Documentation = null;
 			impl_details_class = null;
 			helper_classes = null;
Index: cs-parser.jay
===================================================================
--- cs-parser.jay	(revision 148775)
+++ cs-parser.jay	(working copy)
@@ -347,6 +347,12 @@
 //
 %token COMPLETE_COMPLETION
 
+//
+// Token to initiate parsing strings that will be interpolated
+//
+%token STRING_INTERPOLATION_START
+%token STRING_INTERPOLATION_END
+
 /* Add precedence rules to solve dangling else s/r conflict */
 %nonassoc IF
 %nonassoc ELSE
@@ -2998,6 +3004,7 @@
 
 primary_expression_no_array_creation
 	: literal
+	| interpolated_string
 	| IDENTIFIER opt_type_argument_list
 	  {
 		var lt = (Tokenizer.LocatedToken) $1;
@@ -3037,7 +3044,62 @@
 	| FALSE			{ $$ = new BoolLiteral (false, GetLocation ($1)); }
 	;
 
+interpolated_string
+	: STRING_INTERPOLATION_START interpolated_expressions STRING_INTERPOLATION_END {
+		var list = (List<Tuple<Expression,string>>) $2;
 
+		var format_string = new StringBuilder ();
+		format_string.Append (((StringLiteral) $1).Value);
+		int n = 0;
+		foreach (var t in list)
+	      		format_string.Append (String.Format ("{{{0}}}{1}", n++, t.Item2));
+
+		Arguments args = new Arguments (list.Count + 1);
+		args.Add (new Argument (new StringLiteral (format_string.ToString (), GetLocation ($1))));
+		foreach (var t in list)
+			args.Add (new Argument (t.Item1));
+		
+		var format = new MemberAccess (TypeManager.system_string_expr, "Format");
+		$$ = new Invocation (format, args);
+	  } 
+	;
+
+interpolated_expressions
+	: interpolated_expression {
+		var list = new List<Tuple<Expression,string>> ();
+		list.Add ((Tuple<Expression,string>) $1);
+		$$ = list;
+  	  }
+	| interpolated_expressions interpolated_expression {
+		var list = (List<Tuple<Expression,string>>) $1;
+		list.Add ((Tuple<Expression,string>) $2);
+		$$ = list;
+	  }
+	;
+
+interpolated_expression
+	: expression LITERAL opt_interpolation_format { 
+	        var s = $2 as StringLiteral;
+		if (s == null){
+			Report.Error (-100, GetLocation ($1), "Expected a string literal, got a {0}", $2.GetType ());
+			$$ = null;
+		}
+		var e = (Expression) $1;
+		$$ = new Tuple<Expression,string> (e, s.Value);
+	  }
+	;
+
+opt_interpolation_format
+	: /* empty */
+	| COLON LITERAL { 
+	        var s = $2 as StringLiteral;
+		if (s == null){
+			Report.Error (-100, GetLocation ($1), "Expected a string literal, got a {0}", $2.GetType ());
+			$$ = null;
+		}
+		$$ = $2;
+	  }
+	;
 //
 // Here is the trick, tokenizer may think that parens is a special but
 // parser is interested in open parens only, so we merge them.
@@ -3232,6 +3294,9 @@
 		$$ = new Argument ((Expression) $1);
 	  }
 	| non_simple_argument
+	| GENERATE_COMPLETION {
+		$$ = new Argument (new CompletionSimpleName (MemberName.MakeName ("", null), lexer.Location));
+	  }
 	;
 
 argument_or_named_argument
Index: TODO
===================================================================
--- TODO	(revision 148775)
+++ TODO	(working copy)
@@ -1,3 +1,5 @@
+Remove "private" from the code.
+
 ===========================================
 
 * Value Parameter
