public MethodNode(DeltinScriptParser.MethodContext context, BuildAstVisitor visitor) : base( new Location(visitor.file, DocRange.GetRange(context)), DocRange.GetRange(context.PART().Symbol), DocRange.GetRange(context.LEFT_PAREN().Symbol, context.RIGHT_PAREN().Symbol) ) { Name = context.PART().GetText(); if (context.call_parameters() != null) { Parameters = new Node[context.call_parameters().expr().Length]; for (int i = 0; i < Parameters.Length; i++) { Parameters[i] = visitor.Visit(context.call_parameters().expr()[i]); } } else if (context.picky_parameters() != null) { PickyParameters = new PickyParameter[context.picky_parameters().picky_parameter().Length]; for (int i = 0; i < PickyParameters.Length; i++) { PickyParameters[i] = new PickyParameter(context.picky_parameters().picky_parameter(i), visitor); } } else { Parameters = new Node[0]; } }
/// <summary>Determines if there are any missing parameters.</summary> public void GetMissingParameters(DocRange genericErrorRange, OverloadError messageHandler, DeltinScriptParser.Call_parametersContext context, DocRange functionCallRange) { for (int i = 0; i < OrderedParameters.Length; i++) { if (OrderedParameters[i]?.Value == null) { if (OrderedParameters[i] == null) { OrderedParameters[i] = new PickyParameter(true); } AddContextualParameter(context, functionCallRange, i); // Default value if (Option.Parameters[i].DefaultValue != null) { // Set the default value. OrderedParameters[i].Value = Option.Parameters[i].DefaultValue; } else { // Parameter is missing. Error(string.Format(messageHandler.MissingParameter, Option.Parameters[i].Name), genericErrorRange); } } } }
private PickyParameter[] ParametersFromContext(DeltinScriptParser.Call_parametersContext context) { // Return empty if context is null. if (context == null) { return(new PickyParameter[0]); } // Create the parameters array with the same length as the number of input parameters. PickyParameter[] parameters = new PickyParameter[context.call_parameter().Length]; for (int i = 0; i < parameters.Length; i++) { PickyParameter parameter = new PickyParameter(false); parameters[i] = parameter; // Get the picky name. // A is not picky, B is picky. // 'name' will be null depending on how the parameter is written. A is null, B is not null. // A: '5' // B: 'parameter: 5' parameter.Name = context.call_parameter(i).PART()?.GetText(); parameter.Picky = parameter.Name != null; if (parameter.Picky) { parameter.NameRange = DocRange.GetRange(context.call_parameter(i).PART()); // Get the name range if picky. } // If the expression context exists, set expression and expressionRange. if (context.call_parameter(i).expr() != null) { parameter.Value = parseInfo.GetExpression(getter, context.call_parameter(i).expr()); parameter.ExpressionRange = DocRange.GetRange(context.call_parameter(i).expr()); } else if (parameter.Picky) // TODO: remove condition so only 'else' remains if parameter-quick-skip is not implemented. // Throw a syntax error if picky. { parseInfo.Script.Diagnostics.Error("Expected expression.", DocRange.GetRange(context.call_parameter(i).TERNARY_ELSE())); } // Check if there are any duplicate names. if (parameter.Picky && parameters.Any(p => p != null && p.Picky && p != parameter && p.Name == parameter.Name)) { // If there are, syntax error parseInfo.Script.Diagnostics.Error($"The parameter {parameter.Name} was already set.", parameter.NameRange); } } return(parameters); }
public IWorkshopTree[] ParsePickyParameters(ScopeGroup getter, ScopeGroup scope, ParameterBase[] parameters, PickyParameter[] values, string methodName, LanguageServer.Location methodRange) { for (int f = 0; f < values.Length; f++) { // Syntax error if the parameter does not exist. if (!parameters.Any(param => param.Name.Replace(" ", "") == values[f].Name)) { throw new SyntaxErrorException(values[f].Name + " is not a parameter in the method " + methodName + ".", values[f].Location); } // Check if there are any duplicates. for (int n = 0; n < values.Length; n++) { if (f != n && values[f].Name == values[n].Name) { int use = Math.Max(f, n); throw new SyntaxErrorException(values[use].Name + " was already set.", values[use].Location); } } } // Parse the parameters List <IWorkshopTree> parsedParameters = new List <IWorkshopTree>(); for (int i = 0; i < parameters.Length; i++) { PickyParameter setter = values.FirstOrDefault(value => value.Name == parameters[i].Name.Replace(" ", "")); IWorkshopTree result; if (setter == null) { result = GetDefaultValue(parameters[i], methodName, methodRange); } else { result = parameters[i].Parse(this, getter, scope, setter.Expression); } parsedParameters.Add(result); } return(parsedParameters.ToArray()); }
private PickyParameter[] ParametersFromContext(List <ParameterValue> context) { // Return empty if context is null. if (context == null) { return(new PickyParameter[0]); } // Create the parameters array with the same length as the number of input parameters. PickyParameter[] parameters = new PickyParameter[context.Count]; for (int i = 0; i < parameters.Length; i++) { PickyParameter parameter = new PickyParameter(false); parameters[i] = parameter; if (parameter.Picky = context[i].PickyParameter != null) { // Get the picky name. parameter.Name = context[i].PickyParameter.Text; // Get the name range parameter.NameRange = context[i].PickyParameter.Range; // Check if there are any duplicate names. if (parameters.Any(p => p != null && p.Picky && p != parameter && p.Name == parameter.Name)) { // If there are, syntax error parseInfo.Script.Diagnostics.Error($"The parameter {parameter.Name} was already set.", parameter.NameRange); } } // Set expression and expressionRange. parameter.LambdaInfo = new ExpectingLambdaInfo(); parameter.Value = parseInfo.SetLambdaInfo(parameter.LambdaInfo).GetExpression(getter, context[i].Expression); parameter.ExpressionRange = context[i].Expression.Range; } return(parameters); }
private OverloadMatch MatchOverload(IParameterCallable option, PickyParameter[] inputParameters, DeltinScriptParser.Call_parametersContext context) { PickyParameter lastPicky = null; OverloadMatch match = new OverloadMatch(option); match.OrderedParameters = new PickyParameter[option.Parameters.Length]; // Iterate through the option's parameters. for (int i = 0; i < inputParameters.Length; i++) { if (inputParameters[i].ParameterOrdered(option.Parameters[i])) { // If the picky parameters end but there is an additional picky parameter, throw a syntax error. if (lastPicky != null && inputParameters[i].Name == null) { match.Error($"Named argument '{lastPicky.Name}' is used out-of-position but is followed by an unnamed argument", lastPicky.NameRange); } else { match.OrderedParameters[i] = inputParameters[i]; // Next contextual parameter if (i == inputParameters.Length - 1 && i < option.Parameters.Length - 1) { match.LastContextualParameterIndex = i + 1; } } } else { // Picky parameter ends. lastPicky = inputParameters[i]; // Set relevant picky parameter. bool nameFound = false; for (int p = 0; p < option.Parameters.Length && !nameFound; p++) { if (inputParameters[i].Name == option.Parameters[p].Name) { match.OrderedParameters[p] = inputParameters[i]; nameFound = true; } } // If the named argument's name is not found, throw an error. if (!nameFound) { match.Error($"Named argument '{lastPicky.Name}' does not exist in the function '{option.GetLabel(false)}'.", inputParameters[i].NameRange); } } } // Compare parameter types. for (int i = 0; i < match.OrderedParameters.Length; i++) { match.CompareParameterTypes(i); } // Get the missing parameters. match.GetMissingParameters(genericErrorRange, ErrorMessages, context, CallRange); return(match); }
public void SetContext(DeltinScriptParser.Picky_parametersContext context) { if (_setContext) { throw new Exception("Already set the context for the overload chooser."); } PickyContext = context; _setContext = true; PickyParameter[] parameters = new PickyParameter[context.picky_parameter().Length]; for (int i = 0; i < parameters.Length; i++) { string name = context.picky_parameter(i).PART().GetText(); IExpression expression = null; DocRange expressionRange = null; // Get the expression. If it doesn't exist, add a syntax error. if (context.picky_parameter(i).expr() != null) { expression = DeltinScript.GetExpression(parseInfo, getter, context.picky_parameter(i).expr()); expressionRange = DocRange.GetRange(context.picky_parameter(i).expr()); } else { parseInfo.Script.Diagnostics.Error("Expected expression.", DocRange.GetRange(context.picky_parameter(i).TERNARY_ELSE())); } var nameRange = DocRange.GetRange(context.picky_parameter(i).PART()); // Syntax error if the parameter was already set. if (parameters.Any(p => p != null && p.Name == name)) { parseInfo.Script.Diagnostics.Error($"The parameter {name} was already set.", nameRange); } else { // Add the parameter. parameters[i] = new PickyParameter( name, expression, DocRange.GetRange(context.picky_parameter(i)), nameRange, expressionRange ); } } if (!SetParameterCount(parameters.Length)) { return; } // Match by value types and parameter types. foreach (var parameter in parameters) { foreach (var option in CurrentOptions) { int index = -1; for (int i = 0; i < option.Parameters.Length; i++) { if (option.Parameters[i].Name == parameter.Name) { index = i; break; } } if (index == -1) { // Syntax error if the parameter does not exist. optionDiagnostics[option].Add(new Diagnostic( string.Format(ErrorMessages.ParameterDoesntExist, parameter.Name), parameter.NameRange, Diagnostic.Error )); } // parameter.Value is null if there is no expression. // A syntax error for this was already thrown earlier. else if (parameter.Value != null) { // Check the types. CompareParameterTypes(parameter.Value, option, index, parameter.ExpressionRange); } } } GetBestOption(); List <string> pickyParameterCompletion = Overload.Parameters.Select(p => p.Name).ToList(); ParameterRanges = new DocRange[Overload.Parameters.Length]; IExpression[] values = new IExpression[Overload.Parameters.Length]; for (int i = 0; i < values.Length; i++) { int parameterIndex = -1; for (int p = 0; p < parameters.Length && parameterIndex == -1; p++) { if (parameters[p].Name == Overload.Parameters[i].Name) { parameterIndex = p; pickyParameterCompletion.Remove(parameters[p].Name); } } if (parameterIndex != -1) { values[i] = parameters[parameterIndex].Value; ParameterRanges[i] = parameters[parameterIndex].FullRange; } else { values[i] = MissingParameter(Overload.Parameters[i]); } } Values = values; // Add the picky parameter completion. parseInfo.Script.AddCompletionRange(new CompletionRange(pickyParameterCompletion.Select(p => new CompletionItem() { Label = p + ":", Kind = CompletionItemKind.Field }).ToArray(), CallRange, CompletionRangeKind.Additive)); GetAdditionalData(); }