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.
107 lines
2.8 KiB
JavaScript
107 lines
2.8 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 lazyWrapper = require("./templates/lazy-wrapper");
|
|
const callLazyWrapper = require("./templates/call-lazy-wrapper");
|
|
const templateExpression = require("./util/template-expression");
|
|
|
|
let tmplFunctionDefinitionUniversal = templateExpression(`
|
|
((%%universal%%) => {
|
|
return %%body%%;
|
|
})
|
|
`);
|
|
|
|
let tmplFunctionDefinitionWithFormals = templateExpression(`(
|
|
(%%universal%%) => {
|
|
%%handleArguments%%;
|
|
|
|
return %%body%%;
|
|
}
|
|
)`);
|
|
|
|
let tmplHandleArgument = template(`
|
|
const %%name%% = $handleArgument(%%nameString%%, %%universal%%, %%defaultArg%%);
|
|
`);
|
|
|
|
let tmplFunctionCall = templateExpression(`
|
|
(%%function%%(%%arg%%))
|
|
`);
|
|
|
|
function typesUndefined() {
|
|
// Apparently there's no undefinedLiteral???
|
|
return types.unaryExpression("void", types.numericLiteral(0));
|
|
}
|
|
|
|
function functionDefinition({ universal, formals, body }) {
|
|
if (formals != null) {
|
|
let defaultedUniversal = universal ?? "$tempArg";
|
|
|
|
return tmplFunctionDefinitionWithFormals({
|
|
universal: defaultedUniversal,
|
|
body: body,
|
|
handleArguments: formals.map((formal) => {
|
|
return tmplHandleArgument({
|
|
universal: defaultedUniversal,
|
|
name: types.identifier(formal.name),
|
|
nameString: types.stringLiteral(formal.name),
|
|
defaultArg: formal.default ?? typesUndefined()
|
|
});
|
|
})
|
|
});
|
|
} else {
|
|
return tmplFunctionDefinitionUniversal({
|
|
body: body,
|
|
universal: universal
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
name: "functions",
|
|
visitors: {
|
|
NixFunctionDefinition: (_node, { defer, setContext }) => {
|
|
setContext([ "universal", "formals" ], "identifierType", "define");
|
|
|
|
return defer((node) => {
|
|
return 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 {
|
|
name: formal.name.name,
|
|
// NOTE: This unwrap-and-rewrap dance is necessary to make out-of-order references work, like in eval-okay-scope-4.nix
|
|
default: (formal.default != null)
|
|
? lazyWrapper(callLazyWrapper(formal.default))
|
|
: undefined
|
|
};
|
|
});
|
|
}
|
|
}),
|
|
body: node.body
|
|
});
|
|
});
|
|
},
|
|
NixFunctionCall: (_node, { defer }) => {
|
|
return defer((node) => {
|
|
return tmplFunctionCall({
|
|
function: node.function,
|
|
arg: lazyWrapper(node.argument)
|
|
});
|
|
});
|
|
}
|
|
}
|
|
};
|