<commit_before>package edu.kit.iti.formal.pse.worthwhile.typesystem;

import org.eclipse.emf.ecore.EObject;

import de.itemis.xtext.typesystem.trace.TypeCalculationTrace;
import edu.kit.iti.formal.pse.worthwhile.model.ast.ASTNode;
import edu.kit.iti.formal.pse.worthwhile.model.ast.ArrayLiteral;
import edu.kit.iti.formal.pse.worthwhile.model.ast.ArrayType;
import edu.kit.iti.formal.pse.worthwhile.model.ast.AstFactory;
import edu.kit.iti.formal.pse.worthwhile.model.ast.BooleanType;
import edu.kit.iti.formal.pse.worthwhile.model.ast.FunctionDeclaration;
import edu.kit.iti.formal.pse.worthwhile.model.ast.IntegerType;
import edu.kit.iti.formal.pse.worthwhile.model.ast.PrimitiveType;
import edu.kit.iti.formal.pse.worthwhile.model.ast.ReturnValueReference;
import edu.kit.iti.formal.pse.worthwhile.model.ast.Type;
import edu.kit.iti.formal.pse.worthwhile.model.ast.VariableReference;
import edu.kit.iti.formal.pse.worthwhile.model.ast.visitor.ASTNodeBottomUpVisitor;
import edu.kit.iti.formal.pse.worthwhile.model.ast.visitor.ASTNodeReturnVisitor;
import edu.kit.iti.formal.pse.worthwhile.typesys.WorthwhileTypesystemGenerated;

/**
 * The type system for validation.
 */
public class WorthwhileTypesystem extends WorthwhileTypesystemGenerated {

	/**
	 * Returns the type of the {@link VariableReference}. If the variable reference is an array access return the
	 * base type of the array.
	 * 
	 * @param element
	 *                The variable reference from which you want to get the type.
	 * @param trace
	 *                A type calculation trace.
	 * 
	 * @return the type of the variable reference.
	 */
	@Override
	protected final EObject type(final VariableReference element, final TypeCalculationTrace trace) {

		if (element.getIndex() != null
		                && isInstanceOf(element.getVariable().getType(), p.getArrayType(), trace)) {
			trace.add(element, "variableReference_arrayAccess");

			return ((ArrayType) element.getVariable().getType()).getBaseType();
		} else {
			trace.add(element, "variableReference");
			return typeof(element.getVariable().getType(), trace);
		}
	}

	/**
	 * Returns the type of the {@link ArrayLiteral}. Sets the base type of the array literal to the type of the
	 * first element of the array. If the array has no elements the base type is null.
	 * 
	 * @param element
	 *                The array literal from which you want to get the type.
	 * @param trace
	 *                A type calculation trace.
	 * 
	 * @return The type of the array literal.
	 */
	@Override
	protected final EObject type(final ArrayLiteral element, final TypeCalculationTrace trace) {

		ArrayType at = AstFactory.eINSTANCE.createArrayType();
		if (element.getValues().size() == 0) {
			at.setBaseType(null);
		} else {
			at.setBaseType((PrimitiveType) typeof(element.getValues().get(0), trace));

		}
		trace.add(element, "arrayType");
		return at;
	}

