root/execute.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. execute_expression_statement
  2. execute_global_statement
  3. execute_elsif
  4. execute_if_statement
  5. execute_while_statement
  6. execute_for_statement
  7. execute_return_statement
  8. execute_break_statement
  9. execute_continue_statement
  10. execute_try_statement
  11. execute_throw_statement
  12. execute_statement
  13. crb_execute_statement_list

#include <math.h>
#include <string.h>
#include "MEM.h"
#include "DBG.h"
#include "crowbar.h"

static StatementResult
execute_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                  Statement *statement);

static StatementResult
execute_expression_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                             Statement *statement)
{
    StatementResult result;
    CRB_Value v;

    result.type = NORMAL_STATEMENT_RESULT;

    v = crb_eval_expression(inter, env, statement->u.expression_s);

    return result;
}

static StatementResult
execute_global_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                         Statement *statement)
{
    IdentifierList *pos;
    StatementResult result;

    result.type = NORMAL_STATEMENT_RESULT;

    if (env == NULL) {
        crb_runtime_error(inter, env, statement->line_number,
                          GLOBAL_STATEMENT_IN_TOPLEVEL_ERR,
                          CRB_MESSAGE_ARGUMENT_END);
    }
    for (pos = statement->u.global_s.identifier_list; pos; pos = pos->next) {
        GlobalVariableRef *ref_pos;
        GlobalVariableRef *new_ref;
        CRB_Value       *value;
        for (ref_pos = env->global_variable; ref_pos;
             ref_pos = ref_pos->next) {
            if (!strcmp(ref_pos->name, pos->name))
                goto NEXT_IDENTIFIER;
        }
        value = CRB_search_global_variable(inter, pos->name);
        if (value == NULL) {
            crb_runtime_error(inter, env, statement->line_number,
                              GLOBAL_VARIABLE_NOT_FOUND_ERR,
                              CRB_STRING_MESSAGE_ARGUMENT, "name", pos->name,
                              CRB_MESSAGE_ARGUMENT_END);
        }
        new_ref = MEM_malloc(sizeof(GlobalVariableRef));
        new_ref->name = pos->name;
        new_ref->value = value;
        new_ref->next = env->global_variable;
        env->global_variable = new_ref;
      NEXT_IDENTIFIER:
        ;
    }

    return result;
}


static StatementResult
execute_elsif(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
              Elsif *elsif_list, CRB_Boolean *executed)
{
    StatementResult result;
    CRB_Value   cond;
    Elsif *pos;

    *executed = CRB_FALSE;
    result.type = NORMAL_STATEMENT_RESULT;
    for (pos = elsif_list; pos; pos = pos->next) {
        cond = crb_eval_expression(inter, env, pos->condition);
        if (cond.type != CRB_BOOLEAN_VALUE) {
            crb_runtime_error(inter, env, pos->condition->line_number,
                              NOT_BOOLEAN_TYPE_ERR, CRB_MESSAGE_ARGUMENT_END);
        }
        if (cond.u.boolean_value) {
            result = crb_execute_statement_list(inter, env,
                                                pos->block->statement_list);
            *executed = CRB_TRUE;
            if (result.type != NORMAL_STATEMENT_RESULT)
                goto FUNC_END;
        }
    }

  FUNC_END:
    return result;
}

static StatementResult
execute_if_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                     Statement *statement)
{
    StatementResult result;
    CRB_Value   cond;

    result.type = NORMAL_STATEMENT_RESULT;
    cond = crb_eval_expression(inter, env, statement->u.if_s.condition);
    if (cond.type != CRB_BOOLEAN_VALUE) {
        crb_runtime_error(inter, env, statement->u.if_s.condition->line_number,
                          NOT_BOOLEAN_TYPE_ERR, CRB_MESSAGE_ARGUMENT_END);
    }
    DBG_assert(cond.type == CRB_BOOLEAN_VALUE, ("cond.type..%d", cond.type));

    if (cond.u.boolean_value) {
        result = crb_execute_statement_list(inter, env,
                                            statement->u.if_s.then_block
                                            ->statement_list);
    } else {
        CRB_Boolean elsif_executed;
        result = execute_elsif(inter, env, statement->u.if_s.elsif_list,
                               &elsif_executed);
        if (result.type != NORMAL_STATEMENT_RESULT)
            goto FUNC_END;
        if (!elsif_executed && statement->u.if_s.else_block) {
            result = crb_execute_statement_list(inter, env,
                                                statement->u.if_s.else_block
                                                ->statement_list);
        }
    }

  FUNC_END:
    return result;
}

