This commit is contained in:
Dante
2026-05-21 23:40:20 -07:00
parent 3e2915dff7
commit 877a69d844
5737 changed files with 29796 additions and 1589684 deletions

View File

@ -23,6 +23,8 @@
import java.Boot;
import java.Lib;
using StringTools;
@:coreApi @:nativeGen class Std {
@:deprecated('Std.is is deprecated. Use Std.isOfType instead.')
public static inline function is(v:Dynamic, t:Dynamic):Bool {
@ -63,54 +65,74 @@ import java.Lib;
return cast x;
}
static inline function isSpaceChar(code:Int):Bool
return (code > 8 && code < 14) || code == 32;
static inline function isHexPrefix(cur:Int, next:Int):Bool
return cur == '0'.code && (next == 'x'.code || next == 'X'.code);
static inline function isDecimalDigit(code:Int):Bool
return '0'.code <= code && code <= '9'.code;
static inline function isHexadecimalDigit(code:Int):Bool
return isDecimalDigit(code) || ('a'.code <= code && code <= 'f'.code) || ('A'.code <= code && code <= 'F'.code);
public static function parseInt(x:String):Null<Int> {
if (x == null)
return null;
var base = 10;
var len = x.length;
var foundCount = 0;
var sign = 0;
var firstDigitIndex = 0;
var lastDigitIndex = -1;
var previous = 0;
final len = x.length;
var index = 0;
for(i in 0...len) {
var c = StringTools.fastCodeAt(x, i);
switch c {
case _ if((c > 8 && c < 14) || c == 32):
if(foundCount > 0) {
return null;
}
continue;
case '-'.code if(foundCount == 0):
sign = -1;
case '+'.code if(foundCount == 0):
sign = 1;
case '0'.code if(foundCount == 0 || (foundCount == 1 && sign != 0)):
case 'x'.code | 'X'.code if(previous == '0'.code && ((foundCount == 1 && sign == 0) || (foundCount == 2 && sign != 0))):
base = 16;
case _ if('0'.code <= c && c <= '9'.code):
case _ if(base == 16 && (('a'.code <= c && c <= 'z'.code) || ('A'.code <= c && c <= 'Z'.code))):
case _:
break;
}
if((foundCount == 0 && sign == 0) || (foundCount == 1 && sign != 0)) {
firstDigitIndex = i;
}
foundCount++;
lastDigitIndex = i;
previous = c;
inline function hasIndex(index:Int)
return index < len;
// skip whitespace
while (hasIndex(index)) {
if (!isSpaceChar(x.unsafeCodeAt(index)))
break;
++index;
}
if(firstDigitIndex <= lastDigitIndex) {
var digits = x.substring(firstDigitIndex + (base == 16 ? 2 : 0), lastDigitIndex + 1);
return try {
(sign == -1 ? -1 : 1) * java.lang.Integer.parseInt(digits, base);
} catch(e:java.lang.NumberFormatException) {
null;
// handle sign
final isNegative = hasIndex(index) && {
final sign = x.unsafeCodeAt(index);
if (sign == '-'.code || sign == '+'.code) {
++index;
}
sign == '-'.code;
}
return null;
// handle base
final isHexadecimal = hasIndex(index + 1) && isHexPrefix(x.unsafeCodeAt(index), x.unsafeCodeAt(index + 1));
if (isHexadecimal)
index += 2; // skip prefix
// handle digits
final firstInvalidIndex = {
var cur = index;
if (isHexadecimal) {
while (hasIndex(cur)) {
if (!isHexadecimalDigit(x.unsafeCodeAt(cur)))
break;
++cur;
}
} else {
while (hasIndex(cur)) {
if (!isDecimalDigit(x.unsafeCodeAt(cur)))
break;
++cur;
}
}
cur;
}
// no valid digits
if (index == firstInvalidIndex)
return null;
final result = java.lang.Integer.parseInt(x.substring(index, firstInvalidIndex), if (isHexadecimal) 16 else 10);
return if (isNegative) -result else result;
}
public static function parseFloat(x:String):Float {

View File

@ -21,6 +21,8 @@
*/
import java.lang.System;
import java.net.URI;
import java.nio.file.Paths;
import sys.io.Process;
using haxe.Int64;
@ -48,20 +50,19 @@ using haxe.Int64;
return java.lang.System.getenv(s);
}
public static function putEnv(s:String, v:String):Void {
public static function putEnv(s:String, v:Null<String>):Void {
// java offers no support for it (!)
throw new haxe.exceptions.NotImplementedException("Not implemented in this platform");
}
public static function environment():Map<String, String> {
if (_env != null)
return _env;
var _env = _env = new haxe.ds.StringMap();
for (mv in java.lang.System.getenv().entrySet()) {
_env.set(mv.getKey(), mv.getValue());
if (_env == null) {
_env = new haxe.ds.StringMap();
for (mv in java.lang.System.getenv().entrySet())
_env.set(mv.getKey(), mv.getValue());
}
return _env;
return _env.copy();
}
public static function sleep(seconds:Float):Void {
@ -141,7 +142,8 @@ using haxe.Int64;
}
public static function programPath():String {
return java.Lib.toNativeType(Sys).getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
final uri:URI = java.Lib.toNativeType(Sys).getProtectionDomain().getCodeSource().getLocation().toURI();
return Std.string(Paths.get(uri));
}
public static function getChar(echo:Bool):Int {

View File

@ -179,8 +179,8 @@ enum ValueType {
}
// cache empty constructor arguments so we don't allocate it on each createEmptyInstance call
@:protected @:readOnly static var __createEmptyInstance_EMPTY_TYPES = java.NativeArray.make(java.Lib.toNativeEnum(java.internal.Runtime.EmptyObject));
@:protected @:readOnly static var __createEmptyInstance_EMPTY_ARGS = java.NativeArray.make(java.internal.Runtime.EmptyObject.EMPTY);
@:protected @:readOnly static var __createEmptyInstance_EMPTY_TYPES = java.Lib.toNativeEnum(java.internal.Runtime.EmptyObject);
@:protected @:readOnly static var __createEmptyInstance_EMPTY_ARGS = java.internal.Runtime.EmptyObject.EMPTY;
public static function createEmptyInstance<T>(cl:Class<T>):T {
var t = java.Lib.toNativeType(cl);

View File

@ -3,39 +3,87 @@ package haxe;
import haxe.iterators.RestIterator;
import haxe.iterators.RestKeyValueIterator;
import java.NativeArray;
import java.lang.System;
import java.StdTypes;
import java.lang.Object;
import java.lang.System;
import java.util.Arrays;
private typedef NativeRest<T> = NativeArray<Object>;
private typedef NativeRest<T> = NativeArray<T>;
@:coreApi
abstract Rest<T>(NativeRest<T>) {
public var length(get,never):Int;
public var length(get, never):Int;
inline function get_length():Int
return this.length;
@:from static public function of<T>(array:Array<T>):Rest<T> {
var native = @:privateAccess array.__a;
var result:NativeRest<T>;
#if jvm
result = (cast native:Object).clone();
#else
result = new NativeRest<T>(native.length);
for(i in 0...native.length)
result[i] = cast native[i];
#end
@:from extern inline static public function of<T>(array:Array<T>):Rest<T> {
var result = createNative(array.length);
var src:NativeArray<Object> = cast @:privateAccess array.__a;
for (i in 0...result.length)
result[i] = cast src[i];
return new Rest(result);
}
@:noDoc
@:generic
static function ofNativePrimitive<TBoxed, TRest>(result:NativeRest<TBoxed>, collection:NativeArray<TRest>):Rest<TRest> {
for (i in 0...collection.length)
result[i] = cast collection[i];
return new Rest(cast result);
}
@:noDoc
@:from static function ofNativeInt(collection:NativeArray<Int>):Rest<Int>
return ofNativePrimitive(new NativeRest<java.lang.Integer>(collection.length), collection);
@:noDoc
@:from static function ofNativeFloat(collection:NativeArray<Float>):Rest<Float>
return ofNativePrimitive(new NativeRest<java.lang.Double>(collection.length), collection);
@:noDoc
@:from static function ofNativeBool(collection:NativeArray<Bool>):Rest<Bool>
return ofNativePrimitive(new NativeRest<java.lang.Boolean>(collection.length), collection);
@:noDoc
@:from static function ofNativeInt8(collection:NativeArray<Int8>):Rest<Int8>
return ofNativePrimitive(new NativeRest<java.lang.Byte>(collection.length), collection);
@:noDoc
@:from static function ofNativeInt16(collection:NativeArray<Int16>):Rest<Int16>
return ofNativePrimitive(new NativeRest<java.lang.Short>(collection.length), collection);
@:noDoc
@:from static function ofNativeChar16(collection:NativeArray<Char16>):Rest<Char16>
return ofNativePrimitive(new NativeRest<java.lang.Character>(collection.length), collection);
@:noDoc
@:from static function ofNativeHaxeInt64(collection:NativeArray<haxe.Int64>):Rest<haxe.Int64>
return ofNativePrimitive(new NativeRest<java.lang.Long>(collection.length), collection);
@:noDoc
@:from static function ofNativeInt64(collection:NativeArray<Int64>):Rest<Int64>
return ofNativePrimitive(new NativeRest<java.lang.Long>(collection.length), collection);
@:noDoc
@:from static function ofNative<T>(collection:NativeArray<T>):Rest<T> {
return new Rest(collection);
}
inline function new(a:NativeRest<T>):Void
this = a;
/**
* Implemented in genjvm (to auto-box primitive types) and genjava
*/
static function createNative<T>(length:Int):NativeRest<T>
return new NativeRest<T>(length);
@:arrayAccess inline function get(index:Int):T
return cast this[index];
return this[index];
@:to public function toArray():Array<T> {
return [for(i in 0...this.length) cast this[i]];
return [for (i in 0...this.length) this[i]];
}
public inline function iterator():RestIterator<T>
@ -44,15 +92,21 @@ abstract Rest<T>(NativeRest<T>) {
public inline function keyValueIterator():RestKeyValueIterator<T>
return new RestKeyValueIterator<T>(this);
public function append(item:T):Rest<T> {
var result = new NativeRest<T>(this.length + 1);
extern inline public function append(item:T):Rest<T> {
return _append(createNative(this.length + 1), item);
}
function _append(result:NativeRest<T>, item:T):Rest<T> {
System.arraycopy(this, 0, result, 0, this.length);
result[this.length] = cast item;
return new Rest(result);
}
public function prepend(item:T):Rest<T> {
var result = new NativeRest<T>(this.length + 1);
extern inline public function prepend(item:T):Rest<T> {
return _prepend(createNative(this.length + 1), item);
}
function _prepend(result:NativeRest<T>, item:T):Rest<T> {
System.arraycopy(this, 0, result, 1, this.length);
result[0] = cast item;
return new Rest(result);
@ -61,4 +115,4 @@ abstract Rest<T>(NativeRest<T>) {
public function toString():String {
return toArray().toString();
}
}
}

View File

@ -0,0 +1,34 @@
package haxe.atomic;
import java.util.concurrent.atomic.AtomicBoolean;
abstract AtomicBool(AtomicBoolean) {
public inline function new(value:Bool) {
this = new AtomicBoolean(value);
}
public inline function compareExchange(expected:Bool, replacement:Bool):Bool {
// Java's compareAndSet returns a boolean, so do a CAS loop to be able to return the original value without a potential race condition
var original;
var real_replacement;
do {
original = this.get();
real_replacement = original == expected ? replacement : original;
} while (!this.compareAndSet(original, real_replacement));
return original;
}
public inline function exchange(value:Bool):Bool {
return this.getAndSet(value);
}
public inline function load():Bool {
return this.get();
}
public inline function store(value:Bool):Bool {
this.set(value);
return value;
}
}

View File

@ -0,0 +1,64 @@
package haxe.atomic;
import java.util.concurrent.atomic.AtomicInteger;
abstract AtomicInt(AtomicInteger) {
public inline function new(value:Int) {
this = new AtomicInteger(value);
}
private inline function cas_loop(value:Int, op:(a:Int, b:Int) -> Int):Int {
var val;
do {
val = this.get();
} while (!this.compareAndSet(val, op(val, value)));
return val;
}
public inline function add(b:Int):Int {
return this.getAndAdd(b);
}
public inline function sub(b:Int):Int {
return this.getAndAdd(-b);
}
public inline function and(b:Int):Int {
return cas_loop(b, (a:Int, b:Int) -> a & b);
}
public inline function or(b:Int):Int {
return cas_loop(b, (a:Int, b:Int) -> a | b);
}
public inline function xor(b:Int):Int {
return cas_loop(b, (a:Int, b:Int) -> a ^ b);
}
public inline function compareExchange(expected:Int, replacement:Int):Int {
// Java's compareAndSet returns a boolean, so do a CAS loop to be able to return the original value without a potential race condition
var original;
var real_replacement;
do {
original = this.get();
real_replacement = original == expected ? replacement : original;
} while (!this.compareAndSet(original, real_replacement));
return original;
}
public inline function exchange(value:Int):Int {
return this.getAndSet(value);
}
public inline function load():Int {
return this.get();
}
public inline function store(value:Int):Int {
this.set(value);
return value;
}
}

View File

@ -0,0 +1,34 @@
package haxe.atomic;
import java.util.concurrent.atomic.AtomicReference;
abstract AtomicObject<T:{}>(AtomicReference<T>) {
public inline function new(value:T) {
this = new AtomicReference(value);
}
public inline function compareExchange(expected:T, replacement:T):T {
// Java's compareAndSet returns a boolean, so do a CAS loop to be able to return the original value without a potential race condition
var original;
var real_replacement;
do {
original = this.get();
real_replacement = original == expected ? replacement : original;
} while (!this.compareAndSet(original, real_replacement));
return original;
}
public inline function exchange(value:T):T {
return this.getAndSet(value);
}
public inline function load():T {
return this.get();
}
public inline function store(value:T):T {
this.set(value);
return value;
}
}

View File

@ -364,7 +364,7 @@ import java.NativeArray;
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(i);
@ -373,7 +373,7 @@ import java.NativeArray;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -378,7 +378,7 @@ import java.NativeArray;
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(Std.string(i));
@ -387,7 +387,7 @@ import java.NativeArray;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -377,7 +377,7 @@ import java.NativeArray;
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(i);
@ -386,7 +386,7 @@ import java.NativeArray;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -404,7 +404,7 @@ import java.lang.ref.ReferenceQueue;
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(Std.string(i));
@ -413,7 +413,7 @@ import java.lang.ref.ReferenceQueue;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -41,19 +41,41 @@ class FileSystem {
var f = new File(path);
if (!f.exists())
throw "Path " + path + " doesn't exist";
return {
gid: 0, // java doesn't let you get this info
uid: 0, // same
atime: Date.now(), // same
mtime: Date.fromTime(cast(f.lastModified(), Float)),
ctime: Date.fromTime(cast(f.lastModified(), Float)), // same
size: cast(f.length(), Int), // TODO: maybe change to Int64 for Haxe 3?
dev: 0, // FIXME: not sure what that is
ino: 0, // FIXME: not sure what that is
nlink: 0, // FIXME: not sure what that is
rdev: 0, // FIXME: not sure what that is
mode: 0 // FIXME: not sure what that is
};
try {
final pathObject = java.nio.file.Paths.get(path);
final attributes = java.nio.file.Files.readAttributes(pathObject, "unix:*");
return {
atime: Date.fromTime(cast(attributes.get("lastAccessTime").toMillis(), Float)),
ctime: Date.fromTime(cast(attributes.get("creationTime").toMillis(), Float)),
dev: cast(attributes.get("dev"), Int),
gid: attributes.get("gid"),
ino: cast(attributes.get("ino"), Int),
mode: attributes.get("mode"),
mtime: Date.fromTime(cast(attributes.get("lastModifiedTime").toMillis(), Float)),
nlink: attributes.get("nlink"),
rdev: cast(attributes.get("rdev"), Int),
size: cast(attributes.get("size"), Int),
uid: attributes.get("uid"),
};
}
catch (e) {
return {
gid: 0, // java doesn't let you get this info
uid: 0, // same
atime: Date.now(), // same
mtime: Date.fromTime(cast(f.lastModified(), Float)),
ctime: Date.fromTime(cast(f.lastModified(), Float)), // same
size: cast(f.length(), Int), // TODO: maybe change to Int64 for Haxe 3?
dev: 0, // FIXME: not sure what that is
ino: 0, // FIXME: not sure what that is
nlink: 0, // FIXME: not sure what that is
rdev: 0, // FIXME: not sure what that is
mode: 0 // FIXME: not sure what that is
};
}
}
public static function fullPath(relPath:String):String {

View File

@ -75,7 +75,7 @@ class Process {
}
}
return new java.lang.ProcessBuilder(pargs);
return new java.lang.ProcessBuilder(...pargs);
}
public function new(cmd:String, ?args:Array<String>, ?detached:Bool):Void {

View File

@ -0,0 +1,45 @@
package sys.thread;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition as NativeCondition;
@:access(sys.thread.Mutex)
@:coreApi
@:native('haxe.java.vm.Condition')
class Condition {
final lock:ReentrantLock;
final native:NativeCondition;
public function new():Void {
this.lock = new ReentrantLock();
this.native = lock.newCondition();
}
public function acquire():Void {
lock.lock();
}
public function tryAcquire():Bool {
return this.lock.tryLock();
}
public function release():Void {
lock.unlock();
}
// without the @:native, you get "java.lang.VerifyError: class sys.thread.Condition overrides final method java.lang.Object.wait()V" on jvm
// and "wait() in Condition cannot override wait() in Object" from javac
@:native("waitOn")
public function wait():Void {
native.await();
}
public function signal():Void {
native.signal();
}
public function broadcast():Void {
native.signalAll();
}
}

View File

@ -0,0 +1,25 @@
package sys.thread;
import java.util.concurrent.TimeUnit;
@:coreApi
@:native('haxe.java.vm.Semaphore')
class Semaphore {
final native:java.util.concurrent.Semaphore;
public function new(value:Int):Void {
this.native = new java.util.concurrent.Semaphore(value);
}
public function acquire():Void {
native.acquire();
}
public function tryAcquire(?timeout:Float):Bool {
return timeout == null ? native.tryAcquire() : native.tryAcquire(haxe.Int64.fromFloat(timeout * 1000000000),TimeUnit.NANOSECONDS);
}
public function release():Void {
native.release();
}
}

View File

@ -193,7 +193,7 @@ class DynamicObject extends HxObject {
if (ts != null)
return ts();
var ret = new StringBuf();
ret.add("{");
ret.add("[");
var first = true;
for (f in Reflect.fields(this)) {
if (first)
@ -207,7 +207,7 @@ class DynamicObject extends HxObject {
}
if (!first)
ret.add(" ");
ret.add("}");
ret.add("]");
return ret.toString();
}
}