/* * JAME 6.2.1 * http://jame.sourceforge.net * * Copyright 2001, 2016 Andrea Medeghini * * This file is part of JAME. * * JAME is an application for creating fractals and other graphics artifacts. * * JAME is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JAME is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JAME. If not, see <http://www.gnu.org/licenses/>. * */ package net.sf.jame.contextfree.parser; import org.antlr.v4.runtime.Token; class ASTLoop extends ASTReplacement { private ASTExpression loopArgs; private ASTModification loopModHolder; private double[] loopData = new double[3]; private ASTRepContainer loopBody = new ASTRepContainer(); private ASTRepContainer finallyBody = new ASTRepContainer(); private int loopIndexName; private String loopName; public ASTLoop(int nameIndex, String name, ASTExpression args, ASTModification mods, Token location) { super(mods, ERepElemType.empty, location); this.loopArgs = args; this.loopModHolder = null; this.loopIndexName = nameIndex; this.loopName = name; loopBody.addLoopParameter(loopIndexName, false, false, location); finallyBody.addLoopParameter(loopIndexName, false, false, location); } public ASTRepContainer getLoopBody() { return loopBody; } public ASTRepContainer getFinallyBody() { return finallyBody; } public void setLoopHolder(ASTModification loopModHolder) { this.loopModHolder = loopModHolder; } public ASTExpression getLoopArgs() { return loopArgs; } public ASTModification getLoopModHolder() { return loopModHolder; } public double[] getLoopData() { return loopData; } public int getLoopIndexName() { return loopIndexName; } public String getLoopName() { return loopName; } public void compileLoopMod() { if (loopModHolder != null) { loopModHolder.compile(ECompilePhase.TypeCheck); getChildChange().grab(loopModHolder); } else { getChildChange().compile(ECompilePhase.TypeCheck); } } @Override public void compile(ECompilePhase ph) { if (loopArgs != null) { loopArgs.compile(ph); } switch (ph) { case TypeCheck: { if (loopArgs == null) { error("A loop must have one to three index parameters."); return; } StringBuilder ent = new StringBuilder(); ent.append(loopName); loopArgs.entropy(ent); if (loopModHolder != null) { getChildChange().addEntropy(ent.toString()); } boolean bodyNatural = false; boolean finallyNatural = false; ELocality locality = loopArgs.getLocality(); if (loopArgs.isConstant()) { setupLoop(loopData, loopArgs, null); bodyNatural = loopData[0] == Math.floor(loopData[0]) && loopData[1] == Math.floor(loopData[1]) && loopData[2] == Math.floor(loopData[2]) && loopData[0] >= 0 && loopData[1] >= 0 && loopData[0] < 9007199254740992.0 && loopData[1] < 9007199254740992.0; finallyNatural = bodyNatural && loopData[1] + loopData[2] >= -1.0 && loopData[1] + loopData[2] < 9007199254740992.0; loopArgs = null; } else { int c = loopArgs.evaluate(null, 0); if (c < 1 || c > 3) { error("A loop must have one to three index parameters."); } for (int i = 0, count = 0; i < loopArgs.size(); i++) { ASTExpression loopArg = loopArgs.getChild(i); int num = loopArg.evaluate(null, 0); switch (count) { case 0: if (loopArg.isNatural()) { bodyNatural = finallyNatural = true; } break; case 2: // Special case: if 1st & 2nd args are natural and 3rd // is -1 then that is ok double[] step = new double[1]; if (loopArg.isConstant() && loopArg.evaluate(step, 1) == 1 && step[0] == -1.0) { break; } // else fall through case 1: if (!loopArg.isNatural()) { bodyNatural = finallyNatural = false; } break; default: break; } count += num; } } loopBody.getParameters().get(loopBody.getParameters().size() - 1).setIsNatural(bodyNatural); loopBody.getParameters().get(loopBody.getParameters().size() - 1).setLocality(locality); loopBody.compile(ph, this, null); finallyBody.getParameters().get(finallyBody.getParameters().size() - 1).setIsNatural(finallyNatural); finallyBody.getParameters().get(finallyBody.getParameters().size() - 1).setLocality(locality); finallyBody.compile(ph, null, null); if (loopModHolder == null) { getChildChange().addEntropy(ent.toString()); } } break; case Simplify: if (loopArgs != null) { loopArgs.simplify(); } loopBody.compile(ph, null, null); finallyBody.compile(ph, null, null); break; default: break; } } @Override public void traverse(Shape parent, boolean tr, RTI rti) { Shape loopChild = parent; boolean opsOnly = (loopBody.getRepType() | finallyBody.getRepType()) == ERepElemType.op.getType(); if (opsOnly && !tr) { loopChild.getWorldState().setTransform(null); } double[] data = new double[2]; rti.getCurrentSeed().add(getChildChange().getModData().getRand64Seed()); if (loopArgs != null) { setupLoop(data, loopArgs, rti); } else { data[0] = loopData[0]; data[1] = loopData[1]; data[2] = loopData[2]; } StackType t = new StackType(data[0]); StackType oldTop = rti.getLogicalStackTop(); rti.getCFStack().add(t); StackType index = rti.getCFStack().get(rti.getCFStack().size() - 1); index.addNumber(1); rti.setLogicalStackTop(index); for (;;) { if (rti.getRequestStop() /*TODO || Renderer.abortEverything()*/) { throw new RuntimeException("Stopping"); } if (data[2] > 0.0) { if (index.getNumber() >= data[1]) { break; } } else { if (index.getNumber() <= data[1]) { break; } } loopBody.traverse(loopChild, tr || opsOnly, rti, false); Modification[] mod = new Modification[1]; getChildChange().evaluate(mod, true, rti); loopChild.setWorldState(mod[0]); index.addNumber(data[2]); } finallyBody.traverse(loopChild, tr || opsOnly, rti, false); rti.getCFStack().remove(rti.getCFStack().size() - 1); rti.setLogicalStackTop(oldTop); } private void setupLoop(double[] data, ASTExpression exp, RTI rti) { switch (exp.evaluate(data, 3, rti)) { case 1: data[1] = data[0]; data[0] = 0.0; break; case 2: data[2] = 1.0; break; case 3: break; default: error("A loop must have one to three index parameters."); break; } } }