static StatementResult
execute_while_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                        Statement *statement)
{
    StatementResult result;
    CRB_Value   cond;

    result.type = NORMAL_STATEMENT_RESULT;
    for (;;) {
        cond = crb_eval_expression(inter, env, statement->u.while_s.condition);
        if (cond.type != CRB_BOOLEAN_VALUE) {
            crb_runtime_error(inter, env,
                              statement->u.while_s.condition->line_number,
                              NOT_BOOLEAN_TYPE_ERR, CRB_MESSAGE_ARGUMENT_END);
        }
        DBG_assert(cond.type == CRB_BOOLEAN_VALUE,
                   ("cond.type..%d", cond.type));
        if (!cond.u.boolean_value)
            break;

        result = crb_execute_statement_list(inter, env,
                                            statement->u.while_s.block
                                            ->statement_list);
        if (result.type == RETURN_STATEMENT_RESULT) {
            break;
        } else if (result.type == BREAK_STATEMENT_RESULT) {
            result.type = NORMAL_STATEMENT_RESULT;
            break;
        }
    }

    return result;
}

static StatementResult
execute_for_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                      Statement *statement)
{
    StatementResult result;
    CRB_Value   cond;

    result.type = NORMAL_STATEMENT_RESULT;

    if (statement->u.for_s.init) {
        crb_eval_expression(inter, env, statement->u.for_s.init);
    }
    for (;;) {
        if (statement->u.for_s.condition) {
            cond = crb_eval_expression(inter, env,
                                       statement->u.for_s.condition);
            if (cond.type != CRB_BOOLEAN_VALUE) {
                crb_runtime_error(inter, env,
                                  statement->u.for_s.condition->line_number,
                                  NOT_BOOLEAN_TYPE_ERR,
                                  CRB_MESSAGE_ARGUMENT_END);
            }
            DBG_assert(cond.type == CRB_BOOLEAN_VALUE,
                       ("cond.type..%d", cond.type));
            if (!cond.u.boolean_value)
                break;
        }
        result = crb_execute_statement_list(inter, env,
                                            statement->u.for_s.block
                                            ->statement_list);
        if (result.type == RETURN_STATEMENT_RESULT) {
            break;
        } else if (result.type == BREAK_STATEMENT_RESULT) {
            result.type = NORMAL_STATEMENT_RESULT;
            break;
        }

        if (statement->u.for_s.post) {
            crb_eval_expression(inter, env, statement->u.for_s.post);
        }
    }

    return result;
}

static StatementResult
execute_return_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                         Statement *statement)
{
    StatementResult result;

    result.type = RETURN_STATEMENT_RESULT;
    if (statement->u.return_s.return_value) {
        result.u.return_value
            = crb_eval_expression(inter, env,
                                  statement->u.return_s.return_value);
    } else {
        result.u.return_value.type = CRB_NULL_VALUE;
    }

    return result;
}

static StatementResult
execute_break_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                        Statement *statement)
{
    StatementResult result;

    result.type = BREAK_STATEMENT_RESULT;

    return result;
}

static StatementResult
execute_continue_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                           Statement *statement)
{
    StatementResult result;

    result.type = CONTINUE_STATEMENT_RESULT;

    return result;
}

