--- vala/codegen/valaccodebasemodule.vala	2013-12-09 13:09:38.708678110 -0800
+++ a/codegen/valaccodebasemodule.vala	2013-12-09 13:05:22.304676185 -0800
@@ -3762,6 +3762,7 @@
 	}
 
 	public override void visit_expression (Expression expr) {
+		expr.emitted = true;
 		if (get_cvalue (expr) != null && !expr.lvalue) {
 			if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
 				var st = expr.formal_value_type.type_parameter.parent_symbol.parent_symbol as Struct;
@@ -6689,3 +6690,4 @@
 		return result;
 	}
 }
+
--- vala/vala/valaassignment.vala	2013-12-09 13:09:38.748678110 -0800
+++ a/vala/valaassignment.vala	2013-12-09 13:06:28.796676684 -0800
@@ -475,7 +475,7 @@
 			    !(field is ArrayLengthField) &&
 				!(left.value_type.is_real_non_null_struct_type () && right is ObjectCreationExpression)) {
 				// visit_assignment not necessary
-				if (instance && ma.inner != null) {
+				if (instance && ma.inner != null && !ma.inner.emitted) {
 					ma.inner.emit (codegen);
 				}
 
@@ -507,7 +507,7 @@
 				return;
 			}
 
-			if (instance && ma.inner != null && property != null) {
+			if (instance && ma.inner != null  && !ma.inner.emitted && property != null) {
 				ma.inner.emit (codegen);
 			} else {
 				// always process full lvalue
--- vala/vala/valaexpression.vala	2013-12-09 13:09:38.752678110 -0800
+++ a/vala/valaexpression.vala	2013-12-09 13:05:22.308676185 -0800
@@ -57,6 +57,8 @@
 
 	public TargetValue? target_value { get; set; }
 
+	public bool emitted { get; set; default = false; }
+
 	/**
 	 * Returns whether this expression is constant, i.e. whether this
 	 * expression only consists of literals and other constants.
@@ -102,3 +104,4 @@
 		block.insert_before (parent_statement, stmt);
 	}
 }
+
--- vala/vala/valamemberaccess.vala	2013-12-09 13:09:38.772678111 -0800
+++ a/vala/valamemberaccess.vala	2013-12-09 13:05:22.308676185 -0800
@@ -47,6 +47,11 @@
 	public string member_name { get; set; }
 
 	/**
+	 * Cascade member access.
+	 */
+	public bool cascade_member_access { get; set; }
+
+	/**
 	 * Pointer member access.
 	 */
 	public bool pointer_member_access { get; set; }
@@ -89,6 +94,13 @@
 		this.source_reference = source_reference;
 	}
 
+	public MemberAccess.cascade (Expression inner, string member_name, SourceReference? source_reference = null) {
+		this.inner = inner;
+		this.member_name = member_name;
+		this.source_reference = source_reference;
+		cascade_member_access = true;
+	}
+
 	public MemberAccess.pointer (Expression inner, string member_name, SourceReference? source_reference = null) {
 		this.inner = inner;
 		this.member_name = member_name;
@@ -900,7 +912,7 @@
 	}
 
 	public override void emit (CodeGenerator codegen) {
-		if (inner != null) {
+		if (inner != null && inner.emitted == false) {
 			inner.emit (codegen);
 		}
 
@@ -928,3 +940,4 @@
 		}
 	}
 }
+
--- vala/vala/valaparser.vala	2013-12-09 13:09:38.776678111 -0800
+++ a/vala/valaparser.vala	2013-12-09 13:05:22.308676185 -0800
@@ -39,6 +39,12 @@
 
 	Comment comment;
 
+	Expression cascade_inner;
+	StatementList stmt_list;
+	int level = 0;
+	int cascade_level;
+	bool parse_more = false;
+
 	const int BUFFER_SIZE = 32;
 
 	static List<TypeParameter> _empty_type_parameter_list;
@@ -557,8 +563,6 @@
 	}
 
 	Expression parse_primary_expression () throws ParseError {
-		var begin = get_location ();
-
 		Expression expr;
 
 		switch (current ()) {
@@ -612,13 +616,36 @@
 			break;
 		}
 
+		expr = parse_inner_primary_expression (expr);
+		
+		return expr;
+	}
+
+	Expression parse_inner_primary_expression (Expression expr_temp) throws ParseError {
+		var begin = get_location ();
+
+		Expression expr = expr_temp;
+
 		// process primary expressions that start with an inner primary expression
 		bool found = true;
 		while (found) {
 			switch (current ()) {
 			case TokenType.DOT:
-				expr = parse_member_access (begin, expr);
-				break;
+				if (cascade_inner == null || cascade_level == level) {
+ 					expr = parse_member_access (begin, expr);
+ 				} else {
+ 					parse_more = true;
+ 					found = false;
+ 				}
+ 				break;
+			case TokenType.CASCADE:
+				if (cascade_inner == null || cascade_level == level) {
+ 					expr = parse_cascade_member_access (begin, expr);
+ 				} else {
+ 					parse_more = true;
+ 					found = false;
+ 				}
+ 				break;
 			case TokenType.OP_PTR:
 				expr = parse_pointer_member_access (begin, expr);
 				break;
@@ -710,7 +737,19 @@
 		expect (TokenType.DOT);
 		string id = parse_identifier ();
 		List<DataType> type_arg_list = parse_type_argument_list (true);
-		var expr = new MemberAccess (inner, id, get_src (begin));
+
+		if (cascade_inner != null) {
+ 			stmt_list.add (new ExpressionStatement (inner, get_src (begin)));
+ 			inner = cascade_inner;
+ 		}
+
+		MemberAccess expr = new MemberAccess (inner, id, get_src (begin));
+
+		if (cascade_inner != null) {
+			cascade_inner = expr;
+			cascade_level = level;
+		}
+
 		if (type_arg_list != null) {
 			foreach (DataType type_arg in type_arg_list) {
 				expr.add_type_argument (type_arg);
@@ -719,6 +758,30 @@
 		return expr;
 	}
 
+	Expression parse_cascade_member_access (SourceLocation begin, Expression inner) throws ParseError {
+ 		expect (TokenType.CASCADE);
+ 		string id = parse_identifier ();
+ 		List<DataType> type_arg_list = parse_type_argument_list (true);
+
+ 		if (cascade_inner == null) {
+ 			cascade_inner = inner;
+ 			cascade_level = level;
+ 		} else {
+ 			if (stmt_list == null) {
+ 				stmt_list = new StatementList (get_src (begin));
+ 			}
+ 			stmt_list.add (new ExpressionStatement (inner, get_src (begin)));
+ 			inner = cascade_inner;
+ 		}
+ 		var expr = new MemberAccess.cascade (inner, id, get_src (begin));
+ 		if (type_arg_list != null) {
+			foreach (DataType type_arg in type_arg_list) {
+ 				expr.add_type_argument (type_arg);
+ 			}
+ 		}
+ 		return expr;
+ 	}
+
 	Expression parse_pointer_member_access (SourceLocation begin, Expression inner) throws ParseError {
 		expect (TokenType.OP_PTR);
 		string id = parse_identifier ();
@@ -1413,7 +1476,9 @@
 			var operator = get_assignment_operator (current ());
 			if (operator != AssignmentOperator.NONE) {
 				next ();
+				level++;
 				var rhs = parse_expression ();
+				level--;
 				expr = new Assignment (expr, rhs, operator, get_src (begin));
 			} else if (current () == TokenType.OP_GT) { // >>=
 				char* first_gt_pos = tokens[index].begin.pos;
@@ -1427,11 +1492,19 @@
 					prev ();
 					break;
 				}
+			} else if (parse_more && level == cascade_level) {
+				expr = parse_inner_primary_expression (expr);
+				parse_more = false;
 			} else {
 				break;
 			}
 		}
 
+		if (expr != cascade_inner && cascade_inner != null && level == cascade_level) {
+			stmt_list.add (new ExpressionStatement (expr, get_src (begin)));
+			return cascade_inner;
+		}
+
 		return expr;
 	}
 
@@ -1525,6 +1598,11 @@
 				if (!is_decl) {
 					block.add_statement (stmt);
 				}
+
+				if (stmt_list != null) {
+					block.add_statement (stmt_list);
+					stmt_list = null;
+				}
 			} catch (ParseError e) {
 				if (recover () != RecoveryState.STATEMENT_BEGIN) {
 					// beginning of next declaration or end of file reached
@@ -1561,6 +1639,7 @@
 		case TokenType.OP_GT: // >>=
 		// member access
 		case TokenType.DOT:
+		case TokenType.CASCADE:
 		// pointer member access
 		case TokenType.OP_PTR:
 			rollback (begin);
@@ -1733,6 +1812,7 @@
 			block.add_statement (new DeclarationStatement (local, local.source_reference));
 		} while (accept (TokenType.COMMA));
 		expect (TokenType.SEMICOLON);
+		cascade_inner = null;
 	}
 
 	LocalVariable parse_local_variable (DataType? variable_type) throws ParseError {
@@ -1784,6 +1864,7 @@
 		var begin = get_location ();
 		var expr = parse_statement_expression ();
 		expect (TokenType.SEMICOLON);
+		cascade_inner = null;
 		return new ExpressionStatement (expr, get_src (begin));
 	}
 
@@ -1962,6 +2043,7 @@
 			expr = parse_expression ();
 		}
 		expect (TokenType.SEMICOLON);
