Skip to content

Commit 6e81c57

Browse files
committed
Allow static functions to use static extensions (using classes)
1 parent 9824bf4 commit 6e81c57

File tree

2 files changed

+62
-39
lines changed

2 files changed

+62
-39
lines changed

polymod/hscript/_internal/PolymodInterpEx.hx

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ class PolymodInterpEx extends Interp
140140
// Force call super function.
141141
return super.fcall(o, '__super_${f}', args);
142142
}
143-
else if (Std.isOfType(o, PolymodStaticClassReference)) {
143+
else if (Std.isOfType(o, PolymodStaticClassReference))
144+
{
144145
var ref:PolymodStaticClassReference = cast(o, PolymodStaticClassReference);
145146

146147
return ref.callFunction(f, args);
@@ -153,50 +154,60 @@ class PolymodInterpEx extends Interp
153154
}
154155

155156
var func = get(o, f);
157+
if (func != null)
158+
{
159+
return call(o, func, args);
160+
}
156161

157162
@:privateAccess
163+
if (_proxy != null && _proxy._cachedUsingFunctions.exists(f))
164+
{
165+
return _proxy._cachedUsingFunctions[f]([o].concat(args));
166+
}
167+
else if (_classDeclOverride != null)
158168
{
159-
if (func == null && _proxy != null && _proxy._cachedUsingFunctions.exists(f))
169+
// TODO: Optimize with a cache
170+
var usingFuncs:Map<String, Array<Dynamic>->Dynamic> = [];
171+
PolymodScriptClass.buildExtensionFunctionCache(_classDeclOverride, usingFuncs);
172+
173+
if (usingFuncs.exists(f))
160174
{
161-
return _proxy._cachedUsingFunctions[f]([o].concat(args));
175+
return usingFuncs[f]([o].concat(args));
162176
}
163177
}
164178

165179
#if html5
166180
// Workaround for an HTML5-specific issue.
167181
// https://github.com/HaxeFoundation/haxe/issues/11298
168-
if (func == null && f == "contains") {
182+
if (f == "contains")
183+
{
169184
func = get(o, "includes");
170185
}
171-
172186
// For web: remove is inlined so we have to use something else.
173-
if (func == null && f == "remove")
187+
else if (f == "remove")
174188
{
175189
@:privateAccess
176190
return HxOverrides.remove(cast o, args[0]);
177191
}
178192
#end
179193

180-
if (func == null)
194+
if (Std.isOfType(o, HScriptedClass))
181195
{
182-
if (Std.isOfType(o, HScriptedClass))
196+
// This is a scripted class!
197+
// We should try to call the function on the scripted class.
198+
// If it doesn't exist, `asc.callFunction()` will handle generating an error message.
199+
if (o.scriptCall != null)
183200
{
184-
// This is a scripted class!
185-
// We should try to call the function on the scripted class.
186-
// If it doesn't exist, `asc.callFunction()` will handle generating an error message.
187-
if (o.scriptCall != null) {
188-
return o.scriptCall(f, args);
189-
}
190-
191-
errorEx(EInvalidScriptedFnAccess(f));
192-
}
193-
else
194-
{
195-
// Throw an error for a missing function.
196-
errorEx(EInvalidAccess(f));
201+
return o.scriptCall(f, args);
197202
}
203+
204+
return errorEx(EInvalidScriptedFnAccess(f));
205+
}
206+
else
207+
{
208+
// Throw an error for a missing function.
209+
return errorEx(EInvalidAccess(f));
198210
}
199-
return call(o, func, args);
200211
}
201212

202213
private static var _scriptClassDescriptors:Map<String, PolymodClassDeclEx> = new Map<String, PolymodClassDeclEx>();

polymod/hscript/_internal/PolymodScriptClass.hx

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ class PolymodScriptClass
914914
private var _cachedSuperFunctionDecls:Map<String, Dynamic> = [];
915915
private var _cachedFunctionDecls:Map<String, FunctionDecl> = [];
916916
private var _cachedVarDecls:Map<String, VarDecl> = [];
917-
private var _cachedUsingFunctions:Map<String, Dynamic> = [];
917+
private var _cachedUsingFunctions:Map<String, Array<Dynamic>->Dynamic> = [];
918918

919919
private function buildCaches()
920920
{
@@ -924,22 +924,7 @@ class PolymodScriptClass
924924
_cachedVarDecls.clear();
925925
_cachedUsingFunctions.clear();
926926

927-
for (n => u in _c.usings)
928-
{
929-
var fields = Type.getClassFields(u.cls);
930-
if (fields.length == 0) continue;
931-
932-
for (fld in fields)
933-
{
934-
var func:Dynamic = function(params:Array<Dynamic>)
935-
{
936-
var prop:Dynamic = Reflect.getProperty(u.cls, fld);
937-
return Reflect.callMethod(u.cls, prop, params);
938-
}
939-
940-
_cachedUsingFunctions.set(fld, func);
941-
}
942-
}
927+
buildExtensionFunctionCache(_c, _cachedUsingFunctions);
943928

944929
for (f in _c.fields)
945930
{
@@ -964,5 +949,32 @@ class PolymodScriptClass
964949
}
965950
}
966951
}
952+
953+
/**
954+
* Populates a string map with functions from a 'using' class.
955+
* @param clsDecl The class to retrieve functions from.
956+
* @param usingCache The map to populate.
957+
*/
958+
public static function buildExtensionFunctionCache(clsDecl:PolymodClassDeclEx, usingCache:Map<String, Array<Dynamic>->Dynamic>):Void
959+
{
960+
for (_ => u in clsDecl.usings)
961+
{
962+
var fields = Type.getClassFields(u.cls);
963+
if (fields.length == 0) continue;
964+
965+
for (fld in fields)
966+
{
967+
var field:Dynamic = Reflect.getProperty(u.cls, fld);
968+
if (!Reflect.isFunction(field)) continue;
969+
970+
var func:Dynamic = function(params:Array<Dynamic>)
971+
{
972+
return Reflect.callMethod(u.cls, field, params);
973+
}
974+
975+
usingCache.set(fld, func);
976+
}
977+
}
978+
}
967979
}
968980
#end

0 commit comments

Comments
 (0)