예제 #1
0
static nxt_int_t
njs_parser_statement_semicolon(njs_vm_t *vm, njs_parser_t *parser,
    void *data)
{
    njs_token_t        token;
    njs_parser_node_t  *node;

    node = data;

    switch (parser->lexer->token) {

    case NJS_TOKEN_SEMICOLON:
        token = njs_parser_token(parser);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            /* TODO: NJS_TOKEN_AGAIN */
            return NXT_ERROR;
        }

        /* Fall through. */

    case NJS_TOKEN_END:

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

        return NXT_OK;

    default:
        break;
    }

    return NXT_ERROR;
}
예제 #2
0
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;
}
예제 #3
0
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);
    }
}
예제 #4
0
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;
}
예제 #5
0
static njs_token_t
njs_parser_property_brackets(njs_vm_t *vm, njs_parser_t *parser,
    njs_token_t token)
{
    token = njs_parser_expression(vm, parser, token);
    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
        return token;
    }

    if (nxt_slow_path(token != NJS_TOKEN_CLOSE_BRACKET)) {
        return NJS_TOKEN_ERROR;
    }

    return njs_parser_token(parser);
}
예제 #6
0
static nxt_int_t
njs_parser_switch(njs_vm_t *vm, njs_parser_t *parser, void *data)
{
    nxt_int_t                    ret;
    nxt_uint_t                   n;
    njs_token_t                  token;
    njs_parser_switch_t          *swtch;
    const njs_parser_terminal_t  *term;

    swtch = data;
    token = parser->lexer->token;

    n = swtch->count;
    term = swtch->terminal;

    do {
        if (token == term->token || term->token == NJS_TOKEN_ANY) {
            ret = term->operation(vm, parser, token, term->data);
            if (nxt_slow_path(ret != NXT_OK)) {
                return NXT_ERROR;
            }

            ret = njs_parser_stack_push(vm, parser, term->primed);
            if (nxt_slow_path(ret != NXT_OK)) {
                return NXT_ERROR;
            }

            if (term->token != NJS_TOKEN_ANY) {
                token = njs_parser_token(parser);
                if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
                    /* TODO: NJS_TOKEN_AGAIN */
                    return NXT_ERROR;
                }
            }

            return NXT_OK;
        }

        term++;
        n--;

    } while (n != 0);

    return NXT_OK;
}
예제 #7
0
static nxt_int_t
njs_parser_test_token(njs_vm_t *vm, njs_parser_t *parser, void *data)
{
    njs_token_t  token;

    token = (njs_token_t) data;

    if (parser->lexer->token == token) {
        token = njs_parser_token(parser);
        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
            /* TODO: NJS_TOKEN_AGAIN */
            return NXT_ERROR;
        }

        return NXT_OK;
    }

    vm->exception = &njs_exception_syntax_error;

    return NXT_ERROR;
}
예제 #8
0
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);
}
예제 #9
0
njs_parser_node_t *
njs_nonrecursive_parser(njs_vm_t *vm, njs_parser_t *parser)
{
    nxt_int_t                     ret;
    njs_token_t                   token;
    njs_parser_stack_operation_t  operation;

    if (top < 0) {
        njs_parser_stack_push(vm, parser, njs_parser_statement);
    }

    token = njs_parser_token(parser);
    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
        /* TODO: NJS_TOKEN_AGAIN */
        return NULL;
    }

    do {
        operation = (njs_parser_stack_operation_t) njs_parser_stack_pop(parser);

        if (operation == NULL) {

            if (parser->lexer->token == NJS_TOKEN_END) {
                return parser->node;
            }

            break;
        }

        ret = operation(vm, parser, njs_parser_stack_pop(parser));

    } while (ret == NXT_OK);

    nxt_thread_log_error(NXT_LOG_ERR, "unexpected token");

    return NULL;
}
예제 #10
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;
        }
    }
}
예제 #11
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;
}
예제 #12
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;
    }
}
예제 #13
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);
    }
}
예제 #14
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;
            }
        }
    }
}
예제 #15
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;
            }
        }
    }
}