Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

module block proposal implementation #476

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
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
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ public class Parser extends AbstractParser {
private static final String MESSAGE_EXPECTED_OPERAND = "expected.operand";
private static final String MESSAGE_PROPERTY_REDEFINITON = "property.redefinition";

private static final String MODULE = "module";

/** Current env. */
private final ScriptEnvironment env;

Expand Down Expand Up @@ -276,6 +278,8 @@ public class Parser extends AbstractParser {
public static final boolean PROFILE_PARSING = Options.getBooleanProperty("parser.profiling", false);
public static final boolean PROFILE_PARSING_PRINT = Options.getBooleanProperty("parser.profiling.print", true);

private static final List<Statement> EMPTY_LIST = new ArrayList<>();

/**
* Constructor
*
Expand Down Expand Up @@ -450,7 +454,7 @@ public FunctionNode parseModule(final String moduleName, final int startPos, fin

scanFirstToken();

return module(moduleName);
return module(moduleName, false);
} catch (final Exception e) {
handleParseException(e);

Expand Down Expand Up @@ -3602,6 +3606,7 @@ private void debuggerStatement() {
* RegularExpressionLiteral
* TemplateLiteral
* CoverParenthesizedExpressionAndArrowParameterList
* ModuleBlockExpression
*
* CoverParenthesizedExpressionAndArrowParameterList :
* ( Expression )
Expand All @@ -3625,10 +3630,23 @@ private Expression primaryExpression(boolean yield, boolean await) {
markThis();
return new IdentNode(primaryToken, finish, name).setIsThis();
case IDENT:
// mimic code from AbstractParser.getIdent()
final long identToken = token;
String identString = (String) getValue(identToken);

if (identString.equals(MODULE) && lookahead().equals(LBRACE)) {
nextOrEOL();
expect(LBRACE);

return module(source.getName() + "#L" + line, true);
}

final IdentNode ident = identifierReference(yield, await);

if (ident == null) {
break;
}

return detectSpecialProperty(ident);
case NON_OCTAL_DECIMAL:
if (isStrictMode) {
Expand Down Expand Up @@ -6298,20 +6316,23 @@ private void addTemplateLiteralString(final ArrayList<Expression> rawStrings, fi
* ModuleItemList
* </pre>
*/
private FunctionNode module(final String moduleName) {
private FunctionNode module(final String moduleName, boolean moduleBlock) {
// Make a pseudo-token for the script holding its start and length.
int functionStart = Math.min(Token.descPosition(Token.withDelimiter(token)), finish);
final long functionToken = Token.toDesc(FUNCTION, functionStart, source.getLength() - functionStart);
final int functionLine = line;

final Scope moduleScope = Scope.createModule();
final IdentNode ident = null;

final IdentNode ident = moduleBlock ? new IdentNode(functionToken, finish, moduleName) : null;

final ParserContextFunctionNode script = createParserContextFunctionNode(
ident,
functionToken,
FunctionNode.IS_MODULE,
moduleBlock ? FunctionNode.IS_MODULE_BLOCK : FunctionNode.IS_MODULE,
functionLine,
Collections.<IdentNode> emptyList(), 0, moduleScope);

script.setInternalName(moduleName);

lc.push(script);
Expand All @@ -6320,7 +6341,7 @@ private FunctionNode module(final String moduleName) {
functionDeclarations = new ArrayList<>();

try {
moduleBody(module);
moduleBody(module, moduleBlock);

// Insert a synthetic yield before the module body but after any function declarations.
long yieldToken = Token.toDesc(YIELD, functionStart, 0);
Expand All @@ -6329,7 +6350,10 @@ private FunctionNode module(final String moduleName) {

addFunctionDeclarations(script);
} finally {
functionDeclarations = null;

// module blocks expect an empty list otherwise evaluating the code fails
functionDeclarations = moduleBlock ? Collections.emptyList() : null;

restoreBlock(body);
lc.pop(script);
}
Expand All @@ -6338,7 +6362,11 @@ private FunctionNode module(final String moduleName) {
final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY | Block.IS_MODULE_BODY, body.getScope(), body.getStatements());
script.setLastToken(token);

expect(EOF);
if (moduleBlock) {
expect(RBRACE);
} else {
expect(EOF);
}

script.setModule(module.createModule());
return createFunctionNode(script, functionToken, ident, functionLine, programBody);
Expand All @@ -6361,11 +6389,15 @@ private FunctionNode module(final String moduleName) {
* StatementListItem
* </pre>
*/
private void moduleBody(ParserContextModuleNode module) {
loop: while (type != EOF) {
private void moduleBody(ParserContextModuleNode module, boolean moduleBlock) {
TokenType endModuleToken = moduleBlock ? RBRACE : EOF;

loop: while (type != endModuleToken) {
switch (type) {
case EOF:
break loop;
case RBRACE:
break loop;
case EXPORT:
exportDeclaration(module);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
/** Is this function a class field initializer? */
public static final int IS_CLASS_FIELD_INITIALIZER = 1 << 30;

/** Is this function a module block? */
public static final int IS_MODULE_BLOCK = 1 << 31;

/**
* Constructor
*
Expand Down Expand Up @@ -787,4 +790,8 @@ public boolean needsSuper() {
public boolean isClassFieldInitializer() {
return getFlag(IS_CLASS_FIELD_INITIALIZER);
}

public boolean isModuleBlock() {
return getFlag(IS_MODULE_BLOCK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
import com.oracle.truffle.js.nodes.function.EvalNode;
import com.oracle.truffle.js.nodes.function.FunctionRootNode;
import com.oracle.truffle.js.nodes.function.JSBuiltin;
import com.oracle.truffle.js.nodes.module.ModuleBlockNode;
import com.oracle.truffle.js.nodes.promise.NewPromiseCapabilityNode;
import com.oracle.truffle.js.nodes.promise.PerformPromiseThenNode;
import com.oracle.truffle.js.parser.date.DateParser;
Expand Down Expand Up @@ -133,6 +134,13 @@ public ScriptNode parseEval(JSContext context, Node lastNode, Source source) {
return parseEval(context, lastNode, source, false, null);
}

@Override
public JavaScriptNode parseModuleBlock(JSContext context, Source source) {
NodeFactory nodeFactory = NodeFactory.getInstance(context);

return JavaScriptTranslator.translateModuleBlock(nodeFactory, context, source);
}

/**
* Evaluate Function(parameterList, body).
*/
Expand Down Expand Up @@ -370,6 +378,19 @@ private static JSModuleRecord hostResolveImportedModule(JSModuleRecord referenci
return referencingModule.getModuleLoader().resolveImportedModule(referencingModule, specifier);
}

@Override
public JSModuleRecord hostResolveImportedModuleBlock(JSContext context,
ScriptOrModule referencingScriptOrModule, JSModuleRecord moduleBlock, DynamicObject specifier) {
JSModuleLoader moduleLoader = ((JSModuleRecord) referencingScriptOrModule).getModuleLoader();
return moduleLoader.resolveImportedModuleBlock(moduleBlock, specifier);
}

@Override
public JSModuleRecord hostResolveImportedModule(JSContext context, ScriptOrModule referencingScriptOrModule, DynamicObject moduleBlock, Source source) {
JSModuleLoader moduleLoader = ((JSModuleRecord) referencingScriptOrModule).getModuleLoader();
return moduleLoader.resolveImportedModuleBlock(source, moduleBlock);
}

Collection<String> getExportedNames(JSModuleRecord moduleRecord) {
return getExportedNames(moduleRecord, new HashSet<>());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ public JavaScriptNode enterFunctionNode(FunctionNode functionNode) {
List<JavaScriptNode> declarations;
if (functionMode) {
declarations = functionEnvInit(functionNode);
} else if (functionNode.isModule()) {
} else if (functionNode.isModule() || functionNode.isModuleBlock()) {
assert currentFunction.isGlobal();
declarations = Collections.emptyList();
} else {
Expand All @@ -399,6 +399,10 @@ public JavaScriptNode enterFunctionNode(FunctionNode functionNode) {

functionRoot = createFunctionRoot(functionNode, functionData, currentFunction, body);

if (functionNode.isModuleBlock()) {
return factory.createModuleBlock(context, body, functionRoot.getName());
}

if (isEval) {
// force eager call target init for Function() code to avoid deopt at call site
functionData.getCallTarget();
Expand Down Expand Up @@ -994,7 +998,7 @@ private void findSymbol(String varName) {
if (!local) {
markUsesAncestorScopeUntil(lastFunction, true);
}
} else if (function.isModule() && isImport(varName)) {
} else if ((function.isModule() || function.isModuleBlock()) && isImport(varName)) {
// needed for GetActiveScriptOrModule()
if (!local) {
markUsesAncestorScopeUntil(lastFunction, true);
Expand Down Expand Up @@ -1267,15 +1271,15 @@ private List<JavaScriptNode> createTemporalDeadZoneInit(Block block) {
}

private void createResolveImports(FunctionNode functionNode, List<JavaScriptNode> declarations) {
assert functionNode.isModule();
assert functionNode.isModule() || functionNode.isModuleBlock();

// Assert: all named exports from module are resolvable.
for (ImportEntry importEntry : functionNode.getModule().getImportEntries()) {
String moduleRequest = importEntry.getModuleRequest();
String localName = importEntry.getLocalName();
JSWriteFrameSlotNode writeLocalNode = (JSWriteFrameSlotNode) environment.findLocalVar(localName).createWriteNode(null);
JavaScriptNode thisModule = getActiveModule();
if (importEntry.getImportName().equals(Module.STAR_NAME)) {
if (importEntry.getImportName().equals(Module.STAR_NAME) || functionNode.isModuleBlock()) {
assert functionNode.getBody().getScope().hasSymbol(localName) && functionNode.getBody().getScope().getExistingSymbol(localName).hasBeenDeclared();
declarations.add(factory.createResolveStarImport(context, thisModule, moduleRequest, writeLocalNode));
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -45,6 +45,7 @@
import com.oracle.js.parser.ir.Scope;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.js.lang.JavaScriptLanguage;
import com.oracle.truffle.js.nodes.JavaScriptNode;
import com.oracle.truffle.js.nodes.NodeFactory;
import com.oracle.truffle.js.nodes.ScriptNode;
import com.oracle.truffle.js.nodes.function.FunctionRootNode;
Expand Down Expand Up @@ -117,6 +118,15 @@ public static ScriptNode translateFunction(NodeFactory factory, JSContext contex
return new JavaScriptTranslator(factory, context, source, prologLength, env, isParentStrict).translateScript(rootNode);
}

public static JavaScriptNode translateModuleBlock(NodeFactory factory, JSContext context, Source source) {
FunctionNode parsed = GraalJSParserHelper.parseModule(context, source, context.getParserOptions().putStrict(true));
JavaScriptTranslator translator = new JavaScriptTranslator(factory, context, source, 0, null, true);

FunctionRootNode functionRoot = translator.translateModule(parsed); // <- works

return translator.enterFunctionNode(parsed);
}

public static JSModuleRecord translateModule(NodeFactory factory, JSContext context, Source source, JSModuleLoader moduleLoader) {
FunctionNode parsed = GraalJSParserHelper.parseModule(context, source, context.getParserOptions().putStrict(true));
JavaScriptTranslator translator = new JavaScriptTranslator(factory, context, source, 0, null, true);
Expand Down
Loading