Beispiel #1
0
bool isChildofMain(TIntermNode *node, TIntermNode *root)
{
    TIntermNode *main = getFunctionBySignature(MAIN_FUNC_SIGNATURE, root);

    if (!main) {
        dbgPrint(DBGLVL_ERROR, "CodeTools - could not find main function\n");
        exit(1);
    }

    TIntermAggregate *aggregate;

    if (!(aggregate = main->getAsAggregate())) {
        dbgPrint(DBGLVL_ERROR, "CodeTools - main is not Aggregate\n");
        exit(1);
    }
    
    TIntermSequence sequence = aggregate->getSequence();
    TIntermSequence::iterator sit;

    for(sit = sequence.begin(); sit != sequence.end(); sit++) {
        if (*sit == node) {
            return true;
        }
    }

    return false;
}
Beispiel #2
0
int getFunctionDebugParameter(TIntermAggregate *node)
{
    int result = -1;
    int i;

    if (!node)
        return result;

    if ( node->getOp() != EOpFunction) {
        return result;
    }

    TIntermSequence funcDeclSeq = node->getSequence();
    
    if (!funcDeclSeq[0] ||
        !funcDeclSeq[0]->getAsAggregate() ||
        !(funcDeclSeq[0]->getAsAggregate()->getOp() == EOpParameters)) {
        dbgPrint(DBGLVL_ERROR, "CodeTools - function does not comply with assumptions\n");
        exit(1);
    }
    TIntermSequence funcDeclParamSeq = (funcDeclSeq[0]->getAsAggregate())->getSequence();
    TIntermSequence::iterator pD = funcDeclParamSeq.begin();
    
    for (i=0; pD != funcDeclParamSeq.end(); ++pD, ++i) {
        if ((*pD)->getAsFuncParamNode()->getType().getQualifier() == EvqIn) {
            result = i;
        }
    }

    return result;
}
Beispiel #3
0
void TOutputGLSL::writeFunctionParameters(const TIntermSequence& args)
{
    TInfoSinkBase& out = objSink();
    for (TIntermSequence::const_iterator iter = args.begin();
         iter != args.end(); ++iter)
    {
        const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
        ASSERT(arg != NULL);

        const TType& type = arg->getType();
        TQualifier qualifier = type.getQualifier();
        // TODO(alokp): Validate qualifier for function arguments.
        if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
            out << type.getQualifierString() << " ";

        out << getTypeName(type);

        const TString& name = arg->getSymbol();
        if (!name.empty())
            out << " " << name;
        if (type.isArray())
            out << arrayBrackets(type);

        // Put a comma if this is not the last argument.
        if (iter != args.end() - 1)
            out << ", ";
    }
}
Beispiel #4
0
bool TCompiler::pruneUnusedFunctions(TIntermNode *root)
{
    TIntermAggregate *rootNode = root->getAsAggregate();
    ASSERT(rootNode != nullptr);

    UnusedPredicate isUnused(&mCallDag, &functionMetadata);
    TIntermSequence *sequence = rootNode->getSequence();
    sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->end());

    return true;
}
Beispiel #5
0
//
// Merge the function bodies and global-level initializers from unitGlobals into globals.
// Will error check duplication of function bodies for the same signature.
//
void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, const TIntermSequence& unitGlobals)
{
    // TODO: link-time performance: Processing in alphabetical order will be faster

    // Error check the global objects, not including the linker objects
    for (unsigned int child = 0; child < globals.size() - 1; ++child) {
        for (unsigned int unitChild = 0; unitChild < unitGlobals.size() - 1; ++unitChild) {
            TIntermAggregate* body = globals[child]->getAsAggregate();
            TIntermAggregate* unitBody = unitGlobals[unitChild]->getAsAggregate();
            if (body && unitBody && body->getOp() == EOpFunction && unitBody->getOp() == EOpFunction && body->getName() == unitBody->getName()) {
                error(infoSink, "Multiple function bodies in multiple compilation units for the same signature in the same stage:");
                infoSink.info << "    " << globals[child]->getAsAggregate()->getName() << "\n";
            }
        }
    }

    // Merge the global objects, just in front of the linker objects
    globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1);
}
Beispiel #6
0
TIntermNode* getFunctionBySignature(const char *sig, TIntermNode* root)
// Assumption: 1. roots hold all function definitions.
//                for single file shaders this should hold.
// Todo: Add solution for multiple files compiled in one shader.
{
	TIntermAggregate *aggregate;
	TIntermSequence sequence;
	TIntermSequence::iterator sit;

	// Root must be aggregate
	if (!(aggregate = root->getAsAggregate())) {
		return NULL;
	}
	if (aggregate->getOp() == EOpFunction) {
		// do not stop search at function prototypes
		if (aggregate->getSequence().size() != 0) {
			if (!strcmp(sig, aggregate->getName().c_str())) {
				return aggregate;
			}
		}
	} else {
		sequence = aggregate->getSequence();

		for (sit = sequence.begin(); sit != sequence.end(); sit++) {
			if ((*sit)->getAsAggregate()
					&& (*sit)->getAsAggregate()->getOp() == EOpFunction) {
				// do not stop search at function prototypes
				if ((*sit)->getAsAggregate()->getSequence().size() != 0) {
					if (!strcmp(sig,
							(*sit)->getAsAggregate()->getName().c_str())) {
						return *sit;
					}
				}
			}
		}
	}
	return NULL;
}
void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
{
    TInfoSinkBase& out = objSink();
    for (TIntermSequence::const_iterator iter = args.begin();
         iter != args.end(); ++iter)
    {
        const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
        ASSERT(arg != NULL);

        const TType& type = arg->getType();
        writeVariableType(type);

        const TString& name = arg->getSymbol();
        if (!name.empty())
            out << " " << name;
        if (type.isArray())
            out << arrayBrackets(type);

        // Put a comma if this is not the last argument.
        if (iter != args.end() - 1)
            out << ", ";
    }
}
bool TSamplerTraverser::traverseAggregate( bool preVisit, TIntermAggregate *node, TIntermTraverser *it)
{
   TSamplerTraverser* sit = static_cast<TSamplerTraverser*>(it);
   TInfoSink &infoSink = sit->infoSink;

   if (sit->abort)
      return false;

   if (! (sit->typing) )
   {
      switch (node->getOp())
      {
      
      case EOpFunction:
         // Store the current function name to use to setup the parameters
         sit->currentFunction = node->getName().c_str(); 
         break;

      case EOpParameters:
         // Store the parameters to the function in the map
         sit->functionMap[sit->currentFunction.c_str()] = &(node->getSequence());
         break;

      case EOpFunctionCall:
         {
            // This is a bit tricky.  Find the function in the map.  Loop over the parameters
            // and see if the parameters have been marked as a typed sampler.  If so, propagate
            // the sampler type to the caller
            if ( sit->functionMap.find ( node->getName().c_str() ) != sit->functionMap.end() )
            {
               // Get the sequence of function parameters
               TIntermSequence *funcSequence = sit->functionMap[node->getName().c_str()];
               
               // Get the sequence of parameters being passed to function
               TIntermSequence &sequence = node->getSequence();

               // Grab iterators to both sequences
               TIntermSequence::iterator it = sequence.begin();
               TIntermSequence::iterator funcIt = funcSequence->begin();

               assert ( sequence.size() == funcSequence->size() );
               if ( sequence.size() == funcSequence->size() )
               {
                  while ( it != sequence.end() )
                  {
                     TIntermSymbol *sym = (*it)->getAsSymbolNode();
                     TIntermSymbol *funcSym = (*funcIt)->getAsSymbolNode();
                     
                     if ( sym != NULL && funcSym != NULL)
                     {
                        // If the parameter is generic, and the sampler to which
                        // it is being passed has been marked, propogate its sampler
                        // type to the caller.
                        if ( sym->getBasicType() == EbtSamplerGeneric &&
                             funcSym->getBasicType() != EbtSamplerGeneric )
                        {
                           sit->typeSampler ( sym, funcSym->getBasicType() );
                        }
                     }
                     it++;
                     funcIt++;
                  }
               }
            }
         }
         break;

         //HLSL texture functions
      case EOpTex1D:
      case EOpTex1DProj:
      case EOpTex1DLod:
      case EOpTex1DBias:
      case EOpTex1DGrad:
         {
            TIntermSequence &sequence = node->getSequence();
            assert( sequence.size());
            TIntermTyped *sampArg = sequence[0]->getAsTyped();
            if ( sampArg)
            {
               if (sampArg->getBasicType() == EbtSamplerGeneric)
               {
                  //type the sampler
                  sit->typeSampler( sampArg, EbtSampler1D);
               }
               else if (sampArg->getBasicType() != EbtSampler1D)
               {
                  //We have a sampler mismatch error
                  infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n";
               }
            }
            else
            {
               assert(0);
            }

         }
         // We need to continue the traverse here, because the calls could be nested 
         break;


      case EOpTex2D:
      case EOpTex2DProj:
      case EOpTex2DLod:
      case EOpTex2DBias:
      case EOpTex2DGrad:
         {
            TIntermSequence &sequence = node->getSequence();
            assert( sequence.size());
            TIntermTyped *sampArg = sequence[0]->getAsTyped();
            if ( sampArg)
            {
               if (sampArg->getBasicType() == EbtSamplerGeneric)
               {
                  //type the sampler
                  sit->typeSampler( sampArg, EbtSampler2D);
               }
               else if (sampArg->getBasicType() != EbtSampler2D)
               {
                  //We have a sampler mismatch error
                  infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n";
               }
            }
            else
            {
               assert(0);
            }

         }
         // We need to continue the traverse here, because the calls could be nested 
         break;

	  case EOpTexRect:
	  case EOpTexRectProj:
		  {
			  TIntermSequence &sequence = node->getSequence();
			  assert( sequence.size());
			  TIntermTyped *sampArg = sequence[0]->getAsTyped();
			  if ( sampArg)
			  {
				  if (sampArg->getBasicType() == EbtSamplerGeneric)
				  {
					  //type the sampler
					  sit->typeSampler( sampArg, EbtSamplerRect);
				  }
				  else if (sampArg->getBasicType() != EbtSamplerRect)
				  {
					  //We have a sampler mismatch error
					  infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n";
				  }
			  }
			  else
			  {
				  assert(0);
			  }
			  
		  }
		  // We need to continue the traverse here, because the calls could be nested 
		  break;
			  
			  
      case EOpTex3D:
      case EOpTex3DProj:
      case EOpTex3DLod:
      case EOpTex3DBias:
      case EOpTex3DGrad:
         {
            TIntermSequence &sequence = node->getSequence();
            assert( sequence.size());
            TIntermTyped *sampArg = sequence[0]->getAsTyped();
            if ( sampArg)
            {
               if (sampArg->getBasicType() == EbtSamplerGeneric)
               {
                  //type the sampler
                  sit->typeSampler( sampArg, EbtSampler3D);
               }
               else if (sampArg->getBasicType() != EbtSampler3D)
               {
                  //We have a sampler mismatch error
                  infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n";
               }
            }
            else
            {
               assert(0);
            }

         }
         // We need to continue the traverse here, because the calls could be nested 
         break;

      case EOpTexCube:
      case EOpTexCubeProj:
      case EOpTexCubeLod:
      case EOpTexCubeBias:
      case EOpTexCubeGrad:
         {
            TIntermSequence &sequence = node->getSequence();
            assert( sequence.size());
            TIntermTyped *sampArg = sequence[0]->getAsTyped();
            if ( sampArg)
            {
               if (sampArg->getBasicType() == EbtSamplerGeneric)
               {
                  //type the sampler
                  sit->typeSampler( sampArg, EbtSamplerCube);
               }
               else if (sampArg->getBasicType() != EbtSamplerCube)
               {
                  //We have a sampler mismatch error
                  infoSink.info << "Error: " << node->getLine() << ": Sampler type mismatch, likely using a generic sampler as two types\n";
               }
            }
            else
            {
               assert(0);
            }

         }
         // We need to continue the traverse here, because the calls could be nested 
         break;

      default: 
         break;
      }
   }


   return !(sit->abort);
}
bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
{
    bool visitChildren = true;
    TInfoSinkBase &out = objSink();
    switch (node->getOp())
    {
      case EOpInitialize:
        if (visit == InVisit)
        {
            out << " = ";
            // RHS of initialize is not being declared.
            mDeclaringVariables = false;
        }
        break;
      case EOpAssign:
        writeTriplet(visit, "(", " = ", ")");
        break;
      case EOpAddAssign:
        writeTriplet(visit, "(", " += ", ")");
        break;
      case EOpSubAssign:
        writeTriplet(visit, "(", " -= ", ")");
        break;
      case EOpDivAssign:
        writeTriplet(visit, "(", " /= ", ")");
        break;
      case EOpIModAssign:
        writeTriplet(visit, "(", " %= ", ")");
        break;
      // Notice the fall-through.
      case EOpMulAssign:
      case EOpVectorTimesMatrixAssign:
      case EOpVectorTimesScalarAssign:
      case EOpMatrixTimesScalarAssign:
      case EOpMatrixTimesMatrixAssign:
        writeTriplet(visit, "(", " *= ", ")");
        break;
      case EOpBitShiftLeftAssign:
        writeTriplet(visit, "(", " <<= ", ")");
        break;
      case EOpBitShiftRightAssign:
        writeTriplet(visit, "(", " >>= ", ")");
        break;
      case EOpBitwiseAndAssign:
        writeTriplet(visit, "(", " &= ", ")");
        break;
      case EOpBitwiseXorAssign:
        writeTriplet(visit, "(", " ^= ", ")");
        break;
      case EOpBitwiseOrAssign:
        writeTriplet(visit, "(", " |= ", ")");
        break;

      case EOpIndexDirect:
        writeTriplet(visit, NULL, "[", "]");
        break;
      case EOpIndexIndirect:
        if (node->getAddIndexClamp())
        {
            if (visit == InVisit)
            {
                if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
                    out << "[int(clamp(float(";
                else
                    out << "[webgl_int_clamp(";
            }
            else if (visit == PostVisit)
            {
                int maxSize;
                TIntermTyped *left = node->getLeft();
                TType leftType = left->getType();

                if (left->isArray())
                {
                    // The shader will fail validation if the array length is not > 0.
                    maxSize = leftType.getArraySize() - 1;
                }
                else
                {
                    maxSize = leftType.getNominalSize() - 1;
                }

                if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
                    out << "), 0.0, float(" << maxSize << ")))]";
                else
                    out << ", 0, " << maxSize << ")]";
            }
        }
        else
        {
            writeTriplet(visit, NULL, "[", "]");
        }
        break;
      case EOpIndexDirectStruct:
        if (visit == InVisit)
        {
            // Here we are writing out "foo.bar", where "foo" is struct
            // and "bar" is field. In AST, it is represented as a binary
            // node, where left child represents "foo" and right child "bar".
            // The node itself represents ".". The struct field "bar" is
            // actually stored as an index into TStructure::fields.
            out << ".";
            const TStructure *structure = node->getLeft()->getType().getStruct();
            const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
            const TField *field = structure->fields()[index->getIConst(0)];

            TString fieldName = field->name();
            if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
                fieldName = hashName(fieldName);

            out << fieldName;
            visitChildren = false;
        }
        break;
      case EOpIndexDirectInterfaceBlock:
          if (visit == InVisit)
          {
              out << ".";
              const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
              const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
              const TField *field = interfaceBlock->fields()[index->getIConst(0)];

              TString fieldName = field->name();
              ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
              fieldName = hashName(fieldName);

              out << fieldName;
              visitChildren = false;
          }
          break;
      case EOpVectorSwizzle:
        if (visit == InVisit)
        {
            out << ".";
            TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
            TIntermSequence *sequence = rightChild->getSequence();
            for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
            {
                TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
                ASSERT(element->getBasicType() == EbtInt);
                ASSERT(element->getNominalSize() == 1);
                const TConstantUnion& data = element->getUnionArrayPointer()[0];
                ASSERT(data.getType() == EbtInt);
                switch (data.getIConst())
                {
                  case 0:
                    out << "x";
                    break;
                  case 1:
                    out << "y";
                    break;
                  case 2:
                    out << "z";
                    break;
                  case 3:
                    out << "w";
                    break;
                  default:
                    UNREACHABLE();
                }
            }
            visitChildren = false;
        }
        break;

      case EOpAdd:
        writeTriplet(visit, "(", " + ", ")");
        break;
      case EOpSub:
        writeTriplet(visit, "(", " - ", ")");
        break;
      case EOpMul:
        writeTriplet(visit, "(", " * ", ")");
        break;
      case EOpDiv:
        writeTriplet(visit, "(", " / ", ")");
        break;
      case EOpIMod:
        writeTriplet(visit, "(", " % ", ")");
        break;
      case EOpBitShiftLeft:
        writeTriplet(visit, "(", " << ", ")");
        break;
      case EOpBitShiftRight:
        writeTriplet(visit, "(", " >> ", ")");
        break;
      case EOpBitwiseAnd:
        writeTriplet(visit, "(", " & ", ")");
        break;
      case EOpBitwiseXor:
        writeTriplet(visit, "(", " ^ ", ")");
        break;
      case EOpBitwiseOr:
        writeTriplet(visit, "(", " | ", ")");
        break;

      case EOpEqual:
        writeTriplet(visit, "(", " == ", ")");
        break;
      case EOpNotEqual:
        writeTriplet(visit, "(", " != ", ")");
        break;
      case EOpLessThan:
        writeTriplet(visit, "(", " < ", ")");
        break;
      case EOpGreaterThan:
        writeTriplet(visit, "(", " > ", ")");
        break;
      case EOpLessThanEqual:
        writeTriplet(visit, "(", " <= ", ")");
        break;
      case EOpGreaterThanEqual:
        writeTriplet(visit, "(", " >= ", ")");
        break;

      // Notice the fall-through.
      case EOpVectorTimesScalar:
      case EOpVectorTimesMatrix:
      case EOpMatrixTimesVector:
      case EOpMatrixTimesScalar:
      case EOpMatrixTimesMatrix:
        writeTriplet(visit, "(", " * ", ")");
        break;

      case EOpLogicalOr:
        writeTriplet(visit, "(", " || ", ")");
        break;
      case EOpLogicalXor:
        writeTriplet(visit, "(", " ^^ ", ")");
        break;
      case EOpLogicalAnd:
        writeTriplet(visit, "(", " && ", ")");
        break;
      default:
        UNREACHABLE();
    }

    return visitChildren;
}
void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
{
    bool visit = true;

    TIntermSequence *sequence = node->getSequence();
    if (node->getOp() == EOpPrototype)
    {
        addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), sequence);
    }

    if (preVisit)
        visit = visitAggregate(PreVisit, node);

    if (visit)
    {
        bool inFunctionMap = false;
        if (node->getOp() == EOpFunctionCall)
        {
            inFunctionMap = isInFunctionMap(node);
            if (!inFunctionMap)
            {
                // The function is not user-defined - it is likely built-in texture function.
                // Assume that those do not have out parameters.
                setInFunctionCallOutParameter(false);
            }
        }

        incrementDepth(node);

        if (inFunctionMap)
        {
            TIntermSequence *params             = getFunctionParameters(node);
            TIntermSequence::iterator paramIter = params->begin();
            for (auto *child : *sequence)
            {
                ASSERT(paramIter != params->end());
                TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
                setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);

                child->traverse(this);
                if (visit && inVisit)
                {
                    if (child != sequence->back())
                        visit = visitAggregate(InVisit, node);
                }

                ++paramIter;
            }

            setInFunctionCallOutParameter(false);
        }
        else
        {
            // Find the built-in function corresponding to this op so that we can determine the
            // in/out qualifiers of its parameters.
            TFunction *builtInFunc = nullptr;
            TString opString = GetOperatorString(node->getOp());
            if (!node->isConstructor() && !opString.empty())
            {
                // The return type doesn't affect the mangled name of the function, which is used
                // to look it up from the symbol table.
                TType dummyReturnType;
                TFunction call(&opString, &dummyReturnType, node->getOp());
                for (auto *child : *sequence)
                {
                    TType *paramType = child->getAsTyped()->getTypePointer();
                    TConstParameter p(paramType);
                    call.addParameter(p);
                }

                TSymbol *sym = mSymbolTable.findBuiltIn(call.getMangledName(), mShaderVersion);
                if (sym != nullptr && sym->isFunction())
                {
                    builtInFunc = static_cast<TFunction *>(sym);
                    ASSERT(builtInFunc->getParamCount() == sequence->size());
                }
            }

            size_t paramIndex = 0;

            for (auto *child : *sequence)
            {
                TQualifier qualifier = EvqIn;
                if (builtInFunc != nullptr)
                    qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
                setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
                child->traverse(this);

                if (visit && inVisit)
                {
                    if (child != sequence->back())
                        visit = visitAggregate(InVisit, node);
                }

                ++paramIndex;
            }

            setInFunctionCallOutParameter(false);
        }

        decrementDepth();
    }

    if (visit && postVisit)
        visitAggregate(PostVisit, node);
}
Beispiel #11
0
void Parser::parseExpr(TIntermSequence& e) {
    for (auto it = e.begin(); it != e.end(); ++it) {
        auto aggregate = (*it)->getAsAggregate();
        auto binop = (*it)->getAsBinaryNode();
        if (aggregate != nullptr) {
            switch (aggregate->getOp()) {
            case EOpFunctionCall: {
                ParsedExpr expr;
                expr.v = nullptr;
                ParsedValue value;
                value.v = nullptr;
                value.p = aggregate->getLine().first_line;
                std::vector<TIntermTyped*> args;
                for (auto it2 = aggregate->getSequence().begin(); it2 != aggregate->getSequence().end(); ++it2) {
                    args.push_back((*it2)->getAsTyped());
                }
                expr.e = new ParsedValue(makeCall(aggregate->getName().c_str(), args, aggregate->getLine().first_line));
                expr.p = aggregate->getLine().first_line;
                cur.exprs.push_back(expr);
                break;
            }
            case EOpDeclaration: {
                PLocal* local = new PLocal;
                auto var = dynamic_cast<TIntermBinary*>(aggregate->getSequence()[0]);
                if (var->getOp() != EOpInitialize) error("Expected initialization.", var->getLine().first_line);
                local->v = allocVar(var->getLeft()->getAsSymbolNode()->getSymbol().c_str(), var->getLeft()->getTypePointer(), VTmp, var->getLine().first_line);

                ParsedExpr expr;
                ParsedValue* value = new ParsedValue;
                value->v = local;
                value->p = var->getLine().first_line;
                expr.v = value;
                expr.e = new ParsedValue(parseValue(var->getRight()));
                expr.p = var->getLine().first_line;
                cur.exprs.push_back(expr);
                break;
            }
            default:
                break;
            }
        }
        else if (binop != nullptr) {
            switch (binop->getOp()) {
            case EOpAssign:
                addAssign(parseValue(binop->getLeft()), parseValue(binop->getRight()), binop->getLine().first_line);
                break;
            case EOpAddAssign:

                break;
            case EOpSubAssign:

                break;
            case EOpMulAssign:

                break;
            case EOpVectorTimesScalarAssign:

                break;
            case EOpMatrixTimesScalarAssign:

                break;
            case EOpVectorTimesMatrixAssign:

                break;
            case EOpMatrixTimesMatrixAssign:
                //case OpAssignOp(op):
                //	addAssign(parseValue(e1), parseValue( { expr : EBinop(op, e1, e2), pos : e.pos } ), e.pos);
                break;
            default:
                error("Operation should have side-effects", binop->getLine().first_line);
            }
        }

        /*switch (e.expr) {
        case EBlock(el):
        auto eold = cur.exprs;
        auto old = allowReturn;
        auto last = el[el.length - 1];
        cur.exprs = [];
        for (e in el) {
        allowReturn = old && (e == last);
        parseExpr(e);
        }
        allowReturn = old;
        eold.push({ v : null, e : { v : PBlock(cur.exprs), p : e.pos }, p : e.pos });
        cur.exprs = eold;
        case EIf(cond, eif, eelse):
        var pcond = parseValue(cond);

        var eold = cur.exprs;
        cur.exprs = [];
        parseExpr(eif);
        var pif = { v : PBlock(cur.exprs), p : eif.pos };

        var pelse = null;
        if( eelse != null ) {
        cur.exprs = [];
        parseExpr(eelse);
        pelse = { v : PBlock(cur.exprs), p : eelse.pos };
        }
        cur.exprs = eold;
        cur.exprs.push( {v:null, e: { v:PIf(pcond, pif, pelse), p : e.pos }, p : e.pos} );
        case EFor(it, expr):
        var iter = null, vname = null;
        switch( it.expr ) {
        case EIn(v,it):
        switch( v.expr ) {
        case EConst(c):
        	switch( c ) {
        	case CIdent(i) #if !haxe3 , CType(i) #end: vname = i;
        	default:
        	}
        default:
        }
        iter = parseValue(it);
        default:
        }
        if( vname == null )
        error("For should be in the form for( x in it )", it.pos);

        var old = cur.exprs;
        cur.exprs = [];
        parseExpr(expr);
        var pexpr = { v : PBlock(cur.exprs), p : expr.pos };
        cur.exprs = old;
        cur.exprs.push( {v : null, e:{v:PFor(vname, iter, pexpr), p:e.pos}, p:e.pos } );
        case EReturn(r):
        if( r == null ) error("Return must return a value", e.pos);
        if( !allowReturn ) error("Return only allowed as final expression in helper methods", e.pos);
        var v = parseValue(r);
        cur.exprs.push( { v : null, e : { v : PReturn(v), p : e.pos }, p : e.pos } );
        default:
        error("Unsupported expression", e.pos);
        }*/
    }
}