From: Charlie Brej Date: Fri, 12 Jun 2009 17:04:25 +0000 (+0100) Subject: Initial scripted plugin support X-Git-Tag: 0.7.0~156 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5ea8be95ab9eb64b9fd7b2d01f523cde2fc22476;p=thirdparty%2Fplymouth.git Initial scripted plugin support This is an initial support for the scripted plugin. There are _many_ FIXMEs and the whole code is reather unstable. The formatting is completely incorrect and will be changed soon. There are scripts which are converted using a perl to an C embeddable string. --- diff --git a/configure.ac b/configure.ac index bcd7d7b0..f7353401 100644 --- a/configure.ac +++ b/configure.ac @@ -207,6 +207,7 @@ AC_OUTPUT([Makefile src/plugins/splash/details/Makefile src/plugins/splash/space-flares/Makefile src/plugins/splash/two-step/Makefile + src/plugins/splash/script/Makefile src/plugins/controls/Makefile src/plugins/controls/label/Makefile src/Makefile @@ -222,6 +223,7 @@ AC_OUTPUT([Makefile themes/details/Makefile themes/solar/Makefile themes/glow/Makefile + themes/script/Makefile images/Makefile scripts/Makefile ]) diff --git a/src/plugins/splash/Makefile.am b/src/plugins/splash/Makefile.am index f8316ece..3510531d 100644 --- a/src/plugins/splash/Makefile.am +++ b/src/plugins/splash/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = throbgress fade-throbber text details space-flares two-step +SUBDIRS = throbgress fade-throbber text details space-flares two-step script MAINTAINERCLEANFILES = Makefile.in if ADD_DEFAULT_PLUGIN_LINK diff --git a/src/plugins/splash/script/Makefile.am b/src/plugins/splash/script/Makefile.am new file mode 100644 index 00000000..0c02f35f --- /dev/null +++ b/src/plugins/splash/script/Makefile.am @@ -0,0 +1,59 @@ +INCLUDES = -I$(top_srcdir) \ + -I$(srcdir)/../../../libply \ + -I$(srcdir)/../../../libplybootsplash \ + -I$(srcdir)/../../.. \ + -I$(srcdir)/../.. \ + -I$(srcdir)/.. \ + -I$(srcdir) + +plugindir = $(libdir)/plymouth +plugin_LTLIBRARIES = script.la + +script_la_CFLAGS = $(PLYMOUTH_CFLAGS) \ + -DPLYMOUTH_IMAGE_DIR=\"$(datadir)/plymouth/\" \ + -DPLYMOUTH_LOGO_FILE=\"$(logofile)\" \ + -DPLYMOUTH_BACKGROUND_COLOR=$(background_color) \ + -DPLYMOUTH_BACKGROUND_END_COLOR=$(background_end_color) \ + -DPLYMOUTH_BACKGROUND_START_COLOR=$(background_start_color) +script_la_LDFLAGS = -module -avoid-version -export-dynamic +script_la_LIBADD = $(PLYMOUTH_LIBS) \ + ../../../libply/libply.la \ + ../../../libplybootsplash/libplybootsplash.la +script_la_SOURCES = $(srcdir)/plugin.c \ + $(srcdir)/plugin.h \ + $(srcdir)/script.c \ + $(srcdir)/script.h \ + $(srcdir)/script-parse.c \ + $(srcdir)/script-parse.h \ + $(srcdir)/script-execute.c \ + $(srcdir)/script-execute.h \ + $(srcdir)/script-object.c \ + $(srcdir)/script-object.h \ + $(srcdir)/script-lib-image.c \ + $(srcdir)/script-lib-image.h \ + $(srcdir)/script-lib-image.script \ + $(srcdir)/script-lib-sprite.c \ + $(srcdir)/script-lib-sprite.h \ + $(srcdir)/script-lib-sprite.script \ + $(srcdir)/script-lib-plymouth.c \ + $(srcdir)/script-lib-plymouth.h \ + $(srcdir)/script-lib-plymouth.script \ + $(srcdir)/script-lib-math.c \ + $(srcdir)/script-lib-math.h \ + $(srcdir)/script-lib-math.script \ + $(srcdir)/ply-scan.c \ + $(srcdir)/ply-scan.h + +MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = *.script.string + + +EXTRA_DIST = stringify.pl + +%.string: %.script stringify.pl + ./stringify.pl < $< > $@ + +script-lib-image.c : script-lib-image.string +script-lib-sprite.c : script-lib-sprite.string +script-lib-math.c : script-lib-math.string +script-lib-plymouth.c : script-lib-plymouth.string diff --git a/src/plugins/splash/script/plugin.c b/src/plugins/splash/script/plugin.c new file mode 100644 index 00000000..b3f922cc --- /dev/null +++ b/src/plugins/splash/script/plugin.c @@ -0,0 +1,464 @@ +/* plugin.c - boot script plugin + * + * Copyright (C) 2007, 2008 Red Hat, Inc. + * 2008 Charlie Brej + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Charlie Brej + * Ray Strode + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ply-boot-splash-plugin.h" +#include "ply-buffer.h" +#include "ply-entry.h" +#include "ply-event-loop.h" +#include "ply-key-file.h" +#include "ply-label.h" +#include "ply-list.h" +#include "ply-logger.h" +#include "ply-frame-buffer.h" +#include "ply-image.h" +#include "ply-trigger.h" +#include "ply-utils.h" +#include "ply-window.h" + +#include "script.h" +#include "script-parse.h" +#include "script-object.h" +#include "script-execute.h" +#include "script-lib-image.h" +#include "script-lib-sprite.h" +#include "script-lib-plymouth.h" +#include "script-lib-math.h" + +#include + +#ifndef FRAMES_PER_SECOND +#define FRAMES_PER_SECOND 50 +#endif + + +typedef enum { + PLY_BOOT_SPLASH_DISPLAY_NORMAL, + PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY, + PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY +} ply_boot_splash_display_type_t; + +struct _ply_boot_splash_plugin +{ + ply_event_loop_t *loop; + ply_boot_splash_mode_t mode; + ply_frame_buffer_t *frame_buffer; + ply_window_t *window; + + ply_boot_splash_display_type_t state; + + char *script_filename; + char *image_dir; + + double progress; + double progress_target; + + script_state *script_state; + script_op *script_main_op; + script_lib_sprite_data_t *script_sprite_lib; + script_lib_image_data_t *script_image_lib; + script_lib_plymouth_data_t *script_plymouth_lib; + script_lib_math_data_t *script_math_lib; + + uint32_t is_animating : 1; +}; + +void destroy_plugin (ply_boot_splash_plugin_t *plugin); +static void add_handlers (ply_boot_splash_plugin_t *plugin); +static void remove_handlers (ply_boot_splash_plugin_t *plugin); +static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin); +static void stop_animation (ply_boot_splash_plugin_t *plugin); +ply_boot_splash_plugin_t *create_plugin (ply_key_file_t *key_file); + + +ply_boot_splash_plugin_t * +create_plugin (ply_key_file_t *key_file) +{ + ply_boot_splash_plugin_t *plugin; + srand ((int) ply_get_timestamp ()); + + plugin = calloc (1, sizeof (ply_boot_splash_plugin_t)); + + plugin->image_dir = ply_key_file_get_value (key_file, "script", "ImageDir"); + plugin->script_filename = ply_key_file_get_value (key_file, "script", "ScriptFile"); + + plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; + plugin->progress = 0; + plugin->progress_target = -1; + return plugin; +} + +void +destroy_plugin (ply_boot_splash_plugin_t *plugin) +{ + if (plugin == NULL) + return; + + remove_handlers (plugin); + + if (plugin->loop != NULL) + { + stop_animation (plugin); + ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t) + detach_from_event_loop, + plugin); + detach_from_event_loop (plugin); + } + + free (plugin->script_filename); + free (plugin->image_dir); + free (plugin); +} + +static void +on_timeout (ply_boot_splash_plugin_t *plugin) +{ + double sleep_time; + double now; + + now = ply_get_timestamp (); + + if (plugin->script_plymouth_lib->script_refresh_func){ + script_state* sub_state = script_state_init_sub(plugin->script_state); + script_return ret = script_execute(sub_state, plugin->script_plymouth_lib->script_refresh_func->data.function->data.script); // FIXME too many redirections + if (ret.object) script_obj_unref(ret.object); // Throw anything sent back away + script_state_destroy(sub_state); + } + script_lib_sprite_refresh(plugin->script_sprite_lib); + + sleep_time = 1.0 / FRAMES_PER_SECOND; + ply_event_loop_watch_for_timeout (plugin->loop, + sleep_time, + (ply_event_loop_timeout_handler_t) + on_timeout, plugin); +} + +static void +on_boot_progress (ply_boot_splash_plugin_t *plugin, + double duration, + double percent_done) +{ + if (plugin->progress_target<0) + plugin->progress = percent_done; + plugin->progress_target = percent_done; +} + + +static bool +start_animation (ply_boot_splash_plugin_t *plugin) +{ + ply_frame_buffer_area_t area; + assert (plugin != NULL); + assert (plugin->loop != NULL); + + if (plugin->is_animating) + return true; + + ply_frame_buffer_get_size (plugin->frame_buffer, &area); + + ply_window_draw_area (plugin->window, area.x, area.y, area.width, area.height); + + ply_trace ("starting simple"); + plugin->script_main_op = script_parse_file (plugin->script_filename); + ply_trace ("starting simple"); + plugin->script_state = script_state_new(plugin); + plugin->script_image_lib = script_lib_image_setup(plugin->script_state,plugin->image_dir); + plugin->script_sprite_lib = script_lib_sprite_setup(plugin->script_state, plugin->window); + plugin->script_plymouth_lib = script_lib_plymouth_setup(plugin->script_state); + plugin->script_math_lib = script_lib_math_setup(plugin->script_state); + + script_return ret = script_execute(plugin->script_state, plugin->script_main_op); + if (ret.object) script_obj_unref(ret.object); // Throw anything sent back away + + + + + on_timeout (plugin); + + plugin->is_animating = true; + return true; +} + +static void +stop_animation (ply_boot_splash_plugin_t *plugin) +{ + assert (plugin != NULL); + assert (plugin->loop != NULL); + + if (!plugin->is_animating) + return; + + plugin->is_animating = false; + if (plugin->loop != NULL) + { + ply_event_loop_stop_watching_for_timeout (plugin->loop, + (ply_event_loop_timeout_handler_t) + on_timeout, plugin); + } + script_state_destroy(plugin->script_state); + script_parse_op_free (plugin->script_main_op); + script_lib_sprite_destroy(plugin->script_sprite_lib); + script_lib_image_destroy(plugin->script_image_lib); + script_lib_plymouth_destroy(plugin->script_plymouth_lib); + script_lib_math_destroy(plugin->script_math_lib); +} + +static void +on_interrupt (ply_boot_splash_plugin_t *plugin) +{ + ply_event_loop_exit (plugin->loop, 1); + stop_animation (plugin); + ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); +} + +static void +detach_from_event_loop (ply_boot_splash_plugin_t *plugin) +{ + plugin->loop = NULL; +} + +void +on_keyboard_input (ply_boot_splash_plugin_t *plugin, + const char *keyboard_input, + size_t character_size) +{ +} + +void +on_backspace (ply_boot_splash_plugin_t *plugin) +{ +} + +void +on_enter (ply_boot_splash_plugin_t *plugin, + const char *text) +{ +} + + +void +on_draw (ply_boot_splash_plugin_t *plugin, + int x, + int y, + int width, + int height) +{ +} + +void +on_erase (ply_boot_splash_plugin_t *plugin, + int x, + int y, + int width, + int height) +{ +} + +static void +add_handlers (ply_boot_splash_plugin_t *plugin) +{ + ply_window_add_keyboard_input_handler (plugin->window, + (ply_window_keyboard_input_handler_t) + on_keyboard_input, plugin); + ply_window_add_backspace_handler (plugin->window, + (ply_window_backspace_handler_t) + on_backspace, plugin); + ply_window_add_enter_handler (plugin->window, + (ply_window_enter_handler_t) + on_enter, plugin); + ply_window_set_draw_handler (plugin->window, + (ply_window_draw_handler_t) + on_draw, plugin); + ply_window_set_erase_handler (plugin->window, + (ply_window_erase_handler_t) + on_erase, plugin); +} + +static void +remove_handlers (ply_boot_splash_plugin_t *plugin) +{ + + ply_window_remove_keyboard_input_handler (plugin->window, (ply_window_keyboard_input_handler_t) on_keyboard_input); + ply_window_remove_backspace_handler (plugin->window, (ply_window_backspace_handler_t) on_backspace); + ply_window_remove_enter_handler (plugin->window, (ply_window_enter_handler_t) on_enter); + ply_window_set_draw_handler (plugin->window, NULL, NULL); + ply_window_set_erase_handler (plugin->window, NULL, NULL); +} + +void +add_window (ply_boot_splash_plugin_t *plugin, + ply_window_t *window) +{ + plugin->window = window; +} + +void +remove_window (ply_boot_splash_plugin_t *plugin, + ply_window_t *window) +{ + plugin->window = NULL; +} + +bool +show_splash_screen (ply_boot_splash_plugin_t *plugin, + ply_event_loop_t *loop, + ply_buffer_t *boot_buffer, + ply_boot_splash_mode_t mode) +{ + assert (plugin != NULL); + + add_handlers (plugin); + + plugin->loop = loop; + plugin->mode = mode; + + plugin->frame_buffer = ply_window_get_frame_buffer (plugin->window); + + ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) + detach_from_event_loop, + plugin); + + ply_event_loop_watch_signal (plugin->loop, + SIGINT, + (ply_event_handler_t) + on_interrupt, plugin); + + ply_trace ("setting graphics mode"); + if (!ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_GRAPHICS)) + return false; + ply_window_clear_screen (plugin->window); + ply_window_hide_text_cursor (plugin->window); + + ply_trace ("starting boot animation"); + return start_animation (plugin); + +} + +void +update_status (ply_boot_splash_plugin_t *plugin, + const char *status) +{ + assert (plugin != NULL); +} + +void +hide_splash_screen (ply_boot_splash_plugin_t *plugin, + ply_event_loop_t *loop) +{ + assert (plugin != NULL); + + remove_handlers (plugin); + + if (plugin->loop != NULL) + { + stop_animation (plugin); + + ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t) + detach_from_event_loop, + plugin); + detach_from_event_loop (plugin); + } + + plugin->frame_buffer = NULL; + + ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT); +} + +void +on_root_mounted (ply_boot_splash_plugin_t *plugin) +{ +} + +void +become_idle (ply_boot_splash_plugin_t *plugin, + ply_trigger_t *idle_trigger) +{ + ply_trigger_pull (idle_trigger, NULL); +} + + + +void display_normal (ply_boot_splash_plugin_t *plugin) +{ + plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; +} + +void +display_password (ply_boot_splash_plugin_t *plugin, + const char *prompt, + int bullets) +{ + plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY; +} + +void +display_question (ply_boot_splash_plugin_t *plugin, + const char *prompt, + const char *entry_text) +{ + plugin->state = PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY; +} + +ply_boot_splash_plugin_interface_t * +ply_boot_splash_plugin_get_interface (void) +{ + static ply_boot_splash_plugin_interface_t plugin_interface = + { + .create_plugin = create_plugin, + .destroy_plugin = destroy_plugin, + .add_window = add_window, + .remove_window = remove_window, + .show_splash_screen = show_splash_screen, + .update_status = update_status, + .on_boot_progress = on_boot_progress, + .hide_splash_screen = hide_splash_screen, + .on_root_mounted = on_root_mounted, + .become_idle = become_idle, + .display_normal = display_normal, + .display_password = display_password, + .display_question = display_question, + }; + + return &plugin_interface; +} + +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/plugins/splash/script/plugin.h b/src/plugins/splash/script/plugin.h new file mode 100644 index 00000000..e69de29b diff --git a/src/plugins/splash/script/ply-scan.c b/src/plugins/splash/script/ply-scan.c new file mode 100644 index 00000000..d047387d --- /dev/null +++ b/src/plugins/splash/script/ply-scan.c @@ -0,0 +1,240 @@ +#include "ply-bitarray.h" +#include "ply-scan.h" +#include +#include +#include +#include +#include +#include + +static ply_scan_t* ply_scan_new(void) +{ + unsigned char* chars; + ply_scan_t* scan = calloc(1, sizeof(ply_scan_t)); + scan->tokens = NULL; + scan->tokencount = 0; + + scan->identifier_1st_char = ply_bitarray_new(256); + scan->identifier_nth_char = ply_bitarray_new(256); + + for (chars = (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; *chars; chars++){ + ply_bitarray_set(scan->identifier_1st_char, *chars); + } + for (chars = (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789"; *chars; chars++){ + ply_bitarray_set(scan->identifier_nth_char, *chars); + } + return scan; +} + +ply_scan_t* ply_scan_file(char* filename) +{ + int fd = open(filename, O_RDONLY); + if (fd<0) return NULL; + ply_scan_t* scan = ply_scan_new(); + scan->source.fd = fd; + scan->source_is_file = true; + ply_scan_get_next_char(scan); + return scan; +} + +ply_scan_t* ply_scan_string(char* string) +{ + ply_scan_t* scan = ply_scan_new(); + scan->source.string = string; + scan->source_is_file = false; + ply_scan_get_next_char(scan); + return scan; +} + +void ply_scan_token_clean(ply_scan_token_t* token) +{ + switch (token->type){ + case PLY_SCAN_TOKEN_TYPE_EMPTY: + case PLY_SCAN_TOKEN_TYPE_EOF: + case PLY_SCAN_TOKEN_TYPE_INTEGER: + case PLY_SCAN_TOKEN_TYPE_SYMBOL: + break; + case PLY_SCAN_TOKEN_TYPE_IDENTIFIER: + case PLY_SCAN_TOKEN_TYPE_STRING: + free(token->data.string); + break; + } + token->type = PLY_SCAN_TOKEN_TYPE_EMPTY; +} + +void ply_scan_free(ply_scan_t* scan) +{ + int i; + if (scan->source_is_file) close(scan->source.fd); + for (i=0; itokencount; i++){ + ply_scan_token_clean(scan->tokens[i]); + free(scan->tokens[i]); + } + ply_bitarray_free(scan->identifier_1st_char); + ply_bitarray_free(scan->identifier_nth_char); + free(scan->tokens); + free(scan); +} + +unsigned char ply_scan_get_current_char(ply_scan_t* scan) +{ + return scan->cur_char; +} + +unsigned char ply_scan_get_next_char(ply_scan_t* scan) +{ + + if (scan->source_is_file) { + int got = read (scan->source.fd, &scan->cur_char, 1); + if (!got) return 0; // FIXME a better way of doing EOF etc + } + else { + scan->cur_char = *scan->source.string; + if (scan->cur_char) scan->source.string++; + } + // update indexes + return scan->cur_char; +} + +void ply_scan_read_next_token(ply_scan_t* scan, ply_scan_token_t* token) +{ + unsigned char curchar = ply_scan_get_current_char(scan); + + while(true){ + if (curchar == ' ') {curchar = ply_scan_get_next_char(scan); continue;} + if (curchar == '\n') {curchar = ply_scan_get_next_char(scan); continue;} + if (curchar == '\t') {curchar = ply_scan_get_next_char(scan); continue;} + break; + } + if (ply_bitarray_lookup(scan->identifier_1st_char, curchar)){ + token->type = PLY_SCAN_TOKEN_TYPE_IDENTIFIER; + int index = 0; + token->data.string = NULL; + do { + token->data.string = realloc(token->data.string, (index+2)*sizeof(char)); + token->data.string[index] = curchar; + token->data.string[index+1] = '\0'; + index++; + curchar = ply_scan_get_next_char(scan); + } + while (ply_bitarray_lookup(scan->identifier_nth_char, curchar)); + return; + } + if (curchar >= '0' && curchar <= '9'){ + token->type = PLY_SCAN_TOKEN_TYPE_INTEGER; + long long int value = 0; + do { + value *= 10; + value += curchar - '0'; + curchar = ply_scan_get_next_char(scan); + } + while (curchar >= '0' && curchar <= '9'); + token->data.integer = value; + return; + } + + if (!curchar) { + token->type = PLY_SCAN_TOKEN_TYPE_EOF; + return; + } + + if (curchar == '"') { + token->type = PLY_SCAN_TOKEN_TYPE_STRING; + int index = 0; + token->data.string = malloc(sizeof(char)); + token->data.string[0] = '\0'; + + while (1){ + curchar = ply_scan_get_next_char(scan); + if (curchar == '"') break; + assert(curchar != '\0'); + if (curchar == '\\') { + curchar = ply_scan_get_next_char(scan); + switch (curchar){ + case 'n': + curchar = '\n'; + break; + case '0': + curchar = '\0'; + break; + case '"': + curchar = '\"'; + break; + default: + break; + } + } + token->data.string = realloc(token->data.string, (index+2)*sizeof(char)); + token->data.string[index] = curchar; + token->data.string[index+1] = '\0'; + index++; + } + ply_scan_get_next_char(scan); + return; + } + + // all other + token->type = PLY_SCAN_TOKEN_TYPE_SYMBOL; + token->data.symbol = curchar; + ply_scan_get_next_char(scan); + return; +} + + +static ply_scan_token_t* ply_scan_peek_token(ply_scan_t* scan, int n) +{ + int i; + if (scan->tokencount <= n){ + scan->tokens = realloc(scan->tokens, (n+1)*sizeof(ply_scan_token_t*)); + for (i = scan->tokencount; i<=n; i++){ // FIXME warning about possibely inifnite loop + scan->tokens[i] = malloc(sizeof(ply_scan_token_t)); + scan->tokens[i]->type = PLY_SCAN_TOKEN_TYPE_EMPTY; + } + scan->tokencount = n+1; + } + + if (scan->tokens[n]->type == PLY_SCAN_TOKEN_TYPE_EMPTY){ + if (n > 0 && scan->tokens[n-1]->type == PLY_SCAN_TOKEN_TYPE_EMPTY) + ply_scan_peek_token(scan, n-1); + ply_scan_read_next_token(scan, scan->tokens[n]); +// printf("%d:", n); +// switch (scan->tokens[n]->type){ +// case PLY_SCAN_TOKEN_TYPE_STRING: +// printf("\"%s\"\n", scan->tokens[n]->data.string); +// break; +// case PLY_SCAN_TOKEN_TYPE_IDENTIFIER: +// printf("%s\n", scan->tokens[n]->data.string); +// break; +// case PLY_SCAN_TOKEN_TYPE_SYMBOL: +// printf("'%c'\n", scan->tokens[n]->data.symbol); +// break; +// case PLY_SCAN_TOKEN_TYPE_INTEGER: +// printf("%d\n", (int)scan->tokens[n]->data.integer); +// break; +// } + } + return scan->tokens[n]; +} + +ply_scan_token_t* ply_scan_get_next_token(ply_scan_t* scan) +{ + int i; + ply_scan_token_clean(scan->tokens[0]); + for (i=0; i<(scan->tokencount-1); i++){ + *scan->tokens[i] = *scan->tokens[i+1]; + } + scan->tokens[(scan->tokencount-1)]->type = PLY_SCAN_TOKEN_TYPE_EMPTY; + return ply_scan_peek_token(scan, 0); +} + +ply_scan_token_t* ply_scan_get_current_token(ply_scan_t* scan) +{ + return ply_scan_peek_token(scan, 0); +} + +ply_scan_token_t* ply_scan_peek_next_token(ply_scan_t* scan) +{ + return ply_scan_peek_token(scan, 1); +} + + diff --git a/src/plugins/splash/script/ply-scan.h b/src/plugins/splash/script/ply-scan.h new file mode 100644 index 00000000..d7cf5a61 --- /dev/null +++ b/src/plugins/splash/script/ply-scan.h @@ -0,0 +1,54 @@ +#ifndef PLY_SCAN_H +#define PLY_SCAN_H + +#include "ply-bitarray.h" +#include + +typedef enum +{ + PLY_SCAN_TOKEN_TYPE_EMPTY, + PLY_SCAN_TOKEN_TYPE_EOF, + PLY_SCAN_TOKEN_TYPE_INTEGER, + PLY_SCAN_TOKEN_TYPE_IDENTIFIER, + PLY_SCAN_TOKEN_TYPE_STRING, + PLY_SCAN_TOKEN_TYPE_SYMBOL, +} ply_scan_token_type_t; + +typedef struct +{ + ply_scan_token_type_t type; + union + { + char* string; + char symbol; + long long int integer; + } data; +} ply_scan_token_t; + +typedef struct +{ + union + { + int fd; + char* string; + } source; + unsigned char cur_char; + ply_bitarray_t *identifier_1st_char; + ply_bitarray_t *identifier_nth_char; + int tokencount; + ply_scan_token_t **tokens; + bool source_is_file; +} ply_scan_t; + +ply_scan_t* ply_scan_file(char* filename); +ply_scan_t* ply_scan_string(char* string); +void ply_scan_token_clean(ply_scan_token_t* token); +void ply_scan_free(ply_scan_t* scan); +unsigned char ply_scan_get_current_char(ply_scan_t* scan); +unsigned char ply_scan_get_next_char(ply_scan_t* scan); +ply_scan_token_t* ply_scan_get_current_token(ply_scan_t* scan); +ply_scan_token_t* ply_scan_get_next_token(ply_scan_t* scan); +ply_scan_token_t* ply_scan_peek_next_token(ply_scan_t* scan); +void ply_scan_read_next_token(ply_scan_t* scan, ply_scan_token_t* token); + +#endif /* PLY_SCAN_H */ diff --git a/src/plugins/splash/script/script-execute.c b/src/plugins/splash/script/script-execute.c new file mode 100644 index 00000000..63bd634b --- /dev/null +++ b/src/plugins/splash/script/script-execute.c @@ -0,0 +1,720 @@ +#define _GNU_SOURCE +#include "ply-scan.h" +#include "ply-hashtable.h" +#include "ply-list.h" +#include +#include +#include +#include +#include +#include +#include + +#include "script.h" +#include "script-execute.h" +#include "script-object.h" + + +static script_obj* script_evaluate (script_state* state, script_exp* exp); + +static script_obj* script_evaluate_plus (script_state* state, script_exp* exp) +{ + script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a); + script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b); + script_obj* obj = NULL; + + script_obj_deref (&script_obj_a); + script_obj_deref (&script_obj_b); + + switch (script_obj_a->type){ + case SCRIPT_OBJ_TYPE_INT: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_INT: + obj = script_obj_new_int (script_obj_a->data.integer + script_obj_b->data.integer); + break; + case SCRIPT_OBJ_TYPE_NULL: + obj = script_obj_new_int (script_obj_a->data.integer); // int + NULL = int ? meh + break; + default: + break; + } + break; + } + case SCRIPT_OBJ_TYPE_NULL: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_INT: + obj = script_obj_new_int (script_obj_b->data.integer); + break; + case SCRIPT_OBJ_TYPE_STRING: + { + obj = script_obj_new_string (script_obj_b->data.string); + break; + } + default: + break; + } + break; + } + + case SCRIPT_OBJ_TYPE_STRING: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_INT: + { + char* newstring; + asprintf(&newstring, "%s%d", script_obj_a->data.string, script_obj_b->data.integer); + obj = script_obj_new_string (newstring); // FIXME these two asprintfs complain about ignored returned values + free(newstring); + break; + } + case SCRIPT_OBJ_TYPE_STRING: + { + char* newstring; + asprintf(&newstring, "%s%s", script_obj_a->data.string, script_obj_b->data.string); + obj = script_obj_new_string (newstring); + free(newstring); + break; + case SCRIPT_OBJ_TYPE_NULL: + obj = script_obj_new_string (script_obj_a->data.string); + break; + } + default: + break; + } + break; + } + + default: + break; + } + + script_obj_unref (script_obj_a); + script_obj_unref (script_obj_b); + + if (!obj){ + obj = script_obj_new_null (); + } + return obj; +} + +static script_obj* script_evaluate_minus (script_state* state, script_exp* exp) +{ + script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a); + script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b); + script_obj* obj = NULL; + + script_obj_deref (&script_obj_a); + script_obj_deref (&script_obj_b); + + switch (script_obj_a->type){ + case SCRIPT_OBJ_TYPE_INT: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_INT: + obj = script_obj_new_int (script_obj_a->data.integer - script_obj_b->data.integer); + break; + case SCRIPT_OBJ_TYPE_NULL: + obj = script_obj_new_int (script_obj_a->data.integer); + break; + default: + break; + } + break; + } + case SCRIPT_OBJ_TYPE_NULL: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_INT: + obj = script_obj_new_int (-script_obj_b->data.integer); + break; + default: + break; + } + break; + } + default: + break; + } + + script_obj_unref (script_obj_a); + script_obj_unref (script_obj_b); + if (!obj){ + obj = script_obj_new_null (); + } + return obj; +} + +static script_obj* script_evaluate_mul (script_state* state, script_exp* exp) +{ + script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a); + script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b); + script_obj* obj = NULL; + + script_obj_deref (&script_obj_a); + script_obj_deref (&script_obj_b); + + switch (script_obj_a->type){ + case SCRIPT_OBJ_TYPE_INT: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_INT: + obj = script_obj_new_int (script_obj_a->data.integer * script_obj_b->data.integer); + break; + default: + break; + } + break; + } + default: + break; + } + + script_obj_unref (script_obj_a); + script_obj_unref (script_obj_b); + if (!obj){ + obj = script_obj_new_null (); + } + return obj; +} + +static script_obj* script_evaluate_div (script_state* state, script_exp* exp) +{ + script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a); + script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b); + script_obj* obj = NULL; + + script_obj_deref (&script_obj_a); + script_obj_deref (&script_obj_b); + + switch (script_obj_a->type){ + case SCRIPT_OBJ_TYPE_INT: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_INT: + if (script_obj_b->data.integer == 0) obj = script_obj_new_null (); + else obj = script_obj_new_int (script_obj_a->data.integer / script_obj_b->data.integer); + break; + default: + break; + } + break; + } + default: + break; + } + + script_obj_unref (script_obj_a); + script_obj_unref (script_obj_b); + if (!obj){ + obj = script_obj_new_null (); + } + return obj; +} + + +static script_obj* script_evaluate_mod (script_state* state, script_exp* exp) +{ + script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a); + script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b); + script_obj* obj = NULL; + + script_obj_deref (&script_obj_a); + script_obj_deref (&script_obj_b); + + switch (script_obj_a->type){ + case SCRIPT_OBJ_TYPE_INT: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_INT: + if (script_obj_b->data.integer == 0) obj = script_obj_new_null (); + else obj = script_obj_new_int (script_obj_a->data.integer % script_obj_b->data.integer); + break; + default: + break; + } + break; + } + default: + break; + } + + script_obj_unref (script_obj_a); + script_obj_unref (script_obj_b); + if (!obj){ + obj = script_obj_new_null (); + } + return obj; +} + +static script_obj* script_evaluate_hash (script_state* state, script_exp* exp) +{ + script_obj* hash = script_evaluate (state, exp->data.dual.sub_a); + script_obj* key = script_evaluate (state, exp->data.dual.sub_b); + script_obj* hash_dereffed = script_obj_deref_direct(hash); + script_obj* obj; + script_obj_deref (&key); + + if (hash_dereffed->type == SCRIPT_OBJ_TYPE_HASH){ + script_obj_deref (&hash); + } + else { + script_obj_reset (hash); + script_obj* newhash = script_obj_new_hash (); + hash->type = SCRIPT_OBJ_TYPE_REF; + hash->data.obj = newhash; + script_obj_deref (&hash); + } + + + char* name = script_obj_as_string(key); + script_vareable* vareable = ply_hashtable_lookup (hash->data.hash, name); + + if (vareable) { + obj = vareable->object; + free(name); + } + else { + obj = script_obj_new_null (); + vareable = malloc(sizeof(script_vareable)); + vareable->name = name; + vareable->object = obj; + ply_hashtable_insert (hash->data.hash, vareable->name, vareable); + } + + script_obj_ref (obj); + script_obj_unref (hash); + script_obj_unref (key); + return obj; +} + + +static script_obj* script_evaluate_var (script_state* state, script_exp* exp) +{ + char* name = exp->data.string; + script_obj* obj; + assert (state->global->type == SCRIPT_OBJ_TYPE_HASH); + assert (state->local->type == SCRIPT_OBJ_TYPE_HASH); + + script_vareable* vareable = ply_hashtable_lookup (state->local->data.hash, name); + if (!vareable) + vareable = ply_hashtable_lookup (state->global->data.hash, name); + if (vareable) { + obj = vareable->object; + script_obj_ref (obj); + return obj; + } + obj = script_obj_new_null (); + + vareable = malloc(sizeof(script_vareable)); + vareable->name = strdup(name); + vareable->object = obj; + + ply_hashtable_insert (state->local->data.hash, vareable->name, vareable); + script_obj_ref (obj); + return obj; +} + + +static script_obj* script_evaluate_assign (script_state* state, script_exp* exp) +{ + script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a); + script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b); + script_obj_deref (&script_obj_b); + script_obj_reset (script_obj_a); + script_obj_assign (script_obj_a, script_obj_b); + + script_obj_unref(script_obj_b); + return script_obj_a; +} + +static script_obj* script_evaluate_cmp (script_state* state, script_exp* exp) +{ + script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a); + script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b); + + script_obj_deref (&script_obj_a); + script_obj_deref (&script_obj_b); + + int gt=0; + int lt=0; + int eq=0; + int ne=0; + + int val; + int valset=0; + + switch (script_obj_a->type){ + case SCRIPT_OBJ_TYPE_REF: + assert(0); + case SCRIPT_OBJ_TYPE_INT: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_REF: + assert(0); + case SCRIPT_OBJ_TYPE_INT: + val = script_obj_a->data.integer - script_obj_b->data.integer; + valset=1; + break; + default: + ne = 1; + break; + } + break; + } + case SCRIPT_OBJ_TYPE_STRING: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_REF: + assert(0); + case SCRIPT_OBJ_TYPE_STRING: + val = strcmp(script_obj_a->data.string, script_obj_b->data.string); + valset=1; + break; + default: + ne = 1; + break; + } + break; + } + case SCRIPT_OBJ_TYPE_HASH: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_REF: + assert(0); + case SCRIPT_OBJ_TYPE_HASH: + if (script_obj_a == script_obj_b) eq = 1; + else ne = 1; + break; + default: + ne = 1; + break; + } + break; + } + case SCRIPT_OBJ_TYPE_FUNCTION: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_REF: + assert(0); + case SCRIPT_OBJ_TYPE_FUNCTION: + if (script_obj_a == script_obj_b) eq = 1; + else ne = 1; + break; + default: + ne = 1; + break; + } + break; + } + case SCRIPT_OBJ_TYPE_NULL: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_REF: + assert(0); + case SCRIPT_OBJ_TYPE_NULL: + eq = 1; + break; + default: + ne = 1; + break; + } + break; + } + case SCRIPT_OBJ_TYPE_NATIVE: + { + switch (script_obj_b->type){ + case SCRIPT_OBJ_TYPE_REF: + assert(0); + case SCRIPT_OBJ_TYPE_NATIVE: + eq = 1; + break; + default: + ne = 1; + break; + } + break; + } + } + if(valset){ + if (val < 0) {lt = 1; ne = 1;} + if (val == 0) eq = 1; + if (val > 0) {gt = 1; ne = 1;} + } + + int reply = 0; + + switch (exp->type){ + case SCRIPT_EXP_TYPE_EQ: + if (eq) reply=1; + break; + case SCRIPT_EXP_TYPE_NE: + if (ne) reply=1; + break; + case SCRIPT_EXP_TYPE_GT: + if (gt) reply=1; + break; + case SCRIPT_EXP_TYPE_GE: + if (gt || eq) reply=1; + break; + case SCRIPT_EXP_TYPE_LT: + if (lt) reply=1; + break; + case SCRIPT_EXP_TYPE_LE: + if (lt || eq) reply=1; // CHECKME Errr so "(NULL <= NULL) is true" makes sense? + break; + default: + assert(0); + } + + script_obj_unref (script_obj_a); + script_obj_unref (script_obj_b); + + return script_obj_new_int (reply); +} + +static script_obj* script_evaluate_func (script_state* state, script_exp* exp) +{ + script_state localstate; + script_obj* func = script_evaluate (state, exp->data.function.name); + script_obj* obj = NULL; + script_obj_deref (&func); + + if (func->type != SCRIPT_OBJ_TYPE_FUNCTION) + return script_obj_new_null (); + + localstate = *state; + localstate.local = script_obj_new_hash(); + + ply_list_t* parameter_names = func->data.function->parameters; + ply_list_t* parameter_data = exp->data.function.parameters; + + ply_list_node_t *node_name = ply_list_get_first_node (parameter_names); + ply_list_node_t *node_data = ply_list_get_first_node (parameter_data); + while (node_name && node_data){ + script_exp* data_exp = ply_list_node_get_data (node_data); + char* name = ply_list_node_get_data (node_name); + script_obj* data_obj = script_evaluate (state, data_exp); + + script_vareable* vareable = malloc(sizeof(script_vareable)); + vareable->name = strdup(name); + vareable->object = data_obj; + + ply_hashtable_insert (localstate.local->data.hash, vareable->name, vareable); + + + node_name = ply_list_get_next_node (parameter_names, node_name); + node_data = ply_list_get_next_node (parameter_data, node_data); + } + + script_return reply; + switch (func->data.function->type){ + case SCRIPT_FUNCTION_TYPE_SCRIPT: + { + script_op* op = func->data.function->data.script; + reply = script_execute (&localstate, op); + break; + } + case SCRIPT_FUNCTION_TYPE_NATIVE: + { + reply = func->data.function->data.native (&localstate, func->data.function->user_data); + break; + } + } + + + + script_obj_unref (localstate.local); + script_obj_unref (func); + if (reply.type == SCRIPT_RETURN_TYPE_RETURN) + obj = reply.object; + if (!obj){ + obj = script_obj_new_null (); + } + return obj; +} + + +static script_obj* script_evaluate (script_state* state, script_exp* exp) +{ + switch (exp->type){ + case SCRIPT_EXP_TYPE_PLUS: + { + return script_evaluate_plus (state, exp); + } + case SCRIPT_EXP_TYPE_MINUS: + { + return script_evaluate_minus (state, exp); + } + case SCRIPT_EXP_TYPE_MUL: + { + return script_evaluate_mul (state, exp); + } + case SCRIPT_EXP_TYPE_DIV: + { + return script_evaluate_div (state, exp); + } + case SCRIPT_EXP_TYPE_MOD: + { + return script_evaluate_mod (state, exp); + } + case SCRIPT_EXP_TYPE_EQ: + case SCRIPT_EXP_TYPE_NE: + case SCRIPT_EXP_TYPE_GT: + case SCRIPT_EXP_TYPE_GE: + case SCRIPT_EXP_TYPE_LT: + case SCRIPT_EXP_TYPE_LE: + { + return script_evaluate_cmp (state, exp); + } + case SCRIPT_EXP_TYPE_TERM_INT: + { + return script_obj_new_int (exp->data.integer); + } + case SCRIPT_EXP_TYPE_TERM_STRING: + { + return script_obj_new_string (exp->data.string); + } + case SCRIPT_EXP_TYPE_TERM_NULL: + { + return script_obj_new_null(); + } + case SCRIPT_EXP_TYPE_TERM_LOCAL: + { + script_obj_ref(state->local); + return state->local; + } + case SCRIPT_EXP_TYPE_TERM_GLOBAL: + { + script_obj_ref(state->global); + return state->global; + } + case SCRIPT_EXP_TYPE_TERM_VAR: + { + return script_evaluate_var (state, exp); + } + case SCRIPT_EXP_TYPE_ASSIGN: + { + return script_evaluate_assign (state, exp); + } + case SCRIPT_EXP_TYPE_HASH: + { + return script_evaluate_hash (state, exp); + } + case SCRIPT_EXP_TYPE_FUNCTION: + { + return script_evaluate_func (state, exp); + } +// default: +// printf("unhandeled operation type %d\n", exp->type); +// assert(0); + } + assert(0); +} + +static script_return script_execute_list (script_state* state, ply_list_t* op_list) // FIXME script_execute returns the return obj +{ + script_return reply = {SCRIPT_RETURN_TYPE_NORMAL, NULL}; + ply_list_node_t *node = ply_list_get_first_node (op_list); + for (node = ply_list_get_first_node (op_list); node; node = ply_list_get_next_node (op_list, node)){ + script_op* op = ply_list_node_get_data (node); + reply = script_execute(state, op); + switch (reply.type) { + case SCRIPT_RETURN_TYPE_NORMAL: + break; + case SCRIPT_RETURN_TYPE_RETURN: + case SCRIPT_RETURN_TYPE_BREAK: + case SCRIPT_RETURN_TYPE_CONTINUE: + return reply; + } + } + return reply; +} + + +script_return script_execute (script_state* state, script_op* op) +{ + script_return reply = {SCRIPT_RETURN_TYPE_NORMAL, NULL}; + switch (op->type){ + case SCRIPT_OP_TYPE_EXPRESSION: + { + script_obj* obj = script_evaluate (state, op->data.exp); + script_obj_unref(obj); // there is always a reply from all expressions (even assigns) which we chuck away + break; + } + case SCRIPT_OP_TYPE_OP_BLOCK: + { + reply = script_execute_list (state, op->data.list); + // FIXME blocks should normall reply a NULL , but if they replied something else then that was a return + break; + } + case SCRIPT_OP_TYPE_IF: + { + script_obj* obj = script_evaluate (state, op->data.cond_op.cond); + if (script_obj_as_bool(obj)){ + reply = script_execute (state, op->data.cond_op.op); // FIXME propagate break + } + script_obj_unref(obj); + break; + } + case SCRIPT_OP_TYPE_WHILE: + { + script_obj* obj; + while (1){ + obj = script_evaluate (state, op->data.cond_op.cond); + if (script_obj_as_bool(obj)){ + reply = script_execute (state, op->data.cond_op.op); // FIXME handle break + script_obj_unref(obj); + switch (reply.type) { + case SCRIPT_RETURN_TYPE_NORMAL: + break; + case SCRIPT_RETURN_TYPE_RETURN: + return reply; + case SCRIPT_RETURN_TYPE_BREAK: + return (script_return){SCRIPT_RETURN_TYPE_NORMAL, NULL}; + case SCRIPT_RETURN_TYPE_CONTINUE: + reply = (script_return){SCRIPT_RETURN_TYPE_NORMAL, NULL}; + break; + } + } + else { + script_obj_unref(obj); + break; + } + } + break; + } + case SCRIPT_OP_TYPE_FUNCTION_DEF: + { + script_obj* obj = script_evaluate(state, op->data.function_def.name); + script_obj_reset (obj); + obj->type = SCRIPT_OBJ_TYPE_FUNCTION; + obj->data.function = op->data.function_def.function; + script_obj_unref(obj); + break; + } + case SCRIPT_OP_TYPE_RETURN: + { + script_obj* obj; + if (op->data.exp) obj = script_evaluate (state, op->data.exp); + else obj = script_obj_new_null(); + reply = (script_return){SCRIPT_RETURN_TYPE_RETURN, obj}; + break; + } + case SCRIPT_OP_TYPE_BREAK: + { + reply = (script_return){SCRIPT_RETURN_TYPE_BREAK, NULL}; + break; + } + case SCRIPT_OP_TYPE_CONTINUE: + { + reply = (script_return){SCRIPT_RETURN_TYPE_CONTINUE, NULL}; + break; + } + } + return reply; +} + + + diff --git a/src/plugins/splash/script/script-execute.h b/src/plugins/splash/script/script-execute.h new file mode 100644 index 00000000..ded3f54b --- /dev/null +++ b/src/plugins/splash/script/script-execute.h @@ -0,0 +1,9 @@ +#ifndef SCRIPT_EXECUTE_H +#define SCRIPT_EXECUTE_H + +#include "script.h" + +script_return script_execute (script_state* state, script_op* op); + + +#endif /* SCRIPT_EXECUTE_H */ diff --git a/src/plugins/splash/script/script-lib-image.c b/src/plugins/splash/script/script-lib-image.c new file mode 100644 index 00000000..14df7236 --- /dev/null +++ b/src/plugins/splash/script/script-lib-image.c @@ -0,0 +1,114 @@ +#define _GNU_SOURCE +#include "ply-image.h" +#include "ply-utils.h" +#include "script.h" +#include "script-object.h" +#include "script-execute.h" +#include "script-lib-image.h" +#include +#include +#include +#include + +#include "config.h" + +#define STRINGIFY_VAR script_lib_image_string + +#include "script-lib-image.string" + + +static void image_free (script_obj* obj) +{ + ply_image_t *image = obj->data.native.object_data; + ply_image_free (image); +} + + +static script_return image_new (script_state* state, void* user_data) +{ + script_lib_image_data_t* data = user_data; + script_obj* reply; + char* filename; + char* path_filename; + + script_obj* script_obj_filename = script_obj_hash_get_element (state->local, "filename"); + filename = script_obj_as_string(script_obj_filename); + asprintf(&path_filename, "%s/%s", data->image_dir, filename); + script_obj_unref(script_obj_filename); + + ply_image_t *image = ply_image_new (path_filename); + if (ply_image_load (image)){ + reply = script_obj_new_native (image, data->class); + } + else { + reply = script_obj_new_null (); + } + free(filename); + free(path_filename); + return (script_return){SCRIPT_RETURN_TYPE_RETURN, reply}; +} + +static script_return image_get_width (script_state* state, void* user_data) +{ + script_lib_image_data_t* data = user_data; + script_obj* script_obj_image = script_obj_hash_get_element (state->local, "image"); + script_obj_deref(&script_obj_image); + script_obj* reply; + if (script_obj_image->type == SCRIPT_OBJ_TYPE_NATIVE && + script_obj_image->data.native.class == data->class){ + ply_image_t *image = script_obj_image->data.native.object_data; + reply = script_obj_new_int (ply_image_get_width (image)); + } + else + reply = script_obj_new_null (); + script_obj_unref(script_obj_image); + return (script_return){SCRIPT_RETURN_TYPE_RETURN, reply}; +} + +static script_return image_get_height (script_state* state, void* user_data) +{ + script_lib_image_data_t* data = user_data; + script_obj* script_obj_image = script_obj_hash_get_element (state->local, "image"); + script_obj_deref(&script_obj_image); + script_obj* reply; + if (script_obj_image->type == SCRIPT_OBJ_TYPE_NATIVE && + script_obj_image->data.native.class == data->class){ + ply_image_t *image = script_obj_image->data.native.object_data; + reply = script_obj_new_int (ply_image_get_height (image)); + } + else + reply = script_obj_new_null (); + script_obj_unref(script_obj_image); + return (script_return){SCRIPT_RETURN_TYPE_RETURN, reply}; +} + + + + +script_lib_image_data_t* script_lib_image_setup(script_state *state, char* image_dir) +{ + script_lib_image_data_t* data = malloc(sizeof(script_lib_image_data_t)); + data->class = script_obj_native_class_new(image_free, "image", data); + data->image_dir = strdup(image_dir); + + script_add_native_function (state->global, "ImageNew", image_new, data, "filename", NULL); + script_add_native_function (state->global, "ImageGetWidth", image_get_width, data, "image", NULL); + script_add_native_function (state->global, "ImageGetHeight", image_get_height, data, "image", NULL); + + data->script_main_op = script_parse_string (script_lib_image_string); + script_return ret = script_execute(state, data->script_main_op); + if (ret.object) script_obj_unref(ret.object); // Throw anything sent back away + + return data; +} + + +void script_lib_image_destroy(script_lib_image_data_t* data) +{ + script_obj_native_class_destroy(data->class); + free(data->image_dir); + script_parse_op_free (data->script_main_op); + free(data); +} + + diff --git a/src/plugins/splash/script/script-lib-image.h b/src/plugins/splash/script/script-lib-image.h new file mode 100644 index 00000000..245718df --- /dev/null +++ b/src/plugins/splash/script/script-lib-image.h @@ -0,0 +1,17 @@ +#ifndef SCRIPT_LIB_IMAGE +#define SCRIPT_LIB_IMAGE + +#include "script.h" + +typedef struct +{ + script_obj_native_class* class; + script_op *script_main_op; + char* image_dir; +} script_lib_image_data_t; + + +script_lib_image_data_t* script_lib_image_setup(script_state *state, char* image_dir); +void script_lib_image_destroy(script_lib_image_data_t* data); + +#endif /* SCRIPT_LIB_IMAGE */ diff --git a/src/plugins/splash/script/script-lib-image.script b/src/plugins/splash/script/script-lib-image.script new file mode 100644 index 00000000..bac9c714 --- /dev/null +++ b/src/plugins/splash/script/script-lib-image.script @@ -0,0 +1 @@ + diff --git a/src/plugins/splash/script/script-lib-math.c b/src/plugins/splash/script/script-lib-math.c new file mode 100644 index 00000000..93c31353 --- /dev/null +++ b/src/plugins/splash/script/script-lib-math.c @@ -0,0 +1,38 @@ +#define _GNU_SOURCE +#include "ply-utils.h" +#include "script.h" +#include "script-execute.h" +#include "script-object.h" +#include "script-lib-math.h" +#include +#include +#include +#include + +#include "config.h" + +#define STRINGIFY_VAR script_lib_math_string + +#include "script-lib-math.string" + + + +script_lib_math_data_t* script_lib_math_setup(script_state *state) +{ + script_lib_math_data_t* data = malloc(sizeof(script_lib_math_data_t)); + + data->script_main_op = script_parse_string (script_lib_math_string); + script_return ret = script_execute(state, data->script_main_op); + if (ret.object) script_obj_unref(ret.object); // Throw anything sent back away + + return data; +} + + +void script_lib_math_destroy(script_lib_math_data_t* data) +{ + script_parse_op_free (data->script_main_op); + free(data); +} + + diff --git a/src/plugins/splash/script/script-lib-math.h b/src/plugins/splash/script/script-lib-math.h new file mode 100644 index 00000000..17e2ebba --- /dev/null +++ b/src/plugins/splash/script/script-lib-math.h @@ -0,0 +1,15 @@ +#ifndef SCRIPT_LIB_MATH +#define SCRIPT_LIB_MATH + +#include "script.h" + +typedef struct +{ + script_op *script_main_op; +} script_lib_math_data_t; + + +script_lib_math_data_t* script_lib_math_setup(script_state *state); +void script_lib_math_destroy(script_lib_math_data_t* data); + +#endif /* SCRIPT_LIB_MATH */ diff --git a/src/plugins/splash/script/script-lib-math.script b/src/plugins/splash/script/script-lib-math.script new file mode 100644 index 00000000..bac9c714 --- /dev/null +++ b/src/plugins/splash/script/script-lib-math.script @@ -0,0 +1 @@ + diff --git a/src/plugins/splash/script/script-lib-plymouth.c b/src/plugins/splash/script/script-lib-plymouth.c new file mode 100644 index 00000000..0b82e5b9 --- /dev/null +++ b/src/plugins/splash/script/script-lib-plymouth.c @@ -0,0 +1,51 @@ +#define _GNU_SOURCE +#include "ply-utils.h" +#include "script.h" +#include "script-execute.h" +#include "script-object.h" +#include "script-lib-plymouth.h" +#include +#include +#include +#include + +#include "config.h" + +#define STRINGIFY_VAR script_lib_plymouth_string + +#include "script-lib-plymouth.string" + + +static script_return plymouth_set_refresh (script_state* state, void* user_data) +{ + script_lib_plymouth_data_t* data = user_data; + script_obj* obj = script_obj_hash_get_element (state->local, "function"); + script_obj_deref(&obj); + if (obj->type == SCRIPT_OBJ_TYPE_FUNCTION){ + data->script_refresh_func = obj; + } + return (script_return){SCRIPT_RETURN_TYPE_RETURN, script_obj_new_null ()}; +} + + +script_lib_plymouth_data_t* script_lib_plymouth_setup(script_state *state) +{ + script_lib_plymouth_data_t* data = malloc(sizeof(script_lib_plymouth_data_t)); + + data->script_refresh_func = NULL; + + script_add_native_function (state->global, "PlymouthSetRefreshFunction", plymouth_set_refresh, data, "function", NULL); + data->script_main_op = script_parse_string (script_lib_plymouth_string); + script_return ret = script_execute(state, data->script_main_op); + if (ret.object) script_obj_unref(ret.object); // Throw anything sent back away + + return data; +} + + +void script_lib_plymouth_destroy(script_lib_plymouth_data_t* data) +{ + script_parse_op_free (data->script_main_op); + script_obj_unref(data->script_refresh_func); + free(data); +} diff --git a/src/plugins/splash/script/script-lib-plymouth.h b/src/plugins/splash/script/script-lib-plymouth.h new file mode 100644 index 00000000..34c38d04 --- /dev/null +++ b/src/plugins/splash/script/script-lib-plymouth.h @@ -0,0 +1,16 @@ +#ifndef SCRIPT_LIB_PLYMOUTH +#define SCRIPT_LIB_PLYMOUTH + +#include "script.h" + +typedef struct +{ + script_op *script_main_op; + script_obj *script_refresh_func; +} script_lib_plymouth_data_t; + + +script_lib_plymouth_data_t* script_lib_plymouth_setup(script_state *state); +void script_lib_plymouth_destroy(script_lib_plymouth_data_t* data); + +#endif /* SCRIPT_LIB_PLYMOUTH */ diff --git a/src/plugins/splash/script/script-lib-plymouth.script b/src/plugins/splash/script/script-lib-plymouth.script new file mode 100644 index 00000000..bac9c714 --- /dev/null +++ b/src/plugins/splash/script/script-lib-plymouth.script @@ -0,0 +1 @@ + diff --git a/src/plugins/splash/script/script-lib-sprite.c b/src/plugins/splash/script/script-lib-sprite.c new file mode 100644 index 00000000..f7982c29 --- /dev/null +++ b/src/plugins/splash/script/script-lib-sprite.c @@ -0,0 +1,238 @@ +#include "ply-image.h" +#include "ply-utils.h" +#include "ply-window.h" +#include "ply-logger.h" +#include "ply-key-file.h" +#include "script.h" +#include "script-execute.h" +#include "script-object.h" +#include "script-lib-image.h" +#include "script-lib-sprite.h" +#include +#include + + +#define STRINGIFY_VAR script_lib_sprite_string +#include "script-lib-sprite.string" + +static void sprite_free (script_obj* obj) +{ + script_lib_sprite_data_t* data = obj->data.native.class->user_data; + ply_list_remove_data (data->sprite_list, obj->data.native.object_data); + sprite_t *sprite = obj->data.native.object_data; + if (sprite->image_obj) script_obj_unref(sprite->image_obj); + free(obj->data.native.object_data); +} + +static script_return sprite_new (script_state* state, void* user_data) +{ + script_lib_sprite_data_t* data = user_data; + script_obj* reply; + + sprite_t *sprite = calloc(1, sizeof(sprite_t)); + sprite->x = 0; + sprite->y = 0; + sprite->z = 0; + sprite->opacity = 1.0; + sprite->old_x = 0; + sprite->old_y = 0; + sprite->old_z = 0; + sprite->old_opacity = 1.0; + sprite->refresh_me = false; + sprite->image = NULL; + sprite->image_obj = NULL; + ply_list_append_data (data->sprite_list, sprite); + + reply = script_obj_new_native (sprite, data->class); + return (script_return){SCRIPT_RETURN_TYPE_RETURN, reply}; +} + + +static script_return sprite_set_image (script_state* state, void* user_data) +{ + script_lib_sprite_data_t* data = user_data; + script_obj* script_obj_sprite = script_obj_hash_get_element (state->local, "sprite"); + script_obj_deref(&script_obj_sprite); + script_obj* script_obj_image = script_obj_hash_get_element (state->local, "image"); + script_obj_deref(&script_obj_image); + + if (script_obj_image->type == SCRIPT_OBJ_TYPE_NATIVE && + script_obj_sprite->type == SCRIPT_OBJ_TYPE_NATIVE && + script_obj_sprite->data.native.class == data->class){ + sprite_t *sprite = script_obj_sprite->data.native.object_data; + ply_image_t *image = script_obj_image->data.native.object_data; + if (sprite->image_obj) script_obj_unref(sprite->image_obj); + script_obj_ref(script_obj_image); + sprite->image = image; + sprite->image_obj = script_obj_image; + } + script_obj_unref(script_obj_sprite); + script_obj_unref(script_obj_image); + + return (script_return){SCRIPT_RETURN_TYPE_RETURN, script_obj_new_null ()}; +} + + + +static script_return sprite_set_x (script_state* state, void* user_data) +{ + script_lib_sprite_data_t* data = user_data; + script_obj* script_obj_sprite = script_obj_hash_get_element (state->local, "sprite"); + script_obj_deref(&script_obj_sprite); + script_obj* script_obj_value = script_obj_hash_get_element (state->local, "value"); + script_obj_deref(&script_obj_value); + + if (script_obj_sprite->type == SCRIPT_OBJ_TYPE_NATIVE && + script_obj_sprite->data.native.class == data->class){ + sprite_t *sprite = script_obj_sprite->data.native.object_data; + sprite->x = script_obj_as_int(script_obj_value); + } + script_obj_unref(script_obj_sprite); + script_obj_unref(script_obj_value); + return (script_return){SCRIPT_RETURN_TYPE_RETURN, script_obj_new_null ()}; +} + +static script_return sprite_set_y (script_state* state, void* user_data) +{ + script_lib_sprite_data_t* data = user_data; + script_obj* script_obj_sprite = script_obj_hash_get_element (state->local, "sprite"); + script_obj_deref(&script_obj_sprite); + script_obj* script_obj_value = script_obj_hash_get_element (state->local, "value"); + script_obj_deref(&script_obj_value); + + if (script_obj_sprite->type == SCRIPT_OBJ_TYPE_NATIVE && + script_obj_sprite->data.native.class == data->class){ + sprite_t *sprite = script_obj_sprite->data.native.object_data; + sprite->y = script_obj_as_int(script_obj_value); + } + script_obj_unref(script_obj_sprite); + script_obj_unref(script_obj_value); + return (script_return){SCRIPT_RETURN_TYPE_RETURN, script_obj_new_null ()}; +} + +static script_return sprite_set_z (script_state* state, void* user_data) +{ + script_lib_sprite_data_t* data = user_data; + script_obj* script_obj_sprite = script_obj_hash_get_element (state->local, "sprite"); + script_obj_deref(&script_obj_sprite); + script_obj* script_obj_value = script_obj_hash_get_element (state->local, "value"); + script_obj_deref(&script_obj_value); + + if (script_obj_sprite->type == SCRIPT_OBJ_TYPE_NATIVE && + script_obj_sprite->data.native.class == data->class){ + sprite_t *sprite = script_obj_sprite->data.native.object_data; + sprite->z = script_obj_as_int(script_obj_value); + } + script_obj_unref(script_obj_sprite); + script_obj_unref(script_obj_value); + return (script_return){SCRIPT_RETURN_TYPE_RETURN, script_obj_new_null ()}; +} + + + + +static void +draw_area (script_lib_sprite_data_t* data, + int x, + int y, + int width, + int height) +{ + ply_frame_buffer_area_t clip_area; + clip_area.x = x; + clip_area.y = y; + clip_area.width = width; + clip_area.height = height; + ply_frame_buffer_t *frame_buffer = ply_window_get_frame_buffer (data->window); + + ply_frame_buffer_pause_updates (frame_buffer); + + + ply_frame_buffer_fill_with_hex_color (frame_buffer, &clip_area, 0x00000000); + + ply_list_node_t *node; + for (node = ply_list_get_first_node (data->sprite_list); node; node = ply_list_get_next_node (data->sprite_list, node)) + { + sprite_t* sprite = ply_list_node_get_data (node); + ply_frame_buffer_area_t sprite_area; + + + sprite_area.x = sprite->x; + sprite_area.y = sprite->y; + + if (sprite_area.x>=(x+width)) continue; + if (sprite_area.y>=(y+height)) continue; + + sprite_area.width = ply_image_get_width (sprite->image); + sprite_area.height = ply_image_get_height (sprite->image); + + if ((sprite_area.x+(int)sprite_area.width) <= x) continue; + if ((sprite_area.y+(int)sprite_area.height) <= y) continue; + + ply_frame_buffer_fill_with_argb32_data_at_opacity_with_clip (frame_buffer, + &sprite_area, &clip_area, 0, 0, + ply_image_get_data (sprite->image), sprite->opacity); + } + ply_frame_buffer_unpause_updates (frame_buffer); +} + + +script_lib_sprite_data_t* script_lib_sprite_setup(script_state *state, ply_window_t *window) +{ + script_lib_sprite_data_t* data = malloc(sizeof(script_lib_sprite_data_t)); + data->class = script_obj_native_class_new(sprite_free, "sprite", data); + data->sprite_list = ply_list_new(); + data->window = window; + + script_add_native_function (state->global, "SpriteNew", sprite_new, data, NULL); + script_add_native_function (state->global, "SpriteSetImage", sprite_set_image, data, "sprite", "image", NULL); + script_add_native_function (state->global, "SpriteSetX", sprite_set_x, data, "sprite", "value", NULL); + script_add_native_function (state->global, "SpriteSetY", sprite_set_y, data, "sprite", "value", NULL); + script_add_native_function (state->global, "SpriteSetZ", sprite_set_z, data, "sprite", "value", NULL); + + data->script_main_op = script_parse_string (script_lib_sprite_string); + script_return ret = script_execute(state, data->script_main_op); + if (ret.object) script_obj_unref(ret.object); // Throw anything sent back away + + { + ply_frame_buffer_area_t screen_area; + ply_frame_buffer_t *frame_buffer = ply_window_get_frame_buffer (data->window); + ply_frame_buffer_get_size (frame_buffer, &screen_area); + draw_area (data, screen_area.x, screen_area.y, screen_area.width, screen_area.height); + } + return data; +} + + +void script_lib_sprite_refresh(script_lib_sprite_data_t* data) +{ + ply_list_node_t *node; + for(node = ply_list_get_first_node (data->sprite_list); node; node = ply_list_get_next_node (data->sprite_list, node)){ + sprite_t* sprite = ply_list_node_get_data (node); + if (!sprite->image) continue; + if (sprite->x != sprite->old_x || sprite->y != sprite->old_y || sprite->z != sprite->old_z || sprite->old_opacity != sprite->opacity || sprite->refresh_me){ + int width = ply_image_get_width (sprite->image); + int height= ply_image_get_height (sprite->image); + draw_area (data, sprite->x, sprite->y, width, height); + draw_area (data, sprite->old_x, sprite->old_y, width, height); + sprite->old_x = sprite->x; + sprite->old_y = sprite->y; + sprite->old_z = sprite->z; + sprite->old_opacity = sprite->opacity; + } + } +} + + + + +void script_lib_sprite_destroy(script_lib_sprite_data_t* data) +{ + script_obj_native_class_destroy(data->class); + ply_list_free(data->sprite_list); + script_parse_op_free (data->script_main_op); + free(data); +} + + + diff --git a/src/plugins/splash/script/script-lib-sprite.h b/src/plugins/splash/script/script-lib-sprite.h new file mode 100644 index 00000000..8f33f58f --- /dev/null +++ b/src/plugins/splash/script/script-lib-sprite.h @@ -0,0 +1,35 @@ +#ifndef SCRIPT_LIB_SPRITE +#define SCRIPT_LIB_SPRITE + +#include "script.h" + +typedef struct +{ + ply_window_t *window; + ply_list_t *sprite_list; + script_obj_native_class* class; + script_op *script_main_op; +} script_lib_sprite_data_t; + + +typedef struct +{ + int x; + int y; + int z; + float opacity; + int old_x; + int old_y; + int old_z; + float old_opacity; + bool refresh_me; + ply_image_t *image; + script_obj *image_obj; +} sprite_t; + + +script_lib_sprite_data_t* script_lib_sprite_setup(script_state *state, ply_window_t *window); +void script_lib_sprite_refresh(script_lib_sprite_data_t* data); +void script_lib_sprite_destroy(script_lib_sprite_data_t* data); + +#endif /* SCRIPT_LIB_SPRITE */ diff --git a/src/plugins/splash/script/script-lib-sprite.script b/src/plugins/splash/script/script-lib-sprite.script new file mode 100644 index 00000000..f8fddfa0 --- /dev/null +++ b/src/plugins/splash/script/script-lib-sprite.script @@ -0,0 +1,25 @@ +fun SpriteUpdate(sprite){ + SpriteSetX(sprite.native, sprite.x); + SpriteSetY(sprite.native, sprite.y); + SpriteSetZ(sprite.native, sprite.z); + } + + +fun SpriteNewWithImage(filename){ + local.sprite; + + sprite.image = ImageNew(filename); + sprite.native = SpriteNew(); + if (sprite.image == NULL) return NULL; + SpriteSetImage(sprite.native, sprite.image); + + sprite.x = 0; + sprite.y = 0; + sprite.z = 0; + + SpriteUpdate(sprite); + + return sprite; + } + + diff --git a/src/plugins/splash/script/script-object.c b/src/plugins/splash/script/script-object.c new file mode 100644 index 00000000..c63dc7c0 --- /dev/null +++ b/src/plugins/splash/script/script-object.c @@ -0,0 +1,385 @@ +#define _GNU_SOURCE +#include "ply-scan.h" +#include "ply-hashtable.h" +#include "ply-list.h" +#include "ply-bitarray.h" +#include +#include +#include +#include +#include +#include +#include + +#include "script.h" +#include "script-object.h" + + +char* script_obj_print (script_obj* obj); +void script_obj_reset (script_obj* obj); + + +void script_obj_free (script_obj* obj) +{ + assert(!obj->refcount); + script_obj_reset (obj); + free(obj); +} + + +void script_obj_ref (script_obj* obj) +{ + obj->refcount++; +} + +void script_obj_unref (script_obj* obj) +{ + obj->refcount--; + if (obj->refcount<=0){ + script_obj_free (obj); + } +} + +static void foreach_free_vareable (void *key, + void *data, + void *user_data) +{ + script_vareable* vareable = data; + script_obj_unref(vareable->object); + free(vareable->name); + free(vareable); +} + + + +void script_obj_reset (script_obj* obj) +{ + switch (obj->type){ + case SCRIPT_OBJ_TYPE_REF: + script_obj_unref (obj->data.obj); + break; + case SCRIPT_OBJ_TYPE_INT: + break; + case SCRIPT_OBJ_TYPE_STRING: + free(obj->data.string); + break; + case SCRIPT_OBJ_TYPE_HASH: // FIXME nightmare + ply_hashtable_foreach (obj->data.hash, foreach_free_vareable, NULL); + ply_hashtable_free(obj->data.hash); + break; + case SCRIPT_OBJ_TYPE_FUNCTION: + { + if (obj->data.function->freeable){ + ply_list_node_t *node; + for (node = ply_list_get_first_node (obj->data.function->parameters); + node; + node = ply_list_get_next_node (obj->data.function->parameters, node)){ + char* operand = ply_list_node_get_data (node); + free(operand); + } + ply_list_free(obj->data.function->parameters); + free(obj->data.function); + } + } + break; + case SCRIPT_OBJ_TYPE_NATIVE: + if (obj->data.native.class->free_func) + obj->data.native.class->free_func(obj); + + break; + case SCRIPT_OBJ_TYPE_NULL: + break; + } + obj->type = SCRIPT_OBJ_TYPE_NULL; +} + +script_obj* script_obj_deref_direct (script_obj* obj) +{ + while (obj->type == SCRIPT_OBJ_TYPE_REF){ + obj = obj->data.obj; + } + return obj; +} + +void script_obj_deref (script_obj** obj_ptr) +{ + script_obj* obj = *obj_ptr; + obj = script_obj_deref_direct(obj); + script_obj_ref (obj); + script_obj_unref (*obj_ptr); + *obj_ptr = obj; +} + + +static void foreach_print_vareable (void *key, + void *data, + void *user_data) +{ + script_vareable* vareable = data; + char* string = script_obj_print (vareable->object); + char* reply; + char* prev = *(char**)user_data; + if (!prev) prev = strdup(""); + asprintf(&reply, "%s%s = %s\n", prev, vareable->name, string); + free(string); + free(prev); + *(char**)user_data = reply; +} + + + + +char* script_obj_print (script_obj* obj) +{ + char* reply; + switch (obj->type){ + case SCRIPT_OBJ_TYPE_REF: + { + char* subobj = script_obj_print (obj->data.obj); + asprintf(&reply, "->[%d]%s", obj->refcount, subobj); + free(subobj); + return reply; + } + + case SCRIPT_OBJ_TYPE_INT: + { + asprintf(&reply, "%d[%d]", obj->data.integer, obj->refcount); + return reply; + } + case SCRIPT_OBJ_TYPE_STRING: + { + asprintf(&reply, "\"%s\"[%d]", obj->data.string, obj->refcount); + return reply; + } + case SCRIPT_OBJ_TYPE_NULL: + { + asprintf(&reply, "NULL[%d]", obj->refcount); + return reply; + } + case SCRIPT_OBJ_TYPE_HASH: + { + char* sub = NULL; + ply_hashtable_foreach (obj->data.hash, foreach_print_vareable, &sub); + asprintf(&reply, "HASH{\n%s}[%d]", sub, obj->refcount); + free(sub); + return reply; + } + case SCRIPT_OBJ_TYPE_FUNCTION: + { + asprintf(&reply, "function()[%d]", obj->refcount); + return reply; + } + case SCRIPT_OBJ_TYPE_NATIVE: + { + asprintf(&reply, "(%s)[%d]", obj->data.native.class->name, obj->refcount); + return reply; + } + + default: + printf("unhandeled object type %d\n", obj->type); + assert(0); + } + return NULL; +} + + + +script_obj* script_obj_new_int (int number) +{ + script_obj* obj = malloc(sizeof(script_obj)); + obj->type = SCRIPT_OBJ_TYPE_INT; + obj->refcount = 1; + obj->data.integer = number; + return obj; +} + +script_obj* script_obj_new_string (const char* string) +{ + script_obj* obj = malloc(sizeof(script_obj)); + obj->type = SCRIPT_OBJ_TYPE_STRING; + obj->refcount = 1; + obj->data.string = strdup(string); + return obj; +} + +script_obj* script_obj_new_null (void) +{ + script_obj* obj = malloc(sizeof(script_obj)); + obj->type = SCRIPT_OBJ_TYPE_NULL; + obj->refcount = 1; + return obj; +} + +script_obj* script_obj_new_hash (void) +{ + script_obj* obj = malloc(sizeof(script_obj)); + obj->type = SCRIPT_OBJ_TYPE_HASH; + obj->data.hash = ply_hashtable_new (ply_hashtable_string_hash, ply_hashtable_string_compare); + obj->refcount = 1; + return obj; +} + +script_obj* script_obj_new_function (script_function* function) +{ + script_obj* obj = malloc(sizeof(script_obj)); + obj->type = SCRIPT_OBJ_TYPE_FUNCTION; + obj->data.function = function; + obj->refcount = 1; + return obj; +} + +script_obj* script_obj_new_ref (script_obj* sub_obj) +{ + script_obj* obj = malloc(sizeof(script_obj)); + obj->type = SCRIPT_OBJ_TYPE_REF; + obj->data.obj = sub_obj; + obj->refcount = 1; + return obj; +} + + +script_obj* script_obj_new_native (void* object_data, script_obj_native_class* class) +{ + script_obj* obj = malloc(sizeof(script_obj)); + obj->type = SCRIPT_OBJ_TYPE_NATIVE; + obj->data.native.class = class; + obj->data.native.object_data = object_data; + obj->refcount = 1; + return obj; +} + +int script_obj_as_int (script_obj* obj) +{ // If in then reply contents, otherwise reply 0 + obj = script_obj_deref_direct(obj); + switch (obj->type){ + case SCRIPT_OBJ_TYPE_INT: + if (obj->data.integer) return obj->data.integer; + else return 0; + case SCRIPT_OBJ_TYPE_NULL: + return 0; + case SCRIPT_OBJ_TYPE_REF: // should have been de-reffed already + assert(0); + case SCRIPT_OBJ_TYPE_HASH: + case SCRIPT_OBJ_TYPE_FUNCTION: + case SCRIPT_OBJ_TYPE_NATIVE: + return 0; + case SCRIPT_OBJ_TYPE_STRING: + if (*obj->data.string) return true; + return 0; + } + + assert(0); // Abort on uncaught + return false; +} + +bool script_obj_as_bool (script_obj* obj) +{ // False objects are NULL, 0, "" + obj = script_obj_deref_direct(obj); + switch (obj->type){ + case SCRIPT_OBJ_TYPE_INT: + if (obj->data.integer) return true; + return false; + case SCRIPT_OBJ_TYPE_NULL: + return false; + case SCRIPT_OBJ_TYPE_REF: // should have been de-reffed already + assert(0); + case SCRIPT_OBJ_TYPE_HASH: + case SCRIPT_OBJ_TYPE_FUNCTION: + case SCRIPT_OBJ_TYPE_NATIVE: + return true; + case SCRIPT_OBJ_TYPE_STRING: + if (*obj->data.string) return true; + return false; + } + + assert(0); // Abort on uncaught + return false; +} + + +char* script_obj_as_string (script_obj* obj) // reply is strdupped +{ + obj = script_obj_deref_direct(obj); + char* reply; + + switch (obj->type){ + case SCRIPT_OBJ_TYPE_INT: + asprintf(&reply, "%d", obj->data.integer); + return reply; + case SCRIPT_OBJ_TYPE_NULL: + asprintf(&reply, "NULL"); + return reply; + case SCRIPT_OBJ_TYPE_REF: // should have been de-reffed already + assert(0); + case SCRIPT_OBJ_TYPE_HASH: + assert(0); // FIXME decide + case SCRIPT_OBJ_TYPE_FUNCTION: + assert(0); // FIXME decide + case SCRIPT_OBJ_TYPE_STRING: + return strdup(obj->data.string); + case SCRIPT_OBJ_TYPE_NATIVE: + assert(0); // FIXME decide + } + + assert(0); // Abort on uncaught + return false; +} + +void script_obj_assign (script_obj* obj_a, script_obj* obj_b) +{ + script_obj_deref (&obj_b); + script_obj_reset (obj_a); + + switch (obj_b->type){ + case SCRIPT_OBJ_TYPE_NULL: + obj_a->type = SCRIPT_OBJ_TYPE_NULL; + break; + case SCRIPT_OBJ_TYPE_INT: + obj_a->type = SCRIPT_OBJ_TYPE_INT; + obj_a->data.integer = obj_b->data.integer; + break; + case SCRIPT_OBJ_TYPE_STRING: + obj_a->type = SCRIPT_OBJ_TYPE_STRING; + obj_a->data.string = strdup(obj_b->data.string); + break; + case SCRIPT_OBJ_TYPE_REF: // should have been de-reffed already + assert(0); + case SCRIPT_OBJ_TYPE_HASH: + case SCRIPT_OBJ_TYPE_FUNCTION: + case SCRIPT_OBJ_TYPE_NATIVE: + obj_a->type = SCRIPT_OBJ_TYPE_REF; + obj_a->data.obj = obj_b; + script_obj_ref(obj_b); + break; + } +} + +script_obj* script_obj_hash_get_element (script_obj* hash, const char* name) +{ + assert(hash->type == SCRIPT_OBJ_TYPE_HASH); + script_vareable* vareable = ply_hashtable_lookup (hash->data.hash, (void*)name); + script_obj* obj; + + if (vareable) { + obj = vareable->object; + } + else { + obj = script_obj_new_null (); + vareable = malloc(sizeof(script_vareable)); + vareable->name = strdup(name); + vareable->object = obj; + ply_hashtable_insert (hash->data.hash, vareable->name, vareable); + } + script_obj_ref (obj); + return obj; +} + + +void script_obj_hash_add_element (script_obj* hash, script_obj* element, const char* name) +{ + assert(hash->type == SCRIPT_OBJ_TYPE_HASH); + script_obj* obj = script_obj_hash_get_element (hash, name); + script_obj_assign (obj, element); + script_obj_unref (obj); +} + diff --git a/src/plugins/splash/script/script-object.h b/src/plugins/splash/script/script-object.h new file mode 100644 index 00000000..5e79d435 --- /dev/null +++ b/src/plugins/splash/script/script-object.h @@ -0,0 +1,29 @@ +#ifndef SCRIPT_OBJECT +#define SCRIPT_OBJECT + +#include "script.h" + +void script_obj_free (script_obj* obj); +void script_obj_ref (script_obj* obj); +void script_obj_unref (script_obj* obj); +void script_obj_reset (script_obj* obj); +script_obj* script_obj_deref_direct (script_obj* obj); +void script_obj_deref (script_obj** obj_ptr); +char* script_obj_print (script_obj* obj); +script_obj* script_obj_new_int (int number); +script_obj* script_obj_new_string (const char* string); +script_obj* script_obj_new_null (void); +script_obj* script_obj_new_hash (void); +script_obj* script_obj_new_function (script_function* function); +script_obj* script_obj_new_ref (script_obj* sub_obj); +script_obj* script_obj_new_native (void* object_data, script_obj_native_class* class); +int script_obj_as_int (script_obj* obj); +bool script_obj_as_bool (script_obj* obj); +char* script_obj_as_string (script_obj* obj); +void script_obj_assign (script_obj* obj_a, script_obj* obj_b); +script_obj* script_obj_hash_get_element (script_obj* hash, const char* name); +void script_obj_hash_add_element (script_obj* hash, script_obj* element, const char* name); + + + +#endif /* SCRIPT_OBJECT */ diff --git a/src/plugins/splash/script/script-parse.c b/src/plugins/splash/script/script-parse.c new file mode 100644 index 00000000..cd575117 --- /dev/null +++ b/src/plugins/splash/script/script-parse.c @@ -0,0 +1,646 @@ +#define _GNU_SOURCE +#include "ply-scan.h" +#include "ply-hashtable.h" +#include "ply-list.h" +#include "ply-bitarray.h" +#include +#include +#include +#include +#include +#include +#include + +#include "script.h" +#include "script-parse.h" + + +#define WITH_SEMIES + + + + +/* done todo +int var (exp) tm = ! ++ -- +f() f[] f.a pi = +* / % md = ++ - pm = && || +< <= > >= gt = +== != eq = += as = += -= *= %= + +*/ + + +static script_op* script_parse_op (ply_scan_t* scan); +static script_exp* script_parse_exp (ply_scan_t* scan); +static ply_list_t* script_parse_op_list (ply_scan_t* scan); +static void script_parse_op_list_free (ply_list_t* op_list); + +static script_exp* script_parse_exp_tm (ply_scan_t* scan) +{ + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + script_exp* exp = NULL; + if (curtoken->type == PLY_SCAN_TOKEN_TYPE_INTEGER){ + exp = malloc(sizeof(script_exp)); + exp->type = SCRIPT_EXP_TYPE_TERM_INT; + exp->data.integer = curtoken->data.integer; + ply_scan_get_next_token(scan); + return exp; + } + + if (curtoken->type == PLY_SCAN_TOKEN_TYPE_IDENTIFIER){ + exp = malloc(sizeof(script_exp)); + if (!strcmp(curtoken->data.string, "NULL")){ + exp->type = SCRIPT_EXP_TYPE_TERM_NULL; + } + else if (!strcmp(curtoken->data.string, "global")){ + exp->type = SCRIPT_EXP_TYPE_TERM_GLOBAL; + } + else if (!strcmp(curtoken->data.string, "local")){ + exp->type = SCRIPT_EXP_TYPE_TERM_LOCAL; + } + else { + exp->type = SCRIPT_EXP_TYPE_TERM_VAR; + exp->data.string = strdup(curtoken->data.string); + } + curtoken = ply_scan_get_next_token(scan); + return exp; + } + + if (curtoken->type == PLY_SCAN_TOKEN_TYPE_STRING){ + exp = malloc(sizeof(script_exp)); + exp->type = SCRIPT_EXP_TYPE_TERM_STRING; + exp->data.string = strdup(curtoken->data.string); + ply_scan_get_next_token(scan); + return exp; + } + + if (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && curtoken->data.symbol == '('){ + ply_scan_get_next_token(scan); + exp = script_parse_exp (scan); + assert(exp); //FIXME syntax error + curtoken = ply_scan_get_current_token(scan); + assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && curtoken->data.symbol == ')'); + ply_scan_get_next_token(scan); + return exp; + } + return exp; +} + +static script_exp* script_parse_exp_pi (ply_scan_t* scan) +{ + script_exp* exp = script_parse_exp_tm (scan); + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + while (true){ + if (curtoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break; + if (curtoken->data.symbol == '('){ + script_exp* func = malloc(sizeof(script_exp)); + ply_list_t* parameters = ply_list_new(); + ply_scan_get_next_token(scan); + while (true){ + if (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && curtoken->data.symbol == ')') break; + + script_exp* parameter = script_parse_exp (scan); + + ply_list_append_data (parameters, parameter); + + curtoken = ply_scan_get_current_token(scan); + assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL); //FIXME syntax error + if (curtoken->data.symbol == ')') break; + assert (curtoken->data.symbol == ','); //FIXME syntax error + ply_scan_get_next_token(scan); + } + ply_scan_get_next_token(scan); + func->data.function.name = exp; + exp = func; + exp->type = SCRIPT_EXP_TYPE_FUNCTION; + exp->data.function.parameters = parameters; + continue; + } + + script_exp* key; + + if (curtoken->data.symbol == '.'){ + ply_scan_get_next_token(scan); + if (curtoken->type == PLY_SCAN_TOKEN_TYPE_IDENTIFIER){ + key = malloc(sizeof(script_exp)); + key->type = SCRIPT_EXP_TYPE_TERM_STRING; + key->data.string = strdup(curtoken->data.string); + } + else if (curtoken->type == PLY_SCAN_TOKEN_TYPE_INTEGER){ // errrr, integer keys without being [] bracketted + key = malloc(sizeof(script_exp)); // This is broken with floats as obj.10.6 is obj[10.6] and not obj[10][6] + key->type = SCRIPT_EXP_TYPE_TERM_INT; + key->data.integer = curtoken->data.integer; + } + else assert(0); //FIXME syntax error + curtoken = ply_scan_get_next_token(scan); + } + else if (curtoken->data.symbol == '['){ + ply_scan_get_next_token(scan); + key = script_parse_exp (scan); + curtoken = ply_scan_get_current_token(scan); + assert (curtoken->data.symbol == ']'); + curtoken = ply_scan_get_next_token(scan); + } + else break; + script_exp* hash = malloc(sizeof(script_exp)); + hash->type = SCRIPT_EXP_TYPE_HASH; + hash->data.dual.sub_a = exp; + hash->data.dual.sub_b = key; + exp = hash; // common hash lookup bit; + + + } + return exp; +} + + + + +static script_exp* script_parse_exp_md (ply_scan_t* scan) +{ + script_exp* sub_a = script_parse_exp_pi (scan); + if (!sub_a) return NULL; + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + while (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && + (curtoken->data.symbol == '*' || + curtoken->data.symbol == '/' || + curtoken->data.symbol == '%' )){ + script_exp* exp = malloc(sizeof(script_exp)); + if (curtoken->data.symbol == '*') exp->type = SCRIPT_EXP_TYPE_MUL; + else if (curtoken->data.symbol == '/') exp->type = SCRIPT_EXP_TYPE_DIV; + else exp->type = SCRIPT_EXP_TYPE_MOD; + exp->data.dual.sub_a = sub_a; + ply_scan_get_next_token(scan); + exp->data.dual.sub_b = script_parse_exp_pi (scan); + assert(exp->data.dual.sub_b); //FIXME syntax error + sub_a = exp; + curtoken = ply_scan_get_current_token(scan); + } + + return sub_a; +} + +static script_exp* script_parse_exp_pm (ply_scan_t* scan) +{ + script_exp* sub_a = script_parse_exp_md (scan); + if (!sub_a) return NULL; + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + while (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && + (curtoken->data.symbol == '+' || + curtoken->data.symbol == '-' )){ + script_exp* exp = malloc(sizeof(script_exp)); + if (curtoken->data.symbol == '+') exp->type = SCRIPT_EXP_TYPE_PLUS; + else exp->type = SCRIPT_EXP_TYPE_MINUS; + exp->data.dual.sub_a = sub_a; + ply_scan_get_next_token(scan); + exp->data.dual.sub_b = script_parse_exp_md (scan); + assert(exp->data.dual.sub_b); //FIXME syntax error + sub_a = exp; + curtoken = ply_scan_get_current_token(scan); + } + + return sub_a; +} + +static script_exp* script_parse_exp_gt (ply_scan_t* scan) +{ + script_exp* sub_a = script_parse_exp_pm (scan); + if (!sub_a) return NULL; + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + ply_scan_token_t* peektoken = ply_scan_peek_next_token(scan); + while (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && + (curtoken->data.symbol == '<' || + curtoken->data.symbol == '>' )){ // FIXME make sure we dont consume <<= or >>= + int gt = (curtoken->data.symbol == '>'); + int eq = 0; + curtoken = ply_scan_get_next_token(scan); + if (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && + curtoken->data.symbol == '='){ + eq = 1; + curtoken = ply_scan_get_next_token(scan); + } + script_exp* exp = malloc(sizeof(script_exp)); + if ( gt && eq) exp->type = SCRIPT_EXP_TYPE_GE; + else if ( gt && !eq) exp->type = SCRIPT_EXP_TYPE_GT; + else if (!gt && eq) exp->type = SCRIPT_EXP_TYPE_LE; + else exp->type = SCRIPT_EXP_TYPE_LT; + + exp->data.dual.sub_a = sub_a; + exp->data.dual.sub_b = script_parse_exp_pm (scan); + assert(exp->data.dual.sub_b); //FIXME syntax error + sub_a = exp; + curtoken = ply_scan_get_current_token(scan); + peektoken = ply_scan_peek_next_token(scan); + } + + return sub_a; +} + +static script_exp* script_parse_exp_eq (ply_scan_t* scan) +{ + script_exp* sub_a = script_parse_exp_gt (scan); + if (!sub_a) return NULL; + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + ply_scan_token_t* peektoken = ply_scan_peek_next_token(scan); + while (1){ + if (curtoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break; + if (peektoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break; + + if (peektoken->data.symbol != '=') break; + if ((curtoken->data.symbol != '=') && (curtoken->data.symbol != '!')) break; + int ne = (curtoken->data.symbol == '!'); + ply_scan_get_next_token(scan); + ply_scan_get_next_token(scan); + + script_exp* exp = malloc(sizeof(script_exp)); + if (ne) exp->type = SCRIPT_EXP_TYPE_NE; + else exp->type = SCRIPT_EXP_TYPE_EQ; + exp->data.dual.sub_a = sub_a; + exp->data.dual.sub_b = script_parse_exp_gt (scan); + assert(exp->data.dual.sub_b); //FIXME syntax error + sub_a = exp; + curtoken = ply_scan_get_current_token(scan); + peektoken = ply_scan_peek_next_token(scan); + } + + return sub_a; +} + +static script_exp* script_parse_exp_as (ply_scan_t* scan) +{ + script_exp* lhs = script_parse_exp_eq (scan); + if (!lhs) return NULL; + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + + if (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && curtoken->data.symbol == '=' ){ + ply_scan_get_next_token(scan); + script_exp* rhs = script_parse_exp_eq(scan); + assert(rhs); //FIXME syntax error + script_exp* exp = malloc(sizeof(script_exp)); + exp->type = SCRIPT_EXP_TYPE_ASSIGN; + exp->data.dual.sub_a = lhs; + exp->data.dual.sub_b = rhs; + return exp; + } + return lhs; +} + +static script_exp* script_parse_exp (ply_scan_t* scan) +{ + return script_parse_exp_as (scan); + +} + +static script_op* script_parse_op_block (ply_scan_t* scan) +{ + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + + if (curtoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL || curtoken->data.symbol != '{' ) + return NULL; + + ply_scan_get_next_token(scan); + ply_list_t* sublist = script_parse_op_list (scan); + assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL); //FIXME syntax error + assert(curtoken->data.symbol == '}'); + curtoken = ply_scan_get_next_token(scan); + + script_op* op = malloc(sizeof(script_op)); + op->type = SCRIPT_OP_TYPE_OP_BLOCK; + op->data.list = sublist; + return op; +} + +static script_op* script_parse_if_while (ply_scan_t* scan) +{ + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + script_op_type type; + if (curtoken->type != PLY_SCAN_TOKEN_TYPE_IDENTIFIER) + return NULL; + if (!strcmp(curtoken->data.string, "if")) type = SCRIPT_OP_TYPE_IF; + else if (!strcmp(curtoken->data.string, "while")) type = SCRIPT_OP_TYPE_WHILE; + else return NULL; + + curtoken = ply_scan_get_next_token(scan); + assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL); //FIXME syntax error + assert(curtoken->data.symbol == '('); + curtoken = ply_scan_get_next_token(scan); + + script_exp* cond = script_parse_exp (scan); + assert(cond); //FIXME syntax error + + curtoken = ply_scan_get_current_token(scan); + assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL); //FIXME syntax error + assert(curtoken->data.symbol == ')'); + curtoken = ply_scan_get_next_token(scan); + + script_op* cond_op = script_parse_op(scan); + + script_op* op = malloc(sizeof(script_op)); + op->type = type; + op->data.cond_op.cond = cond; + op->data.cond_op.op = cond_op; + return op; +} + + + + + +static script_op* script_parse_function (ply_scan_t* scan) +{ + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + + ply_list_t *parameter_list; + + if (curtoken->type != PLY_SCAN_TOKEN_TYPE_IDENTIFIER) + return NULL; + if (strcmp(curtoken->data.string, "fun")) return NULL; + + curtoken = ply_scan_get_next_token(scan); + assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_IDENTIFIER); //FIXME syntax error + + script_exp* name = malloc(sizeof(script_exp)); + name->type = SCRIPT_EXP_TYPE_TERM_VAR; + name->data.string = strdup(curtoken->data.string); + + curtoken = ply_scan_get_next_token(scan); + + assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL); //FIXME syntax error + assert(curtoken->data.symbol == '('); + curtoken = ply_scan_get_next_token(scan); + parameter_list = ply_list_new(); + + + while (true){ + if (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && curtoken->data.symbol == ')') break; + assert (curtoken->type == PLY_SCAN_TOKEN_TYPE_IDENTIFIER); + char* parameter = strdup(curtoken->data.string); + ply_list_append_data (parameter_list, parameter); + + curtoken = ply_scan_get_next_token(scan); + assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL); //FIXME syntax error + if (curtoken->data.symbol == ')') break; + assert (curtoken->data.symbol == ','); //FIXME syntax error + ply_scan_get_next_token(scan); + } + + curtoken = ply_scan_get_next_token(scan); + + script_op* func_op = script_parse_op(scan); + + + + script_op* op = malloc(sizeof(script_op)); + op->type = SCRIPT_OP_TYPE_FUNCTION_DEF; + op->data.function_def.name = name; + op->data.function_def.function = script_function_script_new(func_op, NULL, parameter_list); + return op; +} + + + + +static script_op* script_parse_return (ply_scan_t* scan) +{ + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + if (curtoken->type != PLY_SCAN_TOKEN_TYPE_IDENTIFIER) + return NULL; + script_op_type type; + if (!strcmp(curtoken->data.string, "return")) type = SCRIPT_OP_TYPE_RETURN; + else if (!strcmp(curtoken->data.string, "break")) type = SCRIPT_OP_TYPE_BREAK; + else if (!strcmp(curtoken->data.string, "continue")) type = SCRIPT_OP_TYPE_CONTINUE; + else return NULL; + + curtoken = ply_scan_get_next_token(scan); + + script_op* op = malloc(sizeof(script_op)); + if (type == SCRIPT_OP_TYPE_RETURN){ + op->data.exp = script_parse_exp (scan); // May be NULL + curtoken = ply_scan_get_current_token(scan); + } + +#ifdef WITH_SEMIES + assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL); + assert(curtoken->data.symbol == ';'); + curtoken = ply_scan_get_next_token(scan); +#endif + + op->type = type; + return op; +} + + + + + + + + +static script_op* script_parse_op (ply_scan_t* scan) +{ + ply_scan_token_t* curtoken = ply_scan_get_current_token(scan); + script_op* reply = NULL; + + + reply = script_parse_op_block (scan); + if (reply) return reply; + + reply = script_parse_if_while (scan); + if (reply) return reply; + + reply = script_parse_return (scan); + if (reply) return reply; + + reply = script_parse_function (scan); + if (reply) return reply; + +// if curtoken->data.string == "if/for/while... + + +// default is expression + { + script_exp* exp = script_parse_exp(scan); + if (!exp) return NULL; + curtoken = ply_scan_get_current_token(scan); +#ifdef WITH_SEMIES + assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL); + assert(curtoken->data.symbol == ';'); + curtoken = ply_scan_get_next_token(scan); +#endif + + script_op* op = malloc(sizeof(script_op)); + op->type = SCRIPT_OP_TYPE_EXPRESSION; + op->data.exp = exp; + return op; + } + return NULL; +} + +static ply_list_t* script_parse_op_list (ply_scan_t* scan) +{ + ply_list_t *op_list = ply_list_new(); + + while(1){ + script_op* op = script_parse_op (scan); + if (!op) break; + ply_list_append_data (op_list, op); + } + + return op_list; +} + +static void script_parse_exp_free (script_exp* exp) +{ + if (!exp) return; + switch (exp->type){ + case SCRIPT_EXP_TYPE_PLUS: + case SCRIPT_EXP_TYPE_MINUS: + case SCRIPT_EXP_TYPE_MUL: + case SCRIPT_EXP_TYPE_DIV: + case SCRIPT_EXP_TYPE_MOD: + case SCRIPT_EXP_TYPE_EQ: + case SCRIPT_EXP_TYPE_NE: + case SCRIPT_EXP_TYPE_GT: + case SCRIPT_EXP_TYPE_GE: + case SCRIPT_EXP_TYPE_LT: + case SCRIPT_EXP_TYPE_LE: + case SCRIPT_EXP_TYPE_ASSIGN: + case SCRIPT_EXP_TYPE_HASH: + script_parse_exp_free (exp->data.dual.sub_a); + script_parse_exp_free (exp->data.dual.sub_b); + break; + case SCRIPT_EXP_TYPE_TERM_INT: + case SCRIPT_EXP_TYPE_TERM_NULL: + case SCRIPT_EXP_TYPE_TERM_LOCAL: + case SCRIPT_EXP_TYPE_TERM_GLOBAL: + break; + case SCRIPT_EXP_TYPE_FUNCTION: + { + ply_list_node_t *node; + for (node = ply_list_get_first_node (exp->data.function.parameters); + node; + node = ply_list_get_next_node (exp->data.function.parameters, node)){ + script_exp* sub = ply_list_node_get_data (node); + script_parse_exp_free (sub); + } + ply_list_free(exp->data.function.parameters); + script_parse_exp_free (exp->data.function.name); + break; + } + case SCRIPT_EXP_TYPE_TERM_STRING: + case SCRIPT_EXP_TYPE_TERM_VAR: + free (exp->data.string); + break; + } + free(exp); +} + + + +void script_parse_op_free (script_op* op) +{ + switch (op->type){ + case SCRIPT_OP_TYPE_EXPRESSION: + { + script_parse_exp_free (op->data.exp); + break; + } + case SCRIPT_OP_TYPE_OP_BLOCK: + { + script_parse_op_list_free (op->data.list); + break; + } + case SCRIPT_OP_TYPE_IF: + case SCRIPT_OP_TYPE_WHILE: + { + script_parse_exp_free (op->data.cond_op.cond); + script_parse_op_free (op->data.cond_op.op); + break; + } + { + break; + } + case SCRIPT_OP_TYPE_FUNCTION_DEF: + { + if (op->data.function_def.function->type == SCRIPT_FUNCTION_TYPE_SCRIPT){ + script_parse_op_free (op->data.function_def.function->data.script); + } + ply_list_node_t *node; + for (node = ply_list_get_first_node (op->data.function_def.function->parameters); + node; + node = ply_list_get_next_node (op->data.function_def.function->parameters, node)){ + char* arg = ply_list_node_get_data (node); + free(arg); + } + ply_list_free(op->data.function_def.function->parameters); + script_parse_exp_free(op->data.function_def.name); + free(op->data.function_def.function); + break; + } + case SCRIPT_OP_TYPE_RETURN: + { + if (op->data.exp) script_parse_exp_free (op->data.exp); + break; + } + case SCRIPT_OP_TYPE_BREAK: + case SCRIPT_OP_TYPE_CONTINUE: + { + break; + } + } + free(op); +} + + +static void script_parse_op_list_free (ply_list_t* op_list) +{ + ply_list_node_t *node; + for (node = ply_list_get_first_node (op_list); node; node = ply_list_get_next_node (op_list, node)){ + script_op* op = ply_list_node_get_data (node); + script_parse_op_free(op); + } + ply_list_free(op_list); + return; +} + + + + +script_op* script_parse_file (char* filename) +{ + ply_scan_t* scan = ply_scan_file (filename); + assert(scan); + ply_list_t* list = script_parse_op_list (scan); + ply_scan_free(scan); + script_op* op = malloc(sizeof(script_op)); + op->type = SCRIPT_OP_TYPE_OP_BLOCK; + op->data.list = list; + return op; +} + + + + + + + +script_op* script_parse_string (char* string) +{ + ply_scan_t* scan = ply_scan_string (string); + assert(scan); + ply_list_t* list = script_parse_op_list (scan); + ply_scan_free(scan); + script_op* op = malloc(sizeof(script_op)); + op->type = SCRIPT_OP_TYPE_OP_BLOCK; + op->data.list = list; + return op; +} + + + + + + + diff --git a/src/plugins/splash/script/script-parse.h b/src/plugins/splash/script/script-parse.h new file mode 100644 index 00000000..04f10865 --- /dev/null +++ b/src/plugins/splash/script/script-parse.h @@ -0,0 +1,12 @@ +#ifndef SCRIPT_PARSE +#define SCRIPT_PARSE + +#include "script.h" + +script_op* script_parse_file (char* filename); +script_op* script_parse_string (char* string); +void script_parse_op_free (script_op* op); + + + +#endif /* SCRIPT_PARSE */ diff --git a/src/plugins/splash/script/script.c b/src/plugins/splash/script/script.c new file mode 100644 index 00000000..66b012ad --- /dev/null +++ b/src/plugins/splash/script/script.c @@ -0,0 +1,112 @@ +#define _GNU_SOURCE +#include "ply-scan.h" +#include "ply-hashtable.h" +#include "ply-list.h" +#include "ply-bitarray.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "script.h" +#include "script-parse.h" +#include "script-object.h" + + + + +script_function* script_function_script_new(script_op* script, void* user_data, ply_list_t* parameter_list) +{ + script_function* function = malloc(sizeof(script_function)); + function->type = SCRIPT_FUNCTION_TYPE_SCRIPT; + function->parameters = parameter_list; + function->data.script = script; + function->freeable = false; + function->user_data = user_data; + return function; +} + +script_function* script_function_native_new(script_native_function native_function, void* user_data, ply_list_t* parameter_list) +{ + script_function* function = malloc(sizeof(script_function)); + function->type = SCRIPT_FUNCTION_TYPE_NATIVE; + function->parameters = parameter_list; + function->data.native = native_function; + function->freeable = true; + function->user_data = user_data; + return function; +} + +void script_add_native_function (script_obj *hash, const char* name, script_native_function native_function, void* user_data, const char* first_arg, ...) +{ + va_list args; + const char* arg; + ply_list_t *parameter_list = ply_list_new(); + + arg = first_arg; + va_start (args, first_arg); + while (arg){ + ply_list_append_data (parameter_list, strdup(arg)); + arg = va_arg (args, const char*); + } + va_end (args); + + script_function* function = script_function_native_new(native_function, user_data, parameter_list); + script_obj* obj = script_obj_new_function (function); + script_obj_hash_add_element (hash, obj, name); + script_obj_unref(obj); +} + + +script_obj_native_class* script_obj_native_class_new(script_obj_function free_func, const char* name, void* user_data) +{ + script_obj_native_class* class = malloc(sizeof(script_obj_native_class)); + class->free_func = free_func; + class->name = strdup(name); + class->user_data = user_data; + return class; +} + + + +void script_obj_native_class_destroy(script_obj_native_class* class) +{ + free(class->name); + free(class); + return; +} + +script_state* script_state_new(void* user_data) +{ + script_state* state = malloc(sizeof(script_state)); + state->global = script_obj_new_hash(); + script_obj_ref(state->global); + state->local = state->global; + state->user_data = user_data; + return state; +} + +script_state* script_state_init_sub(script_state* oldstate) +{ + script_state* newstate = malloc(sizeof(script_state)); + newstate->global = oldstate->global; + script_obj_ref(newstate->global); + newstate->local = script_obj_new_hash(); + newstate->user_data = oldstate->user_data; + return newstate; +} + +void script_state_destroy(script_state* state) +{ + script_obj_unref(state->global); + script_obj_unref(state->local); + free(state); +} + + + + diff --git a/src/plugins/splash/script/script.h b/src/plugins/splash/script/script.h new file mode 100644 index 00000000..8baa6e03 --- /dev/null +++ b/src/plugins/splash/script/script.h @@ -0,0 +1,192 @@ +#ifndef SCRIPT_H +#define SCRIPT_H + + +#include "ply-hashtable.h" +#include "ply-list.h" +#include "ply-scan.h" + + +typedef enum // FIXME add _t to all types +{ + SCRIPT_RETURN_TYPE_NORMAL, + SCRIPT_RETURN_TYPE_RETURN, + SCRIPT_RETURN_TYPE_BREAK, + SCRIPT_RETURN_TYPE_CONTINUE, +} script_return_type; + +struct script_obj; + +typedef struct +{ + script_return_type type; + struct script_obj* object; +} script_return; + +typedef struct +{ + void* user_data; + struct script_obj* global; + struct script_obj* local; +} script_state; + + +typedef enum +{ + SCRIPT_FUNCTION_TYPE_SCRIPT, + SCRIPT_FUNCTION_TYPE_NATIVE, +} script_function_type; + + +typedef script_return (*script_native_function) (script_state*, void*); + +typedef struct script_function +{ + script_function_type type; + ply_list_t* parameters; // list of char* typedef names + void * user_data; + union + { + script_native_function native; + struct script_op* script; + }data; + bool freeable; +} script_function; + +typedef void (*script_obj_function) (struct script_obj*); + +typedef struct +{ + script_obj_function free_func; + char* name; + void* user_data; +} script_obj_native_class; + +typedef struct +{ + void* object_data; + script_obj_native_class* class; +} script_obj_native; + +typedef enum +{ + SCRIPT_OBJ_TYPE_NULL, + SCRIPT_OBJ_TYPE_REF, + SCRIPT_OBJ_TYPE_INT, + SCRIPT_OBJ_TYPE_STRING, + SCRIPT_OBJ_TYPE_HASH, + SCRIPT_OBJ_TYPE_FUNCTION, + SCRIPT_OBJ_TYPE_NATIVE, +} script_obj_type; + +typedef struct script_obj +{ + script_obj_type type; + int refcount; + union + { + int integer; + char* string; + struct script_obj* obj; + script_function* function; + ply_hashtable_t* hash; + script_obj_native native; + } data; +} script_obj; + + + +typedef enum +{ + SCRIPT_EXP_TYPE_TERM_NULL, + SCRIPT_EXP_TYPE_TERM_INT, + SCRIPT_EXP_TYPE_TERM_STRING, + SCRIPT_EXP_TYPE_TERM_VAR, + SCRIPT_EXP_TYPE_TERM_LOCAL, + SCRIPT_EXP_TYPE_TERM_GLOBAL, + SCRIPT_EXP_TYPE_PLUS, + SCRIPT_EXP_TYPE_MINUS, + SCRIPT_EXP_TYPE_MUL, + SCRIPT_EXP_TYPE_DIV, + SCRIPT_EXP_TYPE_MOD, + SCRIPT_EXP_TYPE_GT, + SCRIPT_EXP_TYPE_GE, + SCRIPT_EXP_TYPE_LT, + SCRIPT_EXP_TYPE_LE, + SCRIPT_EXP_TYPE_EQ, + SCRIPT_EXP_TYPE_NE, + SCRIPT_EXP_TYPE_HASH, + SCRIPT_EXP_TYPE_FUNCTION, + SCRIPT_EXP_TYPE_ASSIGN, +} script_exp_type; + + +typedef struct script_exp +{ + script_exp_type type; + union + { + struct { + struct script_exp* sub_a; + struct script_exp* sub_b; + } dual; + struct script_exp *sub; + char* string; + int integer; + struct { + struct script_exp* name; + ply_list_t* parameters; + } function; + } data; +} script_exp; + + + + +typedef enum +{ + SCRIPT_OP_TYPE_EXPRESSION, + SCRIPT_OP_TYPE_OP_BLOCK, + SCRIPT_OP_TYPE_IF, + SCRIPT_OP_TYPE_WHILE, + SCRIPT_OP_TYPE_FUNCTION_DEF, + SCRIPT_OP_TYPE_RETURN, + SCRIPT_OP_TYPE_BREAK, + SCRIPT_OP_TYPE_CONTINUE, +} script_op_type; + +typedef struct script_op +{ + script_op_type type; + union + { + script_exp* exp; + ply_list_t* list; + struct { + script_exp* cond; + struct script_op* op; + } cond_op; + struct { + script_exp* name; + script_function* function; + } function_def; + } data; +} script_op; + + +typedef struct +{ + char* name; + script_obj* object; +} script_vareable; + +script_function* script_function_script_new(script_op* script, void* user_data, ply_list_t* parameter_list); +script_function* script_function_native_new(script_native_function native_function, void* user_data, ply_list_t* parameter_list); +void script_add_native_function (script_obj *hash, const char* name, script_native_function native_function, void* user_data, const char* first_arg, ...); +script_obj_native_class* script_obj_native_class_new(script_obj_function free_func, const char* name, void* user_data); +void script_obj_native_class_destroy(script_obj_native_class* class); +script_state* script_state_new(void* user_data); +script_state* script_state_init_sub(script_state* oldstate); +void script_state_destroy(script_state* state); + +#endif /* SCRIPT_H */ diff --git a/src/plugins/splash/script/stringify.pl b/src/plugins/splash/script/stringify.pl new file mode 100755 index 00000000..a0c3b450 --- /dev/null +++ b/src/plugins/splash/script/stringify.pl @@ -0,0 +1,14 @@ +#! /bin/sh +exec perl -x $0 ${1+"$@"} + if 0; +#!perl + +print "static const char* STRINGIFY_VAR = "; +while (<>) +{ + chomp; + s/\\/\\\\/g; + s/"/\\"/g; + print "\"$_\\n\"\n"; +} +print ";"; diff --git a/themes/Makefile.am b/themes/Makefile.am index 3e5207df..3caa2e62 100644 --- a/themes/Makefile.am +++ b/themes/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = spinfinity fade-in text details solar glow +SUBDIRS = spinfinity fade-in text details solar glow script MAINTAINERCLEANFILES = Makefile.in diff --git a/themes/script/Makefile.am b/themes/script/Makefile.am new file mode 100644 index 00000000..b66a8013 --- /dev/null +++ b/themes/script/Makefile.am @@ -0,0 +1,14 @@ +themedir = $(datadir)/plymouth/themes/script +dist_theme_DATA = \ + script.plymouth \ + script.script + + +MAINTAINERCLEANFILES = Makefile.in script.plymouth +CLEANFILES = script.plymouth + +script.plymouth: $(srcdir)/script.plymouth.in + sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g' \ + $(srcdir)/script.plymouth.in > script.plymouth + +EXTRA_DIST = script.plymouth.in diff --git a/themes/script/script.plymouth.in b/themes/script/script.plymouth.in new file mode 100644 index 00000000..8d916b53 --- /dev/null +++ b/themes/script/script.plymouth.in @@ -0,0 +1,8 @@ +[Plymouth Theme] +Name=Script +Description=Script plugin. not much here atm +ModuleName=script + +[script] +ImageDir=@PLYMOUTH_THEME_PATH@/script +ScriptFile=@PLYMOUTH_THEME_PATH@/script/script.script diff --git a/themes/script/script.script b/themes/script/script.script new file mode 100644 index 00000000..3db6e150 --- /dev/null +++ b/themes/script/script.script @@ -0,0 +1,45 @@ +index = 0; + +while (index<30){ + mystring = index; + if (index<10) mystring = "0" + index; + sprites[index] = SpriteNewWithImage("../spinfinity/throbber-" + mystring + ".png"); + sprites[index].xd = 1 + index; + sprites[index].yd = 1 + index; + index = index + 1; + } + +random = 1; + +fun update_logo_sprite (sprite){ + image_width = ImageGetWidth (sprite.image); + image_height = ImageGetHeight(sprite.image); + + if (sprite.x < 0) + sprite.xd = global.random % 5 + 1; + if (sprite.y < 0) + sprite.yd = global.random % 5 + 1; + if ((sprite.x + image_width) > 800) + sprite.xd = 0 - (global.random % 5 + 1); + if ((sprite.y + image_height) > 600) + sprite.yd = 0 - (global.random % 5 + 1); + + global.random = (1 + global.random * 7) % 101; + + sprite.x = sprite.x + sprite.xd; + sprite.y = sprite.y + sprite.yd; + + SpriteUpdate(sprite); + } + + +fun refresh (){ + index = 0; + while (index<30){ + update_logo_sprite (sprites[index]); + index = index + 1; + } + return; + } + +PlymouthSetRefreshFunction(refresh);