Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions API/hermes/hermes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ class HermesRuntimeImpl final : public HermesRuntime,

compileFlags_.enableGenerator = runtimeConfig.getEnableGenerator();
compileFlags_.enableES6BlockScoping = runtimeConfig.getES6BlockScoping();
compileFlags_.enableAsyncGenerators = runtimeConfig.getEnableAsyncGenerators();
compileFlags_.emitAsyncBreakCheck =
runtimeConfig.getAsyncBreakCheckInEval();
runtime_.addCustomRootsFunction(
Expand Down
14 changes: 14 additions & 0 deletions include/hermes/AST/AsyncGenerator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef HERMES_AST_ASYNCGENERATORS_H
#define HERMES_AST_ASYNCGENERATORS_H

#include "hermes/AST/ESTree.h"

namespace hermes {

/// Recursively transforms the ESTree Node tree such that async generators
/// are converted into generators
ESTree::Node* transformAsyncGenerators(Context &context, ESTree::Node *node);

} // namespace hermes

#endif
11 changes: 11 additions & 0 deletions include/hermes/AST/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ class Context {
/// Whether to parse TypeScript syntax.
bool parseTS_{false};

/// Whether to enable support for async generators
bool enableAsyncGenerators_{false};

/// Whether to enable support for ES6 block scoping.
/// TODO: This is intended to provide a temporary way to configure block
/// scoping until we have debugger support for it.
Expand Down Expand Up @@ -433,6 +436,14 @@ class Context {
return parseTS_;
}

void setEnableAsyncGenerators(bool enableAsyncGenerators) {
enableAsyncGenerators_ = enableAsyncGenerators;
}

bool getEnableAsyncGenerators() const {
return enableAsyncGenerators_;
}

void setEnableES6BlockScoping(bool enableES6BlockScoping) {
enableES6BlockScoping_ = enableES6BlockScoping;
}
Expand Down
25 changes: 25 additions & 0 deletions include/hermes/AST/TransformAST.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

#include "hermes/AST/Context.h"
#include "hermes/AST/ESTree.h"

namespace hermes {

/// General purpose AST transformation which will be applied before running
/// semantic resolution in the compiler pipeline.
/// Allows adding functionality/transforms in a general way directly to the AST
/// in a way that works for lazy compilation, debugger eval, etc.
///
/// \return the transformed node, which should be used for the remainder of
/// compilation. On failure, report an error and return nullptr.
/// The returned Node must be the same kind as the original \p root.
ESTree::Node *transformASTForCompilation(Context &context, ESTree::Node *root);

} // namespace hermes
146 changes: 146 additions & 0 deletions include/hermes/AST/TransformationsBase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#include "hermes/AST/RecursiveVisitor.h"
#include "hermes/Parser/JSLexer.h"
#include "llvh/ADT/StringRef.h"

namespace {
using namespace hermes;

/// Mutable vector that helps dealing with arrays of nodes safely.
/// Once done with the vector, it can create an ESTree::NodeList
/// representation which is used by the ESTree API in several places.
class NodeVector {
public:
using Storage = llvh::SmallVector<ESTree::Node *, 8>;

NodeVector() = default;
NodeVector(std::initializer_list<ESTree::Node *> nodes) {
for (auto &node : nodes) {
_storage.push_back(node);
}
}

NodeVector(ESTree::NodeList &list) {
for (auto &node : list) {
_storage.push_back(&node);
}
}

~NodeVector() = default;

size_t size() const {
return _storage.size();
}

Storage::const_iterator begin() const {
return _storage.begin();
}

Storage::const_iterator end() const {
return _storage.end();
}

void append(ESTree::Node *node) {
_storage.emplace_back(node);
}

void prepend(ESTree::Node *node) {
_storage.insert(_storage.begin(), node);
}

ESTree::NodeList toNodeList() const {
ESTree::NodeList nodeList;
for (auto &node : _storage) {
nodeList.push_back(*node);
}
return nodeList;
}

private:
Storage _storage;
};

class TransformationsBase
: public ESTree::RecursionDepthTracker<TransformationsBase> {
public:
static constexpr bool kEnableNodeListMutation = true;

TransformationsBase(Context &context)
: context_(context),
identVar_(context.getIdentifier("var").getUnderlyingPointer()) {}

void recursionDepthExceeded(ESTree::Node *n) {
context_.getSourceErrorManager().error(
n->getEndLoc(), "Too many nested expressions/statements/declarations");
}

protected:
Context &context_;
UniqueString *const identVar_;

void doCopyLocation(ESTree::Node *src, ESTree::Node *dest) {
if (src != nullptr) {
dest->setStartLoc(src->getStartLoc());
dest->setEndLoc(src->getEndLoc());
dest->setDebugLoc(src->getDebugLoc());
}
}

template <typename T>
T *copyLocation(ESTree::Node *src, T *dest) {
doCopyLocation(src, dest);
return dest;
}

template <typename T, typename... Args>
T *createTransformedNode(ESTree::Node *src, Args &&...args) {
auto *node = new (context_) T(std::forward<Args>(args)...);
return copyLocation(src, node);
}

ESTree::IdentifierNode *makeIdentifierNode(
ESTree::Node *srcNode,
UniqueString *name) {
return createTransformedNode<ESTree::IdentifierNode>(
srcNode, name, nullptr, false);
}

ESTree::IdentifierNode *makeIdentifierNode(
ESTree::Node *srcNode,
llvh::StringRef name) {
return makeIdentifierNode(
srcNode, context_.getIdentifier(name).getUnderlyingPointer());
}

ESTree::Node *makeSingleVarDecl(
ESTree::Node *srcNode,
ESTree::Node *identifier,
ESTree::Node *value) {
auto *variableDeclarator =
createTransformedNode<ESTree::VariableDeclaratorNode>(
srcNode, value, identifier);
ESTree::NodeList variableList;
variableList.push_back(*variableDeclarator);
return createTransformedNode<ESTree::VariableDeclarationNode>(
srcNode, identVar_, std::move(variableList));
}

ESTree::Node *makeHermesInternalCall(
ESTree::Node *srcNode,
llvh::StringRef methodName,
const NodeVector &parameters) {
auto hermesInternalIdentifier = getHermesInternalIdentifier(srcNode);
auto methodIdentifier = makeIdentifierNode(srcNode, methodName);

auto *getPropertyNode = createTransformedNode<ESTree::MemberExpressionNode>(
srcNode, hermesInternalIdentifier, methodIdentifier, false);
return createTransformedNode<ESTree::CallExpressionNode>(
srcNode, getPropertyNode, nullptr, parameters.toNodeList());
}

virtual ESTree::Node *getHermesInternalIdentifier(ESTree::Node *srcNode) {
return nullptr;
};

virtual ~TransformationsBase() = default;
};
} // namespace
2 changes: 2 additions & 0 deletions include/hermes/BCGen/HBC/HBC.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ struct CompileFlags {
bool enableGenerator{true};
/// Enable ES6 block scoping support
bool enableES6BlockScoping{false};
/// Enable async generators support
bool enableAsyncGenerators{false};
/// Define the output format of the generated bytecode. For instance, whether
/// the bytecode is intended for execution or serialisation.
OutputFormatKind format{Execute};
Expand Down
1 change: 1 addition & 0 deletions include/hermes/CompilerDriver/CompilerDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,6 @@ extern llvh::cl::opt<bool> EmitAsyncBreakCheck;
extern llvh::cl::list<std::string> InputFilenames;
extern llvh::cl::opt<bool> OptimizedEval;
extern llvh::cl::opt<bool> PrintCompilerTiming;
extern llvh::cl::opt<bool> EnableAsyncGenerators;
} // namespace cl
#endif
1 change: 1 addition & 0 deletions include/hermes/FrontEndDefs/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ PRIVATE_BUILTIN(functionPrototypeCall)

JS_BUILTIN(spawnAsync)
MARK_FIRST_JS_BUILTIN(spawnAsync)
JS_BUILTIN(makeAsyncIterator)

#undef NORMAL_OBJECT
#undef NORMAL_METHOD
Expand Down
1 change: 1 addition & 0 deletions include/hermes/VM/NativeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ NATIVE_FUNCTION(hermesInternalIsProxy)
NATIVE_FUNCTION(hermesInternalHasPromise)
NATIVE_FUNCTION(hermesInternalTTIReached)
NATIVE_FUNCTION(hermesInternalTTRCReached)
NATIVE_FUNCTION(hermesInternalHasAsyncGenerators)

NATIVE_FUNCTION(hermesInternalSetPromiseRejectionTrackingHook)
NATIVE_FUNCTION(hermesInternalEnablePromiseRejectionTracker)
Expand Down
2 changes: 2 additions & 0 deletions include/hermes/VM/PredefinedStrings.def
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ STR(HermesInternal, "HermesInternal")
STR(detachArrayBuffer, "detachArrayBuffer")
STR(createHeapSnapshot, "createHeapSnapshot")
STR(hasPromise, "hasPromise")
STR(hasAsyncGenerators, "hasAsyncGenerators")
STR(useEngineQueue, "useEngineQueue")
STR(enqueueJob, "enqueueJob")
STR(drainJobs, "drainJobs")
Expand Down Expand Up @@ -463,6 +464,7 @@ STR(fileName, "fileName")
STR(setPromiseRejectionTrackingHook, "setPromiseRejectionTrackingHook")
STR(enablePromiseRejectionTracker, "enablePromiseRejectionTracker")
STR(spawnAsync, "spawnAsync") /* NOLINT */
STR(makeAsyncIterator, "makeAsyncIterator") /* NOLINT */

STR(SHBuiltin, "$SHBuiltin")

Expand Down
7 changes: 7 additions & 0 deletions include/hermes/VM/Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,10 @@ class Runtime : public RuntimeBase, public HandleRootOwner {
return hasES6Proxy_;
}

bool hasAsyncGenerators() const {
return hasAsyncGenerators_;
}

bool hasES6BlockScoping() const {
return hasES6BlockScoping_;
}
Expand Down Expand Up @@ -1143,6 +1147,9 @@ class Runtime : public RuntimeBase, public HandleRootOwner {
/// Set to true if we should enable ES6 Proxy.
const bool hasES6Proxy_;

/// Set to true if we should enable async generators.
const bool hasAsyncGenerators_;

/// Set to true if we should enable ES6 block scoping.
const bool hasES6BlockScoping_;

Expand Down
Loading