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