packages feed

futhark-0.13.1: rts/csharp/reader.cs

private Stream s;
private BinaryReader b;

// Note that the lookahead buffer does not interact well with
// binary reading.  We are careful to not let this become a
// problem.
private Stack<char> LookaheadBuffer = new Stack<char>();

private void ResetLookahead(){
    LookaheadBuffer.Clear();
}

private void ValueReader(Stream s)
{
    this.s = s;
}

private void ValueReader()
{
    this.s = Console.OpenStandardInput();
    this.b = new BinaryReader(s);
}

private char? GetChar()
{
    char c;
    if (LookaheadBuffer.Count == 0)
    {
        c = (char) this.b.ReadByte();
    }
    else
    {
        c = LookaheadBuffer.Pop();
    }

    return c;
}

private char[] GetChars(int n)
{
    return Enumerable.Range(0, n).Select(_ => GetChar().Value).ToArray();
}

private void UngetChar(char c)
{
    LookaheadBuffer.Push(c);
}

private char PeekChar()
{
    var c = GetChar();
    UngetChar(c.Value);
    return c.Value;
}

private void SkipSpaces()
{
    var c = GetChar();
    while (c.HasValue){
        if (char.IsWhiteSpace(c.Value))
        {
            c = GetChar();
        }
        else if (c == '-')
        {
            if (PeekChar() == '-')
            {
                while (c.Value != '\n')
                {
                    c = GetChar();
                }
            }
            else
            {
                break;
            }
        }
        else
        {
            break;
        }
    }

    if (c.HasValue)
    {
        UngetChar(c.Value);
    }
}

private bool ParseSpecificChar(char c)
{
    var got = GetChar();
    if (got.Value != c)
    {
        UngetChar(got.Value);
        throw new ValueError();
    }
    return true;
}

private bool ParseSpecificString(string str)
{
    var read = new List<char>();
    foreach (var c in str.ToCharArray())
    {
        try
        {
            ParseSpecificChar(c);
            read.Add(c);
        }
        catch(ValueError)
        {
            read.Reverse();
            foreach (var cc in read)
            {
                UngetChar(cc);
            }
            throw;
        }
    }

    return true;
}

private string Optional(Func<string> p)
{
    string res = null;
    try
    {
        res = p();
    }
    catch (Exception)
    {
    }

    return res;
}

private bool Optional(Func<char, bool> p, char c)
{
    try
    {
        return p(c);
    }
    catch (Exception)
    {
    }

    return false;
}

private bool OptionalSpecificString(string s)
{
    var c = PeekChar();
    if (c == s[0])
    {
        return ParseSpecificString(s);
    }
    return false;
}


private List<string> sepBy(Func<string> p, Func<string> sep)
{
    var elems = new List<string>();
    var x = Optional(p);
    if (!string.IsNullOrWhiteSpace(x))
    {
        elems.Add(x);
        while (!string.IsNullOrWhiteSpace(Optional(sep)))
        {
            var y = Optional(p);
            elems.Add(y);
        }
    }
    return elems;
}

private string ParseHexInt()
{
    var s = "";
    var c = GetChar();
    while (c.HasValue)
    {
        if (Uri.IsHexDigit(c.Value))
        {
            s += c.Value;
            c = GetChar();
        }
        else if (c == '_')
        {
            c = GetChar();
        }
        else
        {
            UngetChar(c.Value);
            break;
        }
    }

    return Convert.ToString(Convert.ToUInt32(s, 16));
}

private string ParseInt()
{
    var s = "";
    var c = GetChar();
    if (c.Value == '0' && "xX".Contains(PeekChar()))
    {
        GetChar();
        s += ParseHexInt();
    }
    else
    {
        while (c.HasValue)
        {
            if (char.IsDigit(c.Value))
            {
                s += c.Value;
                c = GetChar();
            }else if (c == '_')
            {
                c = GetChar();
            }
            else
            {
                UngetChar(c.Value);
                break;
            }
        }

    }

    if (s.Length == 0)
    {
        throw new Exception("ValueError");
    }

    return s;
}

