Beispiel #1
0
        /// <summary>
        /// Evaluates a right-hand side expression if not evaluated yet.
        /// </summary>
        protected internal static EvaluationResult EvalExpression(Context context, ModuleLiteral env, EvaluationResult o, EvaluationStackFrame args)
        {
            var e = o.Value as Expression;

            return(e?.Eval(context, env, args) ?? o);
        }
Beispiel #2
0
        /// <inheritdoc />
        public override EvaluationResult GetOrEvalField(Context context, StringId name, bool recurs, ModuleLiteral origin, LineInfo location)
        {
            if (m_values.TryGetValue(name.Value, out EvaluationResult result))
            {
                return(result);
            }

            return(EvaluationResult.Undefined);
        }
Beispiel #3
0
 /// <summary>
 /// Creates a task that runs GetOrEvalField taking into consideration concurrency settings
 /// </summary>
 protected Task <object> RunGetOrEvalFieldAsync(ImmutableContextBase context, ModuleLiteral origin, SymbolAtom name, ModuleBinding bindingValue)
 {
     return(context.EvaluationScheduler.EvaluateValue(() => Task.FromResult(GetOrEvalField(context, origin, name, bindingValue))));
 }
Beispiel #4
0
 /// <summary>
 /// Gets or evaluates field.
 /// </summary>
 /// <returns>
 /// Returns evaluated field or <see cref="UndefinedValue.Instance"/> if member is not found.
 /// Unfortunately there is no way to distinguish between type error or missing member, so in both
 /// cases this method will return the same - undefined.
 /// </returns>
 /// <remarks>
 /// Fields may need to be evaluated. This happens in the case of module fields that have thunked expressions.
 /// </remarks>
 public abstract EvaluationResult GetOrEvalField([NotNull] Context context, StringId name, bool recurs, [NotNull] ModuleLiteral origin, LineInfo location);
Beispiel #5
0
        /// <nodoc />
        protected static FullSymbol GetFullyQualifiedBindingName(SymbolTable symbolTable, ModuleLiteral owningModule, SymbolAtom name)
        {
            Contract.Requires(name.IsValid);

            return(owningModule.Id.Name.Combine(symbolTable, name));
        }
Beispiel #6
0
        private void AddGetOrEvalFieldTasks(ImmutableContextBase context, List <Task <object> > list, ModuleLiteral origin)
        {
            Contract.Requires(origin.m_bindings != null);

            foreach (var binding in origin.m_bindings)
            {
                SymbolAtom    name         = binding.Key;
                ModuleBinding bindingValue = binding.Value;

                list.Add(RunGetOrEvalFieldAsync(context, origin, name, bindingValue));
            }
        }
Beispiel #7
0
        /// <summary>
        /// Gets module or namespace based on module id.
        /// </summary>
        public EvaluationResult GetNamespace(ImmutableContextBase context, FullSymbol fullName, bool recurs, ModuleLiteral origin, LineInfo location)
        {
            ModuleBinding binding = GetNamespaceBinding(context, fullName, recurs);

            if (binding == null)
            {
                context.Errors.ReportMissingNamespace(origin ?? this, fullName, this, location);
                return(EvaluationResult.Error);
            }

            return(EvaluationResult.Create(binding.Body));
        }
Beispiel #8
0
        private EvaluationResult GetOrEvalField(Context context, SymbolAtom name, ModuleLiteral startEnv, bool recurs, ModuleLiteral origin, LineInfo location)
        {
            // This logic is still used only V1 evaluation
            if (IsFileModule && name == context.ContextTree.CommonConstants.Qualifier)
            {
                // Someone references 'qualifier' on the file level.
                return(EvaluationResult.Create(Qualifier.Qualifier));
            }

            ModuleBinding binding = null;

            // TODO:ST: sounds reasonable to add "warning" if name was resolved but it is not exposed!
            if (m_bindings?.TryGetValue(name, out binding) == true && (recurs || binding.IsExported))
            {
                return(GetOrEvalFieldBinding(context, name, binding, location));
            }

            if (recurs && OuterScope != null)
            {
                return(OuterScope.GetOrEvalField(context, name, startEnv, true, origin, location));
            }

            context.Errors.ReportMissingMember(origin ?? startEnv, name, startEnv, location);

            return(EvaluationResult.Error);
        }
