LValue *l_func_list_get(LValue *args, LClosure *closure) { LValue *list = l_list_get(args, 0); LValue *index = l_list_get(args, 1); l_assert_is(list, L_LIST_TYPE, L_ERR_MISSING_LIST, closure); l_assert_is(index, L_NUM_TYPE, L_ERR_MISSING_INDEX, closure); LValue *value = l_list_get(list, mpz_get_si(index->core.num)); if(value == NULL) value = l_value_new(L_NIL_TYPE, closure); return value; }
LValue *l_func_str_add(LValue *args, LClosure *closure) { LValue *v1 = l_list_get(args, 0); LValue *v2 = l_list_get(args, 1); LValue *value = l_value_new(L_STR_TYPE, closure); value->core.str = make_stringbuf(""); concat_stringbuf(value->core.str, v1->core.str->str); concat_stringbuf(value->core.str, v2->core.str->str); return value; }
LValue *l_func_list_add(LValue *args, LClosure *closure) { LValue *l1 = l_list_get(args, 0); LValue *l2 = l_list_get(args, 1); LValue *value = l_value_new(L_LIST_TYPE, closure); value->core.list = subvector(l1->core.list, 0, l1->core.list->length); int i; for(i=0; i<l2->core.list->length; i++) { vector_add(value->core.list, l2->core.list->data[i], l2->core.list->sizes[i]); } return value; }
LValue *l_func_add(LValue *args, LClosure *closure) { LValue *v1 = l_list_get(args, 0); LValue *v2 = l_list_get(args, 1); if(v1->type == L_LIST_TYPE && v2->type == L_LIST_TYPE) { return l_func_list_add(args, closure); } else if(v1->type == L_NUM_TYPE && v2->type == L_NUM_TYPE) { return l_func_num_add(args, closure); } else if(v1->type == L_STR_TYPE && v2->type == L_STR_TYPE) { return l_func_str_add(args, closure); } else { return l_value_new(L_NIL_TYPE, closure); } }
bool l_list_eq(LValue *l1, LValue *l2) { if(l1->core.list->length == 0 && l2->core.list->length == 0) { return true; } else if(l1->core.list->length == l2->core.list->length) { int i; for(i=0; i<l1->core.list->length; i++) { if(!l_eq(l_list_get(l1, i), l_list_get(l2, i))) { return false; } } return true; } return false; }
LValue *l_func_count(LValue *args, LClosure *closure) { LValue *list = l_list_get(args, 0); l_assert_is(list, L_LIST_TYPE, L_ERR_MISSING_LIST, closure); LValue *value = l_value_new(L_NUM_TYPE, closure); mpz_init_set_ui(value->core.num, list->core.list->length); return value; }
// FIXME this does not work as expected/desired for a multi-character delimiter // since it uses strtok under the hood LValue *l_func_str_split(LValue *args, LClosure *closure) { LValue *string = l_list_get(args, 0); LValue *delim = l_list_get(args, 1); l_assert_is(string, L_STR_TYPE, L_ERR_MISSING_STR, closure); l_assert_is(delim, L_STR_TYPE, L_ERR_MISSING_STR, closure); int i, size; char **strings = str_split(string->core.str->str, delim->core.str->str, &size); LValue *value = l_value_new(L_LIST_TYPE, closure); value->core.list = create_vector(); LValue *s; for(i=0; i<size; i++) { s = l_value_new(L_STR_TYPE, closure); s->core.str = make_stringbuf(strings[i]); vector_add(value->core.list, s, sizeof(s)); } return value; }
LValue *l_func_rest(LValue *args, LClosure *closure) { LValue *list = l_list_get(args, 0); l_assert_is(list, L_LIST_TYPE, L_ERR_MISSING_LIST, closure); LValue *value = l_value_new(L_LIST_TYPE, closure); if(list->core.list->length > 1) { value->core.list = subvector(list->core.list, 1, list->core.list->length); } else { value->core.list = create_vector(); } return value; }
LValue *l_func_str(LValue *args, LClosure *closure) { LValue *value = l_value_new(L_STR_TYPE, closure); value->core.str = make_stringbuf(""); char *s; int i; for(i=0; i<args->core.list->length; i++) { s = l_str(l_list_get(args, i)); concat_stringbuf(value->core.str, s); } return value; }
LValue *l_func_type(LValue *args, LClosure *closure) { LValue *value = l_list_get(args, 0); char *types[9] = { "nil", "boolean", "boolean", "error", "number", "string", "variable", "list", "function" }; LValue *repr = l_value_new(L_STR_TYPE, closure); repr->core.str = make_stringbuf(types[value->type]); return repr; }
LValue *l_func_require(LValue *args, LClosure *closure) { if(l_loaded_libs == NULL) l_loaded_libs = create_hashmap(); int i; char *p; LValue *path; closure = l_closure_root(closure); for(i=0; i<args->core.list->length; i++) { path = l_list_get(args, i); l_assert_is(path, L_STR_TYPE, "Path for require must be a string.", closure); p = path->core.str->str; // TODO search in cwd, then in lib/extra if(!hashmap_get(l_loaded_libs, p)) { l_eval_path(p, closure); hashmap_put(l_loaded_libs, p, p, sizeof(p)); } } return args; }
// returns a c string representation for the given LValue // (be sure to free the string when you're done) char *l_str(LValue *value) { char *str; stringbuf *str2; switch(value->type) { case L_NUM_TYPE: str = mpz_get_str(NULL, 10, value->core.num); break; case L_STR_TYPE: str = GC_MALLOC(sizeof(char) * (value->core.str->length + 1)); strcpy(str, value->core.str->str); break; case L_LIST_TYPE: str2 = make_stringbuf("["); char *s; int i, len = value->core.list->length; for(i=0; i<len; i++) { s = l_str(l_list_get(value, i)); concat_stringbuf(str2, s); if(i<len-1) buffer_concat(str2, " "); } buffer_concat(str2, "]"); str = GC_MALLOC(sizeof(char) * (str2->length + 1)); strcpy(str, str2->str); destroy_buffer(str2); break; case L_TRUE_TYPE: str = GC_MALLOC(sizeof(char) * 5); strcpy(str, "true"); break; case L_FALSE_TYPE: str = GC_MALLOC(sizeof(char) * 6); strcpy(str, "false"); break; case L_NIL_TYPE: str = GC_MALLOC(sizeof(char) * 4); strcpy(str, "nil"); break; default: str = GC_MALLOC(sizeof(char) * 1); strcpy(str, ""); } return str; }
char *l_inspect_to_str(LValue *value, char *buf, int bufLen) { char *repr; switch(value->type) { case L_ERR_TYPE: snprintf(buf, bufLen-1, "<Err: %s>", value->core.str->str); break; case L_NUM_TYPE: repr = l_str(value); snprintf(buf, bufLen-1, "<Num: %s>", repr); break; case L_STR_TYPE: snprintf(buf, bufLen-1, "<Str: %s>", value->core.str->str); break; case L_LIST_TYPE: if(value->core.list->length > 0) { repr = l_str(l_list_get(value, 0)); snprintf(buf, bufLen-1, "<List with %d item(s), first=%s>", (int)value->core.list->length, repr); } else { snprintf(buf, bufLen-1, "<List with 0 item(s)>"); } break; case L_FUNC_TYPE: if(value->core.func.ptr != NULL) { snprintf(buf, bufLen-1, "<Func Ptr with %d arg(s) and %d expr(s)>", value->core.func.argc, value->core.func.exprc); } else { snprintf(buf, bufLen-1, "<Func with %d arg(s) and %d expr(s)>", value->core.func.argc, value->core.func.exprc); } break; case L_TRUE_TYPE: snprintf(buf, bufLen-1, "<true>"); break; case L_FALSE_TYPE: snprintf(buf, bufLen-1, "<false>"); break; case L_NIL_TYPE: snprintf(buf, bufLen-1, "<nil>"); break; default: snprintf(buf, bufLen-1, "unable to inspect element type %d", value->type); } return buf; }