private string ParseIntSigned()
{
    var c = GetChar();
    if (c.Value == '-' && char.IsDigit(PeekChar()))
    {
        return c + ParseInt();
    }
    else
    {
        if (c.Value != '+')
        {
            UngetChar(c.Value);
        }

        return ParseInt();
    }
}

private string ReadStrComma()
{
    SkipSpaces();
    ParseSpecificChar(',');
    return ",";
}

private int ReadStrInt(string s)
{
    SkipSpaces();
    var x = Convert.ToInt32(ParseIntSigned());
    OptionalSpecificString(s);
    return x;
}

private ulong ReadStrUInt64(string s)
{
    SkipSpaces();
    var x = Convert.ToUInt64(ParseInt());
    OptionalSpecificString(s);
    return x;
}

private long ReadStrInt64(string s)
{
    SkipSpaces();
    var x = Convert.ToInt64(ParseIntSigned());
    OptionalSpecificString(s);
    return x;
}

private uint ReadStrUInt(string s)
{
    SkipSpaces();
    var x = Convert.ToUInt32(ParseInt());
    OptionalSpecificString(s);
    return x;
}

private int ReadStrI8(){return ReadStrInt("i8");}
private int ReadStrI16(){return ReadStrInt("i16");}
private int ReadStrI32(){return ReadStrInt("i32");}
private long ReadStrI64(){return ReadStrInt64("i64");}
private uint ReadStrU8(){return ReadStrUInt("u8");}
private uint ReadStrU16(){return ReadStrUInt("u16");}
private uint ReadStrU32(){return ReadStrUInt("u32");}
private ulong ReadStrU64(){return ReadStrUInt64("u64");}
private sbyte ReadBinI8(){return (sbyte) b.ReadByte();}
private short ReadBinI16(){return b.ReadInt16();}
private int ReadBinI32(){return b.ReadInt32();}
private long ReadBinI64(){return b.ReadInt64();}
private byte ReadBinU8(){return (byte) b.ReadByte();}
private ushort ReadBinU16(){return b.ReadUInt16();}
private uint ReadBinU32(){return b.ReadUInt32();}
private ulong ReadBinU64(){return b.ReadUInt64();}
private float ReadBinF32(){return b.ReadSingle();}
private double ReadBinF64(){return b.ReadDouble();}
private bool ReadBinBool(){return b.ReadBoolean();}

private char ReadChar()
{
    SkipSpaces();
    ParseSpecificChar('\'');
    var c = GetChar();
    ParseSpecificChar('\'');
    return c.Value;
}

private double ReadStrHexFloat(char sign)
{
    var int_part = ParseHexInt();
    ParseSpecificChar('.');
    var frac_part = ParseHexInt();
    ParseSpecificChar('p');
    var exponent = ParseHexInt();

    var int_val = Convert.ToInt32(int_part, 16);
    var frac_val = Convert.ToSingle(Convert.ToInt32(frac_part, 16)) / Math.Pow(16, frac_part.Length);
    var exp_val = Convert.ToInt32(exponent);

    var total_val = (int_val + frac_val) * Math.Pow(2, exp_val);
    if (sign == '-')
    {
        total_val = -1 * total_val;
    }

    return Convert.ToDouble(total_val);
}

private double ReadStrDecimal()
{
    SkipSpaces();
    var c = GetChar();
    char sign;
    if (c.Value == '-')
    {
        sign = '-';
    }
    else
    {
        UngetChar(c.Value);
        sign = '+';
    }

    // Check for hexadecimal float
    c = GetChar();
    if (c.Value == '0' && "xX".Contains(PeekChar()))
    {
        GetChar();
        return ReadStrHexFloat(sign);
    }
    else
    {
        UngetChar(c.Value);
    }

    var bef = Optional(this.ParseInt);
    var aft = "";
    if (string.IsNullOrEmpty(bef))
    {
        bef = "0";
        ParseSpecificChar('.');
        aft = ParseInt();
    }else if (Optional(ParseSpecificChar, '.'))
    {
        aft = ParseInt();
    }
    else
    {
        aft = "0";
    }

    var expt = "";
    if (Optional(ParseSpecificChar, 'E') ||
        Optional(ParseSpecificChar, 'e'))
    {
        expt = ParseIntSigned();
    }
    else
    {
        expt = "0";
    }

    return Convert.ToDouble(sign + bef + "." + aft + "E" + expt);
}

