/// <summary> /// Validates and constructs generic entities out of an ambiguous generic definition entity. /// </summary> private IEntity ConstructAmbiguousEntity(Node constructionNode, Ambiguous ambiguousDefinition, IType[] typeArguments) { var checker = new GenericConstructionChecker(typeArguments, constructionNode); var matches = new List<IEntity>(ambiguousDefinition.Entities); bool reportErrors = false; foreach (Predicate<IEntity> check in checker.Checks) { matches = matches.Collect(check); if (matches.Count == 0) { Errors.Add(checker.Errors[0]); // only report first error, assuming the rest are superfluous return TypeSystemServices.ErrorEntity; } if (reportErrors) checker.ReportErrors(Errors); checker.DiscardErrors(); // We only want full error reporting once we get down to a single candidate if (matches.Count == 1) reportErrors = true; } IEntity[] constructedMatches = Array.ConvertAll<IEntity, IEntity>(matches.ToArray(), def => MakeGenericEntity(def, typeArguments)); return Entities.EntityFromList(constructedMatches); }
/// <summary> /// Validates and constructs generic entities out of an ambiguous generic definition entity. /// </summary> private IEntity ConstructAmbiguousEntity(Node constructionNode, Ambiguous ambiguousDefinition, IType[] typeArguments) { var checker = new GenericConstructionChecker(typeArguments, constructionNode); var matches = new List <IEntity>(ambiguousDefinition.Entities); bool reportErrors = false; foreach (Predicate <IEntity> check in checker.Checks) { matches = matches.Collect(check); if (matches.Count == 0) { Errors.Add(checker.Errors[0]); // only report first error, assuming the rest are superfluous return(TypeSystemServices.ErrorEntity); } if (reportErrors) { checker.ReportErrors(Errors); } checker.DiscardErrors(); // We only want full error reporting once we get down to a single candidate if (matches.Count == 1) { reportErrors = true; } } IEntity[] constructedMatches = Array.ConvertAll <IEntity, IEntity>(matches.ToArray(), def => MakeGenericEntity(def, typeArguments)); return(Entities.EntityFromList(constructedMatches)); }
// Sometimes, for the purpose of overload resolution, it doesn't matter which overload // you pick, because they all take the same callable type and only differ in the rest of // the param list private IMethod ResolveAmbiguousInvocationContext(Ambiguous entity, int argumentIndex) { var candidates = entity.Entities .OfType <IMethod>() .Where(m => m.GetParameters().Length > argumentIndex && m.GetParameters()[argumentIndex].Type is ICallableType) .ToArray(); if (candidates.Length > 0) { var first = candidates[0]; if (candidates.Length == 1) { return(first); } var correspondingType = first.GetParameters()[argumentIndex].Type; if (candidates.Skip(1).All(m => m.GetParameters()[argumentIndex].Type == correspondingType)) { return(first); } var returnType = ((ICallableType)first.GetParameters()[argumentIndex].Type).GetSignature().ReturnType; if (candidates.Skip(1).All(m => ((ICallableType)m.GetParameters()[argumentIndex].Type).GetSignature().ReturnType == returnType)) { _closure["$InferredReturnType"] = returnType; } } AstAnnotations.MarkAmbiguousSignature(MethodInvocationContext); AstAnnotations.MarkAmbiguousSignature(_closure); return(null); }
private IType GetTypeFromMethodInvocationContext() { if (MethodInvocationContext == null) { return(null); } int argumentIndex = MethodInvocationContext.Arguments.IndexOf(Closure); if (argumentIndex == -1 && _asyncParent != null) { argumentIndex = MethodInvocationContext.Arguments.IndexOf(_asyncParent); } var entity = MethodInvocationContext.Target.Entity; var method = entity as IMethodBase; if (method == null) { if (entity.EntityType == EntityType.Type) { var ctors = ((IType)MethodInvocationContext.Target.Entity).GetConstructors().ToArray(); if (ctors.Length == 1) { method = ctors[0]; } else if (ctors.Length == 0) { return(null); } else { entity = new Ambiguous(ctors); } } if (entity.EntityType == EntityType.Ambiguous) { method = ResolveAmbiguousInvocationContext((Ambiguous)entity, argumentIndex); } if (method == null) { return(null); } } IParameter[] parameters = method.GetParameters(); if (argumentIndex < parameters.Length) { return(parameters[argumentIndex].Type); } if (method.AcceptVarArgs) { return(parameters[parameters.Length - 1].Type); } return(null); }
private IEntity ResolvePreferringInternalMacros(string macroTypeName) { IEntity resolved = NameResolutionService.ResolveQualifiedName(macroTypeName); Ambiguous ambiguous = resolved as Ambiguous; if (null != ambiguous && ambiguous.AllEntitiesAre(EntityType.Type)) { return(Entities.PreferInternalEntitiesOverExternalOnes(ambiguous)); } return(resolved); }
private Ambiguous NeedsClarification(FieldStepState stepState) { Ambiguous clarify = null; foreach (var clarification in stepState.Clarifications) { if (clarification.Values.Length > 1) { clarify = clarification; break; } } return(clarify); }
IEntity ResolveMacroExtensionType(MacroStatement node, Ambiguous extensions) { if (null == extensions) { return(null); } foreach (var entity in extensions.Entities) { var extensionType = ResolveMacroExtensionType(node, entity as IMethod); if (null != extensionType) { return(extensionType); } } return(null); }
public static IEntity PreferInternalEntitiesOverExternalOnes(IEntity entity) { Ambiguous ambiguous = entity as Ambiguous; if (null == ambiguous) { return(entity); } bool isAmbiguousBetweenInternalAndExternalEntities = ambiguous.Any(EntityPredicates.IsInternalEntity) && ambiguous.Any(EntityPredicates.IsNonInternalEntity); if (!isAmbiguousBetweenInternalAndExternalEntities) { return(entity); } return(EntityFromList(ambiguous.Select(EntityPredicates.IsInternalEntity))); }
/// <summary> /// Maps a type member involving generic arguments to its constructed counterpart, after substituting /// concrete types for generic arguments. /// </summary> public IEntity Map(IEntity source) { if (source == null) { return(null); } // Map generic source to the constructed owner of this mapping if (source == _genericSource) { return(_constructedOwner); } Ambiguous ambiguous = source as Ambiguous; if (ambiguous != null) { return(MapAmbiguousEntity(ambiguous)); } IMember member = source as IMember; if (member != null) { return(MapMember(member)); } IType type = source as IType; if (type != null) { return(MapType(type)); } return(source); }
private IField <T> ClarifyField(Ambiguous clarify, IRecognize <T> recognizer) { var field = new FieldClarify(_field); foreach (var value in clarify.Values) { var choice = value as Choice; if (choice != null) { field.AddDescription(choice.Value, choice.Description.Description, choice.Description.Image, choice.Description.Message); field.AddTerms(choice.Value, choice.Terms.Alternatives); } else { var desc = recognizer.ValueDescription(value); field.AddDescription(value, desc.Description, desc.Image); field.AddTerms(value, recognizer.ValidInputs(value).ToArray()); } } return(field); }
private IEntity MapAmbiguousEntity(Ambiguous source) { // Map each individual entity in the ambiguous list return(new Ambiguous(Array.ConvertAll <IEntity, IEntity>(source.Entities, Map))); }
public async Task <StepResult> ProcessAsync(IDialogContext context, T state, FormState form, IMessageActivity input, IEnumerable <TermMatch> matches) { var inputText = MessageActivityHelper.GetSanitizedTextInput(input); ValidateResult feedback = new ValidateResult(); feedback.IsValid = true; feedback.Feedback = null; feedback.FeedbackCard = null; feedback.Choices = null; FormPrompt prompt = null; FormPrompt feedbackPrompt = null; var iprompt = _field.Prompt; var fieldState = (FieldStepState)form.StepState; object response = null; if (fieldState.State == FieldStepStates.SentPrompt) { // Response to prompt var firstMatch = matches.FirstOrDefault(); if (matches.Count() == 1) { response = firstMatch.Value; if (_field.AllowsMultiple && response != null && (response.GetType() == typeof(string) || !response.GetType().IsIEnumerable())) { response = new List <object>() { response }; } feedback = await SetValueAsync(state, response, form); if (!feedback.IsValid && feedback.Choices != null) { var choices = new Ambiguous(inputText.Substring(firstMatch.Start, firstMatch.Length), feedback.Choices); fieldState.State = FieldStepStates.SentClarify; fieldState.Settled = new List <object>(); fieldState.Clarifications = new List <Ambiguous>() { choices }; response = SetValue(state, null); prompt = ClarifyPrompt((FieldStepState)form.StepState, iprompt.Recognizer, state); } } else if (matches.Count() > 1) { // Check multiple matches for ambiguity var groups = MatchAnalyzer.GroupedMatches(matches); // 1) Could be multiple match groups like for ingredients. // 2) Could be overlapping matches like "onion". // 3) Could be multiple matches where only one is expected. if (!_field.AllowsMultiple) { // Create a single group of all possibilities if only want one value var mergedGroup = groups.SelectMany((group) => group).ToList(); groups = new List <List <TermMatch> >() { mergedGroup }; } var ambiguous = new List <Ambiguous>(); var settled = new List <object>(); foreach (var choices in groups) { if (choices.Count > 1) { var unclearResponses = string.Join(" ", (from choice in choices select inputText.Substring(choice.Start, choice.Length)).Distinct()); var values = from match in choices select match.Value; ambiguous.Add(new Ambiguous(unclearResponses, values)); } else { var matchValue = choices.First().Value; if (matchValue != null && matchValue.GetType() != typeof(string) && matchValue.GetType().IsIEnumerable()) { foreach (var value in (System.Collections.IEnumerable)matchValue) { settled.Add(value); } } else { settled.Add(choices.First().Value); } } } if (settled.Count > 1) { // Remove no preference if present settled.Remove(null); } if (ambiguous.Count > 0) { // Need 1 or more clarifications fieldState.State = FieldStepStates.SentClarify; fieldState.Settled = settled; fieldState.Clarifications = ambiguous; response = SetValue(state, null); prompt = ClarifyPrompt((FieldStepState)form.StepState, iprompt.Recognizer, state); } else { if (_field.AllowsMultiple) { response = settled; feedback = await SetValueAsync(state, response, form); } else { Debug.Assert(settled.Count == 1); response = settled.First(); feedback = await SetValueAsync(state, response, form); } } } var unmatched = MatchAnalyzer.Unmatched(inputText, matches); var unmatchedWords = string.Join(" ", unmatched); var nonNoise = Language.NonNoiseWords(Language.WordBreak(unmatchedWords)).ToArray(); fieldState.Unmatched = null; if (_field.Prompt.Annotation.Feedback == FeedbackOptions.Always) { fieldState.Unmatched = string.Join(" ", nonNoise); } else if (_field.Prompt.Annotation.Feedback == FeedbackOptions.Auto && nonNoise.Any() && unmatched.Any()) { fieldState.Unmatched = string.Join(" ", nonNoise); } } else if (fieldState.State == FieldStepStates.SentClarify) { if (matches.Count() == 1) { // Clarified ambiguity var clarify = NeedsClarification(fieldState); fieldState.Settled.Add(matches.First().Value); fieldState.Clarifications.Remove(clarify); if (prompt == null) { // No clarification left, so set the field if (_field.AllowsMultiple) { response = fieldState.Settled; feedback = await SetValueAsync(state, response, form); } else { Debug.Assert(fieldState.Settled.Count == 1); response = fieldState.Settled.First(); feedback = await SetValueAsync(state, response, form); } form.SetPhase(StepPhase.Completed); } } } if (form.Phase() == StepPhase.Completed) { form.StepState = null; if (fieldState.Unmatched != null) { if (feedback.FeedbackCard != null) { feedbackPrompt = feedback.FeedbackCard; } else if (feedback.Feedback != null) { feedbackPrompt = new FormPrompt { Prompt = feedback.Feedback }; } else { if (fieldState.Unmatched != string.Empty) { feedbackPrompt = new Prompter <T>(_field.Template(TemplateUsage.Feedback), _field.Form, null).Prompt(state, _field, fieldState.Unmatched); } else { feedbackPrompt = new Prompter <T>(_field.Template(TemplateUsage.Feedback), _field.Form, null).Prompt(state, _field); } } } } var next = _field.Next(response, state); return(new StepResult(feedback.IsValid, next, feedbackPrompt ?? (feedback.FeedbackCard ?? new FormPrompt { Prompt = feedback.Feedback }), prompt)); }
private IEntity AmbiguousReference(SimpleTypeReference node, Ambiguous entity) { CompilerErrors().Add(CompilerErrorFactory.AmbiguousReference(node, node.Name, entity.Entities)); return(TypeSystemServices.ErrorEntity); }
private IPrompt <T> NextClarifyPrompt(T state, FieldStepState stepState, IRecognize <T> recognizer, out Ambiguous clarify) { IPrompt <T> prompter = null; clarify = null; foreach (var clarification in stepState.Clarifications) { if (clarification.Values.Length > 1) { clarify = clarification; break; } } if (clarify != null) { var field = new Field <T>("__clarify__", FieldRole.Value); field.Form = _field.Form; var template = _field.Template(TemplateUsage.Clarify); var helpTemplate = _field.Template(template.AllowNumbers ? TemplateUsage.EnumOneNumberHelp : TemplateUsage.EnumManyNumberHelp); field.SetPrompt(new PromptAttribute(template)); field.ReplaceTemplate(_field.Template(TemplateUsage.Clarify)); field.ReplaceTemplate(helpTemplate); foreach (var value in clarify.Values) { field.AddDescription(value, recognizer.ValueDescription(value)); field.AddTerms(value, recognizer.ValidInputs(value).ToArray()); } var choiceRecognizer = new RecognizeEnumeration <T>(field); prompter = new Prompter <T>(template, _field.Form, choiceRecognizer); } return(prompter); }
private IEntity MapAmbiguousEntity(Ambiguous source) { // Map each individual entity in the ambiguous list return new Ambiguous(Array.ConvertAll<IEntity, IEntity>(source.Entities, Map)); }