// Path: src/main/java/tech/pinto/Pinto.java
// public static class Expression implements TableFunction {
// 		
// 	private final boolean isSubExpression;
// 	private ArrayList<TableFunction>  functions = new ArrayList<>();
// 	private	Optional<Indexer> indexer = null;
// 	private	Optional<TerminalFunction> terminalFunction = Optional.empty();
// 	private Set<String> dependencies = new HashSet<>();
// 	private StringBuilder text = new StringBuilder();
// 	private	Optional<String> nameLiteral = Optional.empty();
// 		
// 	public Expression(boolean isSubExpression) {
// 		this.isSubExpression = isSubExpression;
// 	}
// 
// 	public Table evaluate(Pinto pinto) {
// 		if(!terminalFunction.isPresent()) {
// 			throw new PintoSyntaxException("Need terminal to evaluate expression.");
// 		}
// 		return terminalFunction.get().apply(pinto, this);
// 	}
// 
// 	@Override
// 	public void accept(Pinto pinto, Table table) {
// 		try {
// 			this.indexer.orElse(new Indexer(true)).accept(pinto, table);
// 			for(int i = 0; i < functions.size(); i++) {
// 				functions.get(i).accept(pinto, table);
// 			}
// 			table.collapseFunction();
// 		} catch(RuntimeException e) {
// 			throw new PintoSyntaxException("Error in expression: \"" + getText().trim() + "\": " + e.getLocalizedMessage() + "\n",e);
// 		}
// 	}
// 		
// 	public void addIndexer(Indexer indexer) {
// 		if(this.indexer == null) {
// 			indexer.setIndexForExpression();
// 			this.indexer = Optional.of(indexer);
// 		} else {
// 			functions.add(indexer);
// 		}
// 	}
// 
// 	public void addFunction(Column<?> col) {
// 		addFunction((StackFunction) (p, s) -> s.addFirst(col));
// 	}
// 
// 	public void addFunction(TableFunction function) {
// 		if(this.indexer == null) {
// 			this.indexer = Optional.empty();
// 		}
// 		functions.add(function);
// 	}
// 
// 	public void setTerminal(TerminalFunction function) {
// 		if(isSubExpression) {
// 			throw new PintoSyntaxException("Sub-expressions cannot include terminal functions");
// 		}
// 		this.terminalFunction = Optional.of(function);
// 	}
// 
// 	public ArrayList<TableFunction> getFunctions() {
// 		return functions;
// 	}
// 		
// 	public boolean isExpressionStart() {
// 		return functions.size() == 0;
// 	}
// 
// 	public boolean isNullary() {
// 		return (!indexer.isPresent()) || indexer.get().isNone();
// 	}
// 
// 	public Set<String> getDependencies() {
// 		return dependencies;
// 	}
// 
// 	public String getText() {
// 		return text.toString();
// 	}
// 
// 	public void addText(String expression) {
// 		this.text.append(" ").append(expression);
// 	}
// 
// 	public Optional<String> getNameLiteral() {
// 		return nameLiteral;
// 	}
// 
// 	public void setNameLiteral(String nameLiteral) {
// 		this.nameLiteral = Optional.of(nameLiteral);
// 	}
// 		
// 	public boolean hasTerminal() {
// 		return terminalFunction.isPresent();
// 	}
// 
// }
// 
// Path: src/main/java/tech/pinto/Pinto.java
// @FunctionalInterface
// public static interface TableFunction extends BiConsumer<Pinto,Table> {}
// 
// Path: src/main/java/tech/pinto/Pinto.java
// public static class Stack extends LinkedList<Column<?>> {
// 	private static final long serialVersionUID = 1L;
// 
// 	public Stack() {
// 		super();
// 	}
// 
// 	public Stack(Collection<? extends Column<?>> c) {
// 		super(c);
// 	}
// 		
// }


