Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src-json/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,13 @@
"targets": ["TClass"],
"links": ["https://haxe.org/manual/target-javascript-require.html"]
},
{
"name": "JsFunction",
"metadata": ":js.function",
"doc": "Generate `function` keyword instead of arrow function in `-D js_es >= 6` mode to enable access to function scope `this`.",
"platforms": ["js"],
"targets": ["TExpr"]
},
{
"name": "LuaRequire",
"metadata": ":luaRequire",
Expand Down
18 changes: 14 additions & 4 deletions src/context/common.ml
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ let default_config =
vs_scope = BlockScope;
vs_flags = [];
};
pf_can_capture_this = true;
pf_supports_atomics = false;
}

Expand Down Expand Up @@ -516,6 +517,7 @@ let get_config com =
(if defined Define.JsUnflatten then ReserveAllTopLevelSymbols else ReserveAllTypesFlat)
:: if es6 then [NoShadowing; SwitchCasesNoBlocks;] else [VarHoisting; NoCatchVarShadowing];
};
pf_can_capture_this = es6;
pf_supports_atomics = true;
}
| Lua ->
Expand All @@ -527,7 +529,8 @@ let get_config com =
pf_supports_rest_args = true;
pf_exceptions = { default_config.pf_exceptions with
ec_avoid_wrapping = false;
}
};
pf_can_capture_this = false;
}
| Neko ->
{
Expand All @@ -542,7 +545,8 @@ let get_config com =
};
pf_exceptions = { default_config.pf_exceptions with
ec_avoid_wrapping = false
}
};
pf_can_capture_this = false;
}
| Flash ->
{
Expand All @@ -567,6 +571,7 @@ let get_config com =
vs_scope = FunctionScope;
vs_flags = [VarHoisting];
};
pf_can_capture_this = false;
}
| Php ->
{
Expand Down Expand Up @@ -603,6 +608,7 @@ let get_config com =
vs_flags = [NoShadowing];
vs_scope = FunctionScope;
};
pf_can_capture_this = false;
pf_supports_atomics = true;
}
| Jvm ->
Expand All @@ -626,6 +632,7 @@ let get_config com =
ec_wildcard_catch = (["java";"lang"],"Throwable");
ec_base_throw = (["java";"lang"],"RuntimeException");
};
pf_can_capture_this = false;
pf_supports_atomics = true;
}
| Python ->
Expand All @@ -650,6 +657,7 @@ let get_config com =
vs_scope = FunctionScope;
vs_flags = [VarHoisting]
};
pf_can_capture_this = false;
}
| Hl ->
{
Expand All @@ -664,7 +672,8 @@ let get_config com =
};
pf_exceptions = { default_config.pf_exceptions with
ec_avoid_wrapping = false
}
};
pf_can_capture_this = false;
}
| Eval ->
{
Expand All @@ -676,7 +685,8 @@ let get_config com =
pf_capture_policy = CPWrapRef;
pf_exceptions = { default_config.pf_exceptions with
ec_avoid_wrapping = false
}
};
pf_can_capture_this = false;
}

let memory_marker = [|Unix.time()|]
Expand Down
4 changes: 3 additions & 1 deletion src/context/platformConfig.ml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ type platform_config = {
pf_exceptions : exceptions_config;
(** the scoping of local variables *)
pf_scoping : var_scoping_config;
(** whether or not the target needs a variable to capture `this` *)
pf_can_capture_this : bool;
(** target supports atomic operations via haxe.Atomic **)
pf_supports_atomics : bool;
}
}
15 changes: 13 additions & 2 deletions src/generators/genjs.ml
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,8 @@ and gen_expr ctx e =
| TBreak ->
print ctx "break _hx_loop%s" n;
| _ -> die "" __LOC__)
| TMeta ((Meta.JsFunction, [], _),{eexpr = TFunction f}) ->
gen_function ~hasJsFunction:true ctx f e.epos
| TMeta (_,e) ->
gen_expr ctx e
| TReturn eo ->
Expand Down Expand Up @@ -733,7 +735,7 @@ and gen_expr ctx e =
);
clear_mapping ()

