/// <inheritdoc /> protected override EvaluationResult DoEval(Context context, ModuleLiteral env, EvaluationStackFrame frame) { var receiver = ThisExpression.Eval(context, env, frame); if (receiver.IsErrorValue) { return(EvaluationResult.Error); } if (receiver.Value is ObjectLiteral obj) { if (Selector.GetParent(context.FrontEndContext.SymbolTable) != FullSymbol.Invalid) { context.Errors.ReportFailResolveModuleSelector(env, this); return(EvaluationResult.Error); } return(obj.GetOrEvalField( context, Selector.GetName(context.FrontEndContext.SymbolTable), recurs: false, origin: env, location: Location)); } context.Errors.ReportUnexpectedValueType( env, ThisExpression, receiver, new[] { typeof(ModuleLiteral), typeof(ObjectLiteral) }); return(EvaluationResult.Error); }
/// <inheritdoc /> protected override EvaluationResult DoEval(Context context, ModuleLiteral env, EvaluationStackFrame frame) { var e = ThisExpression.Eval(context, env, frame); if (e.IsErrorValue) { return(EvaluationResult.Error); } var indexObj = Index.Eval(context, env, frame); if (indexObj.IsErrorValue) { return(EvaluationResult.Error); } // Extracting local to avoid casting multiple times var stringIndexer = indexObj.Value as string; if (e.Value is ArrayLiteral arrayLiteral) { if (indexObj.Value is int index) { if (index < 0 || index >= arrayLiteral.Length) { // This behavior is different from the TypeScript one, but this is actually helpful context.Errors.ReportArrayIndexOufOfRange(env, this, index, arrayLiteral.Length); return(EvaluationResult.Error); } return(arrayLiteral[index]); } // indexer for an array can be a number for getting elements, or string if (stringIndexer == null) { context.Errors.ReportUnexpectedValueType(env, Index, indexObj, typeof(int), typeof(string)); return(EvaluationResult.Error); } // Falling back to object literal case if the indexer is a string. } if (e.Value is ObjectLiteral objectLiteral) { if (stringIndexer != null) { var selectorId = context.FrontEndContext.StringTable.AddString(stringIndexer); return(objectLiteral.GetOrEvalField(context, selectorId, recurs: false, origin: env, location: Location)); } context.Errors.ReportUnexpectedValueType(env, Index, indexObj, typeof(string)); return(EvaluationResult.Error); } // Indexer in typescript never fails and return undefined. // Following this pattern. return(EvaluationResult.Undefined); }
/// <inheritdoc /> protected override EvaluationResult DoEval(Context context, ModuleLiteral env, EvaluationStackFrame frame) { var receiver = ThisExpression.Eval(context, env, frame); if (receiver.IsErrorValue) { return(EvaluationResult.Error); } if (receiver.IsUndefined) { context.Errors.ReportFailResolveSelectorDueToUndefined(env, this); return(EvaluationResult.Error); } if (receiver.Value is Expression thisExpressionResult) { if (thisExpressionResult.TryProject(context, Selector, env, context.PredefinedTypes, out EvaluationResult projectionResult, Location)) { return(projectionResult); } context.Errors.ReportUnexpectedValueType( env, ThisExpression, receiver, typeof(ObjectLiteral), typeof(ArrayLiteral), typeof(ModuleLiteral)); return(EvaluationResult.Error); } // Trying to find member function for well-known types. var boundMember = context.PredefinedTypes.ResolveMember(receiver.Value, Selector); if (boundMember != null) { // If bound member represents a property we need to evaluate it. return(boundMember.IsProperty ? EvaluateAmbientProperty(context, env, boundMember) : EvaluationResult.Create(boundMember)); } context.Errors.ReportMissingProperty(env, Selector, receiver.Value, Location); return(EvaluationResult.Error); }