<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using ZScript.Elements;
using ZScript.Runtime.Execution;
using ZScript.Runtime.Execution.VirtualMemory;

namespace ZScript.Runtime
{
    /// <summary>
    /// Represents a runtime that is encapsulated
    /// </summary>
    public class ZRuntime
    {
        /// <summary>
        /// The owner of this ZRuntime
        /// </summary>
        private readonly IRuntimeOwner _owner;

        /// <summary>
        /// The ZRuntimeDefinition that was used to create this runtime
        /// </summary>
        private readonly ZRuntimeDefinition _definition;

        /// <summary>
        /// Stack of local memories for the currently executing functions.
        /// Used to enable closure capture
        /// </summary>
        private readonly Stack<IMemory<string>> _localMemoriesStack;

        /// <summary>
        /// Whether the runtime has expanded the global variables yet
        /// </summary>
        private bool _expandedGlobals;

        /// <summary>
        /// The list of all functions defined in this ZRuntime instance
        /// </summary>
        private readonly ZFunction[] _zFunction;

        /// <summary>
        /// The global memory for the runtime
        /// </summary>
        private readonly Memory _globalMemory;

        /// <summary>
        /// The global memory for the runtime
        /// </summary>
        private readonly IntegerMemory _globalAddressedMemory;

        /// <summary>
        /// Gets the current global memory for the runtime
        /// </summary>
        public IMemory<string> GlobalMemory
        {
            get
            {
                return _globalMemory;
            }
        }

        /// <summary>
        /// Gets the owner of this ZRuntime object
        /// </summary>
        public IRuntimeOwner Owner
        {
            get { return _owner; }
        }

        /// <summary>
        /// Initializes a new instance of the ZRuntime class from the following definition, and with an owner to specify
        /// </summary>
        /// <param name="definition">The runtime definition object to create this runtime from</param>
        /// <param name="owner">The owner of this ZRuntime</param>
        public ZRuntime(ZRuntimeDefinition definition, IRuntimeOwner owner)
        {
            _definition = definition;
            _zFunction = definition.ZFunctionDefinitions.Concat(definition.ZExportFunctionDefinitions).Concat(definition.ZClosureFunctionDefinitions).ToArray();
            _localMemoriesStack = new Stack<IMemory<string>>();
            _owner = owner;
            _globalMemory = new Memory();
            _globalAddressedMemory = new IntegerMemory();
        }

        /// <summary>
        /// Calls a function with a specified name, using an array of objects as arguments.
        /// The method raises an exception when the function call fails for any reason
        /// </summary>
        /// <param name="functionName">The name of the function to execute</param>
        /// <param name="arguments">The arguments for the function to execute</param>
        /// <returns>The return of the function that was called</returns>
        /// <exception cref="ArgumentException">A function with the specified name does not exists</exception>
        /// <exception cref="Exception">The function call failed</exception>
        public object CallFunction(string functionName, params object[] arguments)
        {
            var funcDef = FunctionWithName(functionName);

            if(funcDef == null)
                throw new Exception("Trying to call undefined function '" + functionName + "'");

            return CallFunction(funcDef, arguments);
        }

        /// <summary>
        /// Calls a specified function, using an array of objects as arguments.
        /// The method raises an exception when the function call fails for any reason
        /// </summary>
        /// <param name="funcDef">The function to execute</param>
        /// <param name="arguments">The arguments for the function to execute</param>
        /// <returns>The return of the function that was called</returns>
        /// <exception cref="ArgumentException">A function with the specified name does not exists</exception>
        /// <exception cref="Exception">The function call failed</exception>
        public object CallFunction(ZFunction funcDef, params object[] arguments)
        {
            if (!_expandedGlobals)
            {
                ExpandGlobalVariables();
            }

            if (funcDef == null)
                return null;

            // Export functions are handled separatedly
            var exportFunction = funcDef as ZExportFunction;
            if (exportFunction != null)
            {
                return _owner.CallFunction(exportFunction, arguments);
            }

            IMemory<string> localMemory = Memory.CreateMemoryFromArgs(funcDef, true, arguments);

            // Closures must trap the local memory into their own scope
            if (funcDef.IsClosure)
            {
                ((ZClosureFunction)funcDef).CapturedMemory.AddMemory(localMemory);

                localMemory = ((ZClosureFunction)funcDef).CapturedMemory;
            }

            MemoryMapper mapper = new MemoryMapper();
            mapper.AddMemory(_globalMemory);
            mapper.AddMemory(localMemory);

            _localMemoriesStack.Push(localMemory);

            FunctionVM vm = new FunctionVM(funcDef.Tokens, new VmContext(mapper, _globalAddressedMemory, this));

            vm.Execute();

            if (vm.HasReturnValue)
            {
                return vm.ReturnValue;
            }

            _localMemoriesStack.Pop();

            // Disabling this exception for now because it may interfere with function calls that do not expect a return value anyways
            /*throw new Exception("The function called did not return any value because it did not execute a 'return' statement with a value specified.");*/

            return null;
        }