private float ReadStrF32()
{
    try
    {
        ParseSpecificString("f32.nan");
        return Single.NaN;
    }
    catch (ValueError)
    {
        try
        {
            ParseSpecificString("-f32.inf");
            return Single.NegativeInfinity;
        }
        catch (ValueError)
        {
            try
            {
                ParseSpecificString("f32.inf");
                return Single.PositiveInfinity;
            }
            catch (ValueError)
            {
                var x = ReadStrDecimal();
                OptionalSpecificString("f32");
                return Convert.ToSingle(x);
            }
        }
    }
}

private double ReadStrF64()
{
    try
    {
        ParseSpecificString("f64.nan");
        return Double.NaN;
    }
    catch (ValueError)
    {
        try
        {
            ParseSpecificString("-f64.inf");
            return Double.NegativeInfinity;
        }
        catch (ValueError)
        {
            try
            {
                ParseSpecificString("f64.inf");
                return Double.PositiveInfinity;
            }
            catch (ValueError)
            {
                var x = ReadStrDecimal();
                OptionalSpecificString("f64");
                return x;
            }
        }
    }
}
private bool ReadStrBool()
{
    SkipSpaces();
    if (PeekChar() == 't')
    {
        ParseSpecificString("true");
        return true;
    }

    if (PeekChar() == 'f')
    {
        ParseSpecificString("false");
        return false;
    }

    throw new ValueError();
}

private (T[], int[]) ReadStrArrayElems<T>(int rank, Func<T> ReadStrScalar)
{
    bool first = true;
    bool[] knows_dimsize = new bool[rank];
    int cur_dim = rank-1;
    int[] elems_read_in_dim = new int[rank];
    int[] shape = new int[rank];

    int capacity = 100;
    T[] data = new T[capacity];
    int write_ptr = 0;

    while (true) {
        SkipSpaces();

        char c = (char) GetChar();
        if (c == ']') {
            if (knows_dimsize[cur_dim]) {
                if (shape[cur_dim] != elems_read_in_dim[cur_dim]) {
                    throw new Exception("Irregular array");
                }
            } else {
                knows_dimsize[cur_dim] = true;
                shape[cur_dim] = elems_read_in_dim[cur_dim];
            }
            if (cur_dim == 0) {
                break;
            } else {
                cur_dim--;
                elems_read_in_dim[cur_dim]++;
            }
        } else if (c == ',') {
            SkipSpaces();
            c = (char) GetChar();
            if (c == '[') {
                if (cur_dim == rank - 1) {
                    throw new Exception("Array has too many dimensions");
                }
                first = true;
                cur_dim++;
                elems_read_in_dim[cur_dim] = 0;
            } else if (cur_dim == rank - 1) {
                UngetChar(c);

                data[write_ptr++] = ReadStrScalar();
                if (write_ptr == capacity) {
                    capacity *= 2;
                    Array.Resize(ref data, capacity);
                }
                elems_read_in_dim[cur_dim]++;
            } else {
                throw new Exception("Unexpected comma when reading array");
            }
        } else if (first) {
            if (c == '[') {
                if (cur_dim == rank - 1) {
                    throw new Exception("Array has too many dimensions");
                }
                cur_dim++;
                elems_read_in_dim[cur_dim] = 0;
            } else {
                UngetChar(c);
                data[write_ptr++] = ReadStrScalar();
                if (write_ptr == capacity) {
                    capacity *= 2;
                    Array.Resize(ref data, capacity);
                }
                elems_read_in_dim[cur_dim]++;
                first = false;
            }
        } else {
            throw new Exception("Unexpected character in array");
        }
    }
    Array.Resize(ref data, write_ptr);
    return (data, shape);
}

private (T[], int[]) ReadStrArrayEmpty<T>(int rank, string typeName, Func<T> ReadStrScalar)
{
    ParseSpecificString("empty");
    ParseSpecificChar('(');
    int[] shape = new int[rank];
    for (int i = 0; i < rank; i++) {
        ParseSpecificString("[");
        shape[i] = Convert.ToInt32(ParseIntSigned());
        ParseSpecificString("]");
    }
    ParseSpecificString(typeName);
    ParseSpecificChar(')');

    // Check whether the array really is empty.
    for (int i = 0; i < rank; i++) {
        if (shape[i] == 0) {
            return (new T[1], shape);
        }
    }

    // Not an empty array!
    throw new Exception("empty() used with nonempty shape");
}

