Xamarin Public Jenkins (auto-signing) 536cd135cc Imported Upstream version 5.4.0.167
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
2017-08-21 15:34:15 +00:00

289 lines
6.7 KiB
C#

//
// support.cs: Support routines to work around the fact that System.Reflection.Emit
// can not introspect types that are being constructed
//
// Author:
// Miguel de Icaza (miguel@ximian.com)
// Marek Safar (marek.safar@gmail.com)
//
// Copyright 2001 Ximian, Inc (http://www.ximian.com)
// Copyright 2003-2009 Novell, Inc
// Copyright 2011 Xamarin Inc
//
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
namespace Mono.CSharp {
sealed class ReferenceEquality<T> : IEqualityComparer<T> where T : class
{
public static readonly IEqualityComparer<T> Default = new ReferenceEquality<T> ();
private ReferenceEquality ()
{
}
public bool Equals (T x, T y)
{
return ReferenceEquals (x, y);
}
public int GetHashCode (T obj)
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode (obj);
}
}
static class ArrayComparer
{
public static bool IsEqual<T> (T[] array1, T[] array2)
{
if (array1 == null || array2 == null)
return array1 == array2;
var eq = EqualityComparer<T>.Default;
for (int i = 0; i < array1.Length; ++i) {
if (!eq.Equals (array1[i], array2[i])) {
return false;
}
}
return true;
}
}
/// <summary>
/// This is an arbitrarily seekable StreamReader wrapper.
///
/// It uses a self-tuning buffer to cache the seekable data,
/// but if the seek is too far, it may read the underly
/// stream all over from the beginning.
/// </summary>
public class SeekableStreamReader : IDisposable
{
public const int DefaultReadAheadSize =
#if FULL_AST
65536 / 2; // Large buffer because of ReadChars of large literal string
#else
4096 / 2;
#endif
StreamReader reader;
public readonly Stream Stream;
char[] buffer;
int read_ahead_length; // the length of read buffer
int buffer_start; // in chars
int char_count; // count of filled characters in buffer[]
int pos; // index into buffer[]
public SeekableStreamReader (Stream stream, Encoding encoding, char[] sharedBuffer = null)
{
this.Stream = stream;
this.buffer = sharedBuffer;
InitializeStream (DefaultReadAheadSize);
reader = new StreamReader (stream, encoding, true);
}
public void Dispose ()
{
// Needed to release stream reader buffers
reader.Dispose ();
}
void InitializeStream (int read_length_inc)
{
read_ahead_length += read_length_inc;
int required_buffer_size = read_ahead_length * 2;
if (buffer == null || buffer.Length < required_buffer_size)
buffer = new char [required_buffer_size];
Stream.Position = 0;
buffer_start = char_count = pos = 0;
}
/// <remarks>
/// This value corresponds to the current position in a stream of characters.
/// The StreamReader hides its manipulation of the underlying byte stream and all
/// character set/decoding issues. Thus, we cannot use this position to guess at
/// the corresponding position in the underlying byte stream even though there is
/// a correlation between them.
/// </remarks>
public int Position {
get {
return buffer_start + pos;
}
set {
//
// If the lookahead was too small, re-read from the beginning. Increase the buffer size while we're at it
// This should never happen until we are parsing some weird source code
//
if (value < buffer_start) {
InitializeStream (read_ahead_length);
//
// Discard buffer data after underlying stream changed position
// Cannot use handy reader.DiscardBufferedData () because it for
// some strange reason resets encoding as well
//
reader = new StreamReader (Stream, reader.CurrentEncoding, true);
}
while (value > buffer_start + char_count) {
pos = char_count;
if (!ReadBuffer ())
throw new InternalErrorException ("Seek beyond end of file: " + (buffer_start + char_count - value));
}
pos = value - buffer_start;
}
}
bool ReadBuffer ()
{
int slack = buffer.Length - char_count;
//
// read_ahead_length is only half of the buffer to deal with
// reads ahead and moves back without re-reading whole buffer
//
if (slack <= read_ahead_length) {
//
// shift the buffer to make room for read_ahead_length number of characters
//
int shift = read_ahead_length - slack;
Array.Copy (buffer, shift, buffer, 0, char_count - shift);
// Update all counters
pos -= shift;
char_count -= shift;
buffer_start += shift;
slack += shift;
}
char_count += reader.Read (buffer, char_count, slack);
return pos < char_count;
}
public char[] ReadChars (int fromPosition, int toPosition)
{
char[] chars = new char[toPosition - fromPosition];
if (buffer_start <= fromPosition && toPosition <= buffer_start + buffer.Length) {
Array.Copy (buffer, fromPosition - buffer_start, chars, 0, chars.Length);
} else {
throw new NotImplementedException ();
}
return chars;
}
public int Peek ()
{
if ((pos >= char_count) && !ReadBuffer ())
return -1;
return buffer [pos];
}
public int Read ()
{
if ((pos >= char_count) && !ReadBuffer ())
return -1;
return buffer [pos++];
}
}
public class UnixUtils {
[System.Runtime.InteropServices.DllImport ("libc", EntryPoint="isatty")]
extern static int _isatty (int fd);
public static bool isatty (int fd)
{
try {
return _isatty (fd) == 1;
} catch {
return false;
}
}
}
/// <summary>
/// An exception used to terminate the compiler resolution phase and provide completions
/// </summary>
/// <remarks>
/// This is thrown when we want to return the completions or
/// terminate the completion process by AST nodes used in
/// the completion process.
/// </remarks>
public class CompletionResult : Exception {
string [] result;
string base_text;
public CompletionResult (string base_text, string [] res)
{
if (base_text == null)
throw new ArgumentNullException ("base_text");
this.base_text = base_text;
result = res;
Array.Sort (result);
}
public string [] Result {
get {
return result;
}
}
public string BaseText {
get {
return base_text;
}
}
}
struct TypeNameParser
{
internal static string Escape(string name)
{
if (name == null) {
return null;
}
StringBuilder sb = null;
for (int pos = 0; pos < name.Length; pos++) {
char c = name[pos];
switch (c) {
case '\\':
case '+':
case ',':
case '[':
case ']':
case '*':
case '&':
if (sb == null) {
sb = new StringBuilder(name, 0, pos, name.Length + 3);
}
sb.Append("\\").Append(c);
break;
default:
if (sb != null) {
sb.Append(c);
}
break;
}
}
return sb != null ? sb.ToString() : name;
}
}
}