summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/Parser.cpp
diff options
context:
space:
mode:
authorGaming4JC <g4jc@hyperbola.info>2019-07-13 21:33:52 -0400
committerGaming4JC <g4jc@hyperbola.info>2019-07-18 22:38:41 -0400
commit53e46b1e12ef01ccaabb3256738ea1eac74b7941 (patch)
treed6d90d717876c7c15b8d851ee9ffaa6fd394939e /js/src/frontend/Parser.cpp
parentd1c146adf23e317facd03cd5c097f12a69947392 (diff)
downloadUXP-53e46b1e12ef01ccaabb3256738ea1eac74b7941.tar
UXP-53e46b1e12ef01ccaabb3256738ea1eac74b7941.tar.gz
UXP-53e46b1e12ef01ccaabb3256738ea1eac74b7941.tar.lz
UXP-53e46b1e12ef01ccaabb3256738ea1eac74b7941.tar.xz
UXP-53e46b1e12ef01ccaabb3256738ea1eac74b7941.zip
1216630 - Print class source when calling toString on the constructor.
This is accomplished in the following ways. LazyScripts and JSScripts now have 4 offsets: - Source begin and end for the actual source. This is used for lazy parsing. - toString begin and end for toString. Some kinds of functions, like async, only have a different begin offset. Class constructors have different offsets for both begin and end. For syntactically present (i.e. non-default) constructors, the class source span is remembered directly on the LazyScript or JSScript. The toString implementation then splices out the substring directly. For default constructors, a new SRC_CLASS SrcNote type is added. It's binary and has as its arguments the begin and end offsets of the class expression or statement. MakeDefaultConstructor reads the note and overrides the cloned self-hosted function's source object. This is probably the least intrusive way to accomplish this.
Diffstat (limited to 'js/src/frontend/Parser.cpp')
-rw-r--r--js/src/frontend/Parser.cpp85
1 files changed, 62 insertions, 23 deletions
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index d62a26f76..299b8b93a 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -141,7 +141,8 @@ StatementKindIsBraced(StatementKind kind)
kind == StatementKind::Switch ||
kind == StatementKind::Try ||
kind == StatementKind::Catch ||
- kind == StatementKind::Finally;
+ kind == StatementKind::Finally ||
+ kind == StatementKind::Class;
}
void
@@ -472,6 +473,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac
startLine(1),
startColumn(0),
preludeStart(preludeStart),
+ postludeEnd(0),
length(0),
generatorKindBits_(GeneratorKindAsBits(generatorKind)),
asyncKindBits_(AsyncKindAsBits(asyncKind)),
@@ -542,10 +544,16 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
allowNewTarget_ = true;
allowSuperProperty_ = fun->allowSuperProperty();
- if (kind == DerivedClassConstructor) {
- setDerivedClassConstructor();
- allowSuperCall_ = true;
- needsThisTDZChecks_ = true;
+ if (kind == ClassConstructor || kind == DerivedClassConstructor) {
+ auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
+ MOZ_ASSERT(stmt);
+ stmt->setConstructorBox(this);
+
+ if (kind == DerivedClassConstructor) {
+ setDerivedClassConstructor();
+ allowSuperCall_ = true;
+ needsThisTDZChecks_ = true;
+ }
}
if (isGenexpLambda)
@@ -566,6 +574,16 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
}
void
+FunctionBox::resetForAbortedSyntaxParse(ParseContext* enclosing, FunctionSyntaxKind kind)
+{
+ if (kind == ClassConstructor || kind == DerivedClassConstructor) {
+ auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
+ MOZ_ASSERT(stmt);
+ stmt->clearConstructorBoxForAbortedSyntaxParse(this);
+ }
+}
+
+void
FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
{
if (!function()->isArrow()) {
@@ -3389,6 +3407,7 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
// correctness.
parser->clearAbortedSyntaxParse();
usedNames.rewind(token);
+ funbox->resetForAbortedSyntaxParse(pc, kind);
MOZ_ASSERT_IF(parser->context->isJSContext(),
!parser->context->asJSContext()->isExceptionPending());
break;
@@ -3670,14 +3689,14 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
error(JSMSG_CURLY_AFTER_BODY);
return false;
}
- funbox->bufEnd = pos().end;
+ funbox->setEnd(pos().end);
} else {
#if !JS_HAS_EXPR_CLOSURES
MOZ_ASSERT(kind == Arrow);
#endif
if (tokenStream.hadError())
return false;
- funbox->bufEnd = pos().end;
+ funbox->setEnd(pos().end);
if (kind == Statement && !matchOrInsertSemicolonAfterExpression())
return false;
}
@@ -6935,6 +6954,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS));
+ uint32_t classStartOffset = pos().begin;
bool savedStrictness = setLocalStrictMode(true);
TokenKind tt;
@@ -6960,16 +6980,20 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
tokenStream.ungetToken();
}
+ // Push a ParseContext::ClassStatement to keep track of the constructor
+ // funbox.
+ ParseContext::ClassStatement classStmt(pc);
+
RootedAtom propAtom(context);
// A named class creates a new lexical scope with a const binding of the
- // class name.
- Maybe<ParseContext::Statement> classStmt;
- Maybe<ParseContext::Scope> classScope;
+ // class name for the "inner name".
+ Maybe<ParseContext::Statement> innerScopeStmt;
+ Maybe<ParseContext::Scope> innerScope;
if (name) {
- classStmt.emplace(pc, StatementKind::Block);
- classScope.emplace(this);
- if (!classScope->init(pc))
+ innerScopeStmt.emplace(pc, StatementKind::Block);
+ innerScope.emplace(this);
+ if (!innerScope->init(pc))
return null();
}
@@ -6996,7 +7020,6 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!classMethods)
return null();
- bool seenConstructor = false;
for (;;) {
TokenKind tt;
if (!tokenStream.getToken(&tt))
@@ -7048,16 +7071,17 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
propType = PropertyType::GetterNoExpressionClosure;
if (propType == PropertyType::Setter)
propType = PropertyType::SetterNoExpressionClosure;
- if (!isStatic && propAtom == context->names().constructor) {
+
+ bool isConstructor = !isStatic && propAtom == context->names().constructor;
+ if (isConstructor) {
if (propType != PropertyType::Method) {
errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
return null();
}
- if (seenConstructor) {
+ if (classStmt.constructorBox()) {
errorAt(nameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor");
return null();
}
- seenConstructor = true;
propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor;
} else if (isStatic && propAtom == context->names().prototype) {
errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
@@ -7082,7 +7106,12 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!tokenStream.isCurrentTokenType(TOK_RB))
funName = propAtom;
}
- Node fn = methodDefinition(nameOffset, propType, funName);
+
+ // Calling toString on constructors need to return the source text for
+ // the entire class. The end offset is unknown at this point in
+ // parsing and will be amended when class parsing finishes below.
+ Node fn = methodDefinition(isConstructor ? classStartOffset : nameOffset,
+ propType, funName);
if (!fn)
return null();
@@ -7093,6 +7122,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
return null();
}
+ // Amend the postlude offset for the constructor now that we've finished
+ // parsing the class.
+ uint32_t classEndOffset = pos().end;
+ if (FunctionBox* ctorbox = classStmt.constructorBox()) {
+ if (ctorbox->function()->isInterpretedLazy())
+ ctorbox->function()->lazyScript()->setPostludeEnd(classEndOffset);
+ ctorbox->postludeEnd = classEndOffset;
+ }
+
Node nameNode = null();
Node methodsOrBlock = classMethods;
if (name) {
@@ -7104,15 +7142,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!innerName)
return null();
- Node classBlock = finishLexicalScope(*classScope, classMethods);
+ Node classBlock = finishLexicalScope(*innerScope, classMethods);
if (!classBlock)
return null();
methodsOrBlock = classBlock;
// Pop the inner scope.
- classScope.reset();
- classStmt.reset();
+ innerScope.reset();
+ innerScopeStmt.reset();
Node outerName = null();
if (classContext == ClassStatement) {
@@ -7132,7 +7170,8 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness));
- return handler.newClass(nameNode, classHeritage, methodsOrBlock);
+ return handler.newClass(nameNode, classHeritage, methodsOrBlock,
+ TokenPos(classStartOffset, classEndOffset));
}
template <class ParseHandler>
@@ -8388,7 +8427,7 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
uint32_t end = pos().end;
handler.setBeginPosition(comp, begin);
handler.setEndPosition(comp, end);
- genFunbox->bufEnd = end;
+ genFunbox->setEnd(end);
handler.addStatementToList(body, comp);
handler.setEndPosition(body, end);
handler.setBeginPosition(genfn, begin);