/**
* 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.IsAnonymousFunctionDefinition;
import static com.github.anba.es6draft.semantics.StaticSemantics.PropName;
import java.util.ArrayList;
import com.github.anba.es6draft.ast.ComputedPropertyName;
import com.github.anba.es6draft.ast.Expression;
import com.github.anba.es6draft.ast.IdentifierReference;
import com.github.anba.es6draft.ast.MethodDefinition;
import com.github.anba.es6draft.ast.Node;
import com.github.anba.es6draft.ast.PropertyName;
import com.github.anba.es6draft.ast.PropertyNameDefinition;
import com.github.anba.es6draft.ast.PropertyValueDefinition;
import com.github.anba.es6draft.ast.SpreadProperty;
import com.github.anba.es6draft.ast.synthetic.PropertyDefinitionsMethod;
import com.github.anba.es6draft.compiler.assembler.MethodName;
import com.github.anba.es6draft.compiler.assembler.Type;
import com.github.anba.es6draft.compiler.assembler.Value;
import com.github.anba.es6draft.compiler.assembler.Variable;
import com.github.anba.es6draft.runtime.internal.CompatibilityOption;
import com.github.anba.es6draft.runtime.internal.IndexedMap;
import com.github.anba.es6draft.runtime.types.builtins.OrdinaryObject;
/**
* 12.2.5.8 Runtime Semantics: PropertyDefinitionEvaluation<br>
* 14.3.9 Runtime Semantics: PropertyDefinitionEvaluation<br>
* 14.4.13 Runtime Semantics: PropertyDefinitionEvaluation
*/
final class PropertyGenerator extends DefaultCodeGenerator<DefaultCodeGenerator.ValType> {
private static final class Methods {
// class: ScriptRuntime
static final MethodName ScriptRuntime_EvaluatePropertyDefinition = MethodName.findStatic(
Types.ScriptRuntime, "EvaluatePropertyDefinition", Type.methodType(Type.VOID_TYPE,
Types.OrdinaryObject, Types.Object, Type.BOOLEAN_TYPE,
Types.RuntimeInfo$Function, Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinition_String = MethodName
.findStatic(Types.ScriptRuntime, "EvaluatePropertyDefinition", Type.methodType(
Type.VOID_TYPE, Types.OrdinaryObject, Types.String, Type.BOOLEAN_TYPE,
Types.RuntimeInfo$Function, Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionAsync = MethodName
.findStatic(Types.ScriptRuntime, "EvaluatePropertyDefinitionAsync", Type
.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.Object,
Type.BOOLEAN_TYPE, Types.RuntimeInfo$Function,
Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionAsync_String = MethodName
.findStatic(Types.ScriptRuntime, "EvaluatePropertyDefinitionAsync", Type
.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.String,
Type.BOOLEAN_TYPE, Types.RuntimeInfo$Function,
Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionAsyncGenerator = MethodName
.findStatic(Types.ScriptRuntime, "EvaluatePropertyDefinitionAsyncGenerator", Type
.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.Object,
Type.BOOLEAN_TYPE, Types.RuntimeInfo$Function,
Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionAsyncGenerator_String = MethodName
.findStatic(Types.ScriptRuntime, "EvaluatePropertyDefinitionAsyncGenerator", Type
.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.String,
Type.BOOLEAN_TYPE, Types.RuntimeInfo$Function,
Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionConstructorGenerator = MethodName
.findStatic(Types.ScriptRuntime, "EvaluatePropertyDefinitionConstructorGenerator", Type
.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.Object,
Type.BOOLEAN_TYPE, Types.RuntimeInfo$Function,
Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionConstructorGenerator_String = MethodName
.findStatic(Types.ScriptRuntime, "EvaluatePropertyDefinitionConstructorGenerator", Type
.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.String,
Type.BOOLEAN_TYPE, Types.RuntimeInfo$Function,
Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionGenerator = MethodName.findStatic(
Types.ScriptRuntime, "EvaluatePropertyDefinitionGenerator",
Type.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.Object, Type.BOOLEAN_TYPE,
Types.RuntimeInfo$Function, Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionGenerator_String = MethodName.findStatic(
Types.ScriptRuntime, "EvaluatePropertyDefinitionGenerator",
Type.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.String, Type.BOOLEAN_TYPE,
Types.RuntimeInfo$Function, Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionGetter = MethodName
.findStatic(Types.ScriptRuntime, "EvaluatePropertyDefinitionGetter", Type
.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.Object,
Type.BOOLEAN_TYPE, Types.RuntimeInfo$Function,
Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionGetter_String = MethodName
.findStatic(Types.ScriptRuntime, "EvaluatePropertyDefinitionGetter", Type
.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.String,
Type.BOOLEAN_TYPE, Types.RuntimeInfo$Function,
Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionSetter = MethodName
.findStatic(Types.ScriptRuntime, "EvaluatePropertyDefinitionSetter", Type
.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.Object,
Type.BOOLEAN_TYPE, Types.RuntimeInfo$Function,
Types.ExecutionContext));
static final MethodName ScriptRuntime_EvaluatePropertyDefinitionSetter_String = MethodName
.findStatic(Types.ScriptRuntime, "EvaluatePropertyDefinitionSetter", Type
.methodType(Type.VOID_TYPE, Types.OrdinaryObject, Types.String,
Type.BOOLEAN_TYPE, Types.RuntimeInfo$Function,
Types.ExecutionContext));
static final MethodName ScriptRuntime_defineProperty = MethodName.findStatic(
Types.ScriptRuntime, "defineProperty", Type.methodType(Type.VOID_TYPE,
Types.OrdinaryObject, Types.Object, Types.Object, Types.ExecutionContext));
static final MethodName ScriptRuntime_defineProperty_String = MethodName.findStatic(
Types.ScriptRuntime, "defineProperty", Type.methodType(Type.VOID_TYPE,
Types.OrdinaryObject, Types.String, Types.Object, Types.ExecutionContext));
static final MethodName ScriptRuntime_defineProperty_long = MethodName
.findStatic(Types.ScriptRuntime, "defineProperty", Type.methodType(Type.VOID_TYPE,
Types.OrdinaryObject, Type.LONG_TYPE, Types.Object, Types.ExecutionContext));
static final MethodName ScriptRuntime_defineProtoProperty = MethodName.findStatic(
Types.ScriptRuntime, "defineProtoProperty", Type.methodType(Type.VOID_TYPE,
Types.OrdinaryObject, Types.Object, Types.ExecutionContext));
static final MethodName ScriptRuntime_defineSpreadProperty = MethodName.findStatic(
Types.ScriptRuntime, "defineSpreadProperty", Type.methodType(Type.VOID_TYPE,
Types.OrdinaryObject, Types.Object, Types.ExecutionContext));
}
private final Variable<ArrayList<Object>> decorators;
public PropertyGenerator(CodeGenerator codegen) {
super(codegen);
this.decorators = null;
}
public PropertyGenerator(CodeGenerator codegen, Variable<ArrayList<Object>> decorators) {
super(codegen);
this.decorators = decorators;
}
private Value<ArrayList<Object>> decoratorsOrNull(CodeVisitor mv) {
return this.decorators != null ? this.decorators : mv.anullValue();
}
@Override
protected ValType visit(Node node, CodeVisitor mv) {
throw new IllegalStateException(String.format("node-class: %s", node.getClass()));
}
/**
* 12.2.5.7 Runtime Semantics: Evaluation
* <p>
* ComputedPropertyName : [ AssignmentExpression ]
*/
@Override
public ValType visit(ComputedPropertyName node, CodeVisitor mv) {
/* steps 1-3 */
ValType type = expression(node.getExpression(), mv);
/* step 4 */
return ToPropertyKey(type, mv);
}
@Override
public ValType visit(PropertyDefinitionsMethod node, CodeVisitor mv) {
MethodName method = codegen.compile(node, decorators != null, mv);
boolean hasResume = node.hasResumePoint();
mv.enterVariableScope();
Variable<OrdinaryObject> object = mv.newVariable("object", OrdinaryObject.class);
// stack: [<object>] -> []
mv.store(object);
// stack: [] -> []
mv.lineInfo(0); // 0 = hint for stacktraces to omit this frame
if (hasResume) {
mv.callWithSuspend(method, object, decoratorsOrNull(mv));
} else {
mv.call(method, object, decoratorsOrNull(mv));
}
mv.exitVariableScope();
return null;
}
/**
* 14.3.9 Runtime Semantics: PropertyDefinitionEvaluation<br>
* 14.4.13 Runtime Semantics: PropertyDefinitionEvaluation
*/
@Override
public ValType visit(MethodDefinition node, CodeVisitor mv) {
MethodName method = codegen.compile(node);
boolean hasDecorators = !node.getDecorators().isEmpty();
if (hasDecorators) {
evaluateDecorators(decorators, node.getDecorators(), mv);
}
// stack: [<object>] -> []
String propName = PropName(node);
if (propName == null) {
assert node.getPropertyName() instanceof ComputedPropertyName;
ValType propKey = node.getPropertyName().accept(this, mv);
if (hasDecorators) {
addDecoratorKey(decorators, propKey, mv);
}
mv.iconst(node.getAllocation() == MethodDefinition.MethodAllocation.Object);
mv.invoke(method);
mv.loadExecutionContext();
mv.lineInfo(node);
switch (node.getType()) {
case AsyncFunction:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionAsync);
break;
case AsyncGenerator:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionAsyncGenerator);
break;
case Function:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinition);
break;
case ConstructorGenerator:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionConstructorGenerator);
break;
case Generator:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionGenerator);
break;
case Getter:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionGetter);
break;
case Setter:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionSetter);
break;
case BaseConstructor:
case DerivedConstructor:
case CallConstructor:
default:
throw new AssertionError("invalid method type");
}
} else {
if (hasDecorators) {
addDecoratorKey(decorators, propName, mv);
}
mv.aconst(propName);
mv.iconst(node.getAllocation() == MethodDefinition.MethodAllocation.Object);
mv.invoke(method);
mv.loadExecutionContext();
mv.lineInfo(node);
switch (node.getType()) {
case AsyncFunction:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionAsync_String);
break;
case AsyncGenerator:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionAsyncGenerator_String);
break;
case Function:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinition_String);
break;
case ConstructorGenerator:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionConstructorGenerator_String);
break;
case Generator:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionGenerator_String);
break;
case Getter:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionGetter_String);
break;
case Setter:
mv.invoke(Methods.ScriptRuntime_EvaluatePropertyDefinitionSetter_String);
break;
case BaseConstructor:
case DerivedConstructor:
case CallConstructor:
default:
throw new AssertionError("invalid method type");
}
}
return null;
}
/**
* 12.2.5.8 Runtime Semantics: PropertyDefinitionEvaluation
* <p>
* PropertyDefinition : IdentifierReference
*/
@Override
public ValType visit(PropertyNameDefinition node, CodeVisitor mv) {
IdentifierReference propertyName = node.getPropertyName();
String propName = PropName(propertyName);
assert propName != null;
// stack: [<object>] -> []
mv.aconst(propName);
expressionBoxed(propertyName, mv);
mv.loadExecutionContext();
mv.lineInfo(node);
mv.invoke(Methods.ScriptRuntime_defineProperty_String);
return null;
}
/**
* 12.2.5.8 Runtime Semantics: PropertyDefinitionEvaluation
* <p>
* PropertyDefinition : PropertyName : AssignmentExpression
*/
@Override
public ValType visit(PropertyValueDefinition node, CodeVisitor mv) {
Expression propertyValue = node.getPropertyValue();
PropertyName propertyName = node.getPropertyName();
String propName = PropName(propertyName);
long propIndex = propName != null ? IndexedMap.toIndex(propName) : -1;
// stack: [<object>] -> []
if (propName == null) {
assert propertyName instanceof ComputedPropertyName;
ValType type = propertyName.accept(this, mv);
expressionBoxed(propertyValue, mv);
if (IsAnonymousFunctionDefinition(propertyValue)) {
SetFunctionName(propertyValue, type, mv);
}
mv.loadExecutionContext();
mv.lineInfo(node);
mv.invoke(Methods.ScriptRuntime_defineProperty);
} else if ("__proto__".equals(propName) && codegen.isEnabled(CompatibilityOption.ProtoInitializer)) {
expressionBoxed(propertyValue, mv);
mv.loadExecutionContext();
mv.lineInfo(node);
mv.invoke(Methods.ScriptRuntime_defineProtoProperty);
} else if (IndexedMap.isIndex(propIndex)) {
mv.lconst(propIndex);
expressionBoxed(propertyValue, mv);
if (IsAnonymousFunctionDefinition(propertyValue)) {
SetFunctionName(propertyValue, propName, mv);
}
mv.loadExecutionContext();
mv.lineInfo(node);
mv.invoke(Methods.ScriptRuntime_defineProperty_long);
} else {
mv.aconst(propName);
expressionBoxed(propertyValue, mv);
if (IsAnonymousFunctionDefinition(propertyValue)) {
SetFunctionName(propertyValue, propName, mv);
}
mv.loadExecutionContext();
mv.lineInfo(node);
mv.invoke(Methods.ScriptRuntime_defineProperty_String);
}
return null;
}
@Override
public ValType visit(SpreadProperty node, CodeVisitor mv) {
// stack: [<object>] -> [<object>, value]
expressionBoxed(node.getExpression(), mv);
// stack: [<object>, value] -> []
mv.loadExecutionContext();
mv.lineInfo(node);
mv.invoke(Methods.ScriptRuntime_defineSpreadProperty);
return null;
}
}