//#define msgx

#include "semval.ih"

void svAddCode(SemVal *sv, Opcode opcode, ...)
{
    msg("BEGIN");
    svOut(sv);

    register unsigned idx;
    int marker_value;
    va_list marker;

    if (deadCode())
    {
        msg("DEAD");
        int type = sv->type;
        svDestroy(sv);
        sv->type = type;
        return;
    }

    msg("WITHIN: codelen = %u", sv->codelen);

    va_start(marker, opcode);

    msg("opcode = 0x%x", opcode);
    sp_appendCode(sv, (int)opcode, sizeof(char));

    s_lastOpcode = opcode;
    switch (opcode)
    {
        case op_jmp:                        // write target to jump to 
            switch ((JMP_COND_)va_arg(marker, JMP_COND_))
            {
                case j_uncond:              // absolute jumplocation 
                    sp_appendCode(sv, va_arg(marker, int), sizeof(int16_t));
                break;

                case j_truelist:
                    sp_patchTrue(sv);           // new truelist item 
                break;

                case j_falselist:
                    sp_patchFalse(sv);          // new falselist item 
                break;

                case j_continuelist:
                    sp_patchContinue(sv);       // new continuelist item 
                break;
            }
        break;

        case op_jmp_false:                  // write target to jump if false 
            sp_patchFalse(sv);
        break;

        case op_jmp_true:                   // write target to jump if true 
            sp_patchTrue(sv);
        break;

        case op_push_strconst:              // write idx of the const 
            sp_appendCode(sv, ssIndex(va_arg(marker, int)), sizeof(int16_t));
        break;

        case op_frame:
        {
            unsigned nLocalVars = symtab_nLocals();

            sp_appendCode(sv, (int)nLocalVars, sizeof(char));

            for (idx = 0; idx != nLocalVars; ++idx)
            {
                ExprType type = symtab_localType(idx);
                sp_appendCode(sv, type, sizeof(char));
            }
        }
        break;

        case op_copy_var:                   // write # of the var. 
        case op_push_var:                   // write # of the var. 
        case op_dec:                        // write # of the var. 
        case op_inc:                        // write # of the var. 
            // write backpatch info and fall through ? 
        // FALLING THRU

        case op_push_imm:                   // write value of the int 
        case op_call:                       // write offset of function 
            sp_appendCode(sv, va_arg(marker, int), sizeof(int16_t));
        break;

        case op_asp:                        // write # of args to remove 
            marker_value = va_arg(marker, int);
            if (!marker_value)              // nothing to add to sp 
                --sv->codelen;               // opcode removed from code 
            else
                sp_appendCode(sv, marker_value, sizeof(char));
        break;      

        case op_call_rss:                   // write # of function 
            sp_appendCode(sv, va_arg(marker, int), sizeof(char));
        break;

        case op_ret:
        case op_exit:
            deadInc();
        break;

        default:
            // The default switch entry is inserted to prvent 
            // a long compiler warning about a not-handled enum value
            // 
            // following opcodes already out:
            // 
            // op_pop_reg
            // op_push_reg
            // op_push_1_jmp_end
            // op_push_0
            // op_umin
            // op_atoi
            // op_itoa
            // op_atol
            // op_mul
            // op_div
            // op_mod
            // op_add
            // op_sub
            // op_eq
            // op_neq
            // op_sm
            // op_gr
            // op_younger
            // op_older
            // op_smeq
            // op_greq
        break;
    }

    msg("END");
}