+		cascade_inner = null;
 		return new ReturnStatement (expr, get_src (begin));
 	}
 
--- vala/vala/valascanner.vala	2013-12-09 13:09:38.776678111 -0800
+++ a/vala/valascanner.vala	2013-12-09 13:05:22.312676185 -0800
@@ -873,6 +873,9 @@
 					if (current[0] == '.' && current[1] == '.') {
 						type = TokenType.ELLIPSIS;
 						current += 2;
+					} else if (current[0] == '.') {
+ 						type = TokenType.CASCADE;
+ 						current += 1;
 					}
 				}
 				break;
--- vala/vala/valastatementlist.vala	2013-12-09 13:09:38.780678111 -0800
+++ a/vala/valastatementlist.vala	2013-12-09 13:05:22.312676185 -0800
@@ -59,4 +59,13 @@
 			stmt.emit (codegen);
 		}
 	}
+
+	public override bool check (CodeContext context) {
+		bool return_val = true;
+		foreach (Statement stmt in list) {
+			return_val =  return_val && stmt.check (context);
+		}
+
+		return return_val;
+	}
 }
--- vala/vala/valatokentype.vala	2013-12-09 13:09:38.780678111 -0800
+++ a/vala/valatokentype.vala	2013-12-09 13:05:22.312676185 -0800
@@ -44,6 +44,7 @@
 	CARRET,
 	CASE,
 	CATCH,
+	CASCADE,
 	CHARACTER_LITERAL,
 	CLASS,
 	CLOSE_BRACE,
@@ -176,6 +177,7 @@
 		case CARRET: return "`^'";
 		case CASE: return "`case'";
 		case CATCH: return "`catch'";
+		case CASCADE: return "`..'";
 		case CHARACTER_LITERAL: return "character literal";
 		case CLASS: return "`class'";
 		case CLOSE_BRACE: return "`}'";
