/// <summary>
        /// Tries to parse method definition line.
        /// </summary>
        /// <param name="reader"><see cref="SourceCodeReader"/></param>
        /// <param name="info">[out] Parsed <see cref="MethodInfo"/> (only succeeded in parsing)</param>
        /// <param name="depth">[out] Depth of method definition line (only succeeded in parsing)</param>
        /// <returns>Whether succeeded in parsing or not</returns>
        private bool TryParseDefinitionLine(SourceCodeReader reader, out MethodInfo info, out int depth)
        {
            if (!reader.TryRead(out var text))
            {
                info  = null;
                depth = 0;
                return(false);
            }

            depth = text.Depth;
            var match = MethodRegex.Match(text.Text);

            if (!match.Success)
            {
                reader.Position--;
                info  = null;
                depth = 0;
                return(false);
            }

            var mod        = this.ParseModifiers(match.Groups[1].Value);
            var returnType = string.IsNullOrEmpty(match.Groups[2].Value) ? null : ParseType(match.Groups[2].Value);
            var name       = match.Groups[3].Value;
            var args       = ParseArguments(match.Groups[4].Value);

            info = new MethodInfo(mod, name, returnType, args);

            return(true);
        }
示例#2
0
        public IEnumerable <ClassInfo> Parse(string code)
        {
            if (code == null)
            {
                throw new ArgumentNullException();
            }

            var reader      = new SourceCodeReader(code);
            var classList   = new List <ClassInfo>();
            var classParser = new ClassParser(string.Empty, Modifier.Package);

            while (!reader.IsEndOfLines)
            {
                if (TryParsePackage(reader, out var package))
                {
                    classParser = new ClassParser(package, Modifier.Package);
                    continue;
                }

                if (classParser.TryParse(reader, out var classInfo))
                {
                    classList.Add(classInfo);
                    continue;
                }

                reader.TryRead(out var _);
            }

            return(classList);
        }
示例#3
0
        /// <summary>
        /// Tries to parse class definition line.
        /// </summary>
        /// <param name="reader"><see cref="SourceCodeReader"/></param>
        /// <param name="parentClassName">Parent class name added to a parsed class</param>
        /// <param name="classInfo">[out] Parsed <see cref="ClassInfo"/> (only succeeded in parsing)</param>
        /// <param name="depth">[out] Depth of class definition line (only succeeded in parsing)</param>
        /// <returns>Whether succeeded in parsing or not</returns>
        private bool TryParseDefinitionLine(SourceCodeReader reader, string parentClassName, out ClassInfo classInfo, out int depth)
        {
            if (!reader.TryRead(out var text))
            {
                classInfo = null;
                depth     = 0;
                return(false);
            }

            depth = text.Depth;
            var match = ClassRegex.Match(text.Text);

            if (!match.Success)
            {
                reader.Position--;
                classInfo = null;
                depth     = 0;
                return(false);
            }

            var parentName = string.IsNullOrEmpty(parentClassName) ? string.Empty : parentClassName + ".";
            var mod        = this.ParseModifiers(match.Groups[1].Value);
            var category   = ParseClassCategory(match.Groups[2].Value);
            var type       = ParseType(parentName + match.Groups[3].Value);
            var inheriteds = ParseInheritance(match.Groups[4].Value);

            classInfo = new ClassInfo(mod, category, this.package, type, inheriteds);

            return(true);
        }
