Inheritance: ISignatureInfo
 /// <summary>
 /// Constructs function signature based on function name and 
 /// the function definitions found in the AST.
 /// </summary>
 public static ISignatureInfo MakeSignature(this IFunctionDefinition fd, string functionName) {
     var si = new SignatureInfo(functionName);
     si.Arguments = new List<IArgumentInfo>();
     foreach (var arg in fd.Arguments) {
         var na = arg as NamedArgument;
         if (na != null) {
             string defaultValue = na.DefaultValue != null ? fd.Root.TextProvider.GetText(na.DefaultValue) : string.Empty;
             si.Arguments.Add(new ArgumentInfo(na.Name, string.Empty, defaultValue));
         } else {
             var ea = arg as ExpressionArgument;
             if (ea != null && ea.Children.Count > 0) {
                 var exp = ea.Children[0] as IExpression;
                 if (exp != null && exp.Children.Count > 0) {
                     var v = exp.Children[0] as Variable;
                     if (v != null) {
                         si.Arguments.Add(new ArgumentInfo(v.Name));
                     }
                 }
             }
         }
     }
     return si;
 }
        private static ISignatureInfo ParseSignature(string functionName, ParseContext context, IReadOnlyDictionary<string, string> argumentsDescriptions = null) {
            SignatureInfo info = new SignatureInfo(functionName);
            List<IArgumentInfo> signatureArguments = new List<IArgumentInfo>();

            // RD data may contain function name(s) without braces
            if (context.Tokens.CurrentToken.TokenType == RTokenType.OpenBrace) {
                FunctionCall functionCall = new FunctionCall();
                functionCall.Parse(context, context.AstRoot);

                for (int i = 0; i < functionCall.Arguments.Count; i++) {
                    IAstNode arg = functionCall.Arguments[i];

                    string argName = null;
                    string argDefaultValue = null;
                    bool isEllipsis = false;
                    bool isOptional = false;

                    ExpressionArgument expArg = arg as ExpressionArgument;
                    if (expArg != null) {
                        argName = context.TextProvider.GetText(expArg.ArgumentValue);
                    } else {
                        NamedArgument nameArg = arg as NamedArgument;
                        if (nameArg != null) {
                            argName = context.TextProvider.GetText(nameArg.NameRange);
                            argDefaultValue = RdText.CleanRawRdText(context.TextProvider.GetText(nameArg.DefaultValue));
                        } else {
                            MissingArgument missingArg = arg as MissingArgument;
                            if (missingArg != null) {
                                argName = string.Empty;
                            } else {
                                EllipsisArgument ellipsisArg = arg as EllipsisArgument;
                                if (ellipsisArg != null) {
                                    argName = "...";
                                    isEllipsis = true;
                                }
                            }
                        }
                    }

                    ArgumentInfo argInfo = new ArgumentInfo(argName);
                    argInfo.DefaultValue = argDefaultValue;
                    argInfo.IsEllipsis = isEllipsis;
                    argInfo.IsOptional = isOptional; // TODO: actually parse

                    if (argumentsDescriptions != null) {
                        string description;
                        if (argumentsDescriptions.TryGetValue(argName, out description)) {
                            argInfo.Description = description;
                        }
                    }
                    signatureArguments.Add(argInfo);
                }
            }

            info.Arguments = signatureArguments;
            return info;
        }