// File: 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:
subq $0x1f8, %rsp            # imm = 0x1F8
movq %rdi, 0x1e8(%rsp)
movq %rsi, 0x1e0(%rsp)
movq 0x1e8(%rsp), %rax
movq %rax, 0xc0(%rsp)
movq $0x0, 0x1d8(%rsp)
movq 0x50(%rax), %rdi
movq 0x1e0(%rsp), %rsi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, 0x1d0(%rsp)
cmpq $0x0, 0x1d0(%rsp)
jne 0xf41b
movq 0x66c01(%rip), %rdi     # 0x75ff0
leaq 0x4fe1a(%rip), %rsi     # 0x5f210
callq 0x62d0
movq %rax, %rdi
movq 0x66bb3(%rip), %rsi     # 0x75fb8
callq 0x6320
movq $0x0, 0x1f0(%rsp)
jmp 0xffca
movq 0x1d0(%rsp), %rdi
callq 0x7870
cmpl $0x0, %eax
jne 0xf460
movq 0x66bbc(%rip), %rdi     # 0x75ff0
leaq 0x4fe03(%rip), %rsi     # 0x5f23e
callq 0x62d0
movq %rax, %rdi
movq 0x66b6e(%rip), %rsi     # 0x75fb8
callq 0x6320
movq $0x0, 0x1f0(%rsp)
jmp 0xffca
movq 0x1d0(%rsp), %rdi
callq 0x31410
movq %rax, 0x1c8(%rsp)
cmpq $0x0, 0x1c8(%rsp)
je 0xff6e
movq 0x1c8(%rsp), %rdi
callq 0x13830
movq %rax, %rdi
callq 0x11670
movq %rax, %rcx
movq 0xc0(%rsp), %rax
movq %rcx, 0xb8(%rsp)
movq 0x60(%rax), %rdi
callq 0x115a0
movq %rax, %rcx
movq 0xb8(%rsp), %rax
cmpq %rcx, %rax
je 0xf4f8
movq 0x66b24(%rip), %rdi     # 0x75ff0
leaq 0x4fda9(%rip), %rsi     # 0x5f27c
callq 0x62d0
movq %rax, %rdi
movq 0x66ad6(%rip), %rsi     # 0x75fb8
callq 0x6320
movq $0x0, 0x1f0(%rsp)
jmp 0xffca
leaq 0x1c0(%rsp), %rdi
callq 0x11270
leaq 0x1b8(%rsp), %rdi
callq 0x116a0
movq 0xc0(%rsp), %rax
movq 0x60(%rax), %rdi
callq 0x11290
movq %rax, 0x1b0(%rsp)
movq 0x1b0(%rsp), %rax
movq %rax, 0x1c0(%rsp)
movq 0x1c8(%rsp), %rdi
callq 0x13830
movq %rax, %rdi
callq 0x116c0
movq %rax, 0x1a8(%rsp)
movq 0x1a8(%rsp), %rax
movq %rax, 0x1b8(%rsp)
movq 0xc0(%rsp), %rax
movq 0x60(%rax), %rdi
callq 0x112e0
movq %rax, 0x1a0(%rsp)
leaq 0x1c0(%rsp), %rdi
leaq 0x1a0(%rsp), %rsi
callq 0x112c0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, 0xb7(%rsp)
jne 0xf5a8
jmp 0xf5e1
movq 0x1c8(%rsp), %rdi
callq 0x13830
movq %rax, %rdi
callq 0x11710
movq %rax, 0x198(%rsp)
leaq 0x1b8(%rsp), %rdi
leaq 0x198(%rsp), %rsi
callq 0x116f0
movb %al, 0xb7(%rsp)
movb 0xb7(%rsp), %al
testb $0x1, %al
jne 0xf5f1
jmp 0xf722
leaq 0x1b8(%rsp), %rdi
callq 0x11740
movq (%rax), %rdi
callq 0x134f0
testb $0x1, %al
jne 0xf60f
jmp 0xf6ed
leaq 0x1c0(%rsp), %rdi
callq 0x11310
movq (%rax), %rdi
callq 0xda50
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0xf6eb
movq 0x669b7(%rip), %rdi     # 0x75ff0
leaq 0x4fc77(%rip), %rsi     # 0x5f2b7
callq 0x62d0
movq %rax, 0x98(%rsp)
leaq 0x1b8(%rsp), %rdi
callq 0x11740
movq (%rax), %rsi
leaq 0x178(%rsp), %rdi
movq %rdi, 0xa0(%rsp)
callq 0x13500
movq 0x98(%rsp), %rdi
movq 0xa0(%rsp), %rsi
callq 0x62a0
movq %rax, 0xa8(%rsp)
jmp 0xf691
movq 0xa8(%rsp), %rdi
movq 0x66918(%rip), %rsi     # 0x75fb8
callq 0x6320
jmp 0xf6a7
leaq 0x178(%rsp), %rdi
callq 0x61e0
movq $0x0, 0x1f0(%rsp)
jmp 0xffca
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x170(%rsp)
movl %eax, 0x16c(%rsp)
leaq 0x178(%rsp), %rdi
callq 0x61e0
jmp 0xffda
jmp 0xf6ed
jmp 0xf6ef
leaq 0x1c0(%rsp), %rdi
xorl %esi, %esi
callq 0x11380
movq %rax, 0x160(%rsp)
leaq 0x1b8(%rsp), %rdi
xorl %esi, %esi
callq 0x11770
movq %rax, 0x158(%rsp)
jmp 0xf568
movl $0x0, 0x154(%rsp)
movl $0x70, %edi
callq 0x62f0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x90(%rsp)
callq 0x14530
jmp 0xf74c
movq 0x90(%rsp), %rax
movq %rax, 0x148(%rsp)
movq 0x148(%rsp), %rdi
movq 0x1c8(%rsp), %rsi
callq 0x146f0
movq 0xc0(%rsp), %rax
movq 0x60(%rax), %rdi
callq 0x11290
movq %rax, 0x140(%rsp)
movq 0x140(%rsp), %rax
movq %rax, 0x1c0(%rsp)
movq 0x1c8(%rsp), %rdi
callq 0x13830
movq %rax, %rdi
callq 0x116c0
movq %rax, 0x138(%rsp)
movq 0x138(%rsp), %rax
movq %rax, 0x1b8(%rsp)
movq 0xc0(%rsp), %rax
movq 0x60(%rax), %rdi
callq 0x112e0
movq %rax, 0x130(%rsp)
leaq 0x1c0(%rsp), %rdi
leaq 0x130(%rsp), %rsi
callq 0x112c0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, 0x8f(%rsp)
jne 0xf807
jmp 0xf840
movq 0x1c8(%rsp), %rdi
callq 0x13830
movq %rax, %rdi
callq 0x11710
movq %rax, 0x128(%rsp)
leaq 0x1b8(%rsp), %rdi
leaq 0x128(%rsp), %rsi
callq 0x116f0
movb %al, 0x8f(%rsp)
movb 0x8f(%rsp), %al
testb $0x1, %al
jne 0xf850
jmp 0xfb52
leaq 0x1b8(%rsp), %rdi
callq 0x11740
movq (%rax), %rdi
callq 0x134f0
testb $0x1, %al
jne 0xf86e
jmp 0xf9ed
leaq 0x1c0(%rsp), %rdi
callq 0x11310
movq (%rax), %rax
movq %rax, 0x120(%rsp)
movq 0x120(%rsp), %rdi
movq 0x1e0(%rsp), %rsi
callq 0xe520
movq %rax, 0x118(%rsp)
leaq 0x1b8(%rsp), %rdi
callq 0x11740
movq (%rax), %rdi
callq 0x13590
movq %rax, 0x110(%rsp)
movq 0x148(%rsp), %rdi
movq 0x110(%rsp), %rdx
xorl %eax, %eax
movl %eax, %esi
callq 0x14950
movq %rax, 0x108(%rsp)
cmpq $0x0, 0x108(%rsp)
je 0xf9e8
movq 0x118(%rsp), %rdi
callq 0x7a20
movq %rax, %rdi
callq 0x7870
movl %eax, 0x88(%rsp)
movq 0x108(%rsp), %rdi
callq 0x30cb0
movl %eax, %ecx
movl 0x88(%rsp), %eax
cmpl %ecx, %eax
je 0xf984
movq 0x666c3(%rip), %rdi     # 0x75ff0
leaq 0x4f9d7(%rip), %rsi     # 0x5f30b
callq 0x62d0
movq %rax, %rdi
movq 0x66675(%rip), %rsi     # 0x75fb8
callq 0x6320
movq $0x0, 0x1f0(%rsp)
jmp 0xffca
movq 0x90(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x170(%rsp)
movl %eax, 0x16c(%rsp)
movl $0x70, %esi
callq 0x6300
jmp 0xffda
movq 0x108(%rsp), %rdi
callq 0x30a30
movq %rax, 0x80(%rsp)
cmpq $0x0, %rax
je 0xf9be
movq 0x80(%rsp), %rdi
callq 0x78f0
movq 0x80(%rsp), %rdi
movl $0x10, %esi
callq 0x6300
movq 0x108(%rsp), %rdi
movq 0x118(%rsp), %rsi
callq 0x30a10
movq 0x108(%rsp), %rdi
callq 0x30a30
movq %rax, %rdi
callq 0x7950
jmp 0xfb1d
leaq 0x1c0(%rsp), %rdi
callq 0x11310
movq (%rax), %rdi
movq 0x1e0(%rsp), %rsi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, 0x100(%rsp)
movq 0x100(%rsp), %rdi
callq 0x7870
movl %eax, 0x7c(%rsp)
leaq 0x1b8(%rsp), %rdi
callq 0x11740
movq (%rax), %rdi
callq 0x13530
movl %eax, %ecx
movl 0x7c(%rsp), %eax
cmpl %ecx, %eax
je 0xfaa2
movq 0x148(%rsp), %rax
movq %rax, 0x70(%rsp)
cmpq $0x0, %rax
je 0xfa6f
movq 0x70(%rsp), %rdi
callq 0x145b0
movq 0x70(%rsp), %rdi
movl $0x70, %esi
callq 0x6300
movq 0x6657a(%rip), %rdi     # 0x75ff0
leaq 0x4f8dc(%rip), %rsi     # 0x5f359
callq 0x62d0
movq %rax, %rdi
movq 0x6652c(%rip), %rsi     # 0x75fb8
callq 0x6320
movq $0x0, 0x1f0(%rsp)
jmp 0xffca
movq 0x148(%rsp), %rax
movq %rax, 0x68(%rsp)
leaq 0x1b8(%rsp), %rdi
callq 0x11740
movq (%rax), %rdi
callq 0x13590
movq 0x68(%rsp), %rdi
movq %rax, %rdx
xorl %eax, %eax
movl %eax, %esi
callq 0x14950
movq %rax, 0xf8(%rsp)
cmpq $0x0, 0xf8(%rsp)
je 0xfafd
movq 0xf8(%rsp), %rdi
movq 0x100(%rsp), %rsi
callq 0x30ad0
movq 0x100(%rsp), %rax
movq %rax, 0x60(%rsp)
cmpq $0x0, %rax
je 0xfb1b
movq 0x60(%rsp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
jmp 0xfb1d
jmp 0xfb1f
leaq 0x1c0(%rsp), %rdi
xorl %esi, %esi
callq 0x11380
movq %rax, 0xf0(%rsp)
leaq 0x1b8(%rsp), %rdi
xorl %esi, %esi
callq 0x11770
movq %rax, 0xe8(%rsp)
jmp 0xf7c7
movq 0x1d0(%rsp), %rdi
callq 0x31420
movq %rax, 0xe0(%rsp)
cmpq $0x0, 0xe0(%rsp)
je 0xfba1
movq 0x148(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x1c8(%rsp), %rdi
callq 0x13f90
movq 0x58(%rsp), %rdi
movq %rax, %rsi
movq 0xe0(%rsp), %rdx
callq 0x14860
movq 0xc0(%rsp), %rax
cmpq $-0x1, 0x18(%rax)
jne 0xfd6d
movq 0x1c8(%rsp), %rdi
movq 0x148(%rsp), %rsi
callq 0x137c0
movl %eax, 0x154(%rsp)
cmpl $0x3, 0x154(%rsp)
jne 0xfce9
movq 0x1c8(%rsp), %rdi
callq 0x138f0
cmpl $0x0, %eax
jne 0xfc4f
movq 0x148(%rsp), %rax
movq %rax, 0x50(%rsp)
cmpq $0x0, %rax
je 0xfc1c
movq 0x50(%rsp), %rdi
callq 0x145b0
movq 0x50(%rsp), %rdi
movl $0x70, %esi
callq 0x6300
movq 0x663cd(%rip), %rdi     # 0x75ff0
leaq 0x4f76f(%rip), %rsi     # 0x5f399
callq 0x62d0
movq %rax, %rdi
movq 0x6637f(%rip), %rsi     # 0x75fb8
callq 0x6320
movq $0x0, 0x1f0(%rsp)
jmp 0xffca
movq 0x148(%rsp), %rax
movq 0x50(%rax), %rax
movq %rax, 0x1d8(%rsp)
movq 0x1c8(%rsp), %rdi
callq 0x138f0
movl %eax, 0x4c(%rsp)
movq 0x1d8(%rsp), %rdi
callq 0x7870
movl %eax, %ecx
movl 0x4c(%rsp), %eax
cmpl %ecx, %eax
je 0xfce7
movq 0x1d8(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0x1c8(%rsp), %rdi
callq 0x138f0
movq 0x38(%rsp), %rdi
movl %eax, %esi
callq 0xa620
movq %rax, 0xd8(%rsp)
movq 0x1d8(%rsp), %rax
movq %rax, 0x40(%rsp)
cmpq $0x0, %rax
je 0xfcd7
movq 0x40(%rsp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
movq 0xd8(%rsp), %rax
movq %rax, 0x1d8(%rsp)
jmp 0xfd3c
movl $0x10, %edi
callq 0x62f0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x30(%rsp)
callq 0x7aa0
jmp 0xfd05
movq 0x30(%rsp), %rax
movq %rax, 0x1d8(%rsp)
jmp 0xfd3c
movq 0x30(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x170(%rsp)
movl %eax, 0x16c(%rsp)
movl $0x10, %esi
callq 0x6300
jmp 0xffda
movq 0x148(%rsp), %rax
movq %rax, 0x28(%rsp)
cmpq $0x0, %rax
je 0xfd68
movq 0x28(%rsp), %rdi
callq 0x145b0
movq 0x28(%rsp), %rdi
movl $0x70, %esi
callq 0x6300
jmp 0xff6c
movq 0xc0(%rsp), %rax
cmpq $0x0, 0x18(%rax)
jne 0xfe51
movl $0x10, %edi
callq 0x62f0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x20(%rsp)
movq 0x1c8(%rsp), %rsi
movq 0x148(%rsp), %rdx
callq 0x117a0
jmp 0xfdac
movq 0x20(%rsp), %rax
movq %rax, 0xd0(%rsp)
cmpq $0x0, 0xd0(%rsp)
je 0xfdfb
movq 0xd0(%rsp), %rdi
callq 0x117d0
jmp 0xfdfb
movq 0x20(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x170(%rsp)
movl %eax, 0x16c(%rsp)
movl $0x10, %esi
callq 0x6300
jmp 0xffda
movl $0x10, %edi
callq 0x62f0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x18(%rsp)
callq 0x7aa0
jmp 0xfe17
movq 0x18(%rsp), %rax
movq %rax, 0x1d8(%rsp)
jmp 0xff6a
movq 0x18(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x170(%rsp)
movl %eax, 0x16c(%rsp)
movl $0x10, %esi
callq 0x6300
jmp 0xffda
movq 0xc0(%rsp), %rdi
addq $0x28, %rdi
callq 0x64b0
movq 0xc0(%rsp), %rcx
movq 0x20(%rcx), %rax
cmpq 0x18(%rcx), %rax
jge 0xff09
movl $0x10, %edi
callq 0x62f0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x10(%rsp)
movq 0x1c8(%rsp), %rsi
movq 0x148(%rsp), %rdx
callq 0x117a0
jmp 0xfea4
movq 0x10(%rsp), %rax
movq %rax, 0xc8(%rsp)
cmpq $0x0, 0xc8(%rsp)
je 0xff07
movq 0xc0(%rsp), %rax
movq 0x20(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x20(%rax)
movq 0xc8(%rsp), %rdi
callq 0x117d0
jmp 0xff07
movq 0x10(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x170(%rsp)
movl %eax, 0x16c(%rsp)
movl $0x10, %esi
callq 0x6300
jmp 0xffda
jmp 0xff09
movq 0xc0(%rsp), %rdi
addq $0x28, %rdi
callq 0x6240
movl $0x10, %edi
callq 0x62f0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x8(%rsp)
callq 0x7aa0
jmp 0xff36
movq 0x8(%rsp), %rax
movq %rax, 0x1d8(%rsp)
jmp 0xff6a
movq 0x8(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x170(%rsp)
movl %eax, 0x16c(%rsp)
movl $0x10, %esi
callq 0x6300
jmp 0xffda
jmp 0xff6c
jmp 0xff9e
movq 0x6607b(%rip), %rdi     # 0x75ff0
leaq 0x4f458(%rip), %rsi     # 0x5f3d4
callq 0x62d0
movq %rax, %rdi
movq 0x6602d(%rip), %rsi     # 0x75fb8
callq 0x6320
movq $0x0, 0x1f0(%rsp)
jmp 0xffca
movq 0x1d0(%rsp), %rax
movq %rax, (%rsp)
cmpq $0x0, %rax
je 0xffba
movq (%rsp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
movq 0x1d8(%rsp), %rax
movq %rax, 0x1f0(%rsp)
movq 0x1f0(%rsp), %rax
addq $0x1f8, %rsp            # imm = 0x1F8
retq
movq 0x170(%rsp), %rdi
callq 0x6550
nopw (%rax,%rax)