--- /dev/null
+def is_palindrome num {
+ num.to_string == num.to_string.split.reverse.join
+}
+
+let max = 0
+
+let a = 100
+while a < 1000 {
+ let b = 100
+ while b < 1000 {
+ let product = a * b
+ max = product if is_palindrome product and product > max
+ b = b + 1
+ }
+ a = a + 1
+}
+
+max
#include "data/reference.h"
#include "data/closure.h"
+#include "lib/libtable.h"
+
extern sbPool g_closure_pool;
void data_sys_init() {
sbClosure_sys_init();
sbSymbol_sys_init();
sbList_sys_init();
+
+ sbLib_sys_init();
}
void data_sys_deinit() {
- sbList_sys_deinit();
+ sbLib_sys_deinit();
+
sbSymbol_sys_deinit();
- sbRef_sys_deinit();
+ sbList_sys_deinit();
sbClosure_sys_deinit();
+ sbRef_sys_deinit();
sbHash_sys_deinit();
sbString_sys_deinit();
}
/* TODO: Need a better way of resolving these */
/* also TODO shouldn't be 'to_string' */
if (METHOD_IS("to_string")) {
- sbVm_pop(vm); /* remove method name */
- char stackbuf[1024];
- char *buf = stackbuf;
- usize length = snprintf(buf, 1024, "%lld", (long long)target->integer);
- if (length + 1 >= sizeof(stackbuf)) {
- buf = malloc(length + 1);
- snprintf(buf, length, "%lld", (long long)target->integer);
- }
- sbVm_push_immediate(vm, &HVSTR(sbString_new(buf, length)));
- if (buf != stackbuf) {
- free(buf);
- }
} else {
PANIC("unknown method name for integer");
}
#include "gc/gcinfo.h"
#include "vm/exec.h"
-#include "data/symbol.h"
-#include "data/string.h"
#define LIST_PER_BLOCK 256
#define METHOD_IS(name) (!sbstrncmp(method_name, name, sizeof(name)))
-void list_each_cfunc(hVm vm, flag init);
-void list_map_cfunc(hVm vm, flag init);
-void list_filter_cfunc(hVm vm, flag init);
-void list_any_cfunc(hVm vm, flag init);
-void list_all_cfunc(hVm vm, flag init);
-
/* TODO etc etc */
sbPool g_list_pool;
return item;
}
-void sbList_method(hVm vm) {
- hV *list = sbVm_pop(vm);
- if (list->type != IT_LIST) {
- CHECK("can't call sbList_method on something that isn't a list");
- }
- hV *argc = sbVm_pop(vm);
- if (argc->type != IT_INTEGER) {
- CHECK("argc of send should be integer!");
- }
- /* subtract 1 because the method name is itself a param */
- usize num_params = argc->integer - 1;
- hV *method_name_val = sbVm_peek(vm, num_params);
- if (method_name_val->type != IT_SYMBOL) {
- /* TODO this may become not true */
- PANIC("method name for list must be symbol!");
- }
-
- const char *method_name = sbSymbol_name(method_name_val->symbol);
- /* TODO: Need a better way of resolving these */
- if (METHOD_IS("length")) {
- if (num_params != 0) {
- PANIC("list#length takes no arguments!");
- }
- sbVm_pop(vm); /* remove method name */
- usize length;
- sbList_get_value(list->list, &length);
- sbVm_push_immediate(vm, &HVINT(length));
- } else if (METHOD_IS("push")) {
- if (num_params != 1) {
- PANIC("list#push expects 1 argument!");
- }
- hV *to_append = sbVm_pop(vm);
- sbVm_pop(vm); /* remove method name */
- sbList_append(list->list, to_append);
- sbVm_push_immediate(vm, &HVNIL);
- } else if (METHOD_IS("each")) {
- if (num_params != 1) {
- PANIC("wrong number of arguments passed to list#each");
- }
- sbVm_push_immediate(vm, list);
- sbVm_call_c_func(vm, list_each_cfunc);
- } else if (METHOD_IS("map")) {
- if (num_params != 1) {
- PANIC("wrong number of arguments passed to list#map");
- }
- sbVm_push_immediate(vm, list);
- sbVm_call_c_func(vm, list_map_cfunc);
- } else if (METHOD_IS("filter")) {
- if (num_params != 1) {
- PANIC("wrong number of arguments passed to list#filter");
- }
- sbVm_push_immediate(vm, list);
- sbVm_call_c_func(vm, list_filter_cfunc);
- } else if (METHOD_IS("any?")) {
- if (num_params != 1) {
- PANIC("wrong number of arguments passed to list#any?");
- }
- sbVm_push_immediate(vm, list);
- sbVm_call_c_func(vm, list_any_cfunc);
- } else if (METHOD_IS("all?")) {
- if (num_params != 1) {
- PANIC("wrong number of arguments passed to list#any?");
- }
- sbVm_push_immediate(vm, list);
- sbVm_call_c_func(vm, list_all_cfunc);
- } else if (METHOD_IS("reverse")) {
- if (num_params != 0) {
- PANIC("list#reverse takes no arguments!");
- }
- /* TODO maybe mutate in place if no other refs */
- sbVm_pop(vm); /* remove method name */
- usize length;
- hV *elems = sbList_get_value(list->list, &length);
- hList new_list = sbList_new(length);
- for (usize i = length - 1; ; i--) {
- sbList_append(new_list, &elems[i]);
- if (i == 0) break;
- }
- sbList_get_value(new_list, &length);
- sbVm_push_immediate(vm, &HVLIST(new_list));
- } else if (METHOD_IS("join")) {
- if (num_params > 1) {
- PANIC("list#join takes no arguments or 1 argument!");
- }
- flag join_with = FALSE;
- hString delimiter;
- if (num_params == 1) {
- hV *delimiter_v = sbVm_pop(vm);
- if (delimiter_v->type != IT_STRING) {
- PANIC("list#join parameter should be string!");
- }
- join_with = TRUE;
- delimiter = delimiter_v->string;
- }
- sbVm_pop(vm); /* remove method name */
- usize length;
- hV *elems = sbList_get_value(list->list, &length);
- hString joined = sbString_new("", 0);
- for (usize i = 0; i < length; i++) {
- if (elems[i].type != IT_STRING) {
- PANIC("need string to join");
- }
- joined = sbString_concat(joined, elems[i].string);
- if (join_with && i < length - 1) {
- joined = sbString_concat(joined, delimiter);
- }
- }
- sbVm_push_immediate(vm, &HVSTR(joined));
- } else {
- PANIC("unknown method name for list");
- }
-}
-
/* --- */
sbList *get_list_by_handle(hList handle) {
return sbPool_get_entry(&g_list_pool, handle);
}
-
-void list_each_cfunc(hVm vm, flag init) {
- if (init) {
- /* store three state variables: the list we're iterating, the index into it, and the callback function */
- sbVm_request_var_space(vm, 3);
- hV *iterating_list = sbVm_pop(vm);
- hV *loop_func = sbVm_pop(vm);
- sbVm_pop(vm); /* remove method name */
- hV index = HVINT(0);
- vm->fp->locals[0] = *iterating_list;
- vm->fp->locals[1] = index;
- vm->fp->locals[2] = *loop_func;
- } else {
- /* loop func must have finished, so remove its result */
- sbVm_pop(vm);
- }
-
- usize current_index = vm->fp->locals[1].integer++;
- usize length;
- hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
- if (current_index < length) {
- sbVm_push(vm, &iter_values[current_index]);
- sbVm_push_immediate(vm, &HVINT(1));
- sbVm_call_func(vm, &vm->fp->locals[2]);
- } else {
- /* if index was past the end, callback function won't be called, and we'll exit. return nil */
- sbVm_push_immediate(vm, &HVNIL);
- }
-}
-
-void list_map_cfunc(hVm vm, flag init) {
- if (init) {
- /* state: list being mapped, index, callback, result */
- sbVm_request_var_space(vm, 4);
- hV *iterating_list = sbVm_pop(vm);
- hV *map_func = sbVm_pop(vm);
- sbVm_pop(vm); /* remove method name */
- usize length;
- sbList_get_value(iterating_list->list, &length);
- hV index = HVINT(0);
- hV result = sbV_empty_list(length);
-
- vm->fp->locals[0] = *iterating_list;
- vm->fp->locals[1] = index;
- vm->fp->locals[2] = *map_func;
- vm->fp->locals[3] = result;
- } else {
- /* get result of map function and append its result to result list */
- hV *mapped = sbVm_pop(vm);
- sbList_append(vm->fp->locals[3].list, mapped);
- }
-
- usize current_index = vm->fp->locals[1].integer++;
- usize length;
- hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
- if (current_index < length) {
- sbVm_push(vm, &iter_values[current_index]);
- sbVm_push_immediate(vm, &HVINT(1));
- sbVm_call_func(vm, &vm->fp->locals[2]);
- } else {
- /* return result list */
- sbVm_push_immediate(vm, &vm->fp->locals[3]);
- }
-}
-
-void list_filter_cfunc(hVm vm, flag init) {
- if (init) {
- /* state: list being filtered, index, callback, result */
- sbVm_request_var_space(vm, 4);
- hV *iterating_list = sbVm_pop(vm);
- hV *filter_func = sbVm_pop(vm);
- sbVm_pop(vm); /* remove method name */
- usize length;
- sbList_get_value(iterating_list->list, &length);
- hV index = HVINT(0);
- hV result = sbV_empty_list(length);
-
- vm->fp->locals[0] = *iterating_list;
- vm->fp->locals[1] = index;
- vm->fp->locals[2] = *filter_func;
- vm->fp->locals[3] = result;
- } else {
- /* get result of filter function and append element to result if true */
- hV *mapped = sbVm_pop(vm);
- hV *element = sbVm_pop(vm);
- if (!sbV_c_falsy(mapped)) {
- sbList_append(vm->fp->locals[3].list, element);
- }
- }
-
- usize current_index = vm->fp->locals[1].integer++;
- usize length;
- hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
- if (current_index < length) {
- /* put current value on stack twice: once as parameter for function, once to save for ourselves */
- sbVm_push(vm, &iter_values[current_index]);
- sbVm_push(vm, &iter_values[current_index]);
- sbVm_push_immediate(vm, &HVINT(1));
- sbVm_call_func(vm, &vm->fp->locals[2]);
- } else {
- /* return result list */
- sbVm_push_immediate(vm, &vm->fp->locals[3]);
- }
-}
-
-void list_any_cfunc(hVm vm, flag init) {
- if (init) {
- /* state: list being filtered, index, callback */
- sbVm_request_var_space(vm, 3);
- hV *iterating_list = sbVm_pop(vm);
- hV *pred_func = sbVm_pop(vm);
- sbVm_pop(vm); /* remove method name */
- hV index = HVINT(0);
-
- vm->fp->locals[0] = *iterating_list;
- vm->fp->locals[1] = index;
- vm->fp->locals[2] = *pred_func;
- } else {
- /* get result of predicate function */
- hV *mapped = sbVm_pop(vm);
- if (!sbV_c_falsy(mapped)) {
- /* one was true! return true */
- sbVm_push_immediate(vm, &HVBOOL(TRUE));
- return;
- }
- }
-
- /* haven't found any yet... */
- usize current_index = vm->fp->locals[1].integer++;
- usize length;
- hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
- if (current_index < length) {
- /* try next element */
- sbVm_push(vm, &iter_values[current_index]);
- sbVm_push_immediate(vm, &HVINT(1));
- sbVm_call_func(vm, &vm->fp->locals[2]);
- } else {
- /* no result found */
- sbVm_push_immediate(vm, &HVBOOL(FALSE));
- }
-}
-
-void list_all_cfunc(hVm vm, flag init) {
- if (init) {
- /* state: list being filtered, index, callback */
- sbVm_request_var_space(vm, 3);
- hV *iterating_list = sbVm_pop(vm);
- hV *pred_func = sbVm_pop(vm);
- sbVm_pop(vm); /* remove method name */
- hV index = HVINT(0);
-
- vm->fp->locals[0] = *iterating_list;
- vm->fp->locals[1] = index;
- vm->fp->locals[2] = *pred_func;
- } else {
- /* get result of predicate function */
- hV *mapped = sbVm_pop(vm);
- if (sbV_c_falsy(mapped)) {
- /* one was false; return false */
- sbVm_push_immediate(vm, &HVBOOL(FALSE));
- return;
- }
- }
-
- /* all true so far */
- usize current_index = vm->fp->locals[1].integer++;
- usize length;
- hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
- if (current_index < length) {
- /* try next element */
- sbVm_push(vm, &iter_values[current_index]);
- sbVm_push_immediate(vm, &HVINT(1));
- sbVm_call_func(vm, &vm->fp->locals[2]);
- } else {
- /* all passed */
- sbVm_push_immediate(vm, &HVBOOL(TRUE));
- }
-}
const char *method_name = sbSymbol_name(method_name_val->symbol);
/* TODO: Need a better way of resolving these */
if (METHOD_IS("split")) {
- sbVm_pop(vm); /* remove method name */
- usize length;
- char scratch[8];
- const char *buf = sbString_get_value(target->string, scratch, &length);
- hList l = sbList_new(length);
- for (usize i = 0; i < length; i++) {
- sbList_append(l, &HVSTR(sbString_new(&buf[i], 1)));
- }
- sbVm_push_immediate(vm, &HVLIST(l));
}
}
--- /dev/null
+#include "lib/libtable.h"
+
+#include "data/list.h"
+#include "data/string.h"
+#include "vm/exec.h"
+
+void list_each_cfunc(hVm vm, flag init);
+void list_map_cfunc(hVm vm, flag init);
+void list_filter_cfunc(hVm vm, flag init);
+void list_any_cfunc(hVm vm, flag init);
+void list_all_cfunc(hVm vm, flag init);
+
+sbLibTable g_integer_methods;
+
+static void to_string(hVm vm, hV *target, usize num_params) {
+ sbVm_pop(vm); /* remove method name */
+ char stackbuf[1024];
+ char *buf = stackbuf;
+ usize length = snprintf(buf, 1024, "%lld", (long long)target->integer);
+ if (length + 1 >= sizeof(stackbuf)) {
+ buf = malloc(length + 1);
+ snprintf(buf, length, "%lld", (long long)target->integer);
+ }
+ sbVm_push_immediate(vm, &HVSTR(sbString_new(buf, length)));
+ if (buf != stackbuf) {
+ free(buf);
+ }
+}
+
+void sbInteger_create_methods(void) {
+ LIB_REGISTER(&g_integer_methods, "to_string", to_string);
+}
--- /dev/null
+#include "lib/libtable.h"
+
+#include "data/hashtable.h"
+#include "vm/exec.h"
+#include "mem/debug.h"
+
+/*
+typedef sbLibTable {
+ usize used;
+ usize capacity;
+ hSymbol *keys;
+ sbLibFunc *funcs;
+} sbLibTable;
+*/
+
+extern void sbList_create_methods();
+extern void sbString_create_methods();
+extern void sbInteger_create_methods();
+
+static void insert_func(hSymbol *keys, sbLibFunc *funcs, usize capacity, hSymbol key, sbLibFunc func);
+
+void sbLibTable_initialize(hLibTable t, usize capacity) {
+ *t = (sbLibTable) {0};
+ if (capacity < 16) {
+ capacity = 16;
+ }
+ t->keys = calloc(capacity, sizeof(hSymbol));
+ t->funcs = calloc(capacity, sizeof(sbLibFunc));
+ t->capacity = capacity;
+}
+
+void sbLibTable_deinitialize(hLibTable t) {
+ free(t->keys);
+ free(t->funcs);
+ *t = (sbLibTable) {0};
+}
+
+void sbLib_sys_init() {
+ sbLibTable_initialize(&g_list_methods, 16);
+ sbLibTable_initialize(&g_string_methods, 16);
+ sbLibTable_initialize(&g_integer_methods, 16);
+
+ sbList_create_methods();
+ sbString_create_methods();
+ sbInteger_create_methods();
+}
+
+void sbLib_sys_deinit() {
+ sbLibTable_deinitialize(&g_list_methods);
+ sbLibTable_deinitialize(&g_string_methods);
+ sbLibTable_deinitialize(&g_integer_methods);
+}
+
+void sbLib_resolve_method(hVm vm) {
+ hV *target = sbVm_pop(vm);
+ hV *argc = sbVm_pop(vm);
+ if (argc->type != IT_INTEGER) {
+ CHECK("argc of send should be integer!");
+ }
+ /* subtract 1 because the method name is itself a param */
+ usize num_params = argc->integer - 1;
+ hV *method_name_val = sbVm_peek(vm, num_params);
+ if (method_name_val->type != IT_SYMBOL) {
+ /* TODO this may become not true */
+ PANIC("method name must be symbol!");
+ }
+
+ hLibTable table_to_use = NULL;
+ switch(target->type) {
+ case IT_LIST:
+ table_to_use = &g_list_methods;
+ break;
+ case IT_STRING:
+ table_to_use = &g_string_methods;
+ break;
+ case IT_INTEGER:
+ table_to_use = &g_integer_methods;
+ break;
+ default:
+ PANIC("Have not implemented this method table yet!");
+ }
+
+ sbLibFunc f = sbLibTable_find(table_to_use, method_name_val->symbol);
+ if (f) {
+ f(vm, target, num_params);
+ } else {
+ PANIC("invalid method name for type %lld: %s", (long long)target->type, sbSymbol_name(method_name_val->symbol));
+ }
+}
+
+sbLibFunc sbLibTable_find(hLibTable t, hSymbol key) {
+ sbHashValue hash = sbHash_hash_bytes((const char*)&key, sizeof(hSymbol));
+ usize index = hash % t->capacity;
+ while (t->keys[index] && t->keys[index] != key) {
+ index ++;
+ index %= t->capacity;
+ }
+
+ if (t->keys[index]) {
+ return t->funcs[index];
+ } else {
+ return NULL;
+ }
+}
+
+void sbLibTable_register(hLibTable t, const char *method_name, usize method_name_length, sbLibFunc behavior) {
+ if (t->used > t->capacity / 4 * 3) {
+ /* grow table and rehash */
+ usize new_capacity = t->capacity * 2;
+ hSymbol *new_keys = calloc(new_capacity, sizeof(hSymbol));
+ sbLibFunc *new_funcs = calloc(new_capacity, sizeof(sbLibFunc));
+
+ for (usize i = 0; i < t->capacity; i++) {
+ if (t->keys[i] != 0) {
+ insert_func(new_keys, new_funcs, new_capacity, t->keys[i], t->funcs[i]);
+ }
+ }
+
+ free(t->keys);
+ free(t->funcs);
+ t->keys = new_keys;
+ t->funcs = new_funcs;
+ t->capacity = new_capacity;
+ }
+
+ hSymbol sym = sbSymbol_from_bytes(method_name, method_name_length);
+ insert_func(t->keys, t->funcs, t->capacity, sym, behavior);
+ t->used ++;
+}
+
+/* --- */
+
+static void insert_func(hSymbol *keys, sbLibFunc *funcs, usize capacity, hSymbol key, sbLibFunc func) {
+ sbHashValue hash = sbHash_hash_bytes((const char*)&key, sizeof(hSymbol));
+ usize index = hash % capacity;
+
+ while (keys[index] != 0) {
+ index ++;
+ index %= capacity;
+ }
+
+ keys[index] = key;
+ funcs[index] = func;
+}
--- /dev/null
+#include "common.h"
+
+#include "data/symbol.h"
+
+#define LIB_REGISTER(t, n, b) (sbLibTable_register(t, n, sizeof(n) - 1, b))
+
+typedef void (*sbLibFunc)(hVm, hV*, usize);
+
+typedef struct sbLibTable {
+ usize used;
+ usize capacity;
+ hSymbol *keys;
+ sbLibFunc *funcs;
+} sbLibTable;
+
+extern sbLibTable g_list_methods;
+extern sbLibTable g_string_methods;
+extern sbLibTable g_integer_methods;
+
+typedef sbLibTable *hLibTable;
+
+void sbLibTable_initialize(hLibTable t, usize capacity);
+
+void sbLibTable_deinitialize(hLibTable t);
+
+sbLibFunc sbLibTable_find(hLibTable t, hSymbol key);
+
+void sbLibTable_register(hLibTable t, const char *method_name, usize method_name_length, sbLibFunc behavior);
+
+void sbLib_resolve_method(hVm vm);
+
+void sbLib_sys_init();
+
+void sbLib_sys_deinit();
+
+void sbList_method(hVm vm);
--- /dev/null
+#include "lib/libtable.h"
+
+#include "data/list.h"
+#include "data/string.h"
+#include "vm/exec.h"
+
+void list_each_cfunc(hVm vm, flag init);
+void list_map_cfunc(hVm vm, flag init);
+void list_filter_cfunc(hVm vm, flag init);
+void list_any_cfunc(hVm vm, flag init);
+void list_all_cfunc(hVm vm, flag init);
+
+sbLibTable g_list_methods;
+
+static void length(hVm vm, hV *list, usize num_params) {
+ if (num_params != 0) {
+ PANIC("list#length takes no arguments!");
+ }
+ sbVm_pop(vm); /* remove method name */
+ usize length;
+ sbList_get_value(list->list, &length);
+ sbVm_push_immediate(vm, &HVINT(length));
+}
+
+static void push(hVm vm, hV *list, usize num_params) {
+ if (num_params != 1) {
+ PANIC("list#push expects 1 argument!");
+ }
+ hV *to_append = sbVm_pop(vm);
+ sbVm_pop(vm); /* remove method name */
+ sbList_append(list->list, to_append);
+ sbVm_push_immediate(vm, &HVNIL);
+}
+
+static void reverse(hVm vm, hV *list, usize num_params) {
+ if (num_params != 0) {
+ PANIC("list#reverse takes no arguments!");
+ }
+ /* TODO maybe mutate in place if no other refs */
+ sbVm_pop(vm); /* remove method name */
+ usize length;
+ hV *elems = sbList_get_value(list->list, &length);
+ hList new_list = sbList_new(length);
+ for (usize i = length - 1; ; i--) {
+ sbList_append(new_list, &elems[i]);
+ if (i == 0) break;
+ }
+ sbList_get_value(new_list, &length);
+ sbVm_push_immediate(vm, &HVLIST(new_list));
+}
+
+static void join(hVm vm, hV *list, usize num_params) {
+ if (num_params > 1) {
+ PANIC("list#join takes no arguments or 1 argument!");
+ }
+ flag join_with = FALSE;
+ hString delimiter;
+ if (num_params == 1) {
+ hV *delimiter_v = sbVm_pop(vm);
+ if (delimiter_v->type != IT_STRING) {
+ PANIC("list#join parameter should be string!");
+ }
+ join_with = TRUE;
+ delimiter = delimiter_v->string;
+ }
+ sbVm_pop(vm); /* remove method name */
+ usize length;
+ hV *elems = sbList_get_value(list->list, &length);
+ hString joined = sbString_new("", 0);
+ for (usize i = 0; i < length; i++) {
+ if (elems[i].type != IT_STRING) {
+ PANIC("need string to join");
+ }
+ joined = sbString_concat(joined, elems[i].string);
+ if (join_with && i < length - 1) {
+ joined = sbString_concat(joined, delimiter);
+ }
+ }
+ sbVm_push_immediate(vm, &HVSTR(joined));
+}
+
+static void each(hVm vm, hV *list, usize num_params) {
+ if (num_params != 1) {
+ PANIC("wrong number of arguments passed to list#each");
+ }
+ sbVm_push_immediate(vm, list);
+ sbVm_call_c_func(vm, list_each_cfunc);
+}
+
+static void map(hVm vm, hV *list, usize num_params) {
+ if (num_params != 1) {
+ PANIC("wrong number of arguments passed to list#map");
+ }
+ sbVm_push_immediate(vm, list);
+ sbVm_call_c_func(vm, list_map_cfunc);
+}
+
+static void filter(hVm vm, hV *list, usize num_params) {
+ if (num_params != 1) {
+ PANIC("wrong number of arguments passed to list#filter");
+ }
+ sbVm_push_immediate(vm, list);
+ sbVm_call_c_func(vm, list_filter_cfunc);
+}
+
+static void any_p(hVm vm, hV *list, usize num_params) {
+ if (num_params != 1) {
+ PANIC("wrong number of arguments passed to list#any?");
+ }
+ sbVm_push_immediate(vm, list);
+ sbVm_call_c_func(vm, list_any_cfunc);
+}
+
+static void all_p(hVm vm, hV *list, usize num_params) {
+ if (num_params != 1) {
+ PANIC("wrong number of arguments passed to list#any?");
+ }
+ sbVm_push_immediate(vm, list);
+ sbVm_call_c_func(vm, list_all_cfunc);
+}
+
+void sbList_create_methods(void) {
+ LIB_REGISTER(&g_list_methods, "length", length);
+ LIB_REGISTER(&g_list_methods, "push", push);
+ LIB_REGISTER(&g_list_methods, "reverse", reverse);
+ LIB_REGISTER(&g_list_methods, "join", join);
+ LIB_REGISTER(&g_list_methods, "each", each);
+ LIB_REGISTER(&g_list_methods, "map", map);
+ LIB_REGISTER(&g_list_methods, "filter", filter);
+ LIB_REGISTER(&g_list_methods, "any?", any_p);
+ LIB_REGISTER(&g_list_methods, "all?", all_p);
+}
+
+/* --- */
+
+void list_each_cfunc(hVm vm, flag init) {
+ if (init) {
+ /* store three state variables: the list we're iterating, the index into it, and the callback function */
+ sbVm_request_var_space(vm, 3);
+ hV *iterating_list = sbVm_pop(vm);
+ hV *loop_func = sbVm_pop(vm);
+ sbVm_pop(vm); /* remove method name */
+ hV index = HVINT(0);
+ vm->fp->locals[0] = *iterating_list;
+ vm->fp->locals[1] = index;
+ vm->fp->locals[2] = *loop_func;
+ } else {
+ /* loop func must have finished, so remove its result */
+ sbVm_pop(vm);
+ }
+
+ usize current_index = vm->fp->locals[1].integer++;
+ usize length;
+ hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
+ if (current_index < length) {
+ sbVm_push(vm, &iter_values[current_index]);
+ sbVm_push_immediate(vm, &HVINT(1));
+ sbVm_call_func(vm, &vm->fp->locals[2]);
+ } else {
+ /* if index was past the end, callback function won't be called, and we'll exit. return nil */
+ sbVm_push_immediate(vm, &HVNIL);
+ }
+}
+
+void list_map_cfunc(hVm vm, flag init) {
+ if (init) {
+ /* state: list being mapped, index, callback, result */
+ sbVm_request_var_space(vm, 4);
+ hV *iterating_list = sbVm_pop(vm);
+ hV *map_func = sbVm_pop(vm);
+ sbVm_pop(vm); /* remove method name */
+ usize length;
+ sbList_get_value(iterating_list->list, &length);
+ hV index = HVINT(0);
+ hV result = sbV_empty_list(length);
+
+ vm->fp->locals[0] = *iterating_list;
+ vm->fp->locals[1] = index;
+ vm->fp->locals[2] = *map_func;
+ vm->fp->locals[3] = result;
+ } else {
+ /* get result of map function and append its result to result list */
+ hV *mapped = sbVm_pop(vm);
+ sbList_append(vm->fp->locals[3].list, mapped);
+ }
+
+ usize current_index = vm->fp->locals[1].integer++;
+ usize length;
+ hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
+ if (current_index < length) {
+ sbVm_push(vm, &iter_values[current_index]);
+ sbVm_push_immediate(vm, &HVINT(1));
+ sbVm_call_func(vm, &vm->fp->locals[2]);
+ } else {
+ /* return result list */
+ sbVm_push_immediate(vm, &vm->fp->locals[3]);
+ }
+}
+
+void list_filter_cfunc(hVm vm, flag init) {
+ if (init) {
+ /* state: list being filtered, index, callback, result */
+ sbVm_request_var_space(vm, 4);
+ hV *iterating_list = sbVm_pop(vm);
+ hV *filter_func = sbVm_pop(vm);
+ sbVm_pop(vm); /* remove method name */
+ usize length;
+ sbList_get_value(iterating_list->list, &length);
+ hV index = HVINT(0);
+ hV result = sbV_empty_list(length);
+
+ vm->fp->locals[0] = *iterating_list;
+ vm->fp->locals[1] = index;
+ vm->fp->locals[2] = *filter_func;
+ vm->fp->locals[3] = result;
+ } else {
+ /* get result of filter function and append element to result if true */
+ hV *mapped = sbVm_pop(vm);
+ hV *element = sbVm_pop(vm);
+ if (!sbV_c_falsy(mapped)) {
+ sbList_append(vm->fp->locals[3].list, element);
+ }
+ }
+
+ usize current_index = vm->fp->locals[1].integer++;
+ usize length;
+ hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
+ if (current_index < length) {
+ /* put current value on stack twice: once as parameter for function, once to save for ourselves */
+ sbVm_push(vm, &iter_values[current_index]);
+ sbVm_push(vm, &iter_values[current_index]);
+ sbVm_push_immediate(vm, &HVINT(1));
+ sbVm_call_func(vm, &vm->fp->locals[2]);
+ } else {
+ /* return result list */
+ sbVm_push_immediate(vm, &vm->fp->locals[3]);
+ }
+}
+
+void list_any_cfunc(hVm vm, flag init) {
+ if (init) {
+ /* state: list being filtered, index, callback */
+ sbVm_request_var_space(vm, 3);
+ hV *iterating_list = sbVm_pop(vm);
+ hV *pred_func = sbVm_pop(vm);
+ sbVm_pop(vm); /* remove method name */
+ hV index = HVINT(0);
+
+ vm->fp->locals[0] = *iterating_list;
+ vm->fp->locals[1] = index;
+ vm->fp->locals[2] = *pred_func;
+ } else {
+ /* get result of predicate function */
+ hV *mapped = sbVm_pop(vm);
+ if (!sbV_c_falsy(mapped)) {
+ /* one was true! return true */
+ sbVm_push_immediate(vm, &HVBOOL(TRUE));
+ return;
+ }
+ }
+
+ /* haven't found any yet... */
+ usize current_index = vm->fp->locals[1].integer++;
+ usize length;
+ hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
+ if (current_index < length) {
+ /* try next element */
+ sbVm_push(vm, &iter_values[current_index]);
+ sbVm_push_immediate(vm, &HVINT(1));
+ sbVm_call_func(vm, &vm->fp->locals[2]);
+ } else {
+ /* no result found */
+ sbVm_push_immediate(vm, &HVBOOL(FALSE));
+ }
+}
+
+void list_all_cfunc(hVm vm, flag init) {
+ if (init) {
+ /* state: list being filtered, index, callback */
+ sbVm_request_var_space(vm, 3);
+ hV *iterating_list = sbVm_pop(vm);
+ hV *pred_func = sbVm_pop(vm);
+ sbVm_pop(vm); /* remove method name */
+ hV index = HVINT(0);
+
+ vm->fp->locals[0] = *iterating_list;
+ vm->fp->locals[1] = index;
+ vm->fp->locals[2] = *pred_func;
+ } else {
+ /* get result of predicate function */
+ hV *mapped = sbVm_pop(vm);
+ if (sbV_c_falsy(mapped)) {
+ /* one was false; return false */
+ sbVm_push_immediate(vm, &HVBOOL(FALSE));
+ return;
+ }
+ }
+
+ /* all true so far */
+ usize current_index = vm->fp->locals[1].integer++;
+ usize length;
+ hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
+ if (current_index < length) {
+ /* try next element */
+ sbVm_push(vm, &iter_values[current_index]);
+ sbVm_push_immediate(vm, &HVINT(1));
+ sbVm_call_func(vm, &vm->fp->locals[2]);
+ } else {
+ /* all passed */
+ sbVm_push_immediate(vm, &HVBOOL(TRUE));
+ }
+}
--- /dev/null
+#include "lib/libtable.h"
+
+#include "data/list.h"
+#include "data/string.h"
+#include "vm/exec.h"
+
+void list_each_cfunc(hVm vm, flag init);
+void list_map_cfunc(hVm vm, flag init);
+void list_filter_cfunc(hVm vm, flag init);
+void list_any_cfunc(hVm vm, flag init);
+void list_all_cfunc(hVm vm, flag init);
+
+sbLibTable g_string_methods;
+
+static void split(hVm vm, hV *target, usize num_params) {
+ sbVm_pop(vm); /* remove method name */
+ usize length;
+ char scratch[8];
+ const char *buf = sbString_get_value(target->string, scratch, &length);
+ hList l = sbList_new(length);
+ for (usize i = 0; i < length; i++) {
+ sbList_append(l, &HVSTR(sbString_new(&buf[i], 1)));
+ }
+ sbVm_push_immediate(vm, &HVLIST(l));
+}
+
+void sbString_create_methods(void) {
+ LIB_REGISTER(&g_string_methods, "split", split);
+}
#include "mem/debug.h"
-void print_memory_bytes(void *where, usize how_many) {
+void print_memory_bytes(const char *where, usize how_many) {
for (usize i = 0; i < how_many; i++) {
- printf("%02X ", ((u8*)(char*)where)[i]);
+ printf("%02X ", ((u8*)where)[i]);
}
printf("\n");
}
#include "common.h"
-void print_memory_bytes(void *where, usize how_many);
+void print_memory_bytes(const char *where, usize how_many);
#include "data/list.h"
#include "data/reference.h"
#include "data/closure.h"
+#include "lib/libtable.h"
void call_block(hVm vm, usize block_id, hClosure closure);
void return_from_block(hVm vm);
call_block(vm, v->type, v->closure);
break;
case BC_SEND:
- sbV_message_handler(vm);
+ sbLib_resolve_method(vm);
break;
case BC_NUMARG:
param = get_param(vm);
#include "data/hashtable.h"
#include "data/string.h"
-void sbV_message_handler(hVm vm) {
- hV *target = sbVm_peek(vm, 0);
- switch(target->type) {
- case IT_LIST:
- sbList_method(vm);
- break;
- case IT_INTEGER:
- sbInteger_method(vm);
- break;
- case IT_STRING:
- sbString_method(vm);
- break;
- default:
- if (target->type < 0) {
- PANIC("haven't implemented method calling for this intrinsic type!");
- }
- if (target->type & FLAG_SQUIGGLY) {
- /* squiggle function */
- sbVm_call_func(vm, target);
- } else {
- /* normal function */
- PANIC("haven't implemented method calling for functions yet!");
- //sbFunction_method(target, vm);
- }
- }
-}
-
hV sbV_add(const hV *a, const hV *b) {
if (a->type == IT_INTEGER && b->type == IT_INTEGER) {
return sbV_int(sbInteger_sum(a->integer, b->integer));