diff --git a/src/mangle-name.js b/src/mangle-name.js index 842aa84..7491970 100644 --- a/src/mangle-name.js +++ b/src/mangle-name.js @@ -5,20 +5,29 @@ const assert = require("assert"); const acceptableFirstCharacters = /^[a-zA-Z_]$/; const acceptableSubsequentCharacters = /^[0-9a-zA-Z_]$/; +const reservedWords = new Set([ + "import", + "const", + "let", + "var" +]); + // 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)}` + : `$${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("$")) { + if (reservedWords.has(name)) { + return "$" + name; + } else if (name.startsWith("$")) { + // FIXME: Tag an identifier of this type with an internal property instead return name; } else { let completedFirstCharacter = false; diff --git a/src/prepare-ast.js b/src/prepare-ast.js index cb4cc69..e1f641f 100644 --- a/src/prepare-ast.js +++ b/src/prepare-ast.js @@ -150,7 +150,7 @@ function convertNode(node) { result.uri = node.text; } - if (type === "binary_expression") { + if (type === "binary_expression" || type === "unary_expression") { // Unpack the anonymous token result.operator = result.operator.text; } @@ -201,12 +201,14 @@ function convertNode(node) { inherited_attrs: "NixInheritAttributes", attrs_inherited_from: "NixInheritAttributes", // FIXME: Gone? binding: "NixBinding", + unary_expression: "NixUnaryOperation", binary_expression: "NixBinaryOperation", apply_expression: "NixFunctionCall", select_expression: "NixAttributeSelection", interpolation: "NixInterpolationExpression", list_expression: "NixListLiteral", with_expression: "NixWithExpression", + if_expression: "NixConditional", // Function definitions function_expression: "NixFunctionDefinition", formals: "NixUnpackedAttributes", diff --git a/src/transformers/index.js b/src/transformers/index.js index f5b967a..8ae4bbc 100644 --- a/src/transformers/index.js +++ b/src/transformers/index.js @@ -34,6 +34,16 @@ let tmplImplicitContextTop = templateExpression(` Object.assign({}, %%environment%%) `); +let tmplConditionalExpression = templateExpression(` + (() => { + if (%%condition%%) { + return %%consequence%%; + } else { + return %%alternative%%; + } + })() +`); + let implicitContextCounter = 0; let trivial = { @@ -56,9 +66,10 @@ let trivial = { }, NixIdentifier: (node, { getContext }) => { // FIXME: Mangle reserved keywords like `const` - let safeName = (node.name === "import") - ? "$import" - : node.name; + // let safeName = (node.name === "import") + // ? "$import" + // : node.name; + let safeName = node.name; if (getContext("identifierType") === "define") { return types.identifier(safeName); @@ -69,6 +80,15 @@ let trivial = { return tmplIdentifierReference({ name: safeName }); } }, + NixUnaryOperation: (_node, { defer }) => { + return defer((node) => { + if (node.operator === "-") { + return types.unaryExpression(node.operator, node.argument, true); + } else { + throw new Error(`Unsupported operator: ${node.operator}`); + } + }); + }, NixBinaryOperation: (_node, { defer }) => { return defer((node) => { // FIXME: Verify that all the 'operator' values match between Nix and JS! @@ -94,9 +114,9 @@ let trivial = { setContext(null, "implicitContext", contextName); return defer((node) => { - let setupCode = (hasParent) - ? tmplImplicitContextNested({ environment: node.environment, parent: parentContext }) - : tmplImplicitContextTop({ environment: node.environment }); + let setupCode = (hasParent) + ? tmplImplicitContextNested({ environment: node.environment, parent: parentContext }) + : tmplImplicitContextTop({ environment: node.environment }); return tmplWithWrapper({ contextName: contextName, @@ -104,6 +124,16 @@ let trivial = { body: node.body }); }); + }, + NixConditional: (_node, { defer }) => { + // condition, consequence, alternative + return defer((node) => { + return tmplConditionalExpression({ + condition: node.condition, + consequence: node.consequence, + alternative: node.alternative + }); + }); } } };