private (T[], int[]) ReadStrArray<T>(int rank, string typeName, Func<T> ReadStrScalar)
{
    long read_dims = 0;

    while (true) {
        SkipSpaces();
        var c = GetChar();
        if (c=='[') {
            read_dims++;
        } else {
            if (c != null) {
                UngetChar((char)c);
            }
            break;
        }
    }

    if (read_dims == 0) {
        return ReadStrArrayEmpty(rank, typeName, ReadStrScalar);
    }

    if (read_dims != rank) {
        throw new Exception("Wrong number of dimensions");
    }

    return ReadStrArrayElems(rank, ReadStrScalar);
}

private Dictionary<string, string> primtypes = new Dictionary<string, string>
{
    {"  i8",   "i8"},
    {" i16",  "i16"},
    {" i32",  "i32"},
    {" i64",  "i64"},
    {"  u8",   "u8"},
    {" u16",  "u16"},
    {" u32",  "u32"},
    {" u64",  "u64"},
    {" f32",  "f32"},
    {" f64",  "f64"},
    {"bool", "bool"}
};

private int BINARY_FORMAT_VERSION = 2;


private void read_le_2byte(ref short dest)
{
    dest = b.ReadInt16();
}

private void read_le_4byte(ref int dest)
{
    dest = b.ReadInt32();
}

private void read_le_8byte(ref long dest)
{
    dest = b.ReadInt64();
}

private bool ReadIsBinary()
    {
        SkipSpaces();
        var c = GetChar();
        if (c == 'b')
        {
            byte bin_version = new byte();
            try
            {
                bin_version = (byte) b.ReadByte();
            }
            catch
            {
                Console.WriteLine("binary-input: could not read version");
                Environment.Exit(1);
            }

            if (bin_version != BINARY_FORMAT_VERSION)
            {
                Console.WriteLine((
                    "binary-input: File uses version {0}, but I only understand version {1}.", bin_version,
                    BINARY_FORMAT_VERSION));
                Environment.Exit(1);
            }

            return true;
        }
        UngetChar((char) c);
        return false;
    }

private (T[], int[]) ReadArray<T>(int rank, string typeName, Func<T> ReadStrScalar)
{
    if (!ReadIsBinary())
    {
        return ReadStrArray<T>(rank, typeName, ReadStrScalar);
    }
    else
    {
        return ReadBinArray<T>(rank, typeName, ReadStrScalar);
    }
}
private T ReadScalar<T>(string typeName, Func<T> ReadStrScalar, Func<T> ReadBinScalar)
{
    if (!ReadIsBinary())
    {
        return ReadStrScalar();
    }
    else
    {
        ReadBinEnsureScalar(typeName);
        return ReadBinScalar();
    }
}

private void ReadBinEnsureScalar(string typeName)
{
    var bin_dims = b.ReadByte();
    if (bin_dims != 0)
    {
        Console.WriteLine("binary-input: Expected scalar (0 dimensions), but got array with {0} dimensions.", bin_dims);
        Environment.Exit(1);
    }

    var bin_type = ReadBinReadTypeString();
    if (bin_type != typeName)
    {
        Console.WriteLine("binary-input: Expected scalar of type {0} but got scalar of type {1}.", typeName,
                          bin_type);
        Environment.Exit(1);
    }
}

private string ReadBinReadTypeString()
{
    var str_bytes = b.ReadBytes(4);
    var str = System.Text.Encoding.UTF8.GetString(str_bytes, 0, 4);
    return primtypes[str];
}