Beispiel #9
0
        /// <nodoc />
        public sealed override EvaluationResult GetOrEvalField(Context context, SymbolAtom name, bool recurs, ModuleLiteral origin, LineInfo location)
        {
            Contract.Requires(name.IsValid);

            return(GetOrEvalField(context, name, this, recurs: recurs, origin: origin, location: location));
        }
Beispiel #10
0
 /// <inheritdoc />
 public sealed override bool TryProject(Context context, SymbolAtom name, ModuleLiteral origin, out EvaluationResult result, LineInfo location)
 {
     result = GetOrEvalField(context, name, recurs: false, origin: origin, location: Location);
     return(true);
 }
Beispiel #11
0
 /// <inheritdoc />
 protected override EvaluationResult DoEval(Context context, ModuleLiteral env, EvaluationStackFrame frame)
 {
     return(EvaluationResult.Create(this));
 }
Beispiel #12
0
        /// <summary>
        /// Constructs module literal for namespace.
        /// </summary>
        protected static TypeOrNamespaceModuleLiteral CreateTypeOrNamespaceModule(FullSymbol namespaceName, ModuleLiteral outerScope, LineInfo location)
        {
            Contract.Requires(namespaceName.IsValid);
            Contract.Requires(outerScope != null);
            Contract.Requires(outerScope.IsFileOrGlobal);

            ModuleLiteralId moduleId = outerScope.Id.WithName(namespaceName);

            return(new TypeOrNamespaceModuleLiteral(moduleId, qualifier: QualifierValue.Unqualified,
                                                    outerScope: outerScope, location: location));
        }
Beispiel #13
0
        private EvaluationResult QualifiedEvaluateWithCycleDetection(ref object value, ImmutableContextBase context, ModuleLiteral env, Evaluation currentEvaluation, ref MutableContextFactory factory)
        {
            // Someone else is already busy evaluating this thunk. Let's wait...
            EvaluationStatus result;
            var cycleDetector = context.FrontEndHost.CycleDetector;

            if (cycleDetector != null)
            {
                using (cycleDetector.AddValuePromiseChain(
                           valuePromiseChainGetter: () => GetValuePromiseChain(context, env),
                           cycleAnnouncer: () => currentEvaluation.Cancel(EvaluationStatus.Cycle)))
                {
                    currentEvaluation.Wait(cycleDetector);
                    result = currentEvaluation.Result;
                    if ((result & EvaluationStatus.Value) != 0)
                    {
                        var currentValue = Volatile.Read(ref value);
                        Contract.Assert(currentValue is EvaluationResult);
                        return((EvaluationResult)currentValue);
                    }
                }
            }
            else
            {
                currentEvaluation.Wait();
                result = currentEvaluation.Result;
                if ((result & EvaluationStatus.Value) != 0)
                {
                    var currentValue = Volatile.Read(ref value);
                    Contract.Assert(currentValue is EvaluationResult);
                    return((EvaluationResult)currentValue);
                }
            }

            // Evaluation got canceled --- we hit a cycle (or deadlock)!
            if ((result & EvaluationStatus.Cycle) != 0)
            {
                context.Errors.ReportCycle(env, Expression.Location, factory.ContextName);
                currentEvaluation.SetValue(ref value, EvaluationResult.Error);
                return(EvaluationResult.Error);
            }

            // Evaluation crashed, which means that Expression.Eval had failed, and had thrown an exception.
            if ((result & EvaluationStatus.Crash) != 0)
            {
                // Crash has been reported at the crash site.
                currentEvaluation.SetValue(ref value, EvaluationResult.Error);
                return(EvaluationResult.Error);
            }

            return(EvaluationResult.Error);
        }
