Use heap-of-vars for rec attrsets, fix lazy function args
This commit is contained in:
parent
c87f70e40a
commit
40db79aea0
1
samples/attrset-nested-both.nix
Normal file
1
samples/attrset-nested-both.nix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
rec { a = 1; b = rec { c = d.foo; }; d = { foo = a; }; }.b.c
|
|
@ -5,6 +5,7 @@ const types = require("@babel/types");
|
||||||
const template = require("@babel/template").default;
|
const template = require("@babel/template").default;
|
||||||
const unpackExpression = require("./_unpack-expression");
|
const unpackExpression = require("./_unpack-expression");
|
||||||
const NoChange = require("../astformer/actions/no-change");
|
const NoChange = require("../astformer/actions/no-change");
|
||||||
|
const printAst = require("../print-ast");
|
||||||
|
|
||||||
// FIXME: Add expression parens!
|
// FIXME: Add expression parens!
|
||||||
let tmplCallLazy = template(`
|
let tmplCallLazy = template(`
|
||||||
|
@ -23,9 +24,23 @@ let tmplExtend = template(`(
|
||||||
$$jsNix$extend(this ?? {}, %%object%%)
|
$$jsNix$extend(this ?? {}, %%object%%)
|
||||||
)`);
|
)`);
|
||||||
|
|
||||||
|
let tmplScopeWrapper = template(`(
|
||||||
|
(() => {
|
||||||
|
%%bindings%%;
|
||||||
|
|
||||||
|
return %%object%%;
|
||||||
|
})()
|
||||||
|
)`);
|
||||||
|
|
||||||
|
// FIXME: Verify that this always works, and that we don't need `var` for hoisting!
|
||||||
|
let tmplRecursiveBinding = template(`
|
||||||
|
const %%name%% = %%expression%%;
|
||||||
|
`);
|
||||||
|
|
||||||
function lazyEvaluationWrapper(args) {
|
function lazyEvaluationWrapper(args) {
|
||||||
let { recursive, ... rest } = args;
|
let { recursive, ... rest } = args;
|
||||||
|
|
||||||
|
// printAst(rest.expression);
|
||||||
let wrapper = (recursive)
|
let wrapper = (recursive)
|
||||||
? tmplLazyWrapperRecursive
|
? tmplLazyWrapperRecursive
|
||||||
: tmplLazyWrapper;
|
: tmplLazyWrapper;
|
||||||
|
@ -68,23 +83,41 @@ module.exports = {
|
||||||
let isRecursive = node.recursive;
|
let isRecursive = node.recursive;
|
||||||
let hasDynamicBindings = node.bind.some((binding) => isDynamicBinding(binding));
|
let hasDynamicBindings = node.bind.some((binding) => isDynamicBinding(binding));
|
||||||
|
|
||||||
|
let bindings = node.bind.map((binding) => {
|
||||||
|
assert(binding.attrpath.attr.length === 1); // Nested attributes should have been desugared by this point
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: binding.attrpath.attr[0].name,
|
||||||
|
expression: lazyEvaluationWrapper({ recursive: isRecursive, expression: binding.expression })
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
if (hasDynamicBindings) {
|
if (hasDynamicBindings) {
|
||||||
throw new Error(`UNIMPLEMENTED: Dynamic bindings are not supported yet`);
|
throw new Error(`UNIMPLEMENTED: Dynamic bindings are not supported yet`);
|
||||||
|
} else if (isRecursive) {
|
||||||
|
return unpackExpression(tmplScopeWrapper({
|
||||||
|
bindings: bindings.map(({ name, expression }) => {
|
||||||
|
return tmplRecursiveBinding({
|
||||||
|
name: name,
|
||||||
|
expression: expression
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
object: types.objectExpression(bindings.map(({ name }) => {
|
||||||
|
return types.objectProperty(
|
||||||
|
types.stringLiteral(name),
|
||||||
|
types.identifier(name)
|
||||||
|
);
|
||||||
|
}))
|
||||||
|
}));
|
||||||
} else {
|
} else {
|
||||||
let object = types.objectExpression(node.bind.map((binding) => {
|
let object = types.objectExpression(bindings.map(({ name, expression }) => {
|
||||||
assert(binding.attrpath.attr.length === 1); // Nested attributes should have been desugared by this point
|
|
||||||
let name = binding.attrpath.attr[0].name;
|
|
||||||
let expression = binding.expression;
|
|
||||||
|
|
||||||
return types.objectProperty(
|
return types.objectProperty(
|
||||||
types.stringLiteral(name),
|
types.stringLiteral(name),
|
||||||
lazyEvaluationWrapper({ recursive: isRecursive, expression: expression })
|
// TODO: Remove the isRecursive distinction here once heap-of-vars works
|
||||||
|
expression
|
||||||
);
|
);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// FIXME/MARKER: This is currently broken!
|
|
||||||
console.log({context: getContext("attributeSets_inRecursiveSet")});
|
|
||||||
|
|
||||||
// Only do prototypal inheritance for `this` if we're dealing with nested recursive attribute sets
|
// Only do prototypal inheritance for `this` if we're dealing with nested recursive attribute sets
|
||||||
if (isRecursive && getContext("attributeSets_inRecursiveSet") === true) {
|
if (isRecursive && getContext("attributeSets_inRecursiveSet") === true) {
|
||||||
return unpackExpression(tmplExtend({
|
return unpackExpression(tmplExtend({
|
||||||
|
|
|
@ -32,6 +32,11 @@ let tmplFunctionCall = template(`
|
||||||
(%%function%%(%%arg%%))
|
(%%function%%(%%arg%%))
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
// NOTE: Duplicated from `attribute-sets` for now
|
||||||
|
let tmplLazyWrapper = template(`(
|
||||||
|
() => %%expression%%
|
||||||
|
)`);
|
||||||
|
|
||||||
function functionDefinition({ universal, formals, body }) {
|
function functionDefinition({ universal, formals, body }) {
|
||||||
let convertedFormals = asExpression(() => {
|
let convertedFormals = asExpression(() => {
|
||||||
if (formals != null) {
|
if (formals != null) {
|
||||||
|
@ -101,7 +106,7 @@ module.exports = {
|
||||||
return unpackExpression(
|
return unpackExpression(
|
||||||
tmplFunctionCall({
|
tmplFunctionCall({
|
||||||
function: node.function,
|
function: node.function,
|
||||||
arg: node.argument
|
arg: unpackExpression(tmplLazyWrapper({ expression: node.argument }))
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -47,7 +47,7 @@ let tmplObjectDynamicEntry = template(`
|
||||||
`);
|
`);
|
||||||
|
|
||||||
let tmplIdentifierReference = template(`(
|
let tmplIdentifierReference = template(`(
|
||||||
(this?.%%name%% ?? %%name%%)()
|
%%name%%()
|
||||||
)`);
|
)`);
|
||||||
|
|
||||||
function generateDynamicObject(bindings, recursive) {
|
function generateDynamicObject(bindings, recursive) {
|
||||||
|
|
Loading…
Reference in a new issue