summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeeyong Um <conr2d@gmail.com>2017-07-25 21:24:29 +0900
committerJeeyong Um <conr2d@gmail.com>2017-07-25 21:55:20 +0900
commit4ab7f10951387241ae0d343b38090c74ca8da52d (patch)
treebd5d61f589b24b3aab40424ce4a269a5d5fa2d7c
parent0087167e143c95d2f7b9910b9cde218686de70a0 (diff)
downloadefl-devs/conr2d/script_override.tar.gz
edje_cc: Support script overridedevs/conr2d/script_override
When script_override is set to 1, script of current group contains variables and funtions from script of parent groups. If there is same name variable or function, newly defined one will replace that of parents.
-rw-r--r--src/Makefile_Edje.am1
-rw-r--r--src/bin/edje/edje_cc.h5
-rw-r--r--src/bin/edje/edje_cc_handlers.c38
-rw-r--r--src/bin/edje/edje_cc_script.c466
4 files changed, 509 insertions, 1 deletions
diff --git a/src/Makefile_Edje.am b/src/Makefile_Edje.am
index 4ca20e570b..d4bcfbfdf7 100644
--- a/src/Makefile_Edje.am
+++ b/src/Makefile_Edje.am
@@ -173,6 +173,7 @@ bin/edje/edje_cc_parse.c \
bin/edje/edje_cc_mem.c \
bin/edje/edje_cc_handlers.c \
bin/edje/edje_cc_sources.c \
+bin/edje/edje_cc_script.c \
bin/edje/edje_multisense_convert.c \
bin/edje/edje_svg_loader.c
bin_edje_edje_cc_CPPFLAGS = -I$(top_builddir)/src/lib/efl $(EDJE_COMMON_CPPFLAGS) @EDJE_LUA_CFLAGS@
diff --git a/src/bin/edje/edje_cc.h b/src/bin/edje/edje_cc.h
index 08678f18d4..a66059fbec 100644
--- a/src/bin/edje/edje_cc.h
+++ b/src/bin/edje/edje_cc.h
@@ -91,6 +91,9 @@ struct _Code
char *shared;
char *original;
Eina_List *programs;
+ Eina_List *vars;
+ Eina_List *func;
+ Eina_Bool parsed : 1;
Eina_Bool is_lua : 1;
};
@@ -301,6 +304,8 @@ void convert_color_code(char *str, int *r, int *g, int *b, int *a);
Svg_Node* _svg_load(Eina_File *f, const char *key EINA_UNUSED);
+void script_rewrite(Code *code);
+
/* global vars */
extern Eina_List *ext_dirs;
extern Eina_List *img_dirs;
diff --git a/src/bin/edje/edje_cc_handlers.c b/src/bin/edje/edje_cc_handlers.c
index a878de9347..0c9a5a3137 100644
--- a/src/bin/edje/edje_cc_handlers.c
+++ b/src/bin/edje/edje_cc_handlers.c
@@ -5327,6 +5327,39 @@ st_collections_group_nooverride(void)
pcp->script_override = EINA_FALSE;
}
+static void
+_script_flush(void)
+{
+ Edje_Part_Collection_Parser *pcp;
+ Code *code;
+
+ pcp = eina_list_last_data_get(edje_collections);
+ code = eina_list_last_data_get(codes);
+
+ if (!pcp->script_override || code->is_lua) return;
+
+ // If script is replaceable and overridable, code->shared will be inherited
+ // script. Free it to avoid duplication.
+ if (script_is_replaceable)
+ {
+ if (code->shared)
+ {
+ free(code->shared);
+ code->shared = NULL;
+ }
+ if (code->original)
+ {
+ free(code->original);
+ code->original = NULL;
+ }
+ }
+
+ script_rewrite(code);
+
+ eina_list_free(pcp->base_codes);
+}
+
+
/**
@page edcref
@property
@@ -15878,7 +15911,10 @@ edje_cc_handlers_pop_notify(const char *token)
else if (current_program && (!strcmp(token, "link")))
current_program = NULL;
else if (current_de && (!strcmp(token, "group")))
- _link_combine();
+ {
+ _link_combine();
+ _script_flush();
+ }
else if (current_desc && (!strcmp(token, "description")))
free_anchors();
}
diff --git a/src/bin/edje/edje_cc_script.c b/src/bin/edje/edje_cc_script.c
new file mode 100644
index 0000000000..09ca1c0cd3
--- /dev/null
+++ b/src/bin/edje/edje_cc_script.c
@@ -0,0 +1,466 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "edje_cc.h"
+
+#define MESSAGE_OVERRIDE
+
+typedef struct _Code_Symbol
+{
+ const char *name;
+ const char *tag;
+ Eina_List *args;
+ char *body;
+ Eina_Bool is_public : 1;
+} Code_Symbol;
+
+typedef enum
+{
+ TOKEN_TYPE_INVALID = -1,
+ TOKEN_TYPE_EOF,
+ TOKEN_TYPE_COLON = (1 << 0),
+ TOKEN_TYPE_SEMICOLON = (1 << 1),
+ TOKEN_TYPE_COMMA = (1 << 2),
+ TOKEN_TYPE_PARENS = (1 << 3),
+ TOKEN_TYPE_BRACES = (1 << 4),
+ TOKEN_TYPE_EQUAL_MARK = (1 << 5),
+ TOKEN_TYPE_PUBLIC = (1 << 6),
+ TOKEN_TYPE_IDENTIFIER = (1 << 7)
+} Token_Type;
+
+typedef struct _Token
+{
+ char *str;
+ Token_Type type;
+} Token;
+
+static void code_parse_internal(Code *code);
+static Token *next_token(char **begin, char *end);
+
+static void
+code_parse(Code *code)
+{
+ Edje_Part_Collection_Parser *pcp;
+ Code *base;
+ Eina_List *l;
+ int id;
+
+ if (code->is_lua) return;
+
+ id = eina_list_data_idx(codes, code);
+ pcp = eina_list_nth(edje_collections, id);
+
+ EINA_LIST_FOREACH(pcp->base_codes, l, base)
+ {
+ if (!base->parsed)
+ code_parse(base);
+ }
+
+ if (code->shared)
+ code_parse_internal(code);
+
+ code->parsed = EINA_TRUE;
+}
+
+static void
+code_parse_internal(Code *code)
+{
+ Code_Symbol *sym = NULL, *func;
+ Token *token, *tmp;
+ char *begin = code->shared;
+ char *end = begin + strlen(begin);
+ char *body;
+ Eina_Array *stack;
+ Eina_Bool is_args = EINA_FALSE;
+ Eina_Bool is_public = EINA_FALSE;
+ int depth = 0;
+
+ stack = eina_array_new(4);
+
+ while ((token = next_token(&begin, end)))
+ {
+ if (token->type == TOKEN_TYPE_EOF)
+ break;
+
+ // Variables in script cannot be initialized by assignment.
+ // Skip until value assignment expression ends.
+ if (token->type == TOKEN_TYPE_EQUAL_MARK)
+ {
+ while ((tmp = next_token(&begin, end)))
+ {
+ if ((tmp->type == TOKEN_TYPE_COMMA) ||
+ (tmp->type == TOKEN_TYPE_SEMICOLON))
+ {
+ token = tmp;
+ break;
+ }
+ }
+ }
+
+ switch (token->type)
+ {
+ case TOKEN_TYPE_COLON:
+ if (!sym)
+ sym = mem_alloc(SZ(Code_Symbol));
+ sym->tag = eina_array_pop(stack);
+ break;
+ case TOKEN_TYPE_SEMICOLON:
+ if (eina_array_count(stack))
+ {
+ if (!sym)
+ sym = mem_alloc(SZ(Code_Symbol));
+ sym->name = eina_array_pop(stack);
+ sym->is_public = is_public;
+ code->vars = eina_list_append(code->vars, sym);
+ sym = NULL;
+ }
+ is_public = EINA_FALSE;
+ break;
+ case TOKEN_TYPE_COMMA:
+ if (!sym)
+ sym = mem_alloc(SZ(Code_Symbol));
+ sym->name = eina_array_pop(stack);
+ if (is_args)
+ func->args = eina_list_append(func->args, sym);
+ else
+ {
+ sym->is_public = is_public;
+ code->vars = eina_list_append(code->vars, sym);
+ }
+ sym = NULL;
+ break;
+ case TOKEN_TYPE_PARENS:
+ is_args = !is_args;
+ if (is_args)
+ {
+ if (!sym)
+ func = mem_alloc(SZ(Code_Symbol));
+ else
+ {
+ func = sym;
+ sym = NULL;
+ }
+ func->name = eina_array_pop(stack);
+ }
+ else
+ {
+ if (eina_array_count(stack))
+ {
+ if (!sym)
+ sym = mem_alloc(SZ(Code_Symbol));
+ sym->name = eina_array_pop(stack);
+ func->args = eina_list_append(func->args, sym);
+ }
+ sym = func;
+ }
+ break;
+ case TOKEN_TYPE_BRACES:
+ depth = 1;
+ body = begin;
+ while ((tmp = next_token(&begin, end)))
+ {
+ if (tmp->type == TOKEN_TYPE_BRACES)
+ {
+ switch (tmp->str[0])
+ {
+ case '{':
+ depth++;
+ break;
+ case '}':
+ depth--;
+ break;
+ }
+ }
+ if (!depth)
+ break;
+ }
+ if ((begin - 1) > body)
+ {
+ sym->body = mem_alloc(sizeof(char) * (begin - body - 1));
+ strncpy(sym->body, body, (begin - body - 2));
+ }
+ sym->is_public = is_public;
+ code->func = eina_list_append(code->func, sym);
+ sym = NULL;
+ is_public = EINA_FALSE;
+ break;
+ case TOKEN_TYPE_PUBLIC:
+ is_public = EINA_TRUE;
+ break;
+ case TOKEN_TYPE_IDENTIFIER:
+ eina_array_push(stack, token->str);
+ token->str = NULL;
+ break;
+ default:
+ break;
+ }
+
+ if (token->str)
+ free(token->str);
+ free(token);
+ }
+
+ eina_array_free(stack);
+}
+
+static Token *
+next_token(char **begin, char *end)
+{
+ char buf[PATH_MAX] = { 0, };
+ char *src;
+ int index;
+ Token *token;
+ Eina_Bool parsed = EINA_FALSE;
+
+ if (!begin || (*begin >= end))
+ return NULL;
+
+ token = mem_alloc(SZ(Token));
+ token->type = TOKEN_TYPE_INVALID;
+
+ src = *begin - 1;
+ index = 0;
+
+ while (++src < end)
+ {
+ char ch = *src;
+
+ switch (ch)
+ {
+ case ' ':
+ case '\t':
+ case '\n':
+ if (index > 0)
+ parsed = EINA_TRUE;
+ break;
+ case ':':
+ case ';':
+ case ',':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '=':
+ if (!index)
+ {
+ buf[index++] = ch;
+ src++;
+ }
+ goto exit;
+ default:
+ if (parsed)
+ goto exit;
+ buf[index++] = ch;
+ break;
+ }
+ }
+
+exit:
+ switch (buf[0])
+ {
+ case ':':
+ token->type = TOKEN_TYPE_COLON;
+ break;
+ case ';':
+ token->type = TOKEN_TYPE_SEMICOLON;
+ break;
+ case ',':
+ token->type = TOKEN_TYPE_COMMA;
+ break;
+ case '(':
+ token->type = TOKEN_TYPE_PARENS;
+ break;
+ case ')':
+ token->type = TOKEN_TYPE_PARENS;
+ break;
+ case '{':
+ token->type = TOKEN_TYPE_BRACES;
+ break;
+ case '}':
+ token->type = TOKEN_TYPE_BRACES;
+ break;
+ case '=':
+ token->type = TOKEN_TYPE_EQUAL_MARK;
+ break;
+ case '\0':
+ token->type = TOKEN_TYPE_EOF;
+ break;
+ }
+
+ if (token->type < 0)
+ {
+ if (!strcmp(buf, "public"))
+ token->type = TOKEN_TYPE_PUBLIC;
+ else
+ token->type = TOKEN_TYPE_IDENTIFIER;
+ }
+
+ *begin = src;
+ token->str = strdup(buf);
+ return token;
+}
+
+static void
+_push_symbol(Eina_List **total, Code_Symbol *sym, Edje_Part_Collection *pc)
+{
+ Eina_List *list, *l;
+ Code_Symbol *sym2;
+
+ list = *total;
+
+ EINA_LIST_FOREACH(list, l, sym2)
+ {
+ if (!strcmp(sym2->name, sym->name))
+ {
+ WRN("Symbols in group \"%s\" have same name \"%s\". Latter defined "
+ "will shadow former one.", pc->part, sym->name);
+ list = eina_list_remove(list, sym2);
+ break;
+ }
+ }
+ list = eina_list_append(list, sym);
+ *total = list;
+}
+
+void
+script_rewrite(Code *code)
+{
+ Edje_Part_Collection *pc;
+ Edje_Part_Collection_Parser *pcp;
+ Code *base;
+ Eina_List *l, *ll;
+ int id, count;
+ Eina_Strbuf *buf;
+ Eina_List *vars = NULL;
+ Eina_List *func = NULL;
+#ifdef MESSAGE_OVERRIDE
+ Eina_List *message = NULL;
+#endif
+ Code_Symbol *sym, *arg;
+
+ code_parse(code);
+
+ id = eina_list_data_idx(codes, code);
+ pc = eina_list_nth(edje_collections, id);
+ pcp = (Edje_Part_Collection_Parser *)pc;
+
+ EINA_LIST_FOREACH(pcp->base_codes, l, base)
+ {
+ EINA_LIST_FOREACH(base->vars, ll, sym)
+ _push_symbol(&vars, sym, pc);
+
+ EINA_LIST_FOREACH(base->func, ll, sym)
+ {
+#ifndef MESSAGE_OVERRIDE
+ _push_symbol(&func, sym, pc);
+#else
+ if (strcmp(sym->name, "message"))
+ _push_symbol(&func, sym, pc);
+ else
+ message = eina_list_append(message, sym);
+#endif
+ }
+ }
+
+ EINA_LIST_FOREACH(code->vars, l, sym)
+ _push_symbol(&vars, sym, pc);
+ EINA_LIST_FOREACH(code->func, l, sym)
+ {
+#ifndef MESSAGE_OVERRIDE
+ _push_symbol(&func, sym, pc);
+#else
+ if (strcmp(sym->name, "message"))
+ _push_symbol(&func, sym, pc);
+ else
+ message = eina_list_append(message, sym);
+#endif
+ }
+
+ buf = eina_strbuf_new();
+
+ if (vars)
+ {
+ count = 0;
+ EINA_LIST_FOREACH(vars, l, sym)
+ {
+ if (!sym->is_public) continue;
+
+ if (count++)
+ eina_strbuf_append(buf, ", ");
+ else
+ eina_strbuf_append(buf, "public ");
+
+ if (sym->tag)
+ eina_strbuf_append_printf(buf, "%s:", sym->tag);
+ eina_strbuf_append(buf, sym->name);
+ }
+ if (count)
+ eina_strbuf_append(buf, ";\n");
+
+ count = 0;
+ EINA_LIST_FOREACH(vars, l, sym)
+ {
+ if (sym->is_public) continue;
+
+ if (count++)
+ eina_strbuf_append(buf, ", ");
+
+ if (sym->tag)
+ eina_strbuf_append_printf(buf, "%s:", sym->tag);
+ eina_strbuf_append(buf, sym->name);
+ }
+ if (count)
+ eina_strbuf_append(buf, ";\n");
+ }
+
+ if (func)
+ {
+ EINA_LIST_FOREACH(func, l, sym)
+ {
+ eina_strbuf_append(buf, "\n");
+ if (sym->is_public)
+ eina_strbuf_append(buf, "public ");
+
+ if (sym->tag)
+ eina_strbuf_append_printf(buf, "%s:", sym->tag);
+ eina_strbuf_append_printf(buf, "%s(", sym->name);
+
+ count = 0;
+ EINA_LIST_FOREACH(sym->args, ll, arg)
+ {
+ if (count++)
+ eina_strbuf_append(buf, ", ");
+
+ if (arg->tag)
+ eina_strbuf_append_printf(buf, "%s:", arg->tag);
+ eina_strbuf_append(buf, arg->name);
+ }
+ eina_strbuf_append(buf, ") {");
+ if (sym->body)
+ {
+ eina_strbuf_append(buf, sym->body);
+ eina_strbuf_rtrim(buf);
+ }
+ eina_strbuf_append(buf, "\n}\n");
+ }
+ }
+
+#ifdef MESSAGE_OVERRIDE
+ if (message)
+ {
+ eina_strbuf_append(buf, "\npublic message(Msg_Type:type, id, ...) {");
+ EINA_LIST_FOREACH(message, l, sym)
+ eina_strbuf_append(buf, sym->body);
+ eina_strbuf_rtrim(buf);
+ eina_strbuf_append(buf, "\n}\n");
+ }
+#endif
+
+ code->shared = eina_strbuf_string_steal(buf);
+ code->original = strdup(code->shared);
+ eina_strbuf_free(buf);
+
+ eina_list_free(vars);
+ eina_list_free(func);
+}