//#define msgx

#include "parser.ih"

// see README.args for details

// process: execute(mode, cmd, chead, ahead, ..., atail,     ctail)
// argnr:            1     2    3     4           count - 1, count
// argidx:           0     1    2     3      4    count - 2, count - 1
//                                           ...
//                                           count-3
// at least required: 6 arguments

// cmdhead, arghead, argtail and cmdtail only need to be set (by calling their
//  functions), the run-time exec function then prefixes each argument by
//  cmdhead and postfixes each argument with argtail. Then, before calling the
//  cmd cmdhead is inserted between cmd and the first cmd-argument, while
//  cmdtail is appended after the last argument.
// when calling the command the cmdhead, cmdtail, arghead and argtail
//  arguments are first passed to their handling functions. Then the
//  actual arguments are pushed (in reversed order) followed by calling the
//  command itself.

SemVal pmv_execute(SemVal *args)              // args: SemVal argument structure
{
    SemVal ret = SVzero();

    unsigned count = svValue(args);         // the # arguments
    unsigned nExecArgs = count - 6;

    msg("BEGIN: nArgs = %d, nExecArgs: %d", count, nExecArgs);
   
    if (count < 6)                          // to few arguments 
    {
        util_semantic(sem_illegalArgCount, "execute");
        return SVmove(args);                // dummy  args return 
    }

    *args = smvArgs2code(args);

    SemVal *arg0 = (SemVal *)svArg(args, 0);    // arg0 points to the 
                                                // 1st argument


    ret = pmv_setHeadsTails(arg0, count);   // call the cmd/args heads/tails
                                            // functions, erasing the 
                                            // corresponding elements from
                                            // args

    svPushArgsSubset(&ret, args, 4, nExecArgs);
    msg("svPushArgsSubset done, codelen: %d", svCodeLength(&ret));

    svCatenate(&ret, arg0 + 1);
    svCatenate(&ret, arg0);

                    // push the #of pushed arguments: cmd and P_(NO)CHECK
                    // are the two extra arguments
    svAddCode(&ret, op_push_imm, nExecArgs + 2);


    p_callRss(&ret, f_exec, nExecArgs + 3);  // call the exec function

    p_resetHeadsTails(&ret);

    msg("END");

    return ret;
}
