// File: /workspace/github_cpp_makefile_star2_O1/marxn[P]pupp/src/parser/expression.cpp
// Function: FunctionExpression::Calculate(NodeContext*)
ConstValue * FunctionExpression::Calculate(NodeContext * context)
{
        ConstValue * result = NULL;
        FuncValue * func = static_cast<FuncValue*>(this->FuncObj->Calculate(context));

        if(func==NULL)
        {
                cerr<<"pupp runtime error: Not a qualified function."<<endl;
                return NULL;
        }

        if(func->GetType()==Null)
        {
                cerr<<"pupp runtime error: Function object has not been initialized."<<endl;
                return NULL;
        }

        FunctionNode * funcnode = func->GetFuncNode();

        if(funcnode)
        {
                if(funcnode->GetArgList()->size()!=this->ExprList->size())
                {
                        cerr<<"pupp runtime error: The number of arguments does not match"<<endl;
                        return NULL;
                }

                list<Expression*>::iterator i;
                list<FuncArgDef*>::iterator j;

                for(i = this->ExprList->begin(), j = funcnode->GetArgList()->begin();
                        i!=this->ExprList->end() && j!=funcnode->GetArgList()->end(); i++,j++)
                {
                        if((*j)->isRef())
                        {
                                if((*i)->isLValue()==false)
                                {
                                        cerr<<"pupp runtime error: Cannot pass any expression other than an lvalue to a reference:"<<(*j)->GetName()<<endl;
                                        return NULL;
                                }
                        }
                }

                int rtn = 0;

                NodeContext * new_ctx = new NodeContext;
                new_ctx->AddFrame(funcnode);

                for(i = this->ExprList->begin(), j = funcnode->GetArgList()->begin(); 
                        i!=this->ExprList->end() && j!=funcnode->GetArgList()->end(); i++,j++)
                {
                        if((*j)->isRef())
                        {
                                VarExpression * exp = static_cast<VarExpression*>(*i);
                                ValueBox * vbox = exp->GetVarRef(context);
                                unsigned long index = (*j)->GetArgIndex();
                                Variable * avatar = new_ctx->GetVariable(0, index);

                                if(avatar)
                                {
                                        if(vbox->GetVal()->GetType() != avatar->GetVarType())
                                        {
                                                cerr<<"pupp runtime error: variable type mismatch when passing args to the function."<<endl;
                                                return NULL;
                                        }

                                        delete avatar->GetVBox();
                                        avatar->SetVBox(vbox);
                                        avatar->GetVBox()->IncRefCount();
                                }
                        }
                        else
                        {
                                ConstValue * value = (*i)->Calculate(context);
                                if(value->GetType()!=(*j)->GetType())
                                {
                                        delete new_ctx;
                                        cerr<<"pupp runtime error: data type mismatch when calling a function."<<endl;
                                        return NULL;
                                }

                                Variable * localvar = new_ctx->GetVariable(0, (*j)->GetArgIndex());
                                if(localvar)
                                {
                                        localvar->SetValue(value);
                                }

                                delete value;
                        }
                }

                list<Variable*> * closurevars = func->GetClosureVars();

                if(closurevars!=NULL)
                {
                        //Put closure variables into the new context.
                        new_ctx->ReplaceVariable(funcnode->GetClosureVarStartIndex(), closurevars);
                }
                
                if(this->ThreadNum==-1)
                {
                        //Donot need to launch a new thread. Let's rock!
                        rtn = funcnode->Run(new_ctx);

                        //Check the result of the function.
                        if(rtn==NODE_RET_NEEDRETURN)
                        {
                                if(funcnode->GetRtnType()==Null)
                                {
                                        delete new_ctx;
                                        cerr<<"pupp runtime error: function does not have a return value."<<endl;
                                        return NULL;
                                }
                                
                                result = new_ctx->FunctionRet;
                                if(funcnode->GetRtnType()!=result->GetType())
                                {
                                        ConstValue * ret = ConstValueCast(result, funcnode->GetRtnType());
                                        delete result;
                                        result = ret;
                                }
                        }
                        else
                        {
                                result = new NullValue;
                        }

                        delete new_ctx;
                }
                else if(this->ThreadNum==0)
                {
                        AsynFuncCallContext * asyncallctx = new AsynFuncCallContext(funcnode, new_ctx);        
                        if(asyncallctx)
                        {
                            asyncallctx->AsynCall();
                        }
                               
                        result = new NullValue;
                }
                else
                {
                        pthread_mutex_lock(&this->AccessLock);
                        
                        if(this->ThreadCount < this->ThreadNum)
                        {
                                AsynFuncCallContext * asyncallctx = new AsynFuncCallContext(funcnode, new_ctx);
                                
                                if(asyncallctx)
                                {
                                    this->ThreadCount++;
                                    asyncallctx->AsynCall();
                                }
                        }
                        
                        pthread_mutex_unlock(&this->AccessLock);
                               
                        result = new NullValue;
                }
        }
        else
        {
                cerr<<"pupp runtime error: cannot call a null function"<<endl;
                return NULL;
        }
        
        delete func;
        return result;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %rsi, %rbp
movq %rdi, %r12
movq 0x50(%rdi), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
testq %rax, %rax
je 0xb0b9
movq %rax, %r15
movq %rax, %rdi
callq 0x7dee
testl %eax, %eax
je 0xb0ce
movq %r15, %rdi
callq 0x18ecc
testq %rax, %rax
je 0xb0e3
movq %rax, %r13
movq %rax, %rdi
callq 0xbe26
movq 0x10(%rax), %rcx
movq 0x60(%r12), %rax
cmpq 0x10(%rax), %rcx
jne 0xb0f8
movq (%rax), %r14
movq %r13, %rdi
callq 0xbe26
cmpq 0x60(%r12), %r14
je 0xae17
movq %rax, %rbx
movq (%rbx), %rbx
movq %r13, %rdi
callq 0xbe26
cmpq %rax, %rbx
je 0xae17
movq 0x10(%rbx), %rdi
callq 0xbca0
testb %al, %al
je 0xae0d
movq 0x10(%r14), %rax
cmpb $0x0, 0x8(%rax)
je 0xb1e2
movq (%r14), %r14
cmpq 0x60(%r12), %r14
jne 0xade2
movq %rbp, 0x20(%rsp)
movq %r15, 0x10(%rsp)
movl $0x70, %edi
callq 0x6260
movq %rax, %r14
movq %rax, %rdi
callq 0xc638
movq %r14, 0x8(%rsp)
movq %r14, %rdi
movq %r13, %rsi
callq 0xc748
movq 0x60(%r12), %rax
movq (%rax), %r14
movq %r13, %rdi
callq 0xbe26
cmpq 0x60(%r12), %r14
je 0xb008
movq %rax, %rbp
movq %r13, 0x18(%rsp)
movq (%rbp), %rbp
movq %r13, %rdi
callq 0xbe26
cmpq %rax, %rbp
je 0xb008
movq 0x10(%rbp), %rdi
callq 0xbca0
movq 0x10(%r14), %rdi
testb %al, %al
je 0xaf32
movq 0x20(%rsp), %rsi
callq 0xa4e2
movq %rax, %rbx
movq 0x10(%rbp), %rdi
callq 0xbcd8
movq 0x8(%rsp), %rdi
xorl %esi, %esi
movq %rax, %rdx
callq 0xc886
testq %rax, %rax
je 0xaffa
movq %rax, %r15
movq %rbx, %rdi
callq 0x7ec4
movq %rax, %rdi
callq 0x7dee
movl %eax, %r13d
movq %r15, %rdi
callq 0x18a6c
cmpl %eax, %r13d
jne 0xb299
movq %r15, %rdi
callq 0x18906
testq %rax, %rax
je 0xaf0d
movq %rax, %r13
movq %rax, %rdi
callq 0x7e28
movl $0x10, %esi
movq %r13, %rdi
callq 0x6270
movq %r15, %rdi
movq %rbx, %rsi
callq 0x18900
movq %r15, %rdi
callq 0x18906
movq %rax, %rdi
callq 0x7e60
movq 0x18(%rsp), %r13
jmp 0xaffa
movq (%rdi), %rax
movq 0x20(%rsp), %rsi
callq *0x10(%rax)
movq %rax, %r13
movq %rax, %rdi
callq 0x7dee
movl %eax, %r15d
movq 0x10(%rbp), %rdi
callq 0xbcc6
movl %eax, %ebx
cmpl %eax, %r15d
jne 0xaf8f
movq 0x10(%rbp), %rdi
callq 0xbcd8
movq 0x8(%rsp), %rdi
xorl %esi, %esi
movq %rax, %rdx
callq 0xc886
testq %rax, %rax
je 0xaf83
movq %rax, %rdi
movq %r13, %rsi
callq 0x18960
movq (%r13), %rax
movq %r13, %rdi
callq *0x8(%rax)
jmp 0xafec
movq 0x8(%rsp), %r13
movq %r13, %rdi
callq 0xc69a
movl $0x70, %esi
movq %r13, %rdi
callq 0x6270
movl $0x3f, %edx
movq 0x3d03b(%rip), %r13     # 0x47ff0
movq %r13, %rdi
leaq 0x2b3b3(%rip), %rsi     # 0x36372
callq 0x62f0
movq (%r13), %rax
movq -0x18(%rax), %rdi
addq %r13, %rdi
movl $0xa, %esi
callq 0x6220
movsbl %al, %esi
movq %r13, %rdi
callq 0x6040
movq %rax, %rdi
callq 0x61b0
cmpl %ebx, %r15d
movq 0x18(%rsp), %r13
jne 0xb2bc
movq (%r14), %r14
cmpq 0x60(%r12), %r14
jne 0xae69
movq 0x10(%rsp), %r15
movq %r15, %rdi
callq 0x18ed2
testq %rax, %rax
movq 0x8(%rsp), %rbp
je 0xb038
movq %rax, %rbx
movq %r13, %rdi
callq 0xc2b4
movq %rbp, %rdi
movq %rax, %rsi
movq %rbx, %rdx
callq 0xc838
movq 0x18(%r12), %rax
testq %rax, %rax
je 0xb14f
cmpq $-0x1, %rax
jne 0xb184
movq %r13, %rdi
movq %rbp, %rsi
callq 0xbe10
cmpl $0x3, %eax
jne 0xb26b
movq %r13, %rdi
callq 0xbe6c
testl %eax, %eax
je 0xb2c8
movq 0x50(%rbp), %r12
movq %r13, %rdi
callq 0xbe6c
movl %eax, %ebx
movq %r12, %rdi
callq 0x7dee
cmpl %eax, %ebx
je 0xb280
movq %r13, %rdi
callq 0xbe6c
movq %r12, %rdi
movl %eax, %esi
callq 0x957b
movq %rax, %rbx
movq (%r12), %rax
movq %r12, %rdi
callq *0x8(%rax)
movq %rbx, %r12
jmp 0xb280
movq 0x3cf30(%rip), %rbx     # 0x47ff0
leaq 0x2b162(%rip), %rsi     # 0x36229
movl $0x2d, %edx
jmp 0xb10b
movq 0x3cf1b(%rip), %rbx     # 0x47ff0
leaq 0x2b17b(%rip), %rsi     # 0x36257
movl $0x3d, %edx
jmp 0xb10b
movq 0x3cf06(%rip), %rbx     # 0x47ff0
leaq 0x2b2fc(%rip), %rsi     # 0x363ed
movl $0x2f, %edx
jmp 0xb10b
movq 0x3cef1(%rip), %rbx     # 0x47ff0
leaq 0x2b18f(%rip), %rsi     # 0x36295
movl $0x3a, %edx
movq %rbx, %rdi
callq 0x62f0
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x6220
movsbl %al, %esi
movq %rbx, %rdi
callq 0x6040
movq %rax, %rdi
callq 0x61b0
xorl %r12d, %r12d
movq %r12, %rax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x10, %edi
callq 0x6260
movq %r13, (%rax)
movq %rbp, 0x8(%rax)
movq %rax, %rdi
callq 0xba0e
movl $0x10, %edi
callq 0x6260
movq %rax, %r12
movb $0x1, %bl
movq %rax, %rdi
callq 0x7f20
jmp 0xb305
leaq 0x28(%r12), %rbx
movq %rbx, %rdi
callq 0x63e0
movq 0x20(%r12), %r14
cmpq 0x18(%r12), %r14
jge 0xb1be
movl $0x10, %edi
callq 0x6260
movq %r13, (%rax)
movq %rbp, 0x8(%rax)
incq %r14
movq %r14, 0x20(%r12)
movq %rax, %rdi
callq 0xba0e
movq %rbx, %rdi
callq 0x61e0
movl $0x10, %edi
callq 0x6260
movq %rax, %r12
movb $0x1, %bl
movq %rax, %rdi
callq 0x7f20
jmp 0xb305
movq 0x3ce07(%rip), %r14     # 0x47ff0
leaq 0x2b0e0(%rip), %rsi     # 0x362d0
movl $0x53, %edx
movq %r14, %rdi
callq 0x62f0
movq 0x10(%rbx), %rsi
leaq 0x28(%rsp), %rbx
movq %rbx, %rdi
callq 0xbca4
movq (%rbx), %rsi
movq 0x8(%rbx), %rdx
movq %r14, %rdi
callq 0x62f0
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x6220
movsbl %al, %esi
movq %rbx, %rdi
callq 0x6040
movq %rax, %rdi
callq 0x61b0
leaq 0x38(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0xb300
movq 0x38(%rsp), %rsi
incq %rsi
callq 0x6270
jmp 0xb300
movl $0x10, %edi
callq 0x6260
movq %rax, %r12
movq %rax, %rdi
callq 0x7f20
movq %rbp, %rdi
callq 0xc69a
movl $0x70, %esi
movq %rbp, %rdi
callq 0x6270
movb $0x1, %bl
jmp 0xb305
movq 0x3cd50(%rip), %rbx     # 0x47ff0
leaq 0x2b07d(%rip), %rsi     # 0x36324
movl $0x4d, %edx
movq %rbx, %rdi
callq 0x62f0
movq %rbx, %rdi
callq 0x6140
xorl %ebx, %ebx
xorl %r12d, %r12d
movq 0x10(%rsp), %r15
jmp 0xb305
movq %rbp, %rdi
callq 0xc69a
movl $0x70, %esi
movq %rbp, %rdi
callq 0x6270
movq 0x3cd0c(%rip), %rbx     # 0x47ff0
leaq 0x2b0c7(%rip), %rsi     # 0x363b2
movl $0x3a, %edx
movq %rbx, %rdi
callq 0x62f0
movq %rbx, %rdi
callq 0x6140
xorl %ebx, %ebx
xorl %r12d, %r12d
testb %bl, %bl
je 0xb13a
movq (%r15), %rax
movq %r15, %rdi
callq *0x8(%rax)
jmp 0xb13d
jmp 0xb31f
jmp 0xb31f
movq %rax, %rbx
movl $0x10, %esi
movq %r12, %rdi
jmp 0xb352
movq %rax, %rbx
leaq 0x38(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0xb357
movq 0x38(%rsp), %rsi
incq %rsi
jmp 0xb352
movq %rax, %rbx
movl $0x70, %esi
movq %r14, %rdi
callq 0x6270
movq %rbx, %rdi
callq 0x6470
nop