}
def prime? num {
- factors(num).length() == 0
+ factors(num).length == 0
}
factors 600851475143
#include "lib/method.h"
#include "lib/module.h"
-sbCFuncStatus please_call_again(hVm vm, flag init);
+static sbLibTable *find_method_table(hV *target);
+static sbCFuncStatus please_call_again(hVm vm, flag init);
void sbLib_sys_init() {
sbLib_create_sentinels();
if (argc->type != IT_INTEGER) {
CHECK("argc of send should be integer!");
}
+ if (argc->integer == 0) {
+ PANIC("Method selection is required!");
+ }
+ /* subtract 1 because the method name is itself a param */
+ usize num_params = argc->integer - 1;
+
hV *method_name_val = sbVm_pop(vm);
if (method_name_val->type != IT_SYMBOL) {
- /* TODO this may become not true */
PANIC("method name must be symbol!");
}
hSymbol method_sym = method_name_val->symbol;
- /* subtract 1 because the method name is itself a param */
- usize num_params = argc->integer - 1;
- 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;
- case IT_FLOAT:
- table_to_use = &g_float_methods;
- break;
- }
+ sbLibTable *table_to_use = find_method_table(target);
if (table_to_use == NULL) {
/* did not find built in method table */
}
} else {
/* built in type that has a method table defined: find method */
- sbLibMethod f = sbLibTable_find_method(table_to_use, method_name_val->symbol);
+ sbLibMethod *f = sbLibTable_find_method(table_to_use, method_name_val->symbol);
+ if (f) {
+ if (f->is_property) {
+ /* uhhh... this is theoretically possible but weird. it's like,
+ * saying "list.length(string::convert)". fortunately we can just
+ * sort of treat it as a normal method call again */
+ f->behavior(vm, target, 0);
+ if (num_params > 0) {
+ sbVm_push(vm, &HVINT(num_params));
+ sbLib_resolve_method(vm);
+ }
+ } else {
+ if (num_params >= f->min_args && (num_params <= f->max_args || f->max_args == -1)) {
+ f->behavior(vm, target, num_params);
+ } else {
+ PANIC("Wrong number of arguments passed to method '%s'! (expected %d~%d)", sbSymbol_name(method_name_val->symbol), f->min_args, f->max_args);
+ }
+ }
+ } else {
+ PANIC("invalid method name for type %lld: %s", (long long)target->type, sbSymbol_name(method_name_val->symbol));
+ }
+ }
+}
+
+/* function that resolves constructs like 'a.b' or 'a(:b)' for intrinsic types.
+ * (non-intrinsic types are always functions, so they can be resolved just by
+ * calling them)*/
+void sbLib_resolve_property(hVm vm) {
+ printf("Resolving property\n");
+ sbVm_print_stack(vm);
+ hV *target = sbVm_pop(vm);
+ hV *argc = sbVm_pop(vm);
+ if (argc->type != IT_INTEGER) {
+ CHECK("argc of send should be integer!");
+ }
+ if (argc->integer != 1) {
+ PANIC("Illegal number of arguments!");
+ }
+
+ hV *method_name_val = sbVm_pop(vm);
+ if (method_name_val->type != IT_SYMBOL) {
+ PANIC("method name must be symbol!");
+ }
+
+ sbLibTable *table_to_use = find_method_table(target);
+
+ if (table_to_use == NULL) {
+ /* did not find built in method table */
+ if (target->type <= 0) {
+ /* for built in type, just fail, it's not done yet */
+ PANIC("Have not implemented this method table yet! (%lld)", (long long)target->type);
+ } else {
+ CHECK("This should never be reached!");
+ }
+ } else {
+ /* built in type that has a method table defined: find method */
+ sbLibMethod *f = sbLibTable_find_method(table_to_use, method_name_val->symbol);
if (f) {
- f(vm, target, num_params);
+ if (f->is_property) {
+ /* we found a property! great, just compute it and be done */
+ f->behavior(vm, target, 0);
+ } else {
+ /* it is a method, but it is being called without parameters.
+ * annoyingly, we need to construct a bound version of this method. */
+ PANIC("I haven't done this yet!");
+ }
} else {
PANIC("invalid method name for type %lld: %s", (long long)target->type, sbSymbol_name(method_name_val->symbol));
}
/* --- */
+/* function that looks up something in a built-in method table */
+static sbLibTable *find_method_table(hV *target) {
+ switch(target->type) {
+ case IT_LIST:
+ return &g_list_methods;
+ case IT_STRING:
+ return &g_string_methods;
+ case IT_INTEGER:
+ return &g_integer_methods;
+ case IT_FLOAT:
+ return &g_float_methods;
+ default:
+ return NULL;
+ }
+}
+
/* function that resolves methods from BC_SEND for non intrinsic types (aka functions) */
/* we have something like a.b(c,d,e), we need to call twice to get result of a(:b)(c,d,e) */
/* resolve_method should have set us up so we can just call in twice */
-sbCFuncStatus please_call_again(hVm vm, flag init) {
+static sbCFuncStatus please_call_again(hVm vm, flag init) {
hV *target = sbVm_pop(vm);
if (target->type <= 0) {
PANIC("i have not implemented partial methods for builtin types yet! i'll get to it");
return CFUNC_TAILCALL;
}
}
+
#ifndef __SARABANDE_LIB_H__
#define __SARABANDE_LIB_H__
-typedef void (*sbLibMethod)(hVm, hV*, usize);
+#define METHOD(f, min, max) (sbLibMethod) { .behavior = f, .is_property = FALSE, .min_args = min, .max_args = max }
+#define PROPERTY(f) (sbLibMethod) { .behavior = f, .is_property = TRUE }
+
+typedef struct sbLibMethod {
+ void (*behavior)(hVm, hV*, usize);
+ flag is_property : 1;
+ i16 min_args : 15;
+ i16 max_args;
+} sbLibMethod;
void sbLib_resolve_method(hVm vm);
+void sbLib_resolve_property(hVm vm);
+
void sbLib_resolve_global(hVm vm);
void sbLib_sys_init();
void sbFloat_create_methods(void) {
sbLibTable_initialize(&g_float_methods, 16, TRUE);
- REGISTER_METHOD_SYM(&g_float_methods, S_OP_TO_STRING, to_string);
+ REGISTER_METHOD_SYM(&g_float_methods, S_OP_TO_STRING, &PROPERTY(to_string));
}
void sbInteger_create_methods(void) {
sbLibTable_initialize(&g_integer_methods, 16, TRUE);
- REGISTER_METHOD_SYM(&g_integer_methods, S_OP_TO_STRING, to_string);
+ REGISTER_METHOD_SYM(&g_integer_methods, S_OP_TO_STRING, &PROPERTY(to_string));
}
sbLibTable g_list_methods;
static void length(hVm vm, hV *list, usize num_params) {
- if (num_params != 0) {
- PANIC("list#length takes no arguments!");
- }
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);
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 */
usize length;
hV *elems = sbList_get_value(list->list, &length);
}
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) {
}
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 reduce(hVm vm, hV *list, usize num_params) {
- if (num_params != 2) {
- PANIC("wrong number of arguments passed to list#reduce");
- }
sbVm_push_immediate(vm, list);
sbVm_call_c_func(vm, list_reduce_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) {
sbLibTable_initialize(&g_list_methods, 16, TRUE);
- REGISTER_METHOD(&g_list_methods, "length", length);
- REGISTER_METHOD(&g_list_methods, "push", push);
- REGISTER_METHOD(&g_list_methods, "reverse", reverse);
- REGISTER_METHOD(&g_list_methods, "join", join);
- REGISTER_METHOD(&g_list_methods, "each", each);
- REGISTER_METHOD(&g_list_methods, "map", map);
- REGISTER_METHOD(&g_list_methods, "filter", filter);
- REGISTER_METHOD(&g_list_methods, "reduce", reduce);
- REGISTER_METHOD(&g_list_methods, "any?", any_p);
- REGISTER_METHOD(&g_list_methods, "all?", all_p);
+ REGISTER_METHOD(&g_list_methods, "length", &PROPERTY(length));
+ REGISTER_METHOD(&g_list_methods, "push", &METHOD(push, 1, 1));
+ REGISTER_METHOD(&g_list_methods, "reverse", &METHOD(reverse, 0, 0));
+ REGISTER_METHOD(&g_list_methods, "join", &METHOD(join, 0, 1));
+ REGISTER_METHOD(&g_list_methods, "each", &METHOD(each, 1, 1));
+ REGISTER_METHOD(&g_list_methods, "map", &METHOD(map, 1, 1));
+ REGISTER_METHOD(&g_list_methods, "filter", &METHOD(filter, 1, 1));
+ REGISTER_METHOD(&g_list_methods, "reduce", &METHOD(reduce, 2, 2));
+ REGISTER_METHOD(&g_list_methods, "any?", &METHOD(any_p, 1, 1));
+ REGISTER_METHOD(&g_list_methods, "all?", &METHOD(all_p, 1, 1));
}
/* --- */
void sbString_create_methods(void) {
sbLibTable_initialize(&g_string_methods, 16, TRUE);
- REGISTER_METHOD(&g_string_methods, "split", split);
- REGISTER_METHOD_SYM(&g_string_methods, S_OP_TO_STRING, to_string);
+ REGISTER_METHOD(&g_string_methods, "split", &METHOD(split, 0, 1));
+ REGISTER_METHOD_SYM(&g_string_methods, S_OP_TO_STRING, &PROPERTY(to_string));
}
} sbLibTable;
*/
-static void insert_method(hSymbol *keys, sbLibMethod *methods, usize capacity, hSymbol key, sbLibMethod method);
+static void insert_method(hSymbol *keys, sbLibMethod *methods, usize capacity, hSymbol key, sbLibMethod *method);
static void insert_value(hSymbol *keys, hV *values, usize capacity, hSymbol key, hV *value);
static void check_grow_table(hLibTable t);
*t = (sbLibTable) {0};
}
-sbLibMethod sbLibTable_find_method(hLibTable t, hSymbol key) {
+sbLibMethod *sbLibTable_find_method(hLibTable t, hSymbol key) {
if (!t->method_table) CHECK("cannot find method in non-method table");
sbHashValue hash = sbHash_hash_bytes((const char*)&key, sizeof(hSymbol));
}
if (t->keys[index]) {
- return t->methods[index];
+ return &t->methods[index];
} else {
return NULL;
}
}
}
-void sbLibTable_register_method_sym(hLibTable t, hSymbol key, sbLibMethod method) {
+void sbLibTable_register_method_sym(hLibTable t, hSymbol key, sbLibMethod *method) {
if (!t->method_table) CHECK("cannot put method in non-method table");
check_grow_table(t);
t->used ++;
}
-void sbLibTable_register_method(hLibTable t, const char *method_name, usize method_name_length, sbLibMethod method) {
+void sbLibTable_register_method(hLibTable t, const char *method_name, usize method_name_length, sbLibMethod *method) {
hSymbol sym = sbSymbol_from_bytes(method_name, method_name_length);
sbLibTable_register_method_sym(t, sym, method);
}
/* --- */
-static void insert_method(hSymbol *keys, sbLibMethod *methods, usize capacity, hSymbol key, sbLibMethod method) {
+static void insert_method(hSymbol *keys, sbLibMethod *methods, usize capacity, hSymbol key, sbLibMethod *method) {
sbHashValue hash = sbHash_hash_bytes((const char*)&key, sizeof(hSymbol));
usize index = hash % capacity;
}
keys[index] = key;
- methods[index] = method;
+ methods[index] = *method;
}
static void insert_value(hSymbol *keys, hV *values, usize capacity, hSymbol key, hV *value) {
for (usize i = 0; i < t->capacity; i++) {
if (t->keys[i] != 0) {
- insert_method(new_keys, new_methods, new_capacity, t->keys[i], t->methods[i]);
+ insert_method(new_keys, new_methods, new_capacity, t->keys[i], &t->methods[i]);
}
}
void sbLibTable_deinitialize(hLibTable t);
-sbLibMethod sbLibTable_find_method(hLibTable t, hSymbol key);
+sbLibMethod *sbLibTable_find_method(hLibTable t, hSymbol key);
hV *sbLibTable_find_value(hLibTable t, hSymbol key);
-void sbLibTable_register_method(hLibTable t, const char *method_name, usize method_name_length, sbLibMethod method);
+void sbLibTable_register_method(hLibTable t, const char *method_name, usize method_name_length, sbLibMethod *method);
-void sbLibTable_register_method_sym(hLibTable t, hSymbol key, sbLibMethod method);
+void sbLibTable_register_method_sym(hLibTable t, hSymbol key, sbLibMethod *method);
void sbLibTable_register_value(hLibTable t, const char *value_name, usize value_name_length, hV *value);
if (v->type == IT_BUILTIN) {
call_builtin(vm, v);
} else if (v->type <= 0) {
- /* We need to figure out exception support or some such.
- * User error should not panic. */
- PANIC("attempt to call a non-function value");
+ /* intrinsic type: resolve a property on it */
+ push_stack(vm, v);
+ sbLib_resolve_property(vm);
} else {
call_block(vm, v->type, v->closure);
}