private (T[], int[]) ReadBinArray<T>(int rank, string typeName, Func<T> ReadStrScalar)
{
    var bin_dims = new int();
    var shape = new int[rank];
    try
    {
        bin_dims = b.ReadByte();
    }
    catch
    {
        Console.WriteLine("binary-input: Couldn't get dims.");
        Environment.Exit(1);
    }

    if (bin_dims != rank)
    {
        Console.WriteLine("binary-input: Expected {0} dimensions, but got array with {1} dimensions", rank,
            bin_dims);
        Environment.Exit(1);

    }

    var bin_primtype = ReadBinReadTypeString();
    if (typeName != bin_primtype)
    {
        Console.WriteLine("binary-input: Expected {0}D-array with element type '{1}', but got {2}D-array with element type '{3}'.",
                          rank, typeName, bin_dims, bin_primtype);
        Environment.Exit(1);
    }

    int elem_count = 1;
    for (var i = 0; i < rank; i++)
    {
        long bin_shape = new long();
        try
        {
            read_le_8byte(ref bin_shape);
        }
        catch
        {
            Console.WriteLine("binary-input: Couldn't read size for dimension {0} of array.", i);
            Environment.Exit(1);
        }

        elem_count *= (int) bin_shape;
        shape[i] = (int) bin_shape;
    }

    // For whatever reason, Marshal.SizeOf<bool> is 4, so special-case that here.
    var elem_size = typeof(T) == typeof(bool) ? 1 : Marshal.SizeOf<T>();
    var num_bytes = elem_count * elem_size;
    var tmp = new byte[num_bytes];
    var data = new T[elem_count];

    var to_read = num_bytes;
    var have_read = 0;
    while (to_read > 0)
    {
        var bytes_read = b.Read(tmp, have_read, to_read);
        to_read -= bytes_read;
        have_read += bytes_read;
        if (bytes_read == 0) {
            Console.WriteLine("binary-input: EOF after {0} bytes (expected {1})", have_read, num_bytes);
            Environment.Exit(1);
        }
    }

    if (!BitConverter.IsLittleEndian && elem_size != 1)
    {
        for (int i = 0; i < elem_count; i ++)
        {
            Array.Reverse(tmp, i * elem_size, elem_size); 
        }
    }
    Buffer.BlockCopy(tmp,0,data,0,num_bytes);

    /* we should have a proper error message here */
    return (data, shape);
}


private sbyte ReadI8()
{
    return (sbyte) ReadStrI8();
}
private short ReadI16()
{
    return (short) ReadStrI16();
}
private int ReadI32()
{
    return ReadStrI32();
}
private long ReadI64()
{
    return ReadStrI64();
}

private byte ReadU8()
{
    return (byte) ReadStrU8();
}
private ushort ReadU16()
{
    return (ushort) ReadStrU16();
}
private uint ReadU32()
{
    return (uint) ReadStrU32();
}
private ulong ReadU64()
{
    return (ulong) ReadStrU64();
}
private bool ReadBool()
{
    return ReadStrBool();
}
private float ReadF32()
{
    return ReadStrF32();
}
private double ReadF64()
{
    return ReadStrF64();
}

private void WriteValue(bool x){Console.Write(x ? "true" : "false", x);}
private void WriteValue(sbyte x){Console.Write("{0}i8", x);}
private void WriteValue(short x){Console.Write("{0}i16", x);}
private void WriteValue(int x){Console.Write("{0}i32", x);}
private void WriteValue(long x){Console.Write("{0}i64", x);}
private void WriteValue(byte x){Console.Write("{0}u8", x);}
private void WriteValue(ushort x){Console.Write("{0}u16", x);}
private void WriteValue(uint x){Console.Write("{0}u32", x);}
private void WriteValue(ulong x){Console.Write("{0}u64", x);}
private void WriteValue(float x){if (Single.IsNaN(x))
    {Console.Write("f32.nan");} else if (Single.IsNegativeInfinity(x))
    {Console.Write("-f32.inf");} else if (Single.IsPositiveInfinity(x))
    {Console.Write("f32.inf");} else
    {Console.Write("{0:0.000000}f32", x);}}
private void WriteValue(double x){if (Double.IsNaN(x))
    {Console.Write("f64.nan");} else if (Double.IsNegativeInfinity(x))
    {Console.Write("-f64.inf");} else if (Double.IsPositiveInfinity(x))
    {Console.Write("f64.inf");} else
    {Console.Write("{0:0.000000}f64", x);}}