2014-09-23 12:48:16 -07:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2014-03-29 21:07:19 -07:00
|
|
|
#include <stdio.h>
|
2014-06-18 03:25:07 -07:00
|
|
|
#include <ctype.h>
|
2015-06-25 02:43:54 -07:00
|
|
|
#include <locale.h>
|
2014-06-18 03:25:07 -07:00
|
|
|
|
|
|
|
#include <setjmp.h>
|
|
|
|
#include <assert.h>
|
2014-03-29 21:07:19 -07:00
|
|
|
|
|
|
|
#include "eo_lexer.h"
|
2017-10-30 22:20:09 -07:00
|
|
|
#include "eolian_priv.h"
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2014-07-02 15:39:35 -07:00
|
|
|
static int lastbytes = 0;
|
|
|
|
|
|
|
|
static void
|
|
|
|
next_char(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
int nb;
|
2014-07-02 16:04:30 -07:00
|
|
|
Eina_Bool end = EINA_FALSE;
|
2014-07-02 15:39:35 -07:00
|
|
|
|
2014-06-20 02:45:55 -07:00
|
|
|
if (ls->stream == ls->stream_end)
|
2014-07-02 16:04:30 -07:00
|
|
|
{
|
|
|
|
end = EINA_TRUE;
|
|
|
|
ls->current = '\0';
|
|
|
|
}
|
2014-06-20 02:45:55 -07:00
|
|
|
else
|
|
|
|
ls->current = *(ls->stream++);
|
2014-07-02 15:39:35 -07:00
|
|
|
|
|
|
|
nb = lastbytes;
|
2014-07-02 16:04:30 -07:00
|
|
|
if (!nb && end) nb = 1;
|
|
|
|
if (!nb) eina_unicode_utf8_next_get(ls->stream - 1, &nb);
|
2014-07-02 15:39:35 -07:00
|
|
|
|
|
|
|
if (nb == 1)
|
|
|
|
{
|
|
|
|
nb = 0;
|
2014-07-02 16:14:28 -07:00
|
|
|
++ls->icolumn;
|
|
|
|
ls->column = ls->icolumn;
|
2014-07-02 15:39:35 -07:00
|
|
|
}
|
|
|
|
else --nb;
|
|
|
|
|
|
|
|
lastbytes = nb;
|
2014-06-20 02:45:55 -07:00
|
|
|
}
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
#define KW(x) #x
|
|
|
|
#define KWAT(x) "@" #x
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
static const char * const tokens[] =
|
|
|
|
{
|
2014-07-18 03:48:40 -07:00
|
|
|
"==", "!=", ">=", "<=", "&&", "||", "<<", ">>",
|
2015-09-21 07:26:41 -07:00
|
|
|
"<doc>", "<string>", "<char>", "<number>", "<value>"
|
2014-06-18 03:25:07 -07:00
|
|
|
};
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2015-09-21 07:26:41 -07:00
|
|
|
static const char * const keywords[] = { KEYWORDS };
|
|
|
|
|
2014-06-26 04:02:19 -07:00
|
|
|
static const char * const ctypes[] =
|
|
|
|
{
|
2014-07-14 08:25:26 -07:00
|
|
|
"signed char", "unsigned char", "char", "short", "unsigned short", "int",
|
|
|
|
"unsigned int", "long", "unsigned long", "long long", "unsigned long long",
|
2014-06-26 06:11:52 -07:00
|
|
|
|
|
|
|
"int8_t", "uint8_t", "int16_t", "uint16_t", "int32_t", "uint32_t",
|
|
|
|
"int64_t", "uint64_t", "int128_t", "uint128_t",
|
|
|
|
|
2014-07-14 08:51:38 -07:00
|
|
|
"size_t", "ssize_t", "intptr_t", "uintptr_t", "ptrdiff_t",
|
|
|
|
|
2014-07-14 09:02:58 -07:00
|
|
|
"time_t",
|
|
|
|
|
2014-08-18 05:12:08 -07:00
|
|
|
"float", "double",
|
2014-06-26 06:11:52 -07:00
|
|
|
|
2014-07-11 06:40:14 -07:00
|
|
|
"Eina_Bool",
|
|
|
|
|
2014-09-08 06:52:49 -07:00
|
|
|
"void",
|
|
|
|
|
2017-09-22 08:46:02 -07:00
|
|
|
"Eina_Accessor *", "Eina_Array *", "Eina_Iterator *", "Eina_Hash *",
|
2017-11-23 16:46:55 -08:00
|
|
|
"Eina_List *", "Eina_Inarray *", "Eina_Inlist *",
|
2017-09-22 08:46:02 -07:00
|
|
|
"Efl_Future *",
|
2017-09-22 11:25:31 -07:00
|
|
|
"Eina_Value", "Eina_Value *",
|
2017-11-21 22:44:06 -08:00
|
|
|
"char *", "const char *", "Eina_Stringshare *", "Eina_Strbuf *",
|
2016-05-26 06:36:41 -07:00
|
|
|
|
|
|
|
"void *",
|
2015-05-29 04:03:57 -07:00
|
|
|
|
2016-06-29 15:25:22 -07:00
|
|
|
"Eina_Free_Cb",
|
2017-04-07 09:54:55 -07:00
|
|
|
"function",
|
2014-06-26 04:02:19 -07:00
|
|
|
};
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
#undef KW
|
|
|
|
#undef KWAT
|
2014-04-03 06:20:58 -07:00
|
|
|
|
2014-07-02 16:30:39 -07:00
|
|
|
#define is_newline(c) ((c) == '\n' || (c) == '\r')
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
static Eina_Hash *keyword_map = NULL;
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
static void
|
|
|
|
throw(Eo_Lexer *ls, const char *fmt, ...)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-07-02 16:30:39 -07:00
|
|
|
const char *ln = ls->stream_line, *end = ls->stream_end;
|
2014-07-02 17:48:00 -07:00
|
|
|
Eina_Strbuf *buf = eina_strbuf_new();
|
2014-07-02 16:30:39 -07:00
|
|
|
int i;
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2014-07-02 17:48:00 -07:00
|
|
|
eina_strbuf_append_vprintf(buf, fmt, ap);
|
2014-07-02 16:30:39 -07:00
|
|
|
va_end(ap);
|
2015-05-15 07:10:58 -07:00
|
|
|
eina_strbuf_append(buf, "\n ");
|
2014-07-02 16:30:39 -07:00
|
|
|
while (ln != end && !is_newline(*ln))
|
2014-07-02 17:48:00 -07:00
|
|
|
eina_strbuf_append_char(buf,*(ln++));
|
|
|
|
eina_strbuf_append_char(buf, '\n');
|
2014-07-02 16:30:39 -07:00
|
|
|
for (i = 0; i < ls->column; ++i)
|
2014-07-02 17:48:00 -07:00
|
|
|
eina_strbuf_append_char(buf, ' ');
|
|
|
|
eina_strbuf_append(buf, "^\n");
|
2017-10-30 22:20:09 -07:00
|
|
|
_eolian_log_line(ls->source, ls->line_number, ls->column,
|
|
|
|
"%s", eina_strbuf_string_get(buf));
|
2014-07-02 17:48:00 -07:00
|
|
|
eina_strbuf_free(buf);
|
2014-07-02 16:30:39 -07:00
|
|
|
longjmp(ls->err_jmp, EINA_TRUE);
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
static void
|
|
|
|
init_hash(void)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2015-09-21 07:26:41 -07:00
|
|
|
unsigned int i;
|
2014-06-18 03:25:07 -07:00
|
|
|
if (keyword_map) return;
|
|
|
|
keyword_map = eina_hash_string_superfast_new(NULL);
|
2015-09-21 07:26:41 -07:00
|
|
|
for (i = 0; i < (sizeof(keywords) / sizeof(keywords[0])); ++i)
|
|
|
|
eina_hash_add(keyword_map, keywords[i], (void *)(size_t)(i + 1));
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-06-18 03:25:07 -07:00
|
|
|
destroy_hash(void)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
if (keyword_map)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
eina_hash_free(keyword_map);
|
|
|
|
keyword_map = NULL;
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
static void
|
|
|
|
txt_token(Eo_Lexer *ls, int token, char *buf)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
if (token == TOK_VALUE)
|
2015-05-27 03:25:04 -07:00
|
|
|
memcpy(buf, ls->t.value.s, strlen(ls->t.value.s) + 1);
|
2014-06-18 03:25:07 -07:00
|
|
|
else
|
|
|
|
return eo_lexer_token_to_str(token, buf);
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
void eo_lexer_lex_error (Eo_Lexer *ls, const char *msg, int token);
|
|
|
|
void eo_lexer_syntax_error(Eo_Lexer *ls, const char *msg);
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
static void next_line(Eo_Lexer *ls)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
int old = ls->current;
|
2014-06-20 02:45:55 -07:00
|
|
|
assert(is_newline(ls->current));
|
2014-07-02 16:30:39 -07:00
|
|
|
ls->stream_line = ls->stream;
|
2014-06-18 03:25:07 -07:00
|
|
|
next_char(ls);
|
2014-06-20 02:45:55 -07:00
|
|
|
if (is_newline(ls->current) && ls->current != old)
|
2014-07-02 16:30:39 -07:00
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
ls->stream_line = ls->stream;
|
|
|
|
}
|
2016-06-13 06:53:35 -07:00
|
|
|
if (++ls->iline_number >= INT_MAX)
|
2014-07-01 10:25:17 -07:00
|
|
|
eo_lexer_syntax_error(ls, "chunk has too many lines");
|
2016-06-13 06:53:35 -07:00
|
|
|
ls->line_number = ls->iline_number;
|
2014-07-02 16:14:28 -07:00
|
|
|
ls->icolumn = ls->column = 0;
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
|
2015-05-29 08:10:40 -07:00
|
|
|
static void skip_ws(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
while (isspace(ls->current) && !is_newline(ls->current))
|
|
|
|
next_char(ls);
|
|
|
|
}
|
|
|
|
|
2014-06-18 04:59:22 -07:00
|
|
|
/* go to next line and strip leading whitespace */
|
|
|
|
static void next_line_ws(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
next_line(ls);
|
2015-05-29 08:10:40 -07:00
|
|
|
skip_ws(ls);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
should_skip_star(Eo_Lexer *ls, int ccol, Eina_Bool *term)
|
|
|
|
{
|
|
|
|
Eina_Bool had_star = EINA_FALSE;
|
|
|
|
if (ls->column == ccol && ls->current == '*')
|
|
|
|
{
|
|
|
|
had_star = EINA_TRUE;
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == '/')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
*term = EINA_TRUE;
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
skip_ws(ls);
|
|
|
|
}
|
|
|
|
return had_star;
|
2014-06-18 04:59:22 -07:00
|
|
|
}
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
static void
|
2015-09-03 07:08:08 -07:00
|
|
|
read_long_comment(Eo_Lexer *ls, int ccol)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2015-05-29 08:10:40 -07:00
|
|
|
Eina_Bool had_star = EINA_FALSE, had_nl = EINA_FALSE;
|
2014-06-18 03:25:07 -07:00
|
|
|
eina_strbuf_reset(ls->buff);
|
2014-06-18 04:59:22 -07:00
|
|
|
|
2014-06-20 02:45:55 -07:00
|
|
|
if (is_newline(ls->current))
|
2015-05-29 08:10:40 -07:00
|
|
|
{
|
|
|
|
Eina_Bool term = EINA_FALSE;
|
|
|
|
had_nl = EINA_TRUE;
|
|
|
|
next_line_ws(ls);
|
|
|
|
had_star = should_skip_star(ls, ccol, &term);
|
|
|
|
if (term) goto cend;
|
|
|
|
}
|
2014-06-18 04:59:22 -07:00
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
for (;;)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
if (!ls->current)
|
2014-07-16 08:06:04 -07:00
|
|
|
eo_lexer_lex_error(ls, "unfinished long comment", -1);
|
2014-06-18 03:25:07 -07:00
|
|
|
if (ls->current == '*')
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == '/')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
eina_strbuf_append_char(ls->buff, '*');
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
2014-06-20 02:45:55 -07:00
|
|
|
else if (is_newline(ls->current))
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
eina_strbuf_append_char(ls->buff, '\n');
|
2014-06-18 04:59:22 -07:00
|
|
|
next_line_ws(ls);
|
2015-05-29 08:10:40 -07:00
|
|
|
if (!had_nl)
|
|
|
|
{
|
|
|
|
Eina_Bool term = EINA_FALSE;
|
|
|
|
had_nl = EINA_TRUE;
|
|
|
|
had_star = should_skip_star(ls, ccol, &term);
|
|
|
|
if (term) break;
|
|
|
|
}
|
|
|
|
else if (had_star && ls->column == ccol && ls->current == '*')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == '/')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
skip_ws(ls);
|
|
|
|
}
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
next_char(ls);
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
}
|
2015-05-29 08:10:40 -07:00
|
|
|
cend:
|
2014-06-18 04:59:22 -07:00
|
|
|
eina_strbuf_trim(ls->buff);
|
2014-07-17 06:17:19 -07:00
|
|
|
}
|
|
|
|
|
2015-06-23 07:28:46 -07:00
|
|
|
enum Doc_Tokens {
|
|
|
|
DOC_MANGLED = -2, DOC_UNFINISHED = -1, DOC_TEXT = 0, DOC_SINCE = 1
|
|
|
|
};
|
2015-06-08 07:55:02 -07:00
|
|
|
|
2015-09-23 09:17:50 -07:00
|
|
|
static void
|
2017-12-06 06:06:54 -08:00
|
|
|
doc_ref_class(Eo_Lexer *ls, const char *cname)
|
2015-09-23 09:17:50 -07:00
|
|
|
{
|
|
|
|
size_t clen = strlen(cname);
|
|
|
|
char *buf = alloca(clen + 4);
|
|
|
|
memcpy(buf, cname, clen);
|
|
|
|
buf[clen] = '\0';
|
|
|
|
for (char *p = buf; *p; ++p)
|
|
|
|
{
|
|
|
|
if (*p == '.')
|
|
|
|
*p = '_';
|
|
|
|
else
|
|
|
|
*p = tolower(*p);
|
|
|
|
}
|
|
|
|
memcpy(buf + clen, ".eo", sizeof(".eo"));
|
2017-12-06 06:06:54 -08:00
|
|
|
const char *eop = eina_hash_find(ls->state->filenames_eo, buf);
|
2015-09-23 09:17:50 -07:00
|
|
|
if (!eop)
|
|
|
|
return;
|
2017-12-07 09:58:21 -08:00
|
|
|
eina_hash_set(ls->state->defer, buf, eop);
|
2015-09-23 09:17:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
doc_ref(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
const char *st = ls->stream, *ste = ls->stream_end;
|
|
|
|
size_t rlen = 0;
|
|
|
|
while ((st != ste) && ((*st == '.') || isalnum(*st)))
|
|
|
|
{
|
|
|
|
++st;
|
|
|
|
++rlen;
|
|
|
|
}
|
|
|
|
if ((rlen > 1) && (*(st - 1) == '.'))
|
|
|
|
--rlen;
|
|
|
|
if (!rlen)
|
|
|
|
return;
|
|
|
|
if (*ls->stream == '.')
|
|
|
|
return;
|
|
|
|
|
|
|
|
char *buf = alloca(rlen + 1);
|
|
|
|
memcpy(buf, ls->stream, rlen);
|
|
|
|
buf[rlen] = '\0';
|
|
|
|
|
|
|
|
/* actual full class name */
|
2017-12-06 06:06:54 -08:00
|
|
|
doc_ref_class(ls, buf);
|
2015-09-23 09:17:50 -07:00
|
|
|
|
|
|
|
/* method name at the end */
|
|
|
|
char *end = strrchr(buf, '.');
|
|
|
|
if (!end)
|
|
|
|
return;
|
|
|
|
*end = '\0';
|
2017-12-06 06:06:54 -08:00
|
|
|
doc_ref_class(ls, buf);
|
2015-09-23 09:17:50 -07:00
|
|
|
|
|
|
|
/* .get or .set at the end, handle possible property */
|
|
|
|
if (strcmp(end + 1, "get") && strcmp(end + 1, "set"))
|
|
|
|
return;
|
|
|
|
end = strrchr(buf, '.');
|
|
|
|
if (!end)
|
|
|
|
return;
|
|
|
|
*end = '\0';
|
2017-12-06 06:06:54 -08:00
|
|
|
doc_ref_class(ls, buf);
|
2015-09-23 09:17:50 -07:00
|
|
|
}
|
|
|
|
|
2015-06-23 07:28:46 -07:00
|
|
|
static int
|
2015-08-06 08:53:41 -07:00
|
|
|
doc_lex(Eo_Lexer *ls, Eina_Bool *term, Eina_Bool *since)
|
2015-06-02 10:12:09 -07:00
|
|
|
{
|
2015-06-23 08:34:45 -07:00
|
|
|
int tokret = -1;
|
2015-06-02 10:12:09 -07:00
|
|
|
eina_strbuf_reset(ls->buff);
|
2015-08-06 08:53:41 -07:00
|
|
|
*since = EINA_FALSE;
|
|
|
|
for (;;) switch (ls->current)
|
2015-06-02 10:12:09 -07:00
|
|
|
{
|
2015-06-23 07:28:46 -07:00
|
|
|
/* 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))
|
2015-06-02 10:12:09 -07:00
|
|
|
{
|
2015-06-23 07:28:46 -07:00
|
|
|
eina_strbuf_append_char(ls->buff, ' ');
|
|
|
|
continue;
|
2015-06-02 10:12:09 -07:00
|
|
|
}
|
2015-06-23 07:28:46 -07:00
|
|
|
while (is_newline(ls->current))
|
|
|
|
next_line_ws(ls);
|
2015-06-23 08:34:45 -07:00
|
|
|
tokret = DOC_TEXT;
|
|
|
|
goto exit_with_token;
|
2015-06-23 07:28:46 -07:00
|
|
|
/* escape case: for any \X, output \X
|
|
|
|
* except for \\]], then output just ]]
|
|
|
|
*/
|
|
|
|
case '\\':
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == ']')
|
2015-06-02 10:12:09 -07:00
|
|
|
{
|
2015-06-23 07:28:46 -07:00
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == ']')
|
2015-06-04 07:41:52 -07:00
|
|
|
{
|
2015-06-23 07:28:46 -07:00
|
|
|
next_char(ls);
|
|
|
|
eina_strbuf_append(ls->buff, "]]");
|
2015-06-04 07:41:52 -07:00
|
|
|
}
|
|
|
|
else
|
2015-06-23 07:28:46 -07:00
|
|
|
eina_strbuf_append(ls->buff, "\\]");
|
2015-06-02 10:12:09 -07:00
|
|
|
}
|
|
|
|
else
|
2015-06-23 07:28:46 -07:00
|
|
|
eina_strbuf_append_char(ls->buff, '\\');
|
|
|
|
continue;
|
|
|
|
/* terminating case */
|
|
|
|
case ']':
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == ']')
|
2015-06-02 10:12:09 -07:00
|
|
|
{
|
2015-06-23 07:28:46 -07:00
|
|
|
/* terminate doc */
|
2015-06-23 08:34:45 -07:00
|
|
|
tokret = DOC_TEXT;
|
|
|
|
goto terminated;
|
2015-06-02 10:12:09 -07:00
|
|
|
}
|
2015-06-23 07:28:46 -07:00
|
|
|
eina_strbuf_append_char(ls->buff, ']');
|
|
|
|
continue;
|
2015-08-06 08:53:41 -07:00
|
|
|
/* references and @since */
|
2015-06-23 07:28:46 -07:00
|
|
|
case '@':
|
2015-08-06 08:53:41 -07:00
|
|
|
if ((size_t)(ls->stream_end - ls->stream) >= (sizeof("since")) &&
|
|
|
|
!memcmp(ls->stream, "since ", sizeof("since")))
|
2015-06-02 10:12:09 -07:00
|
|
|
{
|
2015-06-23 07:28:46 -07:00
|
|
|
next_char(ls);
|
2015-08-06 08:53:41 -07:00
|
|
|
*since = EINA_TRUE;
|
|
|
|
for (size_t i = 0; i < sizeof("since"); ++i)
|
|
|
|
next_char(ls);
|
|
|
|
skip_ws(ls);
|
|
|
|
tokret = DOC_TEXT;
|
|
|
|
goto exit_with_token;
|
2015-06-02 10:12:09 -07:00
|
|
|
}
|
2015-09-23 09:17:50 -07:00
|
|
|
doc_ref(ls);
|
2015-08-06 08:53:41 -07:00
|
|
|
eina_strbuf_append_char(ls->buff, '@');
|
|
|
|
next_char(ls);
|
|
|
|
/* in-class references */
|
2018-03-15 04:30:06 -07:00
|
|
|
if (ls->klass && ls->current == '.')
|
2015-06-08 07:55:02 -07:00
|
|
|
{
|
2015-08-06 08:53:41 -07:00
|
|
|
next_char(ls);
|
|
|
|
if (isalpha(ls->current) || ls->current == '_')
|
2018-03-15 04:30:06 -07:00
|
|
|
eina_strbuf_append(ls->buff, ls->klass->base.name);
|
2015-08-06 08:53:41 -07:00
|
|
|
eina_strbuf_append_char(ls->buff, '.');
|
2015-06-23 07:28:46 -07:00
|
|
|
}
|
2015-08-06 08:53:41 -07:00
|
|
|
continue;
|
2015-06-23 07:28:46 -07:00
|
|
|
/* default case - append character */
|
|
|
|
default:
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
next_char(ls);
|
|
|
|
continue;
|
|
|
|
}
|
2015-08-06 08:53:41 -07:00
|
|
|
terminated:
|
|
|
|
next_char(ls);
|
|
|
|
*term = EINA_TRUE;
|
|
|
|
exit_with_token:
|
|
|
|
eina_strbuf_trim(ls->buff);
|
|
|
|
return tokret;
|
|
|
|
}
|
2015-06-23 08:34:45 -07:00
|
|
|
|
2015-08-06 08:53:41 -07:00
|
|
|
static int
|
|
|
|
read_since(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
eina_strbuf_reset(ls->buff);
|
|
|
|
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;
|
2015-06-23 08:34:45 -07:00
|
|
|
skip_ws(ls);
|
|
|
|
while (is_newline(ls->current))
|
|
|
|
next_line_ws(ls);
|
|
|
|
if (ls->current != ']')
|
|
|
|
return DOC_MANGLED;
|
|
|
|
next_char(ls);
|
2015-08-06 08:53:41 -07:00
|
|
|
if (ls->current != ']')
|
|
|
|
return DOC_MANGLED;
|
|
|
|
next_char(ls);
|
|
|
|
return DOC_SINCE;
|
2015-06-23 07:28:46 -07:00
|
|
|
}
|
2015-06-08 07:55:02 -07:00
|
|
|
|
2015-06-23 07:28:46 -07:00
|
|
|
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);
|
|
|
|
}
|
2015-06-08 07:55:02 -07:00
|
|
|
|
2015-06-23 07:28:46 -07:00
|
|
|
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;
|
2015-06-08 07:55:02 -07:00
|
|
|
|
2015-06-23 07:28:46 -07:00
|
|
|
Eina_Strbuf *rbuf = eina_strbuf_new();
|
2015-06-08 07:55:02 -07:00
|
|
|
|
2015-08-06 08:53:41 -07:00
|
|
|
Eina_Bool term = EINA_FALSE, since = EINA_FALSE;
|
2015-06-23 07:28:46 -07:00
|
|
|
while (!term)
|
|
|
|
{
|
2015-08-06 08:53:41 -07:00
|
|
|
int read;
|
|
|
|
if (since)
|
|
|
|
{
|
|
|
|
read = read_since(ls);
|
|
|
|
term = EINA_TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
read = doc_lex(ls, &term, &since);
|
2015-06-23 07:28:46 -07:00
|
|
|
switch (read)
|
|
|
|
{
|
|
|
|
case DOC_MANGLED:
|
2015-06-08 07:55:02 -07:00
|
|
|
doc_error(ls, "mangled documentation", doc, rbuf);
|
|
|
|
return;
|
2015-06-23 07:28:46 -07:00
|
|
|
case DOC_UNFINISHED:
|
|
|
|
doc_error(ls, "unfinished documentation", doc, rbuf);
|
|
|
|
return;
|
|
|
|
case DOC_TEXT:
|
2015-08-06 08:53:41 -07:00
|
|
|
if (!eina_strbuf_length_get(ls->buff))
|
|
|
|
continue;
|
2015-06-23 07:28:46 -07:00
|
|
|
if (!doc->summary)
|
|
|
|
doc->summary = eina_stringshare_add(eina_strbuf_string_get(ls->buff));
|
|
|
|
else
|
2015-06-02 10:12:09 -07:00
|
|
|
{
|
2015-06-23 07:28:46 -07:00
|
|
|
if (eina_strbuf_length_get(rbuf))
|
|
|
|
eina_strbuf_append(rbuf, "\n\n");
|
|
|
|
eina_strbuf_append(rbuf, eina_strbuf_string_get(ls->buff));
|
2015-06-02 10:12:09 -07:00
|
|
|
}
|
2015-06-23 07:28:46 -07:00
|
|
|
break;
|
|
|
|
case DOC_SINCE:
|
|
|
|
doc->since = eina_stringshare_add(eina_strbuf_string_get(ls->buff));
|
|
|
|
break;
|
2015-06-02 10:12:09 -07:00
|
|
|
}
|
|
|
|
}
|
2015-06-08 07:55:02 -07:00
|
|
|
|
2015-06-23 07:28:46 -07:00
|
|
|
if (eina_strbuf_length_get(rbuf))
|
2015-06-08 07:55:02 -07:00
|
|
|
doc->description = eina_stringshare_add(eina_strbuf_string_get(rbuf));
|
2015-06-23 08:44:17 -07:00
|
|
|
if (!doc->summary)
|
|
|
|
doc->summary = eina_stringshare_add("No description supplied.");
|
2018-03-15 04:30:06 -07:00
|
|
|
if (!doc->since && ls->klass && ls->klass->doc)
|
|
|
|
doc->since = eina_stringshare_ref(ls->klass->doc->since);
|
2015-06-08 07:55:02 -07:00
|
|
|
eina_strbuf_free(rbuf);
|
|
|
|
tok->value.doc = doc;
|
2015-06-02 10:12:09 -07:00
|
|
|
}
|
|
|
|
|
2014-07-17 06:17:19 -07:00
|
|
|
static void
|
|
|
|
esc_error(Eo_Lexer *ls, int *c, int n, const char *msg)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
eina_strbuf_reset(ls->buff);
|
|
|
|
eina_strbuf_append_char(ls->buff, '\\');
|
|
|
|
for (i = 0; i < n && c[i]; ++i)
|
|
|
|
eina_strbuf_append_char(ls->buff, c[i]);
|
|
|
|
eo_lexer_lex_error(ls, msg, TOK_STRING);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
hex_val(int c)
|
|
|
|
{
|
|
|
|
if (c >= 'a') return c - 'a' + 10;
|
|
|
|
if (c >= 'A') return c - 'A' + 10;
|
|
|
|
return c - '0';
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
read_hex_esc(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
int c[3] = { 'x' };
|
|
|
|
int i, r = 0;
|
|
|
|
for (i = 1; i < 3; ++i)
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
c[i] = ls->current;
|
|
|
|
if (!isxdigit(c[i]))
|
|
|
|
esc_error(ls, c, i + 1, "hexadecimal digit expected");
|
|
|
|
r = (r << 4) + hex_val(c[i]);
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
read_dec_esc(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
int c[3];
|
|
|
|
int i, r = 0;
|
|
|
|
for (i = 0; i < 3 && isdigit(ls->current); ++i)
|
|
|
|
{
|
|
|
|
c[i] = ls->current;
|
|
|
|
r = r * 10 + (c[i] - '0');
|
|
|
|
next_char(ls);
|
|
|
|
}
|
|
|
|
if (r > UCHAR_MAX)
|
|
|
|
esc_error(ls, c, i, "decimal escape too large");
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-08-07 07:46:11 -07:00
|
|
|
static void
|
|
|
|
read_escape(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
switch (ls->current)
|
|
|
|
{
|
|
|
|
case 'a': eina_strbuf_append_char(ls->buff, '\a'); next_char(ls); break;
|
|
|
|
case 'b': eina_strbuf_append_char(ls->buff, '\b'); next_char(ls); break;
|
|
|
|
case 'f': eina_strbuf_append_char(ls->buff, '\f'); next_char(ls); break;
|
|
|
|
case 'n': eina_strbuf_append_char(ls->buff, '\n'); next_char(ls); break;
|
|
|
|
case 'r': eina_strbuf_append_char(ls->buff, '\r'); next_char(ls); break;
|
|
|
|
case 't': eina_strbuf_append_char(ls->buff, '\t'); next_char(ls); break;
|
|
|
|
case 'v': eina_strbuf_append_char(ls->buff, '\v'); next_char(ls); break;
|
|
|
|
case 'x':
|
|
|
|
eina_strbuf_append_char(ls->buff, read_hex_esc(ls));
|
|
|
|
next_char(ls);
|
|
|
|
break;
|
|
|
|
case '\n': case '\r':
|
|
|
|
next_line(ls);
|
|
|
|
eina_strbuf_append_char(ls->buff, '\n');
|
|
|
|
break;
|
|
|
|
case '\\': case '"': case '\'':
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
break;
|
|
|
|
case '\0':
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (!isdigit(ls->current))
|
|
|
|
esc_error(ls, &ls->current, 1, "invalid escape sequence");
|
|
|
|
eina_strbuf_append_char(ls->buff, read_dec_esc(ls));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 06:17:19 -07:00
|
|
|
static void
|
|
|
|
read_string(Eo_Lexer *ls, Eo_Token *tok)
|
|
|
|
{
|
|
|
|
eina_strbuf_reset(ls->buff);
|
2014-08-07 07:15:07 -07:00
|
|
|
eina_strbuf_append_char(ls->buff, '"');
|
|
|
|
next_char(ls);
|
|
|
|
while (ls->current != '"') switch (ls->current)
|
2014-07-17 06:17:19 -07:00
|
|
|
{
|
|
|
|
case '\0':
|
|
|
|
eo_lexer_lex_error(ls, "unfinished string", -1);
|
|
|
|
break;
|
|
|
|
case '\n': case '\r':
|
|
|
|
eo_lexer_lex_error(ls, "unfinished string", TOK_STRING);
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
{
|
|
|
|
next_char(ls);
|
2014-08-07 07:46:11 -07:00
|
|
|
read_escape(ls);
|
2014-07-17 06:17:19 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
next_char(ls);
|
|
|
|
}
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
next_char(ls);
|
2014-07-17 09:16:31 -07:00
|
|
|
tok->value.s = eina_stringshare_add_length(eina_strbuf_string_get(ls->buff) + 1,
|
|
|
|
(unsigned int)eina_strbuf_length_get(ls->buff) - 2);
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
static int
|
2014-07-17 05:07:39 -07:00
|
|
|
get_type(Eo_Lexer *ls, Eina_Bool is_float)
|
|
|
|
{
|
|
|
|
if (is_float)
|
|
|
|
{
|
|
|
|
if (ls->current == 'f' || ls->current == 'F')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
return NUM_FLOAT;
|
|
|
|
}
|
|
|
|
return NUM_DOUBLE;
|
|
|
|
}
|
|
|
|
if (ls->current == 'u' || ls->current == 'U')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == 'l' || ls->current == 'L')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == 'l' || ls->current == 'L')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
return NUM_ULLONG;
|
|
|
|
}
|
|
|
|
return NUM_ULONG;
|
|
|
|
}
|
|
|
|
return NUM_UINT;
|
|
|
|
}
|
|
|
|
if (ls->current == 'l' || ls->current == 'L')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == 'l' || ls->current == 'L')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
return NUM_LLONG;
|
|
|
|
}
|
|
|
|
return NUM_LONG;
|
|
|
|
}
|
|
|
|
return NUM_INT;
|
|
|
|
}
|
|
|
|
|
2015-06-25 02:43:54 -07:00
|
|
|
static void
|
|
|
|
replace_decpoint(Eo_Lexer *ls, char prevdecp)
|
|
|
|
{
|
|
|
|
if (ls->decpoint == prevdecp) return;
|
|
|
|
char *bufs = eina_strbuf_string_steal(ls->buff);
|
|
|
|
char *p = bufs;
|
|
|
|
while ((p = strchr(p, prevdecp))) *p = ls->decpoint;
|
|
|
|
eina_strbuf_append(ls->buff, bufs);
|
|
|
|
free(bufs);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
write_val_with_decpoint(Eo_Lexer *ls, Eo_Token *tok, int type)
|
|
|
|
{
|
|
|
|
struct lconv *lc = localeconv();
|
|
|
|
char prev = ls->decpoint;
|
|
|
|
ls->decpoint = lc ? lc->decimal_point[0] : '.';
|
|
|
|
if (ls->decpoint == prev)
|
|
|
|
{
|
|
|
|
eo_lexer_lex_error(ls, "malformed number", TOK_NUMBER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
replace_decpoint(ls, prev);
|
|
|
|
char *end = NULL;
|
|
|
|
if (type == NUM_FLOAT)
|
|
|
|
tok->value.f = strtof(eina_strbuf_string_get(ls->buff), &end);
|
|
|
|
else if (type == NUM_DOUBLE)
|
|
|
|
tok->value.d = strtod(eina_strbuf_string_get(ls->buff), &end);
|
|
|
|
if (end && end[0])
|
|
|
|
eo_lexer_lex_error(ls, "malformed number", TOK_NUMBER);
|
2017-09-01 07:07:45 -07:00
|
|
|
tok->kw = type;
|
2015-06-25 02:43:54 -07:00
|
|
|
}
|
|
|
|
|
2014-07-17 05:07:39 -07:00
|
|
|
static void
|
|
|
|
write_val(Eo_Lexer *ls, Eo_Token *tok, Eina_Bool is_float)
|
|
|
|
{
|
|
|
|
int type = get_type(ls, is_float);
|
2014-08-07 07:15:07 -07:00
|
|
|
char *end = NULL;
|
2014-07-17 05:07:39 -07:00
|
|
|
if (is_float)
|
|
|
|
{
|
2015-06-25 02:43:54 -07:00
|
|
|
replace_decpoint(ls, '.');
|
2014-07-17 05:07:39 -07:00
|
|
|
if (type == NUM_FLOAT)
|
2015-07-15 07:32:53 -07:00
|
|
|
tok->value.f = strtof(eina_strbuf_string_get(ls->buff), &end);
|
2014-07-17 05:07:39 -07:00
|
|
|
else if (type == NUM_DOUBLE)
|
2015-07-15 07:32:53 -07:00
|
|
|
tok->value.d = strtod(eina_strbuf_string_get(ls->buff), &end);
|
2014-07-17 05:07:39 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-07-15 07:32:53 -07:00
|
|
|
const char *str = eina_strbuf_string_get(ls->buff);
|
2014-07-17 05:07:39 -07:00
|
|
|
/* signed is always in the same memory location */
|
|
|
|
if (type == NUM_INT || type == NUM_UINT)
|
2014-07-17 09:16:31 -07:00
|
|
|
tok->value.u = strtoul(str, &end, 0);
|
2014-07-17 05:07:39 -07:00
|
|
|
else if (type == NUM_LONG || type == NUM_ULONG)
|
2014-07-17 09:16:31 -07:00
|
|
|
tok->value.ul = strtoul(str, &end, 0);
|
2014-07-17 05:07:39 -07:00
|
|
|
else if (type == NUM_LLONG || type == NUM_ULLONG)
|
2014-07-17 09:16:31 -07:00
|
|
|
tok->value.ull = strtoull(str, &end, 0);
|
2014-07-17 05:07:39 -07:00
|
|
|
}
|
2014-08-07 07:15:07 -07:00
|
|
|
if (end && end[0])
|
2015-06-25 02:43:54 -07:00
|
|
|
{
|
|
|
|
if (is_float)
|
|
|
|
{
|
|
|
|
write_val_with_decpoint(ls, tok, type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
eo_lexer_lex_error(ls, "malformed number", TOK_NUMBER);
|
|
|
|
}
|
2014-07-17 05:07:39 -07:00
|
|
|
tok->kw = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
write_exp(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == '+' || ls->current == '-')
|
|
|
|
{
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
next_char(ls);
|
|
|
|
while (isdigit(ls->current))
|
|
|
|
{
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
next_char(ls);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
read_hex_number(Eo_Lexer *ls, Eo_Token *tok)
|
|
|
|
{
|
|
|
|
Eina_Bool is_float = EINA_FALSE;
|
|
|
|
while (isxdigit(ls->current) || ls->current == '.')
|
|
|
|
{
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
if (ls->current == '.') is_float = EINA_TRUE;
|
|
|
|
next_char(ls);
|
|
|
|
}
|
|
|
|
if (is_float && (ls->current != 'p' && ls->current != 'P'))
|
|
|
|
{
|
|
|
|
eo_lexer_lex_error(ls, "hex float literals require an exponent",
|
|
|
|
TOK_NUMBER);
|
|
|
|
}
|
|
|
|
if (ls->current == 'p' || ls->current == 'P')
|
|
|
|
{
|
|
|
|
is_float = EINA_TRUE;
|
|
|
|
write_exp(ls);
|
|
|
|
}
|
|
|
|
write_val(ls, tok, is_float);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
read_number(Eo_Lexer *ls, Eo_Token *tok)
|
|
|
|
{
|
|
|
|
Eina_Bool is_float = eina_strbuf_string_get(ls->buff)[0] == '.';
|
|
|
|
if (ls->current == '0' && !is_float)
|
|
|
|
{
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == 'x' || ls->current == 'X')
|
|
|
|
{
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
next_char(ls);
|
|
|
|
read_hex_number(ls, tok);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-08-07 07:15:07 -07:00
|
|
|
while (isdigit(ls->current) || ls->current == '.')
|
2014-07-17 05:07:39 -07:00
|
|
|
{
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
|
|
|
if (ls->current == '.') is_float = EINA_TRUE;
|
|
|
|
next_char(ls);
|
|
|
|
}
|
2014-07-22 16:47:26 -07:00
|
|
|
if (ls->current == 'e' || ls->current == 'E')
|
2014-07-17 05:07:39 -07:00
|
|
|
{
|
|
|
|
is_float = EINA_TRUE;
|
|
|
|
write_exp(ls);
|
|
|
|
}
|
|
|
|
write_val(ls, tok, is_float);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
lex(Eo_Lexer *ls, Eo_Token *tok)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
eina_strbuf_reset(ls->buff);
|
2014-07-17 09:16:31 -07:00
|
|
|
tok->value.s = NULL;
|
2014-07-01 10:25:17 -07:00
|
|
|
for (;;) switch (ls->current)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-07-01 10:25:17 -07:00
|
|
|
case '\n':
|
|
|
|
case '\r':
|
|
|
|
next_line(ls);
|
|
|
|
continue;
|
|
|
|
case '/':
|
2014-08-08 03:47:21 -07:00
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current == '*')
|
|
|
|
{
|
2015-05-29 08:10:40 -07:00
|
|
|
int ccol = ls->column;
|
2014-08-08 03:47:21 -07:00
|
|
|
next_char(ls);
|
2015-09-03 07:08:08 -07:00
|
|
|
if (ls->current == '@')
|
|
|
|
{
|
|
|
|
eo_lexer_lex_error(ls, "old style documentation comment", -1);
|
|
|
|
return -1; /* unreachable */
|
|
|
|
}
|
|
|
|
read_long_comment(ls, ccol);
|
|
|
|
continue;
|
2014-08-08 03:47:21 -07:00
|
|
|
}
|
|
|
|
else if (ls->current != '/') return '/';
|
|
|
|
next_char(ls);
|
|
|
|
while (ls->current && !is_newline(ls->current))
|
2015-06-05 08:10:12 -07:00
|
|
|
next_char(ls);
|
2014-08-08 03:47:21 -07:00
|
|
|
continue;
|
|
|
|
}
|
2015-06-02 10:12:09 -07:00
|
|
|
case '[':
|
2015-06-02 10:27:46 -07:00
|
|
|
{
|
|
|
|
int dline = ls->line_number, dcol = ls->column;
|
2016-06-13 06:53:35 -07:00
|
|
|
const char *sline = ls->stream_line;
|
2015-06-02 10:27:46 -07:00
|
|
|
next_char(ls);
|
|
|
|
if (ls->current != '[') return '[';
|
|
|
|
next_char(ls);
|
|
|
|
read_doc(ls, tok, dline, dcol);
|
2016-06-13 06:53:35 -07:00
|
|
|
ls->column = dcol + 1;
|
|
|
|
/* doc is the only potentially multiline token */
|
|
|
|
ls->line_number = dline;
|
|
|
|
ls->stream_line = sline;
|
2015-06-02 10:27:46 -07:00
|
|
|
return TOK_DOC;
|
|
|
|
}
|
2014-07-01 10:25:17 -07:00
|
|
|
case '\0':
|
2014-07-16 08:06:04 -07:00
|
|
|
return -1;
|
2014-07-18 03:48:40 -07:00
|
|
|
case '=':
|
|
|
|
next_char(ls);
|
2014-08-08 03:32:07 -07:00
|
|
|
if (!ls->expr_mode || (ls->current != '=')) return '=';
|
2014-07-18 03:48:40 -07:00
|
|
|
next_char(ls);
|
2016-06-13 06:53:35 -07:00
|
|
|
--ls->column;
|
2014-07-18 03:48:40 -07:00
|
|
|
return TOK_EQ;
|
|
|
|
case '!':
|
|
|
|
next_char(ls);
|
2014-08-08 03:32:07 -07:00
|
|
|
if (!ls->expr_mode || (ls->current != '=')) return '!';
|
2014-07-18 03:48:40 -07:00
|
|
|
next_char(ls);
|
2016-06-13 06:53:35 -07:00
|
|
|
--ls->column;
|
2014-07-18 03:48:40 -07:00
|
|
|
return TOK_NQ;
|
|
|
|
case '>':
|
|
|
|
next_char(ls);
|
2014-08-08 03:32:07 -07:00
|
|
|
if (!ls->expr_mode) return '>';
|
2014-07-18 03:48:40 -07:00
|
|
|
if (ls->current == '=')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
2016-06-13 06:53:35 -07:00
|
|
|
--ls->column;
|
2014-07-18 03:48:40 -07:00
|
|
|
return TOK_GE;
|
|
|
|
}
|
|
|
|
else if (ls->current == '>')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
2016-06-13 06:53:35 -07:00
|
|
|
--ls->column;
|
2014-07-18 03:48:40 -07:00
|
|
|
return TOK_RSH;
|
|
|
|
}
|
|
|
|
return '>';
|
|
|
|
case '<':
|
|
|
|
next_char(ls);
|
2014-08-08 03:32:07 -07:00
|
|
|
if (!ls->expr_mode) return '<';
|
2014-07-18 03:48:40 -07:00
|
|
|
if (ls->current == '=')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
2016-06-13 06:53:35 -07:00
|
|
|
--ls->column;
|
2014-07-18 03:48:40 -07:00
|
|
|
return TOK_LE;
|
|
|
|
}
|
|
|
|
else if (ls->current == '<')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
2016-06-13 06:53:35 -07:00
|
|
|
--ls->column;
|
2014-07-18 03:48:40 -07:00
|
|
|
return TOK_LSH;
|
|
|
|
}
|
|
|
|
return '<';
|
|
|
|
case '&':
|
|
|
|
next_char(ls);
|
2014-08-08 03:32:07 -07:00
|
|
|
if (!ls->expr_mode || (ls->current != '&')) return '&';
|
2014-07-18 03:48:40 -07:00
|
|
|
next_char(ls);
|
2016-06-13 06:53:35 -07:00
|
|
|
--ls->column;
|
2014-07-18 03:48:40 -07:00
|
|
|
return TOK_AND;
|
|
|
|
case '|':
|
|
|
|
next_char(ls);
|
2014-08-08 03:32:07 -07:00
|
|
|
if (!ls->expr_mode || (ls->current != '|')) return '|';
|
2014-07-18 03:48:40 -07:00
|
|
|
next_char(ls);
|
2016-06-13 06:53:35 -07:00
|
|
|
--ls->column;
|
2014-07-18 03:48:40 -07:00
|
|
|
return TOK_OR;
|
2014-08-07 07:15:07 -07:00
|
|
|
case '"':
|
2016-06-13 06:53:35 -07:00
|
|
|
{
|
|
|
|
int dcol = ls->column;
|
|
|
|
if (!ls->expr_mode)
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
return '"';
|
|
|
|
}
|
|
|
|
/* strings are not multiline for now at least */
|
|
|
|
read_string(ls, tok);
|
|
|
|
ls->column = dcol + 1;
|
|
|
|
return TOK_STRING;
|
|
|
|
}
|
2014-08-07 07:15:07 -07:00
|
|
|
case '\'':
|
2016-06-13 06:53:35 -07:00
|
|
|
{
|
|
|
|
int dcol = ls->column;
|
|
|
|
next_char(ls);
|
|
|
|
if (!ls->expr_mode) return '\'';
|
|
|
|
if (ls->current == '\\')
|
|
|
|
{
|
|
|
|
next_char(ls);
|
|
|
|
eina_strbuf_reset(ls->buff);
|
|
|
|
read_escape(ls);
|
|
|
|
tok->value.c = (char)*eina_strbuf_string_get(ls->buff);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tok->value.c = ls->current;
|
|
|
|
next_char(ls);
|
|
|
|
}
|
|
|
|
if (ls->current != '\'')
|
|
|
|
eo_lexer_lex_error(ls, "unfinished character", TOK_CHAR);
|
|
|
|
next_char(ls);
|
|
|
|
ls->column = dcol + 1;
|
|
|
|
return TOK_CHAR;
|
|
|
|
}
|
2014-07-17 05:07:39 -07:00
|
|
|
case '.':
|
2016-06-13 06:53:35 -07:00
|
|
|
{
|
|
|
|
int dcol = ls->column;
|
|
|
|
next_char(ls);
|
|
|
|
if (!isdigit(ls->current)) return '.';
|
|
|
|
eina_strbuf_reset(ls->buff);
|
|
|
|
eina_strbuf_append_char(ls->buff, '.');
|
|
|
|
read_number(ls, tok);
|
|
|
|
ls->column = dcol + 1;
|
|
|
|
return TOK_NUMBER;
|
|
|
|
}
|
2014-07-01 10:25:17 -07:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
if (isspace(ls->current))
|
|
|
|
{
|
|
|
|
assert(!is_newline(ls->current));
|
|
|
|
next_char(ls);
|
2014-06-18 03:25:07 -07:00
|
|
|
continue;
|
2014-07-01 10:25:17 -07:00
|
|
|
}
|
2016-06-30 06:04:03 -07:00
|
|
|
else if (isdigit(ls->current))
|
2014-07-17 05:07:39 -07:00
|
|
|
{
|
2016-06-13 06:53:35 -07:00
|
|
|
int col = ls->column;
|
2014-07-17 05:07:39 -07:00
|
|
|
eina_strbuf_reset(ls->buff);
|
|
|
|
read_number(ls, tok);
|
2016-06-13 06:53:35 -07:00
|
|
|
ls->column = col + 1;
|
2014-07-17 05:07:39 -07:00
|
|
|
return TOK_NUMBER;
|
|
|
|
}
|
2014-07-01 10:25:17 -07:00
|
|
|
if (ls->current && (isalnum(ls->current)
|
2014-07-16 06:46:38 -07:00
|
|
|
|| ls->current == '@' || ls->current == '_'))
|
2014-07-01 10:25:17 -07:00
|
|
|
{
|
2014-07-02 15:39:35 -07:00
|
|
|
int col = ls->column;
|
2014-07-01 10:25:17 -07:00
|
|
|
Eina_Bool at_kw = (ls->current == '@');
|
|
|
|
const char *str;
|
|
|
|
eina_strbuf_reset(ls->buff);
|
|
|
|
do
|
|
|
|
{
|
|
|
|
eina_strbuf_append_char(ls->buff, ls->current);
|
2014-06-18 03:25:07 -07:00
|
|
|
next_char(ls);
|
2014-07-01 10:25:17 -07:00
|
|
|
}
|
|
|
|
while (ls->current && (isalnum(ls->current)
|
2014-07-16 06:46:38 -07:00
|
|
|
|| ls->current == '_'));
|
2014-07-17 05:07:39 -07:00
|
|
|
str = eina_strbuf_string_get(ls->buff);
|
|
|
|
tok->kw = (int)(uintptr_t)eina_hash_find(keyword_map,
|
2014-07-01 10:25:17 -07:00
|
|
|
str);
|
2014-07-02 16:14:28 -07:00
|
|
|
ls->column = col + 1;
|
2016-05-23 02:49:42 -07:00
|
|
|
tok->value.s = eina_stringshare_add(str);
|
2014-07-17 05:07:39 -07:00
|
|
|
if (at_kw && tok->kw == 0)
|
2014-07-01 10:25:17 -07:00
|
|
|
eo_lexer_syntax_error(ls, "invalid keyword");
|
|
|
|
return TOK_VALUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int c = ls->current;
|
|
|
|
next_char(ls);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-08 07:19:52 -07:00
|
|
|
static const char *
|
|
|
|
get_filename(Eo_Lexer *ls)
|
|
|
|
{
|
2017-01-21 09:05:26 -08:00
|
|
|
const char *fslash = strrchr(ls->source, '/');
|
|
|
|
const char *bslash = strrchr(ls->source, '\\');
|
|
|
|
if (fslash || bslash)
|
|
|
|
return eina_stringshare_add((fslash > bslash) ? (fslash + 1) : (bslash + 1));
|
|
|
|
return eina_stringshare_ref(ls->source);
|
2014-08-08 07:19:52 -07:00
|
|
|
}
|
|
|
|
|
2018-03-15 07:31:08 -07:00
|
|
|
static void
|
|
|
|
_node_free(Eolian_Object *obj)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
/* for when we have a proper node allocator and collect on shutdown */
|
|
|
|
if (obj->refcount > 1)
|
|
|
|
{
|
|
|
|
_eolian_log("node %p (type %d, name %s at %s:%d:%d)"
|
|
|
|
" dangling ref (count: %d)", obj, obj->type, obj->name,
|
|
|
|
obj->file, obj->line, obj->column, obj->refcount);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
switch (obj->type)
|
|
|
|
{
|
|
|
|
case EOLIAN_OBJECT_CLASS:
|
|
|
|
database_class_del((Eolian_Class *)obj);
|
|
|
|
break;
|
|
|
|
case EOLIAN_OBJECT_TYPEDECL:
|
|
|
|
database_typedecl_del((Eolian_Typedecl *)obj);
|
|
|
|
break;
|
|
|
|
case EOLIAN_OBJECT_TYPE:
|
|
|
|
database_type_del((Eolian_Type *)obj);
|
|
|
|
break;
|
|
|
|
case EOLIAN_OBJECT_VARIABLE:
|
|
|
|
database_var_del((Eolian_Variable *)obj);
|
|
|
|
break;
|
|
|
|
case EOLIAN_OBJECT_EXPRESSION:
|
|
|
|
database_expr_del((Eolian_Expression *)obj);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* normally unreachable, just for debug */
|
|
|
|
assert(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
static void
|
2018-02-27 04:00:36 -08:00
|
|
|
eo_lexer_set_input(Eo_Lexer *ls, Eolian_State *state, const char *source)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
Eina_File *f = eina_file_open(source, EINA_FALSE);
|
|
|
|
if (!f)
|
2014-07-02 17:48:00 -07:00
|
|
|
{
|
2017-10-30 22:20:09 -07:00
|
|
|
_eolian_log("%s", strerror(errno));
|
2014-07-02 17:48:00 -07:00
|
|
|
longjmp(ls->err_jmp, EINA_TRUE);
|
|
|
|
}
|
2014-07-16 08:06:04 -07:00
|
|
|
ls->lookahead.token = -1;
|
2017-12-06 06:06:54 -08:00
|
|
|
ls->state = state;
|
2014-06-18 03:25:07 -07:00
|
|
|
ls->buff = eina_strbuf_new();
|
|
|
|
ls->handle = f;
|
|
|
|
ls->stream = eina_file_map_all(f, EINA_FILE_RANDOM);
|
2014-06-20 02:45:55 -07:00
|
|
|
ls->stream_end = ls->stream + eina_file_size_get(f);
|
2014-07-02 16:30:39 -07:00
|
|
|
ls->stream_line = ls->stream;
|
2014-06-18 03:25:07 -07:00
|
|
|
ls->source = eina_stringshare_add(source);
|
2014-08-08 07:19:52 -07:00
|
|
|
ls->filename = get_filename(ls);
|
2016-06-13 06:53:35 -07:00
|
|
|
ls->iline_number = ls->line_number = 1;
|
2015-05-19 07:26:53 -07:00
|
|
|
ls->icolumn = ls->column = -1;
|
2015-06-25 02:43:54 -07:00
|
|
|
ls->decpoint = '.';
|
2018-03-15 07:31:08 -07:00
|
|
|
ls->nodes = eina_hash_pointer_new(EINA_FREE_CB(_node_free));
|
2014-06-18 03:25:07 -07:00
|
|
|
next_char(ls);
|
2017-12-14 08:18:32 -08:00
|
|
|
|
|
|
|
Eolian_Unit *ncunit = calloc(1, sizeof(Eolian_Unit));
|
|
|
|
ls->unit = ncunit;
|
2018-02-27 06:53:35 -08:00
|
|
|
database_unit_init(state, ncunit, ls->filename);
|
2017-12-14 08:18:32 -08:00
|
|
|
eina_hash_add(state->units, ls->filename, ncunit);
|
|
|
|
|
2014-09-05 02:04:11 -07:00
|
|
|
if (ls->current != 0xEF)
|
|
|
|
return;
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current != 0xBB)
|
|
|
|
return;
|
|
|
|
next_char(ls);
|
|
|
|
if (ls->current != 0xBF)
|
|
|
|
return;
|
|
|
|
next_char(ls);
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
|
2018-03-15 05:53:50 -07:00
|
|
|
Eolian_Object *
|
|
|
|
eo_lexer_node_new(Eo_Lexer *ls, size_t objsize)
|
|
|
|
{
|
|
|
|
Eolian_Object *obj = calloc(1, objsize);
|
2018-03-15 07:31:08 -07:00
|
|
|
eina_hash_add(ls->nodes, &obj, obj);
|
2018-03-15 05:53:50 -07:00
|
|
|
eolian_object_ref(obj);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2018-03-15 07:31:08 -07:00
|
|
|
Eolian_Object *
|
|
|
|
eo_lexer_node_release(Eo_Lexer *ls, Eolian_Object *obj)
|
2018-03-15 05:53:50 -07:00
|
|
|
{
|
2018-03-15 07:31:08 -07:00
|
|
|
/* just for debug */
|
|
|
|
assert(eina_hash_find(ls->nodes, &obj) && (obj->refcount >= 1));
|
|
|
|
eolian_object_unref(obj);
|
|
|
|
eina_hash_set(ls->nodes, &obj, NULL);
|
|
|
|
return obj;
|
2018-03-15 05:53:50 -07:00
|
|
|
}
|
|
|
|
|
2015-06-02 10:12:09 -07:00
|
|
|
static void
|
|
|
|
_free_tok(Eo_Token *tok)
|
|
|
|
{
|
|
|
|
if (tok->token < START_CUSTOM || tok->token == TOK_NUMBER ||
|
|
|
|
tok->token == TOK_CHAR)
|
|
|
|
return;
|
|
|
|
if (tok->token == TOK_DOC)
|
|
|
|
{
|
|
|
|
/* free doc */
|
2015-06-03 07:35:13 -07:00
|
|
|
if (!tok->value.doc) return;
|
2015-06-02 10:12:09 -07:00
|
|
|
eina_stringshare_del(tok->value.doc->summary);
|
|
|
|
eina_stringshare_del(tok->value.doc->description);
|
|
|
|
free(tok->value.doc);
|
|
|
|
tok->value.doc = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
eina_stringshare_del(tok->value.s);
|
|
|
|
tok->value.s = NULL;
|
|
|
|
}
|
|
|
|
|
2018-03-15 06:12:18 -07:00
|
|
|
void
|
|
|
|
eo_lexer_dtor_push(Eo_Lexer *ls, Eina_Free_Cb free_cb, void *data)
|
|
|
|
{
|
|
|
|
Eo_Lexer_Dtor *dt = malloc(sizeof(Eo_Lexer_Dtor));
|
|
|
|
dt->free_cb = free_cb;
|
|
|
|
dt->data = data;
|
|
|
|
ls->dtors = eina_list_prepend(ls->dtors, dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
eo_lexer_dtor_pop(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
Eo_Lexer_Dtor *dt = eina_list_data_get(ls->dtors);
|
|
|
|
ls->dtors = eina_list_remove_list(ls->dtors, ls->dtors);
|
2018-03-15 08:34:08 -07:00
|
|
|
dt->free_cb(dt->data);
|
2018-03-15 06:12:18 -07:00
|
|
|
free(dt);
|
|
|
|
}
|
|
|
|
|
2014-03-29 21:07:19 -07:00
|
|
|
void
|
2014-06-18 03:25:07 -07:00
|
|
|
eo_lexer_free(Eo_Lexer *ls)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
if (!ls) return;
|
2014-08-08 07:19:52 -07:00
|
|
|
if (ls->source ) eina_stringshare_del(ls->source);
|
|
|
|
if (ls->filename) eina_stringshare_del(ls->filename);
|
|
|
|
if (ls->buff ) eina_strbuf_free (ls->buff);
|
|
|
|
if (ls->handle ) eina_file_close (ls->handle);
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2015-06-02 10:12:09 -07:00
|
|
|
_free_tok(&ls->t);
|
2014-07-22 07:27:11 -07:00
|
|
|
eo_lexer_context_clear(ls);
|
2018-03-15 06:12:18 -07:00
|
|
|
|
|
|
|
Eo_Lexer_Dtor *dtor;
|
|
|
|
EINA_LIST_FREE(ls->dtors, dtor)
|
|
|
|
dtor->free_cb(dtor->data);
|
|
|
|
|
2018-03-15 07:31:08 -07:00
|
|
|
eina_hash_free(ls->nodes);
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
free(ls);
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
Eo_Lexer *
|
2018-02-27 04:00:36 -08:00
|
|
|
eo_lexer_new(Eolian_State *state, const char *source)
|
2014-04-16 06:17:27 -07:00
|
|
|
{
|
2016-12-15 10:44:22 -08:00
|
|
|
volatile Eo_Lexer *ls = calloc(1, sizeof(Eo_Lexer));
|
|
|
|
|
|
|
|
if (!setjmp(((Eo_Lexer *)(ls))->err_jmp))
|
2014-04-16 06:17:27 -07:00
|
|
|
{
|
2017-12-06 06:06:54 -08:00
|
|
|
eo_lexer_set_input((Eo_Lexer *) ls, state, source);
|
2016-12-15 10:44:22 -08:00
|
|
|
return (Eo_Lexer *) ls;
|
2014-04-16 06:17:27 -07:00
|
|
|
}
|
2016-12-15 10:44:22 -08:00
|
|
|
eo_lexer_free((Eo_Lexer *) ls);
|
2014-06-18 03:25:07 -07:00
|
|
|
return NULL;
|
2014-04-16 06:17:27 -07:00
|
|
|
}
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
int
|
|
|
|
eo_lexer_get(Eo_Lexer *ls)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2015-06-02 10:12:09 -07:00
|
|
|
_free_tok(&ls->t);
|
2014-07-16 08:06:04 -07:00
|
|
|
if (ls->lookahead.token >= 0)
|
2014-07-16 06:46:38 -07:00
|
|
|
{
|
|
|
|
ls->t = ls->lookahead;
|
2014-07-16 08:06:04 -07:00
|
|
|
ls->lookahead.token = -1;
|
2014-07-16 06:46:38 -07:00
|
|
|
return ls->t.token;
|
|
|
|
}
|
|
|
|
ls->t.kw = 0;
|
2014-07-17 05:07:39 -07:00
|
|
|
return (ls->t.token = lex(ls, &ls->t));
|
2014-06-18 03:25:07 -07:00
|
|
|
}
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
int
|
|
|
|
eo_lexer_lookahead(Eo_Lexer *ls)
|
|
|
|
{
|
2014-07-16 08:06:04 -07:00
|
|
|
assert (ls->lookahead.token < 0);
|
2014-06-18 03:25:07 -07:00
|
|
|
ls->lookahead.kw = 0;
|
2014-07-22 07:27:11 -07:00
|
|
|
eo_lexer_context_push(ls);
|
|
|
|
ls->lookahead.token = lex(ls, &ls->lookahead);
|
|
|
|
eo_lexer_context_restore(ls);
|
|
|
|
eo_lexer_context_pop(ls);
|
|
|
|
return ls->lookahead.token;
|
2014-06-18 03:25:07 -07:00
|
|
|
}
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
void
|
|
|
|
eo_lexer_lex_error(Eo_Lexer *ls, const char *msg, int token)
|
|
|
|
{
|
|
|
|
if (token)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
char buf[256];
|
|
|
|
txt_token(ls, token, buf);
|
2015-05-15 07:10:58 -07:00
|
|
|
throw(ls, "%s near '%s'", msg, buf);
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
2014-06-18 03:25:07 -07:00
|
|
|
else
|
2015-05-15 07:10:58 -07:00
|
|
|
throw(ls, "%s", msg);
|
2014-06-18 03:25:07 -07:00
|
|
|
}
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
void
|
|
|
|
eo_lexer_syntax_error(Eo_Lexer *ls, const char *msg)
|
|
|
|
{
|
|
|
|
eo_lexer_lex_error(ls, msg, ls->t.token);
|
|
|
|
}
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
void
|
|
|
|
eo_lexer_token_to_str(int token, char *buf)
|
|
|
|
{
|
2014-07-16 08:06:04 -07:00
|
|
|
if (token < 0)
|
|
|
|
{
|
|
|
|
memcpy(buf, "<eof>", 6);
|
|
|
|
}
|
2015-05-01 03:57:50 -07:00
|
|
|
else if (token < START_CUSTOM)
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
assert((unsigned char)token == token);
|
|
|
|
if (iscntrl(token))
|
2014-07-01 10:25:17 -07:00
|
|
|
sprintf(buf, "char(%d)", token);
|
2014-06-18 03:25:07 -07:00
|
|
|
else
|
2014-07-01 10:25:17 -07:00
|
|
|
sprintf(buf, "%c", token);
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
2014-06-18 03:25:07 -07:00
|
|
|
else
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2015-09-21 07:26:41 -07:00
|
|
|
const char *v;
|
|
|
|
size_t idx = token - START_CUSTOM;
|
2015-10-04 06:52:36 -07:00
|
|
|
size_t tsz = sizeof(tokens) / sizeof(tokens[0]);
|
|
|
|
if (idx >= tsz)
|
|
|
|
v = keywords[idx - tsz];
|
2015-09-21 07:26:41 -07:00
|
|
|
else
|
|
|
|
v = tokens[idx];
|
2014-06-18 03:25:07 -07:00
|
|
|
memcpy(buf, v, strlen(v) + 1);
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
2014-06-18 03:25:07 -07:00
|
|
|
}
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2014-06-20 07:31:45 -07:00
|
|
|
const char *
|
|
|
|
eo_lexer_keyword_str_get(int kw)
|
|
|
|
{
|
2015-09-21 07:26:41 -07:00
|
|
|
return keywords[kw - 1];
|
2014-06-20 07:31:45 -07:00
|
|
|
}
|
|
|
|
|
2014-06-26 04:02:19 -07:00
|
|
|
Eina_Bool
|
|
|
|
eo_lexer_is_type_keyword(int kw)
|
|
|
|
{
|
2015-06-10 08:38:41 -07:00
|
|
|
return (kw >= KW_byte && kw < KW_true);
|
2014-06-26 04:02:19 -07:00
|
|
|
}
|
|
|
|
|
2014-08-07 07:15:07 -07:00
|
|
|
int
|
|
|
|
eo_lexer_keyword_str_to_id(const char *kw)
|
|
|
|
{
|
|
|
|
return (int)(uintptr_t)eina_hash_find(keyword_map, kw);
|
|
|
|
}
|
|
|
|
|
2014-06-26 04:02:19 -07:00
|
|
|
const char *
|
|
|
|
eo_lexer_get_c_type(int kw)
|
|
|
|
{
|
|
|
|
if (!eo_lexer_is_type_keyword(kw)) return NULL;
|
2014-07-14 08:25:26 -07:00
|
|
|
return ctypes[kw - KW_byte];
|
2014-06-26 04:02:19 -07:00
|
|
|
}
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
static int _init_counter = 0;
|
2014-03-29 21:07:19 -07:00
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
int
|
|
|
|
eo_lexer_init()
|
|
|
|
{
|
|
|
|
if (!_init_counter)
|
2014-04-30 02:03:09 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
eina_init();
|
|
|
|
init_hash();
|
2014-04-30 02:03:09 -07:00
|
|
|
}
|
2014-06-18 03:25:07 -07:00
|
|
|
return _init_counter++;
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
|
|
|
|
2014-06-18 03:25:07 -07:00
|
|
|
int
|
|
|
|
eo_lexer_shutdown()
|
2014-03-29 21:07:19 -07:00
|
|
|
{
|
2014-06-18 03:25:07 -07:00
|
|
|
if (_init_counter <= 0) return 0;
|
|
|
|
_init_counter--;
|
|
|
|
if (!_init_counter)
|
|
|
|
{
|
|
|
|
destroy_hash();
|
|
|
|
eina_shutdown();
|
|
|
|
}
|
|
|
|
return _init_counter;
|
2014-03-29 21:07:19 -07:00
|
|
|
}
|
2014-07-22 07:27:11 -07:00
|
|
|
|
2015-05-27 03:25:04 -07:00
|
|
|
static Eina_Bool
|
|
|
|
_eo_is_tokstr(int t) {
|
2015-09-03 07:08:08 -07:00
|
|
|
return (t == TOK_STRING) || (t == TOK_VALUE);
|
2015-05-27 03:25:04 -07:00
|
|
|
}
|
|
|
|
|
2014-07-22 07:27:11 -07:00
|
|
|
void
|
|
|
|
eo_lexer_context_push(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
Lexer_Ctx *ctx = malloc(sizeof(Lexer_Ctx));
|
2017-07-13 02:12:01 -07:00
|
|
|
if (!ctx)
|
|
|
|
{
|
2017-10-30 22:20:09 -07:00
|
|
|
_eolian_log("out of memory pushing context");
|
2017-07-13 02:12:01 -07:00
|
|
|
longjmp(ls->err_jmp, EINA_TRUE);
|
|
|
|
}
|
2014-07-22 07:27:11 -07:00
|
|
|
ctx->line = ls->line_number;
|
|
|
|
ctx->column = ls->column;
|
|
|
|
ctx->linestr = ls->stream_line;
|
2015-05-27 03:25:04 -07:00
|
|
|
ctx->token = ls->t;
|
|
|
|
if (_eo_is_tokstr(ctx->token.token))
|
|
|
|
eina_stringshare_ref(ctx->token.value.s);
|
2014-07-22 07:27:11 -07:00
|
|
|
ls->saved_ctxs = eina_list_prepend(ls->saved_ctxs, ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
eo_lexer_context_pop(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
Lexer_Ctx *ctx = (Lexer_Ctx*)eina_list_data_get(ls->saved_ctxs);
|
2015-05-27 03:25:04 -07:00
|
|
|
if (_eo_is_tokstr(ctx->token.token))
|
|
|
|
eina_stringshare_del(ctx->token.value.s);
|
2014-07-22 07:27:11 -07:00
|
|
|
free(ctx);
|
|
|
|
ls->saved_ctxs = eina_list_remove_list(ls->saved_ctxs, ls->saved_ctxs);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
eo_lexer_context_restore(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
if (!eina_list_count(ls->saved_ctxs)) return;
|
|
|
|
Lexer_Ctx *ctx = (Lexer_Ctx*)eina_list_data_get(ls->saved_ctxs);
|
|
|
|
ls->line_number = ctx->line;
|
|
|
|
ls->column = ctx->column;
|
|
|
|
ls->stream_line = ctx->linestr;
|
2015-05-27 03:25:04 -07:00
|
|
|
if (_eo_is_tokstr(ls->t.token))
|
|
|
|
eina_stringshare_del(ls->t.value.s);
|
|
|
|
ls->t = ctx->token;
|
|
|
|
if (_eo_is_tokstr(ls->t.token))
|
|
|
|
eina_stringshare_ref(ls->t.value.s);
|
2014-07-22 07:27:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
eo_lexer_context_clear(Eo_Lexer *ls)
|
|
|
|
{
|
|
|
|
Lexer_Ctx *ctx;
|
|
|
|
EINA_LIST_FREE(ls->saved_ctxs, ctx) free(ctx);
|
|
|
|
}
|