/** * Parse a max 3 digit long octal number from input string iterator. * * @return uint32_t - parsed octal number */ static uint32_t re_parse_octal (re_parser_ctx_t *parser_ctx_p) /**< RegExp parser context */ { uint32_t number = 0; for (int index = 0; index < 3 && parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p && lit_char_is_octal_digit (*parser_ctx_p->input_curr_p); index++) { number = number * 8 + lit_char_hex_to_int (*parser_ctx_p->input_curr_p++); } return number; } /* re_parse_octal */
/** * Read the input pattern and parse the range of character class * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t re_parse_char_class (re_parser_ctx_t *parser_ctx_p, /**< number of classes */ re_char_class_callback append_char_class, /**< callback function, * which adds the char-ranges * to the bytecode */ void *re_ctx_p, /**< regexp compiler context */ re_token_t *out_token_p) /**< out: output token */ { re_token_type_t token_type = ((re_compiler_ctx_t *) re_ctx_p)->current_token.type; out_token_p->qmax = out_token_p->qmin = 1; uint32_t start = RE_CHAR_UNDEF; bool is_range = false; parser_ctx_p->num_of_classes = 0; if (lit_utf8_peek_prev (parser_ctx_p->input_curr_p) != LIT_CHAR_LEFT_SQUARE) { lit_utf8_decr (&parser_ctx_p->input_curr_p); lit_utf8_decr (&parser_ctx_p->input_curr_p); } do { if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { return ecma_raise_syntax_error ("invalid character class, end of string"); } uint32_t ch = lit_utf8_read_next (&parser_ctx_p->input_curr_p); if (ch == LIT_CHAR_RIGHT_SQUARE) { if (start != RE_CHAR_UNDEF) { append_char_class (re_ctx_p, start, start); } break; } else if (ch == LIT_CHAR_MINUS) { if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { return ecma_raise_syntax_error ("invalid character class, end of string after '-'"); } if (start != RE_CHAR_UNDEF && !is_range && *parser_ctx_p->input_curr_p != LIT_CHAR_RIGHT_SQUARE) { is_range = true; continue; } } else if (ch == LIT_CHAR_BACKSLASH) { if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { return ecma_raise_syntax_error ("invalid character class, end of string after '\\'"); } ch = *parser_ctx_p->input_curr_p++; if (ch == LIT_CHAR_LOWERCASE_B) { ch = LIT_CHAR_BS; } else if (ch == LIT_CHAR_LOWERCASE_F) { ch = LIT_CHAR_FF; } else if (ch == LIT_CHAR_LOWERCASE_N) { ch = LIT_CHAR_LF; } else if (ch == LIT_CHAR_LOWERCASE_T) { ch = LIT_CHAR_TAB; } else if (ch == LIT_CHAR_LOWERCASE_R) { ch = LIT_CHAR_CR; } else if (ch == LIT_CHAR_LOWERCASE_V) { ch = LIT_CHAR_VTAB; } else if (ch == LIT_CHAR_LOWERCASE_C) { if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p) { ch = *parser_ctx_p->input_curr_p; if ((ch >= LIT_CHAR_ASCII_UPPERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_UPPERCASE_LETTERS_END) || (ch >= LIT_CHAR_ASCII_LOWERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_LOWERCASE_LETTERS_END) || (ch >= LIT_CHAR_0 && ch <= LIT_CHAR_9)) { /* See ECMA-262 v5, 15.10.2.10 (Point 3) */ ch = (ch % 32); parser_ctx_p->input_curr_p++; } else { ch = LIT_CHAR_LOWERCASE_C; } } } else if (ch == LIT_CHAR_LOWERCASE_X) { lit_code_point_t code_point; if (!lit_read_code_point_from_hex (parser_ctx_p->input_curr_p, 2, &code_point)) { return ecma_raise_syntax_error ("invalid character class, end of string after '\\x'"); } parser_ctx_p->input_curr_p += 2; append_char_class (re_ctx_p, code_point, code_point); } else if (ch == LIT_CHAR_LOWERCASE_U) { lit_code_point_t code_point; if (!lit_read_code_point_from_hex (parser_ctx_p->input_curr_p, 4, &code_point)) { return ecma_raise_syntax_error ("invalid character class, end of string after '\\u'"); } parser_ctx_p->input_curr_p += 4; append_char_class (re_ctx_p, code_point, code_point); } else if (ch == LIT_CHAR_LOWERCASE_D) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_ASCII_DIGITS_BEGIN, LIT_CHAR_ASCII_DIGITS_END); ch = RE_CHAR_UNDEF; } else if (ch == LIT_CHAR_UPPERCASE_D) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_NULL, LIT_CHAR_ASCII_DIGITS_BEGIN - 1); append_char_class (re_ctx_p, LIT_CHAR_ASCII_DIGITS_END + 1, LIT_UTF16_CODE_UNIT_MAX); ch = RE_CHAR_UNDEF; } else if (ch == LIT_CHAR_LOWERCASE_S) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_TAB, LIT_CHAR_CR); append_char_class (re_ctx_p, LIT_CHAR_SP, LIT_CHAR_SP); append_char_class (re_ctx_p, LIT_CHAR_NBSP, LIT_CHAR_NBSP); append_char_class (re_ctx_p, 0x1680UL, 0x1680UL); /* Ogham Space Mark */ append_char_class (re_ctx_p, 0x180EUL, 0x180EUL); /* Mongolian Vowel Separator */ append_char_class (re_ctx_p, 0x2000UL, 0x200AUL); /* En Quad - Hair Space */ append_char_class (re_ctx_p, LIT_CHAR_LS, LIT_CHAR_PS); append_char_class (re_ctx_p, 0x202FUL, 0x202FUL); /* Narrow No-Break Space */ append_char_class (re_ctx_p, 0x205FUL, 0x205FUL); /* Medium Mathematical Space */ append_char_class (re_ctx_p, 0x3000UL, 0x3000UL); /* Ideographic Space */ append_char_class (re_ctx_p, LIT_CHAR_BOM, LIT_CHAR_BOM); ch = RE_CHAR_UNDEF; } else if (ch == LIT_CHAR_UPPERCASE_S) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_NULL, LIT_CHAR_TAB - 1); append_char_class (re_ctx_p, LIT_CHAR_CR + 1, LIT_CHAR_SP - 1); append_char_class (re_ctx_p, LIT_CHAR_SP + 1, LIT_CHAR_NBSP - 1); append_char_class (re_ctx_p, LIT_CHAR_NBSP + 1, 0x167FUL); append_char_class (re_ctx_p, 0x1681UL, 0x180DUL); append_char_class (re_ctx_p, 0x180FUL, 0x1FFFUL); append_char_class (re_ctx_p, 0x200BUL, LIT_CHAR_LS - 1); append_char_class (re_ctx_p, LIT_CHAR_PS + 1, 0x202EUL); append_char_class (re_ctx_p, 0x2030UL, 0x205EUL); append_char_class (re_ctx_p, 0x2060UL, 0x2FFFUL); append_char_class (re_ctx_p, 0x3001UL, LIT_CHAR_BOM - 1); append_char_class (re_ctx_p, LIT_CHAR_BOM + 1, LIT_UTF16_CODE_UNIT_MAX); ch = RE_CHAR_UNDEF; } else if (ch == LIT_CHAR_LOWERCASE_W) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_0, LIT_CHAR_9); append_char_class (re_ctx_p, LIT_CHAR_UPPERCASE_A, LIT_CHAR_UPPERCASE_Z); append_char_class (re_ctx_p, LIT_CHAR_UNDERSCORE, LIT_CHAR_UNDERSCORE); append_char_class (re_ctx_p, LIT_CHAR_LOWERCASE_A, LIT_CHAR_LOWERCASE_Z); ch = RE_CHAR_UNDEF; } else if (ch == LIT_CHAR_UPPERCASE_W) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_NULL, LIT_CHAR_0 - 1); append_char_class (re_ctx_p, LIT_CHAR_9 + 1, LIT_CHAR_UPPERCASE_A - 1); append_char_class (re_ctx_p, LIT_CHAR_UPPERCASE_Z + 1, LIT_CHAR_UNDERSCORE - 1); append_char_class (re_ctx_p, LIT_CHAR_UNDERSCORE + 1, LIT_CHAR_LOWERCASE_A - 1); append_char_class (re_ctx_p, LIT_CHAR_LOWERCASE_Z + 1, LIT_UTF16_CODE_UNIT_MAX); ch = RE_CHAR_UNDEF; } else if (ch <= LIT_UTF16_CODE_UNIT_MAX && lit_char_is_octal_digit ((ecma_char_t) ch) && ch != LIT_CHAR_0) { parser_ctx_p->input_curr_p--; ch = re_parse_octal (parser_ctx_p); } } /* ch == LIT_CHAR_BACKSLASH */ if (ch == RE_CHAR_UNDEF) { if (start != RE_CHAR_UNDEF) { if (is_range) { return ecma_raise_syntax_error ("invalid character class, invalid range"); } else { append_char_class (re_ctx_p, start, start); start = RE_CHAR_UNDEF; } } } else { if (start != RE_CHAR_UNDEF) { if (is_range) { if (start > ch) { return ecma_raise_syntax_error ("invalid character class, wrong order"); } else { append_char_class (re_ctx_p, start, ch); start = RE_CHAR_UNDEF; is_range = false; } } else { append_char_class (re_ctx_p, start, start); start = ch; } } else { start = ch; } } } while (token_type == RE_TOK_START_CHAR_CLASS || token_type == RE_TOK_START_INV_CHAR_CLASS); return re_parse_iterator (parser_ctx_p, out_token_p); } /* re_parse_char_class */
/** * Read the input pattern and parse the next token for the RegExp compiler * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t re_parse_next_token (re_parser_ctx_t *parser_ctx_p, /**< RegExp parser context */ re_token_t *out_token_p) /**< out: output token */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { out_token_p->type = RE_TOK_EOF; return ret_value; } ecma_char_t ch = lit_utf8_read_next (&parser_ctx_p->input_curr_p); switch (ch) { case LIT_CHAR_VLINE: { out_token_p->type = RE_TOK_ALTERNATIVE; break; } case LIT_CHAR_CIRCUMFLEX: { out_token_p->type = RE_TOK_ASSERT_START; break; } case LIT_CHAR_DOLLAR_SIGN: { out_token_p->type = RE_TOK_ASSERT_END; break; } case LIT_CHAR_DOT: { out_token_p->type = RE_TOK_PERIOD; ret_value = re_parse_iterator (parser_ctx_p, out_token_p); break; } case LIT_CHAR_BACKSLASH: { if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { return ecma_raise_syntax_error ("invalid regular experssion"); } out_token_p->type = RE_TOK_CHAR; ch = lit_utf8_read_next (&parser_ctx_p->input_curr_p); if (ch == LIT_CHAR_LOWERCASE_B) { out_token_p->type = RE_TOK_ASSERT_WORD_BOUNDARY; } else if (ch == LIT_CHAR_UPPERCASE_B) { out_token_p->type = RE_TOK_ASSERT_NOT_WORD_BOUNDARY; } else if (ch == LIT_CHAR_LOWERCASE_F) { out_token_p->value = LIT_CHAR_FF; } else if (ch == LIT_CHAR_LOWERCASE_N) { out_token_p->value = LIT_CHAR_LF; } else if (ch == LIT_CHAR_LOWERCASE_T) { out_token_p->value = LIT_CHAR_TAB; } else if (ch == LIT_CHAR_LOWERCASE_R) { out_token_p->value = LIT_CHAR_CR; } else if (ch == LIT_CHAR_LOWERCASE_V) { out_token_p->value = LIT_CHAR_VTAB; } else if (ch == LIT_CHAR_LOWERCASE_C) { if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p) { ch = *parser_ctx_p->input_curr_p; if ((ch >= LIT_CHAR_ASCII_UPPERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_UPPERCASE_LETTERS_END) || (ch >= LIT_CHAR_ASCII_LOWERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_LOWERCASE_LETTERS_END)) { out_token_p->value = (ch % 32); parser_ctx_p->input_curr_p++; } else { out_token_p->value = LIT_CHAR_BACKSLASH; parser_ctx_p->input_curr_p--; } } else { out_token_p->value = LIT_CHAR_BACKSLASH; parser_ctx_p->input_curr_p--; } } else if (ch == LIT_CHAR_LOWERCASE_X && re_hex_lookup (parser_ctx_p, 2)) { lit_code_point_t code_point; if (!lit_read_code_point_from_hex (parser_ctx_p->input_curr_p, 2, &code_point)) { return ecma_raise_syntax_error ("decode error"); } parser_ctx_p->input_curr_p += 2; out_token_p->value = code_point; } else if (ch == LIT_CHAR_LOWERCASE_U && re_hex_lookup (parser_ctx_p, 4)) { lit_code_point_t code_point; if (!lit_read_code_point_from_hex (parser_ctx_p->input_curr_p, 4, &code_point)) { return ecma_raise_syntax_error ("decode error"); } parser_ctx_p->input_curr_p += 4; out_token_p->value = code_point; } else if (ch == LIT_CHAR_LOWERCASE_D) { out_token_p->type = RE_TOK_DIGIT; break; } else if (ch == LIT_CHAR_UPPERCASE_D) { out_token_p->type = RE_TOK_NOT_DIGIT; break; } else if (ch == LIT_CHAR_LOWERCASE_S) { out_token_p->type = RE_TOK_WHITE; break; } else if (ch == LIT_CHAR_UPPERCASE_S) { out_token_p->type = RE_TOK_NOT_WHITE; break; } else if (ch == LIT_CHAR_LOWERCASE_W) { out_token_p->type = RE_TOK_WORD_CHAR; break; } else if (ch == LIT_CHAR_UPPERCASE_W) { out_token_p->type = RE_TOK_NOT_WORD_CHAR; break; } else if (lit_char_is_decimal_digit (ch)) { if (ch == LIT_CHAR_0) { if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p && lit_char_is_decimal_digit (*parser_ctx_p->input_curr_p)) { return ecma_raise_syntax_error ("RegExp escape pattern error."); } out_token_p->value = LIT_UNICODE_CODE_POINT_NULL; } else { if (parser_ctx_p->num_of_groups == -1) { re_count_num_of_groups (parser_ctx_p); } if (parser_ctx_p->num_of_groups) { parser_ctx_p->input_curr_p--; uint32_t number = 0; int index = 0; do { if (index >= RE_MAX_RE_DECESC_DIGITS) { ret_value = ecma_raise_syntax_error ("RegExp escape pattern error: decimal escape too long."); return ret_value; } if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { break; } ecma_char_t digit = *parser_ctx_p->input_curr_p++; if (!lit_char_is_decimal_digit (digit)) { parser_ctx_p->input_curr_p--; break; } number = number * 10 + lit_char_hex_to_int (digit); index++; } while (true); if ((int) number <= parser_ctx_p->num_of_groups) { out_token_p->type = RE_TOK_BACKREFERENCE; } else /* Invalid backreference, fallback to octal */ { /* Rewind to start of number. */ parser_ctx_p->input_curr_p -= index; /* Try to reparse as octal. */ ecma_char_t digit = *parser_ctx_p->input_curr_p; if (!lit_char_is_octal_digit (digit)) { /* Not octal, keep digit character value. */ number = digit; parser_ctx_p->input_curr_p++; } else { number = re_parse_octal (parser_ctx_p); } } out_token_p->value = number; } else /* Invalid backreference, fallback to octal if possible */ { if (!lit_char_is_octal_digit (ch)) { /* Not octal, keep character value. */ out_token_p->value = ch; } else { parser_ctx_p->input_curr_p--; out_token_p->value = re_parse_octal (parser_ctx_p); } } } } else { out_token_p->value = ch; } ret_value = re_parse_iterator (parser_ctx_p, out_token_p); break; } case LIT_CHAR_LEFT_PAREN: { if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { return ecma_raise_syntax_error ("Unterminated group"); } if (*parser_ctx_p->input_curr_p == LIT_CHAR_QUESTION) { parser_ctx_p->input_curr_p++; if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { return ecma_raise_syntax_error ("Invalid group"); } ch = *parser_ctx_p->input_curr_p++; if (ch == LIT_CHAR_EQUALS) { /* (?= */ out_token_p->type = RE_TOK_ASSERT_START_POS_LOOKAHEAD; } else if (ch == LIT_CHAR_EXCLAMATION) { /* (?! */ out_token_p->type = RE_TOK_ASSERT_START_NEG_LOOKAHEAD; } else if (ch == LIT_CHAR_COLON) { /* (?: */ out_token_p->type = RE_TOK_START_NON_CAPTURE_GROUP; } else { return ecma_raise_syntax_error ("Invalid group"); } } else { /* ( */ out_token_p->type = RE_TOK_START_CAPTURE_GROUP; } break; } case LIT_CHAR_RIGHT_PAREN: { out_token_p->type = RE_TOK_END_GROUP; ret_value = re_parse_iterator (parser_ctx_p, out_token_p); break; } case LIT_CHAR_LEFT_SQUARE: { out_token_p->type = RE_TOK_START_CHAR_CLASS; if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { return ecma_raise_syntax_error ("invalid character class"); } if (*parser_ctx_p->input_curr_p == LIT_CHAR_CIRCUMFLEX) { out_token_p->type = RE_TOK_START_INV_CHAR_CLASS; parser_ctx_p->input_curr_p++; } break; } case LIT_CHAR_QUESTION: case LIT_CHAR_ASTERISK: case LIT_CHAR_PLUS: case LIT_CHAR_LEFT_BRACE: { return ecma_raise_syntax_error ("Invalid RegExp token."); } case LIT_CHAR_NULL: { out_token_p->type = RE_TOK_EOF; break; } default: { out_token_p->type = RE_TOK_CHAR; out_token_p->value = ch; ret_value = re_parse_iterator (parser_ctx_p, out_token_p); break; } } return ret_value; } /* re_parse_next_token */
/** * Transforming escape sequences in the charset, outputting converted string to specified buffer * * Note: * Size of string with transformed escape sequences is always * less or equal to size of corresponding source string. * * @return size of converted string */ static lit_utf8_size_t lexer_transform_escape_sequences (const jerry_api_char_t *source_str_p, /**< string to convert, * located in source buffer */ lit_utf8_size_t source_str_size, /**< size of the string and of the output buffer */ jerry_api_char_t *output_str_buf_p) /**< output buffer for converted string */ { if (source_str_size == 0) { return 0; } else { JERRY_ASSERT (source_str_p != NULL); } lit_utf8_byte_t *output_str_buf_iter_p = output_str_buf_p; const size_t output_str_buf_size = source_str_size; bool is_correct_sequence = true; lit_utf8_iterator_t source_str_iter = lit_utf8_iterator_create (source_str_p, source_str_size); ecma_char_t prev_converted_char = LIT_CHAR_NULL; while (!lit_utf8_iterator_is_eos (&source_str_iter)) { ecma_char_t converted_char; const ecma_char_t next_char = lit_utf8_iterator_read_next (&source_str_iter); if (next_char == LIT_CHAR_BACKSLASH) { if (lit_utf8_iterator_is_eos (&source_str_iter)) { is_correct_sequence = false; break; } const ecma_char_t char_after_next = lit_utf8_iterator_read_next (&source_str_iter); if (lit_char_is_decimal_digit (char_after_next)) { if (lit_char_is_octal_digit (char_after_next)) { if (char_after_next == LIT_CHAR_0 && (lit_utf8_iterator_is_eos (&source_str_iter) || !lit_char_is_octal_digit (lit_utf8_iterator_peek_next (&source_str_iter)))) { converted_char = LIT_CHAR_NULL; } else { /* Implementation-defined (ECMA-262 v5, B.1.2): octal escape sequences are not implemented */ is_correct_sequence = false; break; } } else { converted_char = char_after_next; } } else if (char_after_next == LIT_CHAR_LOWERCASE_U || char_after_next == LIT_CHAR_LOWERCASE_X) { if (!lexer_convert_escape_sequence_digits_to_char (&source_str_iter, char_after_next == LIT_CHAR_LOWERCASE_U, &converted_char)) { is_correct_sequence = false; break; } } else if (lit_char_is_line_terminator (char_after_next)) { /* Skip \, followed by a LineTerminatorSequence (ECMA-262, v5, 7.3) */ if (char_after_next == LIT_CHAR_CR && !lit_utf8_iterator_is_eos (&source_str_iter) && lit_utf8_iterator_peek_next (&source_str_iter) == LIT_CHAR_LF) { lit_utf8_iterator_incr (&source_str_iter); } continue; } else { lexer_convert_single_escape_character (char_after_next, &converted_char); } } else { converted_char = next_char; } if (lit_is_code_unit_high_surrogate (prev_converted_char) && lit_is_code_unit_low_surrogate (converted_char)) { output_str_buf_iter_p -= LIT_UTF8_MAX_BYTES_IN_CODE_UNIT; lit_code_point_t code_point = lit_convert_surrogate_pair_to_code_point (prev_converted_char, converted_char); output_str_buf_iter_p += lit_code_point_to_utf8 (code_point, output_str_buf_iter_p); } else { output_str_buf_iter_p += lit_code_unit_to_utf8 (converted_char, output_str_buf_iter_p); JERRY_ASSERT (output_str_buf_iter_p <= output_str_buf_p + output_str_buf_size); } prev_converted_char = converted_char; } if (is_correct_sequence) { return (lit_utf8_size_t) (output_str_buf_iter_p - output_str_buf_p); } else { PARSE_ERROR (JSP_EARLY_ERROR_SYNTAX, "Illegal escape sequence", token_start_pos); } } /* lexer_transform_escape_sequences */