Skip to content

Commit

Permalink
Fix property name quoting in decompiler
Browse files Browse the repository at this point in the history
  • Loading branch information
syg committed Aug 28, 2011
1 parent 592f352 commit 58e7033
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 27 deletions.
13 changes: 10 additions & 3 deletions lib/jsdecomp.js
Expand Up @@ -46,6 +46,7 @@

Narcissus.decompiler = (function() {

const lexer = Narcissus.lexer;
const parser = Narcissus.parser;
const definitions = Narcissus.definitions;
const tokens = definitions.tokens;
Expand Down Expand Up @@ -486,9 +487,15 @@ Narcissus.decompiler = (function() {
if (t.type === PROPERTY_INIT) {
var tc = t.children;
var l;
// see if the left needs to be a string
if (tc[0].value === "" || /[^A-Za-z0-9_$]/.test(tc[0].value) ||
(/^[a-z]*$/.test(tc[0].value) && tc[0].value in Narcissus.definitions.keywords)) {
/*
* See if the left needs to be quoted.
*
* N.B. If negative numeral prop names ever get converted
* internally to numbers by the parser, we need to quote
* those also.
*/
var propName = tc[0].value;
if (typeof propName === "string" && !lexer.isIdentifier(propName)) {
l = nodeStr(tc[0]);
} else {
l = pp(tc[0], d);
Expand Down
78 changes: 54 additions & 24 deletions lib/jslex.js
Expand Up @@ -77,6 +77,53 @@ Narcissus.lexer = (function() {
}
}

/*
* Since JavaScript provides no convenient way to determine if a
* character is in a particular Unicode category, we use
* metacircularity to accomplish this (oh yeaaaah!)
*/
function isValidIdentifierChar(ch, first) {
// check directly for ASCII
if (ch <= "\u007F") {
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_' ||
(!first && (ch >= '0' && ch <= '9'))) {
return true;
}
return false;
}

// create an object to test this in
var x = {};
x["x"+ch] = true;
x[ch] = true;

// then use eval to determine if it's a valid character
var valid = false;
try {
valid = (Function("x", "return (x." + (first?"":"x") + ch + ");")(x) === true);
} catch (ex) {}

return valid;
}

function isIdentifier(str) {
if (typeof str !== "string")
return false;

if (str.length === 0)
return false;

if (!isValidIdentifierChar(str[0], true))
return false;

for (var i = 1; i < str.length; i++) {
if (!isValidIdentifierChar(str[i], false))
return false;
}

return true;
}

/*
* Tokenizer :: (source, filename, line number) -> Tokenizer
*/
Expand Down Expand Up @@ -495,11 +542,10 @@ Narcissus.lexer = (function() {
return e;
},


/* Gets a single valid identifier char from the input stream, or null
* if there is none.
* Since JavaScript provides no convenient way to determine if a
* character is in a particular Unicode category, we use
* metacircularity to accomplish this (oh yeaaaah!) */
*/
getValidIdentifierChar: function(first) {
var input = this.source;
if (this.cursor >= input.length) return null;
Expand All @@ -518,32 +564,16 @@ Narcissus.lexer = (function() {
this.cursor += 5;
}

// check directly for ASCII
if (ch <= "\u007F") {
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_' ||
(!first && (ch >= '0' && ch <= '9'))) {
this.cursor++;
return ch;
}
return null;
}

// create an object to test this in
var x = {};
x["x"+ch] = true;
x[ch] = true;

// then use eval to determine if it's a valid character
var valid = false;
try {
valid = (Function("x", "return (x." + (first?"":"x") + ch + ");")(x) === true);
} catch (ex) {}
var valid = isValidIdentifierChar(ch, first);
if (valid) this.cursor++;
return (valid ? ch : null);
},
};


return { Tokenizer: Tokenizer };
return {
isIdentifier: isIdentifier,
Tokenizer: Tokenizer
};

}());

0 comments on commit 58e7033

Please sign in to comment.