/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.compiler;
import static com.github.anba.es6draft.semantics.StaticSemantics.BoundNames;
import static com.github.anba.es6draft.semantics.StaticSemantics.LexicallyScopedDeclarations;
import static com.github.anba.es6draft.semantics.StaticSemantics.VarScopedDeclarations;
import java.util.HashSet;
import java.util.List;
import com.github.anba.es6draft.ast.Declaration;
import com.github.anba.es6draft.ast.HoistableDeclaration;
import com.github.anba.es6draft.ast.Module;
import com.github.anba.es6draft.ast.StatementListItem;
import com.github.anba.es6draft.ast.VariableStatement;
import com.github.anba.es6draft.ast.scope.Name;
import com.github.anba.es6draft.compiler.CodeGenerator.ModuleName;
import com.github.anba.es6draft.compiler.assembler.Code.MethodCode;
import com.github.anba.es6draft.compiler.assembler.MethodName;
import com.github.anba.es6draft.compiler.assembler.Type;
import com.github.anba.es6draft.compiler.assembler.Variable;
import com.github.anba.es6draft.runtime.ExecutionContext;
import com.github.anba.es6draft.runtime.LexicalEnvironment;
import com.github.anba.es6draft.runtime.ModuleEnvironmentRecord;
import com.github.anba.es6draft.runtime.modules.ExportEntry;
import com.github.anba.es6draft.runtime.modules.ImportEntry;
import com.github.anba.es6draft.runtime.modules.ModuleExport;
import com.github.anba.es6draft.runtime.modules.SourceTextModuleRecord;
import com.github.anba.es6draft.runtime.types.ScriptObject;
import com.github.anba.es6draft.runtime.types.Undefined;
import com.github.anba.es6draft.runtime.types.builtins.FunctionObject;
/**
* <h1>15 ECMAScript Language: Scripts and Modules</h1><br>
* <h2>15.2 Modules</h2><br>
* <h3>15.2.1 Module Semantics</h3><br>
* <h4>15.2.1.15 Source Text Module Records</h4>
* <ul>
* <li>15.2.1.15.4 ModuleDeclarationInstantiation( ) Concrete Method
* </ul>
*/
final class ModuleDeclarationInstantiationGenerator extends DeclarationBindingInstantiationGenerator {
private static final class Methods {
// class: ScriptRuntime
static final MethodName ScriptRuntime_createImportBinding = MethodName.findStatic(
Types.ScriptRuntime, "createImportBinding", Type.methodType(Type.VOID_TYPE,
Types.ExecutionContext, Types.ModuleEnvironmentRecord, Types.String,
Types.ModuleExport));
static final MethodName ScriptRuntime_getModuleNamespace = MethodName.findStatic(
Types.ScriptRuntime, "getModuleNamespace", Type.methodType(Types.ScriptObject,
Types.ExecutionContext, Types.SourceTextModuleRecord, Types.String));
static final MethodName ScriptRuntime_resolveExportOrThrow = MethodName.findStatic(
Types.ScriptRuntime, "resolveExportOrThrow",
Type.methodType(Type.VOID_TYPE, Types.SourceTextModuleRecord, Types.String));
static final MethodName ScriptRuntime_resolveImportOrThrow = MethodName.findStatic(
Types.ScriptRuntime, "resolveImportOrThrow", Type.methodType(Types.ModuleExport,
Types.SourceTextModuleRecord, Types.String, Types.String));
}
private static final int EXECUTION_CONTEXT = 0;
private static final int MODULE = 1;
private static final int MODULE_ENV = 2;
private static final class ModuleDeclInitMethodGenerator extends InstructionVisitor {
ModuleDeclInitMethodGenerator(MethodCode method) {
super(method);
}
@Override
public void begin() {
super.begin();
setParameterName("cx", EXECUTION_CONTEXT, Types.ExecutionContext);
setParameterName("module", MODULE, Types.SourceTextModuleRecord);
setParameterName("moduleEnv", MODULE_ENV, Types.LexicalEnvironment);
}
}
ModuleDeclarationInstantiationGenerator(CodeGenerator codegen) {
super(codegen);
}
void generate(Module module, SourceTextModuleRecord moduleRecord) {
MethodCode method = codegen.newMethod(module, ModuleName.Init);
InstructionVisitor mv = new ModuleDeclInitMethodGenerator(method);
mv.lineInfo(module);
mv.begin();
generate(module, moduleRecord, mv);
mv.end();
}
private void generate(Module module, SourceTextModuleRecord moduleRecord, InstructionVisitor mv) {
Variable<ExecutionContext> context = mv.getParameter(EXECUTION_CONTEXT,
ExecutionContext.class);
Variable<SourceTextModuleRecord> moduleRec = mv.getParameter(MODULE,
SourceTextModuleRecord.class);
Variable<LexicalEnvironment<ModuleEnvironmentRecord>> env = mv.getParameter(MODULE_ENV,
LexicalEnvironment.class).uncheckedCast();
Variable<ModuleEnvironmentRecord> envRec = mv.newVariable("envRec",
ModuleEnvironmentRecord.class);
getEnvironmentRecord(env, envRec, mv);
Variable<ModuleExport> resolved = mv.newVariable("resolved", ModuleExport.class);
Variable<ScriptObject> namespace = null;
Variable<FunctionObject> fo = null;
Variable<Undefined> undef = mv.newVariable("undef", Undefined.class);
mv.loadUndefined();
mv.store(undef);
/* steps 1-8 (not applicable) */
/* step 9 */
for (ExportEntry exportEntry : moduleRecord.getIndirectExportEntries()) {
mv.lineInfo(exportEntry.getLine());
mv.load(moduleRec);
mv.aconst(exportEntry.getExportName());
mv.invoke(Methods.ScriptRuntime_resolveExportOrThrow);
}
/* steps 10-11 (not applicable) */
/* step 12 */
for (ImportEntry importEntry : moduleRecord.getImportEntries()) {
mv.lineInfo(importEntry.getLine());
if (importEntry.isStarImport()) {
Name localName = new Name(importEntry.getLocalName());
BindingOp<ModuleEnvironmentRecord> op = BindingOp.of(envRec, localName);
op.createImmutableBinding(envRec, localName, true, mv);
mv.load(context);
mv.load(moduleRec);
mv.aconst(importEntry.getModuleRequest());
mv.invoke(Methods.ScriptRuntime_getModuleNamespace);
if (namespace == null) {
namespace = mv.newVariable("namespace", ScriptObject.class);
}
mv.store(namespace);
op.initializeBinding(envRec, localName, namespace, mv);
} else {
mv.load(moduleRec);
mv.aconst(importEntry.getModuleRequest());
mv.aconst(importEntry.getImportName());
mv.invoke(Methods.ScriptRuntime_resolveImportOrThrow);
mv.store(resolved);
createImportBinding(context, envRec, importEntry.getLocalName(), resolved, mv);
}
}
/* step 13 */
List<StatementListItem> varDeclarations = VarScopedDeclarations(module);
HashSet<Name> declaredVarNames = new HashSet<>();
/* step 14 */
for (StatementListItem d : varDeclarations) {
assert d instanceof VariableStatement;
for (Name dn : BoundNames((VariableStatement) d)) {
if (declaredVarNames.add(dn)) {
BindingOp<ModuleEnvironmentRecord> op = BindingOp.of(envRec, dn);
op.createMutableBinding(envRec, dn, false, mv);
op.initializeBinding(envRec, dn, undef, mv);
}
}
}
/* step 15 */
List<Declaration> lexDeclarations = LexicallyScopedDeclarations(module);
/* step 16 */
for (Declaration d : lexDeclarations) {
for (Name dn : BoundNames(d)) {
BindingOp<ModuleEnvironmentRecord> op = BindingOp.of(envRec, dn);
if (d.isConstDeclaration()) {
op.createImmutableBinding(envRec, dn, true, mv);
} else {
op.createMutableBinding(envRec, dn, false, mv);
}
if (d instanceof HoistableDeclaration) {
InstantiateFunctionObject(context, env, d, mv);
if (fo == null) {
fo = mv.newVariable("fo", FunctionObject.class);
}
mv.store(fo);
op.initializeBinding(envRec, dn, fo, mv);
}
}
}
/* step 17 */
mv._return();
}
private void createImportBinding(Variable<ExecutionContext> context,
Variable<ModuleEnvironmentRecord> envRec, String name, Variable<ModuleExport> resolved,
InstructionVisitor mv) {
mv.load(context);
mv.load(envRec);
mv.aconst(name);
mv.load(resolved);
mv.invoke(Methods.ScriptRuntime_createImportBinding);
}
}