        /// <summary>
        /// Fetches a function definition by name on this ZRuntime object, or null, if none was found
        /// </summary>
        /// <param name="functionName">The name of the function to fetch</param>
        /// <param name="captureClosures">Whether to automatically capture closures when fetching by name</param>
        /// <returns>The function definition with the given name, or null, if none was found</returns>
        public ZFunction FunctionWithName(string functionName, bool captureClosures = true)
        {<commit_msg>Fixing memory leak due to local memories not being popped when a function returned a value<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using ZScript.Elements;
using ZScript.Runtime.Execution;
using ZScript.Runtime.Execution.VirtualMemory;

namespace ZScript.Runtime
{
    /// <summary>
    /// Represents a runtime that is encapsulated
    /// </summary>
    public class ZRuntime
    {
        /// <summary>
        /// The owner of this ZRuntime
        /// </summary>
        private readonly IRuntimeOwner _owner;

        /// <summary>
        /// The ZRuntimeDefinition that was used to create this runtime
        /// </summary>
        private readonly ZRuntimeDefinition _definition;

        /// <summary>
        /// Stack of local memories for the currently executing functions.
        /// Used to enable closure capture
        /// </summary>
        private readonly Stack<IMemory<string>> _localMemoriesStack;

        /// <summary>
        /// Whether the runtime has expanded the global variables yet
        /// </summary>
        private bool _expandedGlobals;

        /// <summary>
        /// The list of all functions defined in this ZRuntime instance
        /// </summary>
        private readonly ZFunction[] _zFunction;

        /// <summary>
        /// The global memory for the runtime
        /// </summary>
        private readonly Memory _globalMemory;

        /// <summary>
        /// The global memory for the runtime
        /// </summary>
        private readonly IntegerMemory _globalAddressedMemory;

        /// <summary>
        /// Gets the current global memory for the runtime
        /// </summary>
        public IMemory<string> GlobalMemory
        {
            get
            {
                return _globalMemory;
            }
        }

        /// <summary>
        /// Gets the owner of this ZRuntime object
        /// </summary>
        public IRuntimeOwner Owner
        {
            get { return _owner; }
        }

        /// <summary>
        /// Initializes a new instance of the ZRuntime class from the following definition, and with an owner to specify
        /// </summary>
        /// <param name="definition">The runtime definition object to create this runtime from</param>
        /// <param name="owner">The owner of this ZRuntime</param>
        public ZRuntime(ZRuntimeDefinition definition, IRuntimeOwner owner)
        {
            _definition = definition;
            _zFunction = definition.ZFunctionDefinitions.Concat(definition.ZExportFunctionDefinitions).Concat(definition.ZClosureFunctionDefinitions).ToArray();
            _localMemoriesStack = new Stack<IMemory<string>>();
            _owner = owner;
            _globalMemory = new Memory();
            _globalAddressedMemory = new IntegerMemory();
        }

        /// <summary>
        /// Calls a function with a specified name, using an array of objects as arguments.
        /// The method raises an exception when the function call fails for any reason
        /// </summary>
        /// <param name="functionName">The name of the function to execute</param>
        /// <param name="arguments">The arguments for the function to execute</param>
        /// <returns>The return of the function that was called</returns>
        /// <exception cref="ArgumentException">A function with the specified name does not exists</exception>
        /// <exception cref="Exception">The function call failed</exception>
        public object CallFunction(string functionName, params object[] arguments)
        {
            var funcDef = FunctionWithName(functionName);

            if(funcDef == null)
                throw new Exception("Trying to call undefined function '" + functionName + "'");

            return CallFunction(funcDef, arguments);
        }

        /// <summary>
        /// Calls a specified function, using an array of objects as arguments.
        /// The method raises an exception when the function call fails for any reason
        /// </summary>
        /// <param name="funcDef">The function to execute</param>
        /// <param name="arguments">The arguments for the function to execute</param>
        /// <returns>The return of the function that was called</returns>
        /// <exception cref="ArgumentException">A function with the specified name does not exists</exception>
        /// <exception cref="Exception">The function call failed</exception>
        public object CallFunction(ZFunction funcDef, params object[] arguments)
        {
            if (!_expandedGlobals)
            {
                ExpandGlobalVariables();
            }

            if (funcDef == null)
                return null;

            // Export functions are handled separatedly
            var exportFunction = funcDef as ZExportFunction;
            if (exportFunction != null)
            {
                return _owner.CallFunction(exportFunction, arguments);
            }

            IMemory<string> localMemory = Memory.CreateMemoryFromArgs(funcDef, true, arguments);

            // Closures must trap the local memory into their own scope
            if (funcDef.IsClosure)
            {
                ((ZClosureFunction)funcDef).CapturedMemory.AddMemory(localMemory);

                localMemory = ((ZClosureFunction)funcDef).CapturedMemory;
            }

            MemoryMapper mapper = new MemoryMapper();
            mapper.AddMemory(_globalMemory);
            mapper.AddMemory(localMemory);

            _localMemoriesStack.Push(localMemory);

            FunctionVM vm = new FunctionVM(funcDef.Tokens, new VmContext(mapper, _globalAddressedMemory, this));
            vm.Execute();

            _localMemoriesStack.Pop();

            mapper.Clear();

            if (vm.HasReturnValue)
            {
                return vm.ReturnValue;
            }

            // Disabling this exception for now because it may interfere with function calls that do not expect a return value anyways
            /*throw new Exception("The function called did not return any value because it did not execute a 'return' statement with a value specified.");*/

            return null;
        }

        /// <summary>
        /// Fetches a function definition by name on this ZRuntime object, or null, if none was found
        /// </summary>
        /// <param name="functionName">The name of the function to fetch</param>
        /// <param name="captureClosures">Whether to automatically capture closures when fetching by name</param>
        /// <returns>The function definition with the given name, or null, if none was found</returns>
        public ZFunction FunctionWithName(string functionName, bool captureClosures = true)
        {
{'fraction_non_alphanumeric': 0.09200029821814658, 'fraction_numerical': 0.0, 'mean_word_length': 2.0293586269196027, 'pattern_counts': {'":': 0, '<': 131, '<?xml version=': 0, '>': 131, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3190983', 'n_tokens_mistral': 3124, 'n_tokens_neox': 3015, 'n_words': 1090}