net.intelie.pipes.ast.AstStack Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pipes-api Show documentation
Show all versions of pipes-api Show documentation
Intelie Pipes' API classes and interfaces
package net.intelie.pipes.ast;
import net.intelie.pipes.generated.PipesTokenManager;
import net.intelie.pipes.types.Type;
import net.intelie.pipes.util.Preconditions;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class AstStack {
private final ArrayDeque- stack = new ArrayDeque<>(128);
private final Supplier
token;
public AstStack(Supplier token) {
this.token = token;
}
public SourceLocation pop() {
return pop(get());
}
public void pushCall(SourceLocation.Type type, String... expectedFunctions) {
Preconditions.checkArgument(expectedFunctions.length > 0, "must expect functions");
internalPush(type, validator(CallNode.class, node -> {
Preconditions.checkArgument(Arrays.asList(expectedFunctions).contains(node.getName()),
"Function not expected here: %s", node.getName());
}));
}
public void pushCallAny(SourceLocation.Type type) {
internalPush(type, validator(CallNode.class, node -> {
}));
}
public void pushLiteral(SourceLocation.Type type) {
internalPush(type, validator(LiteralNode.class, node -> {
}));
}
public void pushAny(SourceLocation.Type type) {
internalPush(type, node -> {
});
}
private Consumer validator(Class clazz, Consumer consumer) {
return node -> {
Preconditions.checkArgument(clazz.isInstance(node), "Must be %s (%s)", clazz, node);
consumer.accept((T) node);
};
}
private void internalPush(SourceLocation.Type type, Consumer validator) {
stack.addLast(new Item(
PipesTokenManager.toLocationBegin(token.get()).withType(type),
validator));
}
public AstNode validate(AstNode node) {
stack.getLast().validator.accept(node);
return checkCast(node);
}
private AstNode checkCast(AstNode node) {
//doing this check to make AST string representation recompilation idempotent
//this way, e.g., null$ always compile to the same AST string
if (!(node instanceof CallNode))
return node;
CallNode call = (CallNode) node;
if (call.getArgs().size() != 1 || !(call.getArgs().get(0) instanceof LiteralNode))
return node;
Object value = ((LiteralNode) call.getArgs().get(0)).getValue();
if (Type.NUMBER.name().equals(call.getName()))
return new LiteralNode(node.getLocation(), Type.NUMBER, value);
if (Type.STRING.name().equals(call.getName()))
return new LiteralNode(node.getLocation(), Type.STRING, value);
return node;
}
public AstNode fn(String name, List args) {
return validate(new CallNode(get(), name, args));
}
public AstNode fn(String name, AstNode... args) {
return fn(name, Arrays.asList(args));
}
public AstNode fnCopy(String name, AstNode arg) {
return new CallNode(arg.getLocation().withType(SourceLocation.Type.NONE), name, arg);
}
public AstNode fnVirt(String name, AstNode... args) {
return new CallNode(pointLocation(), name, Arrays.asList(args));
}
public AstNode lit(net.intelie.pipes.types.Type type, Object value) {
return validate(new LiteralNode(get(), type, value));
}
public AstNode litVirt(net.intelie.pipes.types.Type type, Object value) {
return new LiteralNode(pointLocation(), type, value);
}
public AstNode rawVirt(Object obj) {
return new RawNode(pointLocation(), obj);
}
public T pop(T obj) {
Preconditions.checkState(!stack.isEmpty(), "BUG: ast stack is empty");
Item removed = stack.removeLast();
return obj;
}
public T checkEmpty(T obj) {
Preconditions.checkState(stack.isEmpty(), "BUG: ast stack should be empty");
return obj;
}
public SourceLocation get() {
SourceLocation begin = stack.getLast().begin;
SourceLocation end = endLocation();
if (begin.comesAfter(end))
return begin;
return new SourceLocation(begin, end);
}
private SourceLocation endLocation() {
return PipesTokenManager.toLocationEnd(token.get());
}
private SourceLocation pointLocation() {
return PipesTokenManager.toLocationPoint(token.get());
}
public AstNode fnPop(String name, List args) {
return pop(fn(name, args));
}
public AstNode fnPop(String name, AstNode... args) {
return pop(fn(name, args));
}
public AstNode litPop(net.intelie.pipes.types.Type type, Object value) {
return pop(lit(type, value));
}
private static class Item {
private final SourceLocation begin;
private final Consumer validator;
public Item(SourceLocation begin, Consumer validator) {
this.begin = begin;
this.validator = validator;
}
}
}