+2008-01-25 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Maciej.
+
+ Fix for bug 17012: REGRESSION: JSC can't round trip an object literal
+
+ Add logic to ensure that object literals and function expressions get
+ parenthesis when necessary.
+
+ * kjs/nodes.h:
+ * kjs/nodes2string.cpp:
+ (KJS::SourceStream::operator<<):
+
2008-01-24 Steve Falkenburg <sfalken@apple.com>
Build fix.
// Serialization.
virtual void streamTo(SourceStream&) const KJS_FAST_CALL = 0;
virtual Precedence precedence() const = 0;
-
+ virtual bool needsParensIfLeftmost() const { return false; }
+
// Used for iterative, depth-first traversal of the node tree. Does not cross function call boundaries.
virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL { }
virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
virtual Precedence precedence() const { return PrecPrimary; }
+ virtual bool needsParensIfLeftmost() const { return true; }
private:
RefPtr<PropertyListNode> list;
};
virtual JSValue *evaluate(ExecState*) KJS_FAST_CALL;
virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
virtual Precedence precedence() const { return PrecMember; }
+ virtual bool needsParensIfLeftmost() const { return true; }
private:
void addParams() KJS_FAST_CALL;
// Used for streamTo
class SourceStream {
public:
- SourceStream() : m_numberNeedsParens(false), m_precedence(PrecExpression) { }
+ SourceStream() : m_numberNeedsParens(false), m_atStartOfStatement(true), m_precedence(PrecExpression) { }
UString toString() const { return m_string; }
SourceStream& operator<<(const Identifier&);
SourceStream& operator<<(const UString&);
UString m_string;
UString m_spacesForIndentation;
bool m_numberNeedsParens;
+ bool m_atStartOfStatement;
Precedence m_precedence;
};
SourceStream& SourceStream::operator<<(char c)
{
m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
UChar ch(c);
m_string.append(ch);
return *this;
SourceStream& SourceStream::operator<<(const char* s)
{
m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
m_string += s;
return *this;
}
{
bool needParens = m_numberNeedsParens;
m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
if (needParens)
m_string.append('(');
SourceStream& SourceStream::operator<<(const UString& s)
{
m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
m_string += s;
return *this;
}
SourceStream& SourceStream::operator<<(const Identifier& s)
{
m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
m_string += s.ustring();
return *this;
}
SourceStream& SourceStream::operator<<(const Node* n)
{
- bool needParens = m_precedence != PrecExpression && n->precedence() > m_precedence;
+ bool needParens = (m_precedence != PrecExpression && n->precedence() > m_precedence) || (m_atStartOfStatement && n->needsParensIfLeftmost());
m_precedence = PrecExpression;
if (n) {
if (needParens)
SourceStream& SourceStream::operator<<(EndlType)
{
m_numberNeedsParens = false;
+ m_atStartOfStatement = true;
m_string.append('\n');
m_string.append(m_spacesForIndentation);
return *this;
SourceStream& SourceStream::operator<<(IndentType)
{
m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
m_spacesForIndentation += " ";
return *this;
}
SourceStream& SourceStream::operator<<(UnindentType)
{
m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
m_spacesForIndentation = m_spacesForIndentation.substr(0, m_spacesForIndentation.size() - 2);
return *this;
}
+2008-01-25 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Maciej.
+
+ Add additional check for using Function.toString on a function with object literals
+
+ * fast/js/function-toString-parentheses-expected.txt:
+ * fast/js/resources/function-toString-parentheses.js:
+
2008-01-25 Darin Adler <darin@apple.com>
Reviewed by Anders.
PASS compileAndSerialize('!a--') is '!a--'
PASS compileAndSerialize('!(a--)') is '!a--'
PASS compileAndSerialize('(!a)--') is '(!a)--'
+PASS compileAndSerializeLeftmostTest('({ }).x') is '({ }).x'
+PASS compileAndSerializeLeftmostTest('x = { }') is 'x = { }'
+PASS compileAndSerializeLeftmostTest('(function () { })()') is '(function () { })()'
+PASS compileAndSerializeLeftmostTest('x = function () { }') is 'x = function () { }'
PASS successfullyParsed is true
TEST COMPLETE
return serializedString;
}
+function compileAndSerializeLeftmostTest(expression)
+{
+ var f = eval("(function () { " + expression + "; })");
+ var serializedString = f.toString();
+ serializedString = serializedString.replace(/[ \t\r\n]+/g, " ");
+ serializedString = serializedString.replace("function () { ", "");
+ serializedString = serializedString.replace("; }", "");
+ return serializedString;
+}
+
var removesExtraParentheses = compileAndSerialize("(a + b) + c") == "a + b + c";
function testLeftAssociativeSame(opA, opB)
shouldBe("compileAndSerialize('!a--')", "'!a--'");
shouldBe("compileAndSerialize('!(a--)')", "'!a--'");
shouldBe("compileAndSerialize('(!a)--')", "'(!a)--'");
-
+shouldBe("compileAndSerializeLeftmostTest('({ }).x')", "'({ }).x'");
+shouldBe("compileAndSerializeLeftmostTest('x = { }')", "'x = { }'");
+shouldBe("compileAndSerializeLeftmostTest('(function () { })()')", "'(function () { })()'");
+shouldBe("compileAndSerializeLeftmostTest('x = function () { }')", "'x = function () { }'");
var successfullyParsed = true;