com.yahoo.yqlplus.engine.internal.compiler.JoinGenerator.java Source code

Java tutorial

Introduction

Here is the source code for com.yahoo.yqlplus.engine.internal.compiler.JoinGenerator.java

Source

/*
 * Copyright (c) 2016 Yahoo Inc.
 * Licensed under the terms of the Apache version 2.0 license.
 * See LICENSE file for terms.
 */

package com.yahoo.yqlplus.engine.internal.compiler;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.GambitCreator;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.GambitScope;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.ObjectBuilder;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.ScopedBuilder;
import com.yahoo.yqlplus.engine.internal.plan.ast.OperatorValue;
import com.yahoo.yqlplus.engine.internal.plan.types.BytecodeExpression;
import com.yahoo.yqlplus.engine.internal.plan.types.TypeWidget;
import com.yahoo.yqlplus.language.parser.Location;
import org.objectweb.asm.Opcodes;

import java.util.List;
import java.util.Map;

class JoinGenerator {
    private final ObjectBuilder builder;
    private final ObjectBuilder.MethodBuilder execMethod;
    private final GambitCreator.ScopeBuilder execBody;
    private final Map<String, ObjectBuilder.FieldBuilder> parameters = Maps.newIdentityHashMap();

    public JoinGenerator(TypeWidget programType, GambitScope environment, final int count) {
        this.builder = environment.createObject(JoinTask.class);
        this.builder.addParameter("$program", programType);
        ObjectBuilder.ConstructorBuilder constructor = this.builder.getConstructor();
        constructor.invokeSpecial(JoinTask.class, constructor.constant(count));
        this.execMethod = builder.method("exec");
        execMethod.addModifiers(Opcodes.ACC_SYNCHRONIZED);
        execBody = execMethod.block();
        execMethod.exit();
    }

    public void addValue(String name, TypeWidget type) {
        parameters.put(name, builder.field(name, type));
        execBody.evaluateInto(name, parameters.get(name).get(execBody.local("this")).read());
    }

    public GambitCreator.ScopeBuilder getBody() {
        return execBody;
    }

    public BytecodeExpression createRunnable(ScopedBuilder body, BytecodeExpression joinExpr,
            List<OperatorValue> valueList) {
        if (valueList.isEmpty()) {
            return joinExpr;
        }
        final List<String> argNames = Lists.newArrayList();
        final List<TypeWidget> argValues = Lists.newArrayList();
        final List<BytecodeExpression> arguments = Lists.newArrayList();
        for (OperatorValue value : valueList) {
            Preconditions.checkArgument(value.getName() != null, "OperatorValue in valueList not assigned name");
            argNames.add(value.getName());
            argValues.add(parameters.get(value.getName()).getType());
            arguments.add(body.local(value.getName()));
        }
        final String methodName = "send" + Joiner.on("$").join(argNames);
        if (!builder.hasMethod(methodName)) {
            ObjectBuilder.MethodBuilder method = builder.method(methodName);
            method.addModifiers(Opcodes.ACC_SYNCHRONIZED);
            List<BytecodeExpression> args = Lists.newArrayList();
            for (int i = 0; i < argNames.size(); ++i) {
                args.add(method.addArgument(argNames.get(i), argValues.get(i)));
            }
            for (int i = 0; i < valueList.size(); ++i) {
                method.exec(
                        parameters.get(valueList.get(i).getName()).get(method.local("this")).write(args.get(i)));
            }
            method.exit();
        }
        final GambitCreator.Invocable send = builder.methodInvocable(methodName, joinExpr);
        body.exec(body.invoke(Location.NONE, send, arguments));
        return joinExpr;
    }

    public TypeWidget getType() {
        return builder.type();
    }

    public ObjectBuilder getBuilder() {
        return builder;
    }
}