<commit_before>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mond.Binding;
using Mond.Repl.Modules;

namespace Mond.Repl
{
    [MondModule("")]
    class Functions
    {
        private static List<KeyValuePair<string, MondValue>> _values;

        public static string Definitions { get; private set; }

        static Functions()
        {
            var functions = MondModuleBinder.BindFunctions<Functions>()
                                            .ToDictionary(kv => kv.Key, kv => new MondValue(kv.Value));

            var modules = new Dictionary<string, MondValue>
            {
                { "Math", MondMath.Binding }
            };

            _values = functions.Concat(modules).ToList();

            if (_values.Count == 0)
            {
                Definitions = "";
                return;
            }

            Definitions = "const " + string.Join(",", _values.Select(v => string.Format("{0}=global.{0}", v.Key))) + ";";
        }

        public static void Register(MondState state)
        {
            foreach (var kv in _values)
            {
                state[kv.Key] = kv.Value;
            }
        }

        [MondFunction("require")]
        public static MondValue Require(MondState state, string fileName)
        {
            // make sure we have somewhere to cache modules
            if (state["__modules"].Type != MondValueType.Object)
                state["__modules"] = new MondValue(state);

            // return cached module if it exists
            var cachedExports = state["__modules"][fileName];
            if (cachedExports)
                return cachedExports;

            // create a new object to store the exports
            var exports = new MondValue(state);
            exports.Prototype = null;

            // instantly cache it so we can have circular dependencies
            state["__modules"][fileName] = exports;

            // wrap the module script in a function so we can pass out exports object to it
            var moduleSource = File.ReadAllText(fileName);
            var source = Definitions + "return fun Module(exports) {" + moduleSource + "return exports; };";

            var program = MondProgram.Compile(source, fileName);
            var initializer = state.Load(program);

            var result = state.Call(initializer, exports);

            if (result.Type != MondValueType.Object)
                throw new MondRuntimeException("Modules must return an Object");

            if (!ReferenceEquals(exports, result))
            {
                // module returned a different object, merge with ours
                exports.Prototype = result.Prototype;

                foreach (var kv in result.RawEnumerate())
                {
                    var key = kv["key"];
                    var value = kv["value"];

                    exports[key] = value;
                }
            }

            return exports;
        }

        [MondFunction("print")]
        public static void Print(params MondValue[] arguments)
        {
            foreach (var v in arguments)
            {
                Console.Write((string)v);
            }
        }

        [MondFunction("printLn")]
        public static void PrintLn(params MondValue[] arguments)<commit_msg>Fix require caching modules that fail to load<commit_after>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mond.Binding;
using Mond.Repl.Modules;

namespace Mond.Repl
{
    [MondModule("")]
    class Functions
    {
        private static List<KeyValuePair<string, MondValue>> _values;

        public static string Definitions { get; private set; }

        static Functions()
        {
            var functions = MondModuleBinder.BindFunctions<Functions>()
                                            .ToDictionary(kv => kv.Key, kv => new MondValue(kv.Value));

            var modules = new Dictionary<string, MondValue>
            {
                { "Math", MondMath.Binding }
            };

            _values = functions.Concat(modules).ToList();

            if (_values.Count == 0)
            {
                Definitions = "";
                return;
            }

            Definitions = "const " + string.Join(",", _values.Select(v => string.Format("{0}=global.{0}", v.Key))) + ";";
        }

        public static void Register(MondState state)
        {
            foreach (var kv in _values)
            {
                state[kv.Key] = kv.Value;
            }
        }

        [MondFunction("require")]
        public static MondValue Require(MondState state, string fileName)
        {
            const string cacheObjectName = "__modules";

            MondValue cacheObject;

            // make sure we have somewhere to cache modules
            if (state[cacheObjectName].Type != MondValueType.Object)
            {
                cacheObject = new MondValue(state);
                cacheObject.Prototype = null;
                state[cacheObjectName] = cacheObject;
            }
            else
            {
                cacheObject = state[cacheObjectName];
            }

            // return cached module if it exists
            var cachedExports = cacheObject[fileName];
            if (cachedExports.Type == MondValueType.Object)
                return cachedExports;

            // create a new object to store the exports
            var exports = new MondValue(state);
            exports.Prototype = null;

            // instantly cache it so we can have circular dependencies
            cacheObject[fileName] = exports;

            try
            {
                // wrap the module script in a function so we can pass out exports object to it
                var moduleSource = File.ReadAllText(fileName);
                var source = Definitions + "return fun Module(exports) {" + moduleSource + "return exports; };";

                var program = MondProgram.Compile(source, fileName);
                var initializer = state.Load(program);

                var result = state.Call(initializer, exports);

                if (result.Type != MondValueType.Object)
                    throw new MondRuntimeException("Modules must return an Object");

                if (!ReferenceEquals(exports, result))
                {
                    // module returned a different object, merge with ours
                    exports.Prototype = result.Prototype;

                    foreach (var kv in result.RawEnumerate())
                    {
                        var key = kv["key"];
                        var value = kv["value"];

                        exports[key] = value;
                    }
                }
            }
            catch
            {
                // if something goes wrong, remove the entry from the cache
                cacheObject[fileName] = MondValue.Undefined;
                throw;
            }

            return exports;
        }

        [MondFunction("print")]
        public static void Print(params MondValue[] arguments)
        {
            foreach (var v in arguments)
            {
                Console.Write((string)v);
            }
        }

        [MondFunction("printLn")]
        public static void PrintLn(params MondValue[] arguments)
{'fraction_non_alphanumeric': 0.09136710239651416, 'fraction_numerical': 0.0008169934640522876, 'mean_word_length': 1.5171350239890335, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2060384', 'n_tokens_mistral': 1768, 'n_tokens_neox': 1687, 'n_words': 491}