NAME ^

src/stacks.c - Stack handling routines for Parrot

DESCRIPTION ^

The stack is stored as a linked list of chunks (Stack_Chunk), where each chunk has room for one entry.

Functions ^

PARROT_API PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT Stack_Chunk_t *new_stack(PARROT_INTERP, ARGIN(const char *name))

Create a new stack and name it. stack->name is used for debugging/error reporting.

PARROT_API void mark_stack(PARROT_INTERP, NOTNULL(Stack_Chunk_t *chunk))

Mark entries in a stack structure during DOD.

PARROT_API void stack_destroy(SHIM(Stack_Chunk_t *top))

stack_destroy() doesn't need to do anything, since GC does it all.

PARROT_API PARROT_WARN_UNUSED_RESULT size_t stack_height(SHIM_INTERP, ARGIN(const Stack_Chunk_t *chunk))

Returns the height of the stack. The maximum "depth" is height - 1.

PARROT_API PARROT_CAN_RETURN_NULL PARROT_WARN_UNUSED_RESULT Stack_Entry_t *stack_entry(PARROT_INTERP, NOTNULL(Stack_Chunk_t *stack), INTVAL depth)

If depth >= 0, return the entry at that depth from the top of the stack, with 0 being the top entry. If depth < 0, then return the entry |depth| entries from the bottom of the stack. Returns NULL if |depth| number> of entries in stack.

PARROT_API void rotate_entries(PARROT_INTERP, NOTNULL(Stack_Chunk_t **stack_p), INTVAL num_entries)

Rotate the top N entries by one. If N > 0, the rotation is bubble up, so the top most element becomes the Nth element. If N < 0, the rotation is bubble down, so that the Nth element becomes the top most element.

*/

PARROT_API void rotate_entries(PARROT_INTERP, NOTNULL(Stack_Chunk_t **stack_p), INTVAL num_entries) { Stack_Chunk_t * const stack = *stack_p; INTVAL depth = num_entries - 1;

    if (num_entries >= -1 && num_entries <= 1) {
        return;
    }

    if (num_entries < 0) {
        INTVAL i;
        Stack_Entry_t temp;

        num_entries = -num_entries;
        depth = num_entries - 1;

        if (stack_height(interp, stack) < (size_t)num_entries) {
            real_exception(interp, NULL, ERROR_STACK_SHALLOW, "Stack too shallow!");
        }

        temp = *stack_entry(interp, stack, depth);
        for (i = depth; i > 0; i--) {
            *stack_entry(interp, stack, i) =
                *stack_entry(interp, stack, i - 1);
        }

        *stack_entry(interp, stack, 0) = temp;
    }
    else {
        INTVAL i;
        Stack_Entry_t temp;

        if (stack_height(interp, stack) < (size_t)num_entries) {
            real_exception(interp, NULL, ERROR_STACK_SHALLOW, "Stack too shallow!");
        }
        temp = *stack_entry(interp, stack, 0);
        for (i = 0; i < depth; i++) {
            *stack_entry(interp, stack, i) =
                *stack_entry(interp, stack, i + 1);
        }

        *stack_entry(interp, stack, depth) = temp;
    }
}
/*

PARROT_API void stack_push(PARROT_INTERP, NOTNULL(Stack_Chunk_t **stack_p), NOTNULL(void *thing), Stack_entry_type type, NULLOK(Stack_cleanup_method cleanup))

Push something on the generic stack.

Note that the cleanup pointer, if non-NULL, points to a routine that'll be called when the entry is removed from the stack. This is handy for those cases where you need some sort of activity to take place when an entry is removed, such as when you push a lexical lock onto the call stack, or localize (or tempify, or whatever we're calling it) variable or something.

*/