示例#4
0
        public override bool TryParse(SourceCodeReader reader, out FieldInfo info)
        {
            if (!reader.TryRead(out var text))
            {
                info = null;
                return(false);
            }

            var depth = text.Depth;
            var match = FieldRegex.Match(text.Text);

            if (!match.Success)
            {
                reader.Position--;
                info = null;
                return(false);
            }

            var idxrArgs = match.Groups[4].Value;
            var mod      = this.ParseModifiers(match.Groups[1].Value);
            var type     = string.IsNullOrWhiteSpace(match.Groups[2].Value) ? null : ParseType(match.Groups[2].Value);
            var name     = match.Groups[3].Value;
            var args     = ParseArguments(Regex.Replace(idxrArgs, "(\\s*\\[\\s*|\\s*\\]\\s*)", string.Empty));

            // Parsing must be treated as failure if parsed type name matches modifier,
            // because field regex pattern matches invalid pattern below.
            // ex) "public int" -> Type : public, FiledName : int
            if (AllModifiers.Contains(type.Name))
            {
                reader.Position--;
                info = null;
                return(false);
            }

            this.ParseImplementationLines(reader, depth, out var propTypeFromImpl);
            var propType   = PropertyType.None;
            var isIndexer  = !string.IsNullOrEmpty(idxrArgs);
            var hasGetter  = !string.IsNullOrEmpty(match.Groups[5].Value);
            var hasDefault = !string.IsNullOrEmpty(match.Groups[6].Value);

            if (isIndexer)
            {
                propType |= PropertyType.Indexer;
            }
            if (hasGetter)
            {
                propType |= PropertyType.Get;
            }
            if (!hasDefault)
            {
                // If definition line contains a default value assignment expression, this field is not a property.
                // If this field is a property, adds a flag parsed from implementation lines.
                propType |= propTypeFromImpl;
            }

            info = new FieldInfo(mod, name, type, propType, args);
            return(true);
        }
示例#5
0
        /// <summary>
        /// Tries to parsing a class.
        /// </summary>
        /// <param name="reader"><see cref="SourceCodeReader"/></param>
        /// <param name="parentClassName">Parent class name added to a parsed class</param>
        /// <param name="info">[out] Parsed class (only succeeded in parsing)</param>
        /// <returns>Whether succeeded in parsing or not</returns>
        public bool TryParseInternal(SourceCodeReader reader, string parentClassName, out ClassInfo info)
        {
            if (!this.TryParseDefinitionLine(reader, parentClassName, out info, out var depth))
            {
                return(false);
            }

            this.ParseImplementationLines(reader, info, info.Name, depth);
            return(true);
        }
        public override bool TryParse(SourceCodeReader reader, out MethodInfo info)
        {
            if (!this.TryParseDefinitionLine(reader, out info, out var depth))
            {
                return(false);
            }

            this.ParseImplementationLines(reader, info, depth);
            return(true);
        }
示例#7
0
        /// <summary>
        /// Checks whether the depth of next line of <see cref="SourceCodeReader"/> is <paramref name="depth"/> or not.
        /// <para>If failed to read, returns false.</para>
        /// <para>This processing does not change position of <see cref="SourceCodeReader"/>.</para>
        /// </summary>
        /// <param name="reader"><see cref="SourceCodeReader"/> to be checked.</param>
        /// <param name="depth">Expected depth</param>
        /// <returns>Whether the depth of next line is <paramref name="depth"/> or not</returns>
        private static bool IsNextLineDepth(SourceCodeReader reader, int depth)
        {
            if (!reader.TryRead(out var text))
            {
                return(false);
            }

            reader.Position--;

            return(text.Depth == depth);
        }
        /// <summary>
        /// Parses implementation lines.
        /// </summary>
        /// <param name="reader"><see cref="SourceCodeReader"/></param>
        /// <param name="info"><see cref="MethodInfo"/> to hold implementation contents</param>
        /// <param name="definitionDepth">Depth of method definition line</param>
        private void ParseImplementationLines(SourceCodeReader reader, MethodInfo info, int definitionDepth)
        {
            var subLines = GetMoreDeepLineCount(reader, definitionDepth);

            for (var i = 0; i < subLines; i++)
            {
                reader.TryRead(out var sub);

                // Skip implementation lines
                // TODO Gets used types in implementation lines
            }
        }
