#ifndef frontend_BinASTParserPerTokenizer_h
#define frontend_BinASTParserPerTokenizer_h
#include "mozilla/Maybe.h"
#include "frontend/BCEParserHandle.h"
#include "frontend/BinASTEnum.h"
#include "frontend/BinASTParserBase.h"
#include "frontend/BinASTToken.h"
#include "frontend/BinASTTokenReaderMultipart.h"
#include "frontend/FullParseHandler.h"
#include "frontend/ParseContext.h"
#include "frontend/ParseNode.h"
#include "frontend/SharedContext.h"
#include "js/CompileOptions.h"
#include "js/GCHashTable.h"
#include "js/GCVector.h"
#include "js/Result.h"
#include "vm/ErrorReporting.h"
namespace js {
namespace frontend {
template <typename Tok>
class BinASTParser;
template <typename Tok>
class BinASTParserPerTokenizer : public BinASTParserBase,
public ErrorReporter,
public BCEParserHandle {
public:
using Tokenizer = Tok;
using AutoList = typename Tokenizer::AutoList;
using AutoTaggedTuple = typename Tokenizer::AutoTaggedTuple;
using BinASTFields = typename Tokenizer::BinASTFields;
using Chars = typename Tokenizer::Chars;
public:
using AssertedDeclaredKind = binast::AssertedDeclaredKind;
using VariableDeclarationKind = binast::VariableDeclarationKind;
public:
BinASTParserPerTokenizer(JSContext* cx, LifoAlloc& alloc,
UsedNameTracker& usedNames,
const JS::ReadOnlyCompileOptions& options,
HandleScriptSourceObject sourceObject,
Handle<LazyScript*> lazyScript = nullptr);
~BinASTParserPerTokenizer() {}
JS::Result<ParseNode*> parse(GlobalSharedContext* globalsc,
const uint8_t* start, const size_t length,
BinASTSourceMetadata** metadataPtr = nullptr);
JS::Result<ParseNode*> parse(GlobalSharedContext* globalsc,
const Vector<uint8_t>& data,
BinASTSourceMetadata** metadataPtr = nullptr);
JS::Result<FunctionNode*> parseLazyFunction(ScriptSource* scriptSource,
const size_t firstOffset);
protected:
MOZ_MUST_USE JS::Result<ParseNode*> parseAux(
GlobalSharedContext* globalsc, const uint8_t* start, const size_t length,
BinASTSourceMetadata** metadataPtr = nullptr);
MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidClosedVar(
JSAtom* name);
MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&>
raiseMissingVariableInAssertedScope(JSAtom* name);
MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&>
raiseMissingDirectEvalInAssertedScope();
MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidKind(
const char* superKind, const BinASTKind kind);
MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseInvalidVariant(
const char* kind, const BinASTVariant value);
MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseMissingField(
const char* kind, const BinASTField field);
MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseEmpty(
const char* description);
MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseOOM();
MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseError(
const char* description);
MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&> raiseError(
BinASTKind kind, const char* description);
void poison();
enum class AssertedScopeKind {
Block,
Catch,
Global,
Parameter,
Var,
};
JS::Result<FunctionNode*> makeEmptyFunctionNode(const size_t start,
const BinASTKind kind,
FunctionBox* funbox);
JS::Result<FunctionNode*> buildFunction(const size_t start,
const BinASTKind kind,
ParseNode* name, ListNode* params,
ParseNode* body);
JS::Result<FunctionBox*> buildFunctionBox(GeneratorKind generatorKind,
FunctionAsyncKind functionAsyncKind,
FunctionSyntaxKind syntax,
ParseNode* name);
MOZ_MUST_USE JS::Result<Ok> addScopeName(
AssertedScopeKind scopeKind, HandleAtom name, ParseContext::Scope* scope,
DeclarationKind declKind, bool isCaptured, bool allowDuplicateName);
void captureFunctionName();
MOZ_MUST_USE JS::Result<Ok> getDeclaredScope(AssertedScopeKind scopeKind,
AssertedDeclaredKind kind,
ParseContext::Scope*& scope,
DeclarationKind& declKind);
MOZ_MUST_USE JS::Result<Ok> getBoundScope(AssertedScopeKind scopeKind,
ParseContext::Scope*& scope,
DeclarationKind& declKind);
MOZ_MUST_USE JS::Result<Ok> checkBinding(JSAtom* name);
MOZ_MUST_USE JS::Result<Ok> checkPositionalParameterIndices(
Handle<GCVector<JSAtom*>> positionalParams, ListNode* params);
MOZ_MUST_USE JS::Result<Ok> checkFunctionLength(uint32_t expectedLength);
MOZ_MUST_USE JS::Result<Ok> checkClosedVars(ParseContext::Scope& scope);
MOZ_MUST_USE JS::Result<Ok> checkFunctionClosedVars();
MOZ_MUST_USE JS::Result<Ok> prependDirectivesToBody(ListNode* body,
ListNode* directives);
MOZ_MUST_USE JS::Result<Ok> prependDirectivesImpl(ListNode* body,
ParseNode* directive);
void forceStrictIfNecessary(SharedContext* sc, ListNode* directives);
protected:
const JS::ReadOnlyCompileOptions& options_;
const JS::ReadOnlyCompileOptions& options() const override {
return this->options_;
}
JSContext* getContext() const override { return cx_; };
MOZ_MUST_USE bool strictMode() const override { return pc_->sc()->strict(); }
MOZ_MUST_USE bool computeErrorMetadata(ErrorMetadata* err,
const ErrorOffset& offset) override;
private:
void doTrace(JSTracer* trc) final;
public:
virtual ObjectBox* newObjectBox(JSObject* obj) override {
MOZ_ASSERT(obj);
ObjectBox* objbox = alloc_.new_<ObjectBox>(obj, traceListHead_);
if (!objbox) {
ReportOutOfMemory(cx_);
return nullptr;
}
traceListHead_ = objbox;
return objbox;
}
virtual ErrorReporter& errorReporter() override { return *this; }
virtual const ErrorReporter& errorReporter() const override { return *this; }
virtual FullParseHandler& astGenerator() override { return handler_; }
public:
virtual void lineAndColumnAt(size_t offset, uint32_t* line,
uint32_t* column) const override {
*line = lineAt(offset);
*column = columnAt(offset);
}
virtual uint32_t lineAt(size_t offset) const override { return 0; }
virtual uint32_t columnAt(size_t offset) const override { return offset; }
virtual bool isOnThisLine(size_t offset, uint32_t lineNum,
bool* isOnSameLine) const override {
if (lineNum != 0) {
return false;
}
*isOnSameLine = true;
return true;
}
virtual void currentLineAndColumn(uint32_t* line,
uint32_t* column) const override {
*line = 0;
*column = offset();
}
size_t offset() const {
if (tokenizer_.isSome()) {
return tokenizer_->offset();
}
return 0;
}
virtual bool hasTokenizationStarted() const override {
return tokenizer_.isSome();
}
virtual const char* getFilename() const override {
return this->options_.filename();
}
protected:
Rooted<LazyScript*> lazyScript_;
FullParseHandler handler_;
mozilla::Maybe<Tokenizer> tokenizer_;
VariableDeclarationKind variableDeclarationKind_;
friend class BinASTParseContext;
friend class AutoVariableDeclarationKind;
class MOZ_RAII AutoVariableDeclarationKind {
public:
explicit AutoVariableDeclarationKind(
BinASTParserPerTokenizer<Tok>* parser MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: parser_(parser), kind(parser->variableDeclarationKind_) {
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
~AutoVariableDeclarationKind() { parser_->variableDeclarationKind_ = kind; }
private:
BinASTParserPerTokenizer<Tok>* parser_;
BinASTParserPerTokenizer<Tok>::VariableDeclarationKind kind;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
private:
using FinalParser = BinASTParser<Tok>;
inline FinalParser* asFinalParser();
inline const FinalParser* asFinalParser() const;
};
class BinASTParseContext : public ParseContext {
public:
template <typename Tok>
BinASTParseContext(JSContext* cx, BinASTParserPerTokenizer<Tok>* parser,
SharedContext* sc, Directives* newDirectives)
: ParseContext(cx, parser->pc_, sc, *parser, parser->usedNames_,
newDirectives, true) {}
};
void TraceBinASTParser(JSTracer* trc, JS::AutoGCRooter* parser);
extern template class BinASTParserPerTokenizer<BinASTTokenReaderMultipart>;
} }
#endif