1let Categories := {} 2let OutputDirectory := Args[1] 3 4for FileName in dir(OutputDirectory) do 5 if FileName[-4, 0] = ".rst" then 6 print('Unlinking {FileName}\n') 7 file::unlink(OutputDirectory + "/" + FileName) 8 end 9end 10 11fun category_name(Type) do 12 if Type:find("State") then 13 ret "internal" 14 elseif let Match := Type % r"^ML(.*)T$" then 15 ret Match[2]:lower 16 else 17 ret Type 18 end 19end 20 21fun write_category(Category) do 22 print('Creating Category: {Category}\n') 23 let File := file('{OutputDirectory}/{Category:lower}.rst', "w") 24 File:write(Category, "\n") 25 for I in Category do File:write("=") end 26 File:write("\n\n") 27 File:write(".. include:: <isonum.txt>\n\n") 28 ret File 29end 30 31fun type_name(Type) do 32 Type or ret "any" 33 if let Match := Type % r"^ML(.*)T$" then 34 ret Match[2]:lower 35 else 36 ret Type 37 end 38end 39 40fun is_symbol(Method) (Method = "\"<op>\"") or (Method:lower = Method:upper) 41 42fun write_method(Category, Kind, Method, Params, Return, Description, Location) do 43 :<print('[{Category}] {Kind}: {Method}\n') 44 print("Params:\n") 45 for Param in Params do print('\t{Param}\n') end 46 print('Returns: {Return}\n') 47 print('Description: {Description}\n\n')>: 48 49 let File := Categories[Category, write_category] 50 let Title := stringbuffer() 51 52 var Terminator := "" 53 var Skip := 1 54 Title:write(':mini:`meth ') 55 if Method = "\"[]\"" then 56 Title:write("(", Params[1][1], ": ", type_name(Params[1][2]), ")[") 57 Terminator := "]" 58 :<elseif Method[1] = "\"" then 59 if Params:length = 1 and is_symbol(Method) then 60 Title:write('{Method[2, -1]}(', Params[1][1], ": ", type_name(Params[1][2]), ")") 61 else 62 Title:write("(", Params[1][1], ": ", type_name(Params[1][2]), ")") 63 if is_symbol(Method) then 64 Title:write(' {Method[2, -1]} ') 65 else 66 Title:write(':{Method[2, -1]}') 67 if Params:length > 1 then 68 Title:write("(") 69 Terminator := ")" 70 end 71 end 72 end>: 73 else 74 if let Match := Method % r"ML(\w+)T" then 75 Title:write('{Match[2]:lower}(') 76 elseif Method[1] = "\"" then 77 if is_symbol(Method) then 78 Title:write('{Method[2, -1]}(') 79 else 80 Title:write(':{Method[2, -1]}(') 81 end 82 else 83 Title:write('{Method}(') 84 end 85 Skip := 0 86 Terminator := ")" 87 end 88 var Seperator := "" 89 for Param in Params skip Skip do 90 Title:write(Seperator, Param[1], ": ", type_name(Param[2])) 91 Seperator := ", " 92 end 93 Title:write(Terminator, "`") 94 if Return:length > 0 then 95 Title:write(" |rarr| :mini:`", type_name(Return[1]), "`") 96 for Type in Return skip 1 do 97 Title:write(" or :mini:`", type_name(Type), "`") 98 end 99 end 100 let TitleString := Title:get 101 File:write(TitleString, "\n") 102 for Line in Description do 103 File:write(" ", Line, "\n") 104 end 105 for Param in Params do 106 if Param[3]:length > 0 then 107 File:write(" :", type_name(Param[2]), " ", Param[1], ": ", Param[3], "\n") 108 end 109 end 110 :>File:write(' *Defined at line {Location[2]} in {Location[1]}*\n') 111 File:write("\n") 112end 113 114fun write_function(Category, Kind, Name, Params, Return, Description, Location) do 115 :<print('[{Category}] {Kind}: {Name}\n') 116 print("Params:\n") 117 for Param in Params do print('\t{Param}\n') end 118 print('Returns: {Return}\n') 119 print('Description: {Description}\n')>: 120 121 let File := Categories[Category, write_category] 122 let Title := stringbuffer() 123 124 var Terminator := "" 125 Title:write(':mini:`fun ', Name, "(") 126 var Seperator := "" 127 for Param in Params do 128 Title:write(Seperator, Param[1], ": ", type_name(Param[2])) 129 Seperator := ", " 130 end 131 Title:write(")`") 132 if Return:length > 0 then 133 Title:write(" |rarr| :mini:`", type_name(Return[1]), "`") 134 for Type in Return skip 1 do 135 Title:write(" or :mini:`", type_name(Type), "`") 136 end 137 end 138 let TitleString := Title:get 139 File:write(TitleString, "\n") 140 for Line in Description do 141 File:write(" ", Line, "\n") 142 end 143 for Param in Params do 144 if Param in method then 145 elseif Param[3]:length > 0 then 146 File:write(" :", type_name(Param[2]), " ", Param[1], ": ", Param[3], "\n") 147 end 148 end 149 :>File:write(' *Defined at line {Location[2]} in {Location[1]}*\n') 150 File:write("\n") 151end 152 153fun write_constructor(Category, Kind, Name, Params, Return, Description, Location) do 154 :<print('[{Category}] {Kind}: {Name}\n') 155 print("Params:\n") 156 for Param in Params do print('\t{Param}\n') end 157 print('Returns: {Return}\n') 158 print('Description: {Description}\n')>: 159 160 let File := Categories[Category, write_category] 161 let Title := stringbuffer() 162 163 var Terminator := "" 164 Title:write(':mini:`constructor ', Name, "(") 165 var Seperator := "" 166 for Param in Params do 167 Title:write(Seperator, Param[1], ": ", type_name(Param[2])) 168 Seperator := ", " 169 end 170 Title:write(")`") 171 if Return:length > 0 then 172 Title:write(" |rarr| :mini:`", type_name(Return[1]), "`") 173 for Type in Return skip 1 do 174 Title:write(" or :mini:`", type_name(Type), "`") 175 end 176 end 177 let TitleString := Title:get 178 File:write(TitleString, "\n") 179 for Line in Description do 180 File:write(" ", Line, "\n") 181 end 182 for Param in Params do 183 if Param in method then 184 elseif Param[3]:length > 0 then 185 File:write(" :", type_name(Param[2]), " ", Param[1], ": ", Param[3], "\n") 186 end 187 end 188 :>File:write(' *Defined at line {Location[2]} in {Location[1]}*\n') 189 File:write("\n") 190end 191 192fun write_type(Category, Name, Parents, Description, Location) do 193 :<print('[{Category}] ML_TYPE: {Name} [{Parents}]\n') 194 print('Description: {Description}\n')>: 195 196 let File := Categories[Category, write_category] 197 let Title := stringbuffer() 198 199 Title:write(':mini:`type {type_name(Name)}') 200 if Parents:length > 0 then 201 Title:write(" < ") 202 var Seperator := "" 203 for Parent in Parents do 204 Title:write(Seperator, type_name(Parent)) 205 Seperator := ", " 206 end 207 end 208 Title:write("`\n") 209 File:write(Title:get) 210 for Line in Description do 211 File:write(" ", Line, "\n") 212 end 213 :>File:write(' *Defined at line {Location[2]} in {Location[1]}*\n') 214 File:write("\n") 215end 216 217def Subscripts := { 218 "/0" is "₀", "/1" is "₁", "/2" is "₂", "/3" is "₃", "/4" is "₄", 219 "/5" is "₅", "/6" is "₆", "/7" is "₇", "/8" is "₈", "/9" is "₉", 220 "/i" is "ᵢ", "/j" is "ⱼ", "/m" is "ₘ", "/n" is "ₙ" 221} 222 223fun process(FileName) do 224 let File := file(FileName, 'r') 225 var DefaultCategory := "general" 226 if let Match := FileName % r"ml_([a-z]+).c" then 227 DefaultCategory := Match[2] 228 end 229 var LineNo := 0 230 loop 231 let Line := while File:read 232 :>print('{LineNo}: {Line}') 233 LineNo := old + 1 234 do 235 if Line % r"//!" then 236 DefaultCategory := Line[4, 0]:trim 237 elseif Line % r"^ML_METHOD_DECL" then 238 elseif Line % r"^ML_METHOD_ANON" then 239 elseif Line % r"^ML_METHOD" then 240 let Location := (FileName, LineNo) 241 let I := Line:find("("), J := Line:find(")") 242 let Kind := Line[1, I] 243 let Types := Line[I + 1, J] / ", " 244 var Method := Types:pop 245 var Category := DefaultCategory 246 let Params := [] 247 var Return := [] 248 let Description := [] 249 loop 250 let Line := while File:read 251 LineNo := old + 1 252 if Line % r"//@" then 253 Method := Line[4, 0]:trim 254 elseif Line % r"^//<" then 255 if let J := Line:find(":", 4) then 256 let K := Line:find(" ", J + 2) or 0 257 Params:put(( 258 Line[4, J]:trim:replace(Subscripts), 259 Line[J + 1, K]:trim, 260 Line[K, 0]:trim 261 )) 262 else 263 let J := Line:find(" ", 4) or 0 264 Params:put(( 265 Line[4, J]:trim:replace(Subscripts), 266 Types:pop, 267 Line[J, 0]:trim 268 )) 269 end 270 elseif Line % r"^//>" then 271 Return := list(Line[4, 0] / "|", :trim, :replace(_, Subscripts)) 272 elseif Line % r"^//!" then 273 Category := Line[4, 0]:trim 274 elseif Line % r"^// " then 275 Description:put(Line[4, 0]:replace(Subscripts)) 276 else 277 exit 278 end 279 end 280 for Type in Types do 281 Params:put(('Arg/{Params:length + 1}':replace(Subscripts), Type, "")) 282 end 283 write_method(Category, Kind, Method, Params, Return, Description, Location) 284 elseif Line % r"^MATH_REAL" then 285 let Location := (FileName, LineNo) 286 let I := Line:find("("), J := Line:find(")") 287 let Kind := Line[1, I] 288 let Types := ["number"] 289 let Method := (Line[I + 1, J] / ", ")[2] 290 var Category := "math" 291 let Params := [] 292 var Return := [] 293 let Description := [] 294 Params:put(( 295 "Arg/1":trim:replace(Subscripts), 296 "number", 297 "" 298 )) 299 if Kind = "MATH_REAL_REAL" then 300 Params:put(( 301 "Arg/2":trim:replace(Subscripts), 302 "number", 303 "" 304 )) 305 end 306 Return := ["number"] 307 write_method(Category, Kind, Method, Params, Return, Description, Location) 308 elseif Line % r"^ML_FUNCTION" then 309 let Location := (FileName, LineNo) 310 let I := Line:find("("), J := Line:find(")") 311 let Kind := Line[1, I] 312 var Name := Line[I + 1, J]:lower 313 var Category := DefaultCategory 314 let Params := [] 315 var Return := [] 316 let Description := [] 317 loop 318 let Line := while File:read 319 LineNo := old + 1 320 if Line % r"//@" then 321 Name := Line[4, 0]:trim 322 elseif Line % r"^//<" then 323 if let J := Line:find(":", 4) then 324 let K := Line:find(" ", J + 2) or 0 325 Params:put([ 326 Line[4, J]:trim:replace(Subscripts), 327 Line[J + 1, K]:trim, 328 Line[K, 0]:trim 329 ]) 330 else 331 let J := Line:find(" ", 4) or 0 332 Params:put([ 333 Line[4, J]:trim:replace(Subscripts), 334 "MLAnyT", 335 Line[J, 0]:trim 336 ]) 337 end 338 elseif Line % r"^//>" then 339 Return := list(Line[4, 0] / "|", :trim, :replace(_, Subscripts)) 340 elseif Line % r"^//!" then 341 Category := Line[4, 0]:trim 342 elseif Line % r"^// " then 343 Description:put(Line[4, 0]:replace(Subscripts)) 344 elseif let Match := Line % r"ML_CHECK(X?)_ARG_COUNT\(([0-9]+)\)" then 345 let Count := integer(Match[3]) 346 for I in (Params:length + 1) .. Count do 347 Params:put(['Arg/{I}':replace(Subscripts), "any", ""]) 348 end 349 elseif let Match := Line % r"ML_CHECK(X?)_ARG_TYPE\(([0-9]+), (\w+)\)" then 350 let Index := integer(Match[3]) + 1 351 Params[Index][2] := type_name(Match[4]) 352 else 353 exit 354 end 355 end 356 write_function(Category, Kind, Name, Params, Return, Description, Location) 357 elseif Line % r"^ML_CONSTRUCTOR" then 358 let Location := (FileName, LineNo) 359 let I := Line:find("("), J := Line:find(")") 360 let Kind := Line[1, I] 361 var Name := Line[I + 1, J]:lower 362 var Category := DefaultCategory 363 let Params := [] 364 let Description := [] 365 loop 366 let Line := while File:read 367 LineNo := old + 1 368 if Line % r"//@" then 369 Name := Line[4, 0]:trim 370 elseif Line % r"^//<" then 371 if let J := Line:find(":", 4) then 372 let K := Line:find(" ", J + 2) or 0 373 Params:put([ 374 Line[4, J]:trim:replace(Subscripts), 375 Line[J + 1, K]:trim, 376 Line[K, 0]:trim 377 ]) 378 else 379 let J := Line:find(" ", 4) or 0 380 Params:put([ 381 Line[4, J]:trim:replace(Subscripts), 382 "MLAnyT", 383 Line[J, 0]:trim 384 ]) 385 end 386 elseif Line % r"^//!" then 387 Category := Line[4, 0]:trim 388 elseif Line % r"^// " then 389 Description:put(Line[4, 0]:replace(Subscripts)) 390 else 391 exit 392 end 393 end 394 write_constructor(Category, Kind, Name, Params, [Name], Description, Location) 395 elseif Line % r"^(ML_TYPE|ML_INTERFACE)" then 396 let Location := (FileName, LineNo) 397 let I := Line:find("("), J := Line:find("(", I + 1) 398 let K := Line:find(")", J + 1) 399 var Name := Line[I + 1, J]:trim(", ") 400 var Category := DefaultCategory 401 let Parents := Line[J + 1, K] / ", " 402 let Title := Line[K + 1, 0]:trim(", ){") 403 let Description := [] 404 loop 405 let Line := while File:read 406 LineNo := old + 1 407 if Line % r"//@" then 408 Name := Line[4, 0]:trim 409 elseif Line % r"^//!" then 410 Category := Line[4, 0]:trim 411 elseif Line % r"^// " then 412 Description:put(Line[4, 0]:replace(Subscripts)) 413 else 414 exit 415 end 416 end 417 write_type(Category, Name, Parents, Description, Location) 418 elseif Line % r"^#define " then 419 loop 420 let Line := while File:read 421 LineNo := old + 1 422 until Line = "\n" 423 end 424 end 425 on Error do 426 print(Line, "\n") 427 print('Error: {Error:message} in {FileName}:{LineNo}\n') 428 for Source in Error:trace do 429 print('\t{Source[1]}:{Source[2]}\n') 430 end 431 end 432 end 433 File:close 434end 435 436let FileNames := list(Args skip 1) 437FileNames:sort(; A, B) do 438 A = "ml_types.c" and ret A 439 B = "ml_types.c" and ret nil 440end 441 442for FileName in FileNames do process(FileName) end 443 444for Category, File in Categories do File:close end 445