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