summaryrefslogtreecommitdiffhomepage
path: root/compiler.c
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2021-05-18 10:45:21 +0200
committerJo-Philipp Wich <jo@mein.io>2021-05-18 13:11:33 +0200
commitff6811f29065951ab3917460f3d76ffe6ddb0c81 (patch)
tree7d3925b2640c9dfc07959faaf866699d77a30d00 /compiler.c
parent5803d8605b84ef362cc7f96f9e523eff5d0d81bc (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.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/compiler.c b/compiler.c
index 889a8dd..cf9ca25 100644
--- a/compiler.c
+++ b/compiler.c
@@ -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)
{