Browse Source

Adds support for the logical and/or assignment operators

pull/2527/head
Christoph Kaser 2 years ago
parent
commit
94a12dcb95
  1. 88
      src-input/duk_js_compiler.c
  2. 12
      src-input/duk_lexer.c
  3. 10
      src-input/duk_lexer.h

88
src-input/duk_js_compiler.c

@ -433,6 +433,8 @@ DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BAND_EQ */ DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BAND_EQ */
DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BOR_EQ */ DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BOR_EQ */
DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BXOR_EQ */ DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BXOR_EQ */
DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_LAND_EQ */
DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_LOR_EQ */
DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NUMBER */ DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NUMBER */
DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_STRING */ DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_STRING */
DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_REGEXP */ DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_REGEXP */
@ -4255,6 +4257,15 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
goto binary_logical; goto binary_logical;
} }
case DUK_TOK_LAND_EQ: {
args = (1 << 9) + (1 << 8) + DUK__BP_ASSIGNMENT - 1;
goto binary_logical;
}
case DUK_TOK_LOR_EQ: {
args = (1 << 9) + (0 << 8) + DUK__BP_ASSIGNMENT - 1;
goto binary_logical;
}
/* CONDITIONAL EXPRESSION */ /* CONDITIONAL EXPRESSION */
case DUK_TOK_QUESTION: { case DUK_TOK_QUESTION: {
@ -4455,6 +4466,52 @@ binary_logical:
duk_small_uint_t args_truthval = args >> 8; duk_small_uint_t args_truthval = args >> 8;
duk_small_uint_t args_rbp = args & 0xff; duk_small_uint_t args_rbp = args & 0xff;
duk_small_uint_t leftt;
duk_hstring *h_varname;
duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
duk_regconst_t reg_obj;
duk_regconst_t rc_key;
if (args_truthval & 2) { // assignment
leftt = left->t;
if (leftt == DUK_IVAL_VAR) {
DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */
h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
/* E5 Section 11.13.1 (and others for other assignments), step 4. */
goto syntax_error_lvalue;
}
duk_dup(thr, left->x1.valstack_idx);
(void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
}
if (leftt == DUK_IVAL_PROP) {
/* Property access expressions ('a[b]') are critical to correct
* LHS evaluation ordering, see test-dev-assign-eval-order*.js.
* We must make sure that the LHS target slot (base object and
* key) don't change during RHS evaluation. The only concrete
* problem is a register reference to a variable-bound register
* (i.e., non-temp). Require temp regs for both key and base.
*
* Don't allow a constant for the object (even for a number
* etc), as it goes into the 'A' field of the opcode.
*/
reg_obj = duk__ispec_toregconst_raw(comp_ctx,
&left->x1,
-1 /*forced_reg*/,
DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
rc_key =
duk__ispec_toregconst_raw(comp_ctx,
&left->x2,
-1 /*forced_reg*/,
DUK__IVAL_FLAG_REQUIRE_TEMP | DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
}
}
/* XXX: unoptimal use of temps, resetting */ /* XXX: unoptimal use of temps, resetting */
reg_temp = DUK__ALLOCTEMP(comp_ctx); reg_temp = DUK__ALLOCTEMP(comp_ctx);
@ -4462,10 +4519,39 @@ binary_logical:
duk__ivalue_toforcedreg(comp_ctx, left, reg_temp); duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
DUK_ASSERT(DUK__ISREG(reg_temp)); DUK_ASSERT(DUK__ISREG(reg_temp));
duk__emit_bc(comp_ctx, duk__emit_bc(comp_ctx,
(args_truthval ? DUK_OP_IFTRUE_R : DUK_OP_IFFALSE_R), ((args_truthval & 1) ? DUK_OP_IFTRUE_R : DUK_OP_IFFALSE_R),
reg_temp); /* skip jump conditionally */ reg_temp); /* skip jump conditionally */
pc_jump = duk__emit_jump_empty(comp_ctx); pc_jump = duk__emit_jump_empty(comp_ctx);
duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/); duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/);
if (args_truthval & 2) { // assignment
if (leftt == DUK_IVAL_VAR) {
if (reg_varbind >= 0) {
duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, reg_varbind, reg_temp);
} else {
duk__emit_a_bc(comp_ctx, DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE, reg_temp, rc_varname);
}
} else if (leftt == DUK_IVAL_PROP) {
duk__emit_a_b_c(comp_ctx,
DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST,
reg_obj,
rc_key,
reg_temp);
} else {
/* No support for lvalues returned from new or function call expressions.
* However, these must NOT cause compile-time SyntaxErrors, but run-time
* ReferenceErrors. Both left and right sides of the assignment must be
* evaluated before throwing a ReferenceError. For instance:
*
* f() = g();
*
* must result in f() being evaluated, then g() being evaluated, and
* finally, a ReferenceError being thrown. See E5 Section 11.13.1.
*/
duk__emit_op_only(comp_ctx, DUK_OP_INVLHS);
}
}
duk__patch_jump_here(comp_ctx, pc_jump); duk__patch_jump_here(comp_ctx, pc_jump);
duk__ivalue_regconst(res, reg_temp); duk__ivalue_regconst(res, reg_temp);

12
src-input/duk_lexer.c

@ -1413,7 +1413,11 @@ restart:
break; break;
case DUK_ASC_AMP: /* '&' */ case DUK_ASC_AMP: /* '&' */
if (DUK__L1() == DUK_ASC_AMP) { if (DUK__L1() == DUK_ASC_AMP) {
advtok = DUK__ADVTOK(2, DUK_TOK_LAND); if (DUK__L2() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(3, DUK_TOK_LAND_EQ);
} else {
advtok = DUK__ADVTOK(2, DUK_TOK_LAND);
}
} else if (DUK__L1() == DUK_ASC_EQUALS) { } else if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ); advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ);
} else { } else {
@ -1422,7 +1426,11 @@ restart:
break; break;
case DUK_ASC_PIPE: /* '|' */ case DUK_ASC_PIPE: /* '|' */
if (DUK__L1() == DUK_ASC_PIPE) { if (DUK__L1() == DUK_ASC_PIPE) {
advtok = DUK__ADVTOK(2, DUK_TOK_LOR); if (DUK__L2() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(3, DUK_TOK_LOR_EQ);
} else {
advtok = DUK__ADVTOK(2, DUK_TOK_LOR);
}
} else if (DUK__L1() == DUK_ASC_EQUALS) { } else if (DUK__L1() == DUK_ASC_EQUALS) {
advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ); advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ);
} else { } else {

10
src-input/duk_lexer.h

@ -162,15 +162,17 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
#define DUK_TOK_BAND_EQ 96 #define DUK_TOK_BAND_EQ 96
#define DUK_TOK_BOR_EQ 97 #define DUK_TOK_BOR_EQ 97
#define DUK_TOK_BXOR_EQ 98 #define DUK_TOK_BXOR_EQ 98
#define DUK_TOK_LAND_EQ 99
#define DUK_TOK_LOR_EQ 100
/* literals (E5 Section 7.8), except null, true, false, which are treated /* literals (E5 Section 7.8), except null, true, false, which are treated
* like reserved words (above). * like reserved words (above).
*/ */
#define DUK_TOK_NUMBER 99 #define DUK_TOK_NUMBER 101
#define DUK_TOK_STRING 100 #define DUK_TOK_STRING 102
#define DUK_TOK_REGEXP 101 #define DUK_TOK_REGEXP 103
#define DUK_TOK_MAXVAL 101 /* inclusive */ #define DUK_TOK_MAXVAL 103 /* inclusive */
#define DUK_TOK_INVALID DUK_SMALL_UINT_MAX #define DUK_TOK_INVALID DUK_SMALL_UINT_MAX

Loading…
Cancel
Save