1
+ import subprocess
2
+ import json
3
+ import os
4
+ import sys
5
+
6
+ def delete_head_spaces (comment : str ) -> str :
7
+ if comment .find ("//" ) == 0 :
8
+ return comment
9
+ result = ""
10
+ for string in comment .split ("\n " ):
11
+ temp = ""
12
+ is_space_flag = True
13
+ for ch in string :
14
+ if is_space_flag and (ch == ' ' or ch == '\t ' ):
15
+ continue
16
+ is_space_flag = False
17
+ temp += ch
18
+ result += temp + "\n "
19
+ if result [- 1 ] == "\n " :
20
+ return result [:- 1 ]
21
+ return result
22
+
23
+ def match_schema_comment (comment_list , schema ) -> str :
24
+ schema_location = schema ["location" ]
25
+ for comment in comment_list :
26
+ comment_location = comment ["location" ]
27
+ if comment_location [3 ] < schema_location [1 ]- 1 :
28
+ continue
29
+ if comment_location [3 ] > schema_location [1 ]:
30
+ continue
31
+ return delete_head_spaces (comment ["content" ])
32
+ return ""
33
+
34
+ def match_comment (comment_list , function ) -> str :
35
+ function_location = function ["location" ]
36
+ for comment in comment_list :
37
+ comment_location = comment ["location" ]
38
+ if comment_location [3 ] < function_location [1 ]- 1 :
39
+ continue
40
+ if comment_location [3 ] > function_location [1 ]:
41
+ continue
42
+ return delete_head_spaces (comment ["content" ])
43
+ return ""
44
+
45
+ def raw_string (name : str ) -> str :
46
+ name = name .replace ("_" , "\\ _" )
47
+ name = name .replace ("<" , "\\ <" )
48
+ name = name .replace (">" , "\\ >" )
49
+ return name
50
+
51
+ def dump_type (type_struct ):
52
+ result = "*" if type_struct ["is_set" ] == "true" else ""
53
+ result += type_struct ["name" ]
54
+ return result
55
+
56
+ def dump_function (function ):
57
+ result = "pub fn " + function ["name" ] + "("
58
+ for param in function ["parameter" ]:
59
+ result += param ["name" ] + ": "
60
+ result += dump_type (param ["type" ]) + ", "
61
+ if result [- 1 ] == " " :
62
+ result = result [:- 2 ]
63
+ result += ") -> "
64
+ result += dump_type (function ["return" ]) + ";"
65
+ return result
66
+
67
+ def dump_function_parameter (function , link_dir = "./schema/" , link_db_path = "./database.html" ) -> str :
68
+ basic_type = ["int" , "float" , "string" , "bool" ]
69
+ result = ""
70
+ for param in function ["parameter" ]:
71
+ result += "* Parameter `" + raw_string (param ["name" ]) + "`: "
72
+ if param ["type" ]["name" ] in basic_type :
73
+ result += "`" + dump_type (param ["type" ]) + "`\n "
74
+ elif param ["type" ]["name" ] in database_map .keys ():
75
+ result += "[`" + dump_type (param ["type" ]) + "`](" + link_db_path + ")\n "
76
+ else :
77
+ result += "[`" + dump_type (param ["type" ]) + "`](" + link_dir + param ["type" ]["name" ] + ".html)\n "
78
+ if function ["return" ]["name" ] in basic_type :
79
+ result += "* Return `" + dump_type (function ["return" ]) + "`\n "
80
+ elif function ["return" ]["name" ] in database_map .keys ():
81
+ result += "* Return [`" + dump_type (function ["return" ]) + "`](" + link_db_path + ")\n "
82
+ else :
83
+ result += "* Return [`" + dump_type (function ["return" ]) + "`](" + link_dir + function ["return" ]["name" ] + ".html)\n "
84
+ return result
85
+
86
+ database_map = {}
87
+ def dump_database (database ) -> str :
88
+ database_map [database ["name" ]] = 1
89
+ result = "## " + database ["name" ] + "\n \n "
90
+ for table in database ["table" ]:
91
+ result += "* " + table ["name" ] + ": "
92
+ result += "[*" + table ["type" ]["name" ] + "](./schema/" + table ["type" ]["name" ] + ".html)\n "
93
+ return result
94
+
95
+ def dump_schema (comment_list , schema ) -> str :
96
+ result = "---\n "
97
+ result += "layout: default\n "
98
+ result += "---\n \n "
99
+ result += "# " + schema ["name" ] + "\n \n "
100
+ comment_of_schema = match_schema_comment (comment_list , schema )
101
+ if len (comment_of_schema ) > 0 :
102
+ result += "```java\n " + comment_of_schema + "\n ```\n "
103
+ if len (schema ["parent" ]) > 0 :
104
+ result += "Inherit from [" + schema ["parent" ] + "](" + "./" + schema ["parent" ] + ".html)\n \n "
105
+ for field in schema ["fields" ]:
106
+ if field ["primary" ]== "true" :
107
+ result += "Primary key: `" + field ["name" ] + ": "
108
+ result += dump_type (field ["type" ]) + "`\n \n "
109
+ break
110
+ result += "```typescript\n "
111
+ result += "schema " + schema ["name" ]
112
+ if len (schema ["parent" ]) > 0 :
113
+ result += " extends " + schema ["parent" ]
114
+ result += " {\n "
115
+ for field in schema ["fields" ]:
116
+ result += " "
117
+ if field ["primary" ]== "true" :
118
+ result += "@primary "
119
+ result += field ["name" ] + ": "
120
+ result += dump_type (field ["type" ]) + ",\n "
121
+ if result [- 2 :] == ",\n " :
122
+ result = result [:- 2 ] + "\n "
123
+ result += "}\n "
124
+ result += "```\n "
125
+ for method in schema ["methods" ]:
126
+ if method ["is_public" ]== "false" :
127
+ continue
128
+ if method ["name" ] in ["is<T>" , "to<T>" , "key_eq" , "key_neq" , "to_set" ]:
129
+ continue
130
+ result += "## " + schema ["name" ] + "::" + raw_string (method ["name" ]) + "\n \n "
131
+ if method ["name" ] == "__all__" :
132
+ result += "Data constraint method.\n \n "
133
+ comment = match_comment (comment_list , method )
134
+ if len (comment ) > 0 :
135
+ result += "```java\n " + comment + "\n ```\n "
136
+ result += dump_function_parameter (method , "./" , "../database.html" ) + "\n "
137
+ result += "```rust\n "
138
+ result += dump_function (method ) + "\n "
139
+ result += "```\n "
140
+ return result
141
+
142
+ def dfs_visit_schema_hierarchy (schema , schema_list , indent : str ) -> str :
143
+ result = indent + "* [" + schema ["name" ] + "](./schema/" + schema ["name" ] + ".html)\n "
144
+ for i in schema_list :
145
+ if i ["parent" ] == schema ["name" ]:
146
+ result += dfs_visit_schema_hierarchy (i , schema_list , indent + " " )
147
+ return result
148
+
149
+ def dump_schema_tree_view (schema_list ) -> str :
150
+ root_schema = []
151
+ for schema in schema_list :
152
+ if len (schema ["parent" ]) == 0 :
153
+ root_schema .append (schema )
154
+ result = ""
155
+ for i in root_schema :
156
+ result += dfs_visit_schema_hierarchy (i , schema_list , "" )
157
+ return result
158
+
159
+ if len (sys .argv ) != 2 :
160
+ print ("Usage: python this_file.py godel_script_executable_path" )
161
+ exit (- 1 )
162
+
163
+ godel_compiler_path = sys .argv [1 ]
164
+ markdown_output_path = "./godel-api"
165
+ input_file_directory = "./.coref-api-build"
166
+
167
+ dirs = [
168
+ "./godel-api" ,
169
+ "./godel-api/cfamily" ,
170
+ "./godel-api/go" ,
171
+ "./godel-api/java" ,
172
+ "./godel-api/javascript" ,
173
+ "./godel-api/properties" ,
174
+ "./godel-api/python" ,
175
+ "./godel-api/sql" ,
176
+ "./godel-api/xml" ,
177
+ "./godel-api/cfamily/schema" ,
178
+ "./godel-api/go/schema" ,
179
+ "./godel-api/java/schema" ,
180
+ "./godel-api/javascript/schema" ,
181
+ "./godel-api/properties/schema" ,
182
+ "./godel-api/python/schema" ,
183
+ "./godel-api/sql/schema" ,
184
+ "./godel-api/xml/schema"
185
+ ]
186
+ for d in dirs :
187
+ if not os .path .exists (d ):
188
+ os .mkdir (d )
189
+
190
+ input_file_list = []
191
+ for (path , dirname , filename ) in os .walk (input_file_directory ):
192
+ for file in filename :
193
+ input_file_list .append ({"path" : path , "name" : file })
194
+
195
+ name_mapper = {
196
+ "coref.cfamily.gdl" : "cfamily" ,
197
+ "coref.go.gdl" : "go" ,
198
+ "coref.java.gdl" : "java" ,
199
+ "coref.javascript.gdl" : "javascript" ,
200
+ "coref.properties.gdl" : "properties" ,
201
+ "coref.python.gdl" : "python" ,
202
+ "coref.sql.gdl" : "sql" ,
203
+ "coref.xml.gdl" : "xml"
204
+ }
205
+
206
+ semantic_dict = {}
207
+ for file in input_file_list :
208
+ file_full_path = file ["path" ] + "/" + file ["name" ]
209
+ print ("Extract semantic info from " + file_full_path )
210
+ result = subprocess .run (
211
+ [godel_compiler_path , "--dump-lsp" , file_full_path ],
212
+ stdout = subprocess .PIPE ,
213
+ stderr = subprocess .DEVNULL
214
+ )
215
+ if result .returncode != 0 :
216
+ continue
217
+ semantic_dict [file ["name" ]] = result .stdout .decode ("utf-8" )
218
+
219
+ for file in input_file_list :
220
+ file_full_path = file ["path" ] + "/" + file ["name" ]
221
+ print ("Generate markdown for " + file_full_path )
222
+ semantic_info = json .loads (semantic_dict [file ["name" ]])
223
+ comment_list = semantic_info ["comments" ]
224
+
225
+ output_data = "---\n "
226
+ output_data += "title: \" coref::" + name_mapper [file ["name" ]] + "\" \n "
227
+ output_data += "layout: default\n "
228
+ output_data += "has_children: true\n "
229
+ output_data += "parent: \" COREF Library Reference\" \n "
230
+ output_data += "---\n "
231
+ output_data += "# COREF Library Reference for " + name_mapper [file ["name" ]] + "\n \n "
232
+ output_data += "* coref::" + name_mapper [file ["name" ]] + " [database](./database.html)\n "
233
+ output_data += "* coref::" + name_mapper [file ["name" ]] + " [function](./function.html)\n "
234
+ output_data += "* coref::" + name_mapper [file ["name" ]] + " [schema](./schema.html)\n "
235
+ output_file_path = markdown_output_path + "/" + name_mapper [file ["name" ]] + "/reference.md"
236
+ open (output_file_path , "w" ).write (output_data )
237
+
238
+ output_data = "---\n "
239
+ output_data += "title: \" database\" \n "
240
+ output_data += "layout: default\n "
241
+ output_data += "parent: \" coref::" + name_mapper [file ["name" ]] + "\" \n "
242
+ output_data += "grand_parent: \" COREF Library Reference\" \n "
243
+ output_data += "---\n "
244
+ output_data += "# Database of " + file ["name" ] + "\n \n "
245
+ database_list = semantic_info ["semantic" ]["database" ]
246
+ for database in database_list :
247
+ output_data += dump_database (database )
248
+ output_file_path = markdown_output_path + "/" + name_mapper [file ["name" ]] + "/database.md"
249
+ print ("Generate" , output_file_path )
250
+ open (output_file_path , "w" ).write (output_data )
251
+
252
+ function_list = semantic_info ["semantic" ]["function" ]
253
+ output_data = "---\n "
254
+ output_data += "title: \" function\" \n "
255
+ output_data += "layout: default\n "
256
+ output_data += "parent: \" coref::" + name_mapper [file ["name" ]] + "\" \n "
257
+ output_data += "grand_parent: \" COREF Library Reference\" \n "
258
+ output_data += "---\n "
259
+ output_data += "# Global Function of " + file ["name" ] + "\n \n "
260
+ for function in function_list :
261
+ if len (function ["location" ][0 ]) == 0 :
262
+ continue
263
+ if function ["is_public" ]== "false" :
264
+ continue
265
+ output_data += "## " + function ["name" ] + "\n \n "
266
+ comment = match_comment (comment_list , function )
267
+ if len (comment ) > 0 :
268
+ output_data += "```java\n " + comment + "\n ```\n "
269
+ output_data += dump_function_parameter (function ) + "\n "
270
+ output_data += "```rust\n "
271
+ output_data += dump_function (function ) + "\n "
272
+ output_data += "```\n "
273
+ output_file_path = markdown_output_path + "/" + name_mapper [file ["name" ]] + "/function.md"
274
+ print ("Generate" , output_file_path )
275
+ open (output_file_path , "w" ).write (output_data )
276
+
277
+ schema_list = semantic_info ["semantic" ]["schema" ]
278
+ print ("Generate schema documents for" , file_full_path , ":" , len (schema_list ))
279
+ for schema in schema_list :
280
+ output_data = dump_schema (comment_list , schema )
281
+ output_file_path = markdown_output_path + "/" + name_mapper [file ["name" ]] + "/schema/" + schema ["name" ] + ".md"
282
+ open (output_file_path , "w" ).write (output_data )
283
+
284
+ output_data = "---\n "
285
+ output_data += "title: \" schema\" \n "
286
+ output_data += "layout: default\n "
287
+ output_data += "parent: \" coref::" + name_mapper [file ["name" ]] + "\" \n "
288
+ output_data += "grand_parent: \" COREF Library Reference\" \n "
289
+ output_data += "---\n "
290
+ output_data += "# Schema of " + file ["name" ] + "\n \n "
291
+ output_data += dump_schema_tree_view (schema_list )
292
+ output_file_path = markdown_output_path + "/" + name_mapper [file ["name" ]] + "/schema.md"
293
+ open (output_file_path , "w" ).write (output_data )
294
+ print ("Generate schema documents for" , file_full_path , ": Done" )
0 commit comments