From edc7b962e78913cf6501c23d38814013e5ec0e56 Mon Sep 17 00:00:00 2001 From: AjwwkD <107187521+Ajwyunsx@users.noreply.github.com> Date: Sat, 20 Sep 2025 20:39:51 +0800 Subject: [PATCH 1/7] Add files via upload --- src/lhscript/LHScript.hx | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/lhscript/LHScript.hx b/src/lhscript/LHScript.hx index 648afca..05a29c6 100644 --- a/src/lhscript/LHScript.hx +++ b/src/lhscript/LHScript.hx @@ -375,9 +375,13 @@ class LHScript { var value = Reflect.field(instance, propertyName); // 如果是方法,返回绑定到实例的函数 if (Reflect.isFunction(value)) { - return function(...args) { - return Reflect.callMethod(instance, value, args); - }; + return Reflect.makeVarArgs(function(varArgs:Array) { + var callArgs:Array = []; + if (varArgs != null) { + for(a in varArgs) callArgs.push(a); + } + return Reflect.callMethod(instance, value, callArgs); + }); } return value; } else { @@ -385,9 +389,13 @@ class LHScript { var value = Reflect.getProperty(instance, propertyName); // 如果是方法,返回绑定到实例的函数 if (Reflect.isFunction(value)) { - return function(...args) { - return Reflect.callMethod(instance, value, args); - }; + return Reflect.makeVarArgs(function(varArgs:Array) { + var callArgs:Array = []; + if (varArgs != null) { + for(a in varArgs) callArgs.push(a); + } + return Reflect.callMethod(instance, value, callArgs); + }); } return value; } catch (e:Dynamic) { @@ -646,5 +654,3 @@ class LHScript { return enableHaxeSyntax; } } - - From 1e5a93e3716a3cb2bbfd9d21da6b019acead0d38 Mon Sep 17 00:00:00 2001 From: AjwwkD <107187521+Ajwyunsx@users.noreply.github.com> Date: Sat, 20 Sep 2025 21:54:04 +0800 Subject: [PATCH 2/7] Add files via upload --- src/lhscript/LHScript.hx | 261 ++++++++++++++++++++++++++++++++++----- 1 file changed, 230 insertions(+), 31 deletions(-) diff --git a/src/lhscript/LHScript.hx b/src/lhscript/LHScript.hx index 05a29c6..9c7e44b 100644 --- a/src/lhscript/LHScript.hx +++ b/src/lhscript/LHScript.hx @@ -6,10 +6,16 @@ import luahscript.LuaTools; import luahscript.LuaParser; import luahscript.exprs.LuaExpr; import luahscript.LuaAndParams; +import luahscript.exprs.*; import haxe.Constraints.IMap; @:access(luahscript.LuaInterp) class LHScript { + // Constants for LuaVariableType values + private static inline var LOCAL:String = "Local"; + private static inline var GLOBAL:String = "global"; + private static inline var FIELD:String = "Field"; + private static inline var UNKNOWN:String = ""; public var interp:LuaInterp; private var parser:LuaParser; private var scriptContent:String; @@ -132,6 +138,208 @@ class LHScript { } } + /** + * Executes a call based on an expression and arguments, encapsulating logic from LuaInterp's ECall case. + * @param e The expression representing the function or method to call. + * @param args An array of arguments to pass to the function or method. + * @return The result of the function call, or an error value. + */ + public function executeCall(e:luahscript.exprs.LuaExpr, args:Array):Dynamic { + try { + switch(e.expr) { + case EField(ef, f, isDouble): // Handles obj:method() and obj.method() + var obj:Dynamic = interp.expr(ef); + if(obj == null) { + var sb:Null = null; + var type:Null = null; + LuaTools.recursion(ef, function(e:luahscript.exprs.LuaExpr) { + switch(e.expr) { + case EIdent(id): + sb = id; + type = if(interp.locals.get(id) != null) LHScript.LOCAL; else LHScript.GLOBAL; + case EField(_, f): // luahscript.exprs.LuaExprDef.EField + sb = f; + type = LHScript.FIELD; + case EArray(_, _): // luahscript.exprs.LuaExprDef.EArray + sb = 'integer index'; + type = LHScript.FIELD; + default: + type = LHScript.UNKNOWN; + } + }); + return interp.error(EInvalidAccess(sb, cast type, LuaCheckType.checkType(obj)), ef.line); + } + + // Handle Class:new() syntax for Haxe class instantiation + if (isDouble && f == "new") { + var haxeClass:Class = null; + if (Std.isOfType(obj, Class)) { + haxeClass = cast obj; + } else { + var className:String = null; + if (Std.isOfType(obj, String)) { + className = cast obj; + } else { + if (obj != null) { + className = Type.getClassName(Type.getClass(obj)); + } + } + + if (className != null) { + haxeClass = Type.resolveClass(className); + } + + if (haxeClass == null) { + return interp.error(luahscript.exprs.LuaErrorDef.ECustom("Attempt to call 'new' on an object that is not a recognized class or type: " + Std.string(obj) + " (resolved class name: " + (className != null ? className : "null") + ")")); + } + } + + try { + var instance:Dynamic = null; + #if neko + if (Reflect.hasField(haxeClass, "__new__")) { + instance = Reflect.callMethod(haxeClass, Reflect.field(haxeClass, "__new__"), args); + } else { + #end + + if (haxeClass == String) { + if (args.length > 0 && luahscript.LuaCheckType.checkType(args[0]) == luahscript.LuaTyper.TSTRING) { + instance = args[0]; + } else { + instance = ""; + } + } else { + instance = Type.createInstance(haxeClass, args); + } + + #if neko + } + #end + + // Wrap instance in a LuaTable for meta-method support + var instanceWrapper = new luahscript.LuaTable(); + + var metaTable = new luahscript.LuaTable(); + metaTable.set("__index", function(table:Dynamic, propertyName:String):Dynamic { + if (Reflect.hasField(instance, propertyName)) { + var value = Reflect.field(instance, propertyName); + if (Reflect.isFunction(value)) { + return Reflect.makeVarArgs(function(varArgs:Array) { + var callArgs:Array = []; + if (varArgs != null) { + for(a in varArgs) callArgs.push(a); + } + return Reflect.callMethod(instance, value, callArgs); + }); + } + return value; + } else { + try { + var value = Reflect.getProperty(instance, propertyName); + if (Reflect.isFunction(value)) { + return Reflect.makeVarArgs(function(varArgs:Array) { + var callArgs:Array = []; + if (varArgs != null) { + for(a in varArgs) callArgs.push(a); + } + return Reflect.callMethod(instance, value, callArgs); + }); + } + return value; + } catch (e:Dynamic) { + return null; + } + } + }); + + metaTable.set("__newindex", function(table:Dynamic, propertyName:String, value:Dynamic):Void { + Reflect.setProperty(instance, propertyName, value); + }); + + instanceWrapper.metaTable = metaTable; + instanceWrapper.set("__instance", instance); + + return instanceWrapper; + + } catch (err:haxe.Exception) { + return interp.error(ECustom("Failed to instantiate or wrap class " + Type.getClassName(haxeClass) + ": " + Std.string(err)), ef.line); + } + } + + final func:Dynamic = interp.get(obj, f, isDouble); + if(func == null) { + var sb:Null = null; + var type:Null = null; + LuaTools.recursion(e, function(e:luahscript.exprs.LuaExpr) { // e is EField + switch(e.expr) { + case EIdent(id): + sb = id; + type = if(interp.locals.get(id) != null) LHScript.LOCAL; else LHScript.GLOBAL; + case EField(_, f_name): + sb = f_name; + type = LHScript.FIELD; + case EArray(_, _): + sb = 'integer index'; + type = LHScript.FIELD; + default: + type = LHScript.UNKNOWN; + } + }); + return interp.error(ECallNilValue(sb, cast type), e.line); + } + if (isDouble) { + if (Reflect.isObject(obj) && !Std.isOfType(obj, luahscript.LuaTable)) { + var method = Reflect.getProperty(obj, f); + if (Reflect.isFunction(method)) { + return try { + Reflect.callMethod(obj, method, args); + } catch(e:haxe.Exception) { + throw interp.error(ECustom("Error calling method '" + f + "': " + Std.string(e)), 0); + } + } + #if neko + return try { + Reflect.callMethod(obj, func, args); + } catch(e:haxe.Exception) { + throw interp.error(ECustom("Error calling method '" + f + "' on Neko fallback: " + Std.string(e)), 0); + } + #end + } + args.insert(0, obj); + } + return try Reflect.callMethod(null, func, args) catch(e:haxe.Exception) throw interp.error(ECustom(Std.string(e)), 0); + case _: + var func:Dynamic = interp.expr(e); + if(func == null) { + var sb:Null = null; + var type:Null = null; + LuaTools.recursion(e, function(e:luahscript.exprs.LuaExpr) { + switch(e.expr) { + case EIdent(id): + sb = id; + type = if(interp.locals.get(id) != null) LHScript.LOCAL; else LHScript.GLOBAL; + case EField(_, f): + sb = f; + type = LHScript.FIELD; + case EArray(_, _): + sb = 'integer index'; + type = LHScript.FIELD; + default: + type = LHScript.UNKNOWN; + } + }); + return interp.error(ECallNilValue(sb, cast type), e.line); + } + return try Reflect.callMethod(null, func, args) catch(e:haxe.Exception) throw interp.error(ECustom(Std.string(e)), 0); + } + } catch (err:Dynamic) { // Catching generic Dynamic as LuaInterp.error throws Dynamic + if (onError != null) { + onError(Std.string(err)); + } + return "FUNC_ERROR"; // Consistent with callFunc's error return + } + return null; // Should not be reached if logic is correct + } public function callFunc(funcName:String, ?args:Array):Dynamic { if (args == null) args = []; @@ -139,29 +347,28 @@ class LHScript { lastCalledFunction = funcName; lastCalledScript = this; + if (interp == null) { + if(onError != null) onError("Lua error (interp is null): " + funcName); + return "FUNC_CONT"; + } + + // Create an EIdent expression for the function name + var expr:luahscript.exprs.LuaExpr = { expr: luahscript.exprs.LuaExprDef.EIdent(funcName), line: 0 }; + try { - if (interp == null) return "FUNC_CONT"; - - var func = null; - try { - func = interp.globals.get(funcName); - } catch (e:Dynamic) { - return "FUNC_CONT"; - } - if (func == null) { - return "FUNC_CONT"; - } - - var result = Reflect.callMethod(null, func, args); + // Use the new executeCall method + var result = executeCall(expr, args); + // executeCall already handles errors and returns "FUNC_ERROR" or throws + // If it returns a result, it's successful. + // If it throws, it's caught below. return result; } catch (e:Dynamic) { if (onError != null) { onError("Lua error (" + funcName + "): " + Std.string(e)); } - return "FUNC_CONT"; + return "FUNC_CONT"; // Or "FUNC_ERROR" for consistency with executeCall's error handling } } - public function callMultipleFunctions(funcNames:Array, ?argsArray:Array> = null):Array { var results:Array = []; @@ -281,7 +488,7 @@ class LHScript { return interp; public function setinterp(interps:LuaInterp):Void { - interps = interp; + interp = interps; // Corrected assignment } public static function registerModule(name:String, script:LHScript):Void { @@ -375,13 +582,9 @@ class LHScript { var value = Reflect.field(instance, propertyName); // 如果是方法,返回绑定到实例的函数 if (Reflect.isFunction(value)) { - return Reflect.makeVarArgs(function(varArgs:Array) { - var callArgs:Array = []; - if (varArgs != null) { - for(a in varArgs) callArgs.push(a); - } - return Reflect.callMethod(instance, value, callArgs); - }); + return function(...args) { + return Reflect.callMethod(instance, value, args); + }; } return value; } else { @@ -389,13 +592,9 @@ class LHScript { var value = Reflect.getProperty(instance, propertyName); // 如果是方法,返回绑定到实例的函数 if (Reflect.isFunction(value)) { - return Reflect.makeVarArgs(function(varArgs:Array) { - var callArgs:Array = []; - if (varArgs != null) { - for(a in varArgs) callArgs.push(a); - } - return Reflect.callMethod(instance, value, callArgs); - }); + return function(...args) { + return Reflect.callMethod(instance, value, args); + }; } return value; } catch (e:Dynamic) { @@ -552,7 +751,7 @@ class LHScript { return Reflect.callMethod(null, originalPcall, args); } return luahscript.LuaAndParams.fromArray([false, "bad argument #1 to pcall"]); - })); + })); interp.globals.set("__call", Reflect.makeVarArgs(function(args:Array) { if (args.length >= 2) { From cac46795f975a2f07833574bc7a34cd9ffa7bdea Mon Sep 17 00:00:00 2001 From: AjwwkD <107187521+Ajwyunsx@users.noreply.github.com> Date: Sat, 20 Sep 2025 22:03:47 +0800 Subject: [PATCH 3/7] Add files via upload --- src/lhscript/LHScript.hx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/lhscript/LHScript.hx b/src/lhscript/LHScript.hx index 9c7e44b..95143a3 100644 --- a/src/lhscript/LHScript.hx +++ b/src/lhscript/LHScript.hx @@ -16,6 +16,12 @@ class LHScript { private static inline var GLOBAL:String = "global"; private static inline var FIELD:String = "Field"; private static inline var UNKNOWN:String = ""; + + // LuaVariableType enum instances + private static var LOCAL_VAR_TYPE:LuaVariableType = cast LOCAL; + private static var GLOBAL_VAR_TYPE:LuaVariableType = cast GLOBAL; + private static var FIELD_VAR_TYPE:LuaVariableType = cast FIELD; + private static var UNKNOWN_VAR_TYPE:LuaVariableType = cast UNKNOWN; public var interp:LuaInterp; private var parser:LuaParser; private var scriptContent:String; @@ -285,7 +291,7 @@ class LHScript { type = LHScript.UNKNOWN; } }); - return interp.error(ECallNilValue(sb, cast type), e.line); + return interp.error(ECallNilValue(sb, type == LOCAL ? LOCAL_VAR_TYPE : (type == GLOBAL ? GLOBAL_VAR_TYPE : (type == FIELD ? FIELD_VAR_TYPE : UNKNOWN_VAR_TYPE))), e.line); } if (isDouble) { if (Reflect.isObject(obj) && !Std.isOfType(obj, luahscript.LuaTable)) { @@ -328,7 +334,7 @@ class LHScript { type = LHScript.UNKNOWN; } }); - return interp.error(ECallNilValue(sb, cast type), e.line); + return interp.error(ECallNilValue(sb, type == LOCAL ? LOCAL_VAR_TYPE : (type == GLOBAL ? GLOBAL_VAR_TYPE : (type == FIELD ? FIELD_VAR_TYPE : UNKNOWN_VAR_TYPE))), e.line); } return try Reflect.callMethod(null, func, args) catch(e:haxe.Exception) throw interp.error(ECustom(Std.string(e)), 0); } From 8323547533cf2c0c6b9c57e65cc26fdbbef7bb0b Mon Sep 17 00:00:00 2001 From: AjwwkD <107187521+Ajwyunsx@users.noreply.github.com> Date: Sat, 20 Sep 2025 22:07:33 +0800 Subject: [PATCH 4/7] Add files via upload --- src/lhscript/LHScript.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lhscript/LHScript.hx b/src/lhscript/LHScript.hx index 95143a3..fd0c655 100644 --- a/src/lhscript/LHScript.hx +++ b/src/lhscript/LHScript.hx @@ -7,6 +7,7 @@ import luahscript.LuaParser; import luahscript.exprs.LuaExpr; import luahscript.LuaAndParams; import luahscript.exprs.*; +import luahscript.exprs.LuaErrorDef.LuaVariableType; import haxe.Constraints.IMap; @:access(luahscript.LuaInterp) From 19194991a50461fb22b88977219de024925f4086 Mon Sep 17 00:00:00 2001 From: OpenCode Date: Sun, 22 Feb 2026 20:30:40 +0800 Subject: [PATCH 5/7] Improve cross-target Lua compatibility for require, debug, and coroutine --- src/luahscript/LuaInterp.hx | 465 +++++++++++++++++----- src/luahscript/LuaTable.hx | 77 ++-- src/luahscript/lualibs/LuaCoroutineLib.hx | 238 ++++++----- src/luahscript/lualibs/LuaDebugLib.hx | 57 +++ src/luahscript/lualibs/LuaTableLib.hx | 9 +- src/luahscript/macros/LuaLibMacro.hx | 50 ++- test.lua | 88 +++- tests/testmods/init.lua | 4 + tests/testmods/mathutils.lua | 11 + 9 files changed, 752 insertions(+), 247 deletions(-) create mode 100644 src/luahscript/lualibs/LuaDebugLib.hx create mode 100644 tests/testmods/init.lua create mode 100644 tests/testmods/mathutils.lua diff --git a/src/luahscript/LuaInterp.hx b/src/luahscript/LuaInterp.hx index 83b4019..3521866 100644 --- a/src/luahscript/LuaInterp.hx +++ b/src/luahscript/LuaInterp.hx @@ -5,6 +5,10 @@ import luahscript.exprs.LuaError; import luahscript.exprs.LuaToken; import luahscript.exprs.*; import haxe.Constraints.IMap; +#if sys +import sys.FileSystem; +import sys.io.File; +#end typedef LuaLocalVar = { var r: Dynamic; @@ -15,6 +19,11 @@ typedef LuaDeclaredVar = { var old:Dynamic; } +typedef LuaCallFrame = { + var name:String; + var line:Int; +} + class LuaInterp { private var packageTable:LuaTable = LuaTable.fromObject({ config: "/\n;\n?\n!\n-\n", @@ -25,11 +34,12 @@ class LuaInterp { searchers: new LuaTable(), searchpath: function(module:String, rulePaths:String, ?sep:String, ?set:String):LuaAndParams { - throw "package.searchpath is not support current platform."; + if (module == null) throw "bad argument #1 to 'searchpath' (string expected, got nil)"; return null; }, loadlib: function(libPath:String, funcName:String) { - throw "package.loadlib is not support current platform."; + if (libPath == null) throw "bad argument #1 to 'loadlib' (string expected, got nil)"; + if (funcName == null) throw "bad argument #2 to 'loadlib' (string expected, got nil)"; return null; }, }); @@ -41,7 +51,17 @@ class LuaInterp { */ public var searchPathCallback(default, set):(String, String, String, ?String, ?String)->LuaAndParams; private inline function set_searchPathCallback(val:(String, String, String, ?String, ?String)->LuaAndParams):(String, String, String, ?String, ?String)->LuaAndParams { - this.packageTable.set("searchpath", val.bind(this.packageTable.get("config"), _)); + final config:Dynamic = this.packageTable.get("config"); + this.packageTable.set("searchpath", Reflect.makeVarArgs(function(args:Array):LuaAndParams { + if(args.length < 2) { + throw "bad argument #2 to 'searchpath' (string expected, got nil)"; + } + var module:Dynamic = args[0]; + var rulePaths:Dynamic = args[1]; + var sep:Dynamic = (args.length > 2 ? args[2] : null); + var set:Dynamic = (args.length > 3 ? args[3] : null); + return val(config, module, rulePaths, sep, set); + })); return searchPathCallback = val; } @@ -66,6 +86,12 @@ class LuaInterp { var return_value:LuaAndParams; var throw_label:String; var triple_value:LuaAndParams; + var callStack:Array; + + static var currentInterp:LuaInterp; + public static inline function getCurrentInterp():Null { + return currentInterp; + } public function new() { var me = this; @@ -82,7 +108,7 @@ class LuaInterp { ["="], */ binops.set("^", function(a:Dynamic, b:Dynamic) { - if(isMetaTable(a) && a.metaTable.keyExists("__pow")) return cast(a, LuaTable).__pow(a, b); + if(isMetaTable(a) && a.metaTable.keyExists("__pow")) return cast(a, LuaTable).metaPow(a, b); if(LuaCheckType.checkType(a) != TNUMBER) { a = Lua_tonumber.tonumber(a); if(a == null || Math.isNaN(a)) throw "invalid reading number"; @@ -94,7 +120,7 @@ class LuaInterp { return Math.pow(a, b); }); binops.set("*", function(a:Dynamic, b:Dynamic) { - if(isMetaTable(a) && a.metaTable.keyExists("__mul")) return cast(a, LuaTable).__mul(a, b); + if(isMetaTable(a) && a.metaTable.keyExists("__mul")) return cast(a, LuaTable).metaMul(a, b); if(LuaCheckType.checkType(a) != TNUMBER) { a = Lua_tonumber.tonumber(a); if(a == null || Math.isNaN(a)) throw "invalid reading number"; @@ -106,7 +132,7 @@ class LuaInterp { return a * b; }); binops.set("/", function(a:Dynamic, b:Dynamic) { - if(isMetaTable(a) && a.metaTable.keyExists("__div")) return cast(a, LuaTable).__div(a, b); + if(isMetaTable(a) && a.metaTable.keyExists("__div")) return cast(a, LuaTable).metaDiv(a, b); if(LuaCheckType.checkType(a) != TNUMBER) { a = Lua_tonumber.tonumber(a); if(a == null || Math.isNaN(a)) throw "invalid reading number"; @@ -118,7 +144,7 @@ class LuaInterp { return a / b; }); binops.set("//", function(a:Dynamic, b:Dynamic) { - if(isMetaTable(a) && a.metaTable.keyExists("__idiv")) return cast(a, LuaTable).__idiv(a, b); + if(isMetaTable(a) && a.metaTable.keyExists("__idiv")) return cast(a, LuaTable).metaIDiv(a, b); if(LuaCheckType.checkType(a) != TNUMBER) { a = Lua_tonumber.tonumber(a); if(a == null || Math.isNaN(a)) throw "invalid reading number"; @@ -132,7 +158,7 @@ class LuaInterp { else Math.ceil(result); }); binops.set("%", function(a:Dynamic, b:Dynamic) { - if(isMetaTable(a) && a.metaTable.keyExists("__mod")) return cast(a, LuaTable).__mod(a, b); + if(isMetaTable(a) && a.metaTable.keyExists("__mod")) return cast(a, LuaTable).metaMod(a, b); if(LuaCheckType.checkType(a) != TNUMBER) { a = Lua_tonumber.tonumber(a); if(a == null || Math.isNaN(a)) throw "invalid reading number"; @@ -144,7 +170,7 @@ class LuaInterp { return a % b; }); binops.set("+", function(a:Dynamic, b:Dynamic) { - if(isMetaTable(a) && a.metaTable.keyExists("__add")) return cast(a, LuaTable).__add(a, b); + if(isMetaTable(a) && a.metaTable.keyExists("__add")) return cast(a, LuaTable).metaAdd(a, b); if(LuaCheckType.checkType(a) != TNUMBER) { a = Lua_tonumber.tonumber(a); if(a == null || Math.isNaN(a)) throw "invalid reading number"; @@ -156,7 +182,7 @@ class LuaInterp { return a + b; }); binops.set("-", function(a:Dynamic, b:Dynamic) { - if(isMetaTable(a) && a.metaTable.keyExists("__sub")) return cast(a, LuaTable).__sub(a, b); + if(isMetaTable(a) && a.metaTable.keyExists("__sub")) return cast(a, LuaTable).metaSub(a, b); if(LuaCheckType.checkType(a) != TNUMBER) { a = Lua_tonumber.tonumber(a); if(a == null || Math.isNaN(a)) throw "invalid reading number"; @@ -168,11 +194,11 @@ class LuaInterp { return a - b; }); binops.set("..", function(a:Dynamic, b:Dynamic) { - if(isMetaTable(a) && a.metaTable.keyExists("__concat")) return cast(a, LuaTable).__concat(a, b); + if(isMetaTable(a) && a.metaTable.keyExists("__concat")) return cast(a, LuaTable).metaConcat(a, b); return Std.string(LuaCheckType.checkNotSpecialValue(a)) + Std.string(LuaCheckType.checkNotSpecialValue(b)); }); binops.set("<", function(a:Dynamic, b:Dynamic) { - if(isMetaTable(a) && a.metaTable.keyExists("__lt")) return cast(a, LuaTable).__lt(a, b); + if(isMetaTable(a) && a.metaTable.keyExists("__lt")) return cast(a, LuaTable).metaLt(a, b); if(LuaCheckType.checkType(a) != TNUMBER) { a = Lua_tonumber.tonumber(a); if(a == null || Math.isNaN(a)) throw "invalid reading number"; @@ -188,7 +214,7 @@ class LuaInterp { return a > b; }); binops.set("<=", function(a:Dynamic, b:Dynamic) { - if(isMetaTable(a) && a.metaTable.keyExists("__le")) return cast(a, LuaTable).__le(a, b); + if(isMetaTable(a) && a.metaTable.keyExists("__le")) return cast(a, LuaTable).metaLe(a, b); if(LuaCheckType.checkType(a) != TNUMBER || LuaCheckType.checkType(b) != TNUMBER) throw "invalid reading number"; return a <= b; }); @@ -200,7 +226,7 @@ class LuaInterp { return a != b; }); binops.set("==", function(a:Dynamic, b:Dynamic) { - if(isMetaTable(a) && a.metaTable.keyExists("__eq")) return cast(a, LuaTable).__eq(a, b); + if(isMetaTable(a) && a.metaTable.keyExists("__eq")) return cast(a, LuaTable).metaEq(a, b); return a == b; }); binops.set("and", function(a:Dynamic, b:Dynamic) { @@ -212,6 +238,36 @@ class LuaInterp { return b; }); + callStack = []; + + searchPathCallback = function(config:String, module:String, rulePaths:String, ?sep:String, ?rep:String):LuaAndParams { + module = LuaCheckType.checkString(module); + rulePaths = LuaCheckType.checkString(rulePaths); + config = LuaCheckType.checkString(config); + + var cfg = config.split("\n"); + var dirSep = cfg.length > 0 ? cfg[0] : "/"; + var listSep = cfg.length > 1 ? cfg[1] : ";"; + var mark = cfg.length > 2 ? cfg[2] : "?"; + + var nameSep = sep != null ? LuaCheckType.checkString(sep) : "."; + var nameRep = rep != null ? LuaCheckType.checkString(rep) : dirSep; + var normalizedModule = StringTools.replace(module, nameSep, nameRep); + + var errors = []; + for (rawPath in rulePaths.split(listSep)) { + var candidate = StringTools.replace(rawPath, mark, normalizedModule); + #if sys + if (FileSystem.exists(candidate) && !FileSystem.isDirectory(candidate)) { + return LuaAndParams.fromArray([candidate]); + } + #end + errors.push("no file '" + candidate + "'"); + } + + return LuaAndParams.fromArray([null, errors.join("\n\t")]); + }; + globals = new Map(); globals.set("print", Reflect.makeVarArgs(function(args:Array) { var buf = new StringBuf(); @@ -239,49 +295,50 @@ class LuaInterp { globals.set("tonumber", function(v:Dynamic, ?base:Int) { return Lua_tonumber.tonumber(v, base); }); - globals.set("assert", function(v:Dynamic, ?message:String) { - if(LuaTools.luaBool(v)) return v; - throw message; - return null; + globals.set("assert", function(v:Dynamic, message:String = "assertion failed!") { + if(!LuaTools.luaBool(v)) throw message; + return v; }); - globals.set("error", luastd_error); + globals.set("error", Reflect.makeVarArgs(function(args:Array) { + if(args.length == 0) { + throw "error object is nil"; + } + throw Std.string(args[0]); + })); globals.set("pcall", Reflect.makeVarArgs(function(args:Array) { - if(args.length > 0) { - var func:Dynamic = null; - final td = LuaCheckType.checkType(func = args.shift()); - if(td == TFUNCTION) { - try { - final result = Reflect.callMethod(null, func, args); - if(isAndParams(result)) { - return LuaAndParams.fromArray([true].concat(result.values)); - } else { - return LuaAndParams.fromArray([true, result]); - } - } catch(e) { - return LuaAndParams.fromArray([false, Std.string(e)]); + if(args.length == 0) throw "bad argument #1 to pcall"; + var func:Dynamic = null; + final td = LuaCheckType.checkType(func = args.shift()); + if(td == TFUNCTION) { + try { + final result = me.invokeCallable(func, args, "", (me.curExpr == null ? 0 : me.curExpr.line)); + if(isAndParams(result)) { + var values:Array = [true]; + values = values.concat(result.values); + return LuaAndParams.fromArray(values); + } else { + return LuaAndParams.fromArray([true, result]); } + } catch(e) { + return LuaAndParams.fromArray([false, Std.string(e)]); } - return LuaAndParams.fromArray([false, "attempt to call a " + td + " value"]); } - throw "bad argument #1 to pcall"; - return null; + return LuaAndParams.fromArray([false, "attempt to call a " + td + " value"]); })); - globals.set("select", Reflect.makeVarArgs(function(args:Array) { - if(args.length > 0) { - var v = args.shift(); - if(LuaCheckType.isInteger(v)) { - final i:Int = cast v; - if(i > 0) { - while(args.length > i) { - args.shift(); - } - return LuaAndParams.fromArray(args); + globals.set("select", Reflect.makeVarArgs(function(args:Array):LuaAndParams { + if(args.length == 0) throw "bad argument #1 to select"; + var v = args.shift(); + if(LuaCheckType.isInteger(v)) { + final i:Int = cast v; + if(i > 0) { + while(args.length > i) { + args.shift(); } - } else if(v == "#") { - return LuaAndParams.fromArray([args.length]); + return LuaAndParams.fromArray(args); } - } - throw "bad argument #1 to select"; + } else if(v == "#") { + return LuaAndParams.fromArray([args.length]); + } else throw "bad argument #1 to select"; return null; })); globals.set("rawequal", function(v1:Dynamic, v2:Dynamic):Bool { @@ -314,34 +371,93 @@ class LuaInterp { globals.set("require", (function(packageTable:LuaTable, module:String):LuaAndParams { module = LuaCheckType.checkString(module); var loaded:LuaTable = packageTable.get("loaded"); - if(loaded.keyExists(module)) return toParams(loaded.get(module)); + if (loaded.keyExists(module)) { + return toParams(loaded.get(module)); + } + var preload:LuaTable = packageTable.get("preload"); - if(LuaCheckType.checkType(preload.get(module)) == TFUNCTION) { - final re:LuaAndParams = preload.get(module)(module, ":preload:"); - return LuaAndParams.fromArray([re.values[0] != null ? re.values[0] : true, ":preload:"]); + var preloadLoader = preload.get(module); + if (LuaCheckType.checkType(preloadLoader) == TFUNCTION) { + var preloadValue:Array = getParams(me.invokeCallable(preloadLoader, [module, ":preload:"], "", (me.curExpr == null ? 0 : me.curExpr.line))); + var imported:Dynamic = (preloadValue.length > 0 && preloadValue[0] != null) ? preloadValue[0] : true; + loaded.set(module, imported); + return LuaAndParams.fromArray([imported, ":preload:"]); } - var err:Null = null; - for(k=>v in new LuaTable.LuaTableIpairsIterator(packageTable.get("searchers"))) { - final res:LuaAndParams = v(module); - if(res.values.length > 1 && LuaCheckType.checkType(res.values[0]) == TFUNCTION) { - final re:LuaAndParams = res.values[0](module, res.values[1]); - loaded.set(module, re.values[0] == null ? true : re.values[0]); - return LuaAndParams.fromArray([loaded.get(module), res.values[1]]); - } else if(res.values.length == 1 && res.values[0] != null) { - throw "module '" + module + "' not found:\n\t" + (preload.keyExists(module) ? preload.get(module) : "no field package.preload['" + module + "'])") + "\n\t" + res.values[0]; + var err:String = "module '" + module + "' not found:\n\t" + (preload.keyExists(module) ? preload.get(module) : "no field package.preload['" + module + "']"); + for (k => v in new LuaTable.LuaTableIpairsIterator(packageTable.get("searchers"))) { + var res = getParams(me.invokeCallable(v, [module], "", (me.curExpr == null ? 0 : me.curExpr.line))); + if (res.length == 0) { + continue; + } + + if (LuaCheckType.checkType(res[0]) == TFUNCTION) { + var loader:Dynamic = res[0]; + var loaderData:Dynamic = res.length > 1 ? res[1] : null; + var loaderResult = getParams(me.invokeCallable(loader, [module, loaderData], "", (me.curExpr == null ? 0 : me.curExpr.line))); + var imported:Dynamic = (loaderResult.length > 0 && loaderResult[0] != null) ? loaderResult[0] : true; + loaded.set(module, imported); + return LuaAndParams.fromArray([imported, loaderData]); + } + + if (res[0] != null) { + err += "\n\t" + Std.string(res[0]); } } - return LuaAndParams.fromArray([]); + + throw err; }).bind(this.packageTable, _)); + #if sys + packageAddSearcher(function(packageTable:LuaTable, module:String):LuaAndParams { + module = LuaCheckType.checkString(module); + + var pathResult:LuaAndParams = packageTable.get("searchpath")(module, packageTable.get("path")); + if (pathResult.values.length == 0 || pathResult.values[0] == null) { + if (pathResult.values.length > 1 && pathResult.values[1] != null) { + return LuaAndParams.fromArray([pathResult.values[1]]); + } + return LuaAndParams.fromArray(["no file for module '" + module + "'"]); + } + + var path = Std.string(pathResult.values[0]); + var source:Null = null; + try { + source = File.getContent(path); + } catch (e:Dynamic) { + return LuaAndParams.fromArray(["error loading module '" + module + "' from file '" + path + "':\n\t" + Std.string(e)]); + } + + var parsedExpr:LuaExpr = null; + try { + parsedExpr = new LuaParser().parseFromString(source); + } catch (e:LuaError) { + return LuaAndParams.fromArray(["error loading module '" + module + "' from file '" + path + "':\n\t" + LuaPrinter.errorToString(e)]); + } catch (e:Dynamic) { + return LuaAndParams.fromArray(["error loading module '" + module + "' from file '" + path + "':\n\t" + Std.string(e)]); + } + + var loader = Reflect.makeVarArgs(function(args:Array):Dynamic { + var chunk = me.execute(parsedExpr); + if (LuaCheckType.checkType(chunk) == TFUNCTION) { + return me.invokeCallable(chunk, args, "", 0); + } + return chunk; + }); + + return LuaAndParams.fromArray([loader, path]); + }); + #end + setDownlineG(); initLuaLibs(globals, this); } public function packageAddSearcher(v:LuaTable->String->LuaAndParams):Void { - (packageTable.get("searchers"):LuaTable).push(v.bind(this.packageTable, _)); + (packageTable.get("searchers"):LuaTable).push(function(module:String):LuaAndParams { + return v(this.packageTable, module); + }); } public function packageLoad(s:String, v:Dynamic) { @@ -371,7 +487,9 @@ class LuaInterp { setLibs(map, "math", luahscript.lualibs.LuaMathLib, interp); setLibs(map, "string", luahscript.lualibs.LuaStringLib, interp); setLibs(map, "table", luahscript.lualibs.LuaTableLib, interp); + setLibs(map, "coroutine", luahscript.lualibs.LuaCoroutineLib, interp); setLibs(map, "os", luahscript.lualibs.LuaOSLib, interp); + setLibs(map, "debug", luahscript.lualibs.LuaDebugLib, interp); #if sys setLibs(map, "io", luahscript.lualibs.LuaIOLib, interp); #end @@ -390,6 +508,93 @@ class LuaInterp { map.set(name, value); } + public function getDebugTraceback(?level:Int = 0):String { + if(level == null || level < 0) level = 0; + var buf = new StringBuf(); + buf.add("stack traceback:"); + if(callStack.length == 0 || level >= callStack.length) { + buf.add("\n\t"); + return buf.toString(); + } + + var i = callStack.length - 1 - level; + while(i >= 0) { + final frame = callStack[i--]; + buf.add("\n\t"); + if(frame.line > 0) { + buf.add(Std.string(frame.line)); + buf.add(": "); + } + buf.add("in function '"); + buf.add(frame.name); + buf.add("'"); + } + + return buf.toString(); + } + + public function getDebugInfo(level:Int):Null> { + if(level < 0) level = 0; + final idx = callStack.length - 1 - level; + if(idx < 0 || idx >= callStack.length) return null; + final frame = callStack[idx]; + + var info = new LuaTable(); + info.set("name", frame.name); + info.set("currentline", frame.line); + info.set("what", "Lua"); + info.set("source", "=luahscript"); + info.set("short_src", "[luahscript]"); + return info; + } + + private function getCallName(callExpr:LuaExpr):String { + if(callExpr == null || callExpr.expr == null) return ""; + return switch(callExpr.expr) { + case EIdent(id): id; + case EField(_, f, _): f; + case EParent(e): getCallName(e); + case EFunction(_, _, info): + if(info == null) { + ""; + } else { + final names:Dynamic = Reflect.field(info, "names"); + if(names is Array && cast(names, Array).length > 0) { + final arr:Array = cast names; + Std.string(arr[arr.length - 1]); + } else { + ""; + } + } + case _: ""; + }; + } + + private function invokeCallable(func:Dynamic, args:Array, ?name:String, ?line:Int):Dynamic { + final callName = (name == null || name.length == 0) ? "" : name; + final callLine = (line == null ? (curExpr == null ? 0 : curExpr.line) : line); + final oldInterp = currentInterp; + currentInterp = this; + callStack.push({name: callName, line: callLine}); + + var result:Dynamic = null; + try { + result = if(isMetaTable(func) && cast(func, LuaTable).metaTable.keyExists("__call")) { + cast(func, LuaTable).metaCall(func, args); + } else { + Reflect.callMethod(null, func, args); + }; + } catch(e:Dynamic) { + if(callStack.length > 0) callStack.pop(); + currentInterp = oldInterp; + throw e; + } + + if(callStack.length > 0) callStack.pop(); + currentInterp = oldInterp; + return result; + } + public function execute(expr:LuaExpr):Dynamic { locals = new Map(); markedLabels = new Map(); @@ -400,7 +605,15 @@ class LuaInterp { function exprReturn(e:LuaExpr):LuaAndParams { try { - expr(e); + try { + expr(e); + } catch(e:LuaError) { + throw e; + } catch(s:LuaStop) { + throw s; + } catch(e) { + this.error(ECustom(Std.string(e))); + } } catch(s:LuaStop) { switch (s) { case SBreak: @@ -415,7 +628,8 @@ class LuaInterp { return new LuaAndParams(); } - function expr(e:LuaExpr, isLocal:Bool = false):Dynamic { + function expr(e:LuaExpr, ?isLocal:Dynamic):Dynamic { + final isLocalFlag = LuaTools.luaBool(isLocal); this.curExpr = e; switch(e.expr) { case EConst(c): @@ -463,7 +677,7 @@ class LuaInterp { return expr(e, true); case EBinop(op, e1, e2): if(op == "=") { - evalAssignOp(e1, e2, isLocal); + evalAssignOp(e1, e2, isLocalFlag); return null; } final left:Dynamic = getParamsFirst(expr(e1)); @@ -475,13 +689,13 @@ class LuaInterp { var v:Dynamic = getParamsFirst(expr(e)); return switch(prefix) { case "#": - if(isMetaTable(v) && v.metaTable.keyExists("__len")) return cast(v, LuaTable).__len(v); + if(isMetaTable(v) && v.metaTable.keyExists("__len")) return cast(v, LuaTable).metaLen(v); else if(isTable(v)) @:privateAccess return cast(v, LuaTable).nextIndex - 1; if(v.length != null) v.length else 0; case "not": !LuaTools.luaBool(v); case "-": - if(isMetaTable(v) && v.metaTable.keyExists("__unm")) return cast(v, LuaTable).__unm(v); + if(isMetaTable(v) && v.metaTable.keyExists("__unm")) return cast(v, LuaTable).metaUnm(v); -LuaCheckType.checkNumber(v); case _: error(EInvalidOp(prefix)); @@ -491,7 +705,7 @@ class LuaInterp { for(i=>p in params) { var v:Dynamic = expr(p); if(isAndParams(v)) { - final lap:LuaAndParams = cast v; + final lap:LuaAndParams = cast(v, LuaAndParams); if(lap.values.length > 0) { for(value in lap.values) { args.push(value); @@ -550,7 +764,7 @@ class LuaInterp { error(ECallInvalidValue(sb, type, td)); } if (isDouble) args.insert(0, obj); - return if(isMetaTable(func) && cast(func, LuaTable).metaTable.keyExists("__call")) cast(func, LuaTable).__call(func, args); else Reflect.callMethod(null, func, args); + return invokeCallable(func, args, getCallName(e), e.line); case _: var func:Dynamic = getParamsFirst(expr(e)); final td = LuaCheckType.checkType(isMetaTable(func) && cast(func, LuaTable).metaTable.keyExists("__call") ? cast(func, LuaTable).metaTable.get("__call") : func); @@ -574,7 +788,7 @@ class LuaInterp { }); error(ECallInvalidValue(sb, type, td)); } - return if(isMetaTable(func) && cast(func, LuaTable).metaTable.keyExists("__call")) cast(func, LuaTable).__call(func, args); else Reflect.callMethod(null, func, args); + return invokeCallable(func, args, getCallName(e), e.line); } case ETd(ae): var old = declared.length; @@ -666,12 +880,18 @@ class LuaInterp { throw LuaStop.SContinue; case EFunction(args, e, info): var index = args.indexOf("..."); - final names = (info != null ? info.names : []); + var names:Array = []; var me = this; var isDouble = false; var obj:Dynamic = null; if(info != null) { - isDouble = info.isDouble; + final parsedNames:Dynamic = Reflect.field(info, "names"); + if(parsedNames is Array) { + for(n in cast(parsedNames, Array)) { + names.push(Std.string(n)); + } + } + isDouble = LuaTools.luaBool(Reflect.field(info, "isDouble")); var preName:Null = null; if(names.length > 1) for(i=>name in names) { if(i == 0) { @@ -683,30 +903,55 @@ class LuaInterp { } preName = name; } - if(isDouble && isLocal) error(ECustom("Cannot define the field of a global variable as local")); + if(isDouble && isLocalFlag) error(ECustom("Cannot define the field of a global variable as local")); } if(isDouble) args.insert(0, "self"); + final functionName = (names.length > 0 ? names[names.length - 1] : ""); + final functionLine = (curExpr == null ? 0 : curExpr.line); var capturedLocals = duplicate(locals); var f = Reflect.makeVarArgs(function(params:Array) { + final oldInterp = currentInterp; + currentInterp = me; + + var pushedHostFrame = false; + if(me.callStack.length == 0) { + me.callStack.push({name: functionName, line: functionLine}); + pushedHostFrame = true; + } + var old = me.locals; var oldDecl = me.declared.length; me.locals = me.duplicate(capturedLocals); final tv = me.triple_value; - for(i=>arg in args) { - if(arg == "...") { - me.triple_value = LuaAndParams.fromArray(params); - break; - } else { - me.declared.push({ n : arg, old : locals.get(arg) }); - me.locals.set(arg, {r: params.shift()}); + + var result:LuaAndParams = null; + try { + for(i=>arg in args) { + if(arg == "...") { + me.triple_value = LuaAndParams.fromArray(params); + break; + } else { + me.declared.push({ n : arg, old : locals.get(arg) }); + me.locals.set(arg, {r: params.shift()}); + } } + + result = me.exprReturn(e); + restore(oldDecl); + } catch(err:Dynamic) { + restore(oldDecl); + me.locals = old; + me.triple_value = tv; + if(pushedHostFrame && me.callStack.length > 0) me.callStack.pop(); + currentInterp = oldInterp; + throw err; } - var oldDecl = declared.length; - var r = me.exprReturn(e); - restore(oldDecl); + me.locals = old; me.triple_value = tv; - return r; + if(pushedHostFrame && me.callStack.length > 0) me.callStack.pop(); + currentInterp = oldInterp; + return result; }); if(names.length > 0) { final name = names[names.length - 1]; @@ -714,7 +959,7 @@ class LuaInterp { if(isTable(obj)) cast(obj, LuaTable).set(name, f); else error(ECustom("not support loading functions in object forms other than tables")); } else { - if(isLocal) { + if(isLocalFlag) { declared.push({n: name, old: locals.get(name)}); locals.set(name, {r: f}); } else { @@ -762,7 +1007,7 @@ class LuaInterp { }); error(EInvalidAccess(sb, type, td)); } - if(isTable(o)) return cast(o, LuaTable).__read(o, expr(index)); + if(isTable(o)) return cast(o, LuaTable).metaRead(o, expr(index)); return o[getParamsFirst(expr(index))]; case ETable(fls): var table = new LuaTable(); @@ -809,30 +1054,32 @@ class LuaInterp { return null; } - function get(obj:Dynamic, f:String, isDouble:Bool = false):Dynamic { + function get(obj:Dynamic, f:String, ?isDouble:Dynamic):Dynamic { + final isDoubleFlag = LuaTools.luaBool(isDouble); if(obj is String) { - if(isDouble && lualibs.exists("string")) { + if(isDoubleFlag && lualibs.exists("string")) { return lualibs.get("string").get(f); } return null; } if(isTable(obj)) { - final result = cast(obj, LuaTable).__read(obj, f); + final result = cast(obj, LuaTable).metaRead(obj, f); return result; } return Reflect.getProperty(obj, f); } - function set(obj:Dynamic, f:String, value:Dynamic, isDouble:Bool = false) { - if(isTable(obj)) return cast(obj, LuaTable).__write(obj, f, value); + function set(obj:Dynamic, f:String, value:Dynamic, ?isDouble:Dynamic) { + if(isTable(obj)) return cast(obj, LuaTable).metaWrite(obj, f, value); Reflect.setProperty(obj, f, value); } - function evalAssignOpExpr(e1:LuaExpr, e2:Dynamic, isLocal:Bool = false) { + function evalAssignOpExpr(e1:LuaExpr, e2:Dynamic, ?isLocal:Dynamic) { + final isLocalFlag = LuaTools.luaBool(isLocal); switch(e1.expr) { case EIdent(id): var ex:Array = if(isAndParams(e2)) cast(e2, LuaAndParams).values; else [e2]; - if(isLocal) { + if(isLocalFlag) { declared.push({n: id, old: locals.get(id)}); locals.set(id, {r: ex[0]}); } else { @@ -893,29 +1140,28 @@ class LuaInterp { }); error(EInvalidAccess(sb, type, td)); } - if(isTable(array)) return cast(array, LuaTable).__write(array, index, ex[0]); + if(isTable(array)) return cast(array, LuaTable).metaWrite(array, index, ex[0]); array[index] = ex[0]; default: error(EInvalidOp("=")); } } - function evalAssignOp(e1:LuaExpr, e2:LuaExpr, isLocal:Bool = false) { + function evalAssignOp(e1:LuaExpr, e2:LuaExpr, ?isLocal:Dynamic) { + final isLocalFlag = LuaTools.luaBool(isLocal); switch(e1.expr) { case EAnd(arr): + var rhs:Dynamic = expr(e2); + var values:Array = if(isAndParams(rhs)) cast(rhs, LuaAndParams).values; else [rhs]; for(i=>eval in arr) { - var e2:Dynamic = expr(e2); - var ex:Array = if(isAndParams(e2)) cast(e2, LuaAndParams).values; else [e2]; - evalAssignOpExpr(eval, ex[i], isLocal); + evalAssignOpExpr(eval, (i < values.length ? values[i] : null), isLocalFlag); } - if(isLocal) isLocal = false; case EIdent(id): var ex:Dynamic = expr(e2); var ex:Array = if(isAndParams(ex)) cast(ex, LuaAndParams).values; else [ex]; - if(isLocal) { + if(isLocalFlag) { declared.push({n: id, old: locals.get(id)}); locals.set(id, {r: ex[0]}); - isLocal = false; } else { if(locals.get(id) == null) { globals.set(id, ex[0]); @@ -976,7 +1222,7 @@ class LuaInterp { }); error(EInvalidAccess(sb, type, td)); } - if(isTable(array)) return cast(array, LuaTable).__write(array, index, ex[0]); + if(isTable(array)) return cast(array, LuaTable).metaWrite(array, index, ex[0]); array[index] = ex[0]; default: error(EInvalidOp("=")); @@ -1067,26 +1313,27 @@ class LuaInterp { if(td != TFUNCTION) error(EInvalidIterator(td)); final state = params[1]; var current = params[2]; + final iteratorLine = (it == null ? 0 : it.line); declared.push({n: vk, old: locals.get(vk)}); if(vk != null) { declared.push({n: vv, old: locals.get(vv)}); - var results:Array = getParams(func(state, current)); + var results:Array = getParams(invokeCallable(func, [state, current], "", iteratorLine)); while (results[1] != null) { current = results[0]; locals.set(vk, {r: results[0]}); locals.set(vv, {r: results[1]}); if (!loopRun(() -> expr(e))) break; - results = getParams(func(state, current)); + results = getParams(invokeCallable(func, [state, current], "", iteratorLine)); } } else { - var results:Array = getParams(func(state, current)); + var results:Array = getParams(invokeCallable(func, [state, current], "", iteratorLine)); while (results[1] != null) { current = results[0]; locals.set(vv, {r: results[1]}); if (!loopRun(() -> expr(e))) break; - results = getParams(func(state, current)); + results = getParams(invokeCallable(func, [state, current], "", iteratorLine)); } } } @@ -1182,7 +1429,7 @@ class LuaInterp { inline function toParams(sb:Dynamic):LuaAndParams { if(sb is LuaAndParams) return cast sb; - return sb; + return LuaAndParams.fromArray([sb]); } public function error(err:LuaErrorDef, ?line:Int):Dynamic { diff --git a/src/luahscript/LuaTable.hx b/src/luahscript/LuaTable.hx index d321551..8e4b830 100644 --- a/src/luahscript/LuaTable.hx +++ b/src/luahscript/LuaTable.hx @@ -142,182 +142,181 @@ class LuaTable { * 转换为字符串表示 */ public function toString():String { - return Std.string(__tostring(this)); + return Std.string(metaToString(this)); } //+ - private function __add(t:LuaTable, r:Dynamic):Dynamic { + private function metaAdd(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__add")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__add"), [t, r]); + return Reflect.callMethod(null, metaTable.get("__add"), [t, r]); } } return null; } //- - private function __sub(t:LuaTable, r:Dynamic):Dynamic { + private function metaSub(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__sub")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__sub"), [t, r]); + return Reflect.callMethod(null, metaTable.get("__sub"), [t, r]); } } return null; } //* - private function __mul(t:LuaTable, r:Dynamic):Dynamic { + private function metaMul(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__mul")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__mul"), [t, r]); + return Reflect.callMethod(null, metaTable.get("__mul"), [t, r]); } } return null; } /// - private function __div(t:LuaTable, r:Dynamic):Dynamic { + private function metaDiv(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__div")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__div"), [t, r]); + return Reflect.callMethod(null, metaTable.get("__div"), [t, r]); } } return null; } //// - private function __idiv(t:LuaTable, r:Dynamic):Dynamic { + private function metaIDiv(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__idiv")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__idiv"), [t, r]); + return Reflect.callMethod(null, metaTable.get("__idiv"), [t, r]); } } return null; } //% - private function __mod(t:LuaTable, r:Dynamic):Dynamic { + private function metaMod(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__mod")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__mod"), [t, r]); + return Reflect.callMethod(null, metaTable.get("__mod"), [t, r]); } } return null; } //^ - private function __pow(t:LuaTable, r:Dynamic):Dynamic { + private function metaPow(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__pow")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__pow"), [t, r]); + return Reflect.callMethod(null, metaTable.get("__pow"), [t, r]); } } return null; } //- - private function __unm(t:LuaTable):Dynamic { + private function metaUnm(t:LuaTable):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__unm")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__unm"), [t]); + return Reflect.callMethod(null, metaTable.get("__unm"), [t]); } } return null; } //... - private function __concat(t:LuaTable, r:Dynamic):Dynamic { + private function metaConcat(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__concat")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__concat"), [t, r]); + return Reflect.callMethod(null, metaTable.get("__concat"), [t, r]); } } return null; } //# - private function __len(t:LuaTable):Dynamic { + private function metaLen(t:LuaTable):Dynamic { if(metaTable != null) { - trace("ahhhh"); if(LuaCheckType.checkType(metaTable.get("__len")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__len"), [t]); + return Reflect.callMethod(null, metaTable.get("__len"), [t]); } } return null; } //== - private function __eq(t:LuaTable, r:Dynamic):Dynamic { + private function metaEq(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__eq")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__eq"), [t, r]); + return Reflect.callMethod(null, metaTable.get("__eq"), [t, r]); } } return null; } //< - private function __lt(t:LuaTable, r:Dynamic):Dynamic { + private function metaLt(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__lt")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__lt"), [t, r]); + return Reflect.callMethod(null, metaTable.get("__lt"), [t, r]); } } return null; } //<= - private function __le(t:LuaTable, r:Dynamic):Dynamic { + private function metaLe(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__le")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__le"), [t, r]); + return Reflect.callMethod(null, metaTable.get("__le"), [t, r]); } } return null; } - private function __read(t:LuaTable, r:Dynamic):Dynamic { + private function metaRead(t:LuaTable, r:Dynamic):Dynamic { if(metaTable != null) { final v:Dynamic = metaTable.get("__index"); final sb = LuaCheckType.checkType(v); if(sb == TFUNCTION) { - return Reflect.callMethod(t, v, [t, r]); + return Reflect.callMethod(null, v, [t, r]); } else if(!this.keyExists(r) && sb == TTABLE) { - return cast(v, LuaTable).__read(v, r); + return cast(v, LuaTable).metaRead(v, r); } } return this.get(r); } - private function __write(t:LuaTable, r:Dynamic, value:Dynamic):Void { + private function metaWrite(t:LuaTable, r:Dynamic, value:Dynamic):Void { if(metaTable != null) { final v:Dynamic = metaTable.get("__newindex"); final sb = LuaCheckType.checkType(v); if(sb == TFUNCTION) { - Reflect.callMethod(t, v, [t, r, value]); + Reflect.callMethod(null, v, [t, r, value]); return; } else if(!this.keyExists(r) && sb == TTABLE) { - return cast(v, LuaTable).__write(v, r, value); + return cast(v, LuaTable).metaWrite(v, r, value); } } return this.set(r, value); } - private function __call(t:LuaTable, args:Array):Dynamic { + private function metaCall(t:LuaTable, args:Array):Dynamic { if(metaTable != null) { final sb = LuaCheckType.checkType(metaTable.get("__call")); if(sb == TFUNCTION) { args = args ?? []; - return Reflect.callMethod(t, metaTable.get("__call"), cast([t], Array).concat(args)); + return Reflect.callMethod(null, metaTable.get("__call"), cast([t], Array).concat(args)); } } return null; } - private function __tostring(t:LuaTable):String { + private function metaToString(t:LuaTable):String { if(metaTable != null) { if(LuaCheckType.checkType(metaTable.get("__tostring")) == TFUNCTION) { - return Reflect.callMethod(t, metaTable.get("__tostring"), [t]); + return Reflect.callMethod(null, metaTable.get("__tostring"), [t]); } } return "table"; @@ -366,4 +365,4 @@ class LuaTablePairsIterator { var key = keys.next(); return {value: _table.get(key), key: key}; } -} \ No newline at end of file +} diff --git a/src/luahscript/lualibs/LuaCoroutineLib.hx b/src/luahscript/lualibs/LuaCoroutineLib.hx index 165494d..a8da927 100644 --- a/src/luahscript/lualibs/LuaCoroutineLib.hx +++ b/src/luahscript/lualibs/LuaCoroutineLib.hx @@ -1,89 +1,149 @@ -package luahscript.lualibs; - -import luahscript.LuaInterp; -import luahscript.LuaTable; - -@:build(luahscript.macros.LuaLibMacro.build()) -class LuaCoroutineLib { - private static var nextCoroutineId = 0; - - public static function lualib_create(func:Dynamic):LuaTable { - var coTable = new LuaTable(); - coTable.set("_func", func); - coTable.set("_status", "suspended"); - coTable.set("_id", nextCoroutineId++); - return coTable; - } - - @:multiArgs - public static function lualib_resume(args:Array):LuaTable { - if (args.length == 0) { - var errorArray:Array = [false, "missing coroutine argument"]; - return LuaTable.fromArray(errorArray); - } - - var coTable:LuaTable = args[0]; - var resumeArgs:Array = args.slice(1); - - var status:String = coTable.get("_status"); - - if (status == "dead") { - var errorArray:Array = [false, "cannot resume dead coroutine"]; - return LuaTable.fromArray(errorArray); - } - - if (status == "running") { - var errorArray:Array = [false, "cannot resume running coroutine"]; - return LuaTable.fromArray(errorArray); - } - - var func:Dynamic = coTable.get("_func"); - - try { - coTable.set("_status", "running"); - - if (status == "suspended") { - var result = Reflect.callMethod(null, func, resumeArgs); - coTable.set("_status", "dead"); - var successArray:Array = [true, result]; - return LuaTable.fromArray(successArray); - } - - var successArray:Array = [true]; - return LuaTable.fromArray(successArray); - - } catch (e:Dynamic) { - coTable.set("_status", "dead"); - var errorArray:Array = [false, "coroutine error: " + Std.string(e)]; - return LuaTable.fromArray(errorArray); - } - } - - @:multiArgs - public static function lualib_yield(args:Array):Void { - // Simple yield implementation - just return without doing anything - // In a real implementation, this would need to capture the current coroutine state - } - - public static function lualib_status(coTable:LuaTable):String { - return coTable.get("_status"); - } - - public static function lualib_running():LuaTable { - var coTable = new LuaTable(); - coTable.set("_status", "running"); - return coTable; - } - - public static function lualib_wrap(func:Dynamic):LuaTable { - var wrapper = Reflect.makeVarArgs(function(args:Array):Dynamic { - var coTable = lualib_create(func); - var result = lualib_resume([coTable].concat(args)); - return result.get(2); - }); - - var wrapperTable = new LuaTable(); - wrapperTable.set("_func", wrapper); - return wrapperTable; - } -} +package luahscript.lualibs; + +import luahscript.LuaAndParams; +import luahscript.LuaInterp; +import luahscript.LuaTable; + +@:build(luahscript.macros.LuaLibMacro.build()) +@:noCompletion +class LuaCoroutineLib { + private static var nextCoroutineId:Int = 0; + private static var runningCoroutine:LuaTable = null; + + private static function checkCoroutine(arg:Dynamic, fnName:String):LuaTable { + if (LuaCheckType.checkType(arg) != TTABLE) { + throw "bad argument #1 to '" + fnName + "' (thread expected)"; + } + + var co = LuaCheckType.checkTable(arg); + if (!co.keyExists("_isCoroutine") || co.get("_isCoroutine") != true) { + throw "bad argument #1 to '" + fnName + "' (thread expected)"; + } + + return co; + } + + private static inline function normalizeResumeResult(v:Dynamic):Array { + if (Std.isOfType(v, LuaAndParams)) { + return (cast v : LuaAndParams).values; + } + return [v]; + } + + public static function lualib_create(func:Dynamic):LuaTable { + if (LuaCheckType.checkType(func) != TFUNCTION) { + throw "bad argument #1 to 'create' (function expected)"; + } + + var co = new LuaTable(); + co.set("_isCoroutine", true); + co.set("_func", func); + co.set("_status", "suspended"); + co.set("_id", nextCoroutineId++); + return co; + } + + @:multiArgs + public static function lualib_resume(args:Array):LuaAndParams { + if (args.length == 0) { + return LuaAndParams.fromArray([false, "bad argument #1 to 'resume' (thread expected)"]); + } + + var co = checkCoroutine(args.shift(), "resume"); + var status = Std.string(co.get("_status")); + + if (status == "dead") { + return LuaAndParams.fromArray([false, "cannot resume dead coroutine"]); + } + + if (status == "running") { + return LuaAndParams.fromArray([false, "cannot resume running coroutine"]); + } + + var func = co.get("_func"); + if (LuaCheckType.checkType(func) != TFUNCTION) { + co.set("_status", "dead"); + return LuaAndParams.fromArray([false, "coroutine has no function"]); + } + + var previous = runningCoroutine; + runningCoroutine = co; + co.set("_status", "running"); + + var values:Array = null; + try { + values = normalizeResumeResult(Reflect.callMethod(null, func, args)); + co.set("_status", "dead"); + } catch (e:Dynamic) { + co.set("_status", "dead"); + runningCoroutine = previous; + return LuaAndParams.fromArray([false, Std.string(e)]); + } + + runningCoroutine = previous; + var output:Array = [true]; + output = output.concat(values); + return LuaAndParams.fromArray(output); + } + + @:multiArgs + public static function lualib_yield(args:Array):LuaAndParams { + if (runningCoroutine == null) { + throw "attempt to yield from outside a coroutine"; + } + + throw "coroutine.yield is not supported yet in luahscript"; + return new LuaAndParams(); + } + + public static function lualib_status(coArg:Dynamic):String { + var co = checkCoroutine(coArg, "status"); + return Std.string(co.get("_status")); + } + + public static function lualib_running():LuaAndParams { + if (runningCoroutine == null) { + var mainInfo:Array = [null, true]; + return LuaAndParams.fromArray(mainInfo); + } + var coInfo:Array = [runningCoroutine, false]; + return LuaAndParams.fromArray(coInfo); + } + + public static function lualib_isyieldable():Bool { + return runningCoroutine != null; + } + + public static function lualib_close(coArg:Dynamic):Bool { + var co = checkCoroutine(coArg, "close"); + var status = Std.string(co.get("_status")); + if (status == "running") { + return false; + } + + co.set("_status", "dead"); + co.set("_func", null); + return true; + } + + public static function lualib_wrap(func:Dynamic):Dynamic { + var co = lualib_create(func); + return Reflect.makeVarArgs(function(args:Array):Dynamic { + var resumeArgs:Array = [co]; + resumeArgs = resumeArgs.concat(args); + var resumed = lualib_resume(resumeArgs); + if (resumed.values.length == 0 || resumed.values[0] != true) { + throw (resumed.values.length > 1 ? resumed.values[1] : "cannot resume coroutine"); + } + + var out = resumed.values.slice(1); + if (out.length == 0) { + return null; + } + if (out.length == 1) { + return out[0]; + } + return LuaAndParams.fromArray(out); + }); + } +} diff --git a/src/luahscript/lualibs/LuaDebugLib.hx b/src/luahscript/lualibs/LuaDebugLib.hx new file mode 100644 index 0000000..df1466f --- /dev/null +++ b/src/luahscript/lualibs/LuaDebugLib.hx @@ -0,0 +1,57 @@ +package luahscript.lualibs; + +import luahscript.LuaInterp; +import luahscript.LuaTable; + +@:build(luahscript.macros.LuaLibMacro.build()) +class LuaDebugLib { + public static function lualib_traceback(?message:Dynamic, ?level:Int):String { + var prefix = message == null ? "" : Std.string(message) + "\n"; + var interp = LuaInterp.getCurrentInterp(); + var stackLevel = (level == null ? 1 : LuaCheckType.checkInteger(level)); + if(stackLevel < 0) stackLevel = 0; + if(interp == null) return prefix + "stack traceback:\n\t"; + return prefix + interp.getDebugTraceback(stackLevel); + } + + public static function lualib_getinfo(v:Dynamic, ?what:String):Dynamic { + if(what != null) LuaCheckType.checkString(what); + + var interp = LuaInterp.getCurrentInterp(); + if(interp == null) return null; + + var level:Int = 1; + switch(LuaCheckType.checkType(v)) { + case TNUMBER: + level = LuaCheckType.checkInteger(v); + case TNIL: + level = 1; + case _: + var info = new LuaTable(); + info.set("name", ""); + info.set("what", "Haxe"); + info.set("source", "=host"); + info.set("short_src", "[host]"); + info.set("currentline", 0); + return info; + } + + if(level < 0) level = 0; + return interp.getDebugInfo(level); + } + + public static function lualib_getmetatable(value:Dynamic):Dynamic { + if(LuaCheckType.checkType(value) == TTABLE) { + return LuaCheckType.checkTable(value).metaTable; + } + return null; + } + + public static function lualib_setmetatable(value:Dynamic, mt:LuaTable):Dynamic { + if(LuaCheckType.checkType(value) != TTABLE) { + throw "bad argument #1 to 'setmetatable' (table expected)"; + } + LuaCheckType.checkTable(value).metaTable = LuaCheckType.checkTable(mt); + return value; + } +} diff --git a/src/luahscript/lualibs/LuaTableLib.hx b/src/luahscript/lualibs/LuaTableLib.hx index 77c16ed..588d3af 100644 --- a/src/luahscript/lualibs/LuaTableLib.hx +++ b/src/luahscript/lualibs/LuaTableLib.hx @@ -1,7 +1,9 @@ package luahscript.lualibs; +import luahscript.LuaAndParams; import luahscript.LuaTable; import luahscript.LuaInterp; +import luahscript.LuaTools; @:build(luahscript.macros.LuaLibMacro.build()) class LuaTableLib { @@ -107,13 +109,16 @@ class LuaTableLib { try { arr.sort(function(a:Dynamic, b:Dynamic):Int { var luaComparisonResult:Dynamic = Reflect.callMethod(null, comp, [a, b]); + if (Std.isOfType(luaComparisonResult, LuaAndParams)) { + var compareParams:LuaAndParams = cast luaComparisonResult; + luaComparisonResult = compareParams.values.length > 0 ? compareParams.values[0] : null; + } if (luaComparisonResult == null) { return 1; } - var haxeBoolResult:Bool = cast luaComparisonResult; - return haxeBoolResult ? -1 : 1; + return LuaTools.luaBool(luaComparisonResult) ? -1 : 1; }); } catch (e:Dynamic) { throw "Invalid comparator function or execution error in table.sort: " + Std.string(e); diff --git a/src/luahscript/macros/LuaLibMacro.hx b/src/luahscript/macros/LuaLibMacro.hx index 0f339bd..3a2eb34 100644 --- a/src/luahscript/macros/LuaLibMacro.hx +++ b/src/luahscript/macros/LuaLibMacro.hx @@ -12,6 +12,43 @@ class LuaLibMacro { static var sbFields:Array; + static inline function isVoidType(ct:Null):Bool { + return switch(ct) { + case TPath(p): p.name == "Void"; + case _: false; + } + } + + static function makeFunctionWrapperExpr(field:Field, func:Function):Expr { + if(field.meta.find(m -> m.name == ":multiArgs") != null) { + return macro Reflect.makeVarArgs($i{field.name}); + } + + var callArgs:Array = []; + for(i => arg in func.args) { + var valueExpr:Expr = if(arg.value != null) { + macro (args.length > $v{i} ? args[$v{i}] : $e{arg.value}); + } else if(arg.opt) { + macro (args.length > $v{i} ? args[$v{i}] : null); + } else { + macro args[$v{i}]; + } + callArgs.push(valueExpr); + } + + final callExpr = macro $i{field.name}($a{callArgs}); + if(isVoidType(func.ret)) { + return macro Reflect.makeVarArgs(function(args:Array) { + $callExpr; + return null; + }); + } + + return macro Reflect.makeVarArgs(function(args:Array) { + return $callExpr; + }); + } + public static function build():Array { var fields = Context.getBuildFields(); sbFields = []; @@ -38,8 +75,15 @@ class LuaLibMacro { } static inline function makeImplements():Field { - var sb:Array = [for(f in sbFields) {field: f.name.substr(LUALIB_PREFFIX.length), expr: if(f.kind.match(FFun(_)) && f.meta.find(m -> m.name == ":multiArgs") != null) macro Reflect.makeVarArgs($i{f.name}) - else macro $i{f.name}}]; + var sb:Array = [for(f in sbFields) { + field: f.name.substr(LUALIB_PREFFIX.length), + expr: switch(f.kind) { + case FFun(func): + makeFunctionWrapperExpr(f, func); + case _: + macro $i{f.name}; + } + }]; return { name: "implement", access: [APublic, AStatic, AInline], @@ -86,4 +130,4 @@ class LuaLibMacro { return fields; } -} \ No newline at end of file +} diff --git a/test.lua b/test.lua index a1d4d05..0ac46c3 100644 --- a/test.lua +++ b/test.lua @@ -327,9 +327,87 @@ _G["global_test1"] = _G["global_test1"] + 1 print("结果: ", _G["global_test1"]) print("_G['field']以及_G.field以及原地址field是否相同", _G.global_test1 == global_test1 and _G["global_test1"] == global_test1) -local lh = MyClass.new() -print('Haxe测试', lh.greeting) -print('sayhallo', lh.sayHello()) ---后面兼容:字符吧 ---print('sayhallo', lh:sayHello()) +print() +print("15. debug模块") + +local function debug_level2() + local info = debug.getinfo(1) + assert(info ~= nil, "debug.getinfo 应该返回表") + assert(type(info.name) == "string", "debug.getinfo.name 应该是字符串") + print("当前函数:", info.name, "行:", info.currentline) + + local trace = debug.traceback("手动追踪") + assert(type(trace) == "string", "debug.traceback 应该返回字符串") + assert(string.find(trace, "stack traceback") ~= nil, "traceback 文本格式不正确") + print(trace) +end + +local function debug_level1() + debug_level2() +end + +debug_level1() + +print() +print("16. require模块") + +if io ~= nil then + local mod1, from1 = require("testmods.mathutils") + assert(mod1 ~= nil, "require('testmods.mathutils') 应该返回非空值") + local addFn = nil + local canReadAdd = pcall(function() + addFn = mod1.add + end) + if canReadAdd and addFn ~= nil then + assert(addFn(7, 5) == 12, "testmods.mathutils.add 行为错误") + end + print("testmods.mathutils from:", from1) + + local requireAgainOk = pcall(function() + require("testmods.mathutils") + end) + assert(requireAgainOk, "require 第二次加载失败") + + local pkgOk, pkg, from2 = pcall(function() + return require("testmods") + end) + assert(pkgOk, "require('testmods') 执行失败") + print("testmods from:", from2) +else + print("跳过文件模块 require 测试(当前目标不支持文件系统)") +end + +print() +print("17. coroutine模块") + +local runningCo, isMain = coroutine.running() +assert(runningCo == nil and isMain == true, "主线程 coroutine.running 结果不正确") + +local co = coroutine.create(function(a, b) + return a + b +end) + +assert(coroutine.status(co) == "suspended", "新建协程应为 suspended") +local ok, sumv = coroutine.resume(co, 9, 4) +assert(ok == true and sumv == 13, "coroutine.resume 返回值不正确") +assert(coroutine.status(co) == "dead", "协程执行后应为 dead") + +local ok2, err2 = coroutine.resume(co) +assert(ok2 == false and type(err2) == "string", "dead 协程再次 resume 应失败") + +local wrapped = coroutine.wrap(function(name) + return "hello " .. name +end) +assert(wrapped("lua") == "hello lua", "coroutine.wrap 返回值不正确") + +local yieldOk = pcall(function() + coroutine.yield("x") +end) +assert(yieldOk == false, "主线程调用 coroutine.yield 应失败") + +local closeCo = coroutine.create(function() + return 1 +end) +assert(coroutine.close(closeCo) == true, "coroutine.close 应返回 true") + print("=== Lua 语法测试完成 ===") diff --git a/tests/testmods/init.lua b/tests/testmods/init.lua new file mode 100644 index 0000000..8da3131 --- /dev/null +++ b/tests/testmods/init.lua @@ -0,0 +1,4 @@ +return { + tag = "init-ok", + value = 42 +} diff --git a/tests/testmods/mathutils.lua b/tests/testmods/mathutils.lua new file mode 100644 index 0000000..95c0f79 --- /dev/null +++ b/tests/testmods/mathutils.lua @@ -0,0 +1,11 @@ +local M = {} + +function M.add(a, b) + return a + b +end + +function M.sub(a, b) + return a - b +end + +return M From 3c2a8ba68bda9f59a6f3594601ee0c848b0e642a Mon Sep 17 00:00:00 2001 From: Ajwyunsx <107187521+Ajwyunsx@users.noreply.github.com> Date: Sun, 22 Feb 2026 12:42:11 +0000 Subject: [PATCH 6/7] Upload run.n --- run.n | Bin 211729 -> 228692 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/run.n b/run.n index f53e8b7edac1e85615bf16ff1b0da256da475b76..c85ae56dada67546dd97bc864b5e752ed1b1f969 100644 GIT binary patch delta 58637 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ƭIu}BwBEO5p1Qn>QO;!MPG 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 yDJ-uWrPbVA(k#=!Ql>?cr$haSu5>&J) Date: Sun, 22 Feb 2026 20:53:33 +0800 Subject: [PATCH 7/7] Fix LHScript type imports and restore pcall error semantics --- src/lhscript/LHScript.hx | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/lhscript/LHScript.hx b/src/lhscript/LHScript.hx index fd0c655..e56c663 100644 --- a/src/lhscript/LHScript.hx +++ b/src/lhscript/LHScript.hx @@ -7,7 +7,7 @@ import luahscript.LuaParser; import luahscript.exprs.LuaExpr; import luahscript.LuaAndParams; import luahscript.exprs.*; -import luahscript.exprs.LuaErrorDef.LuaVariableType; +import luahscript.exprs.LuaError.LuaVariableType; import haxe.Constraints.IMap; @:access(luahscript.LuaInterp) @@ -292,7 +292,7 @@ class LHScript { type = LHScript.UNKNOWN; } }); - return interp.error(ECallNilValue(sb, type == LOCAL ? LOCAL_VAR_TYPE : (type == GLOBAL ? GLOBAL_VAR_TYPE : (type == FIELD ? FIELD_VAR_TYPE : UNKNOWN_VAR_TYPE))), e.line); + return interp.error(ECallInvalidValue(sb, type == LOCAL ? LOCAL_VAR_TYPE : (type == GLOBAL ? GLOBAL_VAR_TYPE : (type == FIELD ? FIELD_VAR_TYPE : UNKNOWN_VAR_TYPE)), TNIL), e.line); } if (isDouble) { if (Reflect.isObject(obj) && !Std.isOfType(obj, luahscript.LuaTable)) { @@ -335,7 +335,7 @@ class LHScript { type = LHScript.UNKNOWN; } }); - return interp.error(ECallNilValue(sb, type == LOCAL ? LOCAL_VAR_TYPE : (type == GLOBAL ? GLOBAL_VAR_TYPE : (type == FIELD ? FIELD_VAR_TYPE : UNKNOWN_VAR_TYPE))), e.line); + return interp.error(ECallInvalidValue(sb, type == LOCAL ? LOCAL_VAR_TYPE : (type == GLOBAL ? GLOBAL_VAR_TYPE : (type == FIELD ? FIELD_VAR_TYPE : UNKNOWN_VAR_TYPE)), TNIL), e.line); } return try Reflect.callMethod(null, func, args) catch(e:haxe.Exception) throw interp.error(ECustom(Std.string(e)), 0); } @@ -741,18 +741,26 @@ class LHScript { return null; })); - var originalPcall = interp.globals.get("pcall"); - interp.globals.set("pcall", Reflect.makeVarArgs(function(args:Array) { - if (args.length >= 1) { - var funcExpr = args[0]; - var callArgs = args.slice(1); - - try { - var result = callFunction(funcExpr, callArgs); - return luahscript.LuaAndParams.fromArray([true, result]); - } catch (e:Dynamic) { - return luahscript.LuaAndParams.fromArray([false, Std.string(e)]); - } + var originalPcall = interp.globals.get("pcall"); + interp.globals.set("pcall", Reflect.makeVarArgs(function(args:Array) { + if (args.length >= 1) { + var funcExpr = args[0]; + if (originalPcall != null && Reflect.isFunction(originalPcall) && Reflect.isFunction(funcExpr)) { + return Reflect.callMethod(null, originalPcall, args); + } + var callArgs = args.slice(1); + + try { + var result = callFunction(funcExpr, callArgs); + if (Std.isOfType(result, luahscript.LuaAndParams)) { + var values:Array = [true]; + values = values.concat((cast result : luahscript.LuaAndParams).values); + return luahscript.LuaAndParams.fromArray(values); + } + return luahscript.LuaAndParams.fromArray([true, result]); + } catch (e:Dynamic) { + return luahscript.LuaAndParams.fromArray([false, Std.string(e)]); + } } if (originalPcall != null && Reflect.isFunction(originalPcall)) { return Reflect.callMethod(null, originalPcall, args);