<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using Crayon.ParseTree;

namespace Crayon
{
    internal class Resolver
    {
        private Parser parser;
        private Executable[] currentCode;

        public Resolver(Parser parser, IList<Executable> originalCode)
        {
            this.parser = parser;
            this.currentCode = originalCode.ToArray();
        }

        private Dictionary<string, Executable> CreateFullyQualifiedLookup(IList<Executable> code)
        {
            HashSet<string> namespaces = new HashSet<string>();

            Dictionary<string, Executable> lookup = new Dictionary<string, Executable>();
            bool mainFound = false;
            foreach (Executable item in code)
            {
                string ns;
                string memberName;
                if (item is FunctionDefinition)
                {
                    FunctionDefinition fd = (FunctionDefinition)item;
                    ns = fd.Namespace;
                    memberName = fd.NameToken.Value;
                    if (memberName == "main")
                    {
                        if (mainFound)
                        {
                            throw new ParserException(item.FirstToken, "Multiple main methods found.");
                        }
                        mainFound = true;
                        lookup["~"] = item;
                    }
                }
                else if (item is ClassDefinition)
                {
                    ClassDefinition cd = (ClassDefinition)item;
                    ns = cd.Namespace;
                    memberName = cd.NameToken.Value;

                    // TODO: nested classes, constants, and enums.
                }
                else if (item is EnumDefinition)
                {
                    EnumDefinition ed = (EnumDefinition)item;
                    ns = ed.Namespace;
                    memberName = ed.Name;
                }
                else if (item is ConstStatement)
                {
                    ConstStatement cs = (ConstStatement)item;
                    ns = cs.Namespace;
                    memberName = cs.Name;
                }
                else
                {
                    string error = "This sort of expression cannot exist outside of function or field definitions.";
                    if (item is Assignment)
                    {
                        error += " Did you mean to mark this as a const expression?";
                    }
                    throw new ParserException(item.FirstToken, error);
                }

                if (ns.Length > 0)
                {
                    string accumulator = "";
                    foreach (string nsPart in ns.Split('.'))
                    {
                        if (accumulator.Length > 0) accumulator += ".";
                        accumulator += nsPart;
                        namespaces.Add(accumulator);
                    }
                }

                string fullyQualifiedName = (ns.Length > 0 ? (ns + ".") : "") + memberName;

                if (lookup.ContainsKey(fullyQualifiedName))
                {
                    // TODO: token information from two locations
                    throw new ParserException(item.FirstToken, "Two items have identical fully-qualified names: '" + fullyQualifiedName + "'");
                }
                lookup[fullyQualifiedName] = item;
            }

            foreach (string key in lookup.Keys)
            {
                if (namespaces.Contains(key))
                {
                    throw new ParserException(lookup[key].FirstToken, "This name collides with a namespace definition.");
                }
            }

            // Go through and fill in all the partially qualified namespace names.
            foreach (string ns in namespaces)
            {
                lookup[ns] = new Namespace(null, ns, null);
            }

            if (lookup.ContainsKey("~"))
            {
                FunctionDefinition mainFunc = (FunctionDefinition)lookup["~"];
                if (mainFunc.ArgNames.Length > 1)
                {
                    throw new ParserException(mainFunc.FirstToken, "The main function must accept 0 or 1 arguments.");
                }
            }
            else
            {
                throw new Exception("No main(args) function was defined.");
            }

            return lookup;
        }

        public Executable[] ResolveTranslatedCode()
        {
            this.SimpleFirstPassResolution();
            return this.currentCode;
        }

