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

@ -130,57 +130,74 @@ import python.Syntax;
}
}
static inline function isSpaceChar(char:String):Bool
return Syntax.isIn(char, " \n\r\t\x0b\x0c");
static inline function isHexPrefix(cur:String, next:String):Bool
return cur == '0' && (next == 'x' || next == 'X');
static inline function isDecimalDigit(char:String):Bool
return Syntax.isIn(char, "0123456789");
static inline function isHexadecimalDigit(char:String):Bool
return Syntax.isIn(char, "0123456789abcdefABCDEF");
public static function parseInt(x:String):Null<Int> {
if (x == null)
return null;
try {
return UBuiltins.int(x);
} catch (e:Dynamic) {
var base = 10;
var len = x.length;
var foundCount = 0;
var sign = 0;
var firstDigitIndex = 0;
var lastDigitIndex = -1;
var previous = 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;
}
if(firstDigitIndex <= lastDigitIndex) {
var digits = x.substring(firstDigitIndex, lastDigitIndex + 1);
return try {
(sign == -1 ? -1 : 1) * UBuiltins.int(digits, base);
} catch(e:Dynamic) {
null;
}
}
return null;
final len = x.length;
var index = 0;
inline function hasIndex(index:Int)
return index < len;
// skip whitespace
while (hasIndex(index)) {
if (!isSpaceChar(Syntax.arrayAccess(x, index)))
break;
++index;
}
// handle sign
final isNegative = hasIndex(index) && {
final sign = Syntax.arrayAccess(x, index);
if (sign == '-' || sign == '+') {
++index;
}
sign == '-';
}
// handle base
final isHexadecimal = hasIndex(index + 1) && isHexPrefix(Syntax.arrayAccess(x, index), Syntax.arrayAccess(x, index + 1));
if (isHexadecimal)
index += 2; // skip prefix
// handle digits
final firstInvalidIndex = {
var cur = index;
if (isHexadecimal) {
while (hasIndex(cur)) {
if (!isHexadecimalDigit(Syntax.arrayAccess(x, cur)))
break;
++cur;
}
} else {
while (hasIndex(cur)) {
if (!isDecimalDigit(Syntax.arrayAccess(x, cur)))
break;
++cur;
}
}
cur;
}
// no valid digits
if (index == firstInvalidIndex)
return null;
final result = python.internal.UBuiltins.int(x.substring(index, firstInvalidIndex), if (isHexadecimal) 16 else 10);
return if (isNegative) -result else result;
}
static function shortenPossibleNumber(x:String):String {

View File

@ -28,20 +28,6 @@ import haxe.ds.StringMap;
@:coreApi
class Sys {
static var environ(get,default):StringMap<String>;
static function get_environ():StringMap<String> {
return switch environ {
case null:
var environ = new StringMap();
var env = Os.environ;
for (key in env.keys()) {
environ.set(key, env.get(key, null));
}
Sys.environ = environ;
case env: env;
}
}
public static inline function time():Float {
return Time.time();
}
@ -64,15 +50,27 @@ class Sys {
}
public static function getEnv(s:String):String {
return environ.get(s);
return Os.environ.get(s, null);
}
public static function putEnv(s:String, v:String):Void {
python.lib.Os.putenv(s, v);
environ.set(s, v);
public static function putEnv(s:String, v:Null<String>):Void {
if (v == null) {
try {
Os.environ.remove(s);
} catch(e:python.Exceptions.KeyError) {
// the variable didn't exist
}
return;
}
Os.environ.set(s, v);
}
public static function environment():Map<String, String> {
final environ = new StringMap();
final env = Os.environ;
for (key in env.keys()) {
environ.set(key, env.get(key, null));
}
return environ;
}
@ -85,7 +83,7 @@ class Sys {
}
public static function getCwd():String {
return python.lib.Os.getcwd();
return haxe.io.Path.addTrailingSlash(python.lib.Os.getcwd());
}
public static function setCwd(s:String):Void {

View File

@ -72,7 +72,7 @@ class IntMap<T> implements haxe.Constraints.IMap<Int, T> {
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(i);
@ -81,7 +81,7 @@ class IntMap<T> implements haxe.Constraints.IMap<Int, T> {
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -71,7 +71,7 @@ class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(Std.string(i));
@ -80,7 +80,7 @@ class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -73,7 +73,7 @@ class StringMap<T> implements haxe.Constraints.IMap<String, T> {
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(i);
@ -82,7 +82,7 @@ class StringMap<T> implements haxe.Constraints.IMap<String, T> {
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -126,6 +126,11 @@ private class SocketOutput extends haxe.io.Output {
__s = new PSocket();
}
function __rebuildIoStreams():Void {
input = new SocketInput(__s);
output = new SocketOutput(__s);
}
public function close():Void {
__s.close();
}

View File

@ -0,0 +1,34 @@
package sys.thread;
@:coreApi
class Condition {
final cond:python.lib.threading.Condition;
public function new():Void {
this.cond = new python.lib.threading.Condition();
}
public function acquire():Void {
cond.acquire();
}
public function tryAcquire():Bool {
return cond.acquire(false);
}
public function release():Void {
cond.release();
}
public function wait():Void {
cond.wait();
}
public function signal():Void {
cond.notify();
}
public function broadcast():Void {
cond.notify_all();
}
}

View File

@ -22,15 +22,17 @@
package sys.thread;
import python.lib.threading.Condition;
using python.internal.UBuiltins;
class Deque<T> {
var deque:NativeDeque<T>;
var lock:NativeCondition;
var lock:Condition;
public function new() {
deque = new NativeDeque<T>();
lock = new NativeCondition();
lock = new Condition();
}
public function add(i:T) {
@ -63,21 +65,9 @@ class Deque<T> {
@:pythonImport("collections", "deque")
@:native("deque")
extern class NativeDeque<T> {
private extern class NativeDeque<T> {
function new();
function append(x:T):Void;
function appendleft(x:T):Void;
function popleft():T;
}
@:pythonImport("threading", "Condition")
@:native("Condition")
private extern class NativeCondition {
function new(?lock:Dynamic);
function acquire(blocking:Bool = true, timeout:Float = -1):Bool;
function release():Void;
function wait(?timeout:Float):Bool;
function wait_for(predicate:()->Bool, ?timeout:Float):Bool;
function notify(n:Int = 1):Void;
function notify_all():Void;
}

View File

@ -22,12 +22,14 @@
package sys.thread;
import python.lib.threading.Semaphore;
@:coreApi
class Lock {
final semaphore:NativeSemaphore;
final semaphore:Semaphore;
public inline function new() {
semaphore = new NativeSemaphore(0);
semaphore = new Semaphore(0);
}
public inline function wait(?timeout:Float):Bool {
@ -38,11 +40,3 @@ class Lock {
semaphore.release();
}
}
@:pythonImport("threading", "Semaphore")
@:native("Lock")
private extern class NativeSemaphore {
function new(value:Int);
function acquire(blocking:Bool = true, ?timeout:Float):Bool;
function release():Void;
}

View File

@ -22,12 +22,14 @@
package sys.thread;
import python.lib.threading.RLock;
@:coreApi
class Mutex {
final lock:NativeRLock;
final lock:RLock;
inline public function new():Void {
lock = new NativeRLock();
lock = new RLock();
}
inline public function acquire():Void {
@ -42,10 +44,3 @@ class Mutex {
lock.release();
}
}
@:pythonImport("threading", "RLock")
private extern class NativeRLock {
function new():Void;
function acquire(blocking:Bool):Bool;
function release():Void;
}

View File

@ -0,0 +1,24 @@
package sys.thread;
import python.lib.threading.Semaphore as NativeSemaphore;
@:coreApi
class Semaphore {
final semaphore:NativeSemaphore;
public function new(value:Int):Void {
this.semaphore = new NativeSemaphore(value);
}
public function acquire():Void {
semaphore.acquire();
}
public function tryAcquire(?timeout:Float):Bool {
return timeout == null ? semaphore.acquire(false) : semaphore.acquire(true, timeout);
}
public function release():Void {
semaphore.release();
}
}

View File

@ -22,6 +22,9 @@
package sys.thread;
import python.lib.threading.Thread as NativeThread;
import python.lib.Threading;
import haxe.ds.ObjectMap;
private typedef ThreadImpl = HxThread;
@ -33,8 +36,8 @@ abstract Thread(ThreadImpl) from ThreadImpl {
return HxThread.current();
}
public static inline function create(callb:Void->Void):Thread {
return HxThread.create(callb, false);
public static inline function create(job:Void->Void):Thread {
return HxThread.create(job, false);
}
public static inline function runWithEventLoop(job:()->Void):Void {
@ -78,7 +81,7 @@ private class HxThread {
static function __init__() {
threads = new ObjectMap();
threadsMutex = new Mutex();
mainThread = new HxThread(PyThreadingAPI.current_thread());
mainThread = new HxThread(Threading.current_thread());
mainThread.events = new EventLoop();
}
@ -92,8 +95,8 @@ private class HxThread {
public static function current():HxThread {
threadsMutex.acquire();
var ct = PyThreadingAPI.current_thread();
if (ct == PyThreadingAPI.main_thread()) {
var ct = Threading.current_thread();
if (ct == Threading.main_thread()) {
threadsMutex.release();
return mainThread;
}
@ -121,7 +124,7 @@ private class HxThread {
}
dropThread(nt);
}
nt = new NativeThread(null, wrappedCallB);
nt = new NativeThread({target:wrappedCallB});
t = new HxThread(nt);
if(withEventLoop)
t.events = new EventLoop();
@ -159,17 +162,3 @@ private class HxThread {
return current().messages.pop(block);
}
}
@:pythonImport("threading", "Thread")
@:native("Thread")
private extern class NativeThread {
function new(group:Dynamic, target:Void->Void);
function start():Void;
}
@:pythonImport("threading")
@:native("threading")
private extern class PyThreadingAPI {
static function current_thread():NativeThread;
static function main_thread():NativeThread;
}

View File

@ -57,6 +57,12 @@ extern class Os {
static function putenv(name:String, value:String):Void;
/** Removes the value for the environment variable `name`.
When targeting python versions prior to 3.9, this function may not exist on some platforms.
**/
static function unsetenv(name:String):Void;
static function chdir(path:String):Void;
static function unlink(path:String):Void;

View File

@ -30,6 +30,14 @@ extern class StartupInfo {
var wShowWindow:Int;
}
extern class CompletedProcess {
var args:EitherType<String, Array<String>>;
var returncode:Int;
var stdout:Null<EitherType<Bytes,String>>;
var stderr:Null<EitherType<Bytes,String>>;
function check_returncode():Void;
}
@:pythonImport("subprocess")
extern class Subprocess {
static function STARTUPINFO():StartupInfo;
@ -49,4 +57,5 @@ extern class Subprocess {
static var STDOUT:Int;
static function call(args:EitherType<String, Array<String>>, ?kwArgs:python.KwArgs<Dynamic>):Int;
static function run(args:EitherType<String, Array<String>>, ?kwArgs:python.KwArgs<Dynamic>):CompletedProcess;
}

View File

@ -80,6 +80,11 @@ extern class Socket {
**/
function getsockname():python.lib.socket.Address;
/**
Return the timeout for the socket or null if no timeout has been set.
**/
function gettimeout():Null<Float>;
/**
Gives a timeout after which blocking socket operations (such as reading and writing) will abort and throw an exception.
**/
@ -90,14 +95,26 @@ extern class Socket {
**/
function waitForRead():Void;
/**
Return the current blocking mode of the socket.
**/
@:require(python_version >= 3.7)
function getblocking():Bool;
/**
Change the blocking mode of the socket. A blocking socket is the default behavior. A non-blocking socket will abort blocking operations immediately by throwing a haxe.io.Error.Blocked value.
**/
function setblocking(b:Bool):Void;
/**
Return the current value of the sockopt as an Int or a Bytes buffer (if buflen is specified).
**/
function getsockopt(family:Int, option:Int):Int;
/**
Change the value of the given socket option.
**/
@:overload(function(family:Int, option:Int, value:Int):Void {})
function setsockopt(family:Int, option:Int, value:Bool):Void;
function fileno():Int;

View File

@ -0,0 +1,12 @@
package python.lib.threading;
@:pythonImport("threading", "Condition")
extern class Condition {
function new(?lock:haxe.extern.EitherType<Lock, RLock>):Void;
function acquire(?blocking:Bool, ?timeout:Float):Bool;
function release():Void;
function wait(?timeout:Float):Bool;
function wait_for(predicate:()->Bool, ?timeout:Float):Bool;
function notify(n:Int = 1):Void;
function notify_all():Void;
}

View File

@ -0,0 +1,9 @@
package python.lib.threading;
@:noDoc
@:pythonImport("threading", "Semaphore")
extern class Semaphore {
function new(value:Int);
function acquire(blocking:Bool = true, ?timeout:Float):Bool;
function release(n:Int = 1):Void;
}

View File

@ -25,12 +25,15 @@ package python.net;
import python.lib.Ssl;
import python.lib.ssl.Purpose;
import python.lib.socket.Socket as PSocket;
import python.lib.Socket in PSocketModule;
import sys.net.Host;
class SslSocket extends sys.net.Socket {
var hostName:String;
var _timeout:Null<Float> = null;
var _blocking:Null<Bool> = null;
var _fastSend:Null<Bool> = null;
override function __initSocket():Void {
function wrapSocketWithSslContext(hostName:String):Void {
#if (python_version >= 3.4)
var context = Ssl.create_default_context(Purpose.SERVER_AUTH);
#else
@ -43,16 +46,42 @@ class SslSocket extends sys.net.Socket {
context.options |= Ssl.OP_NO_COMPRESSION;
#end
context.options |= Ssl.OP_NO_TLSv1 #if (python_version >= 3.4) | Ssl.OP_NO_TLSv1_1 #end; // python 3.4 | Ssl.OP_NO_TLSv1_1;
__s = new PSocket();
__s = context.wrap_socket(__s, false, true, true, this.hostName);
__s = context.wrap_socket(__s, false, true, true, hostName);
if (_timeout != null) {
super.setTimeout(_timeout);
}
if (_blocking != null) {
super.setBlocking(_blocking);
}
if (_fastSend != null) {
super.setFastSend(_fastSend);
}
__rebuildIoStreams();
}
public override function connect(host:Host, port:Int):Void {
this.hostName = host.host;
wrapSocketWithSslContext(host.host);
super.connect(host, port);
}
public override function bind(host:Host, port:Int):Void {
throw new haxe.exceptions.NotImplementedException();
}
public override function setTimeout(timeout:Float):Void {
_timeout = timeout;
super.setTimeout(_timeout);
}
public override function setBlocking(b:Bool):Void {
_blocking = b;
super.setBlocking(_blocking);
}
public override function setFastSend(b:Bool):Void {
_fastSend = b;
super.setFastSend(_fastSend);
}
}