Skip to content

Commit dbb1840

Browse files
committed
Fixes for HashLink
1 parent 57ceb63 commit dbb1840

3 files changed

Lines changed: 164 additions & 3 deletions

File tree

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package polymod.hscript._internal;
2+
3+
import haxe.macro.MacroStringTools;
4+
import haxe.macro.TypedExprTools;
5+
import haxe.macro.Context;
6+
import haxe.macro.Expr;
7+
import haxe.macro.Type;
8+
9+
using Lambda;
10+
using haxe.macro.TypeTools;
11+
using haxe.macro.ComplexTypeTools;
12+
using haxe.macro.ExprTools;
13+
using StringTools;
14+
15+
#if (!macro && hl)
16+
@:build(polymod.hscript._internal.HLWrapperMacro.buildWrapperClass())
17+
class HLMath extends Math {}
18+
19+
@:build(polymod.hscript._internal.HLWrapperMacro.buildWrapperClass())
20+
@:haxe.warning("-WDeprecated")
21+
class HLStd extends Std {}
22+
#else
23+
/**
24+
* Macro that generates wrapper fields for substitutes of `std` classes to make them avaliable to Reflection.
25+
* Currently only works for static fields.
26+
*/
27+
class HLWrapperMacro
28+
{
29+
public static macro function buildWrapperClass():Array<Field>
30+
{
31+
var localClass = Context.getLocalClass().get();
32+
var superClass = localClass.superClass;
33+
if (superClass == null)
34+
throw 'Class ${localClass.name} does not extend class it wants to wrap';
35+
var cls = superClass.t.get();
36+
var buildFields = Context.getBuildFields();
37+
38+
for (field in cls.statics.get())
39+
{
40+
if (field.isPublic && !buildFields.exists((f) -> f.name == field.name))
41+
{
42+
var wrapper = generateWrapper(field, cls);
43+
if (wrapper != null)
44+
buildFields.push(wrapper);
45+
}
46+
}
47+
48+
return buildFields;
49+
}
50+
51+
static function generateWrapper(field:ClassField, cls:ClassType):Null<Field>
52+
{
53+
if (field == null)
54+
throw 'Field is null';
55+
56+
var newField:Field = {
57+
name: field.name,
58+
doc: field.doc,
59+
meta: null,
60+
pos: field.pos,
61+
access: [APublic, AStatic, AInline],
62+
kind: null
63+
};
64+
65+
function populateNewField(t:Type):Bool
66+
{
67+
return switch (t)
68+
{
69+
case TLazy(lz):
70+
var ty = lz();
71+
return populateNewField(ty);
72+
case TFun(args, ret):
73+
var funcArgs:Array<FunctionArg> = [
74+
for (arg in args)
75+
{
76+
name: arg.name,
77+
opt: arg.opt,
78+
type: Context.toComplexType(arg.t)
79+
}
80+
];
81+
var ret = Context.toComplexType(ret);
82+
var callArgs:Array<Expr> = [for (arg in funcArgs) macro $i{arg.name}];
83+
var funcParams:Array<TypeParamDecl> = [for (p in field.params) {name: p.name, constraints: getConstraints(p.t)}];
84+
var body = macro $p{[cls.name, field.name]}($a{callArgs});
85+
86+
newField.kind = FFun({
87+
args: funcArgs,
88+
params: funcParams,
89+
ret: ret,
90+
expr: doesReturnVoid(ret) ? (macro $body) : (macro return $body)
91+
});
92+
return true;
93+
default: false;
94+
}
95+
}
96+
97+
if (populateNewField(field.type))
98+
{
99+
return newField;
100+
}
101+
else if (field.expr() == null)
102+
{
103+
var overKind = switch (field.kind)
104+
{
105+
case FVar(_, _):
106+
// We're overriding a VARIABLE, it shouldn't be modifiable
107+
FieldType.FProp('default', 'null', Context.toComplexType(field.type), macro $p{[cls.name, field.name]});
108+
default: throw "Not implemented!";
109+
}
110+
111+
return {
112+
name: field.name,
113+
doc: field.doc,
114+
meta: field.meta.get(),
115+
pos: field.pos,
116+
access: [APublic, AStatic],
117+
kind: overKind
118+
};
119+
}
120+
121+
return null;
122+
}
123+
124+
static function getConstraints(t:Type)
125+
{
126+
return switch (t)
127+
{
128+
case TInst(_.get() => c, _):
129+
switch (c.kind)
130+
{
131+
case KTypeParameter(consts): [for (c in consts) Context.toComplexType(c)];
132+
default: throw 'Invalid class kind, it is not a TypeParameter';
133+
}
134+
case _: throw '$t has not been implemented!';
135+
}
136+
}
137+
138+
static inline function doesReturnVoid(rt:ComplexType)
139+
{
140+
return switch (rt)
141+
{
142+
case TPath(tp): tp.name == "Void";
143+
default: false;
144+
}
145+
}
146+
}
147+
#end

polymod/hscript/_internal/PolymodAbstractScriptClass.hx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ abstract PolymodAbstractScriptClass(PolymodScriptClass) from PolymodScriptClass
198198
@:privateAccess this._interp.error(EInvalidAccess(name));
199199
// throw "field '" + name + "' does not exist in script class '" + this.fullyQualifiedName + "' or super class '" + Type.getClassName(Type.getClass(this.superClass)) + "'";
200200
}
201+
202+
return null;
201203
}
202204

203205
private static function retrieveClassObjectFields(o:Dynamic):Array<String>

polymod/hscript/_internal/PolymodInterpEx.hx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ class PolymodInterpEx extends Interp
4141
{
4242
super();
4343
_proxy = proxy;
44-
variables.set("Math", Math);
45-
variables.set("Std", Std);
44+
variables.set("Math", #if hl HLWrapperMacro.HLMath #else Math #end);
45+
variables.set("Std", #if hl HLWrapperMacro.HLStd #else Std #end);
4646
this.targetCls = targetCls;
4747
}
4848

@@ -1151,8 +1151,20 @@ class PolymodInterpEx extends Interp
11511151
// #end
11521152
// return result;
11531153
}
1154+
#if hl
1155+
else if (Std.isOfType(o, Enum))
1156+
{
1157+
try {
1158+
return (o:Enum<Dynamic>).createByName(f);
1159+
}
1160+
catch (e)
1161+
{
1162+
return null;
1163+
}
1164+
}
1165+
#end
11541166

1155-
var abstractKey:String = Type.getClassName(o) + '.' + f;
1167+
var abstractKey:String = #if hl untyped o.__name__ #else Type.getClassName(o) #end + '.' + f;
11561168
if (PolymodScriptClass.abstractClassStatics.exists(abstractKey)) {
11571169
return Reflect.getProperty(PolymodScriptClass.abstractClassStatics[abstractKey], abstractKey.replace('.', '_'));
11581170
}

0 commit comments

Comments
 (0)