        public Executable[] ResolveInterpretedCode()
        {
            this.parser.VerifyNoBadImports();

            // Resolve raw names into the actual things they refer to based on namespaces and imports.
            this.ResolveNames();

            this.SimpleFirstPassResolution();

            this.DetermineInlinableLibraryFunctions();<commit_msg>No main function defined error was throwing the wrong kind of exception and was crashing release builds instead of printing the error message.<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using Crayon.ParseTree;

namespace Crayon
{
    internal class Resolver
    {
        private Parser parser;
        private Executable[] currentCode;

        public Resolver(Parser parser, IList<Executable> originalCode)
        {
            this.parser = parser;
            this.currentCode = originalCode.ToArray();
        }

        private Dictionary<string, Executable> CreateFullyQualifiedLookup(IList<Executable> code)
        {
            HashSet<string> namespaces = new HashSet<string>();

            Dictionary<string, Executable> lookup = new Dictionary<string, Executable>();
            bool mainFound = false;
            foreach (Executable item in code)
            {
                string ns;
                string memberName;
                if (item is FunctionDefinition)
                {
                    FunctionDefinition fd = (FunctionDefinition)item;
                    ns = fd.Namespace;
                    memberName = fd.NameToken.Value;
                    if (memberName == "main")
                    {
                        if (mainFound)
                        {
                            throw new ParserException(item.FirstToken, "Multiple main methods found.");
                        }
                        mainFound = true;
                        lookup["~"] = item;
                    }
                }
                else if (item is ClassDefinition)
                {
                    ClassDefinition cd = (ClassDefinition)item;
                    ns = cd.Namespace;
                    memberName = cd.NameToken.Value;

                    // TODO: nested classes, constants, and enums.
                }
                else if (item is EnumDefinition)
                {
                    EnumDefinition ed = (EnumDefinition)item;
                    ns = ed.Namespace;
                    memberName = ed.Name;
                }
                else if (item is ConstStatement)
                {
                    ConstStatement cs = (ConstStatement)item;
                    ns = cs.Namespace;
                    memberName = cs.Name;
                }
                else
                {
                    string error = "This sort of expression cannot exist outside of function or field definitions.";
                    if (item is Assignment)
                    {
                        error += " Did you mean to mark this as a const expression?";
                    }
                    throw new ParserException(item.FirstToken, error);
                }

                if (ns.Length > 0)
                {
                    string accumulator = "";
                    foreach (string nsPart in ns.Split('.'))
                    {
                        if (accumulator.Length > 0) accumulator += ".";
                        accumulator += nsPart;
                        namespaces.Add(accumulator);
                    }
                }

                string fullyQualifiedName = (ns.Length > 0 ? (ns + ".") : "") + memberName;

                if (lookup.ContainsKey(fullyQualifiedName))
                {
                    // TODO: token information from two locations
                    throw new ParserException(item.FirstToken, "Two items have identical fully-qualified names: '" + fullyQualifiedName + "'");
                }
                lookup[fullyQualifiedName] = item;
            }

            foreach (string key in lookup.Keys)
            {
                if (namespaces.Contains(key))
                {
                    throw new ParserException(lookup[key].FirstToken, "This name collides with a namespace definition.");
                }
            }

            // Go through and fill in all the partially qualified namespace names.
            foreach (string ns in namespaces)
            {
                lookup[ns] = new Namespace(null, ns, null);
            }

            if (lookup.ContainsKey("~"))
            {
                FunctionDefinition mainFunc = (FunctionDefinition)lookup["~"];
                if (mainFunc.ArgNames.Length > 1)
                {
                    throw new ParserException(mainFunc.FirstToken, "The main function must accept 0 or 1 arguments.");
                }
            }
            else
            {
                throw new InvalidOperationException("No main(args) function was defined.");
            }

            return lookup;
        }

        public Executable[] ResolveTranslatedCode()
        {
            this.SimpleFirstPassResolution();
            return this.currentCode;
        }

        public Executable[] ResolveInterpretedCode()
        {
            this.parser.VerifyNoBadImports();

            // Resolve raw names into the actual things they refer to based on namespaces and imports.
            this.ResolveNames();

            this.SimpleFirstPassResolution();

            this.DetermineInlinableLibraryFunctions();
{'fraction_non_alphanumeric': 0.07579174428865575, 'fraction_numerical': 0.0011765859397980193, 'mean_word_length': 1.2097053726169844, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 25, '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': '7108271', 'n_tokens_mistral': 2336, 'n_tokens_neox': 2142, 'n_words': 617}