From 4cb239c6a0080f9d8cf3ed29544fcaa3e84301cc Mon Sep 17 00:00:00 2001 From: Sven Slootweg Date: Wed, 2 Feb 2022 14:16:02 +0100 Subject: [PATCH] WIP, memoize lazy evaluation wrappers --- .gitignore | 1 + run.js | 38 +++++++++++++++++++++++------- src/astformer/util/measure-time.js | 2 ++ src/transformers/attribute-sets.js | 2 +- src/transformers/functions.js | 2 +- src/transformers/index.js | 11 +-------- 6 files changed, 36 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 1f04195..1907e34 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules private-notes.txt +old diff --git a/run.js b/run.js index 2836b1c..2b89f3a 100644 --- a/run.js +++ b/run.js @@ -4,6 +4,7 @@ const fs = require("fs"); const assert = require("assert"); const transpile = require("./src/transpile"); +const measureTime = require("./src/astformer/util/measure-time"); assert(process.argv[2] != null); @@ -12,13 +13,34 @@ const nixFile = fs.readFileSync(nixFilePath, "utf8"); let transpiled = transpile(nixFile); -console.log("-- EVALUATION RESULT:"); - -console.log(eval(transpiled)({ +const api = { builtins: {}, - $$jsNix$extend: function (base, props) { - let newObject = Object.create(base); - Object.assign(newObject, props); - return newObject; + $$jsNix$memoize: function (func) { + let isCalled = false; + let storedResult; + + return function (arg) { + if (isCalled === false) { + storedResult = func(arg); + isCalled = true; + } + + return storedResult; + }; } -})); +}; + +// TODO: Switch to Node `vm` API instead, and check whether there's a polyfill for it for non-Node environments, build a custom one if not +const context = { module: {}, exports: {} }; +context.module.exports = exports; + +new Function("module", transpiled)(context.module); + +console.log("-- EVALUATION RESULT:"); + +// Warm-up for hot VM performance testing +// for (let i = 0; i < 10000; i++) { +// context.module.exports(api); +// } + +console.log(measureTime(() => context.module.exports(api))); diff --git a/src/astformer/util/measure-time.js b/src/astformer/util/measure-time.js index db17728..21576ee 100644 --- a/src/astformer/util/measure-time.js +++ b/src/astformer/util/measure-time.js @@ -1,5 +1,7 @@ "use strict"; +// FIXME: Make separate package, measure-function-call or so + function hrtimeToNanoseconds(time) { // If the numbers here become big enough to cause loss of precision, we probably have bigger issues than numeric precision... return (time[0] * 1e9) + time[1]; diff --git a/src/transformers/attribute-sets.js b/src/transformers/attribute-sets.js index 30741ac..700792c 100644 --- a/src/transformers/attribute-sets.js +++ b/src/transformers/attribute-sets.js @@ -13,7 +13,7 @@ let tmplCallLazy = template(` `); let tmplLazyWrapper = template(`( - () => %%expression%% + $$jsNix$memoize(() => %%expression%%) )`); let tmplLazyWrapperRecursive = template(`( diff --git a/src/transformers/functions.js b/src/transformers/functions.js index 32ecbb5..ca8812d 100644 --- a/src/transformers/functions.js +++ b/src/transformers/functions.js @@ -34,7 +34,7 @@ let tmplFunctionCall = template(` // NOTE: Duplicated from `attribute-sets` for now let tmplLazyWrapper = template(`( - () => %%expression%% + $$jsNix$memoize(() => %%expression%%) )`); function functionDefinition({ universal, formals, body }) { diff --git a/src/transformers/index.js b/src/transformers/index.js index 9007aa9..e81027e 100644 --- a/src/transformers/index.js +++ b/src/transformers/index.js @@ -17,20 +17,11 @@ const printAst = require("../print-ast"); // FIXME: Make strict mode! Otherwise objects will inherit from `global` let tmplModule = template(` - module.exports = function({ builtins, $$jsNix$extend }) { + module.exports = function({ builtins, $$jsNix$memoize }) { return %%contents%%; }; `); - -let tmplLetIn = template(` - (() => { - %%letBindings%% - - return %%expression%%; - })() -`); - let tmplObjectDynamic = template(` (() => { let $$nixJS_object = {};