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

@ -32,13 +32,10 @@
to another type.
**/
@:forward.variance
abstract Any(Dynamic) {
abstract Any(Dynamic) from Dynamic {
@:noCompletion @:to extern inline function __promote<T>():T
return this;
@:noCompletion @:from extern inline static function __cast<T>(value:T):Any
return cast value;
@:noCompletion extern inline function toString():String
return Std.string(this);
}

View File

@ -276,10 +276,10 @@ extern class Math {
static function isFinite(f:Float):Bool;
/**
Tells if `f` is not a valid number.
Tells if `f` is `Math.NaN`.
If `f` is `NaN`, the result is `true`, otherwise the result is `false`.
In particular, both `POSITIVE_INFINITY` and `NEGATIVE_INFINITY` are
In particular, `null`, `POSITIVE_INFINITY` and `NEGATIVE_INFINITY` are
not considered `NaN`.
**/
static function isNaN(f:Float):Bool;

View File

@ -97,21 +97,22 @@ extern class Std {
Leading whitespaces are ignored.
If `x` starts with 0x or 0X, hexadecimal notation is recognized where the following digits may
contain 0-9 and A-F.
`x` may optionally start with a + or - to denote a postive or negative value respectively.
Otherwise `x` is read as decimal number with 0-9 being allowed characters. `x` may also start with
a - to denote a negative value.
If the optional sign is followed 0x or 0X, hexadecimal notation is recognized where the following
digits may contain 0-9 and A-F. Both the prefix and digits are case insensitive.
In decimal mode, parsing continues until an invalid character is detected, in which case the
result up to that point is returned. For hexadecimal notation, the effect of invalid characters
is unspecified.
Otherwise `x` is read as decimal number with 0-9 being allowed characters. Octal and binary
notations are not supported.
Leading 0s that are not part of the 0x/0X hexadecimal notation are ignored, which means octal
notation is not supported.
Parsing continues until an invalid character is detected, in which case the result up to
that point is returned. Scientific notation is not supported. That is `Std.parseInt('10e2')` produces `10`.
If `x` is null, the result is unspecified.
If `x` cannot be parsed as integer, the result is `null`.
If `x` is `null`, the result is `null`.
If `x` cannot be parsed as integer or is empty, the result is `null`.
If `x` starts with a hexadecimal prefix which is not followed by at least one valid hexadecimal
digit, the result is unspecified.
**/
static function parseInt(x:String):Null<Int>;
@ -119,9 +120,12 @@ extern class Std {
Converts a `String` to a `Float`.
The parsing rules for `parseInt` apply here as well, with the exception of invalid input
resulting in a `NaN` value instead of null.
resulting in a `NaN` value instead of `null`. Also, hexadecimal support is **not** specified.
Additionally, decimal notation may contain a single `.` to denote the start of the fractions.
It may also end with `e` or `E` followed by optional minus or plus sign and a sequence of
digits (defines exponent to base 10).
**/
static function parseFloat(x:String):Float;

View File

@ -211,7 +211,7 @@ class StringTools {
public static inline function contains(s:String, value:String):Bool {
#if (js && js_es >= 6)
return (cast s).includes(value);
#else
#else
return s.indexOf(value) != -1;
#end
}
@ -234,6 +234,8 @@ class StringTools {
return python.NativeStringTools.startswith(s, start);
#elseif (js && js_es >= 6)
return (cast s).startsWith(start);
#elseif lua
return untyped __lua__("{0}:sub(1, #{1}) == {1}", s, start);
#else
return (s.length >= start.length && s.lastIndexOf(start, 0) == 0);
#end
@ -259,6 +261,8 @@ class StringTools {
return python.NativeStringTools.endswith(s, end);
#elseif (js && js_es >= 6)
return (cast s).endsWith(end);
#elseif lua
return end == "" || untyped __lua__("{0}:sub(-#{1}) == {1}", s, end);
#else
var elen = end.length;
var slen = s.length;

View File

@ -57,12 +57,24 @@ extern class Sys {
/**
Sets the value of the given environment variable.
If `v` is `null`, the environment variable is removed.
(java) This functionality is not available on Java; calling this function will throw.
**/
static function putEnv(s:String, v:String):Void;
static function putEnv(s:String, v:Null<String>):Void;
/**
Returns all environment variables.
Returns a map of the current environment variables and their values
as of the invocation of the function.
(python) On Windows, the variable names are always in upper case.
(cpp)(hl)(neko) On Windows, the variable names match the last capitalization used when modifying
the variable if the variable has been modified, otherwise they match their capitalization at
the start of the process.
On Windows on remaining targets, variable name capitalization matches however they were capitalized
at the start of the process or at the moment of their creation.
**/
static function environment():Map<String, String>;

View File

@ -26,9 +26,14 @@ import haxe.iterators.StringIteratorUnicode;
import haxe.iterators.StringKeyValueIteratorUnicode;
/**
This abstract provides consistent cross-target unicode support.
This abstract provides consistent cross-target unicode support for characters of any width.
@see https://haxe.org/manual/std-UnicodeString.html
Due to differing internal representations of strings across targets, only the basic
multilingual plane (BMP) is supported consistently by `String` class.
This abstract provides API to consistently handle all characters even beyond BMP.
@see https://haxe.org/manual/std-String-unicode.html
**/
@:forward
@:access(StringTools)

View File

@ -22,7 +22,21 @@
package cpp;
@:coreType @:notNull @:runtimeValue abstract Int64 from Int to Int {
@:coreType @:notNull @:runtimeValue abstract Int64 from Int {
/**
Destructively cast to Int
**/
public inline function toInt():Int {
return cast this;
}
@:to
@:deprecated("Implicit cast from Int64 to Int (32 bits) is deprecated. Use .toInt() or explicitly cast instead.")
inline function implicitToInt(): Int {
return toInt();
}
@:to
#if !cppia inline #end function toInt64():haxe.Int64 {
return cast this;

View File

@ -0,0 +1,154 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package cpp;
import haxe.Int64;
@:headerClassCode("
inline void set(cpp::Int64 key, ::null value) { __int64_hash_set(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, bool value) { __int64_hash_set(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, char value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, unsigned char value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, signed char value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, short value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, unsigned short value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, int value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, unsigned int value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, float value) { __int64_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, double value) { __int64_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, ::String value) { __int64_hash_set_string(HX_MAP_THIS,key,value); }
inline void set(cpp::Int64 key, cpp::Int64 value) { __int64_hash_set_int64(HX_MAP_THIS,key,value); }
template<typename V, typename H>
inline void set(cpp::Int64 key, const ::cpp::Struct<V,H> &value) {__int64_hash_set(HX_MAP_THIS,key,value); }
template<typename F>
inline void set(cpp::Int64 key, const ::cpp::Function<F> &value) {__int64_hash_set(HX_MAP_THIS,key,value); }
template<typename V>
inline void set(cpp::Int64 key, const ::cpp::Pointer<V> &value) {__int64_hash_set(HX_MAP_THIS,key,(Dynamic)value ); }
template<typename VALUE>
inline void set(Dynamic &key, const VALUE &value) { set( (cpp::Int64)key, value ); }
inline bool get_bool(cpp::Int64 key) { return __int64_hash_get_bool(h,key); }
inline int get_int(cpp::Int64 key) { return __int64_hash_get_int(h,key); }
inline Float get_float(cpp::Int64 key) { return __int64_hash_get_float(h,key); }
inline String get_string(cpp::Int64 key) { return __int64_hash_get_string(h,key); }
inline cpp::Int64 get_int64(cpp::Int64 key) { return __int64_hash_get_int64(h,key); }
")
@:coreApi class Int64Map<T> implements haxe.Constraints.IMap<Int64, T> {
@:ifFeature("cpp.Int64Map.*")
private var h:Dynamic;
public function new():Void {}
public function set(key:Int64, value:T):Void {
untyped __global__.__int64_hash_set(__cpp__("HX_MAP_THIS"), key, value);
}
public function get(key:Int64):Null<T> {
return untyped __global__.__int64_hash_get(h, key);
}
public function exists(key:Int64):Bool {
return untyped __global__.__int64_hash_exists(h, key);
}
public function remove(key:Int64):Bool {
return untyped __global__.__int64_hash_remove(h, key);
}
public function keys():Iterator<Int64> {
var a:Array<Int64> = untyped __global__.__int64_hash_keys(h);
return a.iterator();
}
public function iterator():Iterator<T> {
var a:Array<Dynamic> = untyped __global__.__int64_hash_values(h);
return a.iterator();
}
@:runtime public inline function keyValueIterator():KeyValueIterator<Int64, T> {
return new haxe.iterators.MapKeyValueIterator(this);
}
public function copy():Int64Map<T> {
var copied = new Int64Map();
for (key in keys())
copied.set(key, get(key));
return copied;
}
public function toString():String {
return untyped __global__.__int64_hash_to_string(h);
}
public function clear():Void {
#if (hxcpp_api_level >= 400)
return untyped __global__.__int64_hash_clear(h);
#else
h = null;
#end
}
#if (scriptable)
private function setString(key:Int64, val:String):Void {
untyped __int64_hash_set_string(__cpp__("HX_MAP_THIS"), key, val);
}
private function setInt(key:Int64, val:Int):Void {
untyped __int64_hash_set_int(__cpp__("HX_MAP_THIS"), key, val);
}
private function setBool(key:Int64, val:Bool):Void {
untyped __int64_hash_set_int(__cpp__("HX_MAP_THIS"), key, val);
}
private function setFloat(key:Int64, val:Float):Void {
untyped __int64_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
}
private function setInt64(key:Int64, val:Int64):Void {
untyped __int64_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
}
private function getString(key:Int64):String {
return untyped __int64_hash_get_string(h, key);
}
private function getInt(key:Int64):Int {
return untyped __int64_hash_get_int(h, key);
}
private function getBool(key:Int64):Bool {
return untyped __int64_hash_get_bool(h, key);
}
private function getFloat(key:Int64):Float {
return untyped __int64_hash_get_float(h, key);
}
private function getInt64(key:Int64):Int64 {
return untyped __int64_hash_get_int64(h, key);
}
#end
}

View File

@ -79,7 +79,7 @@ class Lib {
}
@:noDebug @:native("HX_STACK_DO_RETHROW")
extern static function do_rethrow(inExp:Dynamic);
extern static function do_rethrow(inExp:Dynamic):Void;
@:noDebug #if (!cppia) inline #end
public static function rethrow(inExp:Dynamic) {

View File

@ -43,7 +43,7 @@ extern class NativeProcess {
static function process_stdin_close(handle:Dynamic):Void;
@:native("_hx_std_process_exit")
static function process_exit(handle:Dynamic):Int;
static function process_exit(handle:Dynamic, block:Bool):Dynamic;
@:native("_hx_std_process_pid")
static function process_pid(handle:Dynamic):Int;

View File

@ -34,7 +34,7 @@ extern class NativeSys {
extern static function get_env(v:String):String;
@:native("_hx_std_put_env")
extern static function put_env(e:String, v:String):Void;
extern static function put_env(e:String, v:Null<String>):Void;
@:native("_hx_std_sys_sleep")
extern static function sys_sleep(f:Float):Void;

View File

@ -221,7 +221,7 @@ class Xml {
function new():Void {}
@:native("parse_xml")
extern static function parse_xml(str:String, state:NativeXmlState);
extern static function parse_xml(str:String, state:NativeXmlState):String;
public static function parse(str:String):Xml {
var x = new Xml();

View File

@ -22,4 +22,19 @@
package cpp;
@:coreType @:notNull @:runtimeValue abstract UInt64 from Int to Int {}
@:coreType @:notNull @:runtimeValue abstract UInt64 from Int {
/**
Destructively cast to Int
**/
public inline function toInt():Int {
return cast this;
}
@:to
@:deprecated("Implicit cast from UInt64 to Int (32 bits) is deprecated. Use .toInt() or explicitly cast instead.")
inline function implicitToInt(): Int {
return toInt();
}
}

View File

@ -63,7 +63,7 @@ import haxe.SysTools;
return v;
}
public static function putEnv(s:String, v:String):Void {
public static function putEnv(s:String, v:Null<String>):Void {
NativeSys.put_env(s, v);
}

View File

@ -19,7 +19,10 @@ class Exception {
if(Std.isOfType(value, Exception)) {
return value;
} else {
return new ValueException(value, null, value);
var e = new ValueException(value, null, value);
// Undo automatic __shiftStack()
e.__unshiftStack();
return e;
}
}
@ -63,6 +66,12 @@ class Exception {
__skipStack++;
}
@:noCompletion
@:ifFeature("haxe.Exception.get_stack")
inline function __unshiftStack():Void {
__skipStack--;
}
function get_message():String {
return __exceptionMessage;
}

View File

@ -22,13 +22,8 @@
package haxe;
import haxe.Int64Helper;
@:notNull
@:include("cpp/Int64.h")
@:native("cpp::Int64Struct")
private extern class ___Int64 {
private extern class NativeInt64Helper {
@:native("_hx_int64_make")
static function make(high:Int32, low:Int32):__Int64;
@ -132,21 +127,21 @@ private extern class ___Int64 {
static function low(a:__Int64):Int32;
}
private typedef __Int64 = ___Int64;
private typedef __Int64 = cpp.Int64;
@:coreApi
@:transitive
abstract Int64(__Int64) from __Int64 to __Int64 {
@:notNull
abstract Int64(__Int64) from __Int64 from Int to __Int64 {
public #if !cppia inline #end function copy():Int64
return this;
public static #if !cppia inline #end function make(high:Int32, low:Int32):Int64 {
return __Int64.make(high, low);
return NativeInt64Helper.make(high, low);
}
@:from
public static #if !cppia inline #end function ofInt(x:Int):Int64 {
return __Int64.ofInt(x);
return x;
}
public static #if !cppia inline #end function toInt(x:Int64):Int {
@ -158,11 +153,11 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
@:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead')
inline public static function is(val:Dynamic):Bool {
return isInt64(val);
return val is cpp.Int64;
}
public static #if !cppia inline #end function isInt64(val:Dynamic):Bool
return __Int64.isInt64(val);
return val is cpp.Int64;
@:deprecated("Use high instead")
public static #if !cppia inline #end function getHigh(x:Int64):Int32
@ -173,22 +168,22 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
return x.low;
public static #if !cppia inline #end function isNeg(x:Int64):Bool
return __Int64.isNeg(x);
return NativeInt64Helper.isNeg(x);
public static #if !cppia inline #end function isZero(x:Int64):Bool
return __Int64.isZero(x);
return NativeInt64Helper.isZero(x);
public static #if !cppia inline #end function compare(a:Int64, b:Int64):Int
return __Int64.compare(a, b);
return NativeInt64Helper.compare(a, b);
public static #if !cppia inline #end function ucompare(a:Int64, b:Int64):Int
return __Int64.ucompare(a, b);
return NativeInt64Helper.ucompare(a, b);
public static #if !cppia inline #end function toStr(x:Int64):String
return x.toString();
return cast x.val;
private #if !cppia inline #end function toString():String
return __Int64.toString(this);
return cast this;
public static function parseString(sParam:String):Int64 {
return Int64Helper.parseString(sParam);
@ -201,7 +196,7 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
public static function divMod(dividend:Int64, divisor:Int64):{quotient:Int64, modulus:Int64} {
var q = dividend / divisor;
if (isZero(divisor))
if (divisor == 0)
throw "divide by zero";
var m = dividend - q * divisor;
@ -209,16 +204,16 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
return {quotient: q, modulus: m};
}
@:op(-A)
@:op(-A)
public static #if !cppia inline #end function neg(x:Int64):Int64
return __Int64.neg(x);
return NativeInt64Helper.neg(x);
@:op(++A) private inline function preIncrement():Int64 {
#if cppia
this = this + make(0, 1);
return this;
#else
return __Int64.preIncrement(this);
return NativeInt64Helper.preIncrement(this);
#end
}
@ -228,7 +223,7 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
this = this + make(0, 1);
return result;
#else
return __Int64.postIncrement(this);
return NativeInt64Helper.postIncrement(this);
#end
}
@ -237,7 +232,7 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
untyped this = this - make(0, 1);
return this;
#else
return __Int64.preDecrement(this);
return NativeInt64Helper.preDecrement(this);
#end
}
@ -247,35 +242,35 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
this = this - make(0, 1);
return result;
#else
return __Int64.postDecrement(this);
return NativeInt64Helper.postDecrement(this);
#end
}
@:op(A + B)
public static #if !cppia inline #end function add(a:Int64, b:Int64):Int64
return __Int64.add(a, b);
return NativeInt64Helper.add(a, b);
@:op(A + B)
@:commutative
private static #if !cppia inline #end function addInt(a:Int64, b:Int):Int64
return __Int64.addInt(a, b);
return NativeInt64Helper.addInt(a, b);
@:op(A - B)
public static #if !cppia inline #end function sub(a:Int64, b:Int64):Int64 {
return __Int64.sub(a, b);
return NativeInt64Helper.sub(a, b);
}
@:op(A - B)
private static #if !cppia inline #end function subInt(a:Int64, b:Int):Int64
return __Int64.subInt(a, b);
return NativeInt64Helper.subInt(a, b);
@:op(A - B)
private static #if !cppia inline #end function intSub(a:Int, b:Int64):Int64
return __Int64.intSub(a, b);
return NativeInt64Helper.intSub(a, b);
@:op(A * B)
public static #if !cppia inline #end function mul(a:Int64, b:Int64):Int64
return __Int64.mul(a, b);
return NativeInt64Helper.mul(a, b);
@:op(A * B)
@:commutative
@ -284,9 +279,9 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
@:op(A / B)
public static #if !cppia inline #end function div(a:Int64, b:Int64):Int64 {
if (__Int64.isZero(b))
if (NativeInt64Helper.isZero(b))
throw "divide by zero";
return __Int64.div(a, b);
return NativeInt64Helper.div(a, b);
}
@:op(A / B)
@ -299,9 +294,9 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
@:op(A % B)
public static #if !cppia inline #end function mod(a:Int64, b:Int64):Int64 {
if (__Int64.isZero(b))
if (NativeInt64Helper.isZero(b))
throw "divide by zero";
return __Int64.mod(a, b);
return NativeInt64Helper.mod(a, b);
}
@:op(A % B)
@ -314,16 +309,16 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
@:op(A == B)
public static #if !cppia inline #end function eq(a:Int64, b:Int64):Bool
return __Int64.eq(a, b);
return NativeInt64Helper.eq(a, b);
@:op(A == B)
@:commutative
private static #if !cppia inline #end function eqInt(a:Int64, b:Int):Bool
return __Int64.eqInt(a, b);
return NativeInt64Helper.eqInt(a, b);
@:op(A != B)
public static #if !cppia inline #end function neq(a:Int64, b:Int64):Bool
return __Int64.neq(a, b);
return NativeInt64Helper.neq(a, b);
@:op(A != B)
@:commutative
@ -380,39 +375,44 @@ abstract Int64(__Int64) from __Int64 to __Int64 {
@:op(~A)
private static #if !cppia inline #end function complement(a:Int64):Int64
return __Int64.complement(a);
return NativeInt64Helper.complement(a);
@:op(A & B)
public static #if !cppia inline #end function and(a:Int64, b:Int64):Int64
return __Int64.bitAnd(a, b);
return NativeInt64Helper.bitAnd(a, b);
@:op(A | B)
public static #if !cppia inline #end function or(a:Int64, b:Int64):Int64
return __Int64.bitOr(a, b);
return NativeInt64Helper.bitOr(a, b);
@:op(A ^ B)
public static #if !cppia inline #end function xor(a:Int64, b:Int64):Int64
return __Int64.bitXor(a, b);
return NativeInt64Helper.bitXor(a, b);
@:op(A << B)
public static #if !cppia inline #end function shl(a:Int64, b:Int):Int64
return __Int64.shl(a, b);
return NativeInt64Helper.shl(a, b);
@:op(A >> B)
public static #if !cppia inline #end function shr(a:Int64, b:Int):Int64
return __Int64.shr(a, b);
return NativeInt64Helper.shr(a, b);
@:op(A >>> B)
public static #if !cppia inline #end function ushr(a:Int64, b:Int):Int64
return __Int64.ushr(a, b);
return NativeInt64Helper.ushr(a, b);
public var high(get, never):Int32;
private #if !cppia inline #end function get_high():Int32
return __Int64.high(this);
return NativeInt64Helper.high(this);
public var low(get, never):Int32;
private #if !cppia inline #end function get_low():Int32
return __Int64.low(this);
return NativeInt64Helper.low(this);
private var val(get, never):__Int64;
private #if !cppia inline #end function get_val():__Int64
return this;
}

View File

@ -0,0 +1,68 @@
package haxe.atomic;
#if cppia
extern
#end
abstract AtomicInt(cpp.Pointer<Int>) {
#if cppia
public function new(value:Int):Void;
public function add(b:Int):Int;
public function sub(b:Int):Int;
public function and(b:Int):Int;
public function or(b:Int):Int;
public function xor(b:Int):Int;
public function compareExchange(expected:Int, replacement:Int):Int;
public function exchange(value:Int):Int;
public function load():Int;
public function store(value:Int):Int;
#else
public #if !scriptable inline #end function new(value:Int) {
this = cpp.Pointer.ofArray([value]);
}
public #if !scriptable inline #end function add(b:Int):Int {
return untyped __cpp__("_hx_atomic_add({0}, {1})", this, b);
}
public #if !scriptable inline #end function sub(b:Int):Int {
return untyped __cpp__("_hx_atomic_sub({0}, {1})", this, b);
}
public #if !scriptable inline #end function and(b:Int):Int {
return untyped __cpp__("_hx_atomic_and({0}, {1})", this, b);
}
public #if !scriptable inline #end function or(b:Int):Int {
return untyped __cpp__("_hx_atomic_or({0}, {1})", this, b);
}
public #if !scriptable inline #end function xor(b:Int):Int {
return untyped __cpp__("_hx_atomic_xor({0}, {1})", this, b);
}
public #if !scriptable inline #end function compareExchange(expected:Int, replacement:Int):Int {
return untyped __cpp__("_hx_atomic_compare_exchange({0}, {1}, {2})", this, expected, replacement);
}
public #if !scriptable inline #end function exchange(value:Int):Int {
return untyped __cpp__("_hx_atomic_exchange({0}, {1})", this, value);
}
public #if !scriptable inline #end function load():Int {
return untyped __cpp__("_hx_atomic_load({0})", this);
}
public #if !scriptable inline #end function store(value:Int):Int {
return untyped __cpp__("_hx_atomic_store({0}, {1})", this, value);
}
#end
}

View File

@ -35,6 +35,7 @@ package haxe.ds;
inline void set(int key, float value) { __int_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(int key, double value) { __int_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(int key, ::String value) { __int_hash_set_string(HX_MAP_THIS,key,value); }
inline void set(int key, cpp::Int64 value) { __int_hash_set_int64(HX_MAP_THIS,key,value); }
template<typename V, typename H>
inline void set(int key, const ::cpp::Struct<V,H> &value) {__int_hash_set(HX_MAP_THIS,key,value); }
@ -50,6 +51,7 @@ package haxe.ds;
inline int get_int(int key) { return __int_hash_get_int(h,key); }
inline Float get_float(int key) { return __int_hash_get_float(h,key); }
inline String get_string(int key) { return __int_hash_get_string(h,key); }
inline cpp::Int64 get_int64(int key) { return __int_hash_get_int64(h,key); }
")
@:coreApi class IntMap<T> implements haxe.Constraints.IMap<Int, T> {
@:ifFeature("haxe.ds.IntMap.*")
@ -123,6 +125,10 @@ package haxe.ds;
untyped __int_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
}
private function setInt64(key:Int, val:haxe.Int64):Void {
untyped __int_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
}
private function getString(key:Int):String {
return untyped __int_hash_get_string(h, key);
}
@ -138,5 +144,9 @@ package haxe.ds;
private function getFloat(key:Int):Float {
return untyped __int_hash_get_float(h, key);
}
private function getInt64(key:Int):haxe.Int64 {
return untyped __int_hash_get_int64(h, key);
}
#end
}

View File

@ -0,0 +1,209 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package haxe.ds;
import haxe.Int64;
import haxe.ds.StringMap;
import haxe.ds.IntMap;
import haxe.ds.HashMap;
import haxe.ds.ObjectMap;
import haxe.ds.WeakMap;
import haxe.ds.EnumValueMap;
import haxe.Constraints.IMap;
import cpp.Int64Map;
/**
Map allows key to value mapping for arbitrary value types, and many key
types.
This is a multi-type abstract, it is instantiated as one of its
specialization types depending on its type parameters.
A Map can be instantiated without explicit type parameters. Type inference
will then determine the type parameters from the usage.
Maps can also be created with `[key1 => value1, key2 => value2]` syntax.
Map is an abstract type, it is not available at runtime.
@see https://haxe.org/manual/std-Map.html
**/
@:transitive
@:multiType(@:followWithAbstracts K)
abstract Map<K, V>(IMap<K, V>) {
/**
Creates a new Map.
This becomes a constructor call to one of the specialization types in
the output. The rules for that are as follows:
1. if `K` is a `String`, `haxe.ds.StringMap` is used
2. if `K` is an `Int`, `haxe.ds.IntMap` is used
3. if `K` is an `EnumValue`, `haxe.ds.EnumValueMap` is used
4. if `K` is any other class or structure, `haxe.ds.ObjectMap` is used
5. if `K` is any other type, it causes a compile-time error
(Cpp) Map does not use weak keys on `ObjectMap` by default.
**/
public function new();
/**
Maps `key` to `value`.
If `key` already has a mapping, the previous value disappears.
If `key` is `null`, the result is unspecified.
**/
public inline function set(key:K, value:V)
this.set(key, value);
/**
Returns the current mapping of `key`.
If no such mapping exists, `null` is returned.
Note that a check like `map.get(key) == null` can hold for two reasons:
1. the map has no mapping for `key`
2. the map has a mapping with a value of `null`
If it is important to distinguish these cases, `exists()` should be
used.
If `key` is `null`, the result is unspecified.
**/
@:arrayAccess public inline function get(key:K)
return this.get(key);
/**
Returns true if `key` has a mapping, false otherwise.
If `key` is `null`, the result is unspecified.
**/
public inline function exists(key:K)
return this.exists(key);
/**
Removes the mapping of `key` and returns true if such a mapping existed,
false otherwise.
If `key` is `null`, the result is unspecified.
**/
public inline function remove(key:K)
return this.remove(key);
/**
Returns an Iterator over the keys of `this` Map.
The order of keys is undefined.
**/
public inline function keys():Iterator<K> {
return this.keys();
}
/**
Returns an Iterator over the values of `this` Map.
The order of values is undefined.
**/
public inline function iterator():Iterator<V> {
return this.iterator();
}
/**
Returns an Iterator over the keys and values of `this` Map.
The order of values is undefined.
**/
public inline function keyValueIterator():KeyValueIterator<K, V> {
return this.keyValueIterator();
}
/**
Returns a shallow copy of `this` map.
The order of values is undefined.
**/
public inline function copy():Map<K, V> {
return cast this.copy();
}
/**
Returns a String representation of `this` Map.
The exact representation depends on the platform and key-type.
**/
public inline function toString():String {
return this.toString();
}
/**
Removes all keys from `this` Map.
**/
public inline function clear():Void {
this.clear();
}
@:arrayAccess @:noCompletion public inline function arrayWrite(k:K, v:V):V {
this.set(k, v);
return v;
}
@:to static inline function toStringMap<K:String, V>(t:IMap<K, V>):StringMap<V> {
return new StringMap<V>();
}
@:to static inline function toIntMap<K:Int, V>(t:IMap<K, V>):IntMap<V> {
return new IntMap<V>();
}
@:noDoc
@:to static inline function toInt64Map<K:Int64, V>(t:IMap<K, V>):Int64Map<V> {
return new Int64Map<V>();
}
@:to static inline function toEnumValueMapMap<K:EnumValue, V>(t:IMap<K, V>):EnumValueMap<K, V> {
return new EnumValueMap<K, V>();
}
@:to static inline function toObjectMap<K:{}, V>(t:IMap<K, V>):ObjectMap<K, V> {
return new ObjectMap<K, V>();
}
@:from static inline function fromStringMap<V>(map:StringMap<V>):Map<String, V> {
return cast map;
}
@:from static inline function fromIntMap<V>(map:IntMap<V>):Map<Int, V> {
return cast map;
}
@:noDoc
@:from static inline function fromInt64Map<V>(map:Int64Map<V>):Map<Int64, V> {
return cast map;
}
@:from static inline function fromObjectMap<K:{}, V>(map:ObjectMap<K, V>):Map<K, V> {
return cast map;
}
}

View File

@ -35,6 +35,7 @@ package haxe.ds;
inline void set(Dynamic key, float value) { __object_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(Dynamic key, double value) { __object_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(Dynamic key, ::String value) { __object_hash_set_string(HX_MAP_THIS,key,value); }
inline void set(Dynamic key, cpp::Int64 value) { __object_hash_set_int64(HX_MAP_THIS,key,value); }
template<typename V, typename H>
@ -48,7 +49,7 @@ package haxe.ds;
inline int get_int(Dynamic key) { return __object_hash_get_int(h,key); }
inline Float get_float(Dynamic key) { return __object_hash_get_float(h,key); }
inline String get_string(Dynamic key) { return __object_hash_get_string(h,key); }
inline cpp::Int64 get_int64(Dynamic key) { return __object_hash_get_int64(h,key); }
")
@:coreApi
class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
@ -123,6 +124,10 @@ class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
untyped __object_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
}
private function setInt64(key:Dynamic, val:haxe.Int64):Void {
untyped __object_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
}
private function getString(key:Dynamic):String {
return untyped __object_hash_get_string(h, key);
}
@ -138,5 +143,9 @@ class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
private function getFloat(key:Dynamic):Float {
return untyped __object_hash_get_float(h, key);
}
private function getInt64(key:Dynamic):haxe.Int64 {
return untyped __object_hash_get_int64(h, key);
}
#end
}

View File

@ -35,6 +35,7 @@ package haxe.ds;
inline void set(String key, float value) { __string_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(String key, double value) { __string_hash_set_float(HX_MAP_THIS,key,value); }
inline void set(String key, ::String value) { __string_hash_set_string(HX_MAP_THIS,key,value); }
inline void set(String key, cpp::Int64 value) { __string_hash_set_int64(HX_MAP_THIS,key,value); }
template<typename V, typename H>
inline void set(String key, const ::cpp::Struct<V,H> &value) {__string_hash_set(HX_MAP_THIS,key,value); }
@ -50,6 +51,7 @@ package haxe.ds;
inline int get_int(String key) { return __string_hash_get_int(h,key); }
inline Float get_float(String key) { return __string_hash_get_float(h,key); }
inline String get_string(String key) { return __string_hash_get_string(h,key); }
inline cpp::Int64 get_int64(String key) { return __string_hash_get_int64(h,key); }
")
@:coreApi class StringMap<T> implements haxe.Constraints.IMap<String, T> {
@:ifFeature("haxe.ds.StringMap.*")
@ -123,6 +125,10 @@ package haxe.ds;
untyped __string_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
}
private function setInt64(key:String, val:haxe.Int64):Void {
untyped __string_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
}
private function getString(key:String):String {
return untyped __string_hash_get_string(h, key);
}
@ -138,5 +144,9 @@ package haxe.ds;
private function getFloat(key:String):Float {
return untyped __string_hash_get_float(h, key);
}
private function getInt64(key:String):haxe.Int64 {
return untyped __string_hash_get_int64(h, key);
}
#end
}

View File

@ -35,6 +35,7 @@ package haxe.ds;
inline void set(Dynamic key, float value) { __object_hash_set_float(HX_MAP_THIS,key,value,true); }
inline void set(Dynamic key, double value) { __object_hash_set_float(HX_MAP_THIS,key,value,true); }
inline void set(Dynamic key, ::String value) { __object_hash_set_string(HX_MAP_THIS,key,value,true); }
inline void set(Dynamic key, cpp::Int64 value) { __object_hash_set_int64(HX_MAP_THIS,key,value,true); }
template<typename V, typename H>
inline void set(Dynamic key, const ::cpp::Struct<V,H> &value) {__object_hash_set(HX_MAP_THIS,key,value,true); }

View File

@ -105,9 +105,7 @@ class Process {
}
public function exitCode(block:Bool = true):Null<Int> {
if (block == false)
throw "Non blocking exitCode() not supported on this platform";
return NativeProcess.process_exit(p);
return NativeProcess.process_exit(p, block);
}
public function close():Void {

View File

@ -0,0 +1,33 @@
package sys.thread;
@:coreApi
class Condition {
var c:Dynamic;
public function new():Void {
c = untyped __global__.__hxcpp_condition_create();
}
public function acquire():Void {
untyped __global__.__hxcpp_condition_acquire(c);
}
public function tryAcquire():Bool {
return untyped __global__.__hxcpp_condition_try_acquire(c);
}
public function release():Void {
untyped __global__.__hxcpp_condition_release(c);
}
public function wait():Void {
untyped __global__.__hxcpp_condition_wait(c);
}
public function signal():Void {
untyped __global__.__hxcpp_condition_signal(c);
}
public function broadcast():Void {
untyped __global__.__hxcpp_condition_broadcast(c);
}
}

View File

@ -0,0 +1,22 @@
package sys.thread;
@:coreApi
class Semaphore {
var m:Dynamic;
public function new(value:Int) {
m = untyped __global__.__hxcpp_semaphore_create(value);
}
public function acquire():Void {
untyped __global__.__hxcpp_semaphore_acquire(m);
}
public function tryAcquire(?timeout:Float):Bool {
return untyped __global__.__hxcpp_semaphore_try_acquire(m, timeout == null ? 0 : (timeout:Float));
}
public function release():Void {
untyped __global__.__hxcpp_semaphore_release(m);
}
}

View File

@ -46,6 +46,8 @@ class HostClasses {
"sys.thread.Mutex",
"sys.thread.Thread",
"sys.thread.Tls",
"sys.thread.Semaphore",
"sys.thread.Condition",
"cpp.vm.ExecutionTrace",
"cpp.vm.Gc",
"cpp.vm.Profiler",
@ -53,6 +55,7 @@ class HostClasses {
"cpp.vm.WeakRef",
"cpp.Object",
"cpp.Int64",
"cpp.Int64Map",
"cpp.Finalizable",
"Std",
"StringBuf",
@ -147,6 +150,7 @@ class HostClasses {
"List",
"Map",
"String",
"haxe.atomic.AtomicInt"
];
static function parseClassInfo(externs:Map<String, Bool>, filename:String) {

View File

@ -23,6 +23,8 @@
import cs.Boot;
import cs.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 {
@ -79,54 +81,74 @@ import cs.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, lastDigitIndex + 1);
return try {
(sign == -1 ? -1 : 1) * cs.system.Convert.ToInt32(digits, base);
} catch(e:cs.system.FormatException) {
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 = cs.system.Convert.ToInt32(x.substring(index, firstInvalidIndex), if (isHexadecimal) 16 else 10);
return if (isNegative) -result else result;
}
public static function parseFloat(x:String):Float {

View File

@ -26,7 +26,6 @@ import cs.system.threading.Thread;
@:coreApi
class Sys {
private static var _env:haxe.ds.StringMap<String>;
private static var _args:Array<String>;
public static inline function print(v:Dynamic):Void {
@ -50,22 +49,17 @@ class Sys {
return Environment.GetEnvironmentVariable(s);
}
public static function putEnv(s:String, v:String):Void {
public static function putEnv(s:String, v:Null<String>):Void {
Environment.SetEnvironmentVariable(s, v);
if (_env != null)
_env.set(s, v);
}
public static function environment():Map<String, String> {
if (_env == null) {
var e = _env = new haxe.ds.StringMap();
var nenv = Environment.GetEnvironmentVariables().GetEnumerator();
while (nenv.MoveNext()) {
e.set(nenv.Key, nenv.Value);
}
final env = new haxe.ds.StringMap();
final nenv = Environment.GetEnvironmentVariables().GetEnumerator();
while (nenv.MoveNext()) {
env.set(nenv.Key, nenv.Value);
}
return _env;
return env;
}
public static inline function sleep(seconds:Float):Void {
@ -78,7 +72,7 @@ class Sys {
}
public static inline function getCwd():String {
return cs.system.io.Directory.GetCurrentDirectory();
return haxe.io.Path.addTrailingSlash(cs.system.io.Directory.GetCurrentDirectory());
}
public static inline function setCwd(s:String):Void {

View File

@ -1,20 +1,26 @@
package haxe;
import haxe.iterators.RestIterator;
import haxe.iterators.RestKeyValueIterator;
import cs.NativeArray;
import cs.system.Array as CsArray;
import haxe.iterators.RestIterator;
import haxe.iterators.RestKeyValueIterator;
private typedef NativeRest<T> = #if erase_generics NativeArray<Dynamic> #else NativeArray<T> #end;
@: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 inline function of<T>(array:Array<T>):Rest<T>
#if erase_generics
// This is wrong but so is everything else in my life
return new Rest(@:privateAccess array.__a);
#else
return new Rest(cs.Lib.nativeArray(array, false));
#end
inline function new(a:NativeRest<T>):Void
this = a;
@ -51,4 +57,4 @@ abstract Rest<T>(NativeRest<T>) {
public function toString():String {
return toArray().toString();
}
}
}

View File

@ -0,0 +1,61 @@
package haxe.atomic;
private class IntWrapper {
public var value:Int;
public function new(value:Int) {
this.value = value;
}
}
abstract AtomicInt(IntWrapper) {
public inline function new(value:Int) {
this = new IntWrapper(value);
}
private inline function cas_loop(value:Int, op:(a:Int, b:Int) -> Int):Int {
var oldValue;
var newValue;
do {
oldValue = load();
newValue = op(oldValue, value);
} while(compareExchange(oldValue, newValue) != oldValue);
return oldValue;
}
public inline function add(b:Int):Int {
return cas_loop(b, (a, b) -> a + b);
}
public inline function sub(b:Int):Int {
return cas_loop(b, (a, b) -> a - b);
}
public inline function and(b:Int):Int {
return cas_loop(b, (a, b) -> cast a & b);
}
public inline function or(b:Int):Int {
return cas_loop(b, (a, b) -> cast a | b);
}
public inline function xor(b:Int):Int {
return cas_loop(b, (a, b) -> cast a ^ b);
}
public inline function compareExchange(expected:Int, replacement:Int):Int {
return cs.Syntax.code("System.Threading.Interlocked.CompareExchange(ref ({0}).value, {1}, {2})", this, replacement, expected);
}
public inline function exchange(value:Int):Int {
return cs.Syntax.code("System.Threading.Interlocked.Exchange(ref ({0}).value, {1})", this, value);
}
public inline function load():Int {
return this.value; // according to the CLI spec reads and writes are atomic
}
public inline function store(value:Int):Int {
return this.value = value; // according to the CLI spec reads and writes are atomic
}
}

View File

@ -0,0 +1,33 @@
package haxe.atomic;
import cs.system.threading.Interlocked.*;
private class ObjectWrapper<T:{}> {
public var value:T;
public function new(value:T) {
this.value = value;
}
}
extern abstract AtomicObject<T:{}>(ObjectWrapper<T>) {
public inline function new(value:T) {
this = new ObjectWrapper(value);
}
public inline function compareExchange(expected:T, replacement:T):T {
return cs.Syntax.code("System.Threading.Interlocked.CompareExchange(ref ({0}).value, {1}, {2})", this, replacement, expected);
}
public inline function exchange(value:T):T {
return cs.Syntax.code("System.Threading.Interlocked.Exchange(ref ({0}).value, {1})", this, value);
}
public inline function load():T {
return this.value; // according to the CLI spec reads and writes are atomic
}
public inline function store(value:T):T {
return this.value = value; // according to the CLI spec reads and writes are atomic
}
}

View File

@ -364,7 +364,7 @@ import cs.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 cs.NativeArray;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -378,7 +378,7 @@ import cs.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 cs.NativeArray;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -377,7 +377,7 @@ import cs.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 cs.NativeArray;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -0,0 +1,37 @@
package sys.thread;
import cs.system.threading.Monitor;
@:coreApi
@:access(sys.thread.Mutex)
class Condition {
final object:cs.system.Object;
public function new():Void {
this.object = new cs.system.Object();
}
public function acquire():Void {
Monitor.Enter(object);
}
public function tryAcquire():Bool {
return Monitor.TryEnter(object);
}
public function release():Void {
Monitor.Exit(object);
}
public function wait():Void {
Monitor.Wait(object);
}
public function signal():Void {
Monitor.Pulse(object);
}
public function broadcast():Void {
Monitor.PulseAll(object);
}
}

View File

@ -0,0 +1,22 @@
package sys.thread;
@:coreApi
class Semaphore {
final native:cs.system.threading.Semaphore;
public function new(value:Int):Void {
this.native = new cs.system.threading.Semaphore(value, 0x7FFFFFFF);
}
public function acquire():Void {
native.WaitOne();
}
public function tryAcquire(?timeout:Float):Bool {
return native.WaitOne(timeout == null ? 0 : Std.int(timeout * 1000));
}
public function release():Void {
native.Release();
}
}

View File

@ -230,7 +230,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)
@ -244,7 +244,7 @@ class DynamicObject extends HxObject {
}
if (!first)
ret.add(" ");
ret.add("}");
ret.add("]");
return ret.toString();
}
}

View File

@ -33,7 +33,7 @@ class Sys {
extern static public function getEnv(s:String):String;
extern static public function putEnv(s:String, v:String):Void;
extern static public function putEnv(s:String, v:Null<String>):Void;
extern static public function environment():Map<String, String>;

View File

@ -18,7 +18,10 @@ class Exception {
if(Std.isOfType(value, Exception)) {
return value;
} else {
return new ValueException(value, null, value);
var e = new ValueException(value, null, value);
// Undo automatic __shiftStack()
e.__unshiftStack();
return e;
}
}
@ -63,6 +66,12 @@ class Exception {
__skipStack++;
}
@:noCompletion
@:ifFeature("haxe.Exception.get_stack")
inline function __unshiftStack():Void {
__skipStack--;
}
function get_message():String {
return __exceptionMessage;
}

View File

@ -5,8 +5,8 @@ import haxe.io.Bytes;
extern class PkContext {
function new():Void;
function parse_key(key:Bytes, ?pwd:String):Int;
function parse_keyfile(path:String, ?password:String):Int;
function parse_key(key:Bytes, ?pwd:String, ctr_dbg: CtrDrbg):Int;
function parse_keyfile(path:String, ?password:String, ctr_dbg: CtrDrbg):Int;
function parse_public_key(key:Bytes):Int;
function parse_public_keyfile(path:String):Int;
}

View File

@ -43,11 +43,11 @@ class Host {
this.ip = ip;
}
extern static public function localhost();
extern static public function localhost():String;
extern static function hostReverse(ip:Int);
extern static function hostReverse(ip:Int):String;
extern static function hostToString(ip:Int);
extern static function hostToString(ip:Int):String;
extern static function resolve(name:String);
extern static function resolve(name:String):Int;
}

View File

@ -38,7 +38,7 @@ class Key {
var code = if (isPublic) {
key.native.parse_public_keyfile(file);
} else {
key.native.parse_keyfile(file, pass);
key.native.parse_keyfile(file, pass, Mbedtls.getDefaultCtrDrbg());
}
if (code != 0) {
throw(mbedtls.Error.strerror(code));
@ -51,7 +51,7 @@ class Key {
var code = if (isPublic) {
key.native.parse_public_key(data);
} else {
key.native.parse_key(data);
key.native.parse_key(data, null, Mbedtls.getDefaultCtrDrbg());
}
if (code != 0) {
throw(mbedtls.Error.strerror(code));

View File

@ -0,0 +1,41 @@
package sys.thread;
@:coreApi class Condition {
final cond:eval.luv.Condition;
final mutex:eval.luv.Mutex;
public function new():Void {
cond = eval.luv.Condition.init().resolve();
mutex = eval.luv.Mutex.init(true).resolve();
eval.vm.Gc.finalise(destroy, this);
}
static function destroy(cond:Condition):Void {
cond.cond.destroy();
cond.mutex.destroy();
}
public function acquire():Void {
mutex.lock();
}
public function tryAcquire():Bool {
return mutex.tryLock().isOk();
}
public function release():Void {
mutex.unlock();
}
public function wait():Void {
cond.wait(mutex);
}
public function signal():Void {
cond.signal();
}
public function broadcast():Void {
cond.broadcast();
}
}

View File

@ -3,12 +3,23 @@ package sys.thread;
import eval.luv.Loop;
import eval.luv.Async;
import eval.luv.Timer as LuvTimer;
import haxe.MainLoop;
/**
When an event loop has an available event to execute.
**/
@:coreApi
enum NextEventTime {
/** There's already an event waiting to be executed */
Now;
/** No new events are expected. */
Never;
/**
An event is expected to arrive at any time.
If `time` is specified, then the event will be ready at that time for sure.
*/
AnyTime(time:Null<Float>);
/** An event is expected to be ready for execution at `time`. */
At(time:Float);
}
@ -27,37 +38,47 @@ private class RegularEvent {
}
}
/**
An event loop implementation used for `sys.thread.Thread`
**/
@:coreApi
class EventLoop {
@:allow(eval.luv.Loop)
final handle:Loop;
final mutex = new Mutex();
final oneTimeEvents = new Array<Null<()->Void>>();
var oneTimeEventsIdx = 0;
final wakeup:Async;
var promisedEventsCount = 0;
var pending:Array<()->Void> = [];
var looping = false;
var started:Bool = false;
var isMainThread:Bool;
static var CREATED : Bool;
public function new():Void {
isMainThread = !CREATED;
CREATED = true;
handle = Loop.init().resolve();
wakeup = Async.init(handle, consumePending).resolve();
wakeup.unref();
}
/**
Schedule event for execution every `intervalMs` milliseconds in current loop.
**/
public function repeat(event:()->Void, intervalMs:Int):EventHandler {
var e = new RegularEvent(event);
mutex.acquire();
pending.push(() -> {
e.timer = LuvTimer.init(handle).resolve();
e.timer.start(e.run, intervalMs, intervalMs < 1 ? 1 : intervalMs).resolve();
});
e.timer = LuvTimer.init(handle).resolve();
e.timer.start(e.run, intervalMs, intervalMs < 1 ? 1 : intervalMs).resolve();
mutex.release();
wakeup.send();
return e;
}
/**
Prevent execution of a previously scheduled event in current loop.
**/
public function cancel(eventHandler:EventHandler):Void {
mutex.acquire();
(eventHandler:RegularEvent).event = noop;
@ -71,6 +92,11 @@ class EventLoop {
}
static final noop = function() {}
/**
Notify this loop about an upcoming event.
This makes the thread stay alive and wait for as many events as the number of
times `.promise()` was called. These events should be added via `.runPromised()`.
**/
public function promise():Void {
mutex.acquire();
++promisedEventsCount;
@ -79,6 +105,9 @@ class EventLoop {
wakeup.send();
}
/**
Execute `event` as soon as possible.
**/
public function run(event:()->Void):Void {
mutex.acquire();
pending.push(event);
@ -86,6 +115,9 @@ class EventLoop {
wakeup.send();
}
/**
Add previously promised `event` for execution.
**/
public function runPromised(event:()->Void):Void {
mutex.acquire();
--promisedEventsCount;
@ -96,7 +128,7 @@ class EventLoop {
}
function refUnref():Void {
if(promisedEventsCount > 0) {
if (promisedEventsCount > 0 || (isMainThread && haxe.MainLoop.hasEvents())) {
wakeup.ref();
} else {
wakeup.unref();
@ -104,37 +136,68 @@ class EventLoop {
}
public function progress():NextEventTime {
//TODO: throw if loop is already running
if((handle:Loop).run(NOWAIT)) {
if (started) throw "Event loop already started";
if (handle.run(NOWAIT)) {
return AnyTime(null);
} else {
return Never;
}
}
/**
Blocks until a new event is added or `timeout` (in seconds) to expires.
Depending on a target platform this method may also automatically execute arriving
events while waiting. However if any event is executed it will stop waiting.
Returns `true` if more events are expected.
Returns `false` if no more events expected.
Depending on a target platform this method may be non-reentrant. It must
not be called from event callbacks.
**/
public function wait(?timeout:Float):Bool {
//TODO: throw if loop is already running
if(timeout == null) {
if (started) throw "Event loop already started";
if(timeout != null) {
var timer = LuvTimer.init(handle).resolve();
timer.start(() -> {
timer.stop().resolve();
timer.close(() -> {});
}, Std.int(timeout * 1000));
return (handle:Loop).run(ONCE);
return handle.run(ONCE);
} else {
return (handle:Loop).run(ONCE);
return handle.run(ONCE);
}
}
/**
Execute all pending events.
Wait and execute as many events as the number of times `promise()` was called.
Runs until all repeating events are cancelled and no more events are expected.
Depending on a target platform this method may be non-reentrant. It must
not be called from event callbacks.
**/
public function loop():Void {
//TODO: throw if loop is already running
if (started) throw "Event loop already started";
started = true;
consumePending();
(handle:Loop).run(DEFAULT);
handle.run(DEFAULT);
}
function consumePending(?_:Async):Void {
mutex.acquire();
var p = pending;
pending = [];
mutex.release();
for(fn in p) fn();
if (started && isMainThread) {
var next = @:privateAccess MainLoop.tick();
if (haxe.MainLoop.hasEvents()) wakeup.send();
refUnref();
}
}
}
}

View File

@ -0,0 +1,36 @@
package sys.thread;
@:coreApi class Semaphore {
final native:eval.luv.Semaphore;
public function new(value:Int):Void {
native = eval.luv.Semaphore.init(value).resolve();
eval.vm.Gc.finalise(destroy, this);
}
static function destroy(sem:Semaphore):Void {
sem.native.destroy();
}
public function acquire():Void {
native.wait();
}
public function tryAcquire(?timeout:Float):Bool {
if (timeout == null) {
return native.tryWait().isOk();
} else {
var t = Sys.time() + timeout;
while (Sys.time() < t) {
if (native.tryWait().isOk()) {
return true;
}
}
return false;
}
}
public function release():Void {
native.post();
}
}

View File

@ -18,10 +18,6 @@ package eval.integers;
/**
Parse the given string value to an unsigned integer.
<<<<<<< HEAD
=======
>>>>>>> development
Throws if the given string is not a valid representation of an unsigned
integer.
**/

View File

@ -60,14 +60,14 @@ typedef DirectoryScan = {
**/
extern class DirSync {
@:inheritDoc(eval.luv.Dir.open)
static public function open(loop:Loop, path:NativeString):Result<Dir>;
static public function open(path:NativeString):Result<Dir>;
@:inheritDoc(eval.luv.Dir.close)
static public function close(dir:Dir, loop:Loop):Result<Result.NoData>;
static public function close(dir:Dir):Result<Result.NoData>;
@:inheritDoc(eval.luv.Dir.read)
static public function read(dir:Dir, loop:Loop, ?numberOfEntries:Int):Result<Array<Dirent>>;
static public function read(dir:Dir, ?numberOfEntries:Int):Result<Array<Dirent>>;
@:inheritDoc(eval.luv.Dir.scan)
static public function scan(loop:Loop, path:NativeString):Result<DirectoryScan>;
static public function scan(path:NativeString):Result<DirectoryScan>;
}

View File

@ -16,6 +16,11 @@ extern class Env {
**/
static function setEnv(name:String, value:NativeString):Result<Result.NoData>;
/**
Deletes an environment variable.
**/
static function unsetEnv(name:String):Result<Result.NoData>;
/**
Retrieves all environment variables.
**/

View File

@ -26,11 +26,11 @@ enum abstract FsEventFlag(Int) {
/**
Starts the handle and watches the given path for changes.
**/
public function start(path:NativeString, ?flags:Array<FsEventFlag>, callback:(result:Result<{file:NativeString,events:Array<FsEventType>}>)->Void):Void;
public function start(path:NativeString, ?flags:Array<FsEventFlag>, callback:(result:Result<{file:Null<NativeString>,events:Array<FsEventType>}>)->Void):Void;
/**
Stops the handle.
**/
public function stop():Result<Result.NoData>;
}
}

View File

@ -41,12 +41,12 @@ extern class Resource {
/**
Evaluates to the amount of free memory, in bytes.
**/
static function freeMemory():UInt64;
static function freeMemory():Null<UInt64>;
/**
Evaluates to the total amount of memory, in bytes.
**/
static function totalMemory():UInt64;
static function totalMemory():Null<UInt64>;
/**
Gets the amount of memory available to the process (in bytes) based on
@ -68,11 +68,11 @@ extern class Resource {
/**
Evaluates to the resident set size for the current process.
**/
static function residentSetMemory(pid:Int):Result<UInt64>;
static function residentSetMemory():Result<UInt64>;
/**
Gets the resource usage measures for the current process.
**/
static function getRUsage():Result<RUsage>;
}
}

View File

@ -162,6 +162,10 @@ enum abstract UVError(Int) {
var UV_EFTYPE = 76;
/** illegal byte sequence */
var UV_EILSEQ = 77;
/** value too large for defined data type **/
var UV_EOVERFLOW = 78;
/** socket type not supported**/
var UV_ESOCKTNOSUPPORT = 79;
/**
Converts a system error code to a libuv error.

View File

@ -100,4 +100,10 @@ class Lib {
str = str.split("\\").join("\\\\");
flash.external.ExternalInterface.call("console." + type, str);
}
public static var parseInt(get, never):(string:String, ?radix:Int) -> Float;
extern static inline function get_parseInt():(string:String, ?radix:Int) -> Float {
return untyped __global__["parseInt"];
}
}

View File

@ -49,13 +49,12 @@ import flash.Boot;
return untyped __int__(x);
}
public static function parseInt(x:String):Null<Int>
untyped {
var v = __global__["parseInt"](x);
if (__global__["isNaN"](v))
return null;
return v;
}
public static function parseInt(x:String):Null<Int> {
final v = flash.Lib.parseInt(x);
if (Math.isNaN(v))
return null;
return cast v;
}
public static function parseFloat(x:String):Float {
return untyped __global__["parseFloat"](x);

View File

@ -69,7 +69,7 @@ package haxe.ds;
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(i);
@ -78,7 +78,7 @@ package haxe.ds;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -66,14 +66,14 @@ class ObjectMap<K:{}, V> extends flash.utils.Dictionary implements haxe.Constrai
}
public function toString():String {
var s = "";
var s = "[";
var it = keys();
for (i in it) {
s += (s == "" ? "" : ",") + Std.string(i);
s += " => ";
s += Std.string(get(i));
}
return s + "}";
return s + "]";
}
public function clear():Void {

View File

@ -107,7 +107,7 @@ package haxe.ds;
public function toString():String {
var s = new StringBuf();
s.add("{");
s.add("[");
var it = keys();
for (i in it) {
s.add(i);
@ -116,7 +116,7 @@ package haxe.ds;
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -74,7 +74,7 @@ class UnsafeStringMap<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);
@ -83,7 +83,7 @@ class UnsafeStringMap<T> implements haxe.Constraints.IMap<String, T> {
if (it.hasNext())
s.add(", ");
}
s.add("}");
s.add("]");
return s.toString();
}

View File

@ -66,14 +66,14 @@ class WeakMap<K:{}, V> extends flash.utils.Dictionary implements haxe.Constraint
}
public function toString():String {
var s = "";
var s = "[";
var it = keys();
for (i in it) {
s += (s == "" ? "" : ",") + Std.string(i);
s += " => ";
s += Std.string(get(i));
}
return s + "}";
return s + "]";
}
public function clear():Void {

View File

@ -8,7 +8,7 @@ package flash.globalization;
function format(dateTime : Date) : String;
function formatUTC(dateTime : Date) : String;
function getDateStyle() : DateTimeStyle;
function getDateTimePattern() : DateTimeStyle;
function getDateTimePattern() : String;
function getFirstWeekday() : Int;
function getMonthNames(?nameStyle : DateTimeNameStyle, ?context : DateTimeNameContext) : flash.Vector<String>;
function getTimeStyle() : DateTimeStyle;

View File

@ -150,6 +150,23 @@ class EntryPoint {
flash.Lib.current.stage.addEventListener(flash.events.Event.ENTER_FRAME, function(_) processEvents());
#elseif (target.threaded && !cppia)
//everything is delegated to sys.thread.EventLoop
#elseif lua
inline function luvRun(mode:String):Bool
return untyped __lua__('_hx_luv.run({0})', mode);
while (true) {
var nextTick = processEvents();
if(untyped __lua__('_hx_luv.loop_alive()')) {
if(nextTick < 0)
luvRun("once")
else
luvRun("nowait");
} else {
if (nextTick < 0)
break;
if (nextTick > 0)
sleepLock.wait(nextTick);
}
}
#elseif sys
while (true) {
var nextTick = processEvents();

View File

@ -40,6 +40,14 @@ abstract EnumFlags<T:EnumValue>(Int) {
this = i;
}
@:from static function from<T:EnumValue>(e:T) : EnumFlags<T> {
return new EnumFlags(1 << e.getIndex());
}
@:op(a|b) function or(f:haxe.EnumFlags<T>) : haxe.EnumFlags<T>;
@:op(a&b) function and(f:haxe.EnumFlags<T>) : haxe.EnumFlags<T>;
@:op(a^b) function xor(f:haxe.EnumFlags<T>) : haxe.EnumFlags<T>;
/**
Checks if the index of enum instance `v` is set.
@ -76,6 +84,22 @@ abstract EnumFlags<T:EnumValue>(Int) {
this &= 0xFFFFFFFF - (1 << Type.enumIndex(v));
}
/**
Depending on the value of `condition` sets (`condition=true`) or unsets (`condition=false`)
the index of enum instance `v`.
This method is optimized if `v` is an enum instance expression such as
`SomeEnum.SomeCtor`.
If `v` is `null`, the result is unspecified.
**/
public inline function setTo(v:T, condition:Bool):Void {
if(condition)
set(v)
else
unset(v);
}
/**
Convert a integer bitflag into a typed one (this is a no-op, it does not
have any impact on speed).

View File

@ -37,7 +37,7 @@ extern class EnumTools {
If `e` is inside a package, the package structure is returned dot-
separated, with another dot separating the enum name:
pack1.pack2.(...).packN.EnumName
If `e` is a sub-type of a Haxe module, that module is not part of the
@ -110,6 +110,11 @@ extern class EnumTools {
static inline function getConstructors<T>(e:Enum<T>):Array<String> {
return Type.getEnumConstructs(e);
}
#if (java && jvm)
@:noCompletion
extern static function values<T>(en:Enum<T>):java.NativeArray<java.lang.Enum<T>>;
#end
}
/**

View File

@ -25,7 +25,7 @@ package haxe;
/**
Cross-platform JSON API: it will automatically use the optimized native API if available.
Use `-D haxeJSON` to force usage of the Haxe implementation even if a native API is found:
This will provide extra encoding features such as enums (replaced by their index) and StringMaps.
This will provide extra encoding (but not decoding) features such as enums (replaced by their index) and StringMaps.
@see https://haxe.org/manual/std-Json.html
**/

View File

@ -60,11 +60,6 @@ class MainEvent {
@:access(haxe.MainEvent)
class MainLoop {
#if (target.threaded && !cppia)
static var eventLoopHandler:Null<EventHandler>;
static var mutex = new sys.thread.Mutex();
static var mainThread = Thread.current();
#end
static var pending:MainEvent;
@ -94,7 +89,7 @@ class MainLoop {
/**
Add a pending event to be run into the main loop.
**/
public static function add(f:Void->Void, priority = 0):MainEvent@:privateAccess {
public static function add(f:Void->Void, priority = 0) : MainEvent {
if (f == null)
throw "Event function is null";
var e = new MainEvent(f, priority);
@ -103,29 +98,9 @@ class MainLoop {
head.prev = e;
e.next = head;
pending = e;
injectIntoEventLoop(0);
return e;
}
static function injectIntoEventLoop(waitMs:Int) {
#if (target.threaded && !cppia)
mutex.acquire();
if(eventLoopHandler != null)
mainThread.events.cancel(eventLoopHandler);
eventLoopHandler = mainThread.events.repeat(
() -> {
mainThread.events.cancel(eventLoopHandler);
var wait = tick();
if(hasEvents()) {
injectIntoEventLoop(Std.int(wait * 1000));
}
},
waitMs
);
mutex.release();
#end
}
static function sortEvents() {
// pending = haxe.ds.ListSort.sort(pending, function(e1, e2) return e1.nextRun > e2.nextRun ? -1 : 1);
// we can't use directly ListSort because it requires prev/next to be public, which we don't want here

View File

@ -7,7 +7,7 @@ private typedef NativeRest<T> = Array<T>;
/**
A special type that represents a "rest" function argument.
The special `...` syntax can be used for convenience and improved readability:
```haxe

View File

@ -45,12 +45,12 @@ class SysTools {
**/
public static function quoteWinArg(argument:String, escapeMetaCharacters:Bool):String {
// If there is no space, tab, back-slash, or double-quotes, and it is not an empty string.
if (!~/^[^ \t\\"]+$/.match(argument)) {
if (!~/^(\/)?[^ \t\/\\"]+$/.match(argument)) {
// Based on cpython's subprocess.list2cmdline().
// https://hg.python.org/cpython/file/50741316dd3a/Lib/subprocess.py#l620
var result = new StringBuf();
var needquote = argument.indexOf(" ") != -1 || argument.indexOf("\t") != -1 || argument == "";
var needquote = argument.indexOf(" ") != -1 || argument.indexOf("\t") != -1 || argument == "" || argument.indexOf("/") > 0;
if (needquote)
result.add('"');

View File

@ -40,6 +40,11 @@ import sys.thread.EventLoop;
It is also possible to extend this class and override its `run()` method in
the child class.
Notice for threaded targets:
`Timer` instances require threads they were created in to run with Haxe's event loops.
Main thread of a Haxe program always contains an event loop. For other cases use
`sys.thread.Thread.createWithEventLoop` and `sys.thread.Thread.runWithEventLoop` methods.
**/
class Timer {
#if (flash || js)

View File

@ -0,0 +1,55 @@
package haxe.atomic;
#if !(target.atomics || core_api)
#error "Atomic operations are not supported on this target!"
#end
/**
Atomic boolean.
(js) The Atomics and SharedArrayBuffer objects need to be available. Errors will be thrown if this is not the case.
**/
@:coreApi
abstract AtomicBool(AtomicInt) {
private inline function toInt(v:Bool):Int {
return v ? 1 : 0;
}
private inline function toBool(v:Int):Bool {
return v == 1;
}
public inline function new(value:Bool):Void {
this = new AtomicInt(toInt(value));
}
/**
Atomically compares the value of `a` with `expected` and replaces `a` with `replacement` if they are equal..
Returns the original value of `a`.
**/
public inline function compareExchange(expected:Bool, replacement:Bool):Bool {
return toBool(this.compareExchange(toInt(expected), toInt(replacement)));
}
/**
Atomically exchanges `a` with `value`.
Returns the original value of `a`.
**/
public inline function exchange(value:Bool):Bool {
return toBool(this.exchange(toInt(value)));
}
/**
Atomically fetches the value of `a`.
**/
public inline function load():Bool {
return toBool(this.load());
}
/**
Atomically stores `value` into `a`.
Returns the value that has been stored.
**/
public inline function store(value:Bool):Bool {
return toBool(this.store(toInt(value)));
}
}

View File

@ -0,0 +1,67 @@
package haxe.atomic;
#if !(target.atomics || core_api)
#error "This target does not support atomic operations."
#end
/**
Atomic integer.
(js) The Atomics and SharedArrayBuffer objects need to be available. Errors will be thrown if this is not the case.
**/
@:coreType
abstract AtomicInt {
public function new(value:Int):Void;
/**
Atomically adds `b` to `a`.
Returns the original value of `a`.
**/
public function add(b:Int):Int;
/**
Atomically substracts `b` from `a`.
Returns the original value of `a`.
**/
public function sub(b:Int):Int;
/**
Atomically computes the bitwise and of `a` and `b` and stores it in `a`.
Returns the original value of `a`.
**/
public function and(b:Int):Int;
/**
Atomically computes the bitwise or of `a` and `b` and stores it in `a`.
Returns the original value of `a`.
**/
public function or(b:Int):Int;
/**
Atomically computes the bitwise xor of `a` and `b` and stores it in `a`.
Returns the original value of `a`.
**/
public function xor(b:Int):Int;
/**
Atomically compares the value of `a` with `expected` and replaces `a` with `replacement` if they are equal..
Returns the original value of `a`.
**/
public function compareExchange(expected:Int, replacement:Int):Int;
/**
Atomically exchanges `a` with `value`.
Returns the original value of `a`.
**/
public function exchange(value:Int):Int;
/**
Atomically fetches the value of `a`.
**/
public function load():Int;
/**
Atomically stores `value` into `a`.
Returns the value that has been stored.
**/
public function store(value:Int):Int;
}

View File

@ -0,0 +1,44 @@
package haxe.atomic;
#if !(target.atomics || core_api)
#error "This target does not support atomic operations."
#end
#if (js || hxcpp)
#error "JavaScript and Hxcpp do not support AtomicObject"
#end
/**
Atomic object. Use with care, this does not magically make it thread-safe to mutate objects.
Not supported on JavaScript or C++.
**/
@:coreType
abstract AtomicObject<T:{}> {
public function new(value:T):Void;
/**
Atomically compares the value of `a` with `expected` and replaces `a` with `replacement` if they are equal..
Returns the original value of `a`.
Note that comparison is done by reference, and not by value.
While this is expected for most objects, this might give unexpected behaviour for strings.
**/
public function compareExchange(expected:T, replacement:T):T;
/**
Atomically exchanges `a` with `value`.
Returns the original value of `a`.
**/
public function exchange(value:T):T;
/**
Atomically fetches the value of `a`.
**/
public function load():T;
/**
Atomically stores `value` into `a`.
Returns the value that has been stored.
**/
public function store(value:T):T;
}

View File

@ -0,0 +1,79 @@
// from vshaxe
package haxe.display;
import haxe.display.Position.Location;
import haxe.display.Position.Range;
import haxe.display.JsonModuleTypes;
enum abstract UnresolvedIdentifierSuggestion(Int) {
var UISImport;
var UISTypo;
}
enum abstract MissingFieldCauseKind<T>(String) {
final AbstractParent:MissingFieldCauseKind<{parent:JsonTypePathWithParams}>;
final ImplementedInterface:MissingFieldCauseKind<{parent:JsonTypePathWithParams}>;
final PropertyAccessor:MissingFieldCauseKind<{property:JsonClassField, isGetter:Bool}>;
final FieldAccess:MissingFieldCauseKind<{}>;
final FinalFields:MissingFieldCauseKind<{fields:Array<JsonClassField>}>;
}
typedef MissingFieldCause<T> = {
var kind:MissingFieldCauseKind<T>;
var args:T;
}
typedef MissingField = {
var field:JsonClassField;
var type:JsonType<Dynamic>;
/**
When implementing multiple interfaces, there can be field duplicates among them. This flag is only
true for the first such occurrence of a field, so that the "Implement all" code action doesn't end
up implementing the same field multiple times.
**/
var unique:Bool;
}
typedef MissingFieldDiagnostic = {
var fields:Array<MissingField>;
var cause:MissingFieldCause<Dynamic>;
}
typedef MissingFieldDiagnostics = {
var moduleType:JsonModuleType<Dynamic>;
var moduleFile:String;
var entries:Array<MissingFieldDiagnostic>;
}
enum abstract DiagnosticKind<T>(Int) from Int to Int {
final DKUnusedImport:DiagnosticKind<Void>;
final DKUnresolvedIdentifier:DiagnosticKind<Array<{kind:UnresolvedIdentifierSuggestion, name:String}>>;
final DKCompilerError:DiagnosticKind<String>;
final DKRemovableCode:DiagnosticKind<{description:String, range:Range}>;
final DKParserError:DiagnosticKind<String>;
final DeprecationWarning:DiagnosticKind<String>;
final InactiveBlock:DiagnosticKind<Void>;
final MissingFields:DiagnosticKind<MissingFieldDiagnostics>;
}
enum abstract DiagnosticSeverity(Int) {
var Error = 1;
var Warning;
var Information;
var Hint;
}
typedef Diagnostic<T> = {
var kind:DiagnosticKind<T>;
var range:Range;
var severity:DiagnosticSeverity;
var args:T;
var relatedInformation:Array<DiagnosticRelatedInformation>;
}
typedef DiagnosticRelatedInformation = {
var location:Location;
var message:String;
var depth:Int;
}

View File

@ -25,6 +25,7 @@ package haxe.display;
import haxe.display.JsonModuleTypes;
import haxe.display.Position;
import haxe.display.Protocol;
import haxe.ds.ReadOnlyArray;
/**
Methods of the JSON-RPC-based `--display` protocol in Haxe 4.
@ -32,6 +33,12 @@ import haxe.display.Protocol;
**/
@:publicFields
class DisplayMethods {
/**
The request is sent from the client to Haxe to get diagnostics for a specific file, a list of files or the whole project.
**/
static inline var Diagnostics = new HaxeRequestMethod<DiagnosticsParams, DiagnosticsResult>("display/diagnostics");
/**
The completion request is sent from the client to Haxe to request code completion.
Haxe automatically determines the type of completion to use based on the passed position, see `CompletionResultKind`.
@ -78,11 +85,20 @@ class DisplayMethods {
**/
static inline var SignatureHelp = new HaxeRequestMethod<SignatureHelpParams, SignatureHelpResult>("display/signatureHelp");
/**
The metadata request is sent from the client to Haxe to get a list of all registered metadata and their documentation.
**/
static inline var Metadata = new HaxeRequestMethod<MetadataParams, MetadataResult>("display/metadata");
/**
The defines request is sent from the client to Haxe to get a list of all registered defines and their documentation.
**/
static inline var Defines = new HaxeRequestMethod<DefinesParams, DefinesResult>("display/defines");
/*
TODO:
- finish completion
- diagnostics
- codeLens
- workspaceSymbols ("project/symbol"?)
*/
@ -295,6 +311,7 @@ typedef Metadata = {
var platforms:Array<Platform>;
var targets:Array<MetadataTarget>;
var internal:Bool;
var ?origin:String;
var ?links:Array<String>;
}
@ -305,6 +322,8 @@ typedef Define = {
var parameters:Array<String>;
var platforms:Array<Platform>;
var links:Array<String>;
var ?origin:String;
var ?deprecated:String;
}
typedef Keyword = {
@ -425,6 +444,17 @@ typedef PatternCompletion<T> = ToplevelCompletion<T> & {
var isOutermostPattern:Bool;
}
typedef DiagnosticsParams = {
var ?file:FsPath;
var ?contents:String;
var ?fileContents:Array<{file:FsPath, ?contents:String}>;
}
typedef DiagnosticsResult = Response<ReadOnlyArray<{
var file:FsPath;
var diagnostics:ReadOnlyArray<Diagnostic<Any>>;
}>>
enum abstract CompletionModeKind<T>(Int) {
var Field:CompletionModeKind<FieldCompletionSubject<Dynamic>>;
var StructureField;
@ -542,6 +572,20 @@ typedef SignatureItem = {
typedef SignatureHelpResult = Response<Null<SignatureItem>>;
typedef MetadataParams = {
var compiler:Bool;
var user:Bool;
}
typedef MetadataResult = Response<Array<Metadata>>;
typedef DefinesParams = {
var compiler:Bool;
var user:Bool;
}
typedef DefinesResult = Response<Array<Define>>;
/** General types **/
typedef PositionParams = FileParams & {
/** Unicode character offset in the file. **/

View File

@ -163,6 +163,7 @@ enum abstract JsonBinopKind<T>(String) {
var OpInterval;
var OpArrow;
var OpIn;
var OpNullCoal;
}
typedef JsonBinop<T> = {

View File

@ -41,6 +41,7 @@ class ServerMethods {
static inline var ModuleMemory = new HaxeRequestMethod<ModuleParams, Response<HaxeModuleMemoryResult>>("server/memory/module");
static inline var Modules = new HaxeRequestMethod<ContextParams, Response<Array<String>>>("server/modules");
static inline var Module = new HaxeRequestMethod<ModuleParams, Response<JsonModule>>("server/module");
static inline var Type = new HaxeRequestMethod<TypeParams, Response<JsonModuleType<Any>>>("server/type");
static inline var Files = new HaxeRequestMethod<ContextParams, Response<Array<JsonServerFile>>>("server/files");
static inline var ModuleCreated = new HaxeRequestMethod<FileParams, Response<NoData>>("server/moduleCreated");
}
@ -97,7 +98,9 @@ typedef JsonModule = {
final types:Array<JsonTypePath>;
final file:String;
final sign:String;
final dirty:Null<String>;
final dependencies:Array<ModuleId>;
final dependents:Array<ModuleId>;
}
typedef JsonServerFile = {
@ -108,7 +111,6 @@ typedef JsonServerFile = {
}
/* Memory */
typedef HaxeMemoryResult = {
final contexts:Array<{
final context:HaxeServerContext;
@ -165,3 +167,8 @@ typedef ContextParams = {
typedef ModuleParams = ContextParams & {
final path:String;
}
typedef TypeParams = ContextParams & {
final modulePath:String;
final typeName:String;
}

View File

@ -227,7 +227,7 @@ class BalancedTree<K, V> implements haxe.Constraints.IMap<K, V> {
}
public function toString() {
return root == null ? '{}' : '{${root.toString()}}';
return root == null ? "[]" : '[${root.toString()}]';
}
/**
@ -264,6 +264,6 @@ class TreeNode<K, V> {
return this == null ? 0 : _height;
public function toString() {
return (left == null ? "" : left.toString() + ", ") + '$key=$value' + (right == null ? "" : ", " + right.toString());
return (left == null ? "" : left.toString() + ", ") + '$key => $value' + (right == null ? "" : ", " + right.toString());
}
}

View File

@ -33,11 +33,25 @@ class EnumValueMap<K:EnumValue, V> extends haxe.ds.BalancedTree<K, V> implements
var d = k1.getIndex() - k2.getIndex();
if (d != 0)
return d;
#if hl
var a1 = @:privateAccess Type._enumParameters(k1);
var a2 = @:privateAccess Type._enumParameters(k2);
var ld = a1.length - a2.length;
if (ld != 0)
return ld;
for (i in 0...a1.length) {
var d = compareArg(a1[i], a2[i]);
if (d != 0)
return d;
}
return 0;
#else
var p1 = k1.getParameters();
var p2 = k2.getParameters();
if (p1.length == 0 && p2.length == 0)
return 0;
return compareArgs(p1, p2);
#end
}
function compareArgs(a1:Array<Dynamic>, a2:Array<Dynamic>):Int {

View File

@ -24,9 +24,7 @@ package haxe.ds;
import haxe.ds.StringMap;
import haxe.ds.IntMap;
import haxe.ds.HashMap;
import haxe.ds.ObjectMap;
import haxe.ds.WeakMap;
import haxe.ds.EnumValueMap;
import haxe.Constraints.IMap;

View File

@ -41,7 +41,7 @@ private typedef VectorData<T> =
eval.Vector<T>
#else
Array<T>
#end
#end;
/**
A Vector is a storage of fixed size. It can be faster than Array on some
@ -61,7 +61,7 @@ abstract Vector<T>(VectorData<T>) {
If `length` is less than or equal to 0, the result is unspecified.
**/
public inline function new(length:Int) {
extern overload public inline function new(length:Int) {
#if flash10
this = new flash.Vector<T>(length, true);
#elseif neko
@ -75,7 +75,7 @@ abstract Vector<T>(VectorData<T>) {
#elseif cpp
this = NativeArray.create(length);
#elseif python
this = python.Syntax.code("[{0}]*{1}", null, length);
this = python.Syntax.code("([{0}]*{1})", null, length);
#elseif lua
this = untyped __lua_table__({length: length});
#elseif eval
@ -86,6 +86,43 @@ abstract Vector<T>(VectorData<T>) {
#end
}
/**
Creates a new Vector of length `length` filled with `defaultValue` elements.
Can be faster than `new Vector(length)` for iteration on some targets for non-nullable elements.
If `length` is less than or equal to 0, the result is unspecified.
**/
extern overload public inline function new(length:Int, defaultValue:T):Vector<T> {
#if js
this = [for (_ in 0...length) defaultValue];
#elseif python
this = python.Syntax.code("([{0}]*{1})", defaultValue, length);
#else
#if flash10
this = new flash.Vector<T>(length, true);
#elseif neko
this = untyped __dollar__amake(length);
#elseif cs
this = new cs.NativeArray(length);
#elseif java
this = new java.NativeArray(length);
#elseif cpp
this = NativeArray.create(length);
#elseif lua
this = untyped __lua_table__({length: length});
#elseif eval
this = new eval.Vector(length);
#else
this = [];
untyped this.length = length;
#end
fill(defaultValue);
#end
}
/**
Returns the value at index `index`.
@ -141,6 +178,12 @@ abstract Vector<T>(VectorData<T>) {
#end
}
/**
Sets all `length` elements of `this` Vector to `value`.
**/
public inline function fill(value:T):Void
for (i in 0...length) this[i] = value;
/**
Copies `length` of elements from `src` Vector, beginning at `srcPos` to
`dest` Vector, beginning at `destPos`

View File

@ -128,8 +128,8 @@ class JsonPrinter {
} else
classString(v);
case TEnum(_):
var i:Dynamic = Type.enumIndex(v);
add(i);
var i = Type.enumIndex(v);
add(Std.string(i));
case TBool:
add(#if (php || jvm || hl) (v ? 'true' : 'false') #else v #end);
case TNull:
@ -165,16 +165,15 @@ class JsonPrinter {
function fieldsString(v:Dynamic, fields:Array<String>) {
addChar('{'.code);
var len = fields.length;
var last = len - 1;
var first = true;
var empty = true;
for (i in 0...len) {
var f = fields[i];
var value = Reflect.field(v, f);
if (Reflect.isFunction(value))
continue;
if (first) {
if (empty) {
nind++;
first = false;
empty = false;
} else
addChar(','.code);
newl();
@ -184,11 +183,11 @@ class JsonPrinter {
if (pretty)
addChar(' '.code);
write(f, value);
if (i == last) {
nind--;
newl();
ipad();
}
}
if (!empty) {
nind--;
newl();
ipad();
}
addChar('}'.code);
}

View File

@ -30,6 +30,7 @@ import haxe.io.Bytes;
class HttpJs extends haxe.http.HttpBase {
public var async:Bool;
public var withCredentials:Bool;
public var responseHeaders:Map<String, String>;
var req:js.html.XMLHttpRequest;
@ -53,6 +54,7 @@ class HttpJs extends haxe.http.HttpBase {
public override function request(?post:Bool) {
this.responseAsString = null;
this.responseBytes = null;
this.responseHeaders = null;
var r = req = js.Browser.createXMLHttpRequest();
var onreadystatechange = function(_) {
if (r.readyState != 4)
@ -73,6 +75,21 @@ class HttpJs extends haxe.http.HttpBase {
onStatus(s);
if (s != null && s >= 200 && s < 400) {
req = null;
// split headers and remove the last \r\n\r\n
var headers = r.getAllResponseHeaders().split('\r\n');
headers = headers.filter(h -> h != '');
// store response headers
responseHeaders = new haxe.ds.StringMap();
for (hline in headers) {
var a = hline.split(": ");
var hname = a.shift();
var hval = if (a.length == 1) a[0] else a.join(": ");
hval = StringTools.ltrim(StringTools.rtrim(hval));
responseHeaders.set(hname, hval);
}
success(Bytes.ofData(r.response));
} else if (s == null || (s == 0 && r.response == null)) {
req = null;

View File

@ -27,6 +27,8 @@ import js.node.Buffer;
import haxe.io.Bytes;
class HttpNodeJs extends haxe.http.HttpBase {
public var responseHeaders:Map<String, String>;
var req:js.node.http.ClientRequest;
public function new(url:String) {
@ -47,6 +49,7 @@ class HttpNodeJs extends haxe.http.HttpBase {
public override function request(?post:Bool) {
responseAsString = null;
responseBytes = null;
responseHeaders = null;
var parsedUrl = new js.node.url.URL(url);
var secure = (parsedUrl.protocol == "https:");
var host = parsedUrl.hostname;
@ -97,6 +100,14 @@ class HttpNodeJs extends haxe.http.HttpBase {
var buf = (data.length == 1 ? data[0] : Buffer.concat(data));
responseBytes = Bytes.ofData(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
req = null;
// store response headers
responseHeaders = new haxe.ds.StringMap();
for (field in Reflect.fields(res.headers))
{
responseHeaders.set(field, Reflect.field(res.headers, field));
}
if (s != null && s >= 200 && s < 400) {
success(responseBytes);
} else {

View File

@ -318,4 +318,5 @@ enum abstract Mime(String) from String to String {
var ApplicationXCompress = 'application/x-compress';
var MultipartXZip = 'multipart/x-zip';
var TextXScriptZsh = 'text/x-script.zsh';
var ImageAvif = 'image/avif';
}

View File

@ -27,18 +27,15 @@ class ArrayKeyValueIterator<T> {
var current:Int = 0;
var array:Array<T>;
#if !hl inline #end
public function new(array:Array<T>) {
public inline function new(array:Array<T>) {
this.array = array;
}
#if !hl inline #end
public function hasNext():Bool {
public inline function hasNext():Bool {
return current < array.length;
}
#if !hl inline #end
public function next():{key:Int,value:T} {
public inline function next():{key:Int,value:T} {
return {value:array[current], key:current++};
}
}

View File

@ -52,6 +52,10 @@ enum abstract ModuleCheckPolicy(Int) {
of the current module file.
**/
var NoCheckShadowing = 3;
/**
Retype the module's contents if its file is invalidated. This is currently experimental.
**/
var Retype = 4;
}
enum abstract ContextOptions(Int) {
@ -97,7 +101,9 @@ class CompilationServer {
**/
static public function setModuleCheckPolicy(pathFilters:Array<String>, policy:Array<ModuleCheckPolicy>, ?recursive = true,
?contextOptions:ContextOptions = NormalContext) {
@:privateAccess Compiler.load("server_add_module_check_policy", 4)(pathFilters, policy, recursive, contextOptions);
Context.onAfterInitMacros(() -> {
@:privateAccess Compiler.load("server_add_module_check_policy", 4)(pathFilters, policy, recursive, contextOptions);
});
}
/**

View File

@ -22,6 +22,7 @@
package haxe.macro;
import haxe.display.Display;
import haxe.macro.Expr;
/**
@ -69,13 +70,16 @@ class Compiler {
**/
public static function define(flag:String, ?value:String) {
#if (neko || eval)
Context.assertInitMacro();
load("define", 2)(flag, value);
#end
}
#if (!neko && !eval)
@:deprecated("Will be removed in Haxe 5.0")
private static function typePatch(cl:String, f:String, stat:Bool, t:String) {}
@:deprecated("Will be removed in Haxe 5.0")
private static function metaPatch(meta:String, cl:String, f:String, stat:Bool) {}
private static function addGlobalMetadataImpl(pathFilter:String, meta:String, recursive:Bool, toTypes:Bool, toFields:Bool) {}
@ -85,13 +89,18 @@ class Compiler {
Removes a (static) field from a given class by name.
An error is thrown when `className` or `field` is invalid.
**/
@:deprecated("Will be removed in Haxe 5.0")
public static function removeField(className:String, field:String, ?isStatic:Bool) {
if (!path.match(className))
throw "Invalid " + className;
if (!ident.match(field))
throw "Invalid " + field;
#if (neko || eval)
#if haxe_next
Context.onAfterInitMacros(() -> load("type_patch", 4)(className, field, isStatic == true, null));
#else
load("type_patch", 4)(className, field, isStatic == true, null);
#end
#else
typePatch(className, field, isStatic == true, null);
#end
@ -101,13 +110,18 @@ class Compiler {
Set the type of a (static) field at a given class by name.
An error is thrown when `className` or `field` is invalid.
**/
@:deprecated("Will be removed in Haxe 5.0")
public static function setFieldType(className:String, field:String, type:String, ?isStatic:Bool) {
if (!path.match(className))
throw "Invalid " + className;
if (!ident.match((field.charAt(0) == "$") ? field.substr(1) : field))
throw "Invalid " + field;
#if (neko || eval)
#if haxe_next
Context.onAfterInitMacros(() -> load("type_patch", 4)(className, field, isStatic == true, type));
#else
load("type_patch", 4)(className, field, isStatic == true, type);
#end
#else
typePatch(className, field, isStatic == true, type);
#end
@ -117,13 +131,18 @@ class Compiler {
Add metadata to a (static) field or class by name.
An error is thrown when `className` or `field` is invalid.
**/
@:deprecated
public static function addMetadata(meta:String, className:String, ?field:String, ?isStatic:Bool) {
if (!path.match(className))
throw "Invalid " + className;
if (field != null && !ident.match(field))
throw "Invalid " + field;
#if (neko || eval)
#if haxe_next
Context.onAfterInitMacros(() -> load("meta_patch", 4)(meta, className, field, isStatic == true));
#else
load("meta_patch", 4)(meta, className, field, isStatic == true);
#end
#else
metaPatch(meta, className, field, isStatic == true);
#end
@ -136,6 +155,7 @@ class Compiler {
**/
public static function addClassPath(path:String) {
#if (neko || eval)
Context.assertInitMacro();
load("add_class_path", 1)(path);
#end
}
@ -162,6 +182,19 @@ class Compiler {
#end
}
/**
Returns all the configuration settings applied to the compiler.
Usage of this function outside a macro context returns `null`.
**/
public static function getConfiguration():Null<CompilerConfiguration> {
#if (neko || eval)
return load("get_configuration", 0)();
#else
return null;
#end
}
/**
Adds a native library depending on the platform (e.g. `-swf-lib` for Flash).
@ -169,6 +202,7 @@ class Compiler {
**/
public static function addNativeLib(name:String) {
#if (neko || eval)
Context.assertInitMacro();
load("add_native_lib", 1)(name);
#end
}
@ -192,6 +226,8 @@ class Compiler {
If you want to specify a different set of paths to search for modules, you can use the optional
argument `classPath`.
Usage of this function outside of initialization macros is deprecated and may cause compilation server issues.
@param pack The package dot-path as String. Use `''` to include the root package.
@param rec If true, recursively adds all sub-packages.
@param ignore Array of module names to ignore for inclusion.
@ -201,69 +237,74 @@ class Compiler {
@param strict If true and given package wasn't found in any of class paths, fail with an error.
**/
public static function include(pack:String, ?rec = true, ?ignore:Array<String>, ?classPaths:Array<String>, strict = false) {
var ignoreWildcard:Array<String> = [];
var ignoreString:Array<String> = [];
if (ignore != null) {
for (ignoreRule in ignore) {
if (StringTools.endsWith(ignoreRule, "*")) {
ignoreWildcard.push(ignoreRule.substr(0, ignoreRule.length - 1));
} else {
ignoreString.push(ignoreRule);
function include(pack:String, ?rec = true, ?ignore:Array<String>, ?classPaths:Array<String>, strict = false) {
var ignoreWildcard:Array<String> = [];
var ignoreString:Array<String> = [];
if (ignore != null) {
for (ignoreRule in ignore) {
if (StringTools.endsWith(ignoreRule, "*")) {
ignoreWildcard.push(ignoreRule.substr(0, ignoreRule.length - 1));
} else {
ignoreString.push(ignoreRule);
}
}
}
}
var skip = if (ignore == null) {
function(c) return false;
} else {
function(c:String) {
if (Lambda.has(ignoreString, c))
return true;
for (ignoreRule in ignoreWildcard)
if (StringTools.startsWith(c, ignoreRule))
var skip = if (ignore == null) {
function(c) return false;
} else {
function(c:String) {
if (Lambda.has(ignoreString, c))
return true;
return false;
for (ignoreRule in ignoreWildcard)
if (StringTools.startsWith(c, ignoreRule))
return true;
return false;
}
}
var displayValue = Context.definedValue("display");
if (classPaths == null) {
classPaths = Context.getClassPath();
// do not force inclusion when using completion
switch (displayValue) {
case null:
case "usage":
case _:
return;
}
// normalize class path
for (i in 0...classPaths.length) {
var cp = StringTools.replace(classPaths[i], "\\", "/");
if (StringTools.endsWith(cp, "/"))
cp = cp.substr(0, -1);
if (cp == "")
cp = ".";
classPaths[i] = cp;
}
}
var prefix = pack == '' ? '' : pack + '.';
var found = false;
for (cp in classPaths) {
var path = pack == '' ? cp : cp + "/" + pack.split(".").join("/");
if (!sys.FileSystem.exists(path) || !sys.FileSystem.isDirectory(path))
continue;
found = true;
for (file in sys.FileSystem.readDirectory(path)) {
if (StringTools.endsWith(file, ".hx") && file.substr(0, file.length - 3).indexOf(".") < 0) {
if( file == "import.hx" ) continue;
var cl = prefix + file.substr(0, file.length - 3);
if (skip(cl))
continue;
Context.getModule(cl);
} else if (rec && sys.FileSystem.isDirectory(path + "/" + file) && !skip(prefix + file))
include(prefix + file, true, ignore, classPaths);
}
}
if (strict && !found)
Context.error('Package "$pack" was not found in any of class paths', Context.currentPos());
}
var displayValue = Context.definedValue("display");
if (classPaths == null) {
classPaths = Context.getClassPath();
// do not force inclusion when using completion
switch (displayValue) {
case null:
case "usage":
case _:
return;
}
// normalize class path
for (i in 0...classPaths.length) {
var cp = StringTools.replace(classPaths[i], "\\", "/");
if (StringTools.endsWith(cp, "/"))
cp = cp.substr(0, -1);
if (cp == "")
cp = ".";
classPaths[i] = cp;
}
}
var prefix = pack == '' ? '' : pack + '.';
var found = false;
for (cp in classPaths) {
var path = pack == '' ? cp : cp + "/" + pack.split(".").join("/");
if (!sys.FileSystem.exists(path) || !sys.FileSystem.isDirectory(path))
continue;
found = true;
for (file in sys.FileSystem.readDirectory(path)) {
if (StringTools.endsWith(file, ".hx") && file.substr(0, file.length - 3).indexOf(".") < 0) {
if( file == "import.hx" ) continue;
var cl = prefix + file.substr(0, file.length - 3);
if (skip(cl))
continue;
Context.getModule(cl);
} else if (rec && sys.FileSystem.isDirectory(path + "/" + file) && !skip(prefix + file))
include(prefix + file, true, ignore, classPaths);
}
}
if (strict && !found)
Context.error('Package "$pack" was not found in any of class paths', Context.currentPos());
Context.assertInitMacro();
Context.onAfterInitMacros(() -> include(pack, rec, ignore, classPaths, strict));
}
/**
@ -340,6 +381,7 @@ class Compiler {
/**
Load a type patch file that can modify the field types within declared classes and enums.
**/
@:deprecated("Will be removed in Haxe 5.0")
public static function patchTypes(file:String):Void {
var file = Context.resolvePath(file);
var f = sys.io.File.read(file, true);
@ -450,6 +492,44 @@ class Compiler {
#end
}
/**
Reference a json file describing user-defined metadata
See https://github.com/HaxeFoundation/haxe/blob/development/src-json/meta.json
**/
public static function registerMetadataDescriptionFile(path:String, ?source:String):Void {
var f = sys.io.File.getContent(path);
var content:Array<MetadataDescription> = haxe.Json.parse(f);
for (m in content) registerCustomMetadata(m, source);
}
/**
Reference a json file describing user-defined defines
See https://github.com/HaxeFoundation/haxe/blob/development/src-json/define.json
**/
public static function registerDefinesDescriptionFile(path:String, ?source:String):Void {
var f = sys.io.File.getContent(path);
var content:Array<DefineDescription> = haxe.Json.parse(f);
for (d in content) registerCustomDefine(d, source);
}
/**
Register a custom medatada for documentation and completion purposes
**/
public static function registerCustomMetadata(meta:MetadataDescription, ?source:String):Void {
#if (neko || eval)
load("register_metadata_impl", 2)(meta, source);
#end
}
/**
Register a custom define for documentation purposes
**/
public static function registerCustomDefine(define:DefineDescription, ?source:String):Void {
#if (neko || eval)
load("register_define_impl", 2)(define, source);
#end
}
/**
Change the default JS output by using a custom generator callback
**/
@ -577,3 +657,108 @@ enum abstract NullSafetyMode(String) to String {
**/
var StrictThreaded;
}
typedef MetadataDescription = {
final metadata:String;
final doc:String;
/**
External resources for more information about this metadata.
**/
@:optional final links:Array<String>;
/**
List (small description) of parameters that this metadata accepts.
**/
@:optional final params:Array<String>;
/**
Haxe target(s) for which this metadata is used.
**/
@:optional final platforms:Array<Platform>;
/**
Places where this metadata can be applied.
**/
@:optional final targets:Array<MetadataTarget>;
}
typedef DefineDescription = {
final define:String;
final doc:String;
/**
External resources for more information about this define.
**/
@:optional final links:Array<String>;
/**
List (small description) of parameters that this define accepts.
**/
@:optional final params:Array<String>;
/**
Haxe target(s) for which this define is used.
**/
@:optional final platforms:Array<Platform>;
}
typedef CompilerConfiguration = {
/**
The version integer of the current Haxe compiler build.
**/
final version:Int;
/**
Returns an array of the arguments passed to the compiler from either the `.hxml` file or the command line.
**/
final args:Array<String>;
/**
If `--debug` mode is enabled, this is `true`.
**/
final debug:Bool;
/**
If `--verbose` mode is enabled, this is `true`.
**/
final verbose:Bool;
/**
If `--no-opt` is enabled, this is `false`.
**/
final foptimize:Bool;
/**
The target platform.
**/
final platform:haxe.display.Display.Platform;
/**
The compilation configuration for the target platform.
**/
final platformConfig:PlatformConfig;
/**
A list of paths being used for the standard library.
**/
final stdPath:Array<String>;
/**
The path of the class passed using the `-main` argument.
**/
final mainClass:TypePath;
/**
Special access rules for packages depending on the compiler configuration.
For example, the "java" package is "Forbidden" when the target platform is Python.
**/
final packageRules:Map<String,PackageRule>;
}
enum PackageRule {
Forbidden;
Directory(path:String);
Remap(path:String);
}

View File

@ -39,7 +39,7 @@ class ComplexTypeTools {
static public function toString(c:ComplexType):String
return new Printer().printComplexType(c);
#if (macro || display)
#if macro
/**
Returns a type corresponding to `c`.

View File

@ -47,45 +47,61 @@ class Context {
Displays a compilation error `msg` at the given `Position` `pos`
and aborts the current macro call.
**/
public static function error(msg:String, pos:Position):Dynamic {
return load("error", 2)(msg, pos);
public static function error(msg:String, pos:Position, ?depth:Int = 0):Dynamic {
return load("error", 2)(msg, pos, depth);
}
/**
Displays a compilation error `msg` at the given `Position` `pos`
and aborts the compilation.
**/
public static function fatalError(msg:String, pos:Position):Dynamic {
return load("fatal_error", 2)(msg, pos);
public static function fatalError(msg:String, pos:Position, ?depth:Int = 0):Dynamic {
return load("fatal_error", 2)(msg, pos, depth);
}
/**
Displays a compilation error `msg` at the given `Position` `pos`
without aborting the current macro call.
**/
public static function reportError(msg:String, pos:Position, ?depth:Int = 0):Void {
load("report_error", 2)(msg, pos, depth);
}
/**
Displays a compilation warning `msg` at the given `Position` `pos`.
**/
public static function warning(msg:String, pos:Position) {
load("warning", 2)(msg, pos);
public static function warning(msg:String, pos:Position, ?depth:Int = 0) {
load("warning", 2)(msg, pos, depth);
}
/**
Displays a compilation info `msg` at the given `Position` `pos`.
**/
public static function info(msg:String, pos:Position) {
load("info", 2)(msg, pos);
public static function info(msg:String, pos:Position, ?depth:Int = 0) {
load("info", 2)(msg, pos, depth);
}
/**
Gets a list of all current compilation info/warning messages.
**/
public static function getMessages() : Array<Message> {
return load("get_messages",0)();
public static function getMessages():Array<Message> {
return load("get_messages", 0)();
}
/**
Filters all current info/warning messages. Filtered out messages will
not be displayed by the compiler.
**/
public static function filterMessages( predicate : Message -> Bool ) {
load("filter_messages",1)(predicate);
public static function filterMessages(predicate:Message->Bool) {
load("filter_messages", 1)(predicate);
}
/**
Check if compiler is past initializations macros or not.
When it is, configuration phase is over and parsing/typing can start.
**/
public static function initMacrosDone():Bool {
return load("init_macros_done", 0)();
}
/**
@ -119,6 +135,10 @@ class Context {
return load("contains_display_position", 1)(pos);
}
public static function getDisplayMode():DisplayMode {
return load("get_display_mode", 0)();
}
/**
Returns the position at which the macro was called.
**/
@ -126,6 +146,14 @@ class Context {
return load("current_pos", 0)();
}
/**
Get the call stack (excluding the call to `Context.getMacroStack()`
that led to current macro.
**/
public static function getMacroStack():Array<Position> {
return load("get_macro_stack", 0)();
}
/**
Returns the type which is expected at the place the macro is called.
@ -136,6 +164,7 @@ class Context {
macro is not an expression-macro.
**/
public static function getExpectedType():Null<Type> {
assertInitMacrosDone(false);
return load("get_expected_type", 0)();
}
@ -146,6 +175,7 @@ class Context {
Returns `null` if the current macro is not a `@:genericBuild` macro.
**/
public static function getCallArguments():Null<Array<Expr>> {
assertInitMacrosDone(false);
return load("get_call_arguments", 0)();
}
@ -155,6 +185,7 @@ class Context {
If no such class exists, `null` is returned.
**/
public static function getLocalClass():Null<Type.Ref<Type.ClassType>> {
assertInitMacrosDone(false);
var l:Type = load("get_local_type", 0)();
if (l == null)
return null;
@ -168,6 +199,7 @@ class Context {
Returns the current module path in/on which the macro was called.
**/
public static function getLocalModule():String {
assertInitMacrosDone(false);
return load("get_local_module", 0)();
}
@ -177,6 +209,7 @@ class Context {
If no such type exists, `null` is returned.
**/
public static function getLocalType():Null<Type> {
assertInitMacrosDone(false);
return load("get_local_type", 0)();
}
@ -186,6 +219,7 @@ class Context {
If no such method exists, `null` is returned.
**/
public static function getLocalMethod():Null<String> {
assertInitMacrosDone(false);
return load("get_local_method", 0)();
}
@ -196,6 +230,7 @@ class Context {
Modifying the returned array has no effect on the compiler.
**/
public static function getLocalUsing():Array<Type.Ref<Type.ClassType>> {
assertInitMacrosDone(false);
return load("get_local_using", 0)();
}
@ -205,6 +240,7 @@ class Context {
Modifying the returned array has no effect on the compiler.
**/
public static function getLocalImports():Array<ImportExpr> {
assertInitMacrosDone(false);
return load("get_local_imports", 0)();
}
@ -219,6 +255,7 @@ class Context {
**/
@:deprecated("Use Context.getLocalTVars() instead")
public static function getLocalVars():Map<String, Type> {
assertInitMacrosDone(false);
return load("local_vars", 1)(false);
}
@ -227,6 +264,7 @@ class Context {
of `Type`.
**/
public static function getLocalTVars():Map<String, Type.TVar> {
assertInitMacrosDone(false);
return load("local_vars", 1)(true);
}
@ -279,8 +317,13 @@ class Context {
declared class path has priority.
If no type can be found, an exception of type `String` is thrown.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function getType(name:String):Type {
assertInitMacrosDone();
return load("get_type", 1)(name);
}
@ -292,11 +335,44 @@ class Context {
declared class path has priority.
If no module can be found, an exception of type `String` is thrown.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function getModule(name:String):Array<Type> {
assertInitMacrosDone();
return load("get_module", 1)(name);
}
/**
Returns the typed expression of the call to the main function.
This function will only work in the generation phase. Any calls
made outside a function passed to `haxe.macro.Context.onGenerate`
or `haxe.macro.Context.onAfterGenerate` will return `null`.
**/
public static function getMainExpr():Null<TypedExpr> {
return load("get_main_expr", 0)();
}
/**
Returns an array of module types to be generated in the output.
This list may change depending on the phase of compilation and
should not be treated as conclusive until the generation phase.
Modifying the returned array has no effect on the compilation.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function getAllModuleTypes():Array<haxe.macro.Type.ModuleType> {
assertInitMacrosDone();
return load("get_module_types", 0)();
}
/**
Parses `expr` as Haxe code, returning the corresponding AST.
@ -334,6 +410,7 @@ class Context {
Returns a hashed MD5 signature of value `v`.
**/
public static function signature(v:Dynamic):String {
assertInitMacrosDone(false);
return load("signature", 1)(v);
}
@ -382,6 +459,22 @@ class Context {
load("on_after_typing", 1)(callback);
}
/**
Adds a callback function `callback` which is invoked after the compiler
is done running initialization macros, when typing begins.
`onAfterInitMacros` should be used to delay typer-dependant code from
your initalization macros, to properly separate configuration phase and
actual typing.
**/
public static function onAfterInitMacros(callback:Void->Void):Void {
if (Context.initMacrosDone()) {
callback();
} else {
load("on_after_init_macros", 1)(callback);
}
}
/**
Adds a callback function `callback` which is invoked when a type name
cannot be resolved.
@ -399,8 +492,13 @@ class Context {
Typing the expression may result in a compiler error which can be
caught using `try ... catch`.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function typeof(e:Expr):Type {
assertInitMacrosDone();
return load("typeof", 1)(e);
}
@ -408,9 +506,17 @@ class Context {
Types expression `e` and returns the corresponding `TypedExpr`.
Typing the expression may result in a compiler error which can be
caught using `try ... catch`.
caught using `try ... catch`. Note that not all compiler errors can
be caught this way because the compiler might delay various checks
to a later stage, at which point the exception handler is no longer
active.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function typeExpr(e:Expr):TypedExpr {
assertInitMacrosDone();
return load("type_expr", 1)(e);
}
@ -420,8 +526,13 @@ class Context {
Resolving the type may result in a compiler error which can be
caught using `try ... catch`.
Resolution is performed based on the current context in which the macro is called.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function resolveType(t:ComplexType, p:Position):Type {
assertInitMacrosDone();
return load("resolve_type", 2)(t, p);
}
@ -436,8 +547,13 @@ class Context {
/**
Tries to unify `t1` and `t2` and returns `true` if successful.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function unify(t1:Type, t2:Type):Bool {
assertInitMacrosDone();
return load("unify", 2)(t1, t2);
}
@ -445,8 +561,13 @@ class Context {
Follows a type.
See `haxe.macro.TypeTools.follow` for details.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function follow(t:Type, ?once:Bool):Type {
assertInitMacrosDone();
return load("follow", 2)(t, once);
}
@ -454,8 +575,13 @@ class Context {
Follows a type, including abstracts' underlying implementation
See `haxe.macro.TypeTools.followWithAbstracts` for details.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function followWithAbstracts(t:Type, once:Bool = false):Type {
assertInitMacrosDone();
return load("follow_with_abstracts", 2)(t, once);
}
@ -505,6 +631,7 @@ class Context {
This is only defined for `@:build/@:autoBuild` macros.
**/
public static function getBuildFields():Array<Field> {
assertInitMacrosDone(false);
return load("get_build_fields", 0)();
}
@ -514,11 +641,31 @@ class Context {
If `moduleDependency` is given and is not `null`, it should contain
a module path that will be used as a dependency for the newly defined module
instead of the current module.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function defineType(t:TypeDefinition, ?moduleDependency:String):Void {
assertInitMacrosDone();
load("define_type", 2)(t, moduleDependency);
}
/**
Creates and returns a new instance of monomorph (`TMono`) type.
Returned monomorph can be used with e.g. `Context.unify` to make the compiler
bind the monomorph to an actual type and let macro further process the resulting type.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function makeMonomorph():Type {
assertInitMacrosDone();
return load("make_monomorph", 0)();
}
/**
Defines a new module as `modulePath` with several `TypeDefinition`
`types`. This is analogous to defining a .hx file.
@ -526,12 +673,17 @@ class Context {
The individual `types` can reference each other and any identifier
respects the `imports` and `usings` as usual, expect that imports are
not allowed to have `.*` wildcards or `as s` shorthands.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function defineModule(modulePath:String, types:Array<TypeDefinition>, ?imports:Array<ImportExpr>, ?usings:Array<TypePath>):Void {
if (imports == null)
imports = [];
if (usings == null)
usings = [];
assertInitMacrosDone();
load("define_module", 4)(modulePath, types, imports, usings);
}
@ -539,8 +691,13 @@ class Context {
Returns a syntax-level expression corresponding to typed expression `t`.
This process may lose some information.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function getTypedExpr(t:Type.TypedExpr):Expr {
assertInitMacrosDone();
return load("get_typed_expr", 1)(t);
}
@ -555,8 +712,13 @@ class Context {
that is reset between compilations, so care should be taken when storing
the expression returned by this method in a static variable and using the
compilation server.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function storeTypedExpr(t:Type.TypedExpr):Expr {
assertInitMacrosDone();
return load("store_typed_expr", 1)(t);
}
@ -574,11 +736,29 @@ class Context {
that is reset between compilations, so care should be taken when storing
the expression returned by this method in a static variable and using the
compilation server.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function storeExpr(e:Expr):Expr {
assertInitMacrosDone();
return load("store_expr", 1)(e);
}
/**
This function works like `storeExpr`, but also returns access to the expression's
type through the `type` field of the return value.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function typeAndStoreExpr(e:Expr):{final type:Type.Ref<Type>; final expr:Expr;} {
assertInitMacrosDone();
return load("type_and_store_expr", 1)(e);
}
/**
Manually adds a dependency between module `modulePath` and an external
file `externFile`.
@ -587,9 +767,13 @@ class Context {
`externFile` has changed.
Has no effect if the compilation cache is not used.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function registerModuleDependency(modulePath:String, externFile:String) {
load("register_module_dependency", 2)(modulePath, externFile);
onAfterInitMacros(() -> load("register_module_dependency", 2)(modulePath, externFile));
}
/**
@ -606,10 +790,47 @@ class Context {
stopTimer();
```
**/
public static function timer(id:String):()->Void {
public static function timer(id:String):() -> Void {
return load("timer", 1)(id);
}
/**
Executes `code` in a context that has `imports` and `usings` added.
This is equivalent to temporarily having `import` and `using` statements in a file. These
are only active during the execution of `code` and do not affect anything afterwards. This
is true even if `code` throws an exception.
If any argument is `null`, the result is unspecified.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function withImports<X>(imports:Array<String>, usings:Array<String>, code:() -> X):X {
assertInitMacrosDone();
return load("with_imports", 3)(imports, usings, code);
}
/**
Executes `code` in a context that has some compiler options set, restore the compiler to its
default behavior afterwards.
`allowInlining`: enable or disable inlining during typing with `typeExpr`.
`allowTransform`: when disabled, the code typed with `typeExpr` will be almost exactly the same
as the input code. This will disable some abstract types transformations.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function withOptions<X>(options:{?allowInlining:Bool,?allowTransform:Bool}, code : () -> X) : X {
assertInitMacrosDone();
return load("with_options", 2)(options, code);
}
@:deprecated
public static function registerModuleReuseCall(modulePath:String, macroCall:String) {
throw "This method is no longer supported. See https://github.com/HaxeFoundation/haxe/issues/5746";
@ -639,7 +860,36 @@ class Context {
}
private static function sExpr(e:TypedExpr, pretty:Bool):String {
return haxe.macro.Context.load("s_expr", 2)(e, pretty);
return load("s_expr", 2)(e, pretty);
}
@:allow(haxe.macro.Compiler)
private static function assertInitMacro():Void {
if (initMacrosDone()) {
var stack = getMacroStack();
warning(
"This API should only be used from initialization macros.",
if (stack.length > 2) stack[2] else currentPos()
);
}
}
@:allow(haxe.macro.Compiler)
private static function assertInitMacrosDone(includeSuggestion = true):Void {
#if haxe_next
if (!initMacrosDone()) {
var stack = getMacroStack();
var suggestion = includeSuggestion
? "\nUse `Context.onAfterInitMacros` to register a callback to run when context is ready."
: "";
warning(
"Cannot use this API from initialization macros." + suggestion,
if (stack.length > 2) stack[2] else currentPos()
);
}
#end
}
#end
}

View File

@ -0,0 +1,15 @@
package haxe.macro;
enum DisplayMode {
None;
Default;
Definition;
TypeDefinition;
Implementation;
Package;
Hover;
References(withDefinition:Bool, findDescendants:Bool, findBase:Bool);
ModuleSymbols;
WorkspaceSymbols(filter:String);
Signature;
}

View File

@ -231,7 +231,13 @@ class ExampleJSGenerator {
public function generate() {
print("var $_, $hxClasses = $hxClasses || {}, $estr = function() { return js.Boot.__string_rec(this,''); }");
newline();
print("function $bind(o,m) { var f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; return f; };");
print(
#if (js_es < 5)
"function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $global.$haxeUID++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; o.hx__closures__[m.__id__] = f; } return f; }"
#else
"function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $global.$haxeUID++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = m.bind(o); o.hx__closures__[m.__id__] = f; } return f; }"
#end
);
newline();
for (t in api.types)
genType(t);

View File

@ -60,12 +60,12 @@ enum Constant {
/**
Represents an integer literal.
**/
CInt(v:String);
CInt(v:String, ?s:String);
/**
Represents a float literal.
**/
CFloat(f:String);
CFloat(f:String, ?s:String);
/**
Represents a string literal.
@ -214,6 +214,11 @@ enum Binop {
`in`
**/
OpIn;
/**
`??`
**/
OpNullCoal;
}
/**
@ -252,6 +257,11 @@ enum Unop {
OpSpread;
}
enum EFieldKind {
Normal;
Safe;
}
/**
Represents a node in the AST.
@see https://haxe.org/manual/macro-reification-expression.html
@ -306,6 +316,11 @@ typedef Var = {
**/
var name:String;
/**
The position of the variable name.
**/
var ?namePos:Position;
/**
The type-hint of the variable, if available.
**/
@ -321,6 +336,11 @@ typedef Var = {
**/
var ?isFinal:Bool;
/**
Whether or not the variable is static.
**/
var ?isStatic:Bool;
/**
Metadata associatied with the variable, if available.
**/
@ -424,8 +444,10 @@ enum ExprDef {
/**
Field access on `e.field`.
If `kind` is null, it is equal to Normal.
**/
EField(e:Expr, field:String);
EField(e:Expr, field:String, ?kind:EFieldKind);
/**
Parentheses `(e)`.
@ -545,11 +567,6 @@ enum ExprDef {
**/
EDisplay(e:Expr, displayKind:DisplayKind);
/**
Used internally to provide completion.
**/
EDisplayNew(t:TypePath);
/**
A `(econd) ? eif : eelse` expression.
**/
@ -681,6 +698,11 @@ typedef TypeParamDecl = {
**/
var ?constraints:Array<ComplexType>;
/**
The optional default type of the type parameter.
**/
var ?defaultType:Null<ComplexType>;
/**
The optional parameters of the type parameter.
**/
@ -977,7 +999,7 @@ enum TypeDefKind {
/**
Represents an abstract kind.
**/
TDAbstract(tthis:Null<ComplexType>, ?from:Array<ComplexType>, ?to:Array<ComplexType>);
TDAbstract(tthis:Null<ComplexType>, ?flags:Array<AbstractFlag>, ?from:Array<ComplexType>, ?to:Array<ComplexType>);
/**
Represents a module-level field.
@ -985,6 +1007,28 @@ enum TypeDefKind {
TDField(kind:FieldType, ?access:Array<Access>); // ignore TypeDefinition.fields
}
/**
Represents an abstract flag.
**/
enum AbstractFlag {
/**
Indicates that this abstract is an `enum abstract`
**/
AbEnum;
/**
Indicates that this abstract can be assigned from `ct`.
This flag can be added several times to add multiple "from" types.
**/
AbFrom(ct:ComplexType);
/**
Indicates that this abstract can be assigned to `ct`.
This flag can be added several times to add multiple "to" types.
**/
AbTo(ct:ComplexType);
}
/**
This error can be used to handle or produce compilation errors in macros.
**/
@ -994,6 +1038,11 @@ class Error extends Exception {
**/
public var pos:Position;
/**
Child error messages, if any.
**/
private var childErrors:Array<Error>;
/**
Instantiates an error with given message and position.
**/

View File

@ -70,7 +70,7 @@ class ExprTools {
**/
static public function iter(e:Expr, f:Expr->Void):Void {
switch (e.expr) {
case EConst(_), EContinue, EBreak, EDisplayNew(_):
case EConst(_), EContinue, EBreak:
case EField(e, _), EParenthesis(e), EUntyped(e), EThrow(e), EDisplay(e, _), ECheckType(e, _), EUnop(_, _, e), ECast(e, _), EIs(e, _) | EMeta(_, e):
f(e);
case EArray(e1, e2), EWhile(e1, e2, _), EBinop(_, e1, e2), EFor(e1, e2):
@ -144,7 +144,7 @@ class ExprTools {
case EConst(_): e.expr;
case EArray(e1, e2): EArray(f(e1), f(e2));
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
case EField(e, field): EField(f(e), field);
case EField(e, field, kind): EField(f(e), field, kind);
case EParenthesis(e): EParenthesis(f(e));
case EObjectDecl(fields):
var ret = [];
@ -161,6 +161,8 @@ class ExprTools {
var v2:Var = {name: v.name, type: v.type, expr: opt(v.expr, f)};
if (v.isFinal != null)
v2.isFinal = v.isFinal;
if (v.isStatic != null)
v2.isStatic = v.isStatic;
ret.push(v2);
}
EVars(ret);
@ -176,7 +178,7 @@ class ExprTools {
case EDisplay(e, dk): EDisplay(f(e), dk);
case ETernary(econd, eif, eelse): ETernary(f(econd), f(eif), f(eelse));
case ECheckType(e, t): ECheckType(f(e), t);
case EDisplayNew(_), EContinue, EBreak:
case EContinue, EBreak:
e.expr;
case ETry(e, catches):
var ret = [];

View File

@ -32,7 +32,7 @@ import haxe.macro.Expr;
@:hlNative("macro")
#end
class MacroStringTools {
#if (macro || display)
#if macro
/**
Formats `String` `s` using the usual interpolation rules.

View File

@ -0,0 +1,206 @@
package haxe.macro;
import haxe.macro.Expr;
/**
Represents the internal structure generated with options assigned based on
the target platform.
Warning: `PlatformConfig` and the typedefs unique to its fields correspond to
compiler-internal data structures and might change in minor Haxe releases in
order to adapt to internal changes.
**/
typedef PlatformConfig = {
/**
Has a static type system, with not-nullable basic types (Int/Float/Bool)
**/
final staticTypeSystem:Bool;
/**
Has access to the "sys" package
**/
final sys:Bool;
/**
Captured variables handling (see before)
**/
final capturePolicy:CapturePolicy;
/**
When calling a method with optional args, do we replace the missing args with "null" constants
**/
final padNulls:Bool;
/**
Add a final return to methods not having one already - prevent some compiler warnings
**/
final addFinalReturn:Bool;
/**
Does the platform natively support overloaded functions
**/
final overloadFunctions:Bool;
/**
Can the platform use default values for non-nullable arguments
**/
final canSkipNonNullableArgument:Bool;
/**
Type paths that are reserved on the platform
**/
final reservedTypePaths:Array<TypePath>;
/**
Supports function == function
**/
final supportsFunctionEquality:Bool;
/**
Uses utf16 encoding with ucs2 api
**/
final usesUtf16:Bool;
/**
Target supports accessing `this` before calling `super(...)`
**/
final thisBeforeSuper:Bool;
/**
Target supports threads
**/
final supportsThreads:Bool;
/**
Target supports Unicode
**/
final supportsUnicode:Bool;
/**
Target supports rest arguments
**/
final supportsRestArgs:Bool;
/**
Exceptions handling config
**/
final exceptions:ExceptionsConfig;
/**
The scoping of local variables
**/
final scoping:VarScopingConfig;
/**
Target supports atomic operations via haxe.Atomic
**/
final supportsAtomics:Bool;
}
enum CapturePolicy {
/**
Do nothing, let the platform handle it
**/
None;
/**
Wrap all captured variables into a single-element array to allow modifications
**/
WrapRef;
/**
Similar to wrap ref, but will only apply to the locals that are declared in loops
**/
LoopVars;
}
typedef VarScopingConfig = {
final scope:VarScope;
final flags:Array<VarScopingFlags>;
}
enum VarScope {
FunctionScope;
BlockScope;
}
enum VarScopingFlags {
/**
Variables are hoisted in their scope
**/
VarHoisting;
/**
It's not allowed to shadow existing variables in a scope.
**/
NoShadowing;
/**
It's not allowed to shadow a `catch` variable.
**/
NoCatchVarShadowing;
/**
Local vars cannot have the same name as the current top-level package or
(if in the root package) current class name
**/
ReserveCurrentTopLevelSymbol;
/**
Local vars cannot have a name used for any top-level symbol
(packages and classes in the root package)
**/
ReserveAllTopLevelSymbols;
/**
Reserve all type-paths converted to "flat path" with `Path.flat_path`
**/
ReserveAllTypesFlat;
/**
List of names cannot be taken by local vars
**/
ReserveNames(names:Array<String>);
/**
Cases in a `switch` won't have blocks, but will share the same outer scope.
**/
SwitchCasesNoBlocks;
}
typedef ExceptionsConfig = {
/**
Base types which may be thrown from Haxe code without wrapping.
**/
final nativeThrows:Array<TypePath>;
/**
Base types which may be caught from Haxe code without wrapping.
**/
final nativeCatches:Array<TypePath>;
/**
Hint exceptions filter to avoid wrapping for targets, which can throw/catch any type
Ignored on targets with a specific native base type for exceptions.
**/
final avoidWrapping:Bool;
/**
Path of a native class or interface, which can be used for wildcard catches.
**/
final wildcardCatch:TypePath;
/**
Path of a native base class or interface, which can be thrown.
This type is used to cast `haxe.Exception.thrown(v)` calls to.
For example `throw 123` is compiled to `throw (cast Exception.thrown(123):ec_base_throw)`
**/
final baseThrow:TypePath;
/**
Checks if throwing this expression is a special case for current target
and should not be modified.
**/
// final specialThrow:(TypedExpr)->Bool;
}

View File

@ -60,7 +60,7 @@ class PositionTools {
#end
}
#if (macro || display)
#if macro
/**
Converts a `haxe.macro.Position` to a `haxe.display.Position.Location`.

View File

@ -75,13 +75,15 @@ class Printer {
case OpInterval: "...";
case OpArrow: "=>";
case OpIn: "in";
case OpNullCoal: "??";
case OpAssignOp(op):
printBinop(op) + "=";
}
function escapeString(s:String, delim:String) {
return delim
+ s.replace("\n", "\\n")
+ s.replace('\\', '\\\\')
.replace("\n", "\\n")
.replace("\t", "\\t")
.replace("\r", "\\r")
.replace("'", "\\'")
@ -100,8 +102,10 @@ class Printer {
return switch (c) {
case CString(s, SingleQuotes): printFormatString(s);
case CString(s, _): printString(s);
case CIdent(s), CInt(s), CFloat(s):
case CIdent(s), CInt(s, null), CFloat(s, null):
s;
case CInt(s, suffix), CFloat(s, suffix):
s + suffix;
case CRegexp(s, opt): '~/$s/$opt';
}
@ -192,7 +196,8 @@ class Printer {
return (tpd.meta != null && tpd.meta.length > 0 ? tpd.meta.map(printMetadata).join(" ") + " " : "")
+ tpd.name
+ (tpd.params != null && tpd.params.length > 0 ? "<" + tpd.params.map(printTypeParamDecl).join(", ") + ">" : "")
+ (tpd.constraints != null && tpd.constraints.length > 0 ? ":(" + tpd.constraints.map(printComplexType).join(", ") + ")" : "");
+ (tpd.constraints != null && tpd.constraints.length > 0 ? ":(" + tpd.constraints.map(printComplexType).join(", ") + ")" : "")
+ (tpd.defaultType != null ? "=" + printComplexType(tpd.defaultType) : "");
public function printFunctionArg(arg:FunctionArg)
return (arg.opt ? "?" : "") + arg.name + opt(arg.type, printComplexType, ":") + opt(arg.value, printExpr, " = ");
@ -235,7 +240,7 @@ class Printer {
case EConst(c): printConstant(c);
case EArray(e1, e2): '${printExpr(e1)}[${printExpr(e2)}]';
case EBinop(op, e1, e2): '${printExpr(e1)} ${printBinop(op)} ${printExpr(e2)}';
case EField(e1, n): '${printExpr(e1)}.$n';
case EField(e1, n, kind): kind == Safe ? '${printExpr(e1)}?.$n' : '${printExpr(e1)}.$n';
case EParenthesis(e1): '(${printExpr(e1)})';
case EObjectDecl(fl):
"{ " + fl.map(function(fld) return printObjectField(fld)).join(", ") + " }";
@ -246,7 +251,8 @@ class Printer {
case EUnop(op, false, e1): printUnop(op) + printExpr(e1);
case EFunction(FNamed(no,inlined), func): (inlined ? 'inline ' : '') + 'function $no' + printFunction(func);
case EFunction(kind, func): (kind != FArrow ? "function" : "") + printFunction(func, kind);
case EVars(vl): "var " + vl.map(printVar).join(", ");
case EVars([]): "var ";
case EVars(vl): ((vl[0].isStatic) ? "static " : "") + ((vl[0].isFinal) ? "final " : "var ") + vl.map(printVar).join(", ");
case EBlock([]): '{ }';
case EBlock(el):
var old = tabs;
@ -281,7 +287,6 @@ class Printer {
case ECast(e1, _): "cast " + printExpr(e1);
case EIs(e1, ct): '${printExpr(e1)} is ${printComplexType(ct)}';
case EDisplay(e1, _): '#DISPLAY(${printExpr(e1)})';
case EDisplayNew(tp): '#DISPLAY(${printTypePath(tp)})';
case ETernary(econd, eif, eelse): '${printExpr(econd)} ? ${printExpr(eif)} : ${printExpr(eelse)}';
case ECheckType(e1, ct): '(${printExpr(e1)} : ${printComplexType(ct)})';
case EMeta({ name:":implicitReturn" }, { expr:EReturn(e1) }): printExpr(e1);
@ -377,13 +382,28 @@ class Printer {
case _: printComplexType(ct);
})
+ ";";
case TDAbstract(tthis, from, to):
"abstract "
case TDAbstract(tthis, tflags, from, to):
var from = from == null ? [] : from.copy();
var to = to == null ? [] : to.copy();
var isEnum = false;
if (tflags != null) {
for (flag in tflags) {
switch (flag) {
case AbEnum: isEnum = true;
case AbFrom(ct): from.push(ct);
case AbTo(ct): to.push(ct);
}
}
}
(isEnum ? "enum " : "")
+ "abstract "
+ t.name
+ ((t.params != null && t.params.length > 0) ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
+ (tthis == null ? "" : "(" + printComplexType(tthis) + ")")
+ (from == null ? "" : [for (f in from) " from " + printComplexType(f)].join(""))
+ (to == null ? "" : [for (t in to) " to " + printComplexType(t)].join(""))
+ [for (f in from) " from " + printComplexType(f)].join("")
+ [for (f in to) " to " + printComplexType(f)].join("")
+ " {\n"
+ [
for (f in t.fields) {
@ -443,8 +463,9 @@ class Printer {
add("EBinop " + printBinop(op));
loopI(e1);
loopI(e2);
case EField(e, field):
add("EField " + field);
case EField(e, field, kind):
if (kind == null) kind = Normal;
add('EField $field (${kind.getName()})');
loopI(e);
case EParenthesis(e):
add("EParenthesis");
@ -543,8 +564,6 @@ class Printer {
case EDisplay(e, displayKind):
add("EDisplay");
loopI(e);
case EDisplayNew(t):
add("EDisplayNew");
case ETernary(econd, eif, eelse):
add("ETernary");
loopI(econd);

View File

@ -180,6 +180,11 @@ typedef TypeParameter = {
`KTypeParameter` kind.
**/
var t:Type;
/**
The default type for this type parameter.
**/
var ?defaultType:Null<Type>;
}
/**
@ -765,6 +770,11 @@ typedef TVar = {
The metadata of the variable.
**/
public var meta(default, never):Null<MetaAccess>;
/**
Whether the variable is a local static variable
**/
public var isStatic(default, never):Bool;
}
/**

View File

@ -85,7 +85,7 @@ class TypeTools {
pos: cf.pos,
meta: cf.meta.get(),
} else {
throw "Invalid TAnonymous";
throw "Invalid TAnonymous";
}
}
@ -162,7 +162,7 @@ class TypeTools {
}
}
#if (macro || display)
#if macro
/**
Follows all typedefs of `t` to reach the actual type.
@ -174,12 +174,17 @@ class TypeTools {
If `t` is null, an internal exception is thrown.
Usage example:
Usage example with monomorphs:
var t = Context.typeof(macro null); // TMono(<mono>)
var ts = Context.typeof(macro "foo"); //TInst(String,[])
Context.unify(t, ts);
trace(t); // TMono(<mono>)
trace(t.follow()); //TInst(String,[])
Usage example with typedefs:
var t = Context.typeof(macro ("foo" :MyString)); // typedef MyString = String
trace(t); // TType(MyString,[])
trace(t.follow()); //TInst(String,[])
**/
static public inline function follow(t:Type, ?once:Bool):Type
return Context.follow(t, once);
@ -363,6 +368,35 @@ class TypeTools {
return null;
#end
}
/**
Changes the name of the variable in the typed expression.
**/
static public function setVarName(t:TVar, name:String) {
Context.load("set_var_name", 2)(t, name);
}
/**
Converts type `t` to `haxe.macro.Type.ModuleType`.
**/
static public function toModuleType(t:Type):ModuleType {
#if (neko || eval)
return Context.load("type_to_module_type", 1)(t);
#else
return null;
#end
}
/**
Creates a type from the `haxe.macro.Type.ModuleType` argument.
**/
static public function fromModuleType(mt:ModuleType):Type {
#if (neko || eval)
return Context.load("module_type_to_type", 1)(mt);
#else
return null;
#end
}
#end
/**

View File

@ -167,7 +167,7 @@ class TypedExprTools {
}
}
#if (macro || display)
#if macro
static public function toString(t:TypedExpr, ?pretty = false):String {
return @:privateAccess haxe.macro.Context.sExpr(t, pretty);
}

View File

@ -43,5 +43,10 @@ extern class Api {
@:hlNative("std", "ptr_compare") static function comparePointer(a:Dynamic, b:Dynamic):Int;
#if (hl_ver >= version("1.12.0"))
@:hlNative("std", "is_prim_loaded") static function isPrimLoaded(f:haxe.Constraints.Function):Bool;
@:hlNative("?std", "mem_compact") static function compact<T>( v : T, exclude : hl.NativeArray<Dynamic>, flags : Int, outCount : hl.Ref<Int> ) : T;
@:hlNative("?std", "sys_check_reload") static function checkReload( ?debugFile : hl.Bytes ) : Bool;
#end
#if (hl_ver >= version("1.13.0"))
@:hlNative("?std", "sys_has_debugger") static function hasDebugger() : Bool;
#end
}

View File

@ -0,0 +1,19 @@
package hl;
@:hlNative("std", "atomic_")
extern class Atomics {
static function add32(r:hl.Ref<Int>, a:Int):Int;
static function sub32(r:hl.Ref<Int>, a:Int):Int;
static function and32(r:hl.Ref<Int>, a:Int):Int;
static function or32(r:hl.Ref<Int>, a:Int):Int;
static function xor32(r:hl.Ref<Int>, a:Int):Int;
static function compareExchange32(r:hl.Ref<Int>, a:Int, b:Int):Int;
static function exchange32(r:hl.Ref<Int>, val:Int):Int;
static function load32(r:hl.Ref<Int>):Int;
static function store32(r:hl.Ref<Int>, val:Int):Int;
static function compareExchangePtr(r:hl.Ref<Dynamic>, a:Dynamic, b:Dynamic):Dynamic;
static function exchangePtr(r:hl.Ref<Dynamic>, val:Dynamic):Dynamic;
static function loadPtr(r:hl.Ref<Dynamic>):Dynamic;
static function storePtr(r:hl.Ref<Dynamic>, val:Dynamic):Dynamic;
}

Some files were not shown because too many files have changed in this diff Show More