289 lines
6.7 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|