elm-optimize-level-2/test/passUnwrappedFunctionsTransformer.test.ts

206 lines
4.8 KiB
TypeScript

import { transformCode } from './inlineWrappedFunctions.test';
import { createPassUnwrappedFunctionsTransformer } from '../src/transforms/passUnwrappedFunctions';
import { createInlineContext } from '../src/transforms/inlineWrappedFunctions';
test('it can unwrap lambdas in place ', () => {
const initialCode = `
var f = function(func, a, b) {
return A2(func, a, b)
};
f(F2(function (a,b) {return a + b;}), 1, 2);
`;
const expectedOutputCode = `
var f = function(func, a, b) {
return A2(func, a, b)
}, f_unwrapped = function(func, a, b) {
return func(a, b)
};
f_unwrapped(function (a,b) {return a + b;}, 1, 2);
`;
const { actual, expected } = transformCode(
initialCode,
expectedOutputCode,
createPassUnwrappedFunctionsTransformer(() => undefined)
);
expect(actual).toBe(expected);
});
test('it can deal with nesting too', () => {
const initialCode = `
var f = function(func, a, b) {
return A2(func, a, b)
};
var val = someFunc(
f(F2(function (a,b) {
return f(F2(function (c,d) {return 0} ), a, b)
}), 1,2)
`;
const expectedOutputCode = `
var f = function(func, a, b) {
return A2(func, a, b)
}, f_unwrapped = function(func, a, b) {
return func(a, b)
};
var val = someFunc(
f_unwrapped(function (a,b) {
return f_unwrapped(function (c,d) {return 0}, a, b)
}, 1,2)
`;
const { actual, expected } = transformCode(
initialCode,
expectedOutputCode,
createPassUnwrappedFunctionsTransformer(() => undefined)
);
expect(actual).toBe(expected);
});
test('it can unwrap lambdas in place ', () => {
const initialCode = `
var f = function(func, a, b) {
return A2(func, a, b)
};
f(F2(function (a,b) {return a + b;}), 1, 2);
`;
const expectedOutputCode = `
var f = function(func, a, b) {
return A2(func, a, b)
}, f_unwrapped = function(func, a, b) {
return func(a, b)
};
f_unwrapped(function (a,b) {return a + b;}, 1, 2);
`;
const { actual, expected } = transformCode(
initialCode,
expectedOutputCode,
createPassUnwrappedFunctionsTransformer(() => undefined)
);
expect(actual).toBe(expected);
});
test('it properly replaces names in recursion and all uses of the passed function', () => {
const initialCode = `
var g = function(func) {
return A2(func, 1, 1);
};
var f = function(func, a, b) {
return f(func, A2(func, a, a), A2(func, b, b)) + g(func);
};
f(F2(function (a,b) {return a + b;}), 1, 2);
`;
const expectedOutputCode = `
var g = function(func) {
return A2(func, 1, 1);
}, g_unwrapped = function(func) {
return func(1, 1);
};
var f = function(func, a, b) {
return f(func, A2(func, a, a), A2(func, b, b)) + g(func);
}, f_unwrapped = function(func, a, b) {
return f_unwrapped(func, func(a, a), func(b, b)) + g_unwrapped(func);
};
f_unwrapped(function (a,b) {return a + b;}, 1, 2);
`;
const { actual, expected } = transformCode(
initialCode,
expectedOutputCode,
createPassUnwrappedFunctionsTransformer(() => undefined)
);
expect(actual).toBe(expected);
});
test('it bails out if there is a call with different arity', () => {
const initialCodeWithA = `
var f = function(func, a, b) {
A3(func, a, b, 1);
A2(func, a, b);
};
f(F3(function (a,b,c) {return a + b + c;}), 1, 2);
`;
const initialCodeWithDirectCall = `
var f = function(func, a, b) {
A3(func, a, b, func(a));
};
f(F3(function (a,b,c) {return a + b + c;}), 1, 2);
`;
const resA = transformCode(
initialCodeWithA,
initialCodeWithA,
createPassUnwrappedFunctionsTransformer(() => undefined)
);
expect(resA.actual).toBe(resA.expected);
const resDirectCall = transformCode(
initialCodeWithDirectCall,
initialCodeWithDirectCall,
createPassUnwrappedFunctionsTransformer(() => undefined)
);
expect(resDirectCall.actual).toBe(resDirectCall.expected);
});
// commented out for now
test('it can pass raw functions if there is one registered', () => {
const initialCode = `
var f = function(func, a, b) {
return A2(func, a, b)
};
f(wrappedFunc, 1, 2);
`;
const expectedOutputCode = `
var f = function(func, a, b) {
return A2(func, a, b)
}, f_unwrapped = function(func, a, b) {
return func(a, b)
};
f_unwrapped(wrappedFunc_fn, 1, 2);
`;
const inlineContext = createInlineContext();
inlineContext.splits.set('wrappedFunc', {
arity: 2,
rawLambdaName: 'wrappedFunc_fn',
type: 'raw_func',
});
const { actual, expected } = transformCode(
initialCode,
expectedOutputCode,
createPassUnwrappedFunctionsTransformer(() => inlineContext)
);
expect(actual).toBe(expected);
});