RecursiveVerifyEmbeddedArrayTypes( QuestScriptParser.ArrayLiteralExpressionContext context) { var firstItemType = RecursiveGetTypeOf(context); var result = RecursiveVerifyEmbeddedArrayTypes(context, firstItemType); return(result.isOk, result.actualType, firstItemType, result.context); }
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); }
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); }
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); }