package com.drawbridge.utils; import java.util.HashSet; import java.util.LinkedList; import com.drawbridge.dm.DMImageFactory.DMImage; import com.drawbridge.jsengine.ast.DBParser; import com.drawbridge.jsengine.ast.DeclarationEvaluator; import com.drawbridge.jsengine.ast.Evaluator; import com.drawbridge.jsengine.ast.IntegerLiteralEvaluator; import com.drawbridge.jsengine.ast.NoopEvaluator; import com.drawbridge.jsengine.ast.NumberLiteralEvaluator; import com.drawbridge.jsengine.ast.SpecialOperationEvaluator; import com.drawbridge.text.TextPanel; import com.google.caja.lexer.FilePosition; public class ASTModification { public static enum ASTModificationType { MOD_LOCATION, MOD_SIZE; } /** * Allows modification of parts of the E-AST that refer to the given image. Usually used by the DM Panel. * * @param image * @param mod * @return */ public static <P> boolean modifyImageParams(DMImage image, ASTModification.ASTModificationType mod) { Utils.out.println(ASTModification.class, "modifyImageParams"); // Reset the recently changed evaluators DBParser.getInstance().mRecentlyChangedEvaluators.clear(); Evaluator e = null; switch (mod) { case MOD_LOCATION: e = image.getEvaluatorNode(ASTModification.ASTModificationType.MOD_LOCATION); break; case MOD_SIZE: e = image.getEvaluatorNode(ASTModification.ASTModificationType.MOD_SIZE); break; default: return false; } if (e instanceof DeclarationEvaluator) { DeclarationEvaluator de = (DeclarationEvaluator) e; Utils.out.println("Last modifer of " + mod.name() + " was a DeclarationEvaluator " + de.mChildren.size()); throw new RuntimeException("modifyImageParams not implemented yet"); } else if (e instanceof SpecialOperationEvaluator) { // it's setTweenLocation/setTweenSize or loadImage SpecialOperationEvaluator soEval = (SpecialOperationEvaluator) e; HashSet<Evaluator> changedEvaluators = new HashSet<Evaluator>(); switch (mod) { case MOD_LOCATION: NumberLiteralEvaluator<Integer> evalX = (NumberLiteralEvaluator<Integer>) soEval.mChildren.get(2); NumberLiteralEvaluator<Integer> evalY = (NumberLiteralEvaluator<Integer>) soEval.mChildren.get(3); if(DBParser.getInstance().containsEvaluator(evalY)){ Utils.err.println(ASTModification.class,"MOD_LOCATION_CONTAINS_EVALUATOR"); } else{ Utils.err.println(ASTModification.class,"MOD_LOCATION_DOES_NOT_CONTAIN_EVALUATOR"); } boolean changedX = modifyILEvaluatorValue(evalX, image.getX()); boolean changedY = modifyILEvaluatorValue(evalY, image.getY()); if(changedX) changedEvaluators.add(evalX); if(changedY) changedEvaluators.add(evalY); break; case MOD_SIZE: IntegerLiteralEvaluator evalW = (IntegerLiteralEvaluator) soEval.mChildren.get(4); IntegerLiteralEvaluator evalH = (IntegerLiteralEvaluator) soEval.mChildren.get(5); boolean changedW = modifyILEvaluatorValue(evalW, image.getWidth()); boolean changedH = modifyILEvaluatorValue(evalH, image.getHeight()); if(changedW) changedEvaluators.add(evalW); if(changedH) changedEvaluators.add(evalH); break; } DBParser.getInstance().mRecentlyChangedEvaluators = changedEvaluators; if(TextPanel.hasInstance()){ TextPanel.getInstance().getDocument().repaint(); } return true; } return false; } public interface JavaNumber{ } /** * Modifies the value in the evaluator * @param e * @param newValue * @return boolean - True if the value has changed. */ public static <T> boolean modifyILEvaluatorValue(NumberLiteralEvaluator<T> e, T newValue) { T validNewValue = e.getValidValue((Double)newValue); Utils.err.println(Utils.class, "ASTMODIFICATION"); int filePosDiff = e.getFPDiff(validNewValue); //this is probably very dodgy e.modifyValue(null, validNewValue, true); if (filePosDiff != 0) { Utils.err.println(ASTModification.class, "Before: " + e.toString() + " " + e.getFilePosition().toString()); expandFPInContext(e, filePosDiff); Utils.err.println(ASTModification.class, "After:" + e.getFilePosition().toString()); Evaluator ancestor = getEvalParent(e); LinkedList<Evaluator> evals = DBParser.getInstance().getEvaluators(); if (evals.contains(ancestor)) { int nextIndex = evals.indexOf(ancestor) + 1; if (nextIndex < evals.size() && evals.get(nextIndex) instanceof NoopEvaluator) { shiftFP(evals.get(nextIndex), filePosDiff); } } } if(validNewValue == newValue) return true; return false; } /** * Recursively traverse E-AST, changing FilePositions of parents and siblings to the right * * @param Evaluator * @param LengthDifference */ public static void expandFPInContext(Evaluator e, int lengthDiff) { // Widen fp expandFP(e, lengthDiff); Evaluator parent = e.mParent; // Deal with direct ancestors if (parent != null) { Utils.out.println("Expanding parent:" + parent.toString() + " Before:" + parent.getFilePosition().toString() + "->"); expandFPInContext(parent, lengthDiff); Utils.out.println(" " + parent.getFilePosition().toString()); } // Deal with siblings if (parent != null) { LinkedList<Evaluator> siblings = parent.mChildren; int startIndex = Integer.MAX_VALUE; for (int i = 0; i < siblings.size(); i++) { if(siblings.get(i) == e){ Utils.err.println("Found equal evaluators at " + i + " of " + siblings.size()); startIndex = i + 1; } if(i >= startIndex){ Utils.out.println("Shifting sibling:" + siblings.get(i).toString()); shiftFP(siblings.get(i), lengthDiff); } } } } /** * Changes the length of the FilePosition by the Length Difference * * @param FilePosition * @param Length * Difference * @return Updated FilePosition */ public static void expandFP(Evaluator e, int diff) { FilePosition fp = e.getFilePosition(); e.setFilePosition(FilePosition.instance(fp.source(), fp.startLineNo(), fp.startCharInFile(), fp.startCharInLine(), Math.max(0, fp.length() + diff))); } /** * Moves a file position by a given number of characters. Doesn't do any changes across lines * * @param FilePosition * @param Character * shift * @return Updated FilePosition */ public static void shiftFP(Evaluator e, int shift) { FilePosition fp = e.getFilePosition(); e.setFilePosition(FilePosition.instance(fp.source(), fp.startLineNo(), fp.startCharInFile() + shift, fp.startCharInLine() + shift, fp.length())); } public static Evaluator getEvalParent(Evaluator e) { if (e.mParent != null) { return getEvalParent(e.mParent); } else { return e; } } }