and gen_function ?(keyword="function") ctx f pos =
and gen_function ?(keyword="function") ?(hasJsFunction=false) ctx f pos =
let old = ctx.in_value, ctx.in_loop in
ctx.in_value <- None;
ctx.in_loop <- false;
Expand Down Expand Up @@ -771,7 +773,15 @@ and gen_function ?(keyword="function") ctx f pos =
| _ ->
f, mk_non_rest_arg_names f.tf_args
in
print ctx "%s(%s) " keyword (String.concat "," args);
let can_be_arrow =
keyword = "function" &&
ctx.es_version >= 6 &&
not hasJsFunction
in
if can_be_arrow then
print ctx "(%s) => " (String.concat "," args)
else
print ctx "%s(%s) " keyword (String.concat "," args);
gen_expr ctx (fun_block ctx f pos);
ctx.in_value <- fst old;
ctx.in_loop <- snd old;
Expand Down Expand Up @@ -842,6 +852,7 @@ and gen_value ctx e =
| TNew _
| TUnop _
| TFunction _
| TMeta ((Meta.JsFunction, [], _),_)
| TIdent _ ->
gen_expr ctx e
| TMeta (_,e1) ->
Expand Down
2 changes: 2 additions & 0 deletions src/macro/macroApi.ml
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ and encode_platform_config pc =
"supportsRestArgs", vbool pc.pf_supports_rest_args;
"exceptions", encode_exceptions_config pc.pf_exceptions;
"scoping", encode_var_scoping_config pc.pf_scoping;
"canCaptureThis", vbool pc.pf_can_capture_this;
"supportsAtomics", vbool pc.pf_supports_atomics;
]

Expand Down Expand Up @@ -1723,6 +1724,7 @@ let decode_platform_config v =
pf_supports_rest_args = decode_bool (field v "supportsRestArgs");
pf_exceptions = exception_config;
pf_scoping = var_scoping_config;
pf_can_capture_this = decode_bool (field v "canCaptureThis");
pf_supports_atomics = decode_bool (field v "supportsAtomics");
}

Expand Down
5 changes: 3 additions & 2 deletions src/optimization/inline.ml
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ object(self)
_inlined_vars <- vars; (* Order is reversed due to tail-recursion *)
in
match ethis.eexpr with
| TConst TNull ->
| TConst TNull | TConst TThis ->
set_inlined_vars params f.tf_args;
None
| _ ->
Expand Down Expand Up @@ -712,7 +712,8 @@ let rec type_inline (ictx : inline_context) cf f ethis params tret config p ?(se
l.i_read <- l.i_read + (if !in_loop then 2 else 1);
{ e with eexpr = TLocal l.i_subst }
| None ->
raise_typing_error "Could not inline `this` outside of an instance context" po
{ e with eexpr = TConst TThis }
(* raise_typing_error "Could not inline `this` outside of an instance context" po *)
)
| TVar (v,eo) ->
if has_var_flag v VStatic then raise_typing_error "Inline functions cannot have static locals" v.v_pos;
Expand Down
8 changes: 8 additions & 0 deletions src/typing/typer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,14 @@ and type_meta ?(mode=MGet) ctx m e1 with_type p =
| (Meta.NullSafety, [(EConst (Ident "Off"), _)],_) ->
let e = e() in
{e with eexpr = TMeta(m,e)}
| (Meta.JsFunction, [],pos) when ctx.com.platform=Js ->
let e = e() in
begin match e.eexpr with
| TFunction f ->
{e with eexpr = TMeta(m,e)}
| _ ->
raise_typing_error "@:js.function can be applied only to anonymous functions" pos
end
| (Meta.BypassAccessor,_,p) ->
let old_counter = ctx.e.bypass_accessor in
ctx.e.bypass_accessor <- old_counter + 1;
Expand Down
15 changes: 11 additions & 4 deletions src/typing/typerBase.ml
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,17 @@ let is_lower_ident s p =
with Invalid_argument msg -> raise_typing_error msg p

