All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jfxcore.compiler.ast.emit.EmitMapToBooleanNode Maven / Gradle / Ivy

// Copyright (c) 2021, 2023, JFXcore. All rights reserved.
// Use of this source code is governed by the BSD-3-Clause license that can be found in the LICENSE file.

package org.jfxcore.compiler.ast.emit;

import javassist.CtClass;
import javassist.bytecode.MethodInfo;
import org.jfxcore.compiler.ast.AbstractNode;
import org.jfxcore.compiler.ast.GeneratorEmitterNode;
import org.jfxcore.compiler.diagnostic.SourceInfo;
import org.jfxcore.compiler.ast.ResolvedTypeNode;
import org.jfxcore.compiler.ast.Visitor;
import org.jfxcore.compiler.ast.expression.Operator;
import org.jfxcore.compiler.generate.BooleanMapperGenerator;
import org.jfxcore.compiler.generate.ClassGenerator;
import org.jfxcore.compiler.generate.Generator;
import org.jfxcore.compiler.util.Bytecode;
import org.jfxcore.compiler.util.Resolver;
import org.jfxcore.compiler.util.TypeHelper;
import org.jfxcore.compiler.util.TypeInstance;
import java.util.List;
import java.util.Objects;

import static org.jfxcore.compiler.util.Classes.*;
import static org.jfxcore.compiler.util.Descriptors.*;

/**
 * Emits its child node, which places an {@link javafx.beans.value.ObservableValue} on top of the operand stack.
 * Then maps the observable value to a boolean value as specified by {@link Operator}.
 */
public class EmitMapToBooleanNode extends AbstractNode
        implements ValueEmitterNode, GeneratorEmitterNode, NullableInfo {

    private final ResolvedTypeNode type;
    private final ClassGenerator generator;
    private final boolean invert;
    private EmitterNode child;

    public EmitMapToBooleanNode(EmitterNode child, boolean invert, SourceInfo sourceInfo) {
        super(sourceInfo);

        Resolver resolver = new Resolver(sourceInfo);
        TypeInstance typeInstance = TypeHelper.getTypeInstance(child);
        CtClass valueType = TypeHelper.getBoxedType(resolver.findObservableArgument(typeInstance).jvmType());

        this.generator = new BooleanMapperGenerator(valueType, invert);
        this.child = checkNotNull(child);
        this.invert = invert;
        this.type = new ResolvedTypeNode(
            resolver.getTypeInstance(ObservableValueType(), List.of(TypeInstance.BooleanType())),
            sourceInfo);
    }

    @Override
    public ResolvedTypeNode getType() {
        return type;
    }

    @Override
    public boolean isNullable() {
        return false;
    }

    @Override
    public List emitGenerators(BytecodeEmitContext context) {
        return generator != null ? List.of(generator) : List.of();
    }

    @Override
    public void emit(BytecodeEmitContext context) {
        CtClass generatedClass = context.getNestedClasses().find(generator.getClassName());
        Bytecode code = context.getOutput();

        code.anew(generatedClass)
            .dup();

        context.emit(child);

        code.invokespecial(generatedClass, MethodInfo.nameInit, constructor(ObservableValueType()));
    }

    @Override
    public void acceptChildren(Visitor visitor) {
        super.acceptChildren(visitor);
        child = (EmitterNode)child.accept(visitor);
    }

    @Override
    public EmitMapToBooleanNode deepClone() {
        return new EmitMapToBooleanNode(child.deepClone(), invert, getSourceInfo());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        EmitMapToBooleanNode that = (EmitMapToBooleanNode)o;
        return invert == that.invert && type.equals(that.type) && child.equals(that.child);
    }

    @Override
    public int hashCode() {
        return Objects.hash(invert, type, child);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy