Browse Source

LuatOS doc gen 关键方法通过 JUnit

Peter Zhang 5 năm trước cách đây
mục cha
commit
a365151f08
40 tập tin đã thay đổi với 1328 bổ sung0 xóa
  1. 4 0
      .gitignore
  2. 56 0
      tools/java/pom.xml
  3. 25 0
      tools/java/src/main/java/org/luatos/toolkit/LuatDocEntry.java
  4. 22 0
      tools/java/src/main/java/org/luatos/toolkit/LuatDocGenerator.java
  5. 35 0
      tools/java/src/main/java/org/luatos/toolkit/LuatDocSetup.java
  6. 45 0
      tools/java/src/main/java/org/luatos/toolkit/Luats.java
  7. 9 0
      tools/java/src/main/java/org/luatos/toolkit/api/FnSignGenerating.java
  8. 76 0
      tools/java/src/main/java/org/luatos/toolkit/bean/FnExample.java
  9. 7 0
      tools/java/src/main/java/org/luatos/toolkit/bean/FnModifier.java
  10. 72 0
      tools/java/src/main/java/org/luatos/toolkit/bean/FnParam.java
  11. 176 0
      tools/java/src/main/java/org/luatos/toolkit/bean/FnSign.java
  12. 7 0
      tools/java/src/main/java/org/luatos/toolkit/bean/LuCommentType.java
  13. 135 0
      tools/java/src/main/java/org/luatos/toolkit/bean/LuDocComment.java
  14. 45 0
      tools/java/src/main/java/org/luatos/toolkit/bean/LuatDocHeader.java
  15. 33 0
      tools/java/src/main/java/org/luatos/toolkit/bean/LuatDocSet.java
  16. 45 0
      tools/java/src/main/java/org/luatos/toolkit/bean/LuatDocument.java
  17. 77 0
      tools/java/src/main/java/org/luatos/toolkit/impl/CFnSignGenerating.java
  18. 167 0
      tools/java/src/main/java/org/luatos/toolkit/impl/LuaDocFnSignGenerating.java
  19. 8 0
      tools/java/src/main/resources/doc-gen.json
  20. 10 0
      tools/java/src/test/java/org/luatos/toolkit/LuatTookietTestAll.java
  21. 69 0
      tools/java/src/test/java/org/luatos/toolkit/bean/FnSignTest.java
  22. 50 0
      tools/java/src/test/java/org/luatos/toolkit/bean/LuDocCommentTest.java
  23. 12 0
      tools/java/src/test/resources/expec/c_sign_fn_0.json
  24. 11 0
      tools/java/src/test/resources/expec/c_sign_fn_1.json
  25. 17 0
      tools/java/src/test/resources/expec/c_sign_fn_2.json
  26. 3 0
      tools/java/src/test/resources/expec/cmt_c_multi_0.txt
  27. 4 0
      tools/java/src/test/resources/expec/cmt_c_multi_1.txt
  28. 4 0
      tools/java/src/test/resources/expec/cmt_c_single_0.txt
  29. 9 0
      tools/java/src/test/resources/expec/cmt_lua_0.txt
  30. 21 0
      tools/java/src/test/resources/expec/lua_cmt_fn_0.json
  31. 27 0
      tools/java/src/test/resources/expec/lua_cmt_fn_1.json
  32. 1 0
      tools/java/src/test/resources/input/c_sign_fn_0.txt
  33. 1 0
      tools/java/src/test/resources/input/c_sign_fn_1.txt
  34. 1 0
      tools/java/src/test/resources/input/c_sign_fn_2.txt
  35. 4 0
      tools/java/src/test/resources/input/cmt_c_multi_0.txt
  36. 6 0
      tools/java/src/test/resources/input/cmt_c_multi_1.txt
  37. 4 0
      tools/java/src/test/resources/input/cmt_c_single_0.txt
  38. 11 0
      tools/java/src/test/resources/input/cmt_lua_0.txt
  39. 9 0
      tools/java/src/test/resources/input/lua_cmt_fn_0.txt
  40. 10 0
      tools/java/src/test/resources/input/lua_cmt_fn_1.txt

+ 4 - 0
.gitignore

@@ -60,3 +60,7 @@ bsp/air302/FlashToolCLI/
 bsp/air302/tmp/
 bsp/air302/local*
 *.zip
+tools/java/.classpath
+tools/java/.project
+tools/java/.settings/
+tools/java/target/

+ 56 - 0
tools/java/pom.xml

@@ -0,0 +1,56 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.nutz</groupId>
+  <artifactId>luatos</artifactId>
+  <version>1.r.68-SNAPSHOT</version>
+  <name>LuatOSTool</name>
+  <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <elasticsearch.version>6.3.2</elasticsearch.version>
+    </properties>
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://apache.org/licenses/LICENSE-2.0.txt</url>
+        </license>
+    </licenses>
+    <developers>
+        <developer>
+            <id>zozoh</id>
+            <name>zozoh</name>
+            <email>zozohtnt@gmail.com</email>
+            <url>http://weibo.com/zozoh</url>
+        </developer>
+        <developer>
+            <id>wendal</id>
+            <name>Wendal Chen</name>
+            <email>wendal1985@gmail.com</email>
+            <url>http://wendal.net/</url>
+        </developer>
+    </developers>
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.12</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.17</version>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>3.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.nutz</groupId>
+            <artifactId>nutz</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+     </dependencies>
+</project>

