package org.watertemplate.interpreter.parser; import org.watertemplate.interpreter.parser.exception.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static org.watertemplate.interpreter.parser.AbstractSyntaxTree.EMPTY; import static org.watertemplate.interpreter.parser.NonTerminal.*; import static org.watertemplate.interpreter.parser.Terminal.*; abstract class Production implements GrammarSymbol { private final List<GrammarSymbol> symbols; Production(final GrammarSymbol... symbols) { this.symbols = Arrays.asList(symbols); } @Override public AbstractSyntaxTree buildAbstractSyntaxTree(final TokenStream tokenStream) { List<AbstractSyntaxTree> abstractSyntaxTrees = new ArrayList<>(); int save = tokenStream.getCurrentTokenPosition(); try { for (GrammarSymbol symbol : symbols) { abstractSyntaxTrees.add(symbol.buildAbstractSyntaxTree(tokenStream)); } } catch (ParseException e) { tokenStream.reset(save); throw e; } return zip(abstractSyntaxTrees); } abstract AbstractSyntaxTree zip(final List<AbstractSyntaxTree> statements); static class If extends Production { If() { super(WAVE, IF, BLANK, ID, COLON, STATEMENTS, END_OF_BLOCK); } @Override AbstractSyntaxTree zip(final List<AbstractSyntaxTree> statements) { AbstractSyntaxTree.Id conditionId = (AbstractSyntaxTree.Id) statements.get(3); AbstractSyntaxTree ifStatements = statements.get(5); return new AbstractSyntaxTree.If(conditionId, ifStatements); } } static class IfElse extends Production { IfElse() { super(WAVE, IF, BLANK, ID, COLON, STATEMENTS, ELSE, STATEMENTS, END_OF_BLOCK); } @Override AbstractSyntaxTree zip(final List<AbstractSyntaxTree> statements) { AbstractSyntaxTree.Id conditionId = (AbstractSyntaxTree.Id) statements.get(3); AbstractSyntaxTree ifStatements = statements.get(5); AbstractSyntaxTree elseStatements = statements.get(7); return new AbstractSyntaxTree.If(conditionId, ifStatements, elseStatements); } } static class For extends Production { For() { super(WAVE, FOR, BLANK, PROPERTY_KEY, BLANK, IN, BLANK, ID, COLON, STATEMENTS, END_OF_BLOCK); } @Override AbstractSyntaxTree zip(final List<AbstractSyntaxTree> statements) { String propertyKey = ((AbstractSyntaxTree.Id) statements.get(3)).getPropertyKey(); AbstractSyntaxTree.Id collectionId = (AbstractSyntaxTree.Id) statements.get(7); AbstractSyntaxTree forStatements = statements.get(9); return new AbstractSyntaxTree.For(propertyKey, collectionId, forStatements); } } static class ForElse extends Production { ForElse() { super(WAVE, FOR, BLANK, PROPERTY_KEY, BLANK, IN, BLANK, ID, COLON, STATEMENTS, ELSE, STATEMENTS, END_OF_BLOCK); } @Override AbstractSyntaxTree zip(final List<AbstractSyntaxTree> statements) { String propertyKey = ((AbstractSyntaxTree.Id) statements.get(3)).getPropertyKey(); AbstractSyntaxTree.Id collectionId = (AbstractSyntaxTree.Id) statements.get(7); AbstractSyntaxTree forStatements = statements.get(9); AbstractSyntaxTree elseStatements = statements.get(11); return new AbstractSyntaxTree.For(propertyKey, collectionId, forStatements, elseStatements); } } static class Id extends Production { Id() { super(PROPERTY_KEY, NESTED_PROP); } @Override AbstractSyntaxTree zip(final List<AbstractSyntaxTree> statements) { AbstractSyntaxTree.Id propertyKey = (AbstractSyntaxTree.Id) statements.get(0); AbstractSyntaxTree nested = statements.get(1); if (nested == EMPTY) { return propertyKey; } else { return new AbstractSyntaxTree.Id(propertyKey.getPropertyKey(), (AbstractSyntaxTree.Id) nested); } } } static class NestedProperty extends Production { NestedProperty() { super(ACCESSOR, ID); } @Override AbstractSyntaxTree zip(final List<AbstractSyntaxTree> statements) { return statements.get(1); } } static class Evaluation extends Production { Evaluation() { super(WAVE, ID, WAVE); } @Override AbstractSyntaxTree zip(final List<AbstractSyntaxTree> statements) { return statements.get(1); } } static class Statements extends Production { public Statements(final GrammarSymbol... statements) { super(statements); } @Override AbstractSyntaxTree zip(final List<AbstractSyntaxTree> statements) { return new AbstractSyntaxTree.Statements(statements); } } static class Empty extends Production { @Override AbstractSyntaxTree zip(final List<AbstractSyntaxTree> statements) { return AbstractSyntaxTree.EMPTY; } } }