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

"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)
});
});
}
}
};