eolian: initial versioning implementation

This implements initial support for specifying unit versions.
The default version is 1, specifying the basic feature level.

If you want to specify another version, you need to specify
something like `#version 2` at the beginning of the .eo or
.eot file; the version number must be higher than 0 and lower
than USHRT_MAX (typically 65536).

The beginning of the file is now called the "header section";
other things may be added into the header section later.
Version cannot be specified twice, and it cannot be specified
once other contents (like types or class definition) appear.
Comments do not count as other contents, so those are fine
to appear before #version.

@feature
This commit is contained in:
Daniel Kolesa 2019-05-26 18:09:34 +02:00
parent 13ddc5dbc1
commit db1b637fae
5 changed files with 44 additions and 6 deletions

View File

@ -45,6 +45,7 @@ next_char(Eo_Lexer *ls)
#define KW(x) #x
#define KWAT(x) "@" #x
#define KWH(x) "#" #x
static const char * const tokens[] =
{
@ -87,6 +88,7 @@ static const char * const ctypes[] =
#undef KW
#undef KWAT
#undef KWH
#define is_newline(c) ((c) == '\n' || (c) == '\r')
@ -989,10 +991,10 @@ lex(Eo_Lexer *ls, Eo_Token *tok)
return TOK_NUMBER;
}
if (ls->current && (isalnum(ls->current)
|| ls->current == '@' || ls->current == '_'))
|| ls->current == '@' || ls->current == '#' || ls->current == '_'))
{
int col = ls->column;
Eina_Bool at_kw = (ls->current == '@');
Eina_Bool pfx_kw = (ls->current == '@') || (ls->current == '#');
const char *str;
eina_strbuf_reset(ls->buff);
do
@ -1007,7 +1009,7 @@ lex(Eo_Lexer *ls, Eo_Token *tok)
str);
ls->column = col + 1;
tok->value.s = eina_stringshare_add(str);
if (at_kw && tok->kw == 0)
if (pfx_kw && tok->kw == 0)
eo_lexer_syntax_error(ls, "invalid keyword");
return TOK_VALUE;
}

View File

@ -39,6 +39,8 @@ enum Tokens
KWAT(private), KWAT(property), KWAT(protected), KWAT(restart), \
KWAT(pure_virtual), \
\
KWH(version), \
\
KW(byte), KW(ubyte), KW(char), KW(short), KW(ushort), KW(int), KW(uint), \
KW(long), KW(ulong), KW(llong), KW(ullong), \
\
@ -71,6 +73,7 @@ enum Tokens
/* "regular" keyword and @ prefixed keyword */
#define KW(x) KW_##x
#define KWAT(x) KW_at_##x
#define KWH(x) KW_hash_##x
enum Keywords
{
@ -80,6 +83,7 @@ enum Keywords
#undef KW
#undef KWAT
#undef KWH
enum Numbers
{

View File

@ -1,4 +1,5 @@
#include <assert.h>
#include <limits.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
@ -2278,10 +2279,37 @@ found_class:
static void
parse_chunk(Eo_Lexer *ls, Eina_Bool eot)
{
Eina_Bool parsing_header = EINA_TRUE;
Eina_Bool has_version = EINA_FALSE;
while (ls->t.token >= 0)
/* set eot to EINA_TRUE so that we only allow parsing of one class */
if (parse_unit(ls, eot))
eot = EINA_TRUE;
switch (ls->t.kw)
{
case KW_hash_version:
{
CASE_LOCK(ls, version, "#version specifier");
if (!parsing_header)
eo_lexer_syntax_error(ls, "header keyword outside of unit header");
eo_lexer_get(ls);
check(ls, TOK_NUMBER);
if (ls->t.kw != NUM_INT)
eo_lexer_syntax_error(ls, "invalid #version value");
if (ls->t.value.u > USHRT_MAX)
eo_lexer_syntax_error(ls, "#version too high");
else if (ls->t.value.u < 0)
eo_lexer_syntax_error(ls, "#version too low");
ls->unit->version = (unsigned short)(ls->t.value.u);
eo_lexer_get(ls);
break;
}
default:
parsing_header = EINA_FALSE;
/* set eot to EINA_TRUE so that we only allow parsing of one class */
if (parse_unit(ls, eot))
eot = EINA_TRUE;
break;
}
}
Eolian_Unit *

View File

@ -572,6 +572,9 @@ database_unit_init(Eolian_State *state, Eolian_Unit *unit, const char *file)
unit->structs = eina_hash_stringshared_new(EINA_FREE_CB(database_typedecl_del));
unit->enums = eina_hash_stringshared_new(EINA_FREE_CB(database_typedecl_del));
unit->objects = eina_hash_stringshared_new(NULL);
/* baseline version; support for higher featurelevel must be specified explicitly */
unit->version = 1;
}
static void

View File

@ -45,6 +45,7 @@ struct _Eolian_Unit
Eina_Hash *structs;
Eina_Hash *enums;
Eina_Hash *objects;
unsigned short version;
};
typedef struct _Eolian_State_Area