protected virtual IExpression EvaluateSheet(EvaluationParameters parameters, Nodes.GenericElement element)
        {
            IExpression[] evalArgs = element.Arguments.Select(_ => _.TryEvaluate(parameters)).ToArray();
            if (evalArgs.Length < 2)
            {
                throw new InvalidOperationException();
            }
            string sheetName = evalArgs[0].ToString();
            int    rowKey    = ToInteger(evalArgs[1]);
            int    colKey    = 0;

            if (evalArgs.Length > 2)
            {
                colKey = ToInteger(evalArgs[2]);
            }

            XivRow row   = Data.GetSheet(sheetName)[rowKey];
            object value = row[colKey];

            if (value is INode)
            {
                EvaluationParameters innerParams = new EvaluationParameters(parameters);
                innerParams.InputParameters.Clear();
                for (int i = 3; i < evalArgs.Length; ++i)
                {
                    innerParams.InputParameters[i - 2] = evalArgs[i];
                }


                value = EvaluationHelper.TryEvaluate((INode)value, innerParams);
            }

            return(new GenericExpression(new ObjectWithDisplay(value, row)));
        }
        protected virtual IExpression EvaluateSheetWithAttributive(EvaluationParameters parameters, Nodes.GenericElement element)
        {
            IExpression[] evalArgs = element.Arguments.Select(_ => _.TryEvaluate(parameters)).ToArray();
            if (evalArgs.Length < 3)
            {
                throw new InvalidOperationException();
            }

            Ex.Language lang = TagToLanguageMap[element.Tag];

            string sheetName         = evalArgs[0].ToString();
            int    attributiveRowKey = ToInteger(evalArgs[1]);
            int    rowKey            = ToInteger(evalArgs[2]);

            int columnKey = 0;

            if (evalArgs.Length > 3)
            {
                columnKey = ToInteger(evalArgs[3]);
            }

            int attributiveColumnKey = AttributiveColumnOffsets[element.Tag];

            if (evalArgs.Length > 4)
            {
                attributiveColumnKey += ToInteger(evalArgs[4]);
            }

            XivRow row = Data.GetSheet(sheetName)[rowKey];
            object value;

            if (row is Ex.IMultiRow)
            {
                value = ((Ex.IMultiRow)row)[columnKey, lang];
            }
            else
            {
                value = row[columnKey];
            }

            XivRow attributiveRow = Data.GetSheet(AttributiveSheetName)[attributiveRowKey];
            object attributiveValue;

            if (attributiveRow is Ex.IMultiRow)
            {
                attributiveValue = ((Ex.IMultiRow)attributiveRow)[attributiveColumnKey, lang];
            }
            else
            {
                attributiveValue = attributiveRow[attributiveColumnKey];
            }

            EvaluationParameters innerParams = new EvaluationParameters(parameters);

            innerParams.InputParameters.Clear();
            for (int i = 5; i < evalArgs.Length; ++i)
            {
                innerParams.InputParameters[i - 2] = evalArgs[i];
            }

            if (value is INode)
            {
                value = EvaluationHelper.TryEvaluate((INode)value, innerParams);
            }
            if (attributiveValue is INode)
            {
                attributiveValue = EvaluationHelper.TryEvaluate((INode)attributiveValue, innerParams);
            }

            return(new SurroundedExpression(new ObjectWithDisplay(attributiveValue, attributiveRow), new ObjectWithDisplay(value, row), null));
        }