/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Locals;
import org.objectweb.asm.Label;
import java.util.Objects;
import java.util.Set;
import org.elasticsearch.painless.MethodWriter;
import org.objectweb.asm.Opcodes;
/**
* Represents a boolean expression.
*/
public final class EBool extends AExpression {
private final Operation operation;
private AExpression left;
private AExpression right;
public EBool(Location location, Operation operation, AExpression left, AExpression right) {
super(location);
this.operation = Objects.requireNonNull(operation);
this.left = Objects.requireNonNull(left);
this.right = Objects.requireNonNull(right);
}
@Override
void extractVariables(Set<String> variables) {
left.extractVariables(variables);
right.extractVariables(variables);
}
@Override
void analyze(Locals locals) {
left.expected = Definition.BOOLEAN_TYPE;
left.analyze(locals);
left = left.cast(locals);
right.expected = Definition.BOOLEAN_TYPE;
right.analyze(locals);
right = right.cast(locals);
if (left.constant != null && right.constant != null) {
if (operation == Operation.AND) {
constant = (boolean)left.constant && (boolean)right.constant;
} else if (operation == Operation.OR) {
constant = (boolean)left.constant || (boolean)right.constant;
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
actual = Definition.BOOLEAN_TYPE;
}
@Override
void write(MethodWriter writer, Globals globals) {
if (operation == Operation.AND) {
Label fals = new Label();
Label end = new Label();
left.write(writer, globals);
writer.ifZCmp(Opcodes.IFEQ, fals);
right.write(writer, globals);
writer.ifZCmp(Opcodes.IFEQ, fals);
writer.push(true);
writer.goTo(end);
writer.mark(fals);
writer.push(false);
writer.mark(end);
} else if (operation == Operation.OR) {
Label tru = new Label();
Label fals = new Label();
Label end = new Label();
left.write(writer, globals);
writer.ifZCmp(Opcodes.IFNE, tru);
right.write(writer, globals);
writer.ifZCmp(Opcodes.IFEQ, fals);
writer.mark(tru);
writer.push(true);
writer.goTo(end);
writer.mark(fals);
writer.push(false);
writer.mark(end);
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
@Override
public String toString() {
return singleLineToString(left, operation.symbol, right);
}
}