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
themes/details/Makefile
themes/solar/Makefile
themes/glow/Makefile
+ themes/script/Makefile
images/Makefile
scripts/Makefile
])
-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
--- /dev/null
+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
--- /dev/null
+/* plugin.c - boot script plugin
+ *
+ * Copyright (C) 2007, 2008 Red Hat, Inc.
+ * 2008 Charlie Brej <cbrej@cs.man.ac.uk>
+ *
+ * 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 <cbrej@cs.man.ac.uk>
+ * Ray Strode <rstrode@redhat.com>
+ */
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <values.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#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 <linux/kd.h>
+
+#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: */
--- /dev/null
+#include "ply-bitarray.h"
+#include "ply-scan.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+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; i<scan->tokencount; 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);
+}
+
+
--- /dev/null
+#ifndef PLY_SCAN_H
+#define PLY_SCAN_H
+
+#include "ply-bitarray.h"
+#include <stdbool.h>
+
+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 */
--- /dev/null
+#define _GNU_SOURCE
+#include "ply-scan.h"
+#include "ply-hashtable.h"
+#include "ply-list.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdbool.h>
+
+#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;
+}
+
+
+
--- /dev/null
+#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 */
--- /dev/null
+#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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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);
+}
+
+
--- /dev/null
+#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 */
--- /dev/null
+#define _GNU_SOURCE
+#include "ply-utils.h"
+#include "script.h"
+#include "script-execute.h"
+#include "script-object.h"
+#include "script-lib-math.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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);
+}
+
+
--- /dev/null
+#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 */
--- /dev/null
+#define _GNU_SOURCE
+#include "ply-utils.h"
+#include "script.h"
+#include "script-execute.h"
+#include "script-object.h"
+#include "script-lib-plymouth.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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);
+}
--- /dev/null
+#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 */
--- /dev/null
+#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 <assert.h>
+#include <stdlib.h>
+
+
+#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);
+}
+
+
+
--- /dev/null
+#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 */
--- /dev/null
+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;
+ }
+
+
--- /dev/null
+#define _GNU_SOURCE
+#include "ply-scan.h"
+#include "ply-hashtable.h"
+#include "ply-list.h"
+#include "ply-bitarray.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdbool.h>
+
+#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);
+}
+
--- /dev/null
+#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 */
--- /dev/null
+#define _GNU_SOURCE
+#include "ply-scan.h"
+#include "ply-hashtable.h"
+#include "ply-list.h"
+#include "ply-bitarray.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdbool.h>
+
+#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;
+}
+
+
+
+
+
+
+
--- /dev/null
+#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 */
--- /dev/null
+#define _GNU_SOURCE
+#include "ply-scan.h"
+#include "ply-hashtable.h"
+#include "ply-list.h"
+#include "ply-bitarray.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#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);
+}
+
+
+
+
--- /dev/null
+#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 */
--- /dev/null
+#! /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 ";";
-SUBDIRS = spinfinity fade-in text details solar glow
+SUBDIRS = spinfinity fade-in text details solar glow script
MAINTAINERCLEANFILES = Makefile.in
--- /dev/null
+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
--- /dev/null
+[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
--- /dev/null
+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);