10 changed files with 1107 additions and 43 deletions
@ -0,0 +1,42 @@ |
|||
"use strict"; |
|||
|
|||
const assert = require("assert"); |
|||
|
|||
const acceptableFirstCharacters = /^[a-zA-Z_]$/; |
|||
const acceptableSubsequentCharacters = /^[0-9a-zA-Z_]$/; |
|||
|
|||
// This function deterministically and statelessly translates a name such that it is guaranteed to be valid in all identifier positions in JS.
|
|||
// TODO: This can probably be made more performant...
|
|||
|
|||
function mangleCharacter(character) { |
|||
return (character === "$") |
|||
? "$$" |
|||
: `$${character.codePointAt(0)}` |
|||
} |
|||
|
|||
module.exports = function mangleName(name) { |
|||
assert(name.length > 0); |
|||
|
|||
// FIXME: Tag an identifier of this type with an internal property instead
|
|||
if (name.startsWith("$$jsNix$")) { |
|||
return name; |
|||
} else { |
|||
let completedFirstCharacter = false; |
|||
|
|||
return Array.from(name) |
|||
.map((character) => { |
|||
if (!completedFirstCharacter) { |
|||
completedFirstCharacter = true; |
|||
|
|||
return (acceptableFirstCharacters.test(character)) |
|||
? character |
|||
: mangleCharacter(character); |
|||
} else { |
|||
return (acceptableSubsequentCharacters.test(character)) |
|||
? character |
|||
: mangleCharacter(character); |
|||
} |
|||
}) |
|||
.join(""); |
|||
} |
|||
}; |
@ -0,0 +1,62 @@ |
|||
"use strict"; |
|||
|
|||
const splitFilter = require("split-filter"); |
|||
const assert = require("assert"); |
|||
|
|||
const NoChange = require("../astformer/actions/no-change"); |
|||
const nixTypes = require("./_nix-types"); |
|||
|
|||
module.exports = { |
|||
name: "desugar-inherits", |
|||
visitors: { |
|||
NixAttributeSet: (node) => { |
|||
let [ inherits, regularBindings ] = splitFilter(node.bind, (binding) => binding.type === "NixInherit"); |
|||
|
|||
if (inherits.length === 0) { |
|||
return NoChange; |
|||
} else { |
|||
let tempCounter = 0; |
|||
let inherits_ = inherits.map((inherit) => { |
|||
return { |
|||
tempName: `$$jsNix$temp$${tempCounter++}`, |
|||
sourceExpression: inherit.expression, |
|||
names: inherit.attrs.attr.map((attribute) => { |
|||
assert(attribute.type === "NixAttributeIdentifier"); |
|||
return attribute.name; |
|||
}) |
|||
}; |
|||
}); |
|||
|
|||
let letBindings = inherits_.map((inherit) => { |
|||
return nixTypes.NixBinding( |
|||
[ nixTypes.NixAttributeIdentifier(inherit.tempName) ], |
|||
inherit.sourceExpression |
|||
); |
|||
}); |
|||
|
|||
let body = { |
|||
... node, |
|||
bind: [ |
|||
... regularBindings, |
|||
... inherits_.flatMap((inherit) => { |
|||
return inherit.names.map((name) => { |
|||
return nixTypes.NixBinding( |
|||
[ nixTypes.NixAttributeIdentifier(name) ], |
|||
nixTypes.NixAttributeSelection( |
|||
nixTypes.NixIdentifier(inherit.tempName), |
|||
[ nixTypes.NixAttributeIdentifier(name) ] |
|||
) |
|||
); |
|||
}); |
|||
}) |
|||
] |
|||
}; |
|||
|
|||
return nixTypes.NixLetIn( |
|||
letBindings, |
|||
body |
|||
); |
|||
} |
|||
} |
|||
} |
|||
}; |
@ -0,0 +1,24 @@ |
|||
"use strict"; |
|||
|
|||
const NoChange = require("../astformer/actions/no-change"); |
|||
const mangleName = require("../mangle-name"); |
|||
|
|||
function mangleNode(node) { |
|||
if (node._isMangled) { |
|||
return NoChange; |
|||
} else { |
|||
return { |
|||
... node, |
|||
name: mangleName(node.name), |
|||
_isMangled: true |
|||
}; |
|||
} |
|||
} |
|||
|
|||
module.exports = { |
|||
name: "mangle-identifiers", |
|||
visitors: { |
|||
NixAttributeIdentifier: mangleNode, |
|||
NixIdentifier: mangleNode |
|||
} |
|||
}; |
File diff suppressed because it is too large
Loading…
Reference in new issue