Beispiel #14
0
        private EvaluationResult QualifiedEvaluate(
            ref object value,
            ImmutableContextBase context,
            ModuleLiteral env,
            EvaluationStackFrame args,
            ref MutableContextFactory factory)
        {
            // Contract.Ensures(Contract.Result<object>() != null && !(Contract.Result<object>() is Evaluation));

            // do we have a real value yet?
            var currentValue      = Volatile.Read(ref value);
            var currentEvaluation = currentValue as Evaluation;

            if (currentValue != currentEvaluation)
            {
                Contract.Assert(currentValue is EvaluationResult);

                // so it's not null, and it's not an evaluation => we have a real value!
                return((EvaluationResult)currentValue);
            }

            // no real value yet, let's try to create a new evaluation
            if (currentEvaluation == null && !factory.ForceWaitForResult)
            {
                var newEvaluation = new Evaluation(
                    context.EvaluatorConfiguration.CycleDetectorStartupDelay,
                    context.EvaluatorConfiguration.CycleDetectorIncreasePriorityDelay);
                currentValue      = Interlocked.CompareExchange(ref value, newEvaluation, null);
                currentEvaluation = currentValue as Evaluation;
                if (currentValue != currentEvaluation)
                {
                    Contract.Assert(currentValue is EvaluationResult);

                    // so it's not null, and it's not an evaluation => we have a real value! (and the CompareExchange must have failed)
                    return((EvaluationResult)currentValue);
                }

                if (currentValue == null)
                {
                    using (var newLocalMutableContext = factory.Create(context))
                    {
                        try
                        {
                            var newValue = Expression.Eval(newLocalMutableContext, env, args);

                            // Evaluation got canceled --- we hit a cycle (or deadlock)!
                            if ((newEvaluation.Result & EvaluationStatus.Cycle) != 0)
                            {
                                newLocalMutableContext.Errors.ReportCycle(env, Expression.Location);
                                newEvaluation.SetValue(ref value, EvaluationResult.Error);
                                return(EvaluationResult.Error);
                            }

                            newEvaluation.SetValue(ref value, newValue);
                            return(newValue);
                        }
                        catch
                        {
                            // No actual value was ever set --- this means that Expression.Eval failed, and most likely threw an exception!
                            // Let's propagate this result, so that anyone else waiting for us gets unblocked.
                            newEvaluation.Cancel(EvaluationStatus.Crash);
                            throw;
                        }
                        finally
                        {
                            Contract.Assert(!newLocalMutableContext.HasChildren);

                            // just before the newly created context get disposed, we want to assert that all of its child contexts have already been disposed
                        }
                    }
                }

                // there's already an ongoing evaluation! (and the CompareExchange must have failed) we fall through...
            }

            if (factory.ForceWaitForResult)
            {
                while (currentEvaluation == null)
                {
                    Thread.Sleep(TimeSpan.FromMilliseconds(10));
                    currentEvaluation = Volatile.Read(ref value) as Evaluation;
                }
            }

            return(QualifiedEvaluateWithCycleDetection(ref value, context, env, currentEvaluation, ref factory));
        }
Beispiel #15
0
        /// <summary>
        /// Evaluates this thunk in a new named context
        /// </summary>
        /// <remarks>
        /// V1-specific. Still used to evaluate configuration-related files in V2 (and for the whole V1 legacy evaluation).
        /// </remarks>
        public EvaluationResult LegacyEvaluateWithNewNamedContext(ImmutableContextBase context, ModuleLiteral module, FullSymbol contextName, LineInfo location, bool forceWaitForResult = false)
        {
            // There is no captured template value in V1
            var factory = new MutableContextFactory(this, contextName, module, templateValue: null, location: location, forceWaitForResult: forceWaitForResult);

            return(EvaluateWithNewNamedContextAndTemplate(context, ref factory));
        }