/// <inheritdoc /> protected override EvaluationResult DoEval(Context context, ModuleLiteral env, EvaluationStackFrame frame) { // There is some code duplication between this type and the CoerceQualifierTypeExpression. // But there is not clear how to reuse this because steps are 'slightly' different. var moduleCandidate = ModuleReference.Eval(context, env, frame); if (moduleCandidate.IsErrorValue || moduleCandidate.IsUndefined) { return(moduleCandidate); } // The type checker should make sure that 'this expression' evaluates to a module literal. var module = moduleCandidate.Value as ModuleLiteral; Contract.Assert( module != null, I($"The left hand-side of a withQualifier expression should evaluates to 'TypeOrNamespaceModuleLiteral' but got '{moduleCandidate.Value.GetType()}'")); Contract.Assert(module.CurrentFileModule != null, "module.CurrentFileModule != null"); // QualifierExpression can be an object literal or anything that ended up as an object literal. EvaluationResult objectQualifier; using (var emptyFrame = EvaluationStackFrame.Empty()) { objectQualifier = QualifierExpression.Eval(context, env, emptyFrame); } if (objectQualifier.IsErrorValue) { // Error has been reported. return(EvaluationResult.Error); } var qualifierLiteral = objectQualifier.Value as ObjectLiteral; Contract.Assert( qualifierLiteral != null, I($"The right hand-side of a withQualifier expression should evaluates to 'ObjectLiteral' but got '{objectQualifier.Value.GetType()}'")); if (!QualifierValue.TryCreate(context, env, qualifierLiteral, out QualifierValue qualifierValue, qualifierLiteral.Location)) { // Error has been reported. return(EvaluationResult.Error); } // Coercing qualifier with a given value if ( !QualifierUtilities.CoerceQualifierValueForV2( context, qualifierValue, SourceQualifierSpaceId, TargetQualifierSpaceId, referencingLocation: Location.AsUniversalLocation(env, context), referencedLocation: module.CurrentFileModule.Location.AsUniversalLocation(module.CurrentFileModule, context), coercedQualifierValue: out QualifierValue coercedQualifierValue)) { // Error has been reported return(EvaluationResult.Error); } var result = module.Instantiate(context.ModuleRegistry, coercedQualifierValue); return(EvaluationResult.Create(result)); }
/// <inheritdoc /> protected override EvaluationResult DoEval(Context context, ModuleLiteral env, EvaluationStackFrame frame) { // There is some code duplication between this type and the CoerceQualifierTypeExpression. // But there is not clear how to reuse this because steps are 'slightly' different. var moduleCandidate = ModuleReference.Eval(context, env, frame); if (moduleCandidate.IsErrorValue || moduleCandidate.IsUndefined) { return(moduleCandidate); } // The type checker should make sure that 'this expression' evaluates to a module literal. var module = moduleCandidate.Value as ModuleLiteral; Contract.Assert( module != null, I($"The left hand-side of a withQualifier expression should evaluates to 'TypeOrNamespaceModuleLiteral' but got '{moduleCandidate.Value.GetType()}'")); Contract.Assert(module.CurrentFileModule != null, "module.CurrentFileModule != null"); var currentQualifier = env.CurrentFileModule.Qualifier.Qualifier; // QualifierExpression can be an object literal or anything that ended up as an object literal. EvaluationResult objectQualifier; using (var emptyFrame = EvaluationStackFrame.Empty()) { objectQualifier = QualifierExpression.Eval(context, env, emptyFrame); } if (objectQualifier.IsErrorValue) { // Error has been reported. return(EvaluationResult.Error); } var requestedQualifier = objectQualifier.Value as ObjectLiteral; Contract.Assert( requestedQualifier != null, I($"The right hand-side of a withQualifier expression should evaluates to 'ObjectLiteral' but got '{objectQualifier.Value.GetType()}'")); // TODO: This can be made more efficient by talking with the qualifier table directly // and maintaining a global map of qualifier id to object literal rather than have many copies of // object literal floating around, but that would be more changes than warranted at the moment // since withqualifier is not used that heavily at the moment, when this starts showing up on profiles // we should consider improving the logic here. var qualifierBindings = new Dictionary <StringId, Binding>(); foreach (var member in currentQualifier.Members) { qualifierBindings[member.Key] = new Binding(member.Key, member.Value, requestedQualifier.Location); } foreach (var member in requestedQualifier.Members) { if (member.Value.IsUndefined) { // setting a value to undefined implies explicitly removing they qualifier key. qualifierBindings.Remove(member.Key); } else { qualifierBindings[member.Key] = new Binding(member.Key, member.Value, requestedQualifier.Location); } } var qualifierToUse = ObjectLiteral.Create(qualifierBindings.Values.ToArray()); if (!QualifierValue.TryCreate(context, env, qualifierToUse, out QualifierValue qualifierValue, requestedQualifier.Location)) { // Error has been reported. return(EvaluationResult.Error); } // Coercing qualifier with a given value if ( !QualifierUtilities.CoerceQualifierValueForV2( context, qualifierValue, SourceQualifierSpaceId, TargetQualifierSpaceId, referencingLocation: Location.AsUniversalLocation(env, context), referencedLocation: module.CurrentFileModule.Location.AsUniversalLocation(module.CurrentFileModule, context), coercedQualifierValue: out QualifierValue coercedQualifierValue)) { // Error has been reported return(EvaluationResult.Error); } var result = module.Instantiate(context.ModuleRegistry, coercedQualifierValue); return(EvaluationResult.Create(result)); }