import libc;
import numbers.parser.errno.*;
import printer.formatter.(repr);



//
// Generic parsers
//
[S | CCompatibleString?(S)]
parseIntWith(s:S, intType, convFunc) {
    var p = cstring(s);
    var end = null(CChar);
    var value = convFunc(p, &end, 0);
    var typeName = StaticName(intType);
    if (end^ != 0)
        error("invalid " + typeName + ": ", repr(s));
    if ((errno() == ERANGE) or value < Least(intType) or value > Greatest(intType))
        error(typeName + " out of range: ", repr(s));
    return intType(value);
}

[S | CCompatibleString?(S)]
parseFloatWith(s:S, floatType, convFunc) {
    var p = cstring(s);
    var end = null(CChar);
    var value = convFunc(p, &end);
    var typeName = StaticName(floatType);
    if (end^ != 0)
        error("invalid " + typeName + ": ", repr(s));
    if (errno() == ERANGE)
        error(typeName + " out of range: ", repr(s));
    return floatType(value);
}

[S | CCompatibleString?(S)]
parseImagWith(s:S, imagType, convFunc) {
    var p = cstring(s);
    var end = null(CChar);
    var value = convFunc(p, &end);
    var typeName = StaticName(imagType);
    if (end^ != 0)
        error("invalid " + typeName + ": ", repr(s));
    if (errno() == ERANGE)
        error(typeName + " out of range: ", repr(s));
    return numericConvert(imagType,value);
}

//
// parseInt8, parseUInt8
//

[S | String?(S)]
parseInt8(s:S) = parseInt8(String(s));

[S | CCompatibleString?(S)]
overload parseInt8(s:S) = parseIntWith(s, Int8, libc.strtol);

[S | String?(S)]
parseUInt8(s:S) = parseUInt8(String(s));

[S | CCompatibleString?(S)]
overload parseUInt8(s:S) = parseIntWith(s, UInt8, libc.strtoul);


//
// parseInt16, parseUInt16
//

[S | String?(S)]
parseInt16(s:S) = parseInt16(String(s));

[S | CCompatibleString?(S)]
overload parseInt16(s:S) = parseIntWith(s, Int16, libc.strtol);

[S | String?(S)]
parseUInt16(s:S) = parseUInt16(String(s));

[S | CCompatibleString?(S)]
overload parseUInt16(s:S) =  parseIntWith(s, UInt16, libc.strtoul);


//
// parseInt32, parseUInt32
//

[S | String?(S)]
parseInt32(s:S) = parseInt32(String(s));

[S | CCompatibleString?(S)]
overload parseInt32(s:S) = parseIntWith(s, Int32, libc.strtol);

[S | String?(S)]
parseUInt32(s:S) = parseUInt32(String(s));

[S | CCompatibleString?(S)]
overload parseUInt32(s:S) = parseIntWith(s, UInt32, libc.strtoul);


//
// parseInt64, parseUInt64
//

[S | String?(S)]
parseInt64(s:S) = parseInt64(String(s));

[S | CCompatibleString?(S)]
overload parseInt64(s:S) = parseIntWith(s, Int64, libc.strtoll);

[S | String?(S)]
parseUInt64(s:S) = parseUInt64(String(s));

[S | CCompatibleString?(S)]
overload parseUInt64(s:S) = parseIntWith(s, UInt64, libc.strtoull);


//
// parseFloat32
//

[S | String?(S)]
parseFloat32(s:S) = parseFloat32(String(s));

[S | CCompatibleString?(S)]
overload parseFloat32(s:S) = parseFloatWith(s, Float32, libc.strtod);


//
// parseFloat64
//

[S | String?(S)]
parseFloat64(s:S) = parseFloat64(String(s));

[S | CCompatibleString?(S)]
overload parseFloat64(s:S) = parseFloatWith(s, Float64, libc.strtod);

//
// parseFloat80
//

[S | String?(S)]
parseFloat80(s:S) = parseFloat80(String(s));

[S | CCompatibleString?(S)]
overload parseFloat80(s:S) = parseFloatWith(s, Float80, libc.strtold);


//
// parseImag32
//

[S | String?(S)]
parseImag32(s:S) = parseImag32(String(s));

[S | CCompatibleString?(S)]
overload parseImag32(s:S) = parseImagWith(s, Imag32, libc.strtod);


//
// parseImag64
//

[S | String?(S)]
parseImag64(s:S) = parseImag64(String(s));

[S | CCompatibleString?(S)]
overload parseImag64(s:S) = parseImagWith(s, Imag64, libc.strtod);

//
// parseComplex80
//

[S | String?(S)]
parseImag80(s:S) = parseImag80(String(s));

[S | CCompatibleString?(S)]
overload parseImag80(s:S) = parseImagWith(s, Imag80, libc.strtold);
