예제 #1
0
        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);
        }
예제 #2
0
        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();
        }