static nxt_int_t
njs_parser_name_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token, const void *data)
{
    nxt_uint_t         level;
    njs_extern_t       *ext;
    njs_variable_t     *var;
    njs_parser_node_t  *node;

    node = njs_parser_node_alloc(vm);

    if (nxt_fast_path(node != NULL)) {
        ext = njs_parser_external(vm, parser);

        if (ext != NULL) {
            node->token = NJS_TOKEN_EXTERNAL;
            node->u.value.type = NJS_EXTERNAL;
            node->u.value.data.truth = 1;
            node->index = (njs_index_t) ext;

        } else {
            node->token = token;

            var = njs_parser_variable(vm, parser, &level);
            if (nxt_slow_path(var == NULL)) {
                return NJS_TOKEN_ERROR;
            }

            switch (var->state) {

            case NJS_VARIABLE_CREATED:
                var->state = NJS_VARIABLE_PENDING;
                parser->code_size += sizeof(njs_vmcode_1addr_t);
                break;

            case NJS_VARIABLE_PENDING:
                var->state = NJS_VARIABLE_USED;
                parser->code_size += sizeof(njs_vmcode_1addr_t);
                break;

            case NJS_VARIABLE_USED:
                parser->code_size += sizeof(njs_vmcode_1addr_t);
                break;

            case NJS_VARIABLE_SET:
            case NJS_VARIABLE_DECLARED:
                break;
            }

            node->lvalue = NJS_LVALUE_ENABLED;
            node->u.variable = var;
        }
    }

    parser->node = node;

    return NXT_OK;
}
static njs_token_t
njs_parser_inc_dec_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token)
{
    njs_token_t             next;
    njs_parser_node_t       *node;
    njs_vmcode_operation_t  operation;

    switch (token) {

    case NJS_TOKEN_INCREMENT:
        operation = njs_vmcode_increment;
        break;

    case NJS_TOKEN_DECREMENT:
        operation = njs_vmcode_decrement;
        break;

    default:
        return njs_parser_post_inc_dec_expression(vm, parser, token);
    }

    next = njs_parser_token(parser);
    if (nxt_slow_path(next <= NJS_TOKEN_ILLEGAL)) {
        return next;
    }

    next = njs_parser_call_expression(vm, parser, next);
    if (nxt_slow_path(next <= NJS_TOKEN_ILLEGAL)) {
        return next;
    }

    if (parser->node->lvalue == NJS_LVALUE_NONE) {
        nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required");
        return NJS_TOKEN_ILLEGAL;
    }

    node = njs_parser_node_alloc(vm);
    if (nxt_slow_path(node == NULL)) {
        return NJS_TOKEN_ERROR;
    }

    node->token = token;
    node->u.operation = operation;
    node->left = parser->node;
    parser->node = node;

    parser->code_size += (parser->node->token == NJS_TOKEN_NAME) ?
                             sizeof(njs_vmcode_3addr_t):
                             sizeof(njs_vmcode_prop_get_t)
                             + sizeof(njs_vmcode_3addr_t)
                             + sizeof(njs_vmcode_prop_set_t);

    return next;
}
static njs_token_t
njs_parser_property_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token)
{
    njs_token_t        next;
    njs_parser_node_t  *node;

    for ( ;; ) {
        if (token != NJS_TOKEN_DOT
            && token != NJS_TOKEN_OPEN_BRACKET)
        {
            return token;
        }

        node = njs_parser_node_alloc(vm);
        if (nxt_slow_path(node == NULL)) {
            return NJS_TOKEN_ERROR;
        }

        node->token = NJS_TOKEN_PROPERTY;
        node->lvalue = NJS_LVALUE_ENABLED;
        node->u.operation = njs_vmcode_property_get;
        node->left = parser->node;

        next = njs_parser_token(parser);
        if (nxt_slow_path(next <= NJS_TOKEN_ILLEGAL)) {
            return next;
        }

        if (token == NJS_TOKEN_DOT) {

            if (next != NJS_TOKEN_NAME) {
                return NJS_TOKEN_ILLEGAL;
            }

            token = njs_parser_property_name(vm, parser, next);

        } else {
            token = njs_parser_property_brackets(vm, parser, next);
        }

        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        node->right = parser->node;
        parser->node = node;

        parser->code_size += sizeof(njs_vmcode_prop_get_t);
    }
}
njs_token_t
njs_parser_arguments(njs_vm_t *vm, njs_parser_t *parser,
    njs_parser_node_t *parent)
{
    njs_token_t        token;
    njs_index_t        index;
    njs_parser_node_t  *node;

    index = NJS_SCOPE_CALLEE_ARGUMENTS;

    do {
        token = njs_parser_token(parser);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        if (token == NJS_TOKEN_CLOSE_PARENTHESIS) {
            break;
        }

        token = njs_parser_assignment_expression(vm, parser, NULL, token);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        node = njs_parser_node_alloc(vm);
        if (nxt_slow_path(node == NULL)) {
            return NJS_TOKEN_ERROR;
        }

        node->token = NJS_TOKEN_ARGUMENT;
        node->index = index;
        index += sizeof(njs_value_t);

        node->left = parser->node;
        parser->node->dest = node;
        parent->right = node;
        parent = node;

        parser->code_size += sizeof(njs_vmcode_move_t);

    } while (token == NJS_TOKEN_COMMA);

    if (nxt_slow_path(token != NJS_TOKEN_CLOSE_PARENTHESIS)) {
        return NJS_TOKEN_ILLEGAL;
    }

    return token;
}
static nxt_int_t
njs_parser_null_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token, const void *data)
{
    njs_parser_node_t  *node;

    node = njs_parser_node_alloc(vm);

    if (nxt_fast_path(node != NULL)) {
        node->token = token;
        node->u.value = njs_value_null;
        parser->node = node;

        return NXT_OK;
    }

    return NXT_ERROR;
}
static nxt_int_t
njs_parser_this_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token, const void *data)
{
    njs_parser_node_t  *node;

    node = njs_parser_node_alloc(vm);

    if (nxt_fast_path(node != NULL)) {
        node->token = token;
        node->index = NJS_INDEX_THIS;
        parser->node = node;

        return NXT_OK;
    }

    return NXT_ERROR;
}
static nxt_int_t
njs_parser_boolean_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token, const void *data)
{
    njs_parser_node_t  *node;

    node = njs_parser_node_alloc(vm);

    if (nxt_fast_path(node != NULL)) {
        node->token = token;
        node->u.value = (parser->lexer->number == 0.0) ? njs_value_false:
                                                         njs_value_true;
        parser->node = node;

        return NXT_OK;
    }

    return NXT_ERROR;
}
static nxt_int_t
njs_parser_node(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token,
    const void *data)
{
    njs_parser_node_t  *node;

    token = (njs_token_t) data;

    node = njs_parser_node_alloc(vm);

    if (nxt_fast_path(node != NULL)) {
        node->token = token;
        node->left = parser->node;
        parser->node = node;

        return NXT_OK;
    }

    return NXT_ERROR;
}
njs_token_t
njs_parser_property_name(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token)
{
    nxt_int_t          ret;
    njs_parser_node_t  *node;

    node = njs_parser_node_alloc(vm);
    if (nxt_slow_path(node == NULL)) {
        return NJS_TOKEN_ERROR;
    }

    node->token = NJS_TOKEN_STRING;

    ret = njs_parser_string_create(vm, &node->u.value);
    if (nxt_slow_path(ret != NXT_OK)) {
        return NJS_TOKEN_ERROR;
    }

    parser->node = node;

    return njs_parser_token(parser);
}
static nxt_int_t
njs_parser_number_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token, const void *data)
{
    double             num;
    njs_parser_node_t  *node;

    node = njs_parser_node_alloc(vm);

    if (nxt_fast_path(node != NULL)) {
        node->token = token;
        num = parser->lexer->number;
        node->u.value.data.u.number = num;
        node->u.value.type = NJS_NUMBER;
        node->u.value.data.truth = njs_is_number_true(num);
        parser->node = node;

        return NXT_OK;
    }

    return NXT_ERROR;
}
static nxt_int_t
njs_parser_unary_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token, const void *data)
{
    njs_parser_node_t       *node;
    njs_vmcode_operation_t  operation;

    operation = (njs_vmcode_operation_t) data;

    node = njs_parser_node_alloc(vm);

    if (nxt_fast_path(node != NULL)) {
        node->token = token;
        node->u.operation = operation;
        parser->node = node;
        parser->code_size += sizeof(njs_vmcode_2addr_t);

        return NXT_OK;
    }

    return NXT_ERROR;
}
static nxt_int_t
njs_parser_condition_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token, const void *data)
{
    njs_parser_node_t  *node;

    node = njs_parser_node_alloc(vm);

    if (nxt_fast_path(node != NULL)) {
        node->token = token;
        node->left = parser->node;
        parser->node = node;
        parser->code_size += sizeof(njs_vmcode_cond_jump_t)
                             + sizeof(njs_vmcode_move_t)
                             + sizeof(njs_vmcode_jump_t)
                             + sizeof(njs_vmcode_move_t);
        parser->branch = 1;

        return NXT_OK;
    }

    return NXT_ERROR;
}
static nxt_int_t
njs_parser_string_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token, const void *data)
{
    nxt_int_t          ret;
    njs_parser_node_t  *node;

    node = njs_parser_node_alloc(vm);

    if (nxt_fast_path(node != NULL)) {
        node->token = token;

        ret = njs_parser_string_create(vm, &node->u.value);
        if (nxt_slow_path(ret != NXT_OK)) {
            return NJS_TOKEN_ERROR;
        }

        parser->node = node;

        return NXT_OK;
    }

    return NXT_ERROR;
}
Beispiel #14
0
njs_token_t
njs_parser_var_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token)
{
    size_t                  size;
    njs_parser_node_t       *node, *pending;
    njs_vmcode_operation_t  operation;

    token = njs_parser_conditional_expression(vm, parser, token);
    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
        return token;
    }

    for ( ;; ) {
        size = sizeof(njs_vmcode_3addr_t);

        switch (token) {

        case NJS_TOKEN_ASSIGNMENT:
            nxt_thread_log_debug("JS: =");
            operation = njs_vmcode_move;
            size = sizeof(njs_vmcode_move_t);
            break;

        case NJS_TOKEN_LINE_END:
            token = njs_lexer_token(parser->lexer);
            if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
                return token;
            }

            if (njs_parser_expression_operator(token)) {
                continue;
            }

            /* Fall through. */

        default:
            return token;
        }

        node = parser->node;

        if (node->lvalue == NJS_LVALUE_NONE) {
            nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required");
            return NJS_TOKEN_ILLEGAL;
        }

        pending = NULL;

        if (node->token == NJS_TOKEN_NAME) {
            node->state = NJS_VARIABLE_ASSIGNMENT;

            if (node->u.variable->state == NJS_VARIABLE_PENDING) {
                pending = node;
            }
        }

        node = njs_parser_node_alloc(vm);
        if (nxt_slow_path(node == NULL)) {
            return NJS_TOKEN_ERROR;
        }

        node->token = token;
        node->u.operation = operation;
        node->left = parser->node;
        parser->code_size += size;

        token = njs_parser_token(parser);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        token = njs_parser_var_expression(vm, parser, token);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        node->right = parser->node;
        parser->node = node;

        if (pending != NULL
            && pending->u.variable->state == NJS_VARIABLE_PENDING)
        {
            pending->u.variable->state = NJS_VARIABLE_SET;
            parser->code_size -= sizeof(njs_vmcode_1addr_t);

            if (!parser->branch) {
                pending->state = NJS_VARIABLE_FIRST_ASSIGNMENT;
            }
        }
    }
}
Beispiel #15
0
static njs_token_t
njs_parser_assignment_expression(njs_vm_t *vm, njs_parser_t *parser,
    const njs_parser_expression_t *expr, njs_token_t token)
{
    size_t                  size;
    njs_parser_node_t       *node, *pending;
    njs_vmcode_operation_t  operation;

    token = njs_parser_conditional_expression(vm, parser, token);
    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
        return token;
    }

    for ( ;; ) {
        switch (token) {

        case NJS_TOKEN_ASSIGNMENT:
            nxt_thread_log_debug("JS: =");
            operation = njs_vmcode_move;
            break;

        case NJS_TOKEN_ADDITION_ASSIGNMENT:
            nxt_thread_log_debug("JS: +=");
            operation = njs_vmcode_addition;
            break;

        case NJS_TOKEN_SUBSTRACTION_ASSIGNMENT:
            nxt_thread_log_debug("JS: -=");
            operation = njs_vmcode_substraction;
            break;

        case NJS_TOKEN_MULTIPLICATION_ASSIGNMENT:
            nxt_thread_log_debug("JS: *=");
            operation = njs_vmcode_multiplication;
            break;

        case NJS_TOKEN_DIVISION_ASSIGNMENT:
            nxt_thread_log_debug("JS: /=");
            operation = njs_vmcode_division;
            break;

        case NJS_TOKEN_REMAINDER_ASSIGNMENT:
            nxt_thread_log_debug("JS: %=");
            operation = njs_vmcode_remainder;
            break;

        case NJS_TOKEN_LEFT_SHIFT_ASSIGNMENT:
            nxt_thread_log_debug("JS: <<=");
            operation = njs_vmcode_left_shift;
            break;

        case NJS_TOKEN_RIGHT_SHIFT_ASSIGNMENT:
            nxt_thread_log_debug("JS: >>=");
            operation = njs_vmcode_right_shift;
            break;

        case NJS_TOKEN_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
            nxt_thread_log_debug("JS: >>=");
            operation = njs_vmcode_unsigned_right_shift;
            break;

        case NJS_TOKEN_BITWISE_AND_ASSIGNMENT:
            nxt_thread_log_debug("JS: &=");
            operation = njs_vmcode_bitwise_and;
            break;

        case NJS_TOKEN_BITWISE_XOR_ASSIGNMENT:
            nxt_thread_log_debug("JS: ^=");
            operation = njs_vmcode_bitwise_xor;
            break;

        case NJS_TOKEN_BITWISE_OR_ASSIGNMENT:
            nxt_thread_log_debug("JS: |=");
            operation = njs_vmcode_bitwise_or;
            break;

        case NJS_TOKEN_LINE_END:
            token = njs_lexer_token(parser->lexer);
            if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
                return token;
            }

            if (njs_parser_expression_operator(token)) {
                continue;
            }

            /* Fall through. */

        default:
            return token;
        }

        node = parser->node;

        if (node->lvalue == NJS_LVALUE_NONE) {
            nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required");
            return NJS_TOKEN_ILLEGAL;
        }

        pending = NULL;

        if (node->token == NJS_TOKEN_NAME) {

            if (token == NJS_TOKEN_ASSIGNMENT) {
                node->state = NJS_VARIABLE_ASSIGNMENT;

                if (node->u.variable->state == NJS_VARIABLE_PENDING) {
                    pending = node;
                }

            } else if (node->u.variable->state == NJS_VARIABLE_PENDING) {
                node->u.variable->state = NJS_VARIABLE_USED;
            }
        }

        node = njs_parser_node_alloc(vm);
        if (nxt_slow_path(node == NULL)) {
            return NJS_TOKEN_ERROR;
        }

        node->token = token;
        node->u.operation = operation;
        node->left = parser->node;

        token = njs_parser_token(parser);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        token = njs_parser_assignment_expression(vm, parser, NULL, token);

        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        node->right = parser->node;
        parser->node = node;

        if (node->left->token == NJS_TOKEN_NAME) {

            if (node->token == NJS_TOKEN_ASSIGNMENT) {
                size = sizeof(njs_vmcode_move_t);

            } else {
                if (njs_parser_has_side_effect(node->right)) {
                    size = sizeof(njs_vmcode_move_t)
                           + sizeof(njs_vmcode_3addr_t);
                } else {
                    size = sizeof(njs_vmcode_3addr_t);
                }
            }

        } else {
            if (node->token == NJS_TOKEN_ASSIGNMENT) {
                size = sizeof(njs_vmcode_prop_set_t);

                if (njs_parser_has_side_effect(node->right)) {
                    size += 2 * sizeof(njs_vmcode_move_t);
                }

            } else {
                size = sizeof(njs_vmcode_prop_get_t)
                       + sizeof(njs_vmcode_3addr_t)
                       + sizeof(njs_vmcode_prop_set_t);
            }
        }

        parser->code_size += size;

        if (pending != NULL
            && pending->u.variable->state == NJS_VARIABLE_PENDING)
        {
            pending->u.variable->state = NJS_VARIABLE_SET;

            if (!parser->branch) {
                pending->state = NJS_VARIABLE_FIRST_ASSIGNMENT;
            }
        }
    }
}
Beispiel #16
0
static njs_token_t
njs_parser_call_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token)
{
    nxt_bool_t         ctor;
    njs_parser_node_t  *func, *node;

    ctor = 0;

    if (token == NJS_TOKEN_NEW) {
        token = njs_parser_token(parser);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        ctor = 1;
    }

    token = njs_parser_terminal(vm, parser, token);
    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
        return token;
    }

    for ( ;; ) {

        token = njs_parser_property_expression(vm, parser, token);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        node = parser->node;

        if (token != NJS_TOKEN_OPEN_PARENTHESIS) {
            /* TODO: var o = new Object; */
            node->ctor = ctor;
            return token;
        }

        switch (node->token) {

        case NJS_TOKEN_NAME:
            func = node;
            func->token = NJS_TOKEN_FUNCTION_CALL;
            parser->code_size += sizeof(njs_vmcode_function_frame_t)
                                 + sizeof(njs_vmcode_function_call_t);
            break;

        case NJS_TOKEN_FUNCTION_EXPRESSION:
            func = njs_parser_node_alloc(vm);
            if (nxt_slow_path(func == NULL)) {
                return NJS_TOKEN_ERROR;
            }

            func->token = NJS_TOKEN_FUNCTION_CALL;
            func->left = node;
            func->index = node->index;
            parser->code_size += sizeof(njs_vmcode_function_frame_t)
                                 + sizeof(njs_vmcode_function_call_t);
            break;

        case NJS_TOKEN_PROPERTY:
            func = njs_parser_node_alloc(vm);
            if (nxt_slow_path(func == NULL)) {
                return NJS_TOKEN_ERROR;
            }

            func->token = NJS_TOKEN_METHOD_CALL;
            func->left = node;
            parser->code_size += sizeof(njs_vmcode_method_frame_t)
                                 + sizeof(njs_vmcode_function_call_t);
            break;

        default:
            /*
             * NJS_TOKEN_OPEN_PARENTHESIS,
             * NJS_TOKEN_OBJECT_CONSTRUCTOR,
             * NJS_TOKEN_ARRAY_CONSTRUCTOR,
             * NJS_TOKEN_BOOLEAN_CONSTRUCTOR,
             * NJS_TOKEN_NUMBER_CONSTRUCTOR,
             * NJS_TOKEN_STRING_CONSTRUCTOR,
             * NJS_TOKEN_FUNCTION_CONSTRUCTOR,
             * NJS_TOKEN_REGEXP_CONSTRUCTOR,
             * NJS_TOKEN_EVAL.
             */
            func = njs_parser_node_alloc(vm);
            if (nxt_slow_path(func == NULL)) {
                return NJS_TOKEN_ERROR;
            }

            func->token = NJS_TOKEN_FUNCTION_CALL;
            func->left = node;
            parser->code_size += sizeof(njs_vmcode_function_frame_t)
                                 + sizeof(njs_vmcode_function_call_t);
            break;
        }

        token = njs_parser_arguments(vm, parser, func);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        parser->node = func;

        token = njs_parser_token(parser);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }
    }
}
Beispiel #17
0
njs_token_t
njs_parser_conditional_expression(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token)
{
    njs_parser_node_t  *node, *cond;

    token = njs_parser_binary_expression(vm, parser,
                                         &njs_parser_logical_or_expression,
                                         token);
    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
        return token;
    }

    for ( ;; ) {
        if (token != NJS_TOKEN_CONDITIONAL) {
            return token;
        }

        parser->branch = 1;

        token = njs_parser_token(parser);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        cond = njs_parser_node_alloc(vm);
        if (nxt_slow_path(cond == NULL)) {
            return NJS_TOKEN_ERROR;
        }

        cond->token = NJS_TOKEN_CONDITIONAL;
        cond->left = parser->node;

        node = njs_parser_node_alloc(vm);
        if (nxt_slow_path(node == NULL)) {
            return NJS_TOKEN_ERROR;
        }

        cond->right = node;
        node->token = NJS_TOKEN_BRANCHING;

        token = njs_parser_assignment_expression(vm, parser, NULL, token);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        if (nxt_slow_path(token != NJS_TOKEN_COLON)) {
            return NJS_TOKEN_ILLEGAL;
        }

        node->left = parser->node;
        node->left->dest = cond;

        token = njs_parser_token(parser);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        token = njs_parser_assignment_expression(vm, parser, NULL, token);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        node->right = parser->node;
        node->right->dest = cond;

        parser->node = cond;
        parser->code_size += sizeof(njs_vmcode_cond_jump_t)
                             + sizeof(njs_vmcode_move_t)
                             + sizeof(njs_vmcode_jump_t)
                             + sizeof(njs_vmcode_move_t);
    }
}
Beispiel #18
0
static njs_token_t
njs_parser_unary_expression(njs_vm_t *vm, njs_parser_t *parser,
    const njs_parser_expression_t *expr, njs_token_t token)
{
    double                  num;
    njs_token_t             next;
    njs_parser_node_t       *node;
    njs_vmcode_operation_t  operation;

    switch (token) {

    case NJS_TOKEN_ADDITION:
        token = NJS_TOKEN_UNARY_PLUS;
        operation = njs_vmcode_unary_plus;
        break;

    case NJS_TOKEN_SUBSTRACTION:
        token = NJS_TOKEN_UNARY_NEGATION;
        operation = njs_vmcode_unary_negation;
        break;

    case NJS_TOKEN_LOGICAL_NOT:
        operation = njs_vmcode_logical_not;
        break;

    case NJS_TOKEN_BITWISE_NOT:
        operation = njs_vmcode_bitwise_not;
        break;

    case NJS_TOKEN_TYPEOF:
        operation = njs_vmcode_typeof;
        break;

    case NJS_TOKEN_VOID:
        operation = njs_vmcode_void;
        break;

    case NJS_TOKEN_DELETE:
        operation = njs_vmcode_delete;
        break;

    default:
        return njs_parser_inc_dec_expression(vm, parser, token);
    }

    next = njs_parser_token(parser);
    if (nxt_slow_path(next <= NJS_TOKEN_ILLEGAL)) {
        return next;
    }

    next = njs_parser_unary_expression(vm, parser, NULL, next);
    if (nxt_slow_path(next <= NJS_TOKEN_ILLEGAL)) {
        return next;
    }

    if (token == NJS_TOKEN_UNARY_PLUS
        && parser->node->token == NJS_TOKEN_NUMBER)
    {
        /* Skip the unary plus of number. */
        return next;
    }

    if (token == NJS_TOKEN_UNARY_NEGATION
        && parser->node->token == NJS_TOKEN_NUMBER)
    {
        /* Optimization of common negative number. */

        node = parser->node;
        num = -node->u.value.data.u.number;
        node->u.value.data.u.number = num;
        node->u.value.data.truth = njs_is_number_true(num);

        return next;
    }

    if (token == NJS_TOKEN_TYPEOF
        && parser->node->token == NJS_TOKEN_NAME)
    {
        parser->node->state = NJS_VARIABLE_TYPEOF;

    } else if (token == NJS_TOKEN_DELETE
               && parser->node->token == NJS_TOKEN_PROPERTY)
    {
        parser->node->token = NJS_TOKEN_PROPERTY_DELETE;
        parser->node->u.operation = njs_vmcode_property_delete;
        parser->code_size += sizeof(njs_vmcode_3addr_t);

        return next;
    }

    node = njs_parser_node_alloc(vm);
    if (nxt_slow_path(node == NULL)) {
        return NJS_TOKEN_ERROR;
    }

    node->token = token;
    node->u.operation = operation;
    node->left = parser->node;
    node->left->dest = node;
    parser->node = node;
    parser->code_size += sizeof(njs_vmcode_2addr_t);

    return next;
}
Beispiel #19
0
static njs_token_t
njs_parser_binary_expression(njs_vm_t *vm, njs_parser_t *parser,
    const njs_parser_expression_t *expr, njs_token_t token)
{
    nxt_int_t                     n;
    njs_parser_node_t             *node;
    const njs_parser_operation_t  *op;

    token = expr->next(vm, parser, expr->expression, token);
    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
        return token;
    }

    for ( ;; ) {
        n = expr->count;
        op = expr->op;

        do {
            if (op->token == token) {
                goto found;
            }

            op++;
            n--;

        } while (n != 0);

        if (token == NJS_TOKEN_LINE_END) {

            token = njs_lexer_token(parser->lexer);
            if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
                return token;
            }

            if (njs_parser_expression_operator(token)) {
                continue;
            }
        }

        return token;

    found:

        node = njs_parser_node_alloc(vm);
        if (nxt_slow_path(node == NULL)) {
            return NJS_TOKEN_ERROR;
        }

        node->token = token;
        node->u.operation = op->operation;
        node->left = parser->node;
        node->left->dest = node;

        parser->code_size += op->size;

        token = njs_parser_token(parser);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        token = expr->next(vm, parser, expr->expression, token);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            return token;
        }

        node->right = parser->node;
        node->right->dest = node;
        parser->node = node;
    }
}