public void GenerateThis(ILGenerator generator)
{
// Optimization: if there are no with scopes, simply emit undefined.
bool scopeChainHasWithScope = false;
var scope = this.Scope;
do
{
if (scope is ObjectScope && ((ObjectScope)scope).ProvidesImplicitThisValue == true)
{
scopeChainHasWithScope = true;
break;
}
scope = scope.ParentScope;
} while (scope != null);
if (scopeChainHasWithScope == false)
{
// No with scopes in the scope chain, use undefined as the "this" value.
EmitHelpers.EmitUndefined(generator);
return;
}
var end = generator.CreateLabel();
scope = this.Scope;
ILLocalVariable scopeVariable = generator.CreateTemporaryVariable(typeof(Scope));
EmitHelpers.LoadScope(generator);
generator.StoreVariable(scopeVariable);
do
{
if (scope is DeclarativeScope)
{
if (scope.HasDeclaredVariable(this.Name))
{
// The variable exists but declarative scopes always produce undefined for
// the "this" value.
EmitHelpers.EmitUndefined(generator);
break;
}
}
else
{
var objectScope = (ObjectScope)scope;
// Check if the property exists by calling scope.ScopeObject.HasProperty(propertyName)
if (objectScope.ProvidesImplicitThisValue == false)
EmitHelpers.EmitUndefined(generator);
generator.LoadVariable(scopeVariable);
generator.CastClass(typeof(ObjectScope));
generator.Call(ReflectionHelpers.ObjectScope_ScopeObject);
if (objectScope.ProvidesImplicitThisValue == true)
generator.Duplicate();
generator.LoadString(this.Name);
generator.Call(ReflectionHelpers.ObjectInstance_HasProperty);
generator.BranchIfTrue(end);
generator.Pop();
// If the name is not defined, use undefined for the "this" value.
if (scope.ParentScope == null)
{
EmitHelpers.EmitUndefined(generator);
}
}
// Try the parent scope.
if (scope.ParentScope != null && scope.ExistsAtRuntime == true)
{
generator.LoadVariable(scopeVariable);
generator.Call(ReflectionHelpers.Scope_ParentScope);
generator.StoreVariable(scopeVariable);
}
scope = scope.ParentScope;
} while (scope != null);
// Release the temporary variable.
generator.ReleaseTemporaryVariable(scopeVariable);
// Define a label at the end.
generator.DefineLabelPosition(end);
}