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