/* * Transforms obj["foo"] into obj.foo whenever possible, saving 3 bytes. */ private static void OptimizeObjectMemberAccess(IList tokens) { string tv; int i, length; JavaScriptToken token; for (i = 0, length = tokens.Count; i < length; i++) { if (((JavaScriptToken) tokens[i]).TokenType == Token.LB && i > 0 && i < length - 2 && ((JavaScriptToken) tokens[i - 1]).TokenType == Token.NAME && ((JavaScriptToken) tokens[i + 1]).TokenType == Token.STRING && ((JavaScriptToken) tokens[i + 2]).TokenType == Token.RB) { token = (JavaScriptToken) tokens[i + 1]; tv = token.Value; tv = tv.Substring(1, tv.Length - 2); if (IsValidIdentifier(tv)) { tokens[i] = new JavaScriptToken(Token.DOT, "."); tokens[i + 1] = new JavaScriptToken(Token.NAME, tv); tokens.RemoveAt(i + 2); i = i + 2; length = length - 1; } } } }
/* * Transforms 'foo': ... into foo: ... whenever possible, saving 2 bytes. */ private static void OptimizeObjLitMemberDecl(IList tokens) { string tv; int i, length; JavaScriptToken token; for (i = 0, length = tokens.Count; i < length; i++) { if (((JavaScriptToken) tokens[i]).TokenType == Token.OBJECTLIT && i > 0 && ((JavaScriptToken) tokens[i - 1]).TokenType == Token.STRING) { token = (JavaScriptToken) tokens[i - 1]; tv = token.Value; tv = tv.Substring(1, tv.Length - 2); if (IsValidIdentifier(tv)) { tokens[i - 1] = new JavaScriptToken(Token.NAME, tv); } } } }
private static void ProcessStringLiterals(IList tokens, bool merge) { string tv; int i, length = tokens.Count; JavaScriptToken token, prevToken, nextToken; if (merge) { // Concatenate string literals that are being appended wherever // it is safe to do so. Note that we take care of the case: // "a" + "b".toUpperCase() for (i = 0; i < length; i++) { token = (JavaScriptToken) tokens[i]; switch (token.TokenType) { case Token.ADD: if (i > 0 && i < length) { prevToken = (JavaScriptToken) tokens[i - 1]; nextToken = (JavaScriptToken) tokens[i + 1]; if (prevToken.TokenType == Token.STRING && nextToken.TokenType == Token.STRING && (i == length - 1 || ((JavaScriptToken) tokens[i + 2]).TokenType != Token.DOT)) { tokens[i - 1] = new JavaScriptToken(Token.STRING, prevToken.Value + nextToken.Value); tokens.RemoveAt(i + 1); tokens.RemoveAt(i); i = i - 1; length = length - 2; break; } } break; } } } // Second pass... for (i = 0; i < length; i++) { token = (JavaScriptToken) tokens[i]; if (token.TokenType == Token.STRING) { tv = token.Value; // Finally, add the quoting characters and escape the string. We use // the quoting character that minimizes the amount of escaping to save // a few additional bytes. int singleQuoteCount = CountChar(tv, '\''); int doubleQuoteCount = CountChar(tv, '"'); char quotechar = doubleQuoteCount <= singleQuoteCount ? '"' : '\''; tv = quotechar + EscapeString(tv, quotechar) + quotechar; // String concatenation transforms the old script scheme: // '<scr'+'ipt ...><'+'/script>' // into the following: // '<script ...></script>' // which breaks if this code is embedded inside an HTML document. // Since this is not the right way to do this, let's fix the code by // transforming all "</script" into "<\/script" if (tv.IndexOf("</script", StringComparison.OrdinalIgnoreCase) >= 0) { tv = tv.Replace("<\\/script", "<\\\\/script"); } tokens[i] = new JavaScriptToken(Token.STRING, tv); } } }