diff options
author | Jo-Philipp Wich <jo@mein.io> | 2021-05-18 10:45:21 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2021-05-18 13:11:33 +0200 |
commit | ff6811f29065951ab3917460f3d76ffe6ddb0c81 (patch) | |
tree | 7d3925b2640c9dfc07959faaf866699d77a30d00 /compiler.c | |
parent | 5803d8605b84ef362cc7f96f9e523eff5d0d81bc (diff) |
syntax: implement `delete` as proper operator
Turn `delete` into a proper operator mimicking ECMAScript semantics.
Also ensure to transparently turn deprecated `delete(obj, propname)`
function calls into `delete obj.propname` expressions during compilation.
When strict mode is active, legacy delete() calls throw a syntax error
instead.
Finally drop the `delete()` function from the stdlib as it is shadowed
by the delete operator syntax now.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'compiler.c')
-rw-r--r-- | compiler.c | 53 |
1 files changed, 53 insertions, 0 deletions
@@ -24,6 +24,7 @@ static void uc_compiler_compile_unary(uc_compiler *compiler, bool assignable); static void uc_compiler_compile_binary(uc_compiler *compiler, bool assignable); +static void uc_compiler_compile_delete(uc_compiler *compiler, bool assignable); static void uc_compiler_compile_paren(uc_compiler *compiler, bool assignable); static void uc_compiler_compile_call(uc_compiler *compiler, bool assignable); static void uc_compiler_compile_post_inc(uc_compiler *compiler, bool assignable); @@ -50,6 +51,7 @@ uc_compiler_parse_rules[TK_ERROR + 1] = { [TK_ADD] = { uc_compiler_compile_unary, uc_compiler_compile_binary, P_ADD }, [TK_COMPL] = { uc_compiler_compile_unary, NULL, P_UNARY }, [TK_NOT] = { uc_compiler_compile_unary, NULL, P_UNARY }, + [TK_DELETE] = { uc_compiler_compile_delete, NULL, P_UNARY }, [TK_INC] = { uc_compiler_compile_unary, uc_compiler_compile_post_inc, P_INC }, [TK_DEC] = { uc_compiler_compile_unary, uc_compiler_compile_post_inc, P_INC }, [TK_DIV] = { NULL, uc_compiler_compile_binary, P_MUL }, @@ -966,6 +968,57 @@ uc_compiler_compile_binary(uc_compiler *compiler, bool assignable) } } +static void +uc_compiler_compile_delete(uc_compiler *compiler, bool assignable) +{ + uc_chunk *chunk = uc_compiler_current_chunk(compiler); + enum insn_type type; + + /* If the delete keyword is followed by an opening paren, it might be a + * legacy delete(object, propname) call */ + if (uc_compiler_parse_match(compiler, TK_LPAREN)) { + uc_compiler_parse_precedence(compiler, P_ASSIGN); + + if (uc_compiler_parse_match(compiler, TK_RPAREN)) { + type = chunk->entries[compiler->last_insn]; + + if (type != I_LVAL) + uc_compiler_syntax_error(compiler, 0, + "expecting a property access expression"); + + chunk->entries[compiler->last_insn] = I_DELETE; + } + else if (uc_compiler_parse_match(compiler, TK_COMMA)) { + if (uc_compiler_is_strict(compiler)) { + uc_compiler_syntax_error(compiler, 0, + "attempt to apply 'delete' operator on non-property access expression"); + } + else { + uc_compiler_parse_precedence(compiler, P_ASSIGN); + uc_compiler_emit_insn(compiler, 0, I_DELETE); + uc_compiler_parse_consume(compiler, TK_RPAREN); + } + } + else { + uc_compiler_syntax_error(compiler, 0, "expecting ')' or ','"); + } + } + + /* Otherwise compile expression, ensure that it results in a property + * access (I_LVAL) and overwrite it with delete operation. */ + else { + uc_compiler_parse_precedence(compiler, P_UNARY); + + type = chunk->entries[compiler->last_insn]; + + if (type != I_LVAL) + uc_compiler_syntax_error(compiler, 0, + "expecting a property access expression"); + + chunk->entries[compiler->last_insn] = I_DELETE; + } +} + static enum insn_type uc_compiler_emit_variable_rw(uc_compiler *compiler, uc_value_t *varname, uc_tokentype_t type) { |