Example #1
0
        public static Annotation Create(string text, FilePosition filePosition)
        {
            if (string.IsNullOrWhiteSpace(text)) throw new ArgumentException("text is empty.");

            Match match = wordWithWhitespaceRegex.Match(text.Trim());
            string command = match.Groups["word"].Value;
            switch (command) {
                case "@name":
                    return new NameAnnotation(text, filePosition);
                case "@text":
                    return new TextAnnotation(text, filePosition);
                case "@const":
                    return new ConstantAnnotation(text, filePosition);
                case "@flag":
                    return new FlagAnnotation(text, filePosition);
                case "@attr":
                    return new AttributeAnnotation(text, filePosition);
                case "@in":
                    return new InParameterAnnotation(text, filePosition);
                case "@opt":
                    return new OptionalInParameterAnnotation(text, filePosition);
                case "@out":
                    return new OutParameterAnnotation(text, filePosition);
                case "@overload":
                    return new OverloadAnnotation(text, filePosition);
                default:
                    return new UnknownAnnotation(text, filePosition);
            }
        }
Example #2
0
        public void Parse(DirectoryInfo moaiSourceDirectory, PathFormat messagePathFormat)
        {
            // Check that the input directory looks like the Moai src directory
            if (!moaiSourceDirectory.GetDirectoryInfo("moai-core").Exists) {
                throw new ApplicationException(string.Format("Path '{0}' does not appear to be the 'src' directory of a Moai source copy.", moaiSourceDirectory));
            }

            // Initialize type list with primitive types
            typesByName = new Dictionary<string, MoaiType>();
            var primitiveTypeNames = new[] { "nil", "boolean", "number", "string", "userdata", "function", "thread", "table" };
            foreach (string primitiveTypeName in primitiveTypeNames) {
                typesByName[primitiveTypeName] = new MoaiType { Name = primitiveTypeName, IsPrimitive = true };
            }

            // Parse Moai types and store them by type name
            log.Info("Parsing Moai types.");
            ParseMoaiCodeFiles(moaiSourceDirectory, messagePathFormat);

            // MOAILuaObject is not documented, probably because it would mess up
            // the Doxygen-generated documentation. Use dummy code instead.
            log.Info("Adding hard-coded documentation for MoaiLuaObject base class.");
            FilePosition dummyFilePosition = new FilePosition(new FileInfo("MoaiLuaObject dummy code"), new DirectoryInfo("."), messagePathFormat);
            ParseMoaiFile(MoaiLuaObject.DummyCode, dummyFilePosition);

            // Make sure every class directly or indirectly inherits from MOAILuaObject
            MoaiType moaiLuaObjectType = GetOrCreateType("MOAILuaObject", null);
            foreach (MoaiType type in typesByName.Values) {
                if (!(type.AncestorTypes.Contains(moaiLuaObjectType)) && type != moaiLuaObjectType) {
                    type.BaseTypes.Add(moaiLuaObjectType);
                }
            }

            // Check if we have information on all referenced classes
            IEnumerable<MoaiType> typesReferencedInDocumentation = typesByName.Values
                .Where(type => type.DocumentationReferences.Any());
            foreach (MoaiType type in typesReferencedInDocumentation.ToArray()) {
                WarnIfSpeculative(type);
            }

            log.Info("Creating compact method signatures.");
            foreach (MoaiType type in typesByName.Values) {
                foreach (MoaiMethod method in type.Members.OfType<MoaiMethod>()) {
                    if (!method.Overloads.Any()) {
                        log.WarnFormat("No method documentation found. [{0}]", method.MethodPosition);
                        continue;
                    }

                    try {
                        method.InParameterSignature = GetCompactSignature(method.Overloads.Select(overload => overload.InParameters.ToArray()));
                        method.OutParameterSignature = GetCompactSignature(method.Overloads.Select(overload => overload.OutParameters.ToArray()));
                    } catch (Exception e) {
                        log.WarnFormat("Error determining method signature. {0} [{1}]", e.Message, method.MethodPosition);
                    }
                }
            }
        }
Example #3
0
        protected Annotation(string text, FilePosition filePosition)
        {
            if (string.IsNullOrWhiteSpace(text)) throw new ArgumentException("text is empty.");

            IEnumerable<Match> matches = wordWithWhitespaceRegex.Matches(text.Trim()).Cast<Match>();
            Elements = matches
                .Select(match => match.Groups["word"].Value)
                .ToArray();
            WhitespaceAfterElements = matches
                .Select(match => match.Groups["whitespace"].Value)
                .ToArray();

            FilePosition = filePosition;
        }
Example #4
0
 private MoaiType GetOrCreateType(string typeName, FilePosition documentationPosition)
 {
     MoaiType result = typesByName.ContainsKey(typeName)
         ? typesByName[typeName]
         : typesByName[typeName] = new MoaiType { Name = typeName };
     if (documentationPosition != null) {
         result.DocumentationReferences.Add(documentationPosition);
     }
     return result;
 }
Example #5
0
 public MethodPosition(FilePosition filePosition, string typeName, string nativeMethodName)
     : base(filePosition, typeName)
 {
     NativeMethodName = nativeMethodName;
 }
Example #6
0
 public TypePosition(FilePosition filePosition, string typeName)
     : base(filePosition.FileInfo, filePosition.RootDirectory, filePosition.MessagePathFormat)
 {
     TypeName = typeName;
 }
