com.google.zetasql.resolvedast.ResolvedNode Maven / Gradle / Ivy
Show all versions of zetasql-client Show documentation
/*
* Copyright 2019 Google LLC
*
* Licensed 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 com.google.zetasql.resolvedast;
import com.google.common.base.Preconditions;
import com.google.protobuf.Message;
import com.google.zetasql.DebugPrintableNode;
import com.google.zetasql.FileDescriptorSetsBuilder;
import com.google.zetasql.ZetaSQLResolvedNodeKind.ResolvedNodeKind;
import com.google.zetasql.ResolvedNodeProto;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* This is the base class for the resolved AST. Subclasses are in the generated file
* ResolvedNodes.java. ResolvedNodeKind enum is in the generated file resolved_node_kind.proto.
* See gen_resolved_ast.py.
*
* View code generated classes at (broken link).
* HTML documentation for the class hierarchy is generated in resolved_ast.html.
* A viewable copy is available at (broken link).
*
*
In this hierarchy, classes are either abstract or leaves.
*/
public abstract class ResolvedNode implements Serializable, DebugPrintableNode {
ResolvedNode(ResolvedNodeProto proto, AbstractDeserializationHelper helper) {
// Nothing to deserialize for now.
}
ResolvedNode() {}
/**
* Base case for recursive call in derived AST nodes.
*/
public Message serialize(
@SuppressWarnings("unused") FileDescriptorSetsBuilder fileDescriptorSetsBuilder) {
return ResolvedNodeProto.getDefaultInstance();
}
public abstract ResolvedNodeKind nodeKind();
@Override
public abstract String nodeKindString();
/** Accepts a visitor, which can process the node and optionally redispatch to children. */
public abstract void accept(ResolvedNodes.Visitor visitor);
/** Accepts a visitor, which can return a replacement node. */
public abstract ResolvedNode accept(RewritingVisitor visitor);
/**
* Accepts a visitor, dispatching to the children of this node.
*
*
Note: this function is made non-abstract to allow all generated ResolvedNode implementations
* to perform a {@code super.acceptChildren} call, which ensures all children nodes are sent to
* {@code visitor}.
*/
protected void acceptChildren(ResolvedNodes.Visitor visitor) {}
/**
* Creates a Builder object from this node.
*
*
The returned builder is a distinct object; modifications to the builder do not change this
* object.
*/
public abstract Builder toBuilder();
/**
* A builder class corresponding to ResolvedNode.
*
*
Note, there is a 'Builder' class hierarchy that matches the node class hierarchy found in {@
* link ResolvedNodes}.
*
*
This is declared such that you can chain 'setX' calls freely between a class and those
* classes it extends (transitively). Example:
* // Note: ResolvedArgumentRef extends ResolvedExpr
* ResolvedArgumentRef ref =
* ResolvedArgumentRef.newBuilder()
* .setArgumentKind(...) // A field on ResolvedArgumentRef
* .setType(...) // A field on ResolvedExpr
* .setName("name") // A field on ResolvedArgumentRef
* .build();
*
Propagating 'is_ordered': Some setters will 'propagate' the 'is_ordered' field,
* example: {@link ResolvedNodes.ResolvedLimitOffsetScan#setInputScan}. The setters will will be
* documented as such.
*
*
Optional fields: Nearly all fields are required, and must have a non-null value. A small
* number of fields are optional and have default values.
*/
public abstract static class Builder {
/**
* Create this object.
*
* @throws IllegalArgumentException if any required field is not set.
*/
public abstract ResolvedNode build();
/**
* Validates that each required field is set.
*
* @throws IllegalArgumentException if any required field is not set.
*/
void validate() {}
}
@Override
public final String toString() {
return debugString();
}
public final String debugString() {
StringBuilder sb = new StringBuilder();
debugStringImpl("", "", sb);
return sb.toString();
}
/**
* Return true if the fields returned from collectDebugStringFields would contain any field with a
* non-empty {@code nodes} list. These are the fields that would have child nodes in the
* debugString tree.
*/
private boolean hasDebugStringFieldsWithNodes() {
List fields = new ArrayList<>();
collectDebugStringFields(fields);
for (DebugStringField field : fields) {
if (field.hasNodes()) {
return true;
}
}
return false;
}
/**
* collectDebugStringFieldsWithNameFormat and getNameForDebugStringWithNameFormat are helpers used
* in custom format methods to format nodes as an assignment, "name := node", with node's children
* as children of this node.
*/
protected final void collectDebugStringFieldsWithNameFormat(List fields) {
Preconditions.checkArgument(fields.isEmpty());
if (hasDebugStringFieldsWithNodes()) {
fields.add(new DebugStringField("", this));
} else {
collectDebugStringFields(fields);
}
}
protected final String getNameForDebugStringWithNameFormat(String name) {
if (hasDebugStringFieldsWithNodes()) {
return name + " :=";
} else {
return name + " := " + getNameForDebugString();
}
}
}