import java.lang { System, Long, Double, Int=Integer, Math }

"Represents the machine and virtual machine on which the 
 current process is executing.
 
 Holds information about runtime name, version and about 
 inherent limitations like minimum/maximum values that can 
 be represented by the runtime."
see (`value process`, `value language`, `value system`,
     `value operatingSystem`)
tagged("Environment")
shared native object runtime  {
    
    "The name of the runtime / virtual machine this process 
     is running on."
    shared native String name;
    
    "The version of the runtime / virtual machine this 
     process is running on."
    shared native String version;
    
    "The number of bits used to represent the value of an 
     [[Integer]]."
    see (`class Integer`)
    shared native Integer integerSize;
    
    "The number of bits of [[Integer]] instances which may 
     be manipulated via the methods inherited from
     [[Binary]]."
    shared native Integer integerAddressableSize;
    
    "The smallest [[Integer]] value that can be represented 
     by the runtime.
     
     It is the minimum `Integer` that can be distinguished 
     from its successor using below formula:
     
     `Integer(n-1) = Integer(n) - 1` with `Integer(0) = 0`"
    see (`class Integer`)
    shared native Integer minIntegerValue;

    "The largest [[Integer]] value that can be represented 
     by the runtime.
     
     It is the maximum `Integer` that can be distinguished 
     from its predecessor using below formula:
     
     `Integer(n+1) = Integer(n) + 1` with `Integer(0) = 0`"
    see (`class Integer`)
    shared native Integer maxIntegerValue;
    
    "The maximum size of an [[Array]] that is possible for 
     this runtime. Note that this is a theoretical limit 
     only. In practice it is usually impossible to allocate 
     an array of this size, due to memory constraints."
    see (`class Array`)
    shared native Integer maxArraySize;
    
    "The largest finite [[Float]] value that can be 
     represented by the runtime."
    shared native Float maxFloatValue;

    "The smallest positive nonzero [[Float]] value that can 
     be represented by the runtime."
    shared native Float minFloatValue;
    
    "The _machine epsilon_ for [[floating point|Float]]
     values. That is, the smallest value `e` such that:
     
         1.0 + e > 1.0"
    shared native Float epsilon; 
    
    "The largest [[Integer]] that can be exactly represented
     as a [[Float]] without loss of precision. The negative
     of this value is the smallest `Integer` that can be
     exactly represented as a `Float`."
    see (`value Integer.float`)
    shared native Integer maxExactIntegralFloat;
    
    string => "runtime [``name`` / ``version``]";
}

shared native("jvm") object runtime  {
    shared native("jvm") String name 
            => "jvm";
    shared native("jvm") String version 
            => System.getProperty(
                    "java.specification.version");
    shared native("jvm") Integer integerSize 
            => 64;
    shared native("jvm") Integer integerAddressableSize 
            => 64;
    shared native("jvm") Integer minIntegerValue 
            => Long.\iMIN_VALUE;
    shared native("jvm") Integer maxIntegerValue 
            => Long.\iMAX_VALUE;
    shared native("jvm") Integer maxArraySize 
            = Int.\iMAX_VALUE - 8;
    shared native("jvm") Float maxFloatValue 
            => Double.\iMAX_VALUE;
    shared native("jvm") Float minFloatValue 
            => Double.\iMIN_VALUE;    
    shared native("jvm") Float epsilon 
            = Math.ulp(1.0);
    shared native("jvm") Integer maxExactIntegralFloat 
            = 2^53-1;
}

shared native("js") object runtime  {
    shared native("js") String name {
        dynamic {
            if (is String version 
                = process.propertyValue("node.version")) {
                return "node.js";
            }
            else if (exists window) {
                return "Browser";
            }
            else {
                return "Unknown JavaScript environment";
            }
        }
    }
    shared native("js") String version {
        dynamic { 
            if (is String version 
                = process.propertyValue("node.version")) {
                return version;
            }
            else if (is String version 
                = process.propertyValue("browser.version")) {
                return version;
            }
            else {
                return "Unknown";
            }
        }
    }
    shared native("js") Integer integerSize => 53;
    shared native("js") Integer integerAddressableSize => 32;
    shared native("js") Integer minIntegerValue = -(2^53-1);
    shared native("js") Integer maxIntegerValue = 2^53-1;
    shared native("js") Integer maxArraySize = 2^32-1;
    shared native("js") Float epsilon = 2.0^(-52);
    shared native("js") Integer maxExactIntegralFloat 
            => maxIntegerValue;
    shared native("js") Float maxFloatValue {
        dynamic {
            return \iNumber.\iMAX_VALUE;
        }
    }
    shared native("js") Float minFloatValue {
        dynamic {
            return \iNumber.\iMIN_VALUE;
        }
    }
}