basic function doc formatting

This commit is contained in:
Allen Webster 2016-06-27 15:45:15 -04:00
parent ed29d04c10
commit 27b93e3474
5 changed files with 1004 additions and 590 deletions

File diff suppressed because it is too large Load Diff

View File

@ -616,7 +616,7 @@ DOC_PARAM(out, the output buffer to fill with the result of the read)
DOC_RETURN(returns non-zero on success) DOC_RETURN(returns non-zero on success)
DOC DOC
( (
The output buffer might have a capacity of at least (end - start) The output buffer must have a capacity of at least (end - start)
The output is not null terminated. The output is not null terminated.
This call fails if the buffer does not exist, or if the read range This call fails if the buffer does not exist, or if the read range

View File

@ -330,6 +330,22 @@ char* generate_style(){
} }
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct Argument_Breakdown{
int count;
String *param_string;
String *param_name;
} Argument_Breakdown;
typedef struct Documentation{
int param_count;
String *param_name;
String *param_docs;
String return_doc;
String main_doc;
int see_also_count;
String *see_also;
} Documentation;
typedef struct Function_Set{ typedef struct Function_Set{
String *name; String *name;
String *ret; String *ret;
@ -340,6 +356,9 @@ typedef struct Function_Set{
String *doc_string; String *doc_string;
int *valid; int *valid;
Argument_Breakdown *breakdown;
Documentation *doc;
} Function_Set; } Function_Set;
void void
@ -419,6 +438,13 @@ chop_whitespace(String str){
return(result); return(result);
} }
String
skip_chop_whitespace(String str){
str = skip_whitespace(str);
str = chop_whitespace(str);
return(str);
}
int int
is_comment(String str){ is_comment(String str){
int result = 0; int result = 0;
@ -456,6 +482,13 @@ check_and_fix_docs(String *lexeme){
return(result); return(result);
} }
enum Doc_Note_Type{
DOC_PARAM,
DOC_RETURN,
DOC,
DOC_SEE
};
static String static String
doc_note_string[] = { doc_note_string[] = {
make_lit_string("DOC_PARAM"), make_lit_string("DOC_PARAM"),
@ -465,28 +498,191 @@ doc_note_string[] = {
}; };
String String
doc_parse_identifier(String lexeme, int *pos){ doc_parse_note(String source, int *pos){
String result = {0}; String result = {0};
int p = *pos;
int start = p;
for (; p < source.size; ++p){
if (source.str[p] == '('){
break;
}
}
if (p != source.size){
result = make_string(source.str + start, p - start);
result = skip_chop_whitespace(result);
}
*pos = p;
return(result); return(result);
} }
String
doc_parse_note_string(String source, int *pos){
String result = {0};
assert(source.str[*pos] == '(');
int p = *pos + 1;
int start = p;
int nest_level = 0;
for (; p < source.size; ++p){
if (source.str[p] == ')'){
if (nest_level == 0){
break;
}
else{
--nest_level;
}
}
else if (source.str[p] == '('){
++nest_level;
}
}
if (p != source.size){
result = make_string(source.str + start, p - start);
result = skip_chop_whitespace(result);
++p;
}
*pos = p;
return(result);
}
String
doc_parse_parameter(String source, int *pos){
String result = {0};
int p = *pos;
int start = p;
for (; p < source.size; ++p){
if (source.str[p] == ','){
break;
}
}
if (p != source.size){
result = make_string(source.str + start, p - start);
result = skip_chop_whitespace(result);
++p;
}
*pos = p;
return(result);
}
String
doc_parse_last_parameter(String source, int *pos){
String result = {0};
int p = *pos;
int start = p;
for (; p < source.size; ++p){
if (source.str[p] == ')'){
break;
}
}
if (p == source.size){
result = make_string(source.str + start, p - start);
result = skip_chop_whitespace(result);
}
*pos = p;
return(result);
}
void void
perform_doc_parse(Parse *parse, String lexeme){ perform_doc_parse(String doc_string, Documentation *doc){
int keep_parsing = true; int keep_parsing = true;
int pos = 0; int pos = 0;
int param_count = 0;
int see_count = 0;
do{ do{
String doc_note = doc_parse_identifier(lexeme, &pos); String doc_note = doc_parse_note(doc_string, &pos);
if (doc_note.size == 0){ if (doc_note.size == 0){
keep_parsing = false; keep_parsing = false;
} }
else{ else{
int doc_note_type; int doc_note_type;
if (string_set_match(doc_note_string, ArrayCount(doc_note_string), doc_note, &doc_note_type)){ if (string_set_match(doc_note_string, ArrayCount(doc_note_string), doc_note, &doc_note_type)){
// TODO(allen): switch on the note type and add the info to the parse data
doc_parse_note_string(doc_string, &pos);
switch (doc_note_type){
case DOC_PARAM:
++param_count;
break;
case DOC_SEE:
++see_count;
break;
}
}
}
}while(keep_parsing);
if (param_count + see_count > 0){
int memory_size = sizeof(String)*(2*param_count + see_count);
doc->param_name = (String*)malloc(memory_size);
doc->param_docs = doc->param_name + param_count;
doc->see_also = doc->param_docs + param_count;
doc->param_count = param_count;
doc->see_also_count = see_count;
}
int param_index = 0;
int see_index = 0;
keep_parsing = true;
pos = 0;
do{
String doc_note = doc_parse_note(doc_string, &pos);
if (doc_note.size == 0){
keep_parsing = false;
}
else{
int doc_note_type;
if (string_set_match(doc_note_string, ArrayCount(doc_note_string), doc_note, &doc_note_type)){
String doc_note_string = doc_parse_note_string(doc_string, &pos);
switch (doc_note_type){
case DOC_PARAM:
{
assert(param_index < param_count);
int param_pos = 0;
String param_name = doc_parse_parameter(doc_note_string, &param_pos);
String param_docs = doc_parse_last_parameter(doc_note_string, &param_pos);
doc->param_name[param_index] = param_name;
doc->param_docs[param_index] = param_docs;
++param_index;
}break;
case DOC_RETURN:
{
doc->return_doc = doc_note_string;
}break;
case DOC:
{
doc->main_doc = doc_note_string;
}break;
case DOC_SEE:
{
assert(see_index < see_count);
doc->see_also[see_index++] = doc_note_string;
}break;
}
} }
else{ else{
// TODO(allen): do warning printf("warning: invalid doc note %.*s\n", doc_note.size, doc_note.str);
} }
} }
}while(keep_parsing); }while(keep_parsing);
@ -501,84 +697,6 @@ generate_custom_headers(){
Function_Set function_set = {0}; Function_Set function_set = {0};
#if 0
// NOTE(allen): Header
String data = file_dump("custom_api_spec.cpp");
int line_count = 0;
String line = {0};
for (line = get_first_line(data);
line.str;
line = get_next_line(data, line)){
++line_count;
}
int max_name_size = 0;
int sig_count = 0;
line_count = 0;
for (line = get_first_line(data);
line.str;
line = get_next_line(data, line)){
++line_count;
String parse = line;
parse = skip_whitespace(parse);
parse = chop_whitespace(parse);
if (parse.size > 0){
if (!is_comment(parse)){
zero_index(function_set, sig_count);
int valid = false;
int pos = find(parse, 0, ' ');
function_set.ret[sig_count] = substr(parse, 0, pos);
parse = substr(parse, pos);
parse = skip_whitespace(parse);
if (parse.size > 0){
pos = find(parse, 0, '(');
String name_string = substr(parse, 0, pos);
function_set.name[sig_count] = chop_whitespace(name_string);
parse = substr(parse, pos);
if (parse.size > 0){
char end = parse.str[parse.size - 1];
valid = true;
switch (end){
case ')':
function_set.args[sig_count] = parse;
break;
case ';':
--parse.size;
function_set.args[sig_count] = parse;
break;
default:
valid = false;
break;
}
function_set.valid[sig_count] = valid;
if (max_name_size < name_string.size){
max_name_size = name_string.size;
}
}
}
if (!valid){
printf("custom_api_spec.cpp(%d) : generator warning : invalid function signature\n",
line_count);
}
++sig_count;
}
}
}
#endif
// NOTE(allen): Documentation // NOTE(allen): Documentation
String code_data[2]; String code_data[2];
code_data[0] = file_dump("4ed_api_implementation.cpp"); code_data[0] = file_dump("4ed_api_implementation.cpp");
@ -633,17 +751,19 @@ generate_custom_headers(){
} }
} }
int total_memory = (sizeof(String)*6 + sizeof(int))*line_count; int memory_size = (sizeof(String)*6 + sizeof(int) + sizeof(Argument_Breakdown) + sizeof(Documentation))*line_count;
function_set.name = (String*)malloc(total_memory); function_set.name = (String*)malloc(memory_size);
function_set.ret = function_set.name + line_count; function_set.ret = function_set.name + line_count;
function_set.args = function_set.ret + line_count; function_set.args = function_set.ret + line_count;
function_set.macros = function_set.args + line_count; function_set.macros = function_set.args + line_count;
function_set.public_name = function_set.macros + line_count; function_set.public_name = function_set.macros + line_count;
function_set.doc_string = function_set.public_name + line_count; function_set.doc_string = function_set.public_name + line_count;
function_set.valid = (int*)(function_set.doc_string + line_count); function_set.valid = (int*)(function_set.doc_string + line_count);
function_set.breakdown = (Argument_Breakdown*)(function_set.valid + line_count);
function_set.doc = (Documentation*)(function_set.breakdown + line_count);
memset(function_set.name, 0, total_memory); memset(function_set.name, 0, memory_size);
int sig_count = 0; int sig_count = 0;
for (int J = 0; J < 2; ++J){ for (int J = 0; J < 2; ++J){
@ -702,6 +822,58 @@ generate_custom_headers(){
function_set.args[sig_count] = function_set.args[sig_count] =
make_string(file.data + args_start_token->start, size); make_string(file.data + args_start_token->start, size);
function_set.valid[sig_count] = true; function_set.valid[sig_count] = true;
int arg_count = 1;
Cpp_Token *arg_token = args_start_token;
for (; arg_token < token; ++arg_token){
if (arg_token->type == CPP_TOKEN_COMMA){
++arg_count;
}
}
Argument_Breakdown *breakdown = &function_set.breakdown[sig_count];
breakdown->count = arg_count;
int memory_size = (sizeof(String)*2)*arg_count;
breakdown->param_string = (String*)malloc(memory_size);
breakdown->param_name = breakdown->param_string + arg_count;
memset(breakdown->param_string, 0, memory_size);
int arg_index = 0;
arg_token = args_start_token + 1;
int param_string_start = arg_token->start;
for (; arg_token <= token; ++arg_token){
if (arg_token->type == CPP_TOKEN_COMMA ||
arg_token->type == CPP_TOKEN_PARENTHESE_CLOSE){
int size = arg_token->start - param_string_start;
String param_string = make_string(file.data + param_string_start, size);
param_string = chop_whitespace(param_string);
breakdown->param_string[arg_index] = param_string;
for (Cpp_Token *param_name_token = arg_token - 1;
param_name_token->start > param_string_start;
--param_name_token){
if (param_name_token->type == CPP_TOKEN_IDENTIFIER){
int start = param_name_token->start;
int size = param_name_token->size;
breakdown->param_name[arg_index] = make_string(file.data + start, size);
break;
}
}
++arg_index;
++arg_token;
if (arg_token <= token){
param_string_start = arg_token->start;
}
--arg_token;
}
}
} }
} }
} }
@ -725,7 +897,6 @@ generate_custom_headers(){
!(token->flags & CPP_TFLAG_PP_BODY)){ !(token->flags & CPP_TFLAG_PP_BODY)){
String lexeme = make_string(file.data + token->start, token->size); String lexeme = make_string(file.data + token->start, token->size);
if (match(lexeme, "API_EXPORT")){ if (match(lexeme, "API_EXPORT")){
for (; i < count; ++i, ++token){ for (; i < count; ++i, ++token){
if (token->type == CPP_TOKEN_PARENTHESE_OPEN){ if (token->type == CPP_TOKEN_PARENTHESE_OPEN){
break; break;
@ -745,7 +916,7 @@ generate_custom_headers(){
lexeme = make_string(file.data + token->start, token->size); lexeme = make_string(file.data + token->start, token->size);
if (check_and_fix_docs(&lexeme)){ if (check_and_fix_docs(&lexeme)){
function_set.doc_string[match] = lexeme; function_set.doc_string[match] = lexeme;
perform_doc_parse(parse, lexeme); perform_doc_parse(lexeme, &function_set.doc[match]);
break; break;
} }
} }
@ -851,9 +1022,11 @@ generate_custom_headers(){
#define CODE_STYLE "font-family: \"Courier New\", Courier, monospace; text-align: left;" #define CODE_STYLE "font-family: \"Courier New\", Courier, monospace; text-align: left;"
#define BACK_COLOR "#FFFFE0" #define BACK_COLOR "#FAFAFA"
#define POP_COLOR_1 "#007000" #define TEXT_COLOR "#0D0D0D"
#define POP_BACK_1 "#E0FFD0" #define CODE_BACK "#DFDFDF"
#define POP_COLOR_1 "#309030"
#define POP_BACK_1 "#E0FFD0"
#define POP_COLOR_2 "#007070" #define POP_COLOR_2 "#007070"
#define POP_COLOR_3 "#005000" #define POP_COLOR_3 "#005000"
@ -865,6 +1038,7 @@ generate_custom_headers(){
"body { " "body { "
"background: " BACK_COLOR "; " "background: " BACK_COLOR "; "
"color: " TEXT_COLOR "; "
"}\n" "}\n"
// H things // H things
@ -873,6 +1047,10 @@ generate_custom_headers(){
"margin: 0; " "margin: 0; "
"}\n" "}\n"
"h4 { "
"font-size: 1.1em; "
"}\n"
// ANCHORS // ANCHORS
"a { " "a { "
"color: " POP_COLOR_1 "; " "color: " POP_COLOR_1 "; "
@ -904,13 +1082,8 @@ generate_custom_headers(){
"</style>\n" "</style>\n"
"</head>\n" "</head>\n"
"<body>\n" "<body>\n"
"<div style='" "<div style='font-family:Arial; margin: 0 auto; "
"font-family:Arial; " "width: 900px; text-align: justify; line-height: 1.25;'>\n"
"position: absolute; "
"left: 10mm; "
"width: 180mm; "
"text-align: justify; "
"line-height: 1.25;'>\n"
"<h1 style='margin-top: 5mm; margin-bottom: 5mm;'>4coder API</h1>\n" "<h1 style='margin-top: 5mm; margin-bottom: 5mm;'>4coder API</h1>\n"
); );
@ -956,33 +1129,106 @@ generate_custom_headers(){
fprintf(file, "<h3 style='margin-top: 5mm; margin-bottom: 5mm;'>&sect;"SECTION" Descriptions</h3>\n"); fprintf(file, "<h3 style='margin-top: 5mm; margin-bottom: 5mm;'>&sect;"SECTION" Descriptions</h3>\n");
for (int i = 0; i < sig_count; ++i){ for (int i = 0; i < sig_count; ++i){
String name = function_set.public_name[i]; String name = function_set.public_name[i];
String ret = function_set.ret[i];
String args = function_set.args[i];
String doc = function_set.doc_string[i];
if (doc.size <= 0){
doc = make_lit_string("No doc generated ~ assume this call is not meant to be public");
printf("warning: missing info for %.*s\n", name.size, name.str);
}
fprintf(file, fprintf(file,
"<div id='%.*s' style='margin-bottom: 1cm;'>\n" "<div id='%.*s_doc' style='margin-bottom: 1cm;'>\n"
" <h4>&sect;"SECTION".%d: %.*s</h4>\n" " <h4>&sect;"SECTION".%d: %.*s</h4>\n"
" <div style='"CODE_STYLE" margin-top: 3mm; margin-bottom: 3mm; font-size: .95em;'>", " <div style='"CODE_STYLE" margin-top: 3mm; margin-bottom: 3mm; font-size: .95em; "
"background: "CODE_BACK"; padding: 0.25em;'>",
name.size, name.str, i, name.size, name.str, i,
name.size, name.str name.size, name.str
); );
fprintf(file, "%.*s %.*s", ret.size, ret.str, name.size, name.str); String ret = function_set.ret[i];
// TODO(allen): replace this with a loop to write each parameter on it's own line fprintf(file,
fprintf(file, "%.*s", args.size, args.str); "%.*s %.*s(\n"
"<div style='margin-left: 4mm;'>",
ret.size, ret.str, name.size, name.str);
fprintf(file, Argument_Breakdown *breakdown = &function_set.breakdown[i];
"</div>\n" int arg_count = breakdown->count;
" <div>%.*s</div>\n" for (int j = 0; j < arg_count; ++j){
"</div>\n", String param_string = breakdown->param_string[j];
doc.size, doc.str if (j < arg_count - 1){
); fprintf(file, "%.*s,<br>", param_string.size, param_string.str);
}
else{
fprintf(file, "%.*s<br>", param_string.size, param_string.str);
}
}
fprintf(file,
"</div>)\n"
"</div>\n");
if (function_set.doc_string[i].size == 0){
fprintf(file, "No documentation generated for this function, assume it is non-public.\n");
printf("warning: no documentation string for %.*s\n", name.size, name.str);
}
#define DOC_HEAD_OPEN "<div style='margin-top: 3mm; margin-bottom: 3mm; color: "POP_COLOR_1";'><b><i>"
#define DOC_HEAD_CLOSE "</i></b></div>"
#define DOC_ITEM_OPEN "<div style='margin-left: 5mm; margin-right: 5mm;'>"
#define DOC_ITEM_CLOSE "</div>"
Documentation *doc = &function_set.doc[i];
int doc_param_count = doc->param_count;
if (doc_param_count > 0){
fprintf(file, DOC_HEAD_OPEN"Parameters"DOC_HEAD_CLOSE);
for (int j = 0; j < doc_param_count; ++j){
String param_name = doc->param_name[j];
String param_docs = doc->param_docs[j];
// TODO(allen): check that param_name is actually
// a parameter to this function!
fprintf(file,
"<div>\n"
"<div style='font-weight: 600;'>%.*s</div>\n"
"<div style='margin-bottom: 6mm;'>"DOC_ITEM_OPEN"%.*s"DOC_ITEM_CLOSE"</div>\n"
"</div>\n",
param_name.size, param_name.str,
param_docs.size, param_docs.str
);
}
}
String ret_doc = doc->return_doc;
if (ret_doc.size != 0){
fprintf(file, DOC_HEAD_OPEN"Return"DOC_HEAD_CLOSE);
fprintf(file,
DOC_ITEM_OPEN"%.*s"DOC_ITEM_CLOSE,
ret_doc.size, ret_doc.str
);
}
String main_doc = doc->main_doc;
if (main_doc.size != 0){
fprintf(file, DOC_HEAD_OPEN"Description"DOC_HEAD_CLOSE);
fprintf(file,
DOC_ITEM_OPEN"%.*s"DOC_ITEM_CLOSE,
main_doc.size, main_doc.str
);
}
int doc_see_count = doc->see_also_count;
if (doc_see_count > 0){
fprintf(file, DOC_HEAD_OPEN"See Also"DOC_HEAD_CLOSE);
for (int j = 0; j < doc_see_count; ++j){
String see_also = doc->see_also[j];
fprintf(file,
DOC_ITEM_OPEN"<a href='#%.*s_doc'>%.*s</a>"DOC_ITEM_CLOSE,
see_also.size, see_also.str,
see_also.size, see_also.str
);
}
}
fprintf(file, "</div><hr>\n");
} }
} }

View File

@ -1,14 +1,5 @@
@echo off @echo off
pushd ..\meta
REM cl %OPTS% ..\code\4ed_metagen.cpp /Zi /Femetagen
popd
pushd ..\code
REM "..\meta\metagen"
popd
REM "build_exp.bat" /Zi REM "build_exp.bat" /Zi
"build_all.bat" /DFRED_SUPER /DFRED_INTERNAL /Zi "build_all.bat" /DFRED_SUPER /DFRED_INTERNAL /Zi
REM "build_all.bat" /O2 /Zi REM "build_all.bat" /O2 /Zi

View File

@ -24,20 +24,20 @@ popd
pushd ..\build pushd ..\build
REM call "..\code\buildsuper.bat" ..\code\4coder_default_bindings.cpp REM call "..\code\buildsuper.bat" ..\code\4coder_default_bindings.cpp
call "..\code\buildsuper.bat" ..\code\power\4coder_experiments.cpp REM call "..\code\buildsuper.bat" ..\code\power\4coder_experiments.cpp
REM call "..\code\buildsuper.bat" ..\code\power\4coder_casey.cpp REM call "..\code\buildsuper.bat" ..\code\power\4coder_casey.cpp
REM call "..\code\buildsuper.bat" ..\4vim\4coder_chronal.cpp REM call "..\code\buildsuper.bat" ..\4vim\4coder_chronal.cpp
if %ERRORLEVEL% neq 0 (set FirstError=1) if %ERRORLEVEL% neq 0 (set FirstError=1)
set EXPORTS=/EXPORT:app_get_functions set EXPORTS=/EXPORT:app_get_functions
cl %OPTS% %INCLUDES% %DEFINES% ..\code\4ed_app_target.cpp %* /Fe4ed_app /LD /link /INCREMENTAL:NO /OPT:REF %EXPORTS% REM cl %OPTS% %INCLUDES% %DEFINES% ..\code\4ed_app_target.cpp %* /Fe4ed_app /LD /link /INCREMENTAL:NO /OPT:REF %EXPORTS%
if %ERRORLEVEL% neq 0 (set FirstError=1) if %ERRORLEVEL% neq 0 (set FirstError=1)
cl %OPTS% %INCLUDES% %DEFINES% ..\code\win32_4ed.cpp %LIBS% %ICON% %* /Fe4ed /link /NODEFAULTLIB:library REM cl %OPTS% %INCLUDES% %DEFINES% ..\code\win32_4ed.cpp %LIBS% %ICON% %* /Fe4ed /link /NODEFAULTLIB:library
if %ERRORLEVEL% neq 0 (set FirstError=1) if %ERRORLEVEL% neq 0 (set FirstError=1)
call "print_size.bat" 4ed_app.dll REM call "print_size.bat" 4ed_app.dll
call "print_size.bat" 4ed.exe REM call "print_size.bat" 4ed.exe
popd popd