Example #1
0
        RecursiveVerifyEmbeddedArrayTypes(
            QuestScriptParser.ArrayLiteralExpressionContext context)
        {
            var firstItemType = RecursiveGetTypeOf(context);
            var result        = RecursiveVerifyEmbeddedArrayTypes(context, firstItemType);

            return(result.isOk, result.actualType, firstItemType, result.context);
        }
Example #2
0
        private (bool isOk, ObjectType actualType, ParserRuleContext context) RecursiveVerifyEmbeddedArrayTypes(
            QuestScriptParser.ArrayLiteralExpressionContext context, ObjectType requiredType)
        {
            var firstItem = context.expr._elements[0];

            if (!(firstItem is QuestScriptParser.ArrayLiteralExpressionContext))
            {
                foreach (var item in context.expr._elements)
                {
                    //if the first item wasn't an embedded array, disallow them on other items
                    if (item is QuestScriptParser.ArrayLiteralExpressionContext)
                    {
                        return(false, ObjectType.List, item);
                    }

                    var itemType = item.Accept(this);
                    if (itemType != requiredType)
                    {
                        return(false, itemType, item);
                    }
                }
            }
            else
            {
                foreach (var item in context.expr._elements)
                {
                    //if the first item was an embedded array, enforce their existence on other items
                    if (!(item is QuestScriptParser.ArrayLiteralExpressionContext))
                    {
                        return(false, item.Accept(this), item);
                    }

                    var embedded = (QuestScriptParser.ArrayLiteralExpressionContext)item;
                    var result   = RecursiveVerifyEmbeddedArrayTypes(embedded, requiredType);
                    if (!result.isOk)
                    {
                        return(false, result.actualType, result.context);
                    }
                }
            }

            return(true, requiredType, context);
        }
Example #3
0
        public override ObjectType VisitArrayLiteralExpression(QuestScriptParser.ArrayLiteralExpressionContext context)
        {
            //TODO : add type checks of arrays within arrays, so verifying type of [[1,2],["foo","bar"],[5,6]] would result in error
            //make sure that all elements in the literal have the same type
            if (context.expr._elements.Count <= 0)
            {
                return(ObjectType.List);
            }

            var result = RecursiveVerifyEmbeddedArrayTypes(context);

            if (!result.isOk)
            {
                _scriptEnvironmentBuilder.Errors.Add(new InvalidArrayLiteralException(context,
                                                                                      $"Expected all values in the array ('{context.GetText()}') to be of type '{result.requiredType}', but found an item ({result.context.GetText()}) of which has value(s) of type '{result.actualType}'"));
                return(ObjectType.Unknown);
            }

            return(ObjectType.List);
        }
Example #4
0
        private ObjectType RecursiveGetTypeOf(QuestScriptParser.ArrayLiteralExpressionContext context)
        {
            if (context.expr._elements.Count <= 0) //precaution, should never be true..
            {
                return(ObjectType.Unknown);
            }

            var firstItem = context.expr._elements[0];

            if (firstItem is QuestScriptParser.ArrayLiteralExpressionContext literalArray)
            {
                return(RecursiveGetTypeOf(literalArray));
            }

            var embeddedArray = firstItem.FindDescendantOfType <QuestScriptParser.ArrayLiteralExpressionContext>();

            if (embeddedArray != null)
            {
                return(RecursiveGetTypeOf(embeddedArray));
            }

            var type = firstItem.Accept(this);

            //just to make sure, perhaps we have a method or a function that evaluates to list?
            if (type == ObjectType.List)
            {
                //so, lets try to evaluate it, perhaps we have
                //something like function result to infer the type?
                //TODO : verify this branch of code works when functions/methods evaluation is implemented
                var value = _scriptEnvironmentBuilder.ValueResolverVisitor.Visit(firstItem).Value.GetValueOrLazyValue();

                ObjectType RecordFailureToInferAndReturnUnknownType(
                    QuestScriptParser.ArrayLiteralExpressionContext arrayLiteralExpressionContext,
                    QuestScriptParser.ExpressionContext expressionContext)
                {
                    _scriptEnvironmentBuilder.Errors.Add(new FailedToInferTypeException(arrayLiteralExpressionContext,
                                                                                        expressionContext,
                                                                                        $"First item of {arrayLiteralExpressionContext.GetText()} seems to be an embedded array (item is '{expressionContext.GetText()}'), but failed to infer the type of its first item. Something is wrong here..."));
                    return(ObjectType.Unknown);
                }

                if (value is ArrayList array)
                {
                    object GetFirstItemRecursive(object arrayOrValue)
                    {
                        while (true)
                        {
                            if (!(arrayOrValue is IEnumerable enumerable))
                            {
                                return(arrayOrValue);
                            }

                            var enumerator = enumerable.GetEnumerator();
                            enumerator.MoveNext();
                            arrayOrValue = enumerator.Current;
                        }
                    }

                    var firstArrayItem = GetFirstItemRecursive(array);
                    return(!TypeUtil.TryConvertType(firstArrayItem.GetType(), out var firstItemType)
                        ? RecordFailureToInferAndReturnUnknownType(context, firstItem)
                        : firstItemType);
                }

                RecordFailureToInferAndReturnUnknownType(context, firstItem);
            }

            return(type);
        }