88 lines
3.3 KiB
JavaScript
88 lines
3.3 KiB
JavaScript
import {
|
|
isMemberExpression,
|
|
} from '@/astride/types.js';
|
|
|
|
export default function(node, {evaluate, scope}) {
|
|
const {operator, left} = node;
|
|
const right = evaluate(node.right, {scope});
|
|
if (!isMemberExpression(left)) {
|
|
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)};
|
|
}
|
|
|