/*
* 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 java.util.ArrayList;
import java.util.List;
import org.antlr.v4.runtime.Token;
class ASTDefine extends ASTReplacement {
private EDefineType defineType;
private ASTExpression exp;
private int tupleSize;
private EExpType expType;
private boolean isNatural;
private List<ASTParameter> parameters = new ArrayList<ASTParameter>();
private int stackCount;
private String name;
private int configDepth;
public ASTDefine(String name, Token location) {
super(new ASTModification(location), ERepElemType.empty, location);
this.defineType = EDefineType.StackDefine;
this.expType = EExpType.NoType;
this.isNatural = false;
this.stackCount = 0;
this.name = name;
this.configDepth = -1;
int[] i = new int[1];
getChildChange().getModData().getRand64Seed().init();
getChildChange().getModData().getRand64Seed().xorString(name, i);
}
public EDefineType getDefineType() {
return defineType;
}
public void setDefineType(EDefineType defineType) {
this.defineType = defineType;
}
public ASTExpression getExp() {
return exp;
}
public void setExp(ASTExpression exp) {
this.exp = exp;
}
public int getTupleSize() {
return tupleSize;
}
public void setTupleSize(int tupleSize) {
this.tupleSize = tupleSize;
}
public EExpType getExpType() {
return expType;
}
public void setExpType(EExpType expType) {
this.expType = expType;
}
public boolean isNatural() {
return isNatural;
}
public void setIsNatural(boolean isNatural) {
this.isNatural = isNatural;
}
public List<ASTParameter> getParameters() {
return parameters;
}
public void setParameters(List<ASTParameter> parameters) {
this.parameters = parameters;
}
public int getStackCount() {
return stackCount;
}
public void setStackCount(int stackCount) {
this.stackCount = stackCount;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getConfigDepth() {
return configDepth;
}
public void setConfigDepth(int configDepth) {
this.configDepth = configDepth;
}
public void incStackCount(int value) {
stackCount += value;
}
public void idecStackCount(int value) {
stackCount -= value;
}
@Override
public void compile(ECompilePhase ph) {
if (defineType == EDefineType.FunctionDefine || defineType == EDefineType.LetDefine) {
ASTRepContainer tempCont = new ASTRepContainer();
tempCont.setParameters(parameters);
tempCont.setStackCount(stackCount);
Builder.currentBuilder().pushRepContainer(tempCont);
super.compile(ph);
if (exp != null) {
exp.compile(ph);
}
if (ph == ECompilePhase.Simplify) {
if (exp != null) {
exp.simplify();
}
}
Builder.currentBuilder().popRepContainer(null);
}
switch (ph) {
case TypeCheck:
{
if (defineType == EDefineType.ConfigDefine) {
Builder.currentBuilder().makeConfig(this);
return;
}
getChildChange().getModData().getRand64Seed().init();
getChildChange().setEntropyIndex(0);
getChildChange().addEntropy(name);
EExpType t = exp != null ? exp.getType() : EExpType.ModType;
int sz = 1;
if (t == EExpType.NumericType) {
sz = exp.evaluate(null, 0);
}
if (t == EExpType.ModType) {
sz = 6;
}
if (defineType == EDefineType.FunctionDefine) {
if (t != getExpType()) {
error("Mismatch between declared and defined type of user function");
}
if (getExpType() == EExpType.NumericType && t == EExpType.NumericType && sz != tupleSize) {
error("Mismatch between declared and defined vector length of user function");
}
if (isNatural() && (exp == null || exp.isNatural())) {
error("Mismatch between declared natural and defined not-natural type of user function");
}
} else {
if (getShapeSpecifier().getShapeType() >= 0) {
ASTDefine[] func = new ASTDefine[1];
@SuppressWarnings("unchecked")
List<ASTParameter>[] shapeParams = new List[1];
Builder.currentBuilder().getTypeInfo(getShapeSpecifier().getShapeType(), func, shapeParams);
if (func[0] != null) {
error("Variable name is also the name of a function");
error(func[0].getLocation() + " function definition is here");
}
if (shapeParams[0] != null) {
error("Variable name is also the name of a shape");
}
}
tupleSize = sz;
expType = t;
if (t.getType() != (t.getType() & (-t.getType())) || t.getType() == 0) {//TODO da controllare???
error("Expression can only have one type");
}
if (defineType == EDefineType.StackDefine && (exp != null ? exp.isConstant() : getChildChange().getModExp().isEmpty())) {
defineType = EDefineType.ConstDefine;
}
isNatural = exp != null && exp.isNatural() && expType == EExpType.NumericType;
ASTParameter param = Builder.currentBuilder().getContainerStack().peek().addDefParameter(getShapeSpecifier().getShapeType(), this, getLocation());
if (param.isParameter() || param.getDefinition() == null) {
param.setStackIndex(Builder.currentBuilder().getLocalStackDepth());
Builder.currentBuilder().getContainerStack().peek().setStackCount(Builder.currentBuilder().getContainerStack().peek().getStackCount() + param.getTupleSize());
Builder.currentBuilder().setLocalStackDepth(Builder.currentBuilder().getLocalStackDepth() + param.getTupleSize());
}
}
}
break;
case Simplify:
break;
default:
break;
}
}
@Override
public void traverse(Shape parent, boolean tr, RTI rti) {
if (defineType != EDefineType.StackDefine) {
return;
}
rti.getCurrentSeed().add(getChildChange().getModData().getRand64Seed());
StackType dest = rti.getCFStack().get(rti.getCFStack().size() - 1);
switch (expType) {
case NumericType:
double[] result = new double[1];
if (exp.evaluate(result, tupleSize, rti) != tupleSize) {
error("Error evaluating parameters (too many or not enough).");
}
dest.setNumber(result[0]);
break;
case ModType:
Modification[] mod = new Modification[1];
getChildChange().setVal(mod, rti);
dest.setModification(mod[0]);
break;
case RuleType:
dest.setRule(exp.evalArgs(rti, parent.getParameters()));
break;
default:
error("Unimplemented parameter type.");
break;
}
}
}