From db1b637faea4dfc2c1acd06f282f26a5d88bdcae Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Sun, 26 May 2019 18:09:34 +0200 Subject: [PATCH] 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 --- src/lib/eolian/eo_lexer.c | 8 +++++--- src/lib/eolian/eo_lexer.h | 4 ++++ src/lib/eolian/eo_parser.c | 34 +++++++++++++++++++++++++++++--- src/lib/eolian/eolian_database.c | 3 +++ src/lib/eolian/eolian_database.h | 1 + 5 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/lib/eolian/eo_lexer.c b/src/lib/eolian/eo_lexer.c index 6b2747a130..aad79d8f71 100644 --- a/src/lib/eolian/eo_lexer.c +++ b/src/lib/eolian/eo_lexer.c @@ -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; } diff --git a/src/lib/eolian/eo_lexer.h b/src/lib/eolian/eo_lexer.h index e9b5e7b0e0..5bc7064151 100644 --- a/src/lib/eolian/eo_lexer.h +++ b/src/lib/eolian/eo_lexer.h @@ -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 { diff --git a/src/lib/eolian/eo_parser.c b/src/lib/eolian/eo_parser.c index 524b31a383..74c76d3a7d 100644 --- a/src/lib/eolian/eo_parser.c +++ b/src/lib/eolian/eo_parser.c @@ -1,4 +1,5 @@ #include +#include #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 * diff --git a/src/lib/eolian/eolian_database.c b/src/lib/eolian/eolian_database.c index 93e833e9a5..0fb5a134f6 100644 --- a/src/lib/eolian/eolian_database.c +++ b/src/lib/eolian/eolian_database.c @@ -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 diff --git a/src/lib/eolian/eolian_database.h b/src/lib/eolian/eolian_database.h index f74d0fa31a..0dce769370 100644 --- a/src/lib/eolian/eolian_database.h +++ b/src/lib/eolian/eolian_database.h @@ -45,6 +45,7 @@ struct _Eolian_Unit Eina_Hash *structs; Eina_Hash *enums; Eina_Hash *objects; + unsigned short version; }; typedef struct _Eolian_State_Area