You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
2.4 KiB
JavaScript
81 lines
2.4 KiB
JavaScript
"use strict";
|
|
|
|
const splitFilter = require("split-filter");
|
|
const assert = require("assert");
|
|
|
|
const NoChange = require("astformer/actions/no-change"); // FIXME
|
|
const nixTypes = require("./util/nix-types");
|
|
|
|
module.exports = {
|
|
name: "desugar-inherits",
|
|
visitors: {
|
|
NixAttributeSet: (node) => {
|
|
// console.dir(node, {depth:null})
|
|
let [ inherits, regularBindings ] = splitFilter(node.binding, (binding) => binding.type === "NixInherit");
|
|
|
|
if (inherits.length === 0) {
|
|
return NoChange;
|
|
} else {
|
|
let tempCounter = 0;
|
|
let inherits_ = inherits.map((inherit) => {
|
|
return {
|
|
tempName: `$temp$${tempCounter++}`,
|
|
sourceExpression: inherit.expression,
|
|
names: inherit.attrs.attr.map((attribute) => {
|
|
assert(attribute.type === "NixIdentifier");
|
|
return attribute.name;
|
|
})
|
|
};
|
|
});
|
|
|
|
let letBindings = inherits_.map((inherit) => {
|
|
return nixTypes.NixBinding(
|
|
[ nixTypes.NixIdentifier(inherit.tempName) ],
|
|
inherit.sourceExpression
|
|
);
|
|
});
|
|
|
|
let inheritedAttributeBindings = inherits_.flatMap((inherit) => {
|
|
return inherit.names.map((name) => {
|
|
return nixTypes.NixBinding(
|
|
[ nixTypes.NixIdentifier(name) ],
|
|
nixTypes.NixAttributeSelection(
|
|
nixTypes.NixIdentifier(inherit.tempName),
|
|
[ nixTypes.NixIdentifier(name) ]
|
|
)
|
|
);
|
|
});
|
|
});
|
|
|
|
if (node.recursive === false) {
|
|
// When not recursive, we need to ensure that the temporary variables are defined a scope *higher* than the attribute set that actually makes use of their properties, because we cannot access those variables from the attribute bindings otherwise.
|
|
|
|
return nixTypes.NixLetIn(
|
|
letBindings,
|
|
{
|
|
... node,
|
|
binding: [
|
|
... regularBindings,
|
|
... inheritedAttributeBindings
|
|
]
|
|
}
|
|
);
|
|
} else {
|
|
// ... but when recursive, we *must* specify the temporary variables as part of the recursive attribute set itself, because otherwise we don't have the ability to bidirectionally reference between fixed attributes and inherited ones; see, for example, eval-okay-scope-7.nix.
|
|
// FIXME: Mark the temporary variables as 'internal' so that they don't get returned in the final object; this would make the generated code more readable.
|
|
|
|
return {
|
|
... node,
|
|
binding: [
|
|
... regularBindings,
|
|
... letBindings,
|
|
... inheritedAttributeBindings
|
|
]
|
|
};
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
};
|