static StatementResult
execute_try_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                      Statement *statement)
{
    StatementResult result;
    StatementResult finally_result;
    int stack_pointer_backup;
    RecoveryEnvironment env_backup;

    stack_pointer_backup = crb_get_stack_pointer(inter);
    env_backup = inter->current_recovery_environment;
    if (setjmp(inter->current_recovery_environment.environment) == 0) {
        result = crb_execute_statement_list(inter, env,
                                            statement->u.try_s.try_block
                                            ->statement_list);
    } else {
        crb_set_stack_pointer(inter, stack_pointer_backup);
        inter->current_recovery_environment = env_backup;

        if (statement->u.try_s.catch_block) {
            CRB_Value *dest;
            CRB_Value ex_value;

            ex_value = inter->current_exception;
            CRB_push_value(inter, &ex_value);
            inter->current_exception.type = CRB_NULL_VALUE;

            dest = crb_get_identifier_lvalue(inter, env,
                                             statement->u.try_s.exception);
            if (dest == NULL) {
                if (env != NULL) {
                    CRB_add_local_variable(inter, env,
                                           statement->u.try_s.exception,
                                           &ex_value);
                } else {
                    if (CRB_search_function(inter,
                                            statement->u.try_s.exception)) {
                        crb_runtime_error(inter, env, statement->line_number,
                                          FUNCTION_EXISTS_ERR,
                                          CRB_STRING_MESSAGE_ARGUMENT, "name",
                                          statement->u.try_s.exception,
                                          CRB_MESSAGE_ARGUMENT_END);
                    }
                    CRB_add_global_variable(inter, 
                                            statement->u.try_s.exception,
                                            &ex_value);
                }
            } else {
                *dest = ex_value;
            }
            result = crb_execute_statement_list(inter, env,
                                                statement->u.try_s.catch_block
                                                ->statement_list);
            CRB_shrink_stack(inter, 1);
        }
    }
    inter->current_recovery_environment = env_backup;
    if (statement->u.try_s.finally_block) {
        finally_result
            = crb_execute_statement_list(inter, env,
                                         statement->u.try_s.finally_block
                                         ->statement_list);
        if (finally_result.type != NORMAL_STATEMENT_RESULT) {
            result = finally_result;
        }
    }
    if (!statement->u.try_s.catch_block
        && inter->current_exception.type != CRB_NULL_VALUE) {
        longjmp(env_backup.environment, LONGJMP_ARG);
    }

    return result;
}

static StatementResult
execute_throw_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                        Statement *statement)
{
    CRB_Value *ex_val;

    ex_val = crb_eval_and_peek_expression(inter, env,
                                          statement->u.throw_s.exception);
    inter->current_exception = *ex_val;

    CRB_shrink_stack(inter, 1);

    longjmp(inter->current_recovery_environment.environment, LONGJMP_ARG);
}

static StatementResult
execute_statement(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                  Statement *statement)
{
    StatementResult result;

    result.type = NORMAL_STATEMENT_RESULT;

    switch (statement->type) {
    case EXPRESSION_STATEMENT:
        result = execute_expression_statement(inter, env, statement);
        break;
    case GLOBAL_STATEMENT:
        result = execute_global_statement(inter, env, statement);
        break;
    case IF_STATEMENT:
        result = execute_if_statement(inter, env, statement);
        break;
    case WHILE_STATEMENT:
        result = execute_while_statement(inter, env, statement);
        break;
    case FOR_STATEMENT:
        result = execute_for_statement(inter, env, statement);
        break;
    case RETURN_STATEMENT:
        result = execute_return_statement(inter, env, statement);
        break;
    case BREAK_STATEMENT:
        result = execute_break_statement(inter, env, statement);
        break;
    case CONTINUE_STATEMENT:
        result = execute_continue_statement(inter, env, statement);
        break;
    case TRY_STATEMENT:
        result = execute_try_statement(inter, env, statement);
        break;
    case THROW_STATEMENT:
        result = execute_throw_statement(inter, env, statement);
        break;
    case STATEMENT_TYPE_COUNT_PLUS_1:   /* FALLTHRU */
    default:
        DBG_assert(0, ("bad case...%d", statement->type));
    }

    return result;
}

StatementResult
crb_execute_statement_list(CRB_Interpreter *inter, CRB_LocalEnvironment *env,
                           StatementList *list)
{
    StatementList *pos;
    StatementResult result;

    result.type = NORMAL_STATEMENT_RESULT;
    for (pos = list; pos; pos = pos->next) {
        result = execute_statement(inter, env, pos->statement);
        if (result.type != NORMAL_STATEMENT_RESULT)
            goto FUNC_END;
    }

  FUNC_END:
    return result;
}

/* [<][>][^][v][top][bottom][index][help] */