import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import tech.pinto.Pinto.Expression;
import tech.pinto.Pinto.TableFunction;
import tech.pinto.Pinto.Stack;

	public Indexer clone() {
		try {
			Indexer clone = (Indexer) super.clone();
			return clone;
		} catch (CloneNotSupportedException e) {
			throw new RuntimeException(e);
		}
	}

	private class Index {

		private final String string;
		private boolean copy = false;
		private boolean not = false;
		private int repeat = 0;
		private Optional<String> header = Optional.empty();
		private Optional<Integer> sliceStart = Optional.empty();
		private Optional<Integer> sliceEnd = Optional.empty();
		private Optional<Expression> orFunction = Optional.empty();

		public Index(Pinto pinto, Set<String> dependencies, String s) {
			this.string = s;
			if(!s.isEmpty()) {
				int equalsPosition = s.indexOf("=");
				if (equalsPosition != -1) {
					if(equalsPosition == s.length()-1) {
						throw new IllegalArgumentException("\"=\" should be followed by alternative expression in index:" + s);
					}
					String header = s.substring(0, equalsPosition);
					String altExpression = s.substring(equalsPosition+1);

// Path: src/main/java/tech/pinto/Pinto.java
// public static class Expression implements TableFunction {
// 		
// 	private final boolean isSubExpression;
// 	private ArrayList<TableFunction>  functions = new ArrayList<>();
// 	private	Optional<Indexer> indexer = null;
// 	private	Optional<TerminalFunction> terminalFunction = Optional.empty();
// 	private Set<String> dependencies = new HashSet<>();
// 	private StringBuilder text = new StringBuilder();
// 	private	Optional<String> nameLiteral = Optional.empty();
// 		
// 	public Expression(boolean isSubExpression) {
// 		this.isSubExpression = isSubExpression;
// 	}
// 
// 	public Table evaluate(Pinto pinto) {
// 		if(!terminalFunction.isPresent()) {
// 			throw new PintoSyntaxException("Need terminal to evaluate expression.");
// 		}
// 		return terminalFunction.get().apply(pinto, this);
// 	}
// 
// 	@Override
// 	public void accept(Pinto pinto, Table table) {
// 		try {
// 			this.indexer.orElse(new Indexer(true)).accept(pinto, table);
// 			for(int i = 0; i < functions.size(); i++) {
// 				functions.get(i).accept(pinto, table);
// 			}
// 			table.collapseFunction();
// 		} catch(RuntimeException e) {
// 			throw new PintoSyntaxException("Error in expression: \"" + getText().trim() + "\": " + e.getLocalizedMessage() + "\n",e);
// 		}
// 	}
// 		
// 	public void addIndexer(Indexer indexer) {
// 		if(this.indexer == null) {
// 			indexer.setIndexForExpression();
// 			this.indexer = Optional.of(indexer);
// 		} else {
// 			functions.add(indexer);
// 		}
// 	}
// 
// 	public void addFunction(Column<?> col) {
// 		addFunction((StackFunction) (p, s) -> s.addFirst(col));
// 	}
// 
// 	public void addFunction(TableFunction function) {
// 		if(this.indexer == null) {
// 			this.indexer = Optional.empty();
// 		}
// 		functions.add(function);
// 	}
// 
// 	public void setTerminal(TerminalFunction function) {
// 		if(isSubExpression) {
// 			throw new PintoSyntaxException("Sub-expressions cannot include terminal functions");
// 		}
// 		this.terminalFunction = Optional.of(function);
// 	}
// 
// 	public ArrayList<TableFunction> getFunctions() {
// 		return functions;
// 	}
// 		
// 	public boolean isExpressionStart() {
// 		return functions.size() == 0;
// 	}
// 
// 	public boolean isNullary() {
// 		return (!indexer.isPresent()) || indexer.get().isNone();
// 	}
// 
// 	public Set<String> getDependencies() {
// 		return dependencies;
// 	}
// 
// 	public String getText() {
// 		return text.toString();
// 	}
// 
// 	public void addText(String expression) {
// 		this.text.append(" ").append(expression);
// 	}
// 
// 	public Optional<String> getNameLiteral() {
// 		return nameLiteral;
// 	}
// 
// 	public void setNameLiteral(String nameLiteral) {
// 		this.nameLiteral = Optional.of(nameLiteral);
// 	}
// 		
// 	public boolean hasTerminal() {
// 		return terminalFunction.isPresent();
// 	}
// 
// }
// 
// Path: src/main/java/tech/pinto/Pinto.java
// @FunctionalInterface
// public static interface TableFunction extends BiConsumer<Pinto,Table> {}
// 
// Path: src/main/java/tech/pinto/Pinto.java
// public static class Stack extends LinkedList<Column<?>> {
// 	private static final long serialVersionUID = 1L;
// 
// 	public Stack() {
// 		super();
// 	}
// 
// 	public Stack(Collection<? extends Column<?>> c) {
// 		super(c);
// 	}
// 		
// }


// Path: src/main/java/tech/pinto/Indexer.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import tech.pinto.Pinto.Expression;
import tech.pinto.Pinto.TableFunction;
import tech.pinto.Pinto.Stack;

	public Indexer clone() {
		try {
			Indexer clone = (Indexer) super.clone();
			return clone;
		} catch (CloneNotSupportedException e) {
			throw new RuntimeException(e);
		}
	}

	private class Index {

		private final String string;
		private boolean copy = false;
		private boolean not = false;
		private int repeat = 0;
		private Optional<String> header = Optional.empty();
		private Optional<Integer> sliceStart = Optional.empty();
		private Optional<Integer> sliceEnd = Optional.empty();
		private Optional<Expression> orFunction = Optional.empty();

		public Index(Pinto pinto, Set<String> dependencies, String s) {
			this.string = s;
			if(!s.isEmpty()) {
				int equalsPosition = s.indexOf("=");
				if (equalsPosition != -1) {
					if(equalsPosition == s.length()-1) {
						throw new IllegalArgumentException("\"=\" should be followed by alternative expression in index:" + s);
					}
					String header = s.substring(0, equalsPosition);
					String altExpression = s.substring(equalsPosition+1);

					Pinto.Expression e = pinto.parseSubExpression(" {" + header + ": " + altExpression + "}");