示例#9
0
        /// <summary>
        /// Parses implementation lines.
        /// </summary>
        /// <param name="reader"><see cref="SourceCodeReader"/></param>
        /// <param name="classInfo"><see cref="ClassInfo"/> to hold implementation contents</param>
        /// <param name="parentClassName">Parent class name added to a parsed class</param>
        /// <param name="definitionDepth">Depth of class definition line</param>
        private void ParseImplementationLines(SourceCodeReader reader, ClassInfo classInfo, string parentClassName, int definitionDepth)
        {
            var endOfClass   = reader.Position + GetMoreDeepLineCount(reader, definitionDepth);
            var methodParser = new MethodParser(classInfo, this.DefaultAccessLevel);
            var fieldParser  = new FieldParser(classInfo, this.DefaultAccessLevel);
            var enumParser   = new EnumValuesParser(classInfo, definitionDepth);
            var isFirstLine  = true;

            while (reader.Position < endOfClass)
            {
                if (!IsNextLineDepth(reader, definitionDepth + 1))
                {
                    reader.TryRead(out var _);
                    continue;
                }

                if (isFirstLine && (classInfo.Category == ClassCategory.Enum) && enumParser.TryParse(reader, out var valuesFL))
                {
                    // Parsing enum values of first line is only executed at first
                    classInfo.Fields.AddRange(valuesFL);
                }
                else if (this.TryParseInternal(reader, parentClassName, out var innerInfo))
                {
                    classInfo.InnerClasses.Add(innerInfo);
                }
                else if (methodParser.TryParse(reader, out var methodInfo))
                {
                    classInfo.Methods.Add(methodInfo);
                }
                else if (fieldParser.TryParse(reader, out var fieldInfo))
                {
                    // Parsing filed is executed after trying to parse method because field pattern also matches method
                    classInfo.Fields.Add(fieldInfo);
                }
                else if (!isFirstLine && (classInfo.Category == ClassCategory.Enum) && enumParser.TryParse(reader, out var values))
                {
                    // Parsing enum values is executed after trying to parse method and field just as with field parsing (except for first line)
                    classInfo.Fields.AddRange(values);
                }
                else
                {
                    // Skip a line if it did not match any pattern
                    reader.TryRead(out var _);
                }

                isFirstLine = false;
            }
        }
示例#10
0
        /// <summary>
        /// Gets a line count from current position of <paramref name="reader"/> to end of line that has more deep <paramref name="depth"/> continuously.
        /// <para>The position of <paramref name="reader"/> after this processing is the same as that of before this processing.</para>
        /// </summary>
        /// <param name="reader">Reader</param>
        /// <param name="depth">Depth threshold (excluding self)</param>
        /// <returns>A line count coutinuous more deep lines</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="reader"/> is null</exception>
        protected static int GetMoreDeepLineCount(SourceCodeReader reader, int depth)
        {
            if (reader == null)
            {
                throw new ArgumentNullException();
            }

            var start     = reader.Position;
            var deepLines = 0;

            while (reader.TryRead(out var t) && (t.Depth > depth))
            {
                deepLines++;
            }

            reader.Position = start;
            return(deepLines);
        }
示例#11
0
        /// <summary>
        /// Tries to parse a package.
        /// <para>If failed to parse, the position of <paramref name="reader"/> after this processing is the same as that of before this processing.</para>
        /// </summary>
        /// <param name="reader"><see cref="SourceCodeReader"/></param>
        /// <param name="package">[out] Package name (only succeeded in parsing)</param>
        /// <returns>Whether succeeded in parsing or not</returns>
        private static bool TryParsePackage(SourceCodeReader reader, out string package)
        {
            if (!reader.TryRead(out var text))
            {
                package = null;
                return(false);
            }

            var match = PackageRegex.Match(text.Text);

            if (!match.Success)
            {
                reader.Position--;
                package = null;
                return(false);
            }

            package = match.Groups[1].Value;
            return(true);
        }
        public IEnumerable <ClassInfo> Parse(string code)
        {
            if (code == null)
            {
                throw new ArgumentNullException();
            }

            var reader      = new SourceCodeReader(code);
            var classList   = new List <ClassInfo>();
            var classParser = new ClassParser(string.Empty, Modifier.Internal);
            var prevNS      = new Dictionary <int, string>();

            while (!reader.IsEndOfLines)
            {
                if (TryParseNameSpace(reader, out var nameSpace, out var depth))
                {
                    // Already existed parent namespace, Add it before a nameSpace
                    if (prevNS.ContainsKey(depth - 1))
                    {
                        nameSpace = prevNS[depth - 1] + "." + nameSpace;
                    }

                    prevNS[depth] = nameSpace;
                    classParser   = new ClassParser(nameSpace, Modifier.Internal);
                    continue;
                }

                if (classParser.TryParse(reader, out var classInfo))
                {
                    classList.Add(classInfo);
                    continue;
                }

                reader.TryRead(out var _);
            }

            return(classList);
        }
