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.
116 lines
3.0 KiB
JavaScript
116 lines
3.0 KiB
JavaScript
"use strict";
|
|
|
|
const asExpression = require("as-expression");
|
|
const assert = require("assert");
|
|
const types = require("@babel/types");
|
|
const template = require("@babel/template").default;
|
|
const unpackExpression = require("./_unpack-expression");
|
|
|
|
// TODO: Memoize every function
|
|
// NOTE: These are arrow functions because variable references within functions should always refer to the nearest scope; and since we use `this` to handle variable references within recursive attribute sets, we need to ensure that a function definition *does not* create its own `this` context.
|
|
let tmplFunctionDefinitionFormalsUniversal = template(`
|
|
((%%universal%%) => {
|
|
const %%formals%% = %%universal%%;
|
|
return %%body%%;
|
|
})
|
|
`);
|
|
|
|
// FIXME: Test that this template form actually works with our formals structure
|
|
let tmplFunctionDefinitionFormals = template(`
|
|
((%%formals%%) => {
|
|
return %%body%%;
|
|
})
|
|
`);
|
|
|
|
let tmplFunctionDefinitionUniversal = template(`
|
|
((%%universal%%) => {
|
|
return %%body%%;
|
|
})
|
|
`);
|
|
|
|
let tmplFunctionCall = template(`
|
|
(%%function%%(%%arg%%))
|
|
`);
|
|
|
|
// NOTE: Duplicated from `attribute-sets` for now
|
|
let tmplLazyWrapper = template(`(
|
|
$$jsNix$memoize(() => %%expression%%)
|
|
)`);
|
|
|
|
function functionDefinition({ universal, formals, body }) {
|
|
let convertedFormals = asExpression(() => {
|
|
if (formals != null) {
|
|
return types.objectPattern(formals.map((formal) => {
|
|
return types.objectProperty(
|
|
types.identifier(formal),
|
|
types.identifier(formal)
|
|
);
|
|
}));
|
|
} else {
|
|
return undefined;
|
|
}
|
|
});
|
|
|
|
if (universal != null && formals != null) {
|
|
return tmplFunctionDefinitionFormalsUniversal({
|
|
body: body,
|
|
universal: universal,
|
|
formals: convertedFormals
|
|
});
|
|
} else if (universal != null) {
|
|
return tmplFunctionDefinitionUniversal({
|
|
body: body,
|
|
universal: universal
|
|
});
|
|
} else {
|
|
return tmplFunctionDefinitionFormals({
|
|
body: body,
|
|
formals: convertedFormals
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
name: "functions",
|
|
visitors: {
|
|
NixFunctionDefinition: (_node, { defer, setContext }) => {
|
|
setContext([ "universal", "formals" ], "identifierType", "define");
|
|
|
|
return defer((node) => {
|
|
return unpackExpression(
|
|
functionDefinition({
|
|
universal: asExpression(() => {
|
|
if (node.universal != null) {
|
|
assert(node.universal.type === "Identifier");
|
|
return node.universal.name;
|
|
}
|
|
}),
|
|
formals: asExpression(() => {
|
|
if (node.formals != null) {
|
|
assert(node.formals.type === "NixUnpackedAttributes");
|
|
|
|
return node.formals.formal.map((formal) => {
|
|
assert(formal.type === "NixUnpackedAttribute");
|
|
assert(formal.name.type === "Identifier");
|
|
return formal.name.name;
|
|
});
|
|
}
|
|
}),
|
|
body: node.body
|
|
})
|
|
);
|
|
});
|
|
},
|
|
NixFunctionCall: (_node, { defer }) => {
|
|
return defer((node) => {
|
|
return unpackExpression(
|
|
tmplFunctionCall({
|
|
function: node.function,
|
|
arg: unpackExpression(tmplLazyWrapper({ expression: node.argument }))
|
|
})
|
|
);
|
|
});
|
|
}
|
|
}
|
|
};
|