package com.drawbridge.jsengine.ast; import java.util.LinkedList; import com.drawbridge.jsengine.Scope; import com.drawbridge.jsengine.jsobjects.JSBoolean; import com.drawbridge.jsengine.jsobjects.JSNumber; import com.drawbridge.jsengine.jsobjects.JSReference; import com.drawbridge.jsengine.jsobjects.JSType; import com.drawbridge.utils.Utils; import com.drawbridge.vl.blocks.Block; import com.drawbridge.vl.blocks.BlockOperator; import com.drawbridge.vl.blocks.BlockPrimitive; import com.drawbridge.vl.blocks.BlockOperator.SupportedOperationType; import com.google.caja.parser.js.Operator; import com.google.caja.parser.js.SimpleOperation; public class SimpleOperationEvaluator extends Evaluator{ Operator opType; /** * Simple operation consists of two things - op1 and op2 * @param parser * @param simpleOperation */ public SimpleOperationEvaluator(Evaluator parent, Scope scope, SimpleOperation simpleOperation) { super(parent,scope, simpleOperation.getFilePosition()); opType = simpleOperation.getOperator(); if(simpleOperation.children() != null){ for(int i = 0; i < simpleOperation.children().size(); i++){ mChildren.add(Evaluator.getEvaluator(this, scope, simpleOperation.children().get(i))); } } else{ Utils.out.println("SimpleOperationEvaluator problem in constructor2"); } } @Override public JSType evaluate() { try{ if(mChildren == null){ throw new RuntimeException("No operands available in SimpleOperationEvaluator!"); } Utils.out.println("Simple Operation opsSize: " + mChildren.size()); Utils.out.println(mChildren.get(0).evaluate().toString()); JSType obj1; JSType obj2; JSNumber result1; JSNumber result2; if(mChildren.size() == 1){ obj1 = mChildren.get(0).evaluate(); if(obj1 instanceof JSReference){ result1 = (JSNumber) mScope.getVariable(((JSReference) obj1).mValue).getVariable(); } else if(obj1 instanceof JSNumber){ result1 = (JSNumber) obj1; } else{ throw new RuntimeException("Unexpected type in simple operation evaluator: " + obj1.getClass().getName()); } switch(opType){ case NEGATION: return new JSNumber(result1.mValue * -1); case NOT: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case TYPEOF: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); default: break; } } else if(mChildren.size() == 2){ obj1 = mChildren.get(0).evaluate(); obj2 = mChildren.get(1).evaluate(); if(obj1 instanceof JSReference){ result1 = (JSNumber) mScope.getVariable(((JSReference) obj1).mValue).getVariable(); } else if(obj1 instanceof JSNumber){ result1 = (JSNumber) obj1; } else{ throw new RuntimeException("Unexpected type in simple operation evaluator: " + obj1.getClass().getName()); } if(obj2 instanceof JSReference){ result2 = (JSNumber) mScope.getVariable(((JSReference) obj2).mValue).getVariable(); } else if(obj2 instanceof JSNumber){ result2 = (JSNumber) obj2; } else{ throw new RuntimeException("Unexpected type in simple operation evaluator"); } switch(opType){ case ADDITION: return new JSNumber((result1.mValue + result2.mValue)); case SUBTRACTION: return new JSNumber((result1.mValue - result2.mValue)); case MULTIPLICATION: return new JSNumber((result1.mValue * result2.mValue)); case DIVISION: return new JSNumber((result1.mValue / result2.mValue)); case MODULUS: return new JSNumber((result1.mValue % result2.mValue)); case BITWISE_OR: return new JSNumber(Double.longBitsToDouble(Double.doubleToRawLongBits(result1.mValue) | Double.doubleToRawLongBits(result2.mValue))); case BITWISE_AND: return new JSNumber(Double.longBitsToDouble(Double.doubleToRawLongBits(result1.mValue) & Double.doubleToRawLongBits(result2.mValue))); case BITWISE_XOR: return new JSNumber(Double.longBitsToDouble(Double.doubleToRawLongBits(result1.mValue) ^ Double.doubleToRawLongBits(result2.mValue))); case NEGATION: return new JSNumber(result1.mValue * -1); case EQUAL: return new JSBoolean((result1.mValue.equals(result2.mValue))); case ASSIGN: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case ASSIGN_AND: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case ASSIGN_DIV: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case ASSIGN_LSH: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case ASSIGN_MOD: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case ASSIGN_MUL: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case ASSIGN_OR: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case ASSIGN_RSH: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case ASSIGN_SUB: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case ASSIGN_SUM: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case ASSIGN_USH: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); case ASSIGN_XOR: throw new RuntimeException("Simple Operation not yet implemented:" + opType.toString()); default: break; } } else{ throw new RuntimeException("Too many operands for a Simple OperationEvaluator!"); } } catch(Exception e){ e.printStackTrace(); } return null; } @SuppressWarnings("incomplete-switch") @Override public LinkedList<com.drawbridge.vl.blocks.Block> getBlocks() { LinkedList<com.drawbridge.vl.blocks.Block> result = new LinkedList<com.drawbridge.vl.blocks.Block>(); if(mChildren.size() > 0 && mChildren.get(0) != null){ if(opType == Operator.NEGATION){ LinkedList<Block> negationResults = mChildren.get(0).getBlocks(); if(negationResults.size() == 1 && negationResults.get(0) instanceof BlockPrimitive){ BlockPrimitive primitive = ((BlockPrimitive)negationResults.get(0)); Integer number = Integer.parseInt(primitive.getText()); primitive.setText("" + (number * -1)); } result.addAll(negationResults); } else{ result.addAll(mChildren.get(0).getBlocks()); } } switch(opType){ case ADDITION: result.add(new BlockOperator(getFilePosition(), this, SupportedOperationType.ADDITION)); break; case SUBTRACTION: result.add(new BlockOperator(getFilePosition(), this, SupportedOperationType.SUBTRACTION)); break; case MULTIPLICATION: result.add(new BlockOperator(getFilePosition(), this, SupportedOperationType.MULTIPLICATION)); break; case DIVISION: result.add(new BlockOperator(getFilePosition(), this, SupportedOperationType.DIVISION)); break; case MODULUS: result.add(new BlockOperator(getFilePosition(), this, SupportedOperationType.MODULUS)); break; } if(mChildren.size() > 1 && mChildren.get(1) != null) { result.addAll(mChildren.get(1).getBlocks()); } return result; } }