	/**
	 * @param element
	 *                The {@link ReturnValueReference} of which you want to get the type.
	 * 
	 * @param trace
	 *                A type calculation trace.
	 * 
	 * @return The type of the return value reference.
	 */
	@Override
	protected final EObject type(final ReturnValueReference element, final TypeCalculationTrace trace) {
<commit_msg>[typesystem] Implement base type derivation for empty ArrayLiterals<commit_after>package edu.kit.iti.formal.pse.worthwhile.typesystem;

import java.util.Iterator;

import org.eclipse.emf.ecore.EObject;

import de.itemis.xtext.typesystem.trace.TypeCalculationTrace;
import edu.kit.iti.formal.pse.worthwhile.model.ast.ASTNode;
import edu.kit.iti.formal.pse.worthwhile.model.ast.ArrayLiteral;
import edu.kit.iti.formal.pse.worthwhile.model.ast.ArrayType;
import edu.kit.iti.formal.pse.worthwhile.model.ast.Assignment;
import edu.kit.iti.formal.pse.worthwhile.model.ast.AstFactory;
import edu.kit.iti.formal.pse.worthwhile.model.ast.BooleanType;
import edu.kit.iti.formal.pse.worthwhile.model.ast.Equal;
import edu.kit.iti.formal.pse.worthwhile.model.ast.Expression;
import edu.kit.iti.formal.pse.worthwhile.model.ast.FunctionCall;
import edu.kit.iti.formal.pse.worthwhile.model.ast.FunctionDeclaration;
import edu.kit.iti.formal.pse.worthwhile.model.ast.IntegerType;
import edu.kit.iti.formal.pse.worthwhile.model.ast.PrimitiveType;
import edu.kit.iti.formal.pse.worthwhile.model.ast.ReturnValueReference;
import edu.kit.iti.formal.pse.worthwhile.model.ast.Type;
import edu.kit.iti.formal.pse.worthwhile.model.ast.VariableDeclaration;
import edu.kit.iti.formal.pse.worthwhile.model.ast.VariableReference;
import edu.kit.iti.formal.pse.worthwhile.model.ast.visitor.ASTNodeBottomUpVisitor;
import edu.kit.iti.formal.pse.worthwhile.model.ast.visitor.ASTNodeReturnVisitor;
import edu.kit.iti.formal.pse.worthwhile.typesys.WorthwhileTypesystemGenerated;

/**
 * The type system for validation.
 */
public class WorthwhileTypesystem extends WorthwhileTypesystemGenerated {

	/**
	 * Returns the type of the {@link VariableReference}. If the variable reference is an array access return the
	 * base type of the array.
	 * 
	 * @param element
	 *                The variable reference from which you want to get the type.
	 * @param trace
	 *                A type calculation trace.
	 * 
	 * @return the type of the variable reference.
	 */
	@Override
	protected final EObject type(final VariableReference element, final TypeCalculationTrace trace) {

		if (element.getIndex() != null
		                && isInstanceOf(element.getVariable().getType(), p.getArrayType(), trace)) {
			trace.add(element, "variableReference_arrayAccess");

			return ((ArrayType) element.getVariable().getType()).getBaseType();
		} else {
			trace.add(element, "variableReference");
			return typeof(element.getVariable().getType(), trace);
		}
	}

	/**
	 * Returns the type of the {@link ArrayLiteral}. Sets the base type of the array literal to the type of the
	 * first element of the array. If the array has no elements the base type is null.
	 * 
	 * @param element
	 *                The array literal from which you want to get the type.
	 * @param trace
	 *                A type calculation trace.
	 * 
	 * @return The type of the array literal.
	 */
	@Override
	protected final EObject type(final ArrayLiteral element, final TypeCalculationTrace trace) {

		final ArrayType at = AstFactory.eINSTANCE.createArrayType();
		if (element.getValues().size() == 0) {
			// used to determine the base types of variables (also parameters) the ArrayLiteral is assigned
			// to or compared to (in Equal Expressions)
			final WorthwhileTypesystem ts = WorthwhileTypesystem.this;

			// derives the empty ArrayLiterals base type from the context (up in the AST an Assignment,
			// VariableDeclaration, FunctionCall or Equal) it is used in
			final ASTNodeBottomUpVisitor<Type> visitor = new ASTNodeBottomUpVisitor<Type>() {
				@Override
				public void visit(final Assignment assignment) {
					// base type is the assigned variable's one
					at.setBaseType(((ArrayType) ts.typeof(assignment.getVariable())).getBaseType());
				}

				@Override
				public void visit(final VariableDeclaration variableDeclaration) {
					// base type is the initialized variable's one
					at.setBaseType(((ArrayType) ts.typeof(variableDeclaration)).getBaseType());
				}

				@Override
				public void visit(final Equal equal) {
					// base type is the compared to ArrayLiteral's, ArrayType variable's one or
					// BooleanType by convention when both operands are empty ArrayLiterals
					final ASTNodeReturnVisitor<PrimitiveType> visitor = new ASTNodeReturnVisitor<PrimitiveType>() {
						public void visit(final ArrayLiteral arrayLiteral) {
							if (arrayLiteral.getValues().size() == 0) {
								this.setReturnValue(AstFactory.eINSTANCE
								                .createBooleanType());
							} else {
								super.visit(arrayLiteral);
							}
						};

						public void visit(final Expression expression) {
							this.setReturnValue(((ArrayType) ts.typeof(expression))
							                .getBaseType());
						};
					};

					if (equal.getLeft() == element) {
						at.setBaseType(visitor.apply(equal.getRight()));
					} else if (equal.getRight() == element) {
						at.setBaseType(visitor.apply(equal.getLeft()));
					}
				}

				@Override
				public void visit(final FunctionCall functionCall) {
					// base type is the assigned parameter's one
					final Iterator<VariableDeclaration> p = functionCall.getFunction()
					                .getParameters().iterator();
					final Iterator<Expression> a = functionCall.getActuals().iterator();
					while (a.hasNext()) {
						if (a.next() == element) {
							at.setBaseType(((ArrayType) ts.typeof(p.next())).getBaseType());
						} else {
							p.next();
						}
					}
				}
			};
			element.accept(visitor);
		} else {
			at.setBaseType((PrimitiveType) typeof(element.getValues().get(0), trace));

		}
		trace.add(element, "arrayType");
		return at;
	}

	/**
	 * @param element
	 *                The {@link ReturnValueReference} of which you want to get the type.
	 * 
	 * @param trace
	 *                A type calculation trace.
	 * 
	 * @return The type of the return value reference.
	 */
	@Override
	protected final EObject type(final ReturnValueReference element, final TypeCalculationTrace trace) {

{'fraction_non_alphanumeric': 0.10950946643717728, 'fraction_numerical': 0.0005378657487091222, 'mean_word_length': 3.5, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2410819', 'n_tokens_mistral': 3084, 'n_tokens_neox': 2677, 'n_words': 680}