示例#13
0
        public override bool TryParse(SourceCodeReader reader, out IEnumerable <FieldInfo> values)
        {
            if (!reader.TryRead(out var text))
            {
                values = null;
                return(false);
            }

            if (text.Depth != this.definitionDepth + 1)
            {
                reader.Position--;
                values = null;
                return(false);
            }

            values = text.Text.Split(',')
                     .Select(s => EnumValueRegex.Match(s))
                     .Where(m => m.Success)
                     .Select(m => m.Groups[1].Value)
                     .Select(this.CreateFieldFromValueName);

            return(true);
        }
        /// <summary>
        /// Tries to parse a namespace.
        /// <para>If failed to parse, the position of <paramref name="reader"/> after this processing is the same as that of before this processing.</para>
        /// </summary>
        /// <param name="reader"><see cref="SourceCodeReader"/></param>
        /// <param name="nameSpace">[out] Namespace (only succeeded in parsing)</param>
        /// <param name="depth">[out] Depth of namespace (only succeeded in parsing)</param>
        /// <returns>Whether succeeded in parsing or not</returns>
        private static bool TryParseNameSpace(SourceCodeReader reader, out string nameSpace, out int depth)
        {
            if (!reader.TryRead(out var text))
            {
                nameSpace = null;
                depth     = 0;
                return(false);
            }

            var match = NameSpaceRegex.Match(text.Text);

            if (!match.Success)
            {
                reader.Position--;
                nameSpace = null;
                depth     = 0;
                return(false);
            }

            nameSpace = match.Groups[1].Value;
            depth     = text.Depth;
            return(true);
        }
示例#15
0
        /// <summary>
        /// Parses implementation lines.
        /// <para>If declarations of getter or setter appears, adds <see cref="PropertyType"/> to <paramref name="propType"/>.</para>
        /// </summary>
        /// <param name="reader"><see cref="SourceCodeReader"/></param>
        /// <param name="definitionDepth">Depth of field definition line</param>
        /// <param name="propType"><see cref="PropertyType"/> to be added getter or setter flags</param>
        private void ParseImplementationLines(SourceCodeReader reader, int definitionDepth, out PropertyType propType)
        {
            var subLines = GetMoreDeepLineCount(reader, definitionDepth);

            propType = PropertyType.None;

            // Skips all implementation lines, and checks getter or setter declarations.
            for (var i = 0; i < subLines; i++)
            {
                if (!reader.TryRead(out var sub) || sub.Depth != definitionDepth + 1)
                {
                    continue;
                }

                if (GetterRegex.IsMatch(sub.Text))
                {
                    propType |= PropertyType.Get;
                }
                if (SetterRegex.IsMatch(sub.Text))
                {
                    propType |= PropertyType.Set;
                }
            }
        }
示例#16
0
 /// <summary>
 /// Tries to parse component of source code.
 /// <para>Tries read a line from <paramref name="reader"/>, and if succeeded in parsing, output parsed component.</para>
 /// <para>If succeeded in parsing, the position of the <paramref name="reader"/> is seeked by the number of the read lines.
 /// Otherwise, the position of <paramref name="reader"/> is not changed.</para>
 /// </summary>
 /// <param name="reader"><see cref="SourceCodeReader"/></param>
 /// <param name="obj">[out] Parsed component (only succeeded in parsing)</param>
 /// <returns>Whether succeeded in parsing or not</returns>
 public abstract bool TryParse(SourceCodeReader reader, out T obj);
示例#17
0
 public override bool TryParse(SourceCodeReader reader, out ClassInfo info)
 {
     return(this.TryParseInternal(reader, string.Empty, out info));
 }