diff options
author | Jo-Philipp Wich <jo@mein.io> | 2022-10-04 21:43:34 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-04 21:43:34 +0200 |
commit | a5e59c9e93b9d435caa3fe786c745f0357bb3c0f (patch) | |
tree | 9ac67ae6b7d0d56f6bfdfe40299cddd4fe5c1eaf | |
parent | d64d5d685d86b38dda8a314b7d1404633e26b346 (diff) | |
parent | 76d396d3781b9c6a32897b5d93769db2c9f84d36 (diff) |
Merge pull request #108 from jow-/optimizations
Various improvements
-rw-r--r-- | compiler.c | 92 | ||||
-rw-r--r-- | lexer.c | 241 | ||||
-rw-r--r-- | main.c | 26 | ||||
-rw-r--r-- | tests/cram/test_basic.t | 7 | ||||
-rw-r--r-- | tests/custom/00_syntax/21_regex_literals | 26 | ||||
-rw-r--r-- | tests/custom/99_bugs/41_compiler_invalid_return_opcode | 20 | ||||
-rw-r--r-- | types.c | 3 |
7 files changed, 288 insertions, 127 deletions
@@ -46,9 +46,9 @@ static void uc_compiler_compile_ternary(uc_compiler_t *compiler); static void uc_compiler_compile_array(uc_compiler_t *compiler); static void uc_compiler_compile_object(uc_compiler_t *compiler); -static void uc_compiler_compile_declaration(uc_compiler_t *compiler); -static void uc_compiler_compile_statement(uc_compiler_t *compiler); -static void uc_compiler_compile_expstmt(uc_compiler_t *compiler); +static uc_tokentype_t uc_compiler_compile_declaration(uc_compiler_t *compiler); +static uc_tokentype_t uc_compiler_compile_statement(uc_compiler_t *compiler); +static uc_tokentype_t uc_compiler_compile_expstmt(uc_compiler_t *compiler); static uc_parse_rule_t uc_compiler_parse_rules[TK_ERROR + 1] = { @@ -646,7 +646,7 @@ uc_compiler_emit_exports(uc_compiler_t *compiler) { } static uc_function_t * -uc_compiler_finish(uc_compiler_t *compiler) +uc_compiler_finish(uc_compiler_t *compiler, uc_tokentype_t last_statement_type) { uc_chunk_t *chunk = uc_compiler_current_chunk(compiler); uc_locals_t *locals = &compiler->locals; @@ -1177,6 +1177,7 @@ uc_compiler_compile_assignment(uc_compiler_t *compiler, uc_value_t *var) static bool uc_compiler_compile_arrowfn(uc_compiler_t *compiler, uc_value_t *args, bool restarg) { + uc_tokentype_t last_statement_type = TK_NULL; bool array = (ucv_type(args) == UC_ARRAY); uc_compiler_t fncompiler = { 0 }; size_t i, pos, load_off; @@ -1220,15 +1221,19 @@ uc_compiler_compile_arrowfn(uc_compiler_t *compiler, uc_value_t *args, bool rest if (uc_compiler_parse_match(&fncompiler, TK_LBRACE)) { while (!uc_compiler_parse_check(&fncompiler, TK_RBRACE) && !uc_compiler_parse_check(&fncompiler, TK_EOF)) - uc_compiler_compile_declaration(&fncompiler); + last_statement_type = uc_compiler_compile_declaration(&fncompiler); uc_compiler_parse_consume(&fncompiler, TK_RBRACE); /* overwrite last pop result with return */ - if (fn->chunk.count) { + if (last_statement_type == TK_SCOL) uc_chunk_pop(&fn->chunk); - uc_compiler_emit_insn(&fncompiler, 0, I_RETURN); - } + + /* else load implicit null */ + else + uc_compiler_emit_insn(&fncompiler, 0, I_LNULL); + + uc_compiler_emit_insn(&fncompiler, 0, I_RETURN); } else { uc_compiler_parse_precedence(&fncompiler, P_ASSIGN); @@ -1247,7 +1252,7 @@ uc_compiler_compile_arrowfn(uc_compiler_t *compiler, uc_value_t *args, bool rest : fncompiler.upvals.entries[i].index); /* finalize function compiler */ - fn = uc_compiler_finish(&fncompiler); + fn = uc_compiler_finish(&fncompiler, TK_RETURN); if (fn) uc_compiler_set_u32(compiler, load_off, @@ -1604,19 +1609,22 @@ uc_compiler_compile_labelexpr(uc_compiler_t *compiler) ucv_put(label); } -static bool +static uc_tokentype_t uc_compiler_compile_delimitted_block(uc_compiler_t *compiler, uc_tokentype_t endtype) { + uc_tokentype_t last_statement_type = TK_NULL; + while (!uc_compiler_parse_check(compiler, endtype) && !uc_compiler_parse_check(compiler, TK_EOF)) - uc_compiler_compile_declaration(compiler); + last_statement_type = uc_compiler_compile_declaration(compiler); - return uc_compiler_parse_check(compiler, endtype); + return uc_compiler_parse_check(compiler, endtype) ? last_statement_type : TK_EOF; } static void uc_compiler_compile_funcexpr_common(uc_compiler_t *compiler, bool require_name) { + uc_tokentype_t last_statement_type = TK_NULL; uc_compiler_t fncompiler = { 0 }; uc_value_t *name = NULL; ssize_t slot = -1, pos; @@ -1688,11 +1696,11 @@ uc_compiler_compile_funcexpr_common(uc_compiler_t *compiler, bool require_name) /* parse and compile function body */ if (uc_compiler_parse_match(&fncompiler, TK_COLON)) { - uc_compiler_compile_delimitted_block(&fncompiler, TK_ENDFUNC); + last_statement_type = uc_compiler_compile_delimitted_block(&fncompiler, TK_ENDFUNC); uc_compiler_parse_consume(&fncompiler, TK_ENDFUNC); } else if (uc_compiler_parse_match(&fncompiler, TK_LBRACE)) { - uc_compiler_compile_delimitted_block(&fncompiler, TK_RBRACE); + last_statement_type = uc_compiler_compile_delimitted_block(&fncompiler, TK_RBRACE); uc_compiler_parse_consume(&fncompiler, TK_RBRACE); } else { @@ -1712,7 +1720,7 @@ uc_compiler_compile_funcexpr_common(uc_compiler_t *compiler, bool require_name) : fncompiler.upvals.entries[i].index); /* finalize function compiler */ - fn = uc_compiler_finish(&fncompiler); + fn = uc_compiler_finish(&fncompiler, last_statement_type); if (fn) uc_compiler_set_u32(compiler, load_off, @@ -2265,7 +2273,7 @@ uc_compiler_compile_while(uc_compiler_t *compiler) if (uc_compiler_parse_match(compiler, TK_COLON)) { uc_compiler_enter_scope(compiler); - if (!uc_compiler_compile_delimitted_block(compiler, TK_ENDWHILE)) + if (uc_compiler_compile_delimitted_block(compiler, TK_ENDWHILE) == TK_EOF) uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, "Expecting 'endwhile'"); else @@ -2369,7 +2377,7 @@ uc_compiler_compile_for_in(uc_compiler_t *compiler, bool local, uc_token_t *kvar if (uc_compiler_parse_match(compiler, TK_COLON)) { uc_compiler_enter_scope(compiler); - if (!uc_compiler_compile_delimitted_block(compiler, TK_ENDFOR)) + if (uc_compiler_compile_delimitted_block(compiler, TK_ENDFOR) == TK_EOF) uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, "Expecting 'endfor'"); else @@ -2487,7 +2495,7 @@ uc_compiler_compile_for_count(uc_compiler_t *compiler, bool local, uc_token_t *v if (uc_compiler_parse_match(compiler, TK_COLON)) { uc_compiler_enter_scope(compiler); - if (!uc_compiler_compile_delimitted_block(compiler, TK_ENDFOR)) + if (uc_compiler_compile_delimitted_block(compiler, TK_ENDFOR) == TK_EOF) uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, "Expecting 'endfor'"); else @@ -2862,7 +2870,6 @@ static void uc_compiler_compile_return(uc_compiler_t *compiler) { uc_chunk_t *chunk = uc_compiler_current_chunk(compiler); - size_t off = chunk->count; if (compiler->function->module) { uc_compiler_syntax_error(compiler, 0, "return must be inside function body"); @@ -2870,11 +2877,10 @@ uc_compiler_compile_return(uc_compiler_t *compiler) return; } - uc_compiler_compile_expstmt(compiler); - /* if we compiled an empty expression statement (`;`), load implicit null */ - if (chunk->count == off) + if (uc_compiler_compile_expstmt(compiler) == TK_NULL) uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LNULL); + /* otherwise overwrite the final I_POP instruction with I_RETURN */ else uc_chunk_pop(chunk); @@ -2906,26 +2912,30 @@ uc_compiler_compile_text(uc_compiler_t *compiler) uc_compiler_emit_insn(compiler, 0, I_PRINT); } -static void +static uc_tokentype_t uc_compiler_compile_block(uc_compiler_t *compiler) { + uc_tokentype_t last_statement_type = TK_NULL; + uc_compiler_enter_scope(compiler); while (!uc_compiler_parse_check(compiler, TK_RBRACE) && !uc_compiler_parse_check(compiler, TK_EOF)) - uc_compiler_compile_declaration(compiler); + last_statement_type = uc_compiler_compile_declaration(compiler); uc_compiler_parse_consume(compiler, TK_RBRACE); uc_compiler_leave_scope(compiler); + + return last_statement_type; } -static void +static uc_tokentype_t uc_compiler_compile_expstmt(uc_compiler_t *compiler) { /* empty statement */ if (uc_compiler_parse_match(compiler, TK_SCOL)) - return; + return TK_NULL; uc_compiler_compile_expression(compiler); @@ -2953,11 +2963,14 @@ uc_compiler_compile_expstmt(uc_compiler_t *compiler) } uc_compiler_emit_insn(compiler, 0, I_POP); + + return TK_SCOL; } -static void +static uc_tokentype_t uc_compiler_compile_statement(uc_compiler_t *compiler) { + uc_tokentype_t last_statement_type = compiler->parser->curr.type; uc_exprstack_t expr = { .token = compiler->parser->curr.type, .parent = compiler->exprstack @@ -2988,11 +3001,13 @@ uc_compiler_compile_statement(uc_compiler_t *compiler) else if (uc_compiler_parse_match(compiler, TK_LEXP)) uc_compiler_compile_tplexp(compiler); else if (uc_compiler_parse_match(compiler, TK_LBRACE)) - uc_compiler_compile_block(compiler); + last_statement_type = uc_compiler_compile_block(compiler); else - uc_compiler_compile_expstmt(compiler); + last_statement_type = uc_compiler_compile_expstmt(compiler); compiler->exprstack = expr.parent; + + return last_statement_type; } static void @@ -3570,9 +3585,11 @@ uc_compiler_compile_import(uc_compiler_t *compiler) ucv_put(namelist); } -static void +static uc_tokentype_t uc_compiler_compile_declaration(uc_compiler_t *compiler) { + uc_tokentype_t last_statement_type = compiler->parser->curr.type; + if (uc_compiler_parse_match(compiler, TK_LOCAL)) uc_compiler_compile_local(compiler); else if (uc_compiler_parse_match(compiler, TK_CONST)) @@ -3582,10 +3599,12 @@ uc_compiler_compile_declaration(uc_compiler_t *compiler) else if (uc_compiler_parse_match(compiler, TK_IMPORT)) uc_compiler_compile_import(compiler); else - uc_compiler_compile_statement(compiler); + last_statement_type = uc_compiler_compile_statement(compiler); if (compiler->parser->synchronizing) uc_compiler_parse_synchronize(compiler); + + return last_statement_type; } #endif /* NO_COMPILE */ @@ -3604,6 +3623,7 @@ uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, uc_progra uc_exprstack_t expr = { .token = TK_EOF }; uc_parser_t parser = { .config = config }; uc_compiler_t compiler = { .parser = &parser, .exprstack = &expr }; + uc_tokentype_t last_statement_type = TK_NULL; uc_program_t *progptr; uc_function_t *fn; const char *name; @@ -3629,9 +3649,15 @@ uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, uc_progra uc_compiler_parse_advance(&compiler); while (!uc_compiler_parse_match(&compiler, TK_EOF)) - uc_compiler_compile_declaration(&compiler); + last_statement_type = uc_compiler_compile_declaration(&compiler); + + if (!compiler.function->module && last_statement_type == TK_SCOL) { + uc_chunk_pop(uc_compiler_current_chunk(&compiler)); + uc_compiler_emit_insn(&compiler, 0, I_RETURN); + last_statement_type = TK_RETURN; + } - fn = uc_compiler_finish(&compiler); + fn = uc_compiler_finish(&compiler, last_statement_type); if (errp) { *errp = parser.error ? parser.error->buf : NULL; @@ -209,10 +209,118 @@ append_utf8(uc_lexer_t *lex, int code) { } static uc_token_t * -parse_string(uc_lexer_t *lex, int kind) +parse_escape(uc_lexer_t *lex, const char *retain) { int code, ch, i; + + /* unicode escape sequence */ + if (check_char(lex, 'u')) { + for (i = 0, code = 0; i < 4; i++) { + ch = next_char(lex); + + if (!isxdigit(ch)) + return emit_op(lex, -1, TK_ERROR, ucv_string_new("Invalid escape sequence")); + + code = code * 16 + hex(ch); + } + + /* is a leading surrogate value */ + if ((code & 0xFC00) == 0xD800) { + /* found a subsequent leading surrogate, ignore and emit replacement char for previous one */ + if (lex->lead_surrogate) + append_utf8(lex, 0xFFFD); + + /* store surrogate value and advance to next escape sequence */ + lex->lead_surrogate = code; + } + + /* is a trailing surrogate value */ + else if ((code & 0xFC00) == 0xDC00) { + /* found a trailing surrogate following a leading one, combine and encode */ + if (lex->lead_surrogate) { + code = 0x10000 + ((lex->lead_surrogate & 0x3FF) << 10) + (code & 0x3FF); + lex->lead_surrogate = 0; + } + + /* trailing surrogate not following a leading one, ignore and use replacement char */ + else { + code = 0xFFFD; + } + + append_utf8(lex, code); + } + + /* is a normal codepoint */ + else { + append_utf8(lex, code); + } + } + + /* hex escape sequence */ + else if (check_char(lex, 'x')) { + for (i = 0, code = 0; i < 2; i++) { + ch = next_char(lex); + + if (!isxdigit(ch)) + return emit_op(lex, -1, TK_ERROR, ucv_string_new("Invalid escape sequence")); + + code = code * 16 + hex(ch); + } + + append_utf8(lex, code); + } + + /* octal or letter */ + else { + /* try to parse octal sequence... */ + for (i = 0, code = 0, ch = lookahead_char(lex); + i < 3 && ch >= '0' && ch <= '7'; + i++, next_char(lex), ch = lookahead_char(lex)) { + code = code * 8 + dec(ch); + } + + if (i) { + if (code > 255) + return emit_op(lex, -3, TK_ERROR, ucv_string_new("Invalid escape sequence")); + + append_utf8(lex, code); + } + + /* ... no octal sequence, handle other escape */ + else { + ch = next_char(lex); + + switch (ch) { + case 'a': uc_vector_push(&lex->buffer, '\a'); break; + case 'b': uc_vector_push(&lex->buffer, '\b'); break; + case 'e': uc_vector_push(&lex->buffer, '\033'); break; + case 'f': uc_vector_push(&lex->buffer, '\f'); break; + case 'n': uc_vector_push(&lex->buffer, '\n'); break; + case 'r': uc_vector_push(&lex->buffer, '\r'); break; + case 't': uc_vector_push(&lex->buffer, '\t'); break; + case 'v': uc_vector_push(&lex->buffer, '\v'); break; + + case EOF: + return emit_op(lex, -2, TK_ERROR, ucv_string_new("Unterminated string")); + + default: + if (strchr(retain, ch)) + uc_vector_push(&lex->buffer, '\\'); + + uc_vector_push(&lex->buffer, ch); + } + } + } + + return NULL; +} + +static uc_token_t * +parse_string(uc_lexer_t *lex, int kind) +{ + uc_token_t *err; unsigned type; + int code, ch; size_t off; if (kind == '`') @@ -237,107 +345,74 @@ parse_string(uc_lexer_t *lex, int kind) uc_vector_push(&lex->buffer, '$'); break; - /* escape sequence */ - case '\\': - /* unicode escape sequence */ - if (type != TK_REGEXP && check_char(lex, 'u')) { - for (i = 0, code = 0; i < 4; i++) { - ch = next_char(lex); - - if (!isxdigit(ch)) - return emit_op(lex, -1, TK_ERROR, ucv_string_new("Invalid escape sequence")); + /* regexp bracket expression */ + case '[': + uc_vector_push(&lex->buffer, '['); - code = code * 16 + hex(ch); - } + if (type == TK_REGEXP) { + /* skip leading negation (^) */ + if (check_char(lex, '^')) + uc_vector_push(&lex->buffer, '^'); - /* is a leading surrogate value */ - if ((code & 0xFC00) == 0xD800) { - /* found a subsequent leading surrogate, ignore and emit replacement char for previous one */ - if (lex->lead_surrogate) - append_utf8(lex, 0xFFFD); + /* skip leading `]` - it is literal and not closing the bracket expr */ + if (check_char(lex, ']')) + uc_vector_push(&lex->buffer, ']'); - /* store surrogate value and advance to next escape sequence */ - lex->lead_surrogate = code; - } + /* read until closing `]` */ + for (ch = next_char(lex); ch != EOF; ch = next_char(lex)) { + if (ch == '\\') { + err = parse_escape(lex, "^"); - /* is a trailing surrogate value */ - else if ((code & 0xFC00) == 0xDC00) { - /* found a trailing surrogate following a leading one, combine and encode */ - if (lex->lead_surrogate) { - code = 0x10000 + ((lex->lead_surrogate & 0x3FF) << 10) + (code & 0x3FF); - lex->lead_surrogate = 0; - } + if (err) + return err; - /* trailing surrogate not following a leading one, ignore and use replacement char */ - else { - code = 0xFFFD; + continue; } - append_utf8(lex, code); - } + uc_vector_push(&lex->buffer, ch); - /* is a normal codepoint */ - else { - append_utf8(lex, code); - } - } + if (ch == ']') + break; - /* hex escape sequence */ - else if (type != TK_REGEXP && check_char(lex, 'x')) { - for (i = 0, code = 0; i < 2; i++) { - ch = next_char(lex); + /* skip nested char classes / equivalence classes / collating chars */ + if (ch == '[') { + code = lookahead_char(lex); - if (!isxdigit(ch)) - return emit_op(lex, -1, TK_ERROR, ucv_string_new("Invalid escape sequence")); + if (code == ':' || code == '.' || code == '=') { + uc_vector_push(&lex->buffer, code); + next_char(lex); - code = code * 16 + hex(ch); - } + for (ch = next_char(lex); ch != EOF; ch = next_char(lex)) { + if (ch == '\\') { + err = parse_escape(lex, ""); - append_utf8(lex, code); - } + if (err) + return err; - /* octal or letter */ - else { - /* try to parse octal sequence... */ - for (i = 0, code = 0, ch = lookahead_char(lex); - kind != '/' && i < 3 && ch >= '0' && ch <= '7'; - i++, next_char(lex), ch = lookahead_char(lex)) { - code = code * 8 + dec(ch); - } + continue; + } - if (i) { - if (code > 255) - return emit_op(lex, -3, TK_ERROR, ucv_string_new("Invalid escape sequence")); + uc_vector_push(&lex->buffer, ch); - append_utf8(lex, code); + if (ch == code && check_char(lex, ']')) { + uc_vector_push(&lex->buffer, ']'); + break; + } + } + } + } } + } - /* ... no octal sequence, handle other escape */ - else { - ch = next_char(lex); - - switch (ch) { - case 'a': uc_vector_push(&lex->buffer, '\a'); break; - case 'b': uc_vector_push(&lex->buffer, '\b'); break; - case 'e': uc_vector_push(&lex->buffer, '\033'); break; - case 'f': uc_vector_push(&lex->buffer, '\f'); break; - case 'n': uc_vector_push(&lex->buffer, '\n'); break; - case 'r': uc_vector_push(&lex->buffer, '\r'); break; - case 't': uc_vector_push(&lex->buffer, '\t'); break; - case 'v': uc_vector_push(&lex->buffer, '\v'); break; - - case EOF: - return emit_op(lex, -2, TK_ERROR, ucv_string_new("Unterminated string")); + break; - default: - /* regex mode => retain backslash */ - if (type == TK_REGEXP) - uc_vector_push(&lex->buffer, '\\'); + /* escape sequence */ + case '\\': + err = parse_escape(lex, + (type == TK_REGEXP) ? "^.[$()|*+?{\\" : ""); - uc_vector_push(&lex->buffer, ch); - } - } - } + if (err) + return err; break; @@ -51,6 +51,9 @@ print_usage(const char *app) "-e \"expression\"\n" " Execute the given expression as ucode program.\n\n" + "-p \"expression\"\n" + " Like `-e` but print the result of expression.\n\n" + "-t\n" " Enable VM execution tracing.\n\n" @@ -109,7 +112,7 @@ print_usage(const char *app) static int -compile(uc_vm_t *vm, uc_source_t *src, FILE *precompile, bool strip, char *interp) +compile(uc_vm_t *vm, uc_source_t *src, FILE *precompile, bool strip, char *interp, bool print_result) { uc_value_t *res = NULL; uc_program_t *program; @@ -141,6 +144,14 @@ compile(uc_vm_t *vm, uc_source_t *src, FILE *precompile, bool strip, char *inter switch (rc) { case STATUS_OK: + if (print_result) { + uc_vm_stack_push(vm, res); + uc_vm_stack_push(vm, ucv_string_new("\n")); + uc_stdlib_function("print")(vm, 2); + uc_vm_stack_pop(vm); + uc_vm_stack_pop(vm); + } + rc = 0; break; @@ -475,12 +486,12 @@ appname(const char *argv0) int main(int argc, char **argv) { - const char *optspec = "he:tg:ST::RD:F:U:l:L:c::o:s"; + const char *optspec = "he:p:tg:ST::RD:F:U:l:L:c::o:s"; + bool strip = false, print_result = false; char *interp = "/usr/bin/env ucode"; uc_source_t *source = NULL; FILE *precompile = NULL; char *outfile = NULL; - bool strip = false; uc_vm_t vm = { 0 }; int opt, rv = 0; const char *app; @@ -557,6 +568,11 @@ main(int argc, char **argv) source = uc_source_new_buffer("[-e argument]", xstrdup(optarg), strlen(optarg)); break; + case 'p': + source = uc_source_new_buffer("[-p argument]", xstrdup(optarg), strlen(optarg)); + print_result = true; + break; + case 't': uc_vm_trace_set(&vm, 1); break; @@ -624,7 +640,7 @@ main(int argc, char **argv) } if (!source) { - fprintf(stderr, "Require either -e expression or source file\n"); + fprintf(stderr, "Require either -e/-p expression or source file\n"); rv = 1; goto out; } @@ -654,7 +670,7 @@ main(int argc, char **argv) ucv_put(o); - rv = compile(&vm, source, precompile, strip, interp); + rv = compile(&vm, source, precompile, strip, interp, print_result); out: uc_search_path_free(&config.module_search_path); diff --git a/tests/cram/test_basic.t b/tests/cram/test_basic.t index c33dee9..d7f78a3 100644 --- a/tests/cram/test_basic.t +++ b/tests/cram/test_basic.t @@ -22,6 +22,9 @@ check that ucode provides exepected help: -e "expression" Execute the given expression as ucode program. + -p "expression" + Like `-e` but print the result of expression. + -t Enable VM execution tracing. @@ -85,7 +88,7 @@ check that ucode prints greetings: check that ucode provides proper error messages: $ touch lib.uc; ucode -l lib - Require either -e expression or source file + Require either -e/-p expression or source file [1] $ ucode -l foo -e ' ' @@ -101,7 +104,7 @@ check that ucode provides proper error messages: check that ucode can load fs module: $ ucode -l fs - Require either -e expression or source file + Require either -e/-p expression or source file [1] $ ucode -l fs -e ' ' diff --git a/tests/custom/00_syntax/21_regex_literals b/tests/custom/00_syntax/21_regex_literals index d7ba7c4..7466a2e 100644 --- a/tests/custom/00_syntax/21_regex_literals +++ b/tests/custom/00_syntax/21_regex_literals @@ -4,7 +4,7 @@ within regular expression literals is subject of the underlying regular expression engine. -- Expect stdout -- -[ "/Hello world/", "/test/gis", "/test/g", "/test1 \\\/ test2/", "/\\x31\n\\.\u0007\b\\c\\u2600\\\\/" ] +[ "/Hello world/", "/test/gis", "/test/g", "/test1 / test2/", "/1\n\\.\u0007\bc☀\\\\/" ] -- End -- -- Testcase -- @@ -93,3 +93,27 @@ In line 7, byte 30: } %} -- End -- + + +Testing that slashes within character classes are not treated as regex +literal delimitters. + +-- Expect stdout -- +[ + "/[/]/", + "/[[./.]/]/", + "/[[:alpha:]/]/", + "/[[=/=]/]/" +] +-- End -- + +-- Testcase -- +{% + printf("%.J\n", [ + /[/]/, + /[[./.]/]/, + /[[:alpha:]/]/, + /[[=/=]/]/ + ]); +%} +-- End -- diff --git a/tests/custom/99_bugs/41_compiler_invalid_return_opcode b/tests/custom/99_bugs/41_compiler_invalid_return_opcode new file mode 100644 index 0000000..a97dae9 --- /dev/null +++ b/tests/custom/99_bugs/41_compiler_invalid_return_opcode @@ -0,0 +1,20 @@ +When compiling an arrow function body with a trailing loop or conditional +statement having an empty body, the emitted return code incorrectly +overwrote the target address of the jump instruction. + +-- Testcase -- +(() => { + if(0) + ; +})(); + +print("OK\n"); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +OK +-- End -- @@ -1431,9 +1431,6 @@ ucv_to_string_json_encoded(uc_stringbuf_t *pb, const char *s, size_t len, bool r break; case '/': - if (regexp) - ucv_stringbuf_append(pb, "\\"); - ucv_stringbuf_append(pb, "/"); break; |