+ 25 - 0
tools/java/src/main/java/org/luatos/toolkit/LuatDocEntry.java

@@ -0,0 +1,25 @@
+package org.luatos.toolkit;
+
+public class LuatDocEntry {
+
+    private String path;
+
+    private String[] suffixes;
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public String[] getSuffixes() {
+        return suffixes;
+    }
+
+    public void setSuffixes(String[] suffixes) {
+        this.suffixes = suffixes;
+    }
+
+}

+ 22 - 0
tools/java/src/main/java/org/luatos/toolkit/LuatDocGenerator.java

@@ -0,0 +1,22 @@
+package org.luatos.toolkit;
+
+public class LuatDocGenerator {
+    
+    
+    public LuatDocGenerator(LuatDocEntry entry) {
+        
+    }
+
+    public static void main(String[] args) {
+        
+        // 读取配置文件
+        
+        
+        // 递归每个入口
+        
+        
+        // 全部搞定
+        
+    }
+
+}

+ 35 - 0
tools/java/src/main/java/org/luatos/toolkit/LuatDocSetup.java

@@ -0,0 +1,35 @@
+package org.luatos.toolkit;
+
+public class LuatDocSetup {
+
+    private String workdir;
+
+    private LuatDocEntry[] entries;
+
+    private String output;
+
+    public String getWorkdir() {
+        return workdir;
+    }
+
+    public void setWorkdir(String workdir) {
+        this.workdir = workdir;
+    }
+
+    public LuatDocEntry[] getEntries() {
+        return entries;
+    }
+
+    public void setEntries(LuatDocEntry[] entries) {
+        this.entries = entries;
+    }
+
+    public String getOutput() {
+        return output;
+    }
+
+    public void setOutput(String output) {
+        this.output = output;
+    }
+
+}

+ 45 - 0
tools/java/src/main/java/org/luatos/toolkit/Luats.java

