<commit_before>#include <slash.h>
#include <string.h>

static sl_string_t*
resolve_require_path(sl_vm_t* vm, char* path)
{
    if(sl_abs_file_exists(path)) {
        return sl_cstring(vm, path);
    }
    SLVAL include_dirs = sl_class_get_const(vm, vm->lib.Object, "INC");
    sl_expect(vm, include_dirs, vm->lib.Array);
    size_t len = sl_get_int(sl_array_length(vm, include_dirs));
    SLVAL pathv = sl_make_cstring(vm, path);
    for(size_t i = 0; i < len; i++) {
        sl_string_t* spath = (sl_string_t*)sl_get_ptr(
            sl_string_concat(vm, sl_array_get(vm, include_dirs, i),
                sl_string_concat(vm, sl_make_cstring(vm, "/"), pathv)));
        if(memchr(spath->buff, 0, spath->buff_len)) {
            continue;
        }
        if(sl_file_exists(vm, (char*)spath->buff)) {
            return spath;
        }
    }
    return NULL;
}

SLVAL
sl_require(sl_vm_t* vm, SLVAL self, SLVAL file)
{
    sl_expect(vm, file, vm->lib.String);
    char* file_cstr = sl_to_cstr(vm, file);
    sl_string_t* resolved = resolve_require_path(vm, file_cstr);
    
    if(resolved) {
        SLVAL retn;
        if(st_lookup(vm->required, (st_data_t)resolved, (st_data_t*)&retn)) {
            return retn;
        }
        st_insert(vm->required, (st_data_t)resolved, (st_data_t)sl_get_ptr(vm->lib.nil));
        retn = sl_do_file(vm, (uint8_t*)sl_to_cstr(vm, sl_make_ptr((sl_object_t*)resolved)));
        st_insert(vm->required, (st_data_t)resolved, (st_data_t)sl_get_ptr(retn));
        return retn;
    }
    
    SLVAL err = sl_make_cstring(vm, "Could not load '");
    err = sl_string_concat(vm, err, file);
    err = sl_string_concat(vm, err, sl_make_cstring(vm, "'"));
    sl_throw(vm, sl_make_error2(vm, vm->lib.Error, err));

    (void)self;<commit_msg>try a bunch of suffixes when resolving require path<commit_after>#include <slash.h>
#include <string.h>

static char*
suffixes[] = { "", ".sl" };

static sl_string_t*
resolve_require_path(sl_vm_t* vm, char* path)
{
    if(sl_abs_file_exists(path)) {
        return sl_cstring(vm, path);
    }
    SLVAL include_dirs = sl_class_get_const(vm, vm->lib.Object, "INC");
    sl_expect(vm, include_dirs, vm->lib.Array);
    size_t len = sl_get_int(sl_array_length(vm, include_dirs));
    SLVAL pathv = sl_make_cstring(vm, path);
    for(size_t inc_i = 0; inc_i < len; inc_i++) {
        for(size_t suff_i = 0; suff_i < sizeof(suffixes) / sizeof(*suffixes); suff_i++) {
            
            SLVAL full_path = sl_array_get(vm, include_dirs, inc_i);
            full_path = sl_string_concat(vm, full_path, sl_make_cstring(vm, "/"));
            full_path = sl_string_concat(vm, full_path, pathv);
            full_path = sl_string_concat(vm, full_path, sl_make_cstring(vm, suffixes[suff_i]));
            
            sl_string_t* spath = (sl_string_t*)sl_get_ptr(full_path);
            
            if(memchr(spath->buff, 0, spath->buff_len)) {
                continue;
            }
            
            if(sl_file_exists(vm, (char*)spath->buff)) {
                return spath;
            }
        }
    }
    return NULL;
}

SLVAL
sl_require(sl_vm_t* vm, SLVAL self, SLVAL file)
{
    sl_expect(vm, file, vm->lib.String);
    char* file_cstr = sl_to_cstr(vm, file);
    sl_string_t* resolved = resolve_require_path(vm, file_cstr);
    
    if(resolved) {
        SLVAL retn;
        if(st_lookup(vm->required, (st_data_t)resolved, (st_data_t*)&retn)) {
            return retn;
        }
        st_insert(vm->required, (st_data_t)resolved, (st_data_t)sl_get_ptr(vm->lib.nil));
        retn = sl_do_file(vm, (uint8_t*)sl_to_cstr(vm, sl_make_ptr((sl_object_t*)resolved)));
        st_insert(vm->required, (st_data_t)resolved, (st_data_t)sl_get_ptr(retn));
        return retn;
    }
    
    SLVAL err = sl_make_cstring(vm, "Could not load '");
    err = sl_string_concat(vm, err, file);
    err = sl_string_concat(vm, err, sl_make_cstring(vm, "'"));
    sl_throw(vm, sl_make_error2(vm, vm->lib.Error, err));

    (void)self;
{'fraction_non_alphanumeric': 0.1397903145282077, 'fraction_numerical': 0.0022466300549176237, 'mean_word_length': 3.011011011011011, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2310670', 'n_tokens_mistral': 1553, 'n_tokens_neox': 1535, 'n_words': 255}