Skip to content

Commit bc36900

Browse files
committed
feat: Add extern detection for stdlib method calls
- Check if method/class is extern before transforming to runtime call - Use field.expr() == null to detect extern functions (no implementation) - For extern methods, transform to $ClassName$methodName() runtime call - For non-extern methods, request class compilation via addTypeForCompilation - Add clear comment about instance method limitation (only statics compiled) This properly distinguishes between: - Math.sqrt() -> $Math$sqrt() (extern, needs runtime) - StringMap.set() -> $StringMap$set() (extern, needs runtime) - UserClass.method() -> would compile if we supported instance methods
1 parent e34e621 commit bc36900

1 file changed

Lines changed: 70 additions & 31 deletions

File tree

reflaxe.zyntax/src/zyntax/ZyntaxCompiler.hx

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -156,47 +156,77 @@ class ZyntaxCompiler extends GenericCompiler<AST.Module, AST.Enum, AST.Expr> {
156156
// Handle static method calls (like Math.sqrt)
157157
switch(fa) {
158158
case FStatic(classRef, cf):
159-
// Static method call: Math.sqrt(x) -> $Math$sqrt(x)
160-
var className = classRef.get().name;
161-
var methodName = cf.get().name;
162-
var stdlibFunc = "$" + className + "$" + methodName;
163-
// Use the callee's type (function type) not the call result type
164-
var stdlibCallee: AST.ExprWithPos = {
165-
expr: AST.Expr.Variable(stdlibFunc),
166-
ty: convertType(callee.t),
167-
pos: callee.pos
168-
};
169-
var argExprs = args.map(a -> wrapExpr(a));
170-
AST.Expr.Call(stdlibCallee, argExprs);
171-
172-
case FInstance(_, _, cf) | FAnon(cf) | FClosure(_, cf):
173-
// Instance method call: arr.push(x) -> $Array$push(arr, x)
174-
var methodName = cf.get().name;
175-
var objType = switch(obj.t) {
176-
case TInst(t, _): t.get().name;
177-
default: null;
178-
};
179-
180-
if (methodName != null && objType != null) {
181-
var stdlibFunc = "$" + objType + "$" + methodName;
182-
// Build function type: (self, original_args...) -> return_type
183-
// We need to prepend the object type to the function params
184-
var funcType = buildInstanceMethodType(obj.t, callee.t);
159+
var cls = classRef.get();
160+
var field = cf.get();
161+
var className = cls.name;
162+
var methodName = field.name;
163+
164+
// Check if this is an extern function (no implementation)
165+
// A function is extern if: class is extern OR field has no expr
166+
var isExtern = cls.isExtern || field.expr() == null;
167+
168+
if (isExtern) {
169+
// Extern static method: Math.sqrt(x) -> $Math$sqrt(x)
170+
var stdlibFunc = "$" + className + "$" + methodName;
185171
var stdlibCallee: AST.ExprWithPos = {
186172
expr: AST.Expr.Variable(stdlibFunc),
187-
ty: funcType,
173+
ty: convertType(callee.t),
188174
pos: callee.pos
189175
};
190-
var objExpr = wrapExpr(obj);
191176
var argExprs = args.map(a -> wrapExpr(a));
192-
AST.Expr.Call(stdlibCallee, [objExpr].concat(argExprs));
177+
AST.Expr.Call(stdlibCallee, argExprs);
178+
} else {
179+
// Non-extern static method - request class compilation and use regular call
180+
addTypeForCompilation(TInst(classRef, []));
181+
var calleeExpr = wrapExpr(callee);
182+
var argExprs = args.map(a -> wrapExpr(a));
183+
AST.Expr.Call(calleeExpr, argExprs);
184+
}
185+
186+
case FInstance(classRef, _, cf):
187+
var field = cf.get();
188+
var methodName = field.name;
189+
var objTypeInfo = switch(obj.t) {
190+
case TInst(t, params): {name: t.get().name, clsRef: t, params: params, isExtern: t.get().isExtern};
191+
default: null;
192+
};
193+
194+
if (methodName != null && objTypeInfo != null) {
195+
// Check if method is extern (no implementation)
196+
var isExtern = objTypeInfo.isExtern || field.expr() == null;
197+
198+
if (isExtern) {
199+
// Extern instance method: map.set(k,v) -> $StringMap$set(map, k, v)
200+
var stdlibFunc = "$" + objTypeInfo.name + "$" + methodName;
201+
var funcType = buildInstanceMethodType(obj.t, callee.t);
202+
var stdlibCallee: AST.ExprWithPos = {
203+
expr: AST.Expr.Variable(stdlibFunc),
204+
ty: funcType,
205+
pos: callee.pos
206+
};
207+
var objExpr = wrapExpr(obj);
208+
var argExprs = args.map(a -> wrapExpr(a));
209+
AST.Expr.Call(stdlibCallee, [objExpr].concat(argExprs));
210+
} else {
211+
// Non-extern instance method - request class compilation
212+
addTypeForCompilation(TInst(objTypeInfo.clsRef, objTypeInfo.params));
213+
var calleeExpr = wrapExpr(callee);
214+
var argExprs = args.map(a -> wrapExpr(a));
215+
AST.Expr.Call(calleeExpr, argExprs);
216+
}
193217
} else {
194218
// Fallback to regular call
195219
var calleeExpr = wrapExpr(callee);
196220
var argExprs = args.map(a -> wrapExpr(a));
197221
AST.Expr.Call(calleeExpr, argExprs);
198222
}
199223

224+
case FAnon(cf) | FClosure(_, cf):
225+
// Anonymous/closure field - use regular call (these have implementations)
226+
var calleeExpr = wrapExpr(callee);
227+
var argExprs = args.map(a -> wrapExpr(a));
228+
AST.Expr.Call(calleeExpr, argExprs);
229+
200230
default:
201231
// Other field types - regular call
202232
var calleeExpr = wrapExpr(callee);
@@ -274,8 +304,17 @@ class ZyntaxCompiler extends GenericCompiler<AST.Module, AST.Enum, AST.Expr> {
274304
var cls = clsRef.get();
275305
var className = cls.name;
276306

277-
// Request the class to be compiled (adds to dynamicTypeStack)
278-
addTypeForCompilation(TInst(clsRef, params));
307+
// Check if this class is extern (no Haxe implementation)
308+
// NOTE: Even non-extern classes currently need runtime support because
309+
// we don't yet compile instance methods - only static methods are compiled.
310+
// Once instance method compilation is added, we can check cls.isExtern
311+
// and only use runtime calls for actual extern classes.
312+
var isExtern = true; // For now, treat all class instantiations as extern
313+
314+
if (!isExtern) {
315+
// Non-extern class - request compilation and use regular call
316+
addTypeForCompilation(TInst(clsRef, params));
317+
}
279318

280319
// Generate constructor call: $ClassName$new(args...)
281320
var constructorFunc = "$" + className + "$new";

0 commit comments

Comments
 (0)