it.unibo.alchemist.language.protelis.DotOperator.java Source code

Java tutorial

Introduction

Here is the source code for it.unibo.alchemist.language.protelis.DotOperator.java

Source

/*
 * Copyright (C) 2010-2015, Danilo Pianini and contributors
 * listed in the project's pom.xml file.
 * 
 * This file is part of Alchemist, and is distributed under the terms of
 * the GNU General Public License, with a linking exception, as described
 * in the file LICENSE in the Alchemist distribution's top directory.
 */
package it.unibo.alchemist.language.protelis;

import it.unibo.alchemist.language.protelis.datatype.Field;
import it.unibo.alchemist.language.protelis.datatype.Fields;
import it.unibo.alchemist.language.protelis.interfaces.AnnotatedTree;
import it.unibo.alchemist.language.protelis.java7.functionals.BiFunction;
import it.unibo.alchemist.language.protelis.java7.streams.Stream;
import it.unibo.alchemist.language.protelis.util.ReflectionUtils;
import it.unibo.alchemist.language.protelis.vm.ExecutionContext;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import org.apache.commons.lang3.ArrayUtils;

/**
 * @author Danilo Pianini
 *
 */
public class DotOperator extends AbstractSATree<FunctionCall, Object> {

    private static final long serialVersionUID = -9128116355271771986L;
    private static final byte LEFT_POS = -1;
    private final boolean isApply;
    private final String methodName;
    private final AnnotatedTree<?> left;

    /**
     * @param name function (or method) name
     * @param target Protelis sub-program that annotates itself with the target of this call
     * @param args arguments of the function
     */
    public DotOperator(final String name, final AnnotatedTree<?> target, final List<AnnotatedTree<?>> args) {
        super(args);
        Objects.requireNonNull(name);
        isApply = name.equals("apply");
        methodName = name;
        left = target;
    }

    @Override
    public AnnotatedTree<Object> copy() {
        final DotOperator res = new DotOperator(methodName, left.copy(), deepCopyBranches());
        res.setSuperscript(getSuperscript());
        return res;
    }

    @Override
    public void eval(final ExecutionContext context) {
        /*
         * Eval left
         */
        context.newCallStackFrame(LEFT_POS);
        left.eval(context);
        context.returnFromCallFrame();
        /*
         * If it is a function pointer, then create a new function call
         */
        final Object target = left.getAnnotation();
        if (isApply && target instanceof FunctionDefinition) {
            final FunctionDefinition fd = (FunctionDefinition) target;
            /*
             * Currently, there is no change in the codepath when superscript is
             * executed: f.apply(...) is exactly equivalent to f(...).
             */
            final FunctionCall fc;
            final boolean hasCall = getSuperscript() instanceof FunctionCall;
            final FunctionCall prevFC = hasCall ? (FunctionCall) getSuperscript() : null;
            if (hasCall && fd.equals(prevFC.getFunctionDefinition())) {
                fc = prevFC;
            } else {
                fc = new FunctionCall(fd, deepCopyBranches());
            }
            setSuperscript(fc);
            fc.eval(context);
            setAnnotation(fc.getAnnotation());
        } else {
            /*
             * Otherwise, evaluate branches and proceed to evaluation
             */
            projectAndEval(context);
            /*
             *  Check everything for fields
             */
            final Stream<?> argsstr = getBranchesAnnotationStream();
            final Object[] args = argsstr.toArray();
            /*
             *  collect any field indices
             */

            List<Integer> list = new ArrayList<>();
            for (Object o : args) {
                if (Field.class.isAssignableFrom(o.getClass())) {
                    list.add(ArrayUtils.indexOf(args, o));
                }
            }
            final int[] fieldIndexes = new int[list.size()];
            for (Integer i : list) {
                fieldIndexes[i] = list.get(i);
            }
            // End

            /*
             *  if there are any fields, do a field apply:
             */
            final boolean fieldTarget = target instanceof Field;
            if (fieldTarget || fieldIndexes.length > 0) {
                /*
                 * Run on every element of the field, and at each iteration use the
                 * current annotation as corresponding element for the field. Once
                 * done, set the entire field as annotation.
                 */
                final Field res = Fields.apply(new BiFunction<Object, Object[], Object>() {
                    @Override
                    public Object apply(Object actualT, Object[] actualA) {
                        return ReflectionUtils.invokeBestNotStatic(actualT, methodName, actualA);
                    }
                }, fieldTarget, fieldIndexes, target, args);
                setAnnotation(res);
            } else {
                final Object annotation = ReflectionUtils.invokeBestNotStatic(target, methodName, args);
                setAnnotation(annotation);
            }
        }
    }

    @Override
    protected void innerAsString(final StringBuilder sb, final int indent) {
        sb.append('\n');
        left.toString(sb, indent);
        sb.append('\n');
        indent(sb, indent);
        sb.append('.');
        sb.append(methodName);
        sb.append(" (");
        fillBranches(sb, indent, ',');
        sb.append(')');
    }

}