WIP, identifier mangling, inherit support
parent
52f39570a7
commit
f23f6f6393
@ -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
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue