--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -4,16 +4,17 @@
#include <mozilla/Move.h>
#include <mozilla/PodOperations.h>
#include <mozilla/Vector.h>
#include <frontend/Parser.h>
#include <frontend/ParseNode.h>
#include <frontend/BinTokenReader.h>
+#include <vm/RegExpObject.h>
using namespace mozilla;
using NameBag = GCHashSet<JSString*>;
using Names = GCVector<JSString*, 8>;
// FIXME: Better error handling.
// FIXME: Check that subnodes have the right type.
// FIXME: Check scope information.
@@ -122,16 +123,18 @@ private:
bool parseBlockStatementAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
bool parseExpressionStatementAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
bool parseExpressionAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
bool parseVariableDeclarationAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
// --- Utilities.
bool readString(SimpleTokenReader* reader, std::string&);
+ bool readString(SimpleTokenReader* reader, Maybe<std::string>&);
+ bool readString(SimpleTokenReader* reader, Maybe<std::u16string>&);
bool readString(SimpleTokenReader* reader, MutableHandleString);
bool readString(SimpleTokenReader* reader, MutableHandleAtom);
bool readString(SimpleTokenReader* reader, MutableHandle<PropertyName*>);
bool readBool(SimpleTokenReader* reader, Maybe<bool>&);
bool readNumber(SimpleTokenReader* reader, Maybe<double>&);
const Directives& currentDirectives() const;
const ReadOnlyCompileOptions& options() const;
@@ -140,16 +143,42 @@ private:
/* List of objects allocated during parsing, for GC tracing. */
ObjectBox* traceListHead;
void trace(JSTracer* trc)
{
ObjectBox::TraceList(trc, this->traceListHead);
}
+
+ public:
+ ObjectBox* newObjectBox(JSObject* obj)
+ {
+ MOZ_ASSERT(obj);
+
+ /*
+ * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
+ * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
+ * arenas containing the entries must be alive until we are done with
+ * scanning, parsing and code generation for the whole script or top-level
+ * function.
+ */
+
+ ObjectBox* objbox = alloc.new_<ObjectBox>(obj, traceListHead);
+ if (!objbox) {
+ ReportOutOfMemory(this->cx);
+ return nullptr;
+ }
+
+ traceListHead = objbox;
+
+ return objbox;
+ }
+
+
ParseNodeAllocator allocator;
ParseNode* allocParseNode(size_t size) {
MOZ_ASSERT(size == sizeof(ParseNode));
return static_cast<ParseNode*>(allocator.allocNode());
}
ParseNode* cloneNode(const ParseNode& other) {
@@ -1266,18 +1295,19 @@ ASTReader::parseExpression(SimpleTokenRe
if (!result) {
return false;
}
out = Move(result);
break;
}
case BinKind::directive_literal:
- // FIXME: Implement
- break;
+ // A directive is not truly a literal, so this doesn't make sense
+ // here.
+ return this->raiseError();
case BinKind::null_literal: {
UniquePtr<ParseNode> result(new_<NullLiteral>(TokenPos()));
if (!result) {
return false;
}
out = Move(result);
break;
}
@@ -1302,19 +1332,87 @@ ASTReader::parseExpression(SimpleTokenRe
UniquePtr<ParseNode> result(new_<NullaryNode>(PNK_NUMBER, TokenPos()));
if (!result) {
return false;
}
result->initNumber(*value, DecimalPoint::HasDecimal); // FIXME: Is the DecimalPoint important?
out = Move(result);
break;
}
- case BinKind::regexp_literal:
- // FIXME: Implement
+ case BinKind::regexp_literal: {
+ Maybe<std::u16string> pattern;
+ Maybe<std::string> flags;
+ for (auto field: fields) {
+ switch (field) {
+ case BinField::pattern:
+ if (!this->readString(&sub, pattern)) {
+ return false;
+ }
+ break;
+ case BinField::flags:
+ if (!this->readString(&sub, flags)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
+ }
+ }
+
+ if (!pattern || !flags) {
+ return this->raiseError();
+ }
+
+ // FIXME: RegExpFlag flags = tokenStream.currentToken().regExpFlags();
+
+ RegExpFlag reflags = NoFlags;
+ for (char c: *flags) {
+ if (c == 'g' && !(reflags & GlobalFlag))
+ reflags = RegExpFlag(reflags | GlobalFlag);
+ else if (c == 'i' && !(reflags & IgnoreCaseFlag))
+ reflags = RegExpFlag(reflags | IgnoreCaseFlag);
+ else if (c == 'm' && !(reflags & MultilineFlag))
+ reflags = RegExpFlag(reflags | MultilineFlag);
+ else if (c == 'y' && !(reflags & StickyFlag))
+ reflags = RegExpFlag(reflags | StickyFlag);
+ else if (c == 'u' && !(reflags & UnicodeFlag))
+ reflags = RegExpFlag(reflags | UnicodeFlag);
+ else
+ return this->raiseError();
+ }
+
+
+ Rooted<RegExpObject*> reobj(this->cx);
+ reobj = RegExpObject::create(this->cx,
+ pattern->data(),
+ pattern->length(),
+ reflags,
+ /* options*/ nullptr,
+ /* tokenStream */ nullptr,
+ this->alloc,
+ TenuredObject);
+
+ if (!reobj) {
+ return false;
+ }
+
+
+ ObjectBox* objbox = this->newObjectBox(reobj);
+ if (!objbox) {
+ return false;
+ }
+ UniquePtr<ParseNode> result(new_<RegExpLiteral>(objbox, TokenPos()));
+ if (!result) {
+ // FIXME: I *think* that `objbox` is traced.
+ return false;
+ }
+
+ out = Move(result);
break;
+ }
case BinKind::string_literal: {
RootedAtom value(this->cx);
for (auto field: fields) {
switch (field) {
case BinField::value:
if (!this->readString(&sub, &value)) {
return false;
}