PARROT_API void stack_push(PARROT_INTERP, NOTNULL(Stack_Chunk_t **stack_p), NOTNULL(void *thing), Stack_entry_type type, NULLOK(Stack_cleanup_method cleanup)) { Stack_Entry_t * const entry = (Stack_Entry_t *)stack_prepare_push(interp, stack_p);

    /* Remember the type */
    entry->entry_type = type;
    /* Remember the cleanup function */
    entry->cleanup = cleanup;
    /* Store our thing */
    switch (type) {
        case STACK_ENTRY_INT:
        case STACK_ENTRY_MARK:
            UVal_int(entry->entry) = *(INTVAL *)thing;
            break;
        case STACK_ENTRY_FLOAT:
            UVal_num(entry->entry) = *(FLOATVAL *)thing;
            break;
        case STACK_ENTRY_ACTION:
        case STACK_ENTRY_PMC:
            UVal_pmc(entry->entry) = (PMC *)thing;
            break;
        case STACK_ENTRY_STRING:
            UVal_str(entry->entry) = (STRING *)thing;
            break;
        case STACK_ENTRY_POINTER:
        case STACK_ENTRY_DESTINATION:
            UVal_ptr(entry->entry) = thing;
            break;
        default:
            real_exception(interp, NULL, ERROR_BAD_STACK_TYPE,
                    "Invalid Stack_Entry_type!");
    }
}
/*

PARROT_API PARROT_CAN_RETURN_NULL void *stack_pop(PARROT_INTERP, NOTNULL(Stack_Chunk_t **stack_p), NULLOK(void *where), Stack_entry_type type)

Pop off an entry and return a pointer to the contents.

*/

PARROT_API PARROT_CAN_RETURN_NULL void * stack_pop(PARROT_INTERP, NOTNULL(Stack_Chunk_t **stack_p), NULLOK(void *where), Stack_entry_type type) { Stack_Entry_t * const entry = (Stack_Entry_t *)stack_prepare_pop(interp, stack_p);

    /* Types of 0 mean we don't care */
    if (type && entry->entry_type != type) {
        real_exception(interp, NULL, ERROR_BAD_STACK_TYPE,
                           "Wrong type on top of stack!\n");
    }

    /* Cleanup routine? */
    if (entry->cleanup != STACK_CLEANUP_NULL)
        (*entry->cleanup) (interp, entry);

    /* Sometimes the caller doesn't care what the value was */
    if (where == NULL)
        return NULL;

    /* Snag the value */
    switch (type) {
    case STACK_ENTRY_MARK:
    case STACK_ENTRY_INT:
        *(INTVAL *)where   = UVal_int(entry->entry);
        break;
    case STACK_ENTRY_FLOAT:
        *(FLOATVAL *)where = UVal_num(entry->entry);
        break;
    case STACK_ENTRY_ACTION:
    case STACK_ENTRY_PMC:
        *(PMC **)where     = UVal_pmc(entry->entry);
        break;
    case STACK_ENTRY_STRING:
        *(STRING **)where  = UVal_str(entry->entry);
        break;
    case STACK_ENTRY_POINTER:
    case STACK_ENTRY_DESTINATION:
        *(void **)where    = UVal_ptr(entry->entry);
        break;
    default:
        real_exception(interp, NULL, ERROR_BAD_STACK_TYPE,
                           "Wrong type on top of stack!\n");
    }

    return where;
}
/*

PARROT_API PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL void *pop_dest(PARROT_INTERP)

Pop off a destination entry and return a pointer to the contents.

PARROT_API PARROT_CAN_RETURN_NULL PARROT_WARN_UNUSED_RESULT void *stack_peek(PARROT_INTERP, NOTNULL(Stack_Chunk_t *stack_base), NULLOK(Stack_entry_type *type))

Peek at stack and return pointer to entry and the type of the entry.

PARROT_API PARROT_WARN_UNUSED_RESULT PARROT_PURE_FUNCTION Stack_entry_type get_entry_type(SHIM_INTERP, ARGIN(const Stack_Entry_t *entry))

Returns the stack entry type of entry.

PARROT_API void Parrot_dump_dynamic_environment(PARROT_INTERP, NOTNULL(Stack_Chunk_t *dynamic_env))

Print a representation of the dynamic stack to the standard error (using PIO_eprintf). This is used only temporarily for debugging.

SEE ALSO ^

include/parrot/stacks.h, include/parrot/enums.h, and src/stack_common.c


parrot