q66 pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=c26134df7a43292e2dedee26da8aa62415528657
commit c26134df7a43292e2dedee26da8aa62415528657 Author: Daniel Kolesa <d.kol...@osg.samsung.com> Date: Tue Jun 23 15:28:46 2015 +0100 eolian: new doc token lexer/parser This should allow us to more easily extend the format if desired and overall makes the doc syntax parsing more readable and simpler. --- src/lib/eolian/eo_lexer.c | 269 +++++++++++++++++++++------------------------- 1 file changed, 124 insertions(+), 145 deletions(-) diff --git a/src/lib/eolian/eo_lexer.c b/src/lib/eolian/eo_lexer.c index ac59c6d..24d7080 100644 --- a/src/lib/eolian/eo_lexer.c +++ b/src/lib/eolian/eo_lexer.c @@ -252,185 +252,164 @@ cend: if (tok) tok->value.s = eina_stringshare_add(eina_strbuf_string_get(ls->buff)); } -void doc_error(Eo_Lexer *ls, const char *msg, Eolian_Documentation *doc, Eina_Strbuf *buf) -{ - eina_stringshare_del(doc->summary); - eina_stringshare_del(doc->description); - free(doc); - eina_strbuf_free(buf); - eo_lexer_lex_error(ls, msg, -1); -} +enum Doc_Tokens { + DOC_MANGLED = -2, DOC_UNFINISHED = -1, DOC_TEXT = 0, DOC_SINCE = 1 +}; -static void -read_doc(Eo_Lexer *ls, Eo_Token *tok, int line, int column) +static int +doc_lex(Eo_Lexer *ls, Eina_Bool *term, Eina_Bool allow_since) { - Eolian_Documentation *doc = calloc(1, sizeof(Eolian_Documentation)); - doc->base.file = ls->filename; - doc->base.line = line; - doc->base.column = column; - + Eina_Bool contdoc = EINA_FALSE; eina_strbuf_reset(ls->buff); - - skip_ws(ls); - while (is_newline(ls->current)) - next_line_ws(ls); - - for (;;) + for (;; contdoc = EINA_TRUE) switch (ls->current) { - if (!ls->current) + /* error case */ + case '\0': + return DOC_UNFINISHED; + /* newline case: if two or more newlines are present, new paragraph + * if only one newline is present, append space to the text buffer + * when starting new paragraph, reset doc continutation + */ + case '\n': + case '\r': + next_line(ls); + skip_ws(ls); + if (!is_newline(ls->current)) { - doc_error(ls, "unfinished documentation", doc, NULL); - return; /* unreachable, for static analysis */ + eina_strbuf_append_char(ls->buff, ' '); + continue; } - if (is_newline(ls->current)) + while (is_newline(ls->current)) + next_line_ws(ls); + eina_strbuf_trim(ls->buff); + return DOC_TEXT; + /* escape case: for any \X, output \X + * except for \\]], then output just ]] + */ + case '\\': + next_char(ls); + if (ls->current == ']') { - next_line_ws(ls); - if (is_newline(ls->current)) + next_char(ls); + if (ls->current == ']') { - while (is_newline(ls->current)) - next_line_ws(ls); - break; + next_char(ls); + eina_strbuf_append(ls->buff, "]]"); } else - eina_strbuf_append_char(ls->buff, ' '); + eina_strbuf_append(ls->buff, "\\]"); } else + eina_strbuf_append_char(ls->buff, '\\'); + continue; + /* terminating case */ + case ']': + next_char(ls); + if (ls->current == ']') { - if (ls->current == ']') - { - next_char(ls); - if (ls->current != ']') - eina_strbuf_append_char(ls->buff, ']'); - else - { - next_char(ls); - eina_strbuf_trim(ls->buff); - doc->summary = eina_stringshare_add( - eina_strbuf_string_get(ls->buff)); - tok->value.doc = doc; - return; - } - } - eina_strbuf_append_char(ls->buff, ls->current); + /* terminate doc */ next_char(ls); + *term = EINA_TRUE; + eina_strbuf_trim(ls->buff); + return DOC_TEXT; } - } - - eina_strbuf_trim(ls->buff); - doc->summary = eina_stringshare_add(eina_strbuf_string_get(ls->buff)); - - Eina_Strbuf *rbuf = eina_strbuf_new(); - Eina_Bool had_nl = EINA_TRUE; - - for (;;) - { - if (!ls->current) + eina_strbuf_append_char(ls->buff, ']'); + continue; + /* @since case - only when starting a new paragraph */ + case '@': + eina_strbuf_append_char(ls->buff, '@'); + next_char(ls); + while (ls->current && isalpha(ls->current)) { - doc_error(ls, "unfinished documentation", doc, rbuf); - return; /* unreachable, for static analysis */ + eina_strbuf_append_char(ls->buff, ls->current); + next_char(ls); } - - eina_strbuf_reset(ls->buff); - - if (had_nl && ls->current == '@') + if (contdoc) + continue; + if (!strcmp(eina_strbuf_string_get(ls->buff), "@since")) { -#define LEX_SINCE(c, failure) \ - next_char(ls); \ - if (ls->current != c) \ - { \ - eina_strbuf_append(ls->buff, failure); \ - goto normal; \ - } - - LEX_SINCE('s', "@"); - LEX_SINCE('i', "@s"); - LEX_SINCE('n', "@si"); - LEX_SINCE('c', "@sin"); - LEX_SINCE('e', "@sinc"); - LEX_SINCE(' ', "@since"); - -#undef LEX_SINCE - + /* since-token */ + if (!allow_since) + return DOC_MANGLED; + *term = EINA_TRUE; + eina_strbuf_reset(ls->buff); skip_ws(ls); - - /* gotta have a value */ - if (!ls->current || is_newline(ls->current) || ls->current == ']') - goto docerr; - - /* append the since string */ - while (ls->current && ls->current != ']' && !is_newline(ls->current)) + while (ls->current && (ls->current == '.' || + ls->current == '_' || + isalnum(ls->current))) { eina_strbuf_append_char(ls->buff, ls->current); next_char(ls); } + if (!eina_strbuf_length_get(ls->buff)) + return DOC_UNFINISHED; + skip_ws(ls); + while (is_newline(ls->current)) + next_line_ws(ls); + if (ls->current == ']') + next_char(ls); + if (ls->current != ']') + return DOC_MANGLED; + next_char(ls); + eina_strbuf_trim(ls->buff); + return DOC_SINCE; + } + /* default case - append character */ + default: + eina_strbuf_append_char(ls->buff, ls->current); + next_char(ls); + continue; + } +} - /* trigger "unfinished documentation" if things end early */ - if (!ls->current) - continue; - - /* strip final whitespace */ - while (isspace(ls->current)) - { - if (is_newline(ls->current)) - next_line(ls); - else - next_char(ls); - } +void doc_error(Eo_Lexer *ls, const char *msg, Eolian_Documentation *doc, Eina_Strbuf *buf) +{ + eina_stringshare_del(doc->summary); + eina_stringshare_del(doc->description); + free(doc); + eina_strbuf_free(buf); + eo_lexer_lex_error(ls, msg, -1); +} - if (ls->current != ']') goto docerr; - next_char(ls); - if (ls->current != ']') goto docerr; - next_char(ls); +static void +read_doc(Eo_Lexer *ls, Eo_Token *tok, int line, int column) +{ + Eolian_Documentation *doc = calloc(1, sizeof(Eolian_Documentation)); + doc->base.file = ls->filename; + doc->base.line = line; + doc->base.column = column; - eina_strbuf_trim(ls->buff); - doc->since = eina_stringshare_add(eina_strbuf_string_get(ls->buff)); + Eina_Strbuf *rbuf = eina_strbuf_new(); - goto done; -docerr: + Eina_Bool term = EINA_FALSE; + while (!term) + { + int read = doc_lex(ls, &term, !!doc->summary); + switch (read) + { + case DOC_MANGLED: doc_error(ls, "mangled documentation", doc, rbuf); return; - } - -normal: - had_nl = EINA_FALSE; - while (ls->current && !is_newline(ls->current)) - { - if (ls->current == ']') + case DOC_UNFINISHED: + doc_error(ls, "unfinished documentation", doc, rbuf); + return; + case DOC_TEXT: + if (!doc->summary) + doc->summary = eina_stringshare_add(eina_strbuf_string_get(ls->buff)); + else { - next_char(ls); - if (ls->current != ']') - eina_strbuf_append_char(ls->buff, ']'); - else - { - next_char(ls); - eina_strbuf_trim(ls->buff); - eina_strbuf_append(rbuf, eina_strbuf_string_get(ls->buff)); - goto done; - } + if (eina_strbuf_length_get(rbuf)) + eina_strbuf_append(rbuf, "\n\n"); + eina_strbuf_append(rbuf, eina_strbuf_string_get(ls->buff)); } - eina_strbuf_append_char(ls->buff, ls->current); - next_char(ls); - } - eina_strbuf_trim(ls->buff); - eina_strbuf_append(rbuf, eina_strbuf_string_get(ls->buff)); - - if (is_newline(ls->current)) - { - next_line_ws(ls); - /* new paragraph */ - if (is_newline(ls->current)) - eina_strbuf_append(rbuf, "\n\n"); - else - eina_strbuf_append_char(rbuf, ' '); - while (is_newline(ls->current)) - next_line_ws(ls); - had_nl = EINA_TRUE; + break; + case DOC_SINCE: + doc->since = eina_stringshare_add(eina_strbuf_string_get(ls->buff)); + break; } } -done: - eina_strbuf_trim(rbuf); - if (eina_strbuf_string_get(rbuf)[0]) + if (eina_strbuf_length_get(rbuf)) doc->description = eina_stringshare_add(eina_strbuf_string_get(rbuf)); eina_strbuf_free(rbuf); tok->value.doc = doc; --