summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2022-10-04 21:43:34 +0200
committerGitHub <noreply@github.com>2022-10-04 21:43:34 +0200
commita5e59c9e93b9d435caa3fe786c745f0357bb3c0f (patch)
tree9ac67ae6b7d0d56f6bfdfe40299cddd4fe5c1eaf
parentd64d5d685d86b38dda8a314b7d1404633e26b346 (diff)
parent76d396d3781b9c6a32897b5d93769db2c9f84d36 (diff)
Merge pull request #108 from jow-/optimizations
Various improvements
-rw-r--r--compiler.c92
-rw-r--r--lexer.c241
-rw-r--r--main.c26
-rw-r--r--tests/cram/test_basic.t7
-rw-r--r--tests/custom/00_syntax/21_regex_literals26
-rw-r--r--tests/custom/99_bugs/41_compiler_invalid_return_opcode20
-rw-r--r--types.c3
7 files changed, 288 insertions, 127 deletions
diff --git a/compiler.c b/compiler.c
index 2cc9244..a4f220f 100644
--- a/compiler.c
+++ b/compiler.c
@@ -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;
diff --git a/lexer.c b/lexer.c
index 7c7788a..786e495 100644
--- a/lexer.c
+++ b/lexer.c
@@ -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;
diff --git a/main.c b/main.c
index 03549fe..3957483 100644
--- a/main.c
+++ b/main.c
@@ -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 --
diff --git a/types.c b/types.c
index 1a430ac..38262ca 100644
--- a/types.c
+++ b/types.c
@@ -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;