let get_this ctx p =
let has_jsfun_meta metas =
ctx.com.platform == Js && List.exists (fun (name,args,pos) ->
match name with
| Meta.JsFunction -> true
| _ -> false
) metas
in
match ctx.e.curfun with
| FunStatic ->
raise_typing_error "Cannot access this from a static function" p
| FunMemberClassLocal | FunMemberAbstractLocal ->
| FunMemberClassLocal | FunMemberAbstractLocal when not ctx.com.config.pf_can_capture_this || has_jsfun_meta ctx.f.meta ->
let v = match ctx.f.vthis with
| None ->
let v = if ctx.e.curfun = FunMemberAbstractLocal then begin
Expand All @@ -169,10 +176,10 @@ let get_this ctx p =
v
in
mk (TLocal v) ctx.c.tthis p
| FunMemberAbstract ->
| FunMemberAbstract | FunMemberAbstractLocal ->
let v = (try PMap.find "this" ctx.f.locals with Not_found -> raise_typing_error "Cannot reference this abstract here" p) in
mk (TLocal v) v.v_type p
| FunConstructor | FunMember ->
| FunConstructor | FunMember | FunMemberClassLocal ->
mk (TConst TThis) ctx.c.tthis p

let get_stored_typed_expr ctx id =
Expand Down Expand Up @@ -406,4 +413,4 @@ let get_safe_nav_base ctx eobj =
let v = alloc_var VGenerated "tmp" eobj.etype eobj.epos in
let temp_var = mk (TVar(v, Some eobj)) ctx.t.tvoid v.v_pos in
let eobj = mk (TLocal v) v.v_type v.v_pos in
eobj, Some temp_var
eobj, Some temp_var
4 changes: 4 additions & 0 deletions std/haxe/macro/PlatformConfig.hx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ typedef PlatformConfig = {
**/
final supportsAtomics:Bool;

/**
Whether or not the target needs a variable to capture `this`
**/
final canCaptureThis:Bool;
}

enum CapturePolicy {
Expand Down
4 changes: 2 additions & 2 deletions std/js/_std/HxOverrides.hx
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ class HxOverrides {
return {
cur: 0,
arr: a,
hasNext: function() {
hasNext: @:js.function function() {
return __this__.cur < __this__.arr.length;
},
next: function() {
next: @:js.function function() {
return __this__.arr[__this__.cur++];
}
};
Expand Down
2 changes: 1 addition & 1 deletion std/js/_std/Reflect.hx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
}

public static function makeVarArgs<T>(f:Array<Dynamic>->T):Dynamic {
return function() {
return @:js.function function() {
var a = untyped Array.prototype.slice.call(js.Syntax.code("arguments"));
return f(a);
};
Expand Down
4 changes: 2 additions & 2 deletions std/js/_std/Std.hx
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,13 @@ import js.Syntax;
__feature__("Class.*", js.Syntax.code('var Class = { };'));
__feature__("Enum.*", js.Syntax.code('var Enum = { };'));
#if (js_es < 5)
__feature__("Array.map", if (Array.prototype.map == null) Array.prototype.map = function(f) {
__feature__("Array.map", if (Array.prototype.map == null) Array.prototype.map = @:js.function function(f) {
var a = [];
for (i in 0...__this__.length)
a[i] = f(__this__[i]);
return a;
});
__feature__("Array.filter", if (Array.prototype.filter == null) Array.prototype.filter = function(f) {
__feature__("Array.filter", if (Array.prototype.filter == null) Array.prototype.filter = @:js.function function(f) {
var a = [];
for (i in 0...__this__.length) {
var e = __this__[i];
Expand Down
4 changes: 2 additions & 2 deletions std/js/_std/haxe/ds/IntMap.hx
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ package haxe.ds;
return untyped {
ref: h,
it: keys(),
hasNext: function() {
hasNext: @:js.function function() {
return __this__.it.hasNext();
},
next: function() {
next: @:js.function function() {
var i = __this__.it.next();
return __this__.ref[i];
}
Expand Down
4 changes: 2 additions & 2 deletions std/js/_std/haxe/ds/ObjectMap.hx
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
return untyped {
ref: h,
it: keys(),
hasNext: function() {
hasNext: @:js.function function() {
return __this__.it.hasNext();
},
next: function() {
next: @:js.function function() {
var i = __this__.it.next();
return __this__.ref[getId(i)];
}
Expand Down
1 change: 1 addition & 0 deletions tests/misc/projects/Issue11128/hxtest/Init.hx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class Init {
// Default, except everything has been set to `true`.
public static var intendedConfig: PlatformConfig = {
supportsAtomics: true,
canCaptureThis: true,
thisBeforeSuper: true,
scoping: {
scope: BlockScope,
Expand Down
Loading