/// <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)); }
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)); } }
/// <summary> /// Gets the field body if exists. /// </summary> /// <remarks> /// This method does not evaluate the body of the field if exists, and moreover, does not recurs to the parent. /// </remarks> public bool TryGetField(SymbolAtom name, out object body) { 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 && binding.IsExported) { body = binding.Body; return(true); } body = null; return(false); }
/// <summary> /// Adds a binding. /// </summary> public bool AddBinding(SymbolAtom name, ModuleBinding binding) { Contract.Requires(name.IsValid); Contract.Requires(Qualifier == QualifierValue.Unqualified); Contract.Requires(binding != null); lock (m_syncRoot) { m_bindings = m_bindings ?? new BindingDictionary(); if (m_bindings.ContainsKey(name)) { return(false); } m_bindings.Add(name, binding); } return(true); }
internal bool TryResolveExtendedName(ImmutableContextBase context, FullSymbol enclosingName, FullSymbol requestedName, out ModuleBinding result) { // Semantically nested namespaces forms hierarchical structure, when nested namespace is stored in the outer namespace. // For performance reasons, file module stores all names in one big map with combined keys. // This means that when looking for A.B we should look at the current scope for A, then need to combine A and B // and look for A.B in the file module. // This means that extended (or partial) names are only allowed if the enclosing name is valid. // In this case we will combine requested name with the enclosing one and look in the current file module. result = null; if (!enclosingName.IsValid) { return(false); } if (m_partialSymbolsCache.Value.TryGetValue(requestedName, out result)) { return(true); } var extendedFullName = enclosingName.Combine(context.FrontEndContext.SymbolTable, requestedName); // Now trying to resolve extended name in the current file. result = GetNamespaceBinding(context, extendedFullName, recurs: false); // If resolution was successful, saving it in the cache. if (result != null) { m_partialSymbolsCache.Value.GetOrAdd(requestedName, result); return(true); } return(false); }
private object GetOrEvalField(ImmutableContextBase context, ModuleLiteral origin, SymbolAtom name, ModuleBinding bindingValue) { // This method may be invoked concurrently on the same context. Thus we may not mutate the context at hand, but must create a local mutable child context. using (var localMutableContext = context.CreateWithModule(this)) { var result = origin.GetOrEvalField( localMutableContext, name, recurs: true, origin: origin, location: bindingValue.Location); Contract.Assert(!localMutableContext.HasChildren); // just before the newly created context get disposed, we want to assert that all of its child contexts have already been disposed return(result.Value); } }
/// <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)))); }
private EvaluationResult GetOrEvalFieldBindingThunk(ImmutableContextBase context, SymbolAtom name, ModuleBinding binding, Thunk thunk) { // Keep this call in a separate method to avoid always creating a closure object on the heap in the caller // If the thunk hasn't been evaluated yet for the current qualifier, then its evaluation gets kicked off in a newly allocated mutable named context. // We must not mutate the context at hand directly, as there might be other concurrent child contexts alive. var contextName = GetFullyQualifiedBindingName(context.FrontEndContext.SymbolTable, this, name); return(thunk.LegacyEvaluateWithNewNamedContext(context, this, contextName, binding.Location)); }
/// <summary> /// Evaluates given <paramref name="binding"/> that corresponds to field <paramref name="name"/> /// (<seealso cref="GetOrEvalField(Context, SymbolAtom, bool, ModuleLiteral, LineInfo)"/>) /// </summary> public EvaluationResult GetOrEvalFieldBinding(Context context, SymbolAtom name, ModuleBinding binding, LineInfo callingLocation) { object o = binding.Body; if (o is Thunk thunk) { return(GetOrEvalFieldBindingThunk(context, name, binding, thunk)); } if (o is Expression expr) { using (var frame = EvaluationStackFrame.Empty()) { return(expr.Eval(context, this, frame)); } } return(EvaluationResult.Create(o)); }