<commit_before>﻿using System.Collections.Generic;

namespace Crayon.ParseTree
{
    internal class BracketIndex : Expression
    {
        internal override Expression PastelResolve(Parser parser)
        {
            throw new System.NotImplementedException();
        }

        public override bool CanAssignTo { get { return true; } }

        public Expression Root { get; set; }
        public Token BracketToken { get; private set; }
        public Expression Index { get; set; }

        public BracketIndex(Expression root, Token bracketToken, Expression index, Executable owner)
            : base(root.FirstToken, owner)
        {
            this.Root = root;
            this.BracketToken = bracketToken;
            this.Index = index;
        }

        internal override Expression Resolve(Parser parser)
        {
            this.Root = this.Root.Resolve(parser);
            this.Index = this.Index.Resolve(parser);

            if (this.Root is CompileTimeDictionary)
            {
                // Swap out this bracketed expression with a fixed constant.
                CompileTimeDictionary root = (CompileTimeDictionary)this.Root;

                if (root.Type == "var")
                {
                    if (this.Index is StringConstant)
                    {
                        string index = ((StringConstant)this.Index).Value;

                        if (parser.BuildContext.BuildVariableLookup.ContainsKey(index))
                        {
                            Crayon.BuildContext.BuildVarCanonicalized buildVar = parser.BuildContext.BuildVariableLookup[index];
                            switch (buildVar.Type)
                            {
                                case Crayon.BuildContext.VarType.INT: return new IntegerConstant(this.FirstToken, buildVar.IntValue, this.FunctionOrClassOwner);
                                case Crayon.BuildContext.VarType.FLOAT: return new FloatConstant(this.FirstToken, buildVar.FloatValue, this.FunctionOrClassOwner);
                                case Crayon.BuildContext.VarType.STRING: return new StringConstant(this.FirstToken, buildVar.StringValue, this.FunctionOrClassOwner);
                                case Crayon.BuildContext.VarType.BOOLEAN: return new BooleanConstant(this.FirstToken, buildVar.BoolValue, this.FunctionOrClassOwner);
                                default:
                                    throw new System.Exception("This should not happen."); // invalid types filtered during build context construction.

                            }
                        }
                        else
                        {
                            throw new ParserException(this.Index.FirstToken, "The build variable with id '" + index + "' is not defined for this target.");
                        }
                    }
                }
                else
                {
                    throw new System.Exception("Unknown compile time dictionary type.");
                }
            }

            return this;
        }

        internal override Expression ResolveNames(Parser parser, System.Collections.Generic.Dictionary<string, Executable> lookup, string[] imports)<commit_msg>Return null constants for $var references that don't exist.<commit_after>﻿using System.Collections.Generic;

namespace Crayon.ParseTree
{
    internal class BracketIndex : Expression
    {
        internal override Expression PastelResolve(Parser parser)
        {
            throw new System.NotImplementedException();
        }

        public override bool CanAssignTo { get { return true; } }

        public Expression Root { get; set; }
        public Token BracketToken { get; private set; }
        public Expression Index { get; set; }

        public BracketIndex(Expression root, Token bracketToken, Expression index, Executable owner)
            : base(root.FirstToken, owner)
        {
            this.Root = root;
            this.BracketToken = bracketToken;
            this.Index = index;
        }

        internal override Expression Resolve(Parser parser)
        {
            this.Root = this.Root.Resolve(parser);
            this.Index = this.Index.Resolve(parser);

            if (this.Root is CompileTimeDictionary)
            {
                // Swap out this bracketed expression with a fixed constant.
                CompileTimeDictionary root = (CompileTimeDictionary)this.Root;

                if (root.Type == "var")
                {
                    if (this.Index is StringConstant)
                    {
                        string index = ((StringConstant)this.Index).Value;

                        if (parser.BuildContext.BuildVariableLookup.ContainsKey(index))
                        {
                            Crayon.BuildContext.BuildVarCanonicalized buildVar = parser.BuildContext.BuildVariableLookup[index];
                            switch (buildVar.Type)
                            {
                                case Crayon.BuildContext.VarType.INT: return new IntegerConstant(this.FirstToken, buildVar.IntValue, this.FunctionOrClassOwner);
                                case Crayon.BuildContext.VarType.FLOAT: return new FloatConstant(this.FirstToken, buildVar.FloatValue, this.FunctionOrClassOwner);
                                case Crayon.BuildContext.VarType.STRING: return new StringConstant(this.FirstToken, buildVar.StringValue, this.FunctionOrClassOwner);
                                case Crayon.BuildContext.VarType.BOOLEAN: return new BooleanConstant(this.FirstToken, buildVar.BoolValue, this.FunctionOrClassOwner);
                                default:
                                    throw new System.Exception("This should not happen."); // invalid types filtered during build context construction.

                            }
                        }
                        else
                        {
                            return new NullConstant(this.FirstToken, this.FunctionOrClassOwner);
                            // TODO: strict mode that enforces this. There are two ways this could be done:
                            // 1) $var['foo'] vs $optional['foo']
                            // 2) <strictvars>true</strictvars>
                            // I kind of prefer #1.

                            // throw new ParserException(this.Index.FirstToken, "The build variable with id '" + index + "' is not defined for this target.");
                        }
                    }
                }
                else
                {
                    throw new System.Exception("Unknown compile time dictionary type.");
                }
            }

            return this;
        }

        internal override Expression ResolveNames(Parser parser, System.Collections.Generic.Dictionary<string, Executable> lookup, string[] imports)
{'fraction_non_alphanumeric': 0.07255611875452571, 'fraction_numerical': 0.00043446777697320784, 'mean_word_length': 1.5259692757863936, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4020718', 'n_tokens_mistral': 1560, 'n_tokens_neox': 1481, 'n_words': 388}