private void print(ExpressionNode expression, StringBuilder sb) {
			if (expression.Parenthesized) {
				sb.append("(");
			}
			switch (expression.ExpressionKind) {
			case Literal:
				var literal = (LiteralExpressionNode)expression;
				sb.append(new String(text, literal.ValueOffset, literal.ValueLength));
				break;

			case SimpleName:
				var name = (SimpleNameExpressionNode)expression;
				sb.append(name.Name ?? new String(text, name.NameOffset, name.NameLength));
				if (name.TypeArguments.size() > 0) {
					print(name.TypeArguments, sb);
				}
				break;

			case Invocation:
				var invocation = (InvocationExpressionNode)expression;
				print(invocation.TargetObject, sb);
				sb.append("(");
				var first = true;
				foreach (var arg in invocation.getArguments()) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					print(arg, sb);
				}
				sb.append(")");
				break;

			case MemberAccess:
				var access = (MemberAccessExpressionNode)expression;
				print(access.TargetObject, sb);
				sb.append(".");
				sb.append(access.Member.Name ?? new String(text, access.Member.NameOffset, access.Member.NameLength));
				if (access.Member.TypeArguments.size() > 0) {
					print(access.Member.TypeArguments, sb);
				}
				break;

			case NullSafeMemberAccess:
				var nsaccess = (NullSafeMemberAccessExpressionNode)expression;
				print(nsaccess.TargetObject, sb);
				sb.append("?.");
				sb.append(nsaccess.Member.Name ?? new String(text, nsaccess.Member.NameOffset, nsaccess.Member.NameLength));
				if (nsaccess.Member.TypeArguments.size() > 0) {
					print(nsaccess.Member.TypeArguments, sb);
				}
				break;

			case Assign:
				var assign = (AssignExpressionNode)expression;
				print(assign.Left, sb);
				switch (assign.Operator) {
				case Assign:
					sb.append(" = ");
					break;

				case Or:
					sb.append(" |= ");
					break;

				case Add:
					sb.append(" += ");
					break;

				case Multiply:
					sb.append(" *= ");
					break;

				default:
					throw new RuntimeException("Assignment not supported: " + assign.getOperator());
				}
				print(assign.Right, sb);
				break;

			case ElementAccess:
				var elementAccess = (ElementAccessExpressionNode)expression;
				print(elementAccess.TargetObject, sb);
				sb.append("[");
				first = true;
				foreach (var i in elementAccess.Indexes) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					print(i, sb);
				}
				sb.append("]");
				break;

			case Unary:
				var unary = (UnaryExpressionNode)expression;
				switch (unary.Operator) {
				case PostIncrement:
				case PostDecrement:
					break;

				case Plus:
					sb.append("+");
					break;

				case Minus:
					sb.append("-");
					break;

				case Not:
					sb.append("!");
					break;

				case Complement:
					sb.append("~");
					break;

				case PreIncrement:
					sb.append("++");
					break;

				case PreDecrement:
					sb.append("--");
					break;

				default:
					throw new RuntimeException("Unary operator not supported: " + unary.getOperator());
				}
				print(unary.Operand, sb);
				switch (unary.Operator) {
				case PostIncrement:
					sb.append("++");
					break;

				case PostDecrement:
					sb.append("--");
					break;
				}
				break;

			case Binary:
				var binary = (BinaryExpressionNode)expression;
				print(binary.LeftOperand, sb);
				switch (binary.Operator) {
				case Add:
					sb.append(" + ");
					break;

				case Subtract:
					sb.append(" - ");
					break;

				case Multiply:
					sb.append(" * ");
					break;

				case Modulo:
					sb.append(" % ");
					break;

				case Divide:
					sb.append(" / ");
					break;

				case Equal:
					sb.append(" == ");
					break;

				case NotEqual:
					sb.append(" != ");
					break;

				case LessThan:
					sb.append(" < ");
					break;

				case LessThanOrEqual:
					sb.append(" <= ");
					break;

				case GreaterThan:
					sb.append(" > ");
					break;

				case GreaterThanOrEqual:
					sb.append(" >= ");
					break;

				case LeftShift:
					sb.append(" << ");
					break;

				case RightShift:
					sb.append(" >> ");
					break;

				case UnsignedRightShift:
					sb.append(" >>> ");
					break;

				case LogicalAnd:
					sb.append(" && ");
					break;

				case LogicalOr:
					sb.append(" || ");
					break;

				case And:
					sb.append(" & ");
					break;

				case Or:
					sb.append(" | ");
					break;

				case NullCoalescing:
					sb.append(" ?? ");
					break;

				case Instanceof:
					sb.append(" is ");
					break;

				case As:
					sb.append(" as ");
					break;

				default:
					throw new RuntimeException("Binary operator not supported: " + binary.getOperator());
				}
				print(binary.RightOperand, sb);
				break;

			case ObjectCreation:
				var objectCreation = (ObjectCreationExpressionNode)expression;
				sb.append("new ");
				print(objectCreation.Type, sb);
				if (objectCreation.Arguments.size() > 0 || objectCreation.Initializer == null) {
					sb.append("(");
					first = true;
					foreach (var arg in objectCreation.Arguments) {
						if (first) {
							first = false;
						} else {
							sb.append(", ");
						}
						print(arg, sb);
					}
					sb.append(")");
				}
				if (objectCreation.Initializer != null) {
					print(objectCreation.Initializer, sb);
				}
				break;

			case ObjectInitializer:
				var objectInit = (ObjectInitializerExpressionNode)expression;
				sb.append("{ ");
				first = true;
				foreach (var mi in objectInit.getMemberInitializers()) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					sb.append(new String(text, mi.NameOffset, mi.NameLength));
					sb.append(" = ");
					print(mi.Value, sb);
				}
				sb.append(" }");
				break;

			case ArrayCreation:
				var arrayCreation = (ArrayCreationExpressionNode)expression;
				sb.append("new");
				if (arrayCreation.Type != null) {
					sb.append(" ");
					print(arrayCreation.Type, sb);
				}
				if (arrayCreation.DimensionExpressions.size() > 0) {
					sb.append("[");
					first = true;
					foreach (var exp in arrayCreation.DimensionExpressions) {
						if (first) {
							first = false;
						} else {
							sb.append(", ");
						}
						print(exp, sb);
					}
					sb.append("]");
				}
				if (arrayCreation.Dimensions > 0) {
					sb.append("[");
					for (int i = 1; i < arrayCreation.Dimensions; i++) {
						sb.append(",");
					}
					sb.append("]");
				}
				if (arrayCreation.Initializer != null) {
					print(arrayCreation.Initializer, sb);
				}
				break;

			case ArrayInitializer:
				var arrayInit = (ArrayInitializerExpressionNode)expression;
				sb.append("{ ");
				first = true;
				foreach (var v in arrayInit.Values) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					print(v, sb);
				}
				sb.append(" }");
				break;

			case CollectionInitializer:
				var collInit = (CollectionInitializerExpressionNode)expression;
				sb.append("{ ");
				first = true;
				foreach (var v in collInit.Values) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					sb.append("{ ");
					var firstExp = true;
					foreach (var exp in v) {
						if (firstExp) {
							firstExp = false;
						} else {
							sb.append(", ");
						}
						print(exp, sb);
					}
					sb.append(" }");
				}
				sb.append(" }");
				break;

			case Lambda:
				var lambda = (LambdaExpressionNode)expression;
				if (lambda.Parameters.size() == 1 && lambda.Parameters[0].Type == null) {
					sb.append(lambda.Parameters[0].Name ?? new String(text, lambda.Parameters[0].NameOffset, lambda.Parameters[0].NameLength));
				} else {
					sb.append("(");
					first = true;
					foreach (var p in lambda.Parameters) {
						if (first) {
							first = false;
						} else {
							sb.append(", ");
						}
						if (p.Type != null) {
							print(p.Type, sb);
							sb.append(" ");
						}
						sb.append(p.Name ?? new String(text, p.NameOffset, p.NameLength));
					}
					sb.append(")");
				}
				sb.append(" => ");
				print(lambda.Body, 0, false, sb);
				break;
				
			case Typeof:
				var typeofExp = (TypeofExpressionNode)expression;
				sb.append("typeof(");
				print(typeofExp.Type, sb);
				sb.append(")");
				break;
				
			case AnonymousObjectCreation:
				var anonymous = (AnonymousObjectCreationExpressionNode)expression;
				sb.append("new { ");
				first = true;
				foreach (var decl in anonymous.MemberDeclarators) {
					if (first) {
						first = false;
					} else {
						sb.append(", ");
					}
					if (decl.NameLength > 0) {
						sb.append(new String(text, decl.NameOffset, decl.NameLength));
						sb.append(" = ");
					}
					print(decl.Value, sb);
				}
				sb.append(" }");
				break;
				
			default:
				throw new RuntimeException("Expression not supported: " + expression.getExpressionKind());
			}
			if (expression.Parenthesized) {
				sb.append(")");
			}
		}