<commit_before>﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace VineScript.Core
{
    public class Loader
    {
        private Dictionary<string, PassageScript> passageScripts = new Dictionary<string, PassageScript>();

        private Compiler.VineCompiler compiler;
        
        public string BaseDir { get ; set; } = "./";

        public Loader()
        {
            compiler = new Compiler.VineCompiler(null);
        }

        public PassageScript Get(string scriptname)
        {
            PassageScript passage;
            passageScripts.TryGetValue(scriptname, out passage);
            return passage;
        }

        /// <summary>
        /// Add files from a given directory.
        /// </summary>
        /// <param name="dirname">Directory name</param>
        /// <param name="ext">Files extensions (not case sensitive).
        /// Can add more than one extension with a pipe. E.g: "*.vine|*.txt".
        /// Files can also be searched by pattern. Eg: all files starting with 'foo':
        /// "foo*"</param>
        /// <param name="recursive">Include the current `dirname` directory 
        /// and all its subdirectories in the search.</param>
        /// <returns></returns>
        public bool AddFilesFromDir(string dirname, string ext="*.vine|*", bool recursive=true)
        {
            bool added = false;
            try {
                string dirfullpath = Path.GetFullPath(dirname);
                string[] filenames = GetFiles(dirfullpath, ext,
                    recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly
                 );

                foreach (string fn in filenames) {
                    string scriptname = GetScriptNameFromFile(fn, dirfullpath);
                    AddFile(fn, ref scriptname, dirfullpath);
                }
                added = filenames.Length > 0;
            }
            catch (Exception e) {
                Console.WriteLine(e.Message);
            }
            return added;
        }

        public bool AddFile(string filename, string scriptname="")
        {
            string filefullpath = Path.GetFullPath(filename);
            string dirfullpath = Path.GetFullPath(BaseDir);
            return AddFile(filefullpath, ref scriptname, dirfullpath);
        }

        public bool LoadFile(string filename, string scriptname="")
        {
            string filefullpath = Path.GetFullPath(filename);
            string dirfullpath = Path.GetFullPath(BaseDir);
            if (AddFile(filefullpath, ref scriptname, dirfullpath)) {
                return LoadPassage(scriptname);
            }
            return false;
        }

        private bool AddFile(string filename, ref string scriptname, string dir_root)
        {
            if (string.IsNullOrWhiteSpace(scriptname)) {
                // Give the script a name based on the filename
                scriptname = GetScriptNameFromFile(filename, dir_root);
            }

            if (passageScripts.ContainsKey(scriptname)) {
                throw new Exception(string.Format(
                    "'{0}' can't be added because another script has the same name!",
                    scriptname
                ));
            }

            string fullpath = Path.GetFullPath(filename);
            Console.WriteLine(string.Format(
                "Added '{0}':{1} {2}", scriptname, System.Environment.NewLine, fullpath
            ));
            passageScripts.Add(scriptname, new PassageScript(scriptname, fullpath));
            return true;
        }

        public bool LoadPassage(string scriptname)
        {
            PassageScript passage;
            if (passageScripts.TryGetValue(scriptname, out passage))
            {
                if (passage.Loaded) {
                    throw new Exception(string.Format(
                        "'{0}' can't be loaded because it's already loaded!", scriptname
                    ));
                }

                StreamReader istream = File.OpenText(passage.Filename);
                string code = istream.ReadToEnd();
                compiler.Init(code, passage.Filename);
                var tree = compiler.BuildTree();
                Get(scriptname).Load(tree);
                return true;
            }

            throw new Exception(string.Format("'{0}' doesn't exist!", scriptname));
        }

        public bool LoadFilesFromDir(string dirname, string ext="*.vine|*", bool recursive=true)
        {
            if (AddFilesFromDir(dirname, ext, recursive)) {
                return LoadAll();
            }
            return false;

        }

        public bool LoadAll()
        {
            bool parseError = false;
            if (passageScripts.Count == 0) {
                return false;
            }
            foreach (var el in passageScripts) {
                try {
                    if (el.Value.Loaded || !LoadPassage(el.Key)) {
                        return false;
                    }
                } catch (Compiler.VineParseException e) {
                    // Print the parse error but doesn't stop the loop here.
                    // Continue loading more files to print more potential
                    // parse errors
                    Console.Write(e.Message);
                    // we mark the function to return an error though
                    parseError = true;
                }
            }
            return !parseError;
        }

        public bool Unload(string scriptname)
        {
            PassageScript passage = Get(scriptname);
            if (passage != null) {
                passage.Unload();
                return true;
            }
            return false;
        }

        public bool UnloadAll()
        {
            foreach (var el in passageScripts) {<commit_msg>Changed the visibility of a lot of methods, final user only needs to load and remove scripts. Also added BaseDIr<commit_after>﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using VineScript.Compiler;

namespace VineScript.Core
{
    public class Loader
    {
        private Dictionary<string, PassageScript> passageScripts = new Dictionary<string, PassageScript>();

        private VineCompiler compiler;
        
        private const string CURRENT_DIR = "./";

        /// <summary>
        /// Base directory containing the scripts. By default it uses the
        /// directory in which the program is launched. Calling LoadFromDir()
        /// will change its value.
        /// </summary>
        public string BaseDir { get ; set; } = CURRENT_DIR;

        public Loader()
        {
            compiler = new VineCompiler(null);
        }

        public PassageScript Get(string scriptname)
        {
            PassageScript passage;
            passageScripts.TryGetValue(scriptname, out passage);
            return passage;
        }

        /// <summary>
        /// Add files from a given directory. That directory will become the
        /// root directory for the scripts.
        /// </summary>
        /// <param name="dirname">Directory name</param>
        /// <param name="ext">Files extensions (not case sensitive).
        /// Can add more than one extension with a pipe. E.g: "*.vine|*.txt".
        /// Files can also be searched by pattern. Eg: all files starting with 'foo':
        /// "foo*"</param>
        /// <param name="recursive">Include the current `dirname` directory 
        /// and all its subdirectories in the search.</param>
        /// <returns></returns>
        private bool AddFilesFromDir(string dirname, string ext="*.vine", bool recursive=true)
        {
            bool added = false;
            try {
                BaseDir = Path.GetFullPath(dirname);
                string[] filenames = GetFiles(BaseDir, ext,
                    recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly
                 );

                foreach (string fn in filenames) {
                    AddFile(fn);
                }
                added = filenames.Length > 0;
            }
            catch (Exception e) {
                Console.WriteLine(e.Message);
            }
            return added;
        }

        private bool AddFile(string filename, string scriptname="")
        {
            string filefullpath = Path.GetFullPath(filename);
            string dirfullpath = Path.GetFullPath(BaseDir);
            return AddFile(filefullpath, ref scriptname, dirfullpath);
        }

        private bool AddFile(string filename, ref string scriptname, string dir_root)
        {
            if (string.IsNullOrWhiteSpace(scriptname)) {
                // Give the script a name based on the filename
                scriptname = GetScriptNameFromFile(filename, dir_root);
            }

            if (passageScripts.ContainsKey(scriptname)) {
                throw new Exception(string.Format(
                    "'{0}' can't be added because another script has the same name!",
                    scriptname
                ));
            }

            string fullpath = Path.GetFullPath(filename);
            Console.WriteLine(string.Format(
                "Added '{0}':{1} {2}", scriptname, System.Environment.NewLine, fullpath
            ));
            passageScripts.Add(scriptname, new PassageScript(scriptname, fullpath));
            return true;
        }

        private bool LoadPassage(string scriptname)
        {
            PassageScript passage;
            if (passageScripts.TryGetValue(scriptname, out passage))
            {
                if (passage.Loaded) {
                    throw new Exception(string.Format(
                        "'{0}' can't be loaded because it's already loaded!", scriptname
                    ));
                }

                StreamReader istream = File.OpenText(passage.Filename);
                string code = istream.ReadToEnd();
                compiler.Init(code, passage.Filename);
                var tree = compiler.BuildTree();
                Get(scriptname).Load(tree);
                return true;
            }

            throw new Exception(string.Format("'{0}' doesn't exist!", scriptname));
        }

        public bool Load(string filename, string scriptname="")
        {
            string filefullpath = Path.GetFullPath(filename);
            string dirfullpath = Path.GetFullPath(BaseDir);
            if (AddFile(filefullpath, ref scriptname, dirfullpath)) {
                return LoadPassage(scriptname);
            }
            return false;
        }
        
        /// <summary>
        /// Load files from a given directory. That directory will become the
        /// implicit root directory, and all scripts path will be relative to
        /// it, meaning that you won't need to specify it when calling scripts.
        /// E.g:
        /// You have the directory "./scripts/foo" containing the files:
        ///     * hello.vine
        ///     * bar.vine
        ///     * sub/lorem.vine
        /// You can call:
        /// loader.LoadFromDir("./scripts/foo/bar");
        /// But you don't need to specify the path again, it's now the base
        /// directory for the scripts.
        /// loader.Get("hello");
        /// loader.Get("sub/lorem");
        /// </summary>
        public bool LoadFromDir(string dirname, string ext="*.vine", bool recursive=true)
        {
            if (AddFilesFromDir(dirname, ext, recursive)) {
                return LoadAll();
            }
            return false;
        }

        private bool LoadAll()
        {
            bool parseError = false;
            if (passageScripts.Count == 0) {
                return false;
            }
            foreach (var el in passageScripts) {
                try {
                    if (el.Value.Loaded || !LoadPassage(el.Key)) {
                        return false;
                    }
                } catch (VineParseException e) {
                    // Print the parse error but doesn't stop the loop here.
                    // Continue loading more files to print more potential
                    // parse errors
                    Console.Write(e.Message);
                    // we mark the function to return an error though
                    parseError = true;
                }
            }
            return !parseError;
        }

        private bool Unload(string scriptname)
        {
            PassageScript passage = Get(scriptname);
            if (passage != null) {
                passage.Unload();
                return true;
            }
            return false;
        }

        private bool UnloadAll()
        {
            foreach (var el in passageScripts) {
{'fraction_non_alphanumeric': 0.09260549748354627, 'fraction_numerical': 0.0012388695315524584, 'mean_word_length': 1.5187207488299532, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 33, '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': '3482600', 'n_tokens_mistral': 3197, 'n_tokens_neox': 3038, 'n_words': 892}