Example #7
0
 public UnknownAnnotation(string text, FilePosition filePosition)
     : base(text, filePosition)
 {
 }
Example #8
0
 public ConstantAnnotation(string text, FilePosition filePosition)
     : base(text, filePosition)
 {
 }
Example #9
0
        private void ParseMoaiFile(string code, FilePosition filePosition)
        {
            // Find all documentation blocks
            var matches = documentationRegex.Matches(code);

            // Parse documentation blocks
            foreach (Match match in matches) {
                // A documentation block may be attached to a type or to a method.
                string typeName = match.Groups["className"].Value;
                FilePosition documentationPosition = match.Groups["methodName"].Success
                    ? new MethodPosition(filePosition, typeName, match.Groups["methodName"].Value)
                    : new TypePosition(filePosition, typeName);

                // Parse annotations, filtering out unknown ones
                Annotation[] annotations = match.Groups["annotation"].Captures
                    .Cast<Capture>()
                    .Select(capture => Annotation.Create(capture.Value, documentationPosition))
                    .ToArray();
                foreach (var unknownAnnotation in annotations.OfType<UnknownAnnotation>()) {
                    log.WarnFormat("Unknown annotation command '{0}'. [{1}]", unknownAnnotation.Command, documentationPosition);
                }
                annotations = annotations
                    .Where(annotation => !(annotation is UnknownAnnotation))
                    .ToArray();

                // Parse annotation block
                MoaiType type = GetOrCreateType(typeName, documentationPosition);
                if (documentationPosition is MethodPosition) {
                    // The documentation was attached to a method definition
                    ParseMethodDocumentation(type, annotations, (MethodPosition) documentationPosition);
                } else {
                    // The documentation was attached to a type definition

                    // Get base type names, ignoring all template classes
                    MoaiType[] baseTypes = match.Groups["baseClassName"].Captures
                        .Cast<Capture>()
                        .Where(capture => !capture.Value.Contains("<"))
                        .Select(capture => GetOrCreateType(capture.Value, null))
                        .ToArray();

                    var typePosition = (TypePosition) documentationPosition;
                    type.TypePosition = typePosition;
                    ParseTypeDocumentation(type, annotations, baseTypes, typePosition);
                }
            }
        }
Example #10
0
 public OverloadAnnotation(string text, FilePosition filePosition)
     : base(text, filePosition)
 {
 }
Example #11
0
 public OutParameterAnnotation(string text, FilePosition filePosition)
     : base(text, filePosition)
 {
 }
Example #12
0
 public OptionalInParameterAnnotation(string text, FilePosition filePosition)
     : base(text, filePosition)
 {
     if (Name == null) {
         log.WarnFormat("{0} annotation with type '{1}' is missing its name (2nd word). [{2}]", Command, Type, filePosition);
     }
     // Let's not insist on a description for well-named parameters.
 }
Example #13
0
 public FlagAnnotation(string text, FilePosition filePosition)
     : base(text, filePosition)
 {
 }
Example #14
0
 protected FieldAnnotation(string text, FilePosition filePosition)
     : base(text, filePosition)
 {
     if (Name == null) {
         log.WarnFormat("{0} annotation is missing its name (1st word). [{1}]", Command, filePosition);
     }
     if (Description == null) {
         log.WarnFormat("{0} annotation '{1}' is missing its description (2nd word+). [{2}]", Command, Name, filePosition);
     }
 }
Example #15
0
 private void ParseMoaiCodeFile(FileInfo codeFile, FilePosition filePosition)
 {
     string code = File.ReadAllText(codeFile.FullName);
     ParseMoaiFile(code, filePosition);
 }
Example #16
0
        private void ParseMoaiCodeFiles(DirectoryInfo moaiSourceDirectory, PathFormat messagePathFormat)
        {
            IEnumerable<FileInfo> codeFiles = Directory
                .EnumerateFiles(moaiSourceDirectory.FullName, "*.*", SearchOption.AllDirectories)
                .Where(name => name.EndsWith(".cpp") || name.EndsWith(".h"))
                .Select(name => new FileInfo(name));

            foreach (var codeFile in codeFiles) {
                FilePosition filePosition = new FilePosition(codeFile, moaiSourceDirectory, messagePathFormat);
                ParseMoaiCodeFile(codeFile, filePosition);
            }
        }
Example #17
0
        protected ParameterAnnotation(string text, FilePosition filePosition)
            : base(text, filePosition)
        {
            if (Type == null) {
                log.WarnFormat("{0} annotation is missing its type (1st word). [{1}]", Command, filePosition);
            }
            // Not all parameter annotations require a type or name.
            // Let the derived classes decide.

            if (Description != null && WhitespaceAfterElements[2] == " ") {
                // There is only a single space before the description
                log.WarnFormat(
                    "{0} annotation has only a single space between its name ('{1}') and its description ('{2}'). This often indicates that the description is not self-contained. [{3}]",
                    Command, Name, Description.GetExcerpt(), filePosition);
            }
        }
Example #18
0
 public TextAnnotation(string text, FilePosition filePosition)
     : base(text, filePosition)
 {
     if (Value == null) {
         log.WarnFormat("{0} annotation is missing its value. [{1}]", Command, filePosition);
     }
 }
Example #19
0
 public AttributeAnnotation(string text, FilePosition filePosition)
     : base(text, filePosition)
 {
 }