eolian: initial support for expression parsing

This commit is contained in:
Daniel Kolesa 2014-07-17 17:16:31 +01:00
parent e3192796b6
commit 436a37f0b9
6 changed files with 344 additions and 59 deletions

View File

@ -74,6 +74,12 @@ typedef struct _Eolian_Implement Eolian_Implement;
*/
typedef struct _Eolian_Event Eolian_Event;
/* Expression information
*
* @ingroup Eolian
*/
typedef struct _Eolian_Expression Eolian_Expression;
#define EOLIAN_LEGACY "legacy"
#define EOLIAN_LEGACY_GET "legacy_get"
#define EOLIAN_LEGACY_SET "legacy_set"
@ -126,6 +132,59 @@ typedef enum
EOLIAN_TYPE_CLASS
} Eolian_Type_Type;
typedef enum
{
EOLIAN_EXPR_UNKNOWN,
EOLIAN_EXPR_INT,
EOLIAN_EXPR_UINT,
EOLIAN_EXPR_LONG,
EOLIAN_EXPR_ULONG,
EOLIAN_EXPR_LLONG,
EOLIAN_EXPR_ULLONG,
EOLIAN_EXPR_FLOAT,
EOLIAN_EXPR_DOUBLE,
EOLIAN_EXPR_LDOUBLE,
EOLIAN_EXPR_STRING,
EOLIAN_EXPR_BOOL,
EOLIAN_EXPR_NAME,
EOLIAN_EXPR_UNARY,
EOLIAN_EXPR_BINARY
} Eolian_Expression_Type;
typedef enum
{
BOP_ADD, /* + */
BOP_SUB, /* - */
BOP_MUL, /* * */
BOP_DIV, /* / */
BOP_MOD, /* % */
BOP_EQ, /* == */
BOP_NQ, /* != */
BOP_GT, /* > */
BOP_LT, /* < */
BOP_GE, /* >= */
BOP_LE, /* <= */
BOP_AND, /* && */
BOP_OR, /* || */
BOP_BAND, /* & */
BOP_BOR, /* | */
BOP_BXOR, /* ^ */
BOP_LSH, /* << */
BOP_RSH /* >> */
} Eolian_Binary_Operator;
typedef enum
{
UOP_UNM, /* - */
UOP_UNP, /* + */
UOP_NOT, /* ! */
UOP_BNOT, /* ~ */
} Eolian_Unary_Operator;
/*
* @brief Parse a given .eo file and fill the database.
*

View File

@ -118,6 +118,7 @@ typedef struct _Eo_Lexer_Temps
Eina_List *str_items;
Eolian_Event *event;
Eolian_Implement *impl;
Eina_List *expr_defs;
} Eo_Lexer_Temps;
void eo_definitions_class_def_free(Eo_Class_Def *kls);

View File

@ -44,6 +44,8 @@ next_char(Eo_Lexer *ls)
static const char * const tokens[] =
{
"==", "!=", ">", "<", ">=", "<=", "&&", "||", "<<", ">>",
"<comment>", "<string>", "<number>", "<value>",
KEYWORDS
@ -101,12 +103,12 @@ throw(Eo_Lexer *ls, const char *fmt, ...)
static void
init_hash(void)
{
unsigned int i;
unsigned int i, u;
if (keyword_map) return;
keyword_map = eina_hash_string_superfast_new(NULL);
for (i = 4; i < (sizeof(tokens) / sizeof(const char*)); ++i)
for (i = u = 14; i < (sizeof(tokens) / sizeof(const char*)); ++i)
{
eina_hash_add(keyword_map, tokens[i], (void*)(size_t)(i - 3));
eina_hash_add(keyword_map, tokens[i], (void*)(size_t)(i - u + 1));
}
}
@ -193,7 +195,7 @@ read_long_comment(Eo_Lexer *ls, Eo_Token *tok)
}
}
eina_strbuf_trim(ls->buff);
if (tok) tok->value = eina_stringshare_add(eina_strbuf_string_get(ls->buff));
if (tok) tok->value.s = eina_stringshare_add(eina_strbuf_string_get(ls->buff));
}
static void
@ -302,8 +304,8 @@ skip:
}
eina_strbuf_append_char(ls->buff, ls->current);
next_char(ls);
tok->value = eina_stringshare_add_length(eina_strbuf_string_get(ls->buff) + 1,
(unsigned int)eina_strbuf_length_get(ls->buff) - 2);
tok->value.s = eina_stringshare_add_length(eina_strbuf_string_get(ls->buff) + 1,
(unsigned int)eina_strbuf_length_get(ls->buff) - 2);
}
static int
@ -360,21 +362,21 @@ write_val(Eo_Lexer *ls, Eo_Token *tok, Eina_Bool is_float)
if (is_float)
{
if (type == NUM_FLOAT)
tok->value_f = strtof(str, &end);
tok->value.f = strtof(str, &end);
else if (type == NUM_DOUBLE)
tok->value_d = strtod(str, &end);
tok->value.d = strtod(str, &end);
else if (type == NUM_LDOUBLE)
tok->value_ld = strtold(str, &end);
tok->value.ld = strtold(str, &end);
}
else
{
/* signed is always in the same memory location */
if (type == NUM_INT || type == NUM_UINT)
tok->value_u = strtoul(str, &end, 0);
tok->value.u = strtoul(str, &end, 0);
else if (type == NUM_LONG || type == NUM_ULONG)
tok->value_ul = strtoul(str, &end, 0);
tok->value.ul = strtoul(str, &end, 0);
else if (type == NUM_LLONG || type == NUM_ULLONG)
tok->value_ull = strtoull(str, &end, 0);
tok->value.ull = strtoull(str, &end, 0);
}
if (end)
eo_lexer_lex_error(ls, "malformed number", TOK_NUMBER);
@ -455,7 +457,7 @@ static int
lex(Eo_Lexer *ls, Eo_Token *tok)
{
eina_strbuf_reset(ls->buff);
tok->value = NULL;
tok->value.s = NULL;
for (;;) switch (ls->current)
{
case '\n':
@ -526,7 +528,7 @@ lex(Eo_Lexer *ls, Eo_Token *tok)
ls->column = col + 1;
if (at_kw && tok->kw == 0)
eo_lexer_syntax_error(ls, "invalid keyword");
tok->value = eina_stringshare_add(str);
tok->value.s = eina_stringshare_add(str);
return TOK_VALUE;
}
else
@ -564,7 +566,7 @@ lex_balanced(Eo_Lexer *ls, Eo_Token *tok, char beg, char end)
eina_strbuf_trim(ls->buff);
str = eina_strbuf_string_get(ls->buff);
tok->kw = (int)(uintptr_t)eina_hash_find(keyword_map, str);
tok->value = eina_stringshare_add(str);
tok->value.s = eina_stringshare_add(str);
ls->column = col + 1;
return TOK_VALUE;
}
@ -645,8 +647,8 @@ eo_lexer_get(Eo_Lexer *ls)
{
if (ls->t.token >= START_CUSTOM && ls->t.token != TOK_NUMBER)
{
eina_stringshare_del(ls->t.value);
ls->t.value = NULL;
eina_stringshare_del(ls->t.value.s);
ls->t.value.s = NULL;
}
if (ls->lookahead.token >= 0)
{
@ -714,7 +716,7 @@ eo_lexer_token_to_str(int token, char *buf)
const char *
eo_lexer_keyword_str_get(int kw)
{
return tokens[kw + 3];
return tokens[kw + 13];
}
Eina_Bool

View File

@ -13,7 +13,10 @@
enum Tokens
{
TOK_COMMENT = START_CUSTOM, TOK_STRING, TOK_NUMBER, TOK_VALUE
TOK_EQ = START_CUSTOM, TOK_NQ, TOK_GT, TOK_LT, TOK_GE, TOK_LE,
TOK_AND, TOK_OR, TOK_LSH, TOK_RSH,
TOK_COMMENT, TOK_STRING, TOK_NUMBER, TOK_VALUE
};
/* all keywords in eolian, they can still be used as names (they're TOK_VALUE)
@ -79,19 +82,7 @@ enum Numbers
typedef struct _Eo_Token
{
int token, kw;
union
{
const char *value;
signed int value_i;
unsigned int value_u;
signed long value_l;
unsigned long value_ul;
signed long long value_ll;
unsigned long long value_ull;
float value_f;
double value_d;
long double value_ld;
};
Eolian_Value value;
} Eo_Token;
enum Nodes

View File

@ -170,7 +170,7 @@ parse_name(Eo_Lexer *ls, Eina_Strbuf *buf)
eina_strbuf_reset(buf);
for (;;)
{
eina_strbuf_append(buf, ls->t.value);
eina_strbuf_append(buf, ls->t.value.s);
eo_lexer_get(ls);
if (ls->t.token != '.') break;
eo_lexer_get(ls);
@ -223,6 +223,203 @@ _fill_type_name(Eolian_Type *tp, const char *type_name)
free(full_name);
}
static Eolian_Expression *
push_expr(Eo_Lexer *ls)
{
Eolian_Expression *def = calloc(1, sizeof(Eolian_Expression));
ls->tmp.expr_defs = eina_list_prepend(ls->tmp.expr_defs, def);
return def;
}
static void
pop_expr(Eo_Lexer *ls)
{
ls->tmp.expr_defs = eina_list_remove_list(ls->tmp.expr_defs, ls->tmp.expr_defs);
}
static Eolian_Binary_Operator
get_binop_id(int tok)
{
switch (tok)
{
case '+': return BOP_ADD;
case '-': return BOP_SUB;
case '*': return BOP_MUL;
case '/': return BOP_DIV;
case '%': return BOP_MOD;
case TOK_EQ: return BOP_EQ;
case TOK_NQ: return BOP_NQ;
case TOK_GT: return BOP_GT;
case TOK_LT: return BOP_LT;
case TOK_GE: return BOP_GE;
case TOK_LE: return BOP_LE;
case TOK_AND: return BOP_AND;
case TOK_OR : return BOP_OR;
case '&': return BOP_BAND;
case '|': return BOP_BOR;
case '^': return BOP_BXOR;
case TOK_LSH: return BOP_LSH;
case TOK_RSH: return BOP_RSH;
default: return -1;
}
}
static Eolian_Unary_Operator
get_unop_id(int tok)
{
switch (tok)
{
case '-': return UOP_UNM;
case '+': return UOP_UNP;
case '!': return UOP_NOT;
case '~': return UOP_BNOT;
default: return -1;
}
}
static const int binprec[] = {
8, /* + */
8, /* - */
9, /* * */
9, /* / */
9, /* % */
3, /* == */
3, /* != */
3, /* > */
3, /* < */
3, /* >= */
3, /* <= */
2, /* && */
1, /* || */
6, /* & */
4, /* | */
5, /* ^ */
7, /* << */
7 /* >> */
};
#define UNARY_PRECEDENCE 10
static int
get_binop_prec(Eolian_Binary_Operator id)
{
if (id < 0) return -1;
return binprec[id];
}
static Eolian_Expression *parse_expr_bin(Eo_Lexer *ls, int min_prec);
static Eolian_Expression *parse_expr(Eo_Lexer *ls);
static Eolian_Expression *
parse_expr_simple(Eo_Lexer *ls)
{
Eolian_Expression *expr;
Eolian_Unary_Operator unop = get_unop_id(ls->t.token);
if (unop >= 0)
{
Eolian_Expression *exp = parse_expr_bin(ls, UNARY_PRECEDENCE);
pop_expr(ls);
expr = push_expr(ls);
expr->binop = unop;
expr->type = EOLIAN_EXPR_UNARY;
expr->expr = exp;
return expr;
}
switch (ls->t.token)
{
case TOK_NUMBER:
{
expr = push_expr(ls);
expr->type = ls->t.kw + 1; /* map Numbers from lexer to expr type */
expr->value = ls->t.value;
eo_lexer_get(ls);
break;
}
case TOK_STRING:
{
expr = push_expr(ls);
expr->type = EOLIAN_EXPR_STRING;
expr->value.s = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
break;
}
case TOK_VALUE:
{
switch (ls->t.kw)
{
case KW_true:
case KW_false:
{
expr = push_expr(ls);
expr->type = EOLIAN_EXPR_BOOL;
expr->value.b = (ls->t.kw == KW_true);
eo_lexer_get(ls);
break;
}
default:
{
expr = push_expr(ls);
expr->type = EOLIAN_EXPR_NAME;
expr->value.s = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
break;
}
}
}
case '(':
{
int line = ls->line_number, col = ls->column;
eo_lexer_get(ls);
expr = parse_expr(ls);
check_match(ls, ')', '(', line, col);
}
default:
eo_lexer_syntax_error(ls, "unexpected symbol");
break;
}
return expr;
}
static Eolian_Expression *
parse_expr_bin(Eo_Lexer *ls, int min_prec)
{
Eolian_Expression *lhs = parse_expr_simple(ls);
for (;;)
{
Eolian_Expression *rhs, *bin;
Eolian_Binary_Operator op = get_binop_id(ls->t.token);
int prec = get_binop_prec(op);
if ((op < 0) || (prec < 0) || (prec < min_prec))
break;
rhs = parse_expr_bin(ls, prec + 1);
pop_expr(ls);
pop_expr(ls);
bin = push_expr(ls);
bin->binop = op;
bin->type = EOLIAN_EXPR_BINARY;
bin->lhs = lhs;
bin->rhs = rhs;
lhs = bin;
}
return lhs;
}
static Eolian_Expression *
parse_expr(Eo_Lexer *ls)
{
return parse_expr_bin(ls, 1);
}
static Eolian_Type *parse_type_void(Eo_Lexer *ls);
static Eolian_Type *parse_type_struct_void(Eo_Lexer *ls, Eina_Bool allow_struct);
@ -310,7 +507,7 @@ parse_struct(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
check_next(ls, '{');
if (ls->t.token == TOK_COMMENT)
{
def->comment = eina_stringshare_ref(ls->t.value);
def->comment = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
}
while (ls->t.token != '}')
@ -320,9 +517,9 @@ parse_struct(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
Eolian_Type *tp;
int fline = ls->line_number, fcol = ls->column;
check(ls, TOK_VALUE);
if (eina_hash_find(def->fields, ls->t.value))
if (eina_hash_find(def->fields, ls->t.value.s))
eo_lexer_syntax_error(ls, "double field definition");
fname = eina_stringshare_ref(ls->t.value);
fname = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
check_next(ls, ':');
tp = parse_type(ls);
@ -336,7 +533,7 @@ parse_struct(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
check_next(ls, ';');
if (ls->t.token == TOK_COMMENT)
{
fdef->comment = eina_stringshare_ref(ls->t.value);
fdef->comment = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
}
}
@ -570,7 +767,7 @@ parse_typedef(Eo_Lexer *ls)
check_next(ls, ';');
if (ls->t.token == TOK_COMMENT)
{
def->comment = eina_stringshare_ref(ls->t.value);
def->comment = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
}
return def;
@ -591,7 +788,7 @@ parse_return(Eo_Lexer *ls, Eina_Bool allow_void)
{
int line = ls->line_number, col = ls->column;
eo_lexer_get_balanced(ls, '(', ')');
ret->default_ret_val = eina_stringshare_ref(ls->t.value);
ret->default_ret_val = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
check_match(ls, ')', '(', line, col);
}
@ -603,7 +800,7 @@ parse_return(Eo_Lexer *ls, Eina_Bool allow_void)
check_next(ls, ';');
if (ls->t.token == TOK_COMMENT)
{
ret->comment = eina_stringshare_ref(ls->t.value);
ret->comment = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
}
}
@ -641,7 +838,7 @@ parse_param(Eo_Lexer *ls, Eina_Bool allow_inout)
par->type = parse_type(ls);
pop_type(ls);
check(ls, TOK_VALUE);
par->name = eina_stringshare_ref(ls->t.value);
par->name = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
if (ls->t.kw == KW_at_nonull)
{
@ -651,7 +848,7 @@ parse_param(Eo_Lexer *ls, Eina_Bool allow_inout)
check_next(ls, ';');
if (ls->t.token == TOK_COMMENT)
{
par->comment = eina_stringshare_ref(ls->t.value);
par->comment = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
}
}
@ -661,7 +858,7 @@ parse_legacy(Eo_Lexer *ls)
{
eo_lexer_get(ls);
check(ls, TOK_VALUE);
ls->tmp.legacy_def = eina_stringshare_ref(ls->t.value);
ls->tmp.legacy_def = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
check_next(ls, ';');
}
@ -673,7 +870,7 @@ parse_attrs(Eo_Lexer *ls)
Eina_Bool has_const = EINA_FALSE;
acc = calloc(1, sizeof(Eo_Accessor_Param));
ls->tmp.accessor_param = acc;
acc->name = eina_stringshare_ref(ls->t.value);
acc->name = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
check_next(ls, ':');
check(ls, TOK_VALUE);
@ -710,7 +907,7 @@ parse_accessor(Eo_Lexer *ls)
check_next(ls, '{');
if (ls->t.token == TOK_COMMENT)
{
acc->comment = eina_stringshare_ref(ls->t.value);
acc->comment = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
}
for (;;) switch (ls->t.kw)
@ -775,7 +972,7 @@ parse_property(Eo_Lexer *ls)
prop->base.column = ls->column;
ls->tmp.prop = prop;
check(ls, TOK_VALUE);
prop->name = eina_stringshare_ref(ls->t.value);
prop->name = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
for (;;) switch (ls->t.kw)
{
@ -848,7 +1045,7 @@ parse_method(Eo_Lexer *ls, Eina_Bool ctor)
{
if (ls->t.token != TOK_VALUE)
eo_lexer_syntax_error(ls, "expected method name");
meth->name = eina_stringshare_ref(ls->t.value);
meth->name = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
for (;;) switch (ls->t.kw)
{
@ -864,7 +1061,7 @@ parse_method(Eo_Lexer *ls, Eina_Bool ctor)
else
{
check(ls, TOK_VALUE);
meth->name = eina_stringshare_ref(ls->t.value);
meth->name = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
for (;;) switch (ls->t.kw)
{
@ -897,7 +1094,7 @@ body:
check_next(ls, '{');
if (ls->t.token == TOK_COMMENT)
{
meth->comment = eina_stringshare_ref(ls->t.value);
meth->comment = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
}
for (;;) switch (ls->t.kw)
@ -966,7 +1163,7 @@ parse_implement(Eo_Lexer *ls, Eina_Bool iface)
check_next(ls, '.');
if ((ls->t.token != TOK_VALUE) || (ls->t.kw == KW_get || ls->t.kw == KW_set))
eo_lexer_syntax_error(ls, "name expected");
eina_strbuf_append(buf, ls->t.value);
eina_strbuf_append(buf, ls->t.value.s);
eo_lexer_get(ls);
if (ls->t.token == '.')
{
@ -989,7 +1186,7 @@ parse_implement(Eo_Lexer *ls, Eina_Bool iface)
}
if ((ls->t.token != TOK_VALUE) || (ls->t.kw == KW_get || ls->t.kw == KW_set))
eo_lexer_syntax_error(ls, "class name expected");
eina_strbuf_append(buf, ls->t.value);
eina_strbuf_append(buf, ls->t.value.s);
eo_lexer_get(ls);
check_next(ls, '.');
eina_strbuf_append(buf, ".");
@ -1010,7 +1207,7 @@ parse_implement(Eo_Lexer *ls, Eina_Bool iface)
break;
}
check(ls, TOK_VALUE);
eina_strbuf_append(buf, ls->t.value);
eina_strbuf_append(buf, ls->t.value.s);
eo_lexer_get(ls);
if (ls->t.token != '.') break;
eina_strbuf_append(buf, ".");
@ -1036,14 +1233,14 @@ parse_event(Eo_Lexer *ls)
eo_lexer_get(ls);
}*/
check(ls, TOK_VALUE);
eina_strbuf_append(buf, ls->t.value);
eina_strbuf_append(buf, ls->t.value.s);
eo_lexer_get(ls);
while (ls->t.token == ',')
{
eo_lexer_get(ls);
check(ls, TOK_VALUE);
eina_strbuf_append_char(buf, ',');
eina_strbuf_append(buf, ls->t.value);
eina_strbuf_append(buf, ls->t.value.s);
eo_lexer_get(ls);
}
ev->name = eina_stringshare_add(eina_strbuf_string_get(buf));
@ -1058,7 +1255,7 @@ parse_event(Eo_Lexer *ls)
eo_lexer_get(ls);
if (ls->t.token == TOK_COMMENT)
{
ev->comment = eina_stringshare_ref(ls->t.value);
ev->comment = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
}
}
@ -1147,7 +1344,7 @@ parse_class_body(Eo_Lexer *ls, Eina_Bool allow_ctors, Eolian_Class_Type type)
has_events = EINA_FALSE;
if (ls->t.token == TOK_COMMENT)
{
ls->tmp.kls->comment = eina_stringshare_ref(ls->t.value);
ls->tmp.kls->comment = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
}
if (type == EOLIAN_CLASS_INTERFACE)
@ -1161,7 +1358,7 @@ parse_class_body(Eo_Lexer *ls, Eina_Bool allow_ctors, Eolian_Class_Type type)
eo_lexer_get(ls);
check_next(ls, ':');
check(ls, TOK_VALUE);
ls->tmp.kls->legacy_prefix = eina_stringshare_ref(ls->t.value);
ls->tmp.kls->legacy_prefix = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
check_next(ls, ';');
break;
@ -1170,7 +1367,7 @@ parse_class_body(Eo_Lexer *ls, Eina_Bool allow_ctors, Eolian_Class_Type type)
eo_lexer_get(ls);
check_next(ls, ':');
check(ls, TOK_VALUE);
ls->tmp.kls->eo_prefix = eina_stringshare_ref(ls->t.value);
ls->tmp.kls->eo_prefix = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
check_next(ls, ';');
break;
@ -1180,7 +1377,7 @@ parse_class_body(Eo_Lexer *ls, Eina_Bool allow_ctors, Eolian_Class_Type type)
eo_lexer_get(ls);
check_next(ls, ':');
check(ls, TOK_VALUE);
ls->tmp.kls->data_type = eina_stringshare_ref(ls->t.value);
ls->tmp.kls->data_type = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
check_next(ls, ';');
break;

View File

@ -156,6 +156,41 @@ typedef struct _Eolian_Struct_Field
Eina_Stringshare *comment;
} Eolian_Struct_Field;
typedef union
{
Eina_Bool b;
const char *s;
signed int i;
unsigned int u;
signed long l;
unsigned long ul;
signed long long ll;
unsigned long long ull;
float f;
double d;
long double ld;
} Eolian_Value;
struct _Eolian_Expression
{
Eolian_Expression_Type type;
union
{
struct
{
Eolian_Binary_Operator binop;
Eolian_Expression *lhs;
Eolian_Expression *rhs;
};
struct
{
Eolian_Unary_Operator unop;
Eolian_Expression *expr;
};
Eolian_Value value;
};
};
int database_init();
int database_shutdown();