/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.parser.statements; import gw.config.CommonServices; import gw.internal.gosu.parser.BeanAccess; import gw.internal.gosu.parser.ErrorType; import gw.internal.gosu.parser.Statement; import gw.internal.gosu.parser.TypeLoaderAccess; import gw.internal.gosu.parser.TypeLord; import gw.internal.gosu.parser.expressions.Literal; import gw.lang.parser.GosuParserTypes; import gw.lang.parser.StandardCoercionManager; import gw.lang.parser.statements.ILoopStatement; import gw.lang.reflect.IMethodInfo; import gw.lang.reflect.IPlaceholder; import gw.lang.reflect.IType; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.java.JavaTypes; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; /** */ public abstract class LoopStatement extends Statement implements ILoopStatement { public static boolean isIteratorType( IType typeIn ) { return typeIn.isArray() || typeIn instanceof ErrorType || JavaTypes.ITERABLE().isAssignableFrom( typeIn ) || StandardCoercionManager.isStructurallyAssignable_Laxed( JavaTypes.ITERABLE(), typeIn ) || JavaTypes.ITERATOR().isAssignableFrom( typeIn ) || typeIn == GosuParserTypes.STRING_TYPE() || (typeIn instanceof IPlaceholder && ((IPlaceholder)typeIn).isPlaceholder()); } public static IType getArrayComponentType( IType typeIn ) { IType returnType; if( typeIn.isArray() ) { returnType = typeIn.getComponentType(); } else if( typeIn == GosuParserTypes.STRING_TYPE() ) { returnType = GosuParserTypes.STRING_TYPE(); } else { if( BeanAccess.isNumericType( typeIn ) ) { returnType = JavaTypes.pINT(); } else if( typeIn == JavaTypes.INTEGER_INTERVAL() ) { returnType = JavaTypes.pINT(); } else if( typeIn == JavaTypes.LONG_INTERVAL() ) { returnType = JavaTypes.pLONG(); } else if( typeIn instanceof IPlaceholder && ((IPlaceholder)typeIn).isPlaceholder() ) { returnType = typeIn.getComponentType(); } else { if( typeIn.isGenericType() && !typeIn.isParameterizedType() ) { typeIn = TypeLord.getDefaultParameterizedType( typeIn ); } IType parameterized = TypeLord.findParameterizedType( typeIn, JavaTypes.ITERABLE() ); if( parameterized != null && parameterized.isParameterizedType() ) { returnType = parameterized.getTypeParameters()[0]; } else { parameterized = TypeLord.findParameterizedType( typeIn, JavaTypes.ITERATOR() ); if( parameterized != null && parameterized.isParameterizedType() ) { returnType = parameterized.getTypeParameters()[0]; } else { IMethodInfo iteratorMethod = typeIn.getTypeInfo().getMethod( "iterator" ); if( iteratorMethod != null && JavaTypes.ITERATOR().isAssignableFrom( iteratorMethod.getReturnType() ) ) { // Structural Iterable match IType retType = iteratorMethod.getReturnType(); returnType = retType.isParameterizedType() ? retType.getTypeParameters()[0] : JavaTypes.OBJECT(); } else { returnType = JavaTypes.OBJECT(); } } } } } return returnType; } /** * A helper method for creating Iterators for use with 'exists' and 'foreach' * elements. Primarily for use with generated Java code (not necessary for * direct interpretation). */ public static Iterator makeIterator( Object obj, IType typeHint ) { if( obj == null ) { return null; } if( typeHint.isArray() && (obj.getClass().isArray() || TypeSystem.getFromObject( obj ).isArray()) ) { return new ArrayIterator( obj, typeHint ); } if( obj instanceof Iterable ) { return ((Iterable)obj).iterator(); } if( obj instanceof Iterator ) { return(Iterator)obj; } // Treat a string as a list of characters if( obj instanceof String ) { return new StringIterator( (String)obj ); } if( obj instanceof Number ) { return new NumberIterator( (Number)obj ); } // Oh well. Convert to a List of length one and iterate that single element. return Collections.nCopies( 1, obj ).iterator(); } /** * Return the length of the specified Array or Collection. */ public static int getArrayLength( Object obj ) { if( obj == null ) { return 0; } IType type = TypeLoaderAccess.instance().getIntrinsicTypeFromObject( obj ); if( type.isArray() ) { return type.getArrayLength( obj ); } if( obj instanceof CharSequence ) { return ((CharSequence)obj).length(); } if( obj instanceof Collection ) { return ((Collection)obj).size(); } if( obj instanceof Iterable ) { int iCount = 0; //noinspection UnusedDeclaration for( Object o : (Iterable)obj ) { iCount++; } return iCount; } return 0; } public boolean isConditionLiteralTrue() { return getExpression() instanceof Literal && getExpression().isCompileTimeConstant() && CommonServices.getCoercionManager().makePrimitiveBooleanFrom( getExpression().evaluate() ); } static class ArrayIterator implements Iterator { private int _iCsr; private Object _array; private IType _arrayType; ArrayIterator( Object array, IType arrayType ) { _iCsr = 0; _arrayType = arrayType; _array = CommonServices.getCoercionManager().convertValue(array, _arrayType); } public boolean hasNext() { return _iCsr < _arrayType.getArrayLength( _array ); } public Object next() { if( !hasNext() ) { throw new NoSuchElementException( "No element at index [" + _iCsr + "] for the array." ); } return _arrayType.getArrayComponent( _array, _iCsr++ ); } public void remove() { throw new UnsupportedOperationException( "ArrayIterator does not support remove()." ); } } }