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;
}
}