export default function(node, {evaluate, scope}) { const {operator, left} = node; const right = evaluate(node.right, {scope}); if (!('MemberExpression' === left.type)) { const assign = (value) => { switch (operator) { case '=' : return scope.set(left.name, value); case '+=' : return scope.set(left.name, scope.get(left.name) + value); case '-=' : return scope.set(left.name, scope.get(left.name) - value); case '*=' : return scope.set(left.name, scope.get(left.name) * value); case '/=' : return scope.set(left.name, scope.get(left.name) / value); case '%=' : return scope.set(left.name, scope.get(left.name) % value); case '**=' : return scope.set(left.name, scope.get(left.name) ** value); case '<<=' : return scope.set(left.name, scope.get(left.name) << value); case '>>=' : return scope.set(left.name, scope.get(left.name) >> value); case '>>>=': return scope.set(left.name, scope.get(left.name) >>> value); case '|=' : return scope.set(left.name, scope.get(left.name) | value); case '^=' : return scope.set(left.name, scope.get(left.name) ^ value); case '&=' : return scope.set(left.name, scope.get(left.name) & value); case '||=' : return scope.set(left.name, scope.get(left.name) || value); case '&&=' : return scope.set(left.name, scope.get(left.name) && value); case '??=' : { const l = scope.get(left.name); return scope.set(left.name, (l === null || l === undefined) ? value : l); } /* v8 ignore next 2 */ default: throw new Error(`operator not implemented: ${node.operator}`); } }; if (right.async) { return { async: true, value: Promise.resolve(right.value).then(assign), }; } return {value: assign(right.value)}; } const { computed, object, property, } = left; const memberAssign = (O, P, value) => { switch (operator) { case '=' : return O[P] = value; case '+=' : return O[P] += value; case '-=' : return O[P] -= value; case '*=' : return O[P] *= value; case '/=' : return O[P] /= value; case '%=' : return O[P] %= value; case '**=' : return O[P] **= value; case '<<=' : return O[P] <<= value; case '>>=' : return O[P] >>= value; case '>>>=': return O[P] >>>= value; case '|=' : return O[P] |= value; case '^=' : return O[P] ^= value; case '&=' : return O[P] &= value; case '||=' : return O[P] ||= value; case '&&=' : return O[P] &&= value; case '??=' : return O[P] = (O[P] === null || O[P] === undefined) ? value : O[P]; /* v8 ignore next 2 */ default: throw new Error(`operator not implemented: ${node.operator}`); } }; const makeAsync = (O, P, value) => ( Promise.all([O, P, value]).then(([O, P, value]) => memberAssign(O, P, value)) ); const O = evaluate(object, {scope}); const P = computed ? evaluate(property, {scope}) // Otherwise, identifier : {value: property.name}; if (right.async || O.async || P.async) { return { async: true, value: makeAsync(O.value, P.value, right.value), }; } return {value: memberAssign(O.value, P.value, right.value)}; }