diff --git a/src/experiments/inlineListFromArray.ts b/src/experiments/inlineListFromArray.ts new file mode 100644 index 0000000..77c63d7 --- /dev/null +++ b/src/experiments/inlineListFromArray.ts @@ -0,0 +1,68 @@ +import ts from 'typescript'; + +// ` +// var _List_Nil = { $: "[]" }; + +// function _List_Cons(hd, tl) { +// return { $: "::", a: hd, b: tl }; +// } + +// var _List_cons = F2(_List_Cons); + +// function _List_fromArray(arr) { +// var out = _List_Nil; +// for (var i = arr.length; i--; ) { +// out = _List_Cons(arr[i], out); +// } +// return out; +// } +// `; +// ` +// _List_fromArray([ +// "a", +// "b", +// "c", +// ]) +// `; + +const LIST_FROM_ARRAY_F_NAME = '_List_fromArray'; +const LIST_NIL_NAME = '_List_Nil'; +const LIST_CONS_F_NAME = '_List_cons'; + +const listNil = ts.createIdentifier(LIST_NIL_NAME); +const listConsCall = ts.createIdentifier(LIST_CONS_F_NAME); + +const appendToFront = ( + expression: ts.Expression, + list: ts.Expression +): ts.Expression => { + return ts.createCall(listConsCall, undefined, [expression, list]); +}; + +export const createInlineListFromArrayTransformer = (): ts.TransformerFactory => context => { + return sourceFile => { + const visitor = (node: ts.Node): ts.VisitResult => { + // detects [exp](..) + if (ts.isCallExpression(node)) { + const expression = node.expression; + // detects _List_fromArray(..) + if ( + ts.isIdentifier(expression) && + expression.text === LIST_FROM_ARRAY_F_NAME && + node.arguments.length === 1 + ) { + const [arrayLiteral] = node.arguments; + + // detects _List_fromArray([..]) + if (ts.isArrayLiteralExpression(arrayLiteral)) { + return arrayLiteral.elements.reduceRight(appendToFront, listNil); + } + } + } + + return ts.visitEachChild(node, visitor, context); + }; + + return ts.visitNode(sourceFile, visitor); + }; +}; diff --git a/src/experiments/types.ts b/src/experiments/types.ts new file mode 100644 index 0000000..65f4d5a --- /dev/null +++ b/src/experiments/types.ts @@ -0,0 +1,4 @@ +export enum Mode { + Prod = 'prod', + Dev = 'dev', +} diff --git a/src/experiments/variantShapes.ts b/src/experiments/variantShapes.ts index 6071009..ca0030e 100644 --- a/src/experiments/variantShapes.ts +++ b/src/experiments/variantShapes.ts @@ -1,8 +1,10 @@ import ts from 'typescript'; +import { Mode } from './types'; export type VariantReplacement = { symbolName: string; variantName: string; + variantIndex: number; maximumNumberOfArgs: number; numberOfArgs: number; }; @@ -10,17 +12,22 @@ export type VariantReplacement = { // TODO fill a proper array const argNames = ['a', 'b', 'c', 'd', 'e']; -const createVariantObjectLiteral = ({ - variantName, - maximumNumberOfArgs, - numberOfArgs, -}: { - variantName: string; - maximumNumberOfArgs: number; - numberOfArgs: number; -}): ts.ObjectLiteralExpression => { +const createVariantObjectLiteral = ( + { + variantName, + maximumNumberOfArgs, + numberOfArgs, + variantIndex, + }: VariantReplacement, + mode: Mode +): ts.ObjectLiteralExpression => { return ts.createObjectLiteral([ - ts.createPropertyAssignment('$', ts.createStringLiteral(variantName)), + ts.createPropertyAssignment( + '$', + mode === Mode.Dev + ? ts.createStringLiteral(variantName) + : ts.createNumericLiteral(variantIndex.toString()) + ), // existing arguments ...argNames .slice(0, numberOfArgs) @@ -32,11 +39,11 @@ const createVariantObjectLiteral = ({ ]); }; -const createCtorVariant = ({ - variantName, - maximumNumberOfArgs, - numberOfArgs, -}: VariantReplacement): ts.Expression => { +const createCtorVariant = ( + replacement: VariantReplacement, + mode: Mode +): ts.Expression => { + const { numberOfArgs } = replacement; const funcExpression = ts.createArrowFunction( undefined, undefined, @@ -55,11 +62,7 @@ const createCtorVariant = ({ ), undefined, undefined, - createVariantObjectLiteral({ - variantName, - maximumNumberOfArgs, - numberOfArgs, - }) + createVariantObjectLiteral(replacement, mode) ); if (numberOfArgs > 1) { @@ -75,7 +78,8 @@ const createCtorVariant = ({ }; export const createCustomTypesTransformer = ( - replacements: VariantReplacement[] + replacements: VariantReplacement[], + mode: Mode ): ts.TransformerFactory => context => { return sourceFile => { const visitor = (node: ts.Node): ts.Node => { @@ -83,16 +87,11 @@ export const createCustomTypesTransformer = ( for (const replacement of replacements) { if (node.name.text === replacement.symbolName) { if (replacement.numberOfArgs === 0) { - const { variantName, maximumNumberOfArgs } = replacement; return ts.updateVariableDeclaration( node, node.name, node.type, - createVariantObjectLiteral({ - variantName, - maximumNumberOfArgs, - numberOfArgs: 0, - }) + createVariantObjectLiteral(replacement, mode) ); } @@ -100,7 +99,7 @@ export const createCustomTypesTransformer = ( node, node.name, node.type, - createCtorVariant(replacement) + createCtorVariant(replacement, mode) ); } } diff --git a/src/index.ts b/src/index.ts index c7b8aed..f9bc7e4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,9 @@ import { FuncSplit, createFuncInlineTransformer, } from './experiments/inlineWrappedFunctions'; +import { Mode } from './experiments/types'; + +import { createInlineListFromArrayTransformer } from './experiments/inlineListFromArray'; const elmOutput = ` var $elm$core$Maybe$Nothing = {$: 'Nothing'}; @@ -22,6 +25,8 @@ var $author$project$Main$Three = F3( }); var _v1 = A3($author$project$Main$Three, a, b, c); + +_List_fromArray(['a', 'b', 'c']); `; const source = ts.createSourceFile('elm.js', elmOutput, ts.ScriptTarget.ES2018); @@ -31,6 +36,7 @@ const replacements: VariantReplacement[] = [ symbolName: '$elm$core$Maybe$Nothing', variantName: 'Nothing', maximumNumberOfArgs: 1, + variantIndex: 1, numberOfArgs: 0, }, @@ -38,17 +44,22 @@ const replacements: VariantReplacement[] = [ symbolName: '$elm$core$Maybe$Just', variantName: 'Just', numberOfArgs: 1, + variantIndex: 0, maximumNumberOfArgs: 2, }, { symbolName: '$author$project$Main$Three', variantName: 'Three', numberOfArgs: 3, + variantIndex: 100500, maximumNumberOfArgs: 4, }, ]; -const customTypeTransformer = createCustomTypesTransformer(replacements); +const customTypeTransformer = createCustomTypesTransformer( + replacements, + Mode.Prod +); const [newFile] = ts.transform(source, [customTypeTransformer]).transformed; const printer = ts.createPrinter(); @@ -68,10 +79,21 @@ const [sourceWithSplittedFunctions] = ts.transform(newFile, [ console.log(printer.printFile(sourceWithSplittedFunctions)); console.log(collectedSplits); -console.log('----------AFTER SPLIT TRANSFORM ----------------'); +console.log('----------AFTER INLINE A(n) TRANSFORM ----------------'); const funcInlineTransformer = createFuncInlineTransformer(collectedSplits); const [sourceWithInlinedFuntioncs] = ts.transform(sourceWithSplittedFunctions, [ funcInlineTransformer, ]).transformed; console.log(printer.printFile(sourceWithInlinedFuntioncs)); + +console.log( + '----------AFTER INLINE _List_fromArray TRANSFORM ----------------' +); +const inlineListFromArrayCalls = createInlineListFromArrayTransformer(); +const [sourceWithInlinedListFromArr] = ts.transform( + sourceWithInlinedFuntioncs, + [inlineListFromArrayCalls] +).transformed; + +console.log(printer.printFile(sourceWithInlinedListFromArr));