public void TestCall()
        {
            for (int i = 1; i <= 16; i++)
            {
                using (var container = new Win64Container())
                {
                    var mainFunc = TestProgramGenerator.AddMainFunction(container, i);
                    mainFunc.Optimize = true;

                    var addFunc = TestProgramGenerator.AddFunction(container, i);
                    addFunc.Optimize = true;

                    var assembly = new Assembly(mainFunc, addFunc);

                    container.VirtualMachine.LoadAssembly(assembly);
                    Assert.AreEqual(i * (1 + i) / 2, container.Execute());
                }
            }
        }
        public void TestAlreadyDefined()
        {
            using (var container = new Win64Container())
            {
                var intType = container.VirtualMachine.TypeProvider.GetPrimitiveType(PrimitiveTypes.Int);

                var func1 = new Function(
                    new FunctionDefinition("test", new List<VMType>(), intType),
                    new List<Instruction>()
                    {
                        new Instruction(OpCodes.LoadInt, 0),
                        new Instruction(OpCodes.Ret)
                    },
                    new List<VMType>());

                var func2 = new Function(
                    new FunctionDefinition("test", new List<VMType>(), intType),
                    new List<Instruction>()
                    {
                        new Instruction(OpCodes.LoadInt, 0),
                        new Instruction(OpCodes.Ret)
                    },
                    new List<VMType>());

                var assembly = new Assembly(func1, func2);

                try
                {
                    container.LoadAssembly(assembly);
                    Assert.Fail("Expected already defined to not pass.");
                }
                catch (Exception e)
                {
                    Assert.AreEqual("The function 'test() Int' is already defined.", e.Message);
                }
            }
        }
        public void TestRecursive2()
        {
            using (var container = new Win64Container())
            {
                var mainFunc = TestProgramGenerator.MainWithIntCall(container, "fib", 11);
                mainFunc.Optimize = true;

                var sumFunc = TestProgramGenerator.RecursiveFib(container);
                sumFunc.Optimize = true;

                var assembly = new Assembly(mainFunc, sumFunc);

                container.LoadAssembly(assembly);
                Assert.AreEqual(89, container.Execute());
            }
        }
        public void TestMixed3()
        {
            using (var container = new Win64Container())
            {
                var intType = container.VirtualMachine.TypeProvider.GetPrimitiveType(PrimitiveTypes.Int);
                var floatType = container.VirtualMachine.TypeProvider.GetPrimitiveType(PrimitiveTypes.Float);

                container.VirtualMachine.Binder.Define(FunctionDefinition.NewExternal<FuncFloatArgInt>(
                    "intToFloat",
                    new List<VMType>() { intType },
                    floatType,
                    FloatToInt));

                var convIntToFloat = new Instruction(OpCodes.Call, "intToFloat", new List<VMType>() { intType });
                var paramTypes = new List<VMType>() { intType, floatType, intType, floatType, intType, floatType };

                var addFunc = new Function(
                    new FunctionDefinition("add", paramTypes, floatType),
                    new List<Instruction>()
                    {
                        new Instruction(OpCodes.LoadArgument, 0),
                        convIntToFloat,
                        new Instruction(OpCodes.LoadArgument, 1),
                        new Instruction(OpCodes.LoadArgument, 2),
                        convIntToFloat,
                        new Instruction(OpCodes.LoadArgument, 3),
                        new Instruction(OpCodes.LoadArgument, 4),
                        convIntToFloat,
                        new Instruction(OpCodes.LoadArgument, 5),
                        new Instruction(OpCodes.AddFloat),
                        new Instruction(OpCodes.AddFloat),
                        new Instruction(OpCodes.AddFloat),
                        new Instruction(OpCodes.AddFloat),
                        new Instruction(OpCodes.AddFloat),
                        new Instruction(OpCodes.Ret)
                    },
                    new List<VMType>());
                addFunc.Optimize = true;

                var mainFunc = new Function(
                    new FunctionDefinition("floatMain", new List<VMType>(), floatType),
                    new List<Instruction>()
                    {
                        new Instruction(OpCodes.LoadInt, 1),
                        new Instruction(OpCodes.LoadFloat, 2.0f),
                        new Instruction(OpCodes.LoadInt, 3),
                        new Instruction(OpCodes.LoadFloat, 4.0f),
                        new Instruction(OpCodes.LoadInt, 5),
                        new Instruction(OpCodes.LoadFloat, 6.0f),
                        new Instruction(OpCodes.Call, "add", paramTypes),
                        new Instruction(OpCodes.Ret)
                    },
                    new List<VMType>());
                mainFunc.Optimize = true;

                var assembly = new Assembly(mainFunc, addFunc);

                container.VirtualMachine.LoadAssembly(assembly);
                Assert.AreEqual(1 + 2 + 3 + 4 + 5 + 6, TestProgramGenerator.ExecuteFloatProgram(container));
            }
        }
        /// <summary>
        /// Loads the given assembly
        /// </summary>
        /// <param name="assembly">The assembly</param>
        public void LoadAssembly(Assembly assembly)
        {
            this.loadedAssemblies.Add(assembly);

            foreach (var function in assembly.Functions)
            {
                if (function.Definition.Name == "main")
                {
                    if (!(function.Definition.Parameters.Count == 0
                          && function.Definition.ReturnType.IsPrimitiveType(PrimitiveTypes.Int)))
                    {
                        throw new Exception("Expected the main function to have the signature: 'main() Int'.");
                    }
                }

                if (!this.Binder.Define(function.Definition))
                {
                    throw new Exception($"The function '{function.Definition}' is already defined.");
                }
            }
        }
 /// <summary>
 /// Loads the given assembly
 /// </summary>
 /// <param name="assembly">The assembly</param>
 public void LoadAssembly(Assembly assembly)
 {
     this.VirtualMachine.LoadAssembly(assembly);
 }
        public void TestArguments()
        {
            for (int i = 16; i <= 16; i++)
            {
                using (var container = new Win64Container())
                {
                    var assembly = new Assembly(
                        TestProgramGenerator.AddMainFunction(container, i),
                        TestProgramGenerator.AddFunction(container, i));

                    container.VirtualMachine.LoadAssembly(assembly);
                    Assert.AreEqual(i * (1 + i) / 2, container.Execute());
                }
            }
        }
        public void TestRecursive2()
        {
            using (var container = new Win64Container())
            {
                var assembly = new Assembly(
                    TestProgramGenerator.MainWithIntCall(container, "fib", 11),
                    TestProgramGenerator.RecursiveFib(container));

                container.LoadAssembly(assembly);
                Assert.AreEqual(89, container.Execute());
            }
        }
        public void TestRecursive1()
        {
            using (var container = new Win64Container())
            {
                var assembly = new Assembly(
                    TestProgramGenerator.MainWithIntCall(container, "sum", 10),
                    TestProgramGenerator.ResursiveSum(container));

                container.LoadAssembly(assembly);
                Assert.AreEqual(55, container.Execute());
            }
        }
        public void TestFloatArguments()
        {
            for (int i = 1; i <= 16; i++)
            {
                using (var container = new Win64Container())
                {
                    var assembly = new Assembly(
                        TestProgramGenerator.FloatAddMainFunction(container, i),
                        TestProgramGenerator.FloatAddFunction(container, i));

                    container.VirtualMachine.LoadAssembly(assembly);
                    container.VirtualMachine.Compile();
                    var funcPtr = Marshal.GetDelegateForFunctionPointer<FloatMain>(
                        container.VirtualMachine.Binder.GetFunction("floatMain()").EntryPoint);
                    Assert.AreEqual(i * (1 + i) / 2, funcPtr());
                }
            }
        }
        public void TestOverload()
        {
            using (var container = new Win64Container())
            {
                var intType = container.VirtualMachine.TypeProvider.GetPrimitiveType(PrimitiveTypes.Int);
                var floatType = container.VirtualMachine.TypeProvider.GetPrimitiveType(PrimitiveTypes.Float);

                var func1 = new Function(
                    new FunctionDefinition("test", new List<VMType>() { intType }, intType),
                    new List<Instruction>()
                    {
                        new Instruction(OpCodes.LoadInt, 0),
                        new Instruction(OpCodes.Ret)
                    },
                    new List<VMType>());

                var func2 = new Function(
                    new FunctionDefinition("test", new List<VMType>() { floatType }, floatType),
                    new List<Instruction>()
                    {
                        new Instruction(OpCodes.LoadFloat, 0.0f),
                        new Instruction(OpCodes.Ret)
                    },
                    new List<VMType>());

                var assembly = new Assembly(func1, func2);
                container.LoadAssembly(assembly);
            }
        }