chore: coverage and tidy
This commit is contained in:
parent
d00bcf23f3
commit
2ab82d1d3e
|
@ -41,6 +41,7 @@ export default function evaluate(node, {scope} = {}) {
|
||||||
return evaluators.unary(node, {evaluate, scope});
|
return evaluators.unary(node, {evaluate, scope});
|
||||||
case 'UpdateExpression':
|
case 'UpdateExpression':
|
||||||
return evaluators.update(node, {evaluate, scope});
|
return evaluators.update(node, {evaluate, scope});
|
||||||
|
/* v8 ignore next 2 */
|
||||||
default:
|
default:
|
||||||
throw new EvalError(`astride: Can't evaluate node of type ${node.type}`)
|
throw new EvalError(`astride: Can't evaluate node of type ${node.type}`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import {isSpreadElement} from '@/astride/types.js';
|
|
||||||
|
|
||||||
export default function(node, {evaluate, scope}) {
|
export default function(node, {evaluate, scope}) {
|
||||||
const elements = [];
|
const elements = [];
|
||||||
const asyncSpread = Object.create(null);
|
const asyncSpread = Object.create(null);
|
||||||
let isAsync = false;
|
let isAsync = false;
|
||||||
for (const index in node.elements) {
|
for (const index in node.elements) {
|
||||||
const element = node.elements[index];
|
const element = node.elements[index];
|
||||||
if (isSpreadElement(element)) {
|
if ('SpreadElement' === element.type) {
|
||||||
const {async, value} = evaluate(element.argument, {scope});
|
const {async, value} = evaluate(element.argument, {scope});
|
||||||
isAsync = isAsync || async;
|
isAsync = isAsync || async;
|
||||||
if (async) {
|
if (async) {
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import {
|
|
||||||
isMemberExpression,
|
|
||||||
} from '@/astride/types.js';
|
|
||||||
|
|
||||||
export default function(node, {evaluate, scope}) {
|
export default function(node, {evaluate, scope}) {
|
||||||
const {operator, left} = node;
|
const {operator, left} = node;
|
||||||
const right = evaluate(node.right, {scope});
|
const right = evaluate(node.right, {scope});
|
||||||
if (!isMemberExpression(left)) {
|
if (!('MemberExpression' === left.type)) {
|
||||||
const assign = (value) => {
|
const assign = (value) => {
|
||||||
switch (operator) {
|
switch (operator) {
|
||||||
case '=' : return scope.set(left.name, value);
|
case '=' : return scope.set(left.name, value);
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
import fastCall from '@/util/fast-call.js';
|
import fastCall from '@/util/fast-call.js';
|
||||||
import {
|
|
||||||
isMemberExpression,
|
|
||||||
} from '@/astride/types.js';
|
|
||||||
|
|
||||||
export default function(node, {evaluate, scope}) {
|
export default function(node, {evaluate, scope}) {
|
||||||
let asyncArgs = false;
|
let asyncArgs = false;
|
||||||
|
@ -24,7 +21,7 @@ export default function(node, {evaluate, scope}) {
|
||||||
}
|
}
|
||||||
return fastCall(fn, holder, args);
|
return fastCall(fn, holder, args);
|
||||||
};
|
};
|
||||||
if (!isMemberExpression(callee)) {
|
if (!('MemberExpression' === callee.type)) {
|
||||||
const {async, value} = evaluate(callee, {scope});
|
const {async, value} = evaluate(callee, {scope});
|
||||||
if (asyncArgs || async) {
|
if (asyncArgs || async) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -48,10 +48,8 @@ scopeTest('evaluates optional calls', async ({scope}) => {
|
||||||
scope.set('O', {});
|
scope.set('O', {});
|
||||||
expect(evaluate(await expression('g?.(1, 2, 3)'), {scope}).value)
|
expect(evaluate(await expression('g?.(1, 2, 3)'), {scope}).value)
|
||||||
.to.equal(undefined);
|
.to.equal(undefined);
|
||||||
// expect(evaluate(await expression('O?.g(1, 2, 3)'), {scope}).value)
|
expect(evaluate(await expression('O?.g?.(1, 2, 3)'), {scope}).value)
|
||||||
// .to.equal(undefined);
|
.to.equal(undefined);
|
||||||
// expect(evaluate(await expression('O?.g?.(1, 2, 3)'), {scope}).value)
|
|
||||||
// .to.equal(undefined);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
scopeTest('evaluates async calls', async ({scope}) => {
|
scopeTest('evaluates async calls', async ({scope}) => {
|
||||||
|
|
|
@ -1,25 +1,18 @@
|
||||||
import {
|
|
||||||
isIdentifier,
|
|
||||||
isLiteral,
|
|
||||||
isProperty,
|
|
||||||
isSpreadElement,
|
|
||||||
} from '@/astride/types.js';
|
|
||||||
|
|
||||||
export default function(node, {evaluate, scope}) {
|
export default function(node, {evaluate, scope}) {
|
||||||
const {properties} = node;
|
const {properties} = node;
|
||||||
let isAsync = false;
|
let isAsync = false;
|
||||||
const entries = [];
|
const entries = [];
|
||||||
for (let i = 0; i < properties.length; i++) {
|
for (let i = 0; i < properties.length; i++) {
|
||||||
if (isProperty(properties[i])) {
|
if ('Property' === properties[i].type) {
|
||||||
const {computed, key, value} = properties[i];
|
const {computed, key, value} = properties[i];
|
||||||
let k;
|
let k;
|
||||||
if (computed) {
|
if (computed) {
|
||||||
k = evaluate(key, {scope});
|
k = evaluate(key, {scope});
|
||||||
}
|
}
|
||||||
else if (isIdentifier(key)) {
|
else if ('Identifier' === key.type) {
|
||||||
k = {value: key.name};
|
k = {value: key.name};
|
||||||
}
|
}
|
||||||
else if (isLiteral(key)) {
|
else if ('Literal' === key.type) {
|
||||||
k = {value: key.value};
|
k = {value: key.value};
|
||||||
}
|
}
|
||||||
/* v8 ignore next 3 */
|
/* v8 ignore next 3 */
|
||||||
|
@ -35,7 +28,7 @@ export default function(node, {evaluate, scope}) {
|
||||||
entries.push([k.value, v.value]);
|
entries.push([k.value, v.value]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isSpreadElement(properties[i])) {
|
if ('SpreadElement' === properties[i].type) {
|
||||||
const {argument} = properties[i];
|
const {argument} = properties[i];
|
||||||
const spreading = evaluate(argument, {scope});
|
const spreading = evaluate(argument, {scope});
|
||||||
isAsync ||= spreading.async;
|
isAsync ||= spreading.async;
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
import evaluate from '@/astride/evaluate.js';
|
import evaluate from '@/astride/evaluate.js';
|
||||||
import Scope from '@/astride/scope.js';
|
import Scope from '@/astride/scope.js';
|
||||||
import traverse from '@/astride/traverse.js';
|
import traverse from '@/astride/traverse.js';
|
||||||
import {
|
|
||||||
isArrayPattern,
|
|
||||||
isBlockStatement,
|
|
||||||
isForStatement,
|
|
||||||
isIdentifier,
|
|
||||||
isObjectPattern,
|
|
||||||
} from '@/astride/types.js';
|
|
||||||
|
|
||||||
const YIELD_NONE = 0;
|
const YIELD_NONE = 0;
|
||||||
const YIELD_PROMISE = 1;
|
const YIELD_PROMISE = 1;
|
||||||
|
@ -34,8 +27,8 @@ export default class Sandbox {
|
||||||
this.ast,
|
this.ast,
|
||||||
(node, verb) => {
|
(node, verb) => {
|
||||||
if (
|
if (
|
||||||
isBlockStatement(node)
|
'BlockStatement' === node.type
|
||||||
|| isForStatement(node)
|
|| 'ForStatement' === node.type
|
||||||
) {
|
) {
|
||||||
switch (verb) {
|
switch (verb) {
|
||||||
case 'enter': {
|
case 'enter': {
|
||||||
|
@ -67,7 +60,7 @@ export default class Sandbox {
|
||||||
if (null === element) {
|
if (null === element) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isIdentifier(element)) {
|
if ('Identifier' === element.type) {
|
||||||
scope.allocate(element.name, init[i]);
|
scope.allocate(element.name, init[i]);
|
||||||
}
|
}
|
||||||
/* v8 ignore next 3 */
|
/* v8 ignore next 3 */
|
||||||
|
@ -83,7 +76,7 @@ export default class Sandbox {
|
||||||
const {properties} = id;
|
const {properties} = id;
|
||||||
for (let i = 0; i < properties.length; ++i) {
|
for (let i = 0; i < properties.length; ++i) {
|
||||||
const property = properties[i];
|
const property = properties[i];
|
||||||
if (isObjectPattern(property.value)) {
|
if ('ObjectPattern' === property.value.type) {
|
||||||
this.destructureObject(property.value, init[property.key.name]);
|
this.destructureObject(property.value, init[property.key.name]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -135,6 +128,7 @@ export default class Sandbox {
|
||||||
case 'ChainExpression':
|
case 'ChainExpression':
|
||||||
case 'ObjectExpression':
|
case 'ObjectExpression':
|
||||||
case 'Identifier':
|
case 'Identifier':
|
||||||
|
case 'LogicalExpression':
|
||||||
case 'MemberExpression':
|
case 'MemberExpression':
|
||||||
case 'UnaryExpression':
|
case 'UnaryExpression':
|
||||||
case 'UpdateExpression': {
|
case 'UpdateExpression': {
|
||||||
|
@ -156,6 +150,7 @@ export default class Sandbox {
|
||||||
if (result.yield) {
|
if (result.yield) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
/* v8 ignore next 2 */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'BlockStatement': {
|
case 'BlockStatement': {
|
||||||
|
@ -168,6 +163,7 @@ export default class Sandbox {
|
||||||
if (skipping && child === this.$$execution.stack[depth + 1]) {
|
if (skipping && child === this.$$execution.stack[depth + 1]) {
|
||||||
skipping = false;
|
skipping = false;
|
||||||
}
|
}
|
||||||
|
/* v8 ignore next 3 */
|
||||||
if (skipping) {
|
if (skipping) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -370,6 +366,7 @@ export default class Sandbox {
|
||||||
if (skipping && child === this.$$execution.stack[depth + 1]) {
|
if (skipping && child === this.$$execution.stack[depth + 1]) {
|
||||||
skipping = false;
|
skipping = false;
|
||||||
}
|
}
|
||||||
|
/* v8 ignore next 3 */
|
||||||
if (skipping) {
|
if (skipping) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -390,7 +387,7 @@ export default class Sandbox {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const init = this.executeSync(node.init, depth + 1);
|
const init = this.executeSync(node.init, depth + 1);
|
||||||
if (isIdentifier(id)) {
|
if ('Identifier' === id.type) {
|
||||||
if (init.yield) {
|
if (init.yield) {
|
||||||
return {
|
return {
|
||||||
value: Promise.resolve(init.value)
|
value: Promise.resolve(init.value)
|
||||||
|
@ -405,7 +402,7 @@ export default class Sandbox {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isArrayPattern(id)) {
|
else if ('ArrayPattern' === id.type) {
|
||||||
if (init.yield) {
|
if (init.yield) {
|
||||||
return {
|
return {
|
||||||
value: Promise.resolve(init.value)
|
value: Promise.resolve(init.value)
|
||||||
|
@ -420,7 +417,7 @@ export default class Sandbox {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isObjectPattern(id)) {
|
else if ('ObjectPattern' === id.type) {
|
||||||
if (init.yield) {
|
if (init.yield) {
|
||||||
return {
|
return {
|
||||||
value: Promise.resolve(init.value)
|
value: Promise.resolve(init.value)
|
||||||
|
@ -475,6 +472,7 @@ export default class Sandbox {
|
||||||
yield: YIELD_LOOP_UPDATE,
|
yield: YIELD_LOOP_UPDATE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
/* v8 ignore next 7 */
|
||||||
default:
|
default:
|
||||||
console.log(
|
console.log(
|
||||||
node.type,
|
node.type,
|
||||||
|
|
|
@ -147,6 +147,33 @@ test('evaluates conditional branches', async () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('evaluates conditional expressions', async () => {
|
||||||
|
const sandbox = new Sandbox(
|
||||||
|
await parse(`
|
||||||
|
const x = true || false ? 1 : 2
|
||||||
|
const y = false && true ? 1 : 2
|
||||||
|
const a = (await true) ? await 1 : await 2
|
||||||
|
const b = (await false) ? await 1 : await 2
|
||||||
|
xx = true || false ? 1 : 2
|
||||||
|
yy = false && true ? 1 : 2
|
||||||
|
aa = (await true) ? await 1 : await 2
|
||||||
|
bb = (await false) ? await 1 : await 2
|
||||||
|
`),
|
||||||
|
);
|
||||||
|
await finish(sandbox);
|
||||||
|
expect(sandbox.context)
|
||||||
|
.to.deep.equal({
|
||||||
|
x: 1,
|
||||||
|
y: 2,
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
xx: 1,
|
||||||
|
yy: 2,
|
||||||
|
aa: 1,
|
||||||
|
bb: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('evaluates loops', async () => {
|
test('evaluates loops', async () => {
|
||||||
const sandbox = new Sandbox(
|
const sandbox = new Sandbox(
|
||||||
await parse(`
|
await parse(`
|
||||||
|
@ -155,6 +182,7 @@ test('evaluates loops', async () => {
|
||||||
a = 0
|
a = 0
|
||||||
b = 0
|
b = 0
|
||||||
c = 0
|
c = 0
|
||||||
|
d = 0
|
||||||
for (let i = 0; i < 3; ++i) {
|
for (let i = 0; i < 3; ++i) {
|
||||||
x += 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
|
@ -165,11 +193,14 @@ test('evaluates loops', async () => {
|
||||||
a += 1;
|
a += 1;
|
||||||
} while (a < 3);
|
} while (a < 3);
|
||||||
do {
|
do {
|
||||||
b += 1;
|
b += await 1;
|
||||||
} while (await b < 3);
|
} while (await b < 3);
|
||||||
while (c < 3) {
|
while (c < 3) {
|
||||||
c += 1;
|
c += 1;
|
||||||
}
|
}
|
||||||
|
while (await d < 3) {
|
||||||
|
d += await 1;
|
||||||
|
}
|
||||||
`),
|
`),
|
||||||
);
|
);
|
||||||
await finish(sandbox);
|
await finish(sandbox);
|
||||||
|
@ -178,6 +209,7 @@ test('evaluates loops', async () => {
|
||||||
a: 3,
|
a: 3,
|
||||||
b: 3,
|
b: 3,
|
||||||
c: 3,
|
c: 3,
|
||||||
|
d: 3,
|
||||||
x: 3,
|
x: 3,
|
||||||
y: 3,
|
y: 3,
|
||||||
});
|
});
|
||||||
|
@ -207,8 +239,20 @@ test('returns values at the top level', async () => {
|
||||||
y = 8
|
y = 8
|
||||||
`, {allowReturnOutsideFunction: true}),
|
`, {allowReturnOutsideFunction: true}),
|
||||||
);
|
);
|
||||||
const {value} = sandbox.run();
|
expect(sandbox.run().value)
|
||||||
expect(value)
|
.to.deep.equal([48, 12]);
|
||||||
|
expect(sandbox.context)
|
||||||
|
.to.deep.equal({x: 16, y: 4});
|
||||||
|
sandbox = new Sandbox(
|
||||||
|
await parse(`
|
||||||
|
x = 16
|
||||||
|
y = 4
|
||||||
|
return await [x * 3, y * 3]
|
||||||
|
x = 32
|
||||||
|
y = 8
|
||||||
|
`, {allowReturnOutsideFunction: true}),
|
||||||
|
);
|
||||||
|
expect((await finish(sandbox)).value)
|
||||||
.to.deep.equal([48, 12]);
|
.to.deep.equal([48, 12]);
|
||||||
expect(sandbox.context)
|
expect(sandbox.context)
|
||||||
.to.deep.equal({x: 16, y: 4});
|
.to.deep.equal({x: 16, y: 4});
|
||||||
|
|
|
@ -15,6 +15,7 @@ export const TRAVERSAL_PATH = {
|
||||||
IfStatement: ['alternate', 'consequent', 'test'],
|
IfStatement: ['alternate', 'consequent', 'test'],
|
||||||
MemberExpression: ['object', 'property'],
|
MemberExpression: ['object', 'property'],
|
||||||
Literal: [],
|
Literal: [],
|
||||||
|
LogicalExpression: ['left', 'right'],
|
||||||
ObjectExpression: ['properties'],
|
ObjectExpression: ['properties'],
|
||||||
ObjectPattern: ['properties'],
|
ObjectPattern: ['properties'],
|
||||||
Program: ['body'],
|
Program: ['body'],
|
||||||
|
@ -35,15 +36,9 @@ export default function traverse(node, visitor) {
|
||||||
}
|
}
|
||||||
visitor(node, 'enter');
|
visitor(node, 'enter');
|
||||||
const path = TRAVERSAL_PATH[node.type];
|
const path = TRAVERSAL_PATH[node.type];
|
||||||
let children;
|
const children = [];
|
||||||
if (path instanceof Function) {
|
for (const key of path) {
|
||||||
children = path(node);
|
children.push(...(Array.isArray(node[key]) ? node[key] : [node[key]]));
|
||||||
}
|
|
||||||
else if (Array.isArray(path)) {
|
|
||||||
children = [];
|
|
||||||
for (const key of path) {
|
|
||||||
children.push(...(Array.isArray(node[key]) ? node[key] : [node[key]]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
if (child) {
|
if (child) {
|
||||||
|
|
|
@ -1,116 +0,0 @@
|
||||||
export function isArrayPattern(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'ArrayPattern') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isBlockStatement(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'BlockStatement') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isDoWhileStatement(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'DoWhileStatement') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isExpressionStatement(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'ExpressionStatement') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isForStatement(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'ForStatement') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isIdentifier(node) {
|
|
||||||
if (!node || node.type !== 'Identifier') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isIfStatement(node) {
|
|
||||||
if (!node || node.type !== 'IfStatement') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isLiteral(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'Literal') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isMemberExpression(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'MemberExpression') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isObjectPattern(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'ObjectPattern') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isProperty(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'Property') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isReturnStatement(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'ReturnStatement') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isSpreadElement(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'SpreadElement') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isVariableDeclarator(node) {
|
|
||||||
/* v8 ignore next 3 */
|
|
||||||
if (!node || node.type !== 'VariableDeclarator') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isWhileStatement(node) {
|
|
||||||
if (!node || node.type !== 'WhileStatement') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user