@@ -0,0 +1,45 @@
+package org.luatos.toolkit;
+
+import java.util.Iterator;
+import java.util.List;
+
+public abstract class Luats {
+
+    public static boolean isSame(Object o1, Object o2) {
+        if (null != o1) {
+            if (!o1.equals(o2)) {
+                return false;
+            }
+        } else if (null != o2) {
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean isSameList(List<?> l1, List<?> l2) {
+        if (null != l1) {
+            if (null == l2)
+                return false;
+
+            if (l1.size() != l2.size())
+                return false;
+
+            Iterator<?> it1 = l1.iterator();
+            Iterator<?> it2 = l2.iterator();
+
+            while (it1.hasNext()) {
+                Object o1 = it1.next();
+                Object o2 = it2.next();
+                if (!isSame(o1, o2)) {
+                    return false;
+                }
+                return true;
+            }
+
+        } else if (null != l2) {
+            return false;
+        }
+        return true;
+    }
+
+}

+ 9 - 0
tools/java/src/main/java/org/luatos/toolkit/api/FnSignGenerating.java

@@ -0,0 +1,9 @@
+package org.luatos.toolkit.api;
+
+import org.luatos.toolkit.bean.FnSign;
+
+public interface FnSignGenerating {
+
+    FnSign gen(String block);
+
+}

+ 76 - 0
tools/java/src/main/java/org/luatos/toolkit/bean/FnExample.java

@@ -0,0 +1,76 @@
+package org.luatos.toolkit.bean;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.luatos.toolkit.Luats;
+import org.nutz.lang.Strings;
+
+public class FnExample {
+
+    private List<String> summary;
+
+    private List<String> code;
+
+    public boolean hasSummary() {
+        return null != summary && !summary.isEmpty();
+    }
+
+    public List<String> getSummary() {
+        return summary;
+    }
+
+    public void setSummary(List<String> summary) {
+        this.summary = summary;
+    }
+
+    public void appendSummary(String summary) {
+        if (null == this.summary) {
+            this.summary = new LinkedList<>();
+        }
+        this.summary.add(summary);
+    }
+
+    public boolean hasCode() {
+        return null != code && !code.isEmpty();
+    }
+
+    public List<String> getCode() {
+        return code;
+    }
+
+    public void setCode(List<String> code) {
+        this.code = code;
+    }
+
+    public void appendCode(String code) {
+        if (null == this.code) {
+            this.code = new LinkedList<>();
+        }
+        this.code.add(code);
+    }
+
+    public String toString() {
+        String str = "";
+        if (this.hasSummary()) {
+            str += Strings.join("\n--", this.summary) + "\n";
+        }
+        str += Strings.join("\n", code);
+        return str;
+    }
+
+    public boolean equals(Object o) {
+        if (o instanceof FnExample) {
+            FnExample fe = (FnExample) o;
+            if (!Luats.isSameList(this.summary, fe.summary))
+                return false;
+
+            if (!Luats.isSameList(this.code, fe.code))
+                return false;
+
+            return true;
+        }
+        return false;
+    }
+
+}

+ 7 - 0
tools/java/src/main/java/org/luatos/toolkit/bean/FnModifier.java

@@ -0,0 +1,7 @@
+package org.luatos.toolkit.bean;
+
+public enum FnModifier {
+
+    STATIC,  LOCAL
+    
+}

+ 72 - 0
tools/java/src/main/java/org/luatos/toolkit/bean/FnParam.java

@@ -0,0 +1,72 @@
+package org.luatos.toolkit.bean;
+
+import org.luatos.toolkit.Luats;
+import org.nutz.lang.Strings;
+
+public class FnParam {
+
+    private String type;
+
+    private String name;
+
+    private String comment;
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        if (Strings.isBlank(name)) {
+            this.name = null;
+        } else {
+            this.name = name;
+        }
+    }
+
+    public String getComment() {
+        return comment;
+    }
+
+    public void setComment(String comment) {
+        this.comment = comment;
+    }
+
+    public String toString() {
+        String str = type;
+        if (str.endsWith(" *")) {
+            str += name;
+        } else {
+            str += " " + name;
+        }
+        if (!Strings.isBlank(comment)) {
+            str += "/* " + comment + " */";
+        }
+        return str;
+    }
+
+    public boolean equals(Object o) {
+        if (o instanceof FnParam) {
+            FnParam fp = (FnParam) o;
+            if (!Luats.isSame(this.type, fp.type))
+                return false;
+
+            if (!Luats.isSame(this.name, fp.name))
+                return false;
+
+            if (!Luats.isSame(this.comment, fp.comment))
+                return false;
+
+            return true;
+        }
+        return false;
+    }
+
+}

+ 176 - 0
tools/java/src/main/java/org/luatos/toolkit/bean/FnSign.java

@@ -0,0 +1,176 @@
+package org.luatos.toolkit.bean;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.luatos.toolkit.Luats;
+import org.nutz.lang.Strings;
+
+public class FnSign {
+
+    /**
+     * 原始的输入
+     */
+    private String rawText;
+
+    private String summary;
+
+    private FnModifier modifier;
+
+    private String returnType;
+
+    private String returnComment;
+
+    private String name;
+
+    private List<FnParam> params;
+
+    private List<FnExample> examples;
+
+    public String toString() {
+        String str = "";
+        if (!Strings.isBlank(rawText)) {
+            str += rawText + "\n-----------------------------\n";
+        }
+        if (null != summary) {
+            str += "/*\n" + summary + "\n*/\n";
+        }
+        if (null != modifier) {
+            str += this.modifier.toString().toLowerCase() + " ";
+        }
+        String pmStr = "";
+        if (null != params) {
+            List<String> pms = new ArrayList<>(params.size());
+            for (FnParam pm : params) {
+                pms.add(pm.toString());
+            }
+            pmStr = Strings.join(", ", pms);
+        }
+        str += String.format("%s %s(%s)", returnType, name, pmStr);
+
+        return str;
+    }
+
+    public boolean equals(Object o) {
+        if (o instanceof FnSign) {
+            FnSign fn = (FnSign) o;
+            return isSame(fn, true);
+        }
+        return false;
+    }
+
+    public boolean isSame(FnSign fn, boolean ignoreRawText) {
+        if (!ignoreRawText) {
+            if (!Luats.isSame(this.rawText, fn.rawText)) {
+                return false;
+            }
+        }
+        if (!Luats.isSame(this.modifier, fn.modifier))
+            return false;
+
+        if (!Luats.isSame(this.returnType, fn.returnType))
+            return false;
+
+        if (!Luats.isSame(this.returnComment, fn.returnComment))
+            return false;
+
+        if (!Luats.isSame(this.name, fn.name))
+            return false;
+
+        if (!Luats.isSameList(this.params, fn.params))
+            return false;
+
+        if (!Luats.isSameList(this.examples, fn.examples))
+            return false;
+
+        return true;
+    }
+
+    public String getRawText() {
+        return rawText;
+    }
+
+    public void setRawText(String rawText) {
+        this.rawText = rawText;
+    }
+
+    public String getSummary() {
+        return summary;
+    }
+
+    public void setSummary(String comment) {
+        this.summary = comment;
+    }
+
+    public boolean isLocal() {
+        return FnModifier.LOCAL == this.modifier;
+    }
+
+    public boolean isStatic() {
+        return FnModifier.STATIC == this.modifier;
+    }
+
+    public FnModifier getModifier() {
+        return modifier;
+    }
+
+    public void setModifier(FnModifier modifier) {
+        this.modifier = modifier;
+    }
+
+    public String getReturnType() {
+        return returnType;
+    }
+
+    public void setReturnType(String returnType) {
+        this.returnType = returnType;
+    }
+
+    public String getReturnComment() {
+        return returnComment;
+    }
+
+    public void setReturnComment(String returnComment) {
+        this.returnComment = returnComment;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public List<FnParam> getParams() {
+        return params;
+    }
+
+    public void setParams(List<FnParam> params) {
+        this.params = params;
+    }
+
+    public void addParams(FnParam param) {
+        if (null == this.params) {
+            this.params = new LinkedList<>();
+        }
+        this.params.add(param);
+    }
+
+    public List<FnExample> getExamples() {
+        return examples;
+    }
+
+    public void setExamples(List<FnExample> examples) {
+        this.examples = examples;
+    }
+
+    public void addExamples(FnExample example) {
+        if (null == this.examples) {
+            this.examples = new LinkedList<>();
+        }
+        this.examples.add(example);
+    }
+
+}

+ 7 - 0
tools/java/src/main/java/org/luatos/toolkit/bean/LuCommentType.java

@@ -0,0 +1,7 @@
+package org.luatos.toolkit.bean;
+
+public enum LuCommentType {
+
+    LUA_SIGN, TEXT, DISABLED
+    
+}

+ 135 - 0
tools/java/src/main/java/org/luatos/toolkit/bean/LuDocComment.java

@@ -0,0 +1,135 @@
+package org.luatos.toolkit.bean;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+
+import org.nutz.lang.Strings;
+import org.nutz.lang.util.Regex;
+
+public class LuDocComment {
+
+    private LuCommentType type;
+
+    private List<String> lines;
+
+    public LuDocComment() {}
+
+    public LuDocComment(String block) {
+        this.parse(block);
+    }
+
+    public void clear() {
+        this.type = null;
+        this.lines = null;
+    }
+
+    public boolean isLuaSign() {
+        return LuCommentType.LUA_SIGN == this.type;
+    }
+
+    public boolean isText() {
+        return LuCommentType.TEXT == this.type;
+    }
+
+    public boolean isDisabled() {
+        return LuCommentType.DISABLED == this.type;
+    }
+
+    public boolean isEmpty() {
+        return null == lines || lines.isEmpty();
+    }
+
+    public LuCommentType getType() {
+        return type;
+    }
+
+    public void setType(LuCommentType type) {
+        this.type = type;
+    }
+
+    public List<String> getLines() {
+        return lines;
+    }
+
+    public void setLines(List<String> lines) {
+        this.lines = lines;
+    }
+
+    public void appendLine(String line) {
+        if (null == lines) {
+            lines = new LinkedList<>();
+        }
+        this.lines.add(line);
+    }
+
+    private static final String REG_BEGIN = "^\\s*(/[*]|[*]{1,2} ) *(.*)$";
+    private static final String REG_END = "^(.*) *([*]/)\\s*$";
+
+    public void parse(String block) {
+        String[] ss = block.split("\r?\n");
+        // 有可能是多重
+        if (ss.length >= 2) {
+            // 或者是多行或者是 Lua 的 doxygen 注释
+            if (ss[0].startsWith("/*") && ss[ss.length - 1].endsWith("*/")) {
+                LuCommentType type = null;
+                int lastI = ss.length - 1;
+                for (int i = 0; i <= lastI; i++) {
+                    String s = ss[i];
+                    String str = null;
+                    Matcher m = Regex.getPattern(REG_BEGIN).matcher(s);
+                    // 可能是普通注释第一行
+                    // -> /*
+                    // -> **
+                    // -> *
+                    if (m.find()) {
+                        str = m.group(2);
+                    }
+                    // 看看是否是结尾
+                    else {
+                        m = Regex.getPattern(REG_END).matcher(s);
+                        if (m.find()) {
+                            str = m.group(1);
+                        }
+                        // 那么就是普通行咯
+                        else {
+                            str = s;
+                        }
+                    }
+
+                    // 计入(如果已经开始计入注释行了,那么空行也加进来,当然最后一行除外
+                    if (!Strings.isBlank(str) || (!this.isEmpty() && i < lastI)) {
+                        this.appendLine(str);
+                        // 如果声明了 docxygen 的注释,标识一下类型
+                        if (null == type && str.startsWith("@function")) {
+                            type = LuCommentType.LUA_SIGN;
+                        }
+                    }
+                }
+
+                // 最后设置一下类型
+                if (null == type) {
+                    type = LuCommentType.TEXT;
+                }
+                this.setType(type);
+
+                return;
+            }
+        }
+        // 看看是不是单行注释
+        for (String s : ss) {
+            if (s.startsWith("//")) {
+                this.appendLine(s.substring(2).trim());
+            }
+        }
+        this.setType(LuCommentType.TEXT);
+    }
+
+    public String toString() {
+        if (this.isEmpty()) {
+            return "";
+        }
+        return Strings.join(System.lineSeparator(), lines);
+    }
+
+}

+ 45 - 0
tools/java/src/main/java/org/luatos/toolkit/bean/LuatDocHeader.java

@@ -0,0 +1,45 @@
+package org.luatos.toolkit.bean;
+
+public class LuatDocHeader {
+
+    private String module;
+
+    private String summary;
+
+    private String version;
+
+    private String date;
+
+    public String getModule() {
+        return module;
+    }
+
+    public void setModule(String module) {
+        this.module = module;
+    }
+
+    public String getSummary() {
+        return summary;
+    }
+
+    public void setSummary(String summary) {
+        this.summary = summary;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getDate() {
+        return date;
+    }
+
+    public void setDate(String date) {
+        this.date = date;
+    }
+
+}

+ 33 - 0
tools/java/src/main/java/org/luatos/toolkit/bean/LuatDocSet.java

@@ -0,0 +1,33 @@
+package org.luatos.toolkit.bean;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class LuatDocSet {
+
+    private String name;
+
+    private List<LuatDocument> docs;
+
+    public LuatDocSet(String name) {
+        this.name = name;
+        this.docs = new LinkedList<>();
+    }
+
+    public void addDoc(LuatDocument doc) {
+        this.docs.add(doc);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public List<LuatDocument> getDocs() {
+        return docs;
+    }
+
+}

+ 45 - 0
tools/java/src/main/java/org/luatos/toolkit/bean/LuatDocument.java

@@ -0,0 +1,45 @@
+package org.luatos.toolkit.bean;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class LuatDocument {
+
+    private String path;
+
+    private LuatDocHeader title;
+
+    private List<FnSign> functions;
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public LuatDocHeader getTitle() {
+        return title;
+    }
+
+    public void setTitle(LuatDocHeader title) {
+        this.title = title;
+    }
+
+    public List<FnSign> getFunctions() {
+        return functions;
+    }
+
+    public void setFunctions(List<FnSign> functions) {
+        this.functions = functions;
+    }
+
+    public void addFunctions(FnSign func) {
+        if (null == this.functions) {
+            this.functions = new LinkedList<>();
+        }
+        this.functions.add(func);
+    }
+
+}

+ 77 - 0
tools/java/src/main/java/org/luatos/toolkit/impl/CFnSignGenerating.java

@@ -0,0 +1,77 @@
+package org.luatos.toolkit.impl;
+
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.luatos.toolkit.api.FnSignGenerating;
+import org.luatos.toolkit.bean.FnModifier;
+import org.luatos.toolkit.bean.FnParam;
+import org.luatos.toolkit.bean.FnSign;
+import org.nutz.lang.Lang;
+import org.nutz.lang.Strings;
+import org.nutz.lang.util.Regex;
+
+public class CFnSignGenerating implements FnSignGenerating {
+
+    private static String _r0 = "^\\s*((static)\\s+)?(\\w+(\\s*[*])?)\\s*(\\w+)\\s*\\(([^)]*)\\).*$";
+    private static Pattern PT = Regex.getPattern(_r0);
+
+    private static String _r1 = "^(([\\w\\d]+)(\\s+[*])?)\\s*([\\w\\d]*)$";
+    private static Pattern PM = Regex.getPattern(_r1);
+
+    @Override
+    public FnSign gen(String block) {
+        // 变成一行
+        String str = block.replaceAll("\r?\n", " ");
+
+        // 分析
+        Matcher m = PT.matcher(str);
+
+        // 不合法
+        if (!m.find()) {
+            throw Lang.makeThrow("invalid CFunction sign", block);
+        }
+
+        // 提取值
+        String mod = m.group(2);
+        String retp = m.group(3);
+        String name = m.group(5);
+        String params = m.group(6);
+
+        // 准备返回
+        FnSign fn = new FnSign();
+        fn.setRawText(block);
+
+        if ("static".equals(mod)) {
+            fn.setModifier(FnModifier.STATIC);
+        }
+        fn.setReturnType(retp);
+        fn.setName(name);
+
+        // 分析参数
+        String[] ss = Strings.splitIgnoreBlank(params);
+        if (ss.length == 0) {
+            fn.setParams(new ArrayList<>(0));
+        }
+        // 循环判断参数
+        else {
+            for (String s : ss) {
+                m = PM.matcher(s);
+                if (!m.find()) {
+                    throw Lang.makeThrow("invalid CFunction [" + block + "] param", s);
+                }
+                String pmtp = m.group(1);
+                String pmnm = m.group(4);
+                FnParam pm = new FnParam();
+                pm.setType(pmtp);
+                pm.setName(pmnm);
+                fn.addParams(pm);
+            }
+        }
+
+        // 搞定
+        return fn;
+    }
+
+}

+ 167 - 0
tools/java/src/main/java/org/luatos/toolkit/impl/LuaDocFnSignGenerating.java

@@ -0,0 +1,167 @@
+package org.luatos.toolkit.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.luatos.toolkit.api.FnSignGenerating;
+import org.luatos.toolkit.bean.FnExample;
+import org.luatos.toolkit.bean.FnParam;
+import org.luatos.toolkit.bean.FnSign;
+import org.nutz.lang.Lang;
+import org.nutz.lang.Strings;
+import org.nutz.lang.util.Regex;
+
+public class LuaDocFnSignGenerating implements FnSignGenerating {
+
+    private static final int IN_SUMMARY = 0;
+    private static final int IN_FUNC = 1;
+    private static final int IN_EXAMPLE = 2;
+
+    private static String _r2 = "^\\s*([\\w\\d.]+)\\s*(\\(([^)]*)\\))?.*$";
+    private static Pattern P2 = Regex.getPattern(_r2);
+
+    @Override
+    public FnSign gen(String block) {
+        String[] lines = block.split("\r?\n");
+        List<String> summaries = new ArrayList<>(lines.length);
+        String func;
+        String[] pmnms = null;
+        List<FnParam> params = new ArrayList<>(lines.length);
+        FnExample exmLast = null;
+
+        String feType = null; // @return @string ...
+        String feCmt = "";
+
+        // 准备返回值
+        FnSign fn = new FnSign();
+
+        // 三种状态
+        int mode = IN_SUMMARY;
+
+        // 逐行搞
+        for (String line : lines) {
+            // 还在摘要部分
+            if (IN_SUMMARY == mode) {
+                // 进入函数部分了
+                if (line.startsWith("@function")) {
+                    mode = IN_FUNC;
+                    func = line.substring("@function".length()).trim();
+                    // 来,分析一下
+                    Matcher m = P2.matcher(func);
+                    if (!m.find()) {
+                        throw Lang.makeThrow("Invalid Lua func", func);
+                    }
+                    fn.setName(m.group(1));
+                    pmnms = Strings.splitIgnoreBlank(m.group(3));
+                    continue;
+                }
+                // 计入摘要
+                summaries.add(line);
+            }
+            // 进入函数部分
+            else if (IN_FUNC == mode) {
+                // 明确的开始例子部分
+                if (line.trim().equals("@usage")) {
+                    mode = IN_EXAMPLE;
+                }
+                // 进入例子部分了
+                else if (line.startsWith("--")) {
+                    if (null != exmLast && exmLast.hasCode()) {
+                        fn.addExamples(exmLast);
+                    }
+
+                    exmLast = new FnExample();
+                    exmLast.appendSummary(line.substring(2).trim());
+
+                    mode = IN_EXAMPLE;
+                }
+                // 开始参数或者返回
+                else if (line.startsWith("@")) {
+                    // 推入旧的
+                    if (!Strings.isBlank(feType)) {
+                        pushFnEntity(fn, params, feType, feCmt);
+                    }
+                    // 开启新的
+                    int pos = line.indexOf(' ', 1);
+                    if (pos > 0) {
+                        feType = line.substring(1, pos).trim();
+                        feCmt = line.substring(pos + 1).trim();
+                    } else {
+                        feType = "??";
+                        feCmt = line.substring(1).trim();
+                    }
+                }
+            }
+            // 进入例子部分
+            else if (IN_EXAMPLE == mode) {
+                // 追加说明
+                if (line.startsWith("--")) {
+                    if (null != exmLast && exmLast.hasCode()) {
+                        fn.addExamples(exmLast);
+                    }
+                    if (null == exmLast) {
+                        exmLast = new FnExample();
+                    }
+                    exmLast.appendSummary(line.substring(2).trim());
+                }
+                // 那就是例子代码咯
+                else {
+                    exmLast.appendCode(line);
+                }
+            }
+        }
+
+        // 推入最后一个实体
+        if (!Strings.isBlank(feType)) {
+            pushFnEntity(fn, params, feType, feCmt);
+        }
+
+        // 函数的摘要
+        fn.setSummary(Strings.join(System.lineSeparator(), summaries));
+
+        // 归纳函数参数
+        int plMax = Math.max(params.size(), pmnms.length);
+        for (int i = 0; i < plMax; i++) {
+            String pmnm = i < pmnms.length ? pmnms[i] : "?";
+            FnParam param = i < params.size() ? params.get(i) : null;
+            // 看来只有形参名,木有给定注释说明
+            if (null == param) {
+                param = new FnParam();
+            }
+            param.setName(pmnm);
+            fn.addParams(param);
+        }
+
+        // 最后一个例子
+        if (null != exmLast && exmLast.hasCode()) {
+            fn.addExamples(exmLast);
+        }
+
+        // 搞定
+        return fn;
+    }
+
+    private void pushFnEntity(FnSign fn, List<FnParam> params, String feType, String feCmt) {
+        // 返回值
+        if ("return".equals(feType)) {
+            int pos = feCmt.indexOf(' ');
+            if (pos > 0) {
+                fn.setReturnType(feCmt.substring(0, pos).trim());
+                fn.setReturnComment(feCmt.substring(pos + 1).trim());
+            } else {
+                fn.setReturnType("??");
+                fn.setReturnComment(feCmt);
+            }
+        }
+        // 参数
+        else {
+            FnParam param = new FnParam();
+            param.setType(feType);
+            param.setComment(feCmt);
+            params.add(param);
+        }
+    }
+
+}

+ 8 - 0
tools/java/src/main/resources/doc-gen.json

@@ -0,0 +1,8 @@
+{
+  "workdir": "D:/github/LuatOS/",
+  "entries": [{
+    "path": "luat/src/modules",
+    "suffixes": [".c"]
+  }],
+  "output": "${workdir}/docs/api/"
+}

+ 10 - 0
tools/java/src/test/java/org/luatos/toolkit/LuatTookietTestAll.java

@@ -0,0 +1,10 @@
+package org.luatos.toolkit;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.luatos.toolkit.bean.FnSignTest;
+import org.luatos.toolkit.bean.LuDocCommentTest;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({FnSignTest.class, LuDocCommentTest.class})
+public class LuatTookietTestAll {}

+ 69 - 0
tools/java/src/test/java/org/luatos/toolkit/bean/FnSignTest.java

@@ -0,0 +1,69 @@
+package org.luatos.toolkit.bean;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.luatos.toolkit.api.FnSignGenerating;
+import org.luatos.toolkit.impl.CFnSignGenerating;
+import org.luatos.toolkit.impl.LuaDocFnSignGenerating;
+import org.nutz.json.Json;
+import org.nutz.lang.Files;
+
+public class FnSignTest {
+
+    @Test
+    public void test_lua_cmt_fn_0() {
+        String input = Files.read("input/lua_cmt_fn_0.txt");
+        String expec = Files.read("expec/lua_cmt_fn_0.json");
+        FnSign expFn = Json.fromJson(FnSign.class, expec);
+
+        FnSignGenerating fsg = new LuaDocFnSignGenerating();
+        FnSign axuFn = fsg.gen(input);
+        assertTrue(axuFn.equals(expFn));
+    }
+
+    @Test
+    public void test_lua_cmt_fn_1() {
+        String input = Files.read("input/lua_cmt_fn_1.txt");
+        String expec = Files.read("expec/lua_cmt_fn_1.json");
+        FnSign expFn = Json.fromJson(FnSign.class, expec);
+
+        FnSignGenerating fsg = new LuaDocFnSignGenerating();
+        FnSign axuFn = fsg.gen(input);
+        assertTrue(axuFn.equals(expFn));
+    }
+
+    @Test
+    public void test_c_sign_fn_0() {
+        String input = Files.read("input/c_sign_fn_0.txt");
+        String expec = Files.read("expec/c_sign_fn_0.json");
+        FnSign expFn = Json.fromJson(FnSign.class, expec);
+
+        FnSignGenerating fsg = new CFnSignGenerating();
+        FnSign axuFn = fsg.gen(input);
+        assertTrue(axuFn.equals(expFn));
+    }
+
+    @Test
+    public void test_c_sign_fn_1() {
+        String input = Files.read("input/c_sign_fn_1.txt");
+        String expec = Files.read("expec/c_sign_fn_1.json");
+        FnSign expFn = Json.fromJson(FnSign.class, expec);
+
+        FnSignGenerating fsg = new CFnSignGenerating();
+        FnSign axuFn = fsg.gen(input);
+        assertTrue(axuFn.equals(expFn));
+    }
+
+    @Test
+    public void test_c_sign_fn_2() {
+        String input = Files.read("input/c_sign_fn_2.txt");
+        String expec = Files.read("expec/c_sign_fn_2.json");
+        FnSign expFn = Json.fromJson(FnSign.class, expec);
+
+        FnSignGenerating fsg = new CFnSignGenerating();
+        FnSign axuFn = fsg.gen(input);
+        assertTrue(axuFn.equals(expFn));
+    }
+
+}

+ 50 - 0
tools/java/src/test/java/org/luatos/toolkit/bean/LuDocCommentTest.java

@@ -0,0 +1,50 @@
+package org.luatos.toolkit.bean;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.nutz.lang.Files;
+
+public class LuDocCommentTest {
+
+    @Test
+    public void test_lua_0() {
+        String input = Files.read("input/cmt_lua_0.txt");
+        String expec = Files.read("expec/cmt_lua_0.txt");
+
+        LuDocComment dc = new LuDocComment(input);
+        assertTrue(dc.isLuaSign());
+        assertEquals(expec, dc.toString());
+    }
+
+    @Test
+    public void test_multi_0() {
+        String input = Files.read("input/cmt_c_multi_0.txt");
+        String expec = Files.read("expec/cmt_c_multi_0.txt");
+
+        LuDocComment dc = new LuDocComment(input);
+        assertTrue(dc.isText());
+        assertEquals(expec, dc.toString());
+    }
+
+    @Test
+    public void test_multi_1() {
+        String input = Files.read("input/cmt_c_multi_1.txt");
+        String expec = Files.read("expec/cmt_c_multi_1.txt");
+
+        LuDocComment dc = new LuDocComment(input);
+        assertTrue(dc.isText());
+        assertEquals(expec, dc.toString());
+    }
+
+    @Test
+    public void test_single_0() {
+        String input = Files.read("input/cmt_c_single_0.txt");
+        String expec = Files.read("expec/cmt_c_single_0.txt");
+
+        LuDocComment dc = new LuDocComment(input);
+        assertTrue(dc.isText());
+        assertEquals(expec, dc.toString());
+    }
+
+}

+ 12 - 0
tools/java/src/test/resources/expec/c_sign_fn_0.json

@@ -0,0 +1,12 @@
+{
+  "rawText": "static int socket_ntp_sync(lua_State *L)",
+  "summary": null,
+  "modifier": "STATIC",
+  "returnType": "int",
+  "name": "socket_ntp_sync",
+  "params": [{
+      "type": "lua_State *",
+      "name": "L"
+    }]
+}
+  

+ 11 - 0
tools/java/src/test/resources/expec/c_sign_fn_1.json

@@ -0,0 +1,11 @@
+{
+  "rawText": "void  luat_heap_init(void)",
+  "summary": null,
+  "modifier": null,
+  "returnType": "void",
+  "name": "luat_heap_init",
+  "params": [{
+      "type": "void",
+      "name": null
+    }]
+}

+ 17 - 0
tools/java/src/test/resources/expec/c_sign_fn_2.json

@@ -0,0 +1,17 @@
+{
+  "rawText": "static int socket_ntp_sync(lua_State *L)",
+  "summary": null,
+  "modifier": null,
+  "returnType": "void *",
+  "name": "luat_rt_realloc",
+  "params": [{
+      "type": "void *",
+      "name": "rmem"
+    }, {
+      "type": "rt_size_t",
+      "name": "newsize"
+    }]
+}
+  
+
+  

+ 3 - 0
tools/java/src/test/resources/expec/cmt_c_multi_0.txt

@@ -0,0 +1,3 @@
+results:
+-1, no space to install fatfs driver
+>= 0, there is an space to install littlefs driver

+ 4 - 0
tools/java/src/test/resources/expec/cmt_c_multi_1.txt

@@ -0,0 +1,4 @@
+open upvalues point to values in a thread, so those values should
+be marked when the thread is traversed except in the atomic phase
+(because then the value cannot be changed by the thread and the
+thread may not be traversed again)

+ 4 - 0
tools/java/src/test/resources/expec/cmt_c_single_0.txt

@@ -0,0 +1,4 @@
+Erase a block. A block must be erased before being programmed.
+The state of an erased block is undefined. Negative error codes
+are propogated to the user.
+May return LFS_ERR_CORRUPT if the block should be considered bad.

+ 9 - 0
tools/java/src/test/resources/expec/cmt_lua_0.txt

@@ -0,0 +1,9 @@
+ntp时间同步
+@function    socket.ntpSync(server)
+@string ntp服务器域名,默认值ntp1.aliyun.com
+@return int 启动成功返回0, 失败返回1或者2
+--  如果读取失败,会返回nil
+socket.ntpSync()
+sys.subscribe("NTP_UPDATE", function(re)
+    log.info("ntp", "result", re)
+end)

+ 21 - 0
tools/java/src/test/resources/expec/lua_cmt_fn_0.json

@@ -0,0 +1,21 @@
+{
+  "rawText": "=INPUT",
+  "summary": "ntp时间同步",
+  "modifier": null,
+  "returnType": "int",
+  "returnComment": "启动成功返回0, 失败返回1或者2",
+  "name": "socket.ntpSync",
+  "params": [{
+      "type": "string",
+      "name": "server",
+      "comment": "ntp服务器域名,默认值ntp1.aliyun.com"
+    }],
+  "examples": [{
+    "summary": ["如果读取失败,会返回nil"],
+    "code": [
+      "socket.ntpSync()",
+      "sys.subscribe(\"NTP_UPDATE\", function(re)",
+      "    log.info(\"ntp\", \"result\", re)",
+      "end)"]
+  }]
+}

+ 27 - 0
tools/java/src/test/resources/expec/lua_cmt_fn_1.json

@@ -0,0 +1,27 @@
+{
+  "rawText": "=INPUT",
+  "summary": "启动一个定时器",
+  "modifier": null,
+  "returnType": "id",
+  "returnComment": "如果是定时器消息,会返回定时器消息id及附加信息, 其他消息由底层决定,不向lua层进行任何保证.",
+  "name": "rtos.timer_start",
+  "params": [{
+      "type": "int",
+      "name": "id",
+      "comment": "定时器id"
+    }, {
+      "type": "int",
+      "name": "timeout",
+      "comment": "超时时长,单位毫秒"
+    }, {
+      "type": "int",
+      "name": "_repeat",
+      "comment": "重复次数,默认是0"
+    }],
+  "examples": [{
+    "summary": [
+      "用户代码请使用 sys.timerStart",
+      "启动一个3秒的循环定时器"],
+    "code": ["rtos.timer_start(10000, 3000, -1)"]
+  }]
+}

+ 1 - 0
tools/java/src/test/resources/input/c_sign_fn_0.txt

@@ -0,0 +1 @@
+static int socket_ntp_sync(lua_State *L) {

+ 1 - 0
tools/java/src/test/resources/input/c_sign_fn_1.txt

@@ -0,0 +1 @@
+void  luat_heap_init(void) {};

+ 1 - 0
tools/java/src/test/resources/input/c_sign_fn_2.txt

@@ -0,0 +1 @@
+void *luat_rt_realloc(void *rmem, rt_size_t newsize);

+ 4 - 0
tools/java/src/test/resources/input/cmt_c_multi_0.txt

@@ -0,0 +1,4 @@
+/* results:
+ *  -1, no space to install fatfs driver
+ *  >= 0, there is an space to install littlefs driver
+ */

+ 6 - 0
tools/java/src/test/resources/input/cmt_c_multi_1.txt

@@ -0,0 +1,6 @@
+/*
+** open upvalues point to values in a thread, so those values should
+** be marked when the thread is traversed except in the atomic phase
+** (because then the value cannot be changed by the thread and the
+** thread may not be traversed again)
+*/

+ 4 - 0
tools/java/src/test/resources/input/cmt_c_single_0.txt

@@ -0,0 +1,4 @@
+// Erase a block. A block must be erased before being programmed.
+// The state of an erased block is undefined. Negative error codes
+// are propogated to the user.
+// May return LFS_ERR_CORRUPT if the block should be considered bad.

+ 11 - 0
tools/java/src/test/resources/input/cmt_lua_0.txt

@@ -0,0 +1,11 @@
+/*
+ntp时间同步
+@function    socket.ntpSync(server)
+@string ntp服务器域名,默认值ntp1.aliyun.com
+@return int 启动成功返回0, 失败返回1或者2
+--  如果读取失败,会返回nil
+socket.ntpSync()
+sys.subscribe("NTP_UPDATE", function(re)
+    log.info("ntp", "result", re)
+end)
+*/

+ 9 - 0
tools/java/src/test/resources/input/lua_cmt_fn_0.txt

@@ -0,0 +1,9 @@
+ntp时间同步
+@function    socket.ntpSync(server)
+@string ntp服务器域名,默认值ntp1.aliyun.com
+@return int 启动成功返回0, 失败返回1或者2
+--  如果读取失败,会返回nil
+socket.ntpSync()
+sys.subscribe("NTP_UPDATE", function(re)
+    log.info("ntp", "result", re)
+end)

+ 10 - 0
tools/java/src/test/resources/input/lua_cmt_fn_1.txt

@@ -0,0 +1,10 @@
+启动一个定时器
+@function    rtos.timer_start(id,timeout,_repeat)   
+@int  定时器id
+@int  超时时长,单位毫秒
+@int  重复次数,默认是0
+@return id 如果是定时器消息,会返回定时器消息id及附加信息, 其他消息由底层决定,不向lua层进行任何保证.
+@usage
+-- 用户代码请使用 sys.timerStart
+-- 启动一个3秒的循环定时器
+rtos.timer_start(10000, 3000, -1)