internal static ForeignObject Allocate <T>(VirtualMachine vm) where T : ForeignObject { // Try to allocate given this object's constructors with descending arity var constructors = typeof(T).GetConstructors().Where(IsPublic) .OrderByDescending(ctor => ctor.GetParameters().Length).ToList(); foreach (var ctor in constructors) { var parameters = ctor.GetParameters().Reverse().ToList(); var givenParameters = new List <object>(); var parametersMatch = true; if (parameters.Count > 0) { for (int i = parameters.Count; i > 0; i--) { var param = parameters[i - 1]; switch (vm.GetSlotType(i)) { case Wren.ValueType.WREN_TYPE_BOOL: parametersMatch &= param.ParameterType == typeof(bool); if (parametersMatch) { givenParameters.Insert(0, vm.GetSlotBool(i)); } break; case Wren.ValueType.WREN_TYPE_NUM: parametersMatch &= param.ParameterType == typeof(double); if (parametersMatch) { givenParameters.Insert(0, vm.GetSlotDouble(i)); } break; case Wren.ValueType.WREN_TYPE_STRING: parametersMatch &= param.ParameterType == typeof(string); if (parametersMatch) { givenParameters.Insert(0, vm.GetSlotString(i)); } break; default: parametersMatch = false; break; } } } if (parametersMatch) { var foreignObject = (ForeignObject)ctor.Invoke(givenParameters.ToArray()); foreignObject.VirtualMachine = vm; return(foreignObject); } } return(null); }
public void ForeignObjectMethodAcceptsOddArguments() { var classModule = "boolBot"; var vm = new Wren.VirtualMachine(new Configuration { RaiseExceptionOnError = true }); vm.BindForeign <MathBot>(classModule); vm.Interpret(classModule, @"foreign class MathBot { construct new() {} foreign add(a,b) foreign addInts(a,b) foreign addStrings(a,b) foreign and(a,b) foreign not(a) foreign badActualParam(a) }"); vm.Interpret(classModule, "var bot = MathBot.new()"); #region MathBot.add vm.EnsureSlots(3); vm.GetVariable(classModule, "bot", 0); var addHandle = vm.MakeCallHandle("add(_,_)"); vm.SetSlot(1, 1); vm.SetSlot(2, 2.3d); vm.Call(addHandle); Assert.True(vm.GetSlotType(0) == Wren.ValueType.WREN_TYPE_NUM, "MathBot.add result is a number value"); Assert.Equal(3.3d, vm.GetSlotDouble(0)); #endregion #region MathBot.addInts vm.EnsureSlots(3); vm.GetVariable(classModule, "bot", 0); var addIntsHandle = vm.MakeCallHandle("addInts(_,_)"); vm.SetSlot(1, 4); vm.SetSlot(2, 5.5); vm.Call(addIntsHandle); Assert.True(vm.GetSlotType(0) == Wren.ValueType.WREN_TYPE_NUM, "MathBot.addInts result is a number value"); Assert.Equal(9, vm.GetSlotDouble(0)); #endregion #region MathBot.addStrings vm.EnsureSlots(3); vm.GetVariable(classModule, "bot", 0); var addStringsHandle = vm.MakeCallHandle("addStrings(_,_)"); vm.EnsureSlots(3); vm.GetVariable(classModule, "bot", 0); vm.SetSlot(1, 4.5); vm.SetSlot(2, "foo"); vm.Call(addStringsHandle); Assert.True(vm.GetSlotType(0) == Wren.ValueType.WREN_TYPE_STRING, "MathBot.addStrings result is a string value"); Assert.Equal("4.5foo", vm.GetSlotString(0)); vm.EnsureSlots(3); vm.GetVariable(classModule, "bot", 0); vm.SetSlot(1, false); vm.SetSlot(2, 42); vm.Call(addStringsHandle); Assert.True(vm.GetSlotType(0) == Wren.ValueType.WREN_TYPE_STRING, "MathBot.addStrings result is a string value"); Assert.Equal("False42", vm.GetSlotString(0)); #endregion #region MathBot.and vm.EnsureSlots(3); vm.GetVariable(classModule, "bot", 0); var andHandle = vm.MakeCallHandle("and(_,_)"); vm.SetSlot(1, false); vm.SetSlot(2, true); vm.Call(andHandle); Assert.True(vm.GetSlotType(0) == Wren.ValueType.WREN_TYPE_BOOL, "MathBot.and result is a bool value"); Assert.Equal(false, vm.GetSlotBool(0)); #endregion #region MathBot.not vm.EnsureSlots(2); vm.GetVariable(classModule, "bot", 0); var notHandle = vm.MakeCallHandle("not(_)"); vm.SetSlot(1, false); vm.Call(notHandle); Assert.True(vm.GetSlotType(0) == Wren.ValueType.WREN_TYPE_BOOL, "MathBot.not result is a bool value"); Assert.Equal(true, vm.GetSlotBool(0)); #endregion #region MathBot.badActualParam vm.EnsureSlots(2); vm.GetVariable(classModule, "bot", 0); var badActualParamHandle = vm.MakeCallHandle("badActualParam(_)"); vm.SetSlot(1, 4.5d); var ex = Assert.Throws <WrenException>(() => vm.Call(badActualParamHandle)); Assert.StartsWith("Foreign method 'BadActualParam' parameter 'a' type mismatch given actual parameter of type System.Double (4.5 in slot 1", ex.Message); vm.EnsureSlots(2); vm.GetVariable(classModule, "bot", 0); vm.SetSlot(1, badActualParamHandle); ex = Assert.Throws <WrenException>(() => vm.Call(badActualParamHandle)); Assert.StartsWith("Foreign method 'BadActualParam' parameter 'a' type mismatch given actual parameter of type Unknown (Unknown in slot 1", ex.Message); #endregion addHandle.Dispose(); addIntsHandle.Dispose(); addStringsHandle.Dispose(); andHandle.Dispose(); notHandle.Dispose(); badActualParamHandle.Dispose(); vm.Dispose(); }