Category talk:Wren-psieve

From Rosetta Code

Source code (Wren)

/* Module "psieve.wren" */

/* The Primes class wraps the various functions in the 'primesieve' package for use by Wren.
   Although these methods will accept any integer value up to 2^64 without error
   it is only safe to use 'start' and 'stop' parameters and rely on return values < 2^53.
   Larger values should use the LPrimes class instead. There is no need to free memory
   used by 'primesieve' as this is dealt with automatically.
*/
foreign class Primes {
    // Returns a list of all primes between 'start' and 'stop' inclusive.
    foreign static between(start, stop)

    // Returns a list of all primes <= 'stop'.
    static upTo(stop) { between(2, stop) }

    // Returns a list of the first 'n' primes >= 'start'.
    foreign static firstNfrom(n, start)

    // Returns the first prime >= 'start'.
    foreign static firstFrom(start)

    // If n > 0, returns the 'n'th prime >  'start'.
    // If n = 0, returns the first prime >= 'start'.
    // If n < 0, returns the 'n'th prime <  'start.
    foreign static nthAfter(n, start)

    // If n > 0, returns the 'n'th prime <  'start'.
    // If n = 0, returns the first prime >= 'start'.
    // If n < 0, returns the 'n'th prime >  'start'.
    foreign static nthBefore(n, start)

    // Returns the number of prime groupings between start and stop inclusive.
    foreign static count (start, stop)  // singletons
    foreign static count2(start, stop)  // twins       : max - min = 2
    foreign static count3(start, stop)  // triplets    : max - min = 6
    foreign static count4(start, stop)  // quadruplets : max - min = 8
    foreign static count5(start, stop)  // quintuplets : max - min = 12
    foreign static count6(start, stop)  // sextuplets  : max - min = 16

    // Prints the prime groupings between start and stop inclusive to standard output.
    foreign static print (start, stop)
    foreign static print2(start, stop)
    foreign static print3(start, stop)
    foreign static print4(start, stop)
    foreign static print5(start, stop)
    foreign static print6(start, stop)

    // Returns a list of the prime factors of 'n' in order.
    foreign static factorize(n)

    // Returns the maximum safe value for 'stop'.
    static maxSafeStop { Num.maxSafeInteger }

    // Gets or sets the maximum sieve size in kilobytes. This must be between 16 and 8192
    // inclusive. Optimum is usually L1 or L2 cache size (per core).
    foreign static sieveSize
    foreign static sieveSize=(size)

    // Gets or sets the number of threads to be used in the 'count' and 'nth prime' methods.
    // By default all CPU cores are used.
    foreign static numThreads
    foreign static numThreads=(num)

    // Gets the PrimeSieve version number in the form 'i.j'.
    foreign static version

    // Gets the last error message.
    foreign static lastError

    // Creates and intializes a new PrimeSieve iterator.
    construct iter() {}

    // Gets the next prime returned by the iterator.
    // Returns 2^64 if the next prime > 2^64.
    foreign next

    // Gets the previous prime returned by the iterator.
    // Returns 0 if there is no previous prime.
    foreign prev

    // Resets the iterator to start.
    // Calling 'next' will return first prime > 'start'.
    // Calling 'prev' will return first prime < 'start'.
    // The 'stop' parameter is just a hint for optimimization purposes.
    foreign skipTo(start, stop)

    // As skipTo but 'next' or 'prev' will return the first prime including 'start'.
    jumpTo(start, stop) { skipTo((start-1).max(0), stop) }

    // As the above methods but using a default value for 'stop'.
    skipTo(start) { skipTo(start, Primes.maxSafeStop) }
    jumpTo(start) { jumpTo(start, Primes.maxSafeStop) }
}

/*  The LPrimes class contains similar functionality to the Primes class but is designed
    for use with primes above (or which straddle) the safe threshold of 2^53-1 but are less than
    2^64. As such, 'start' and 'end' are always expressed as strings as are any primes returned.
    Although these methods will accept (or may return) 'safe' values, the Primes class is faster
    for such values and should therefore be preferred.
*/
foreign class LPrimes {
    // Returns a list of all primes between 'start' and 'stop' inclusive.
    foreign static between(start, stop)

    // Returns a list of all primes <= 'stop'.
    static upTo(stop) { between("2", stop) }

    // Returns a list of the first 'n' primes >= 'start'.
    foreign static firstNfrom(n, start)

    // Returns the first prime >= 'start'.
    foreign static firstFrom(start)

    // If n > 0, returns the 'n'th prime >  'start'.
    // If n = 0, returns the first prime >= 'start'.
    // If n < 0, returns the 'n'th prime <  'start.
    foreign static nthAfter(n, start)

    // If n > 0, returns the 'n'th prime <  'start'.
    // If n = 0, returns the first prime >= 'start'.
    // If n < 0, returns the 'n'th prime >  'start'.
    foreign static nthBefore(n, start)

    // Returns the number of prime groupings between start and stop inclusive.
    foreign static count (start, stop)  // singletons
    foreign static count2(start, stop)  // twins       : max - min = 2
    foreign static count3(start, stop)  // triplets    : max - min = 6
    foreign static count4(start, stop)  // quadruplets : max - min = 8
    foreign static count5(start, stop)  // quintuplets : max - min = 12
    foreign static count6(start, stop)  // sextuplets  : max - min = 16

    // Prints the prime groupings between start and stop inclusive to standard output.
    foreign static print (start, stop)
    foreign static print2(start, stop)
    foreign static print3(start, stop)
    foreign static print4(start, stop)
    foreign static print5(start, stop)
    foreign static print6(start, stop)

    // Returns a list of the prime factors of 'n' in order.
    foreign static factorize(n)

    // Returns the maximum value for 'stop'.
    static maxStop { "18446744073709551615" }

    // Gets or sets the maximum sieve size in kilobytes. This must be between 16 and 8192
    // inclusive. Optimum is usually L1 or L2 cache size (per core).
    static sieveSize { Primes.sieveSize }
    static sieveSize=(size) {
        Primes.sieveSize = size
    }

    // Gets or sets the number of threads to be used in the 'count' and 'nth prime' methods.
    // By default all CPU cores are used.
    static numThreads { Primes.numThreads }
    static numThreads=(num) {
        Primes.numThreads = num
    }

    // Gets the PrimeSieve version number in the form 'i.j'.
    static version { Primes.version }

    // Gets the last error message.
    static lastError { Primes.lastError }

    // Creates and intializes a new PrimeSieve iterator.
    construct iter() {}

    // Gets the next prime returned by the iterator.
    // Returns 2^64 if the next prime > 2^64.
    foreign next

    // Gets the previous prime returned by the iterator.
    // Returns 0 if there is no previous prime.
    foreign prev

    // Resets the iterator to start.
    // Calling 'next' will return first prime > 'start'.
    // Calling 'prev' will return first prime < 'start'.
    // The 'stop' parameter is just a hint for optimimization purposes.
    foreign skipTo(start, stop)

    // As skipTo but 'next' or 'prev' will return the first prime including 'start'.
    jumpTo(start, stop) {
        var start2 = (Num.fromString(start) - 1).max(0)
        skipTo(start2.toString, stop)
    }

    // As the above methods but using a default value for 'stop'.
    skipTo(start) { skipTo(start, LPrimes.maxStop) }
    jumpTo(start) { jumpTo(start, LPrimes.maxStop) }
}

Source code (C)

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <errno.h>
#include <primesieve.h>
#include "wren.h"

#define psi primesieve_iterator

/* Primes functions */

void Primes_iterator(WrenVM* vm) {
    psi *pit = (psi *)wrenSetSlotNewForeign(vm, 0, 0, sizeof(psi));
    primesieve_init(pit);
}

void Primes_free(void* data) {
    psi *pit = (psi *)data;
    primesieve_free_iterator(pit);
}

void Primes_next(WrenVM* vm) {
    psi *pit = (psi *)wrenGetSlotForeign(vm, 0);
    uint64_t prime = primesieve_next_prime(pit);
    wrenSetSlotDouble(vm, 0, (double)prime);
}

void Primes_prev(WrenVM* vm) {
    psi *pit = (psi *)wrenGetSlotForeign(vm, 0);
    uint64_t prime = primesieve_prev_prime(pit);
    wrenSetSlotDouble(vm, 0, (double)prime);
}

void Primes_skipTo(WrenVM* vm) {
    psi *pit = (psi *)wrenGetSlotForeign(vm, 0);
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    primesieve_skipto(pit, start, stop);
}

void Primes_between(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    size_t size;
    uint64_t *primes = (uint64_t *)primesieve_generate_primes(start, stop, &size, UINT64_PRIMES);
    int i;
    wrenEnsureSlots(vm, 2);
    wrenSetSlotNewList(vm, 0);
    for (i = 0; i < size; ++i) {
        wrenSetSlotDouble(vm, 1, (double)primes[i]);
        wrenInsertInList(vm, 0, i, 1);
    }
    primesieve_free(primes);
}

void Primes_firstNfrom(WrenVM* vm) {
    uint64_t n = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 2);
    uint64_t *primes = (uint64_t *)primesieve_generate_n_primes(n, start, UINT64_PRIMES);
    int i;
    wrenEnsureSlots(vm, 2);
    wrenSetSlotNewList(vm, 0);
    for (i = 0; i < n; ++i) {
        wrenSetSlotDouble(vm, 1, (double)primes[i]);
        wrenInsertInList(vm, 0, i, 1);
    }
    primesieve_free(primes);
}

void Primes_firstFrom(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t prime = primesieve_nth_prime(0, start);
    wrenSetSlotDouble(vm, 0, (double)prime);
}

void Primes_nthAfter(WrenVM* vm) {
    int64_t n = (int64_t)wrenGetSlotDouble(vm, 1);
    uint64_t after = (uint64_t)wrenGetSlotDouble(vm, 2);
    uint64_t prime = primesieve_nth_prime(n, after);
    wrenSetSlotDouble(vm, 0, (double)prime);
}

void Primes_nthBefore(WrenVM* vm) {
    int64_t n = (int64_t)wrenGetSlotDouble(vm, 1);
    uint64_t before = (uint64_t)wrenGetSlotDouble(vm, 2);
    uint64_t prime = primesieve_nth_prime(-n, before);
    wrenSetSlotDouble(vm, 0, (double)prime);
}

void Primes_count(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    uint64_t count = primesieve_count_primes(start, stop);
    wrenSetSlotDouble(vm, 0, (double)count);
}

void Primes_count2(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    uint64_t count = primesieve_count_twins(start, stop);
    wrenSetSlotDouble(vm, 0, (double)count);
}

void Primes_count3(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    uint64_t count = primesieve_count_triplets(start, stop);
    wrenSetSlotDouble(vm, 0, (double)count);
}

void Primes_count4(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    uint64_t count = primesieve_count_quadruplets(start, stop);
    wrenSetSlotDouble(vm, 0, (double)count);
}

void Primes_count5(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    uint64_t count = primesieve_count_quintuplets(start, stop);
    wrenSetSlotDouble(vm, 0, (double)count);
}

void Primes_count6(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    uint64_t count = primesieve_count_sextuplets(start, stop);
    wrenSetSlotDouble(vm, 0, (double)count);
}

void Primes_print(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    primesieve_print_primes(start, stop);
}

void Primes_print2(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    primesieve_print_twins(start, stop);
}

void Primes_print3(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    primesieve_print_triplets(start, stop);
}

void Primes_print4(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    primesieve_print_quadruplets(start, stop);
}

void Primes_print5(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    primesieve_print_quintuplets(start, stop);
}

void Primes_print6(WrenVM* vm) {
    uint64_t start = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t stop  = (uint64_t)wrenGetSlotDouble(vm, 2);
    primesieve_print_sextuplets(start, stop);
}

void Primes_factorize(WrenVM* vm) {
    uint64_t n = (uint64_t)wrenGetSlotDouble(vm, 1);
    wrenEnsureSlots(vm, 2);
    wrenSetSlotNewList(vm, 0);
    if (n < 2) return;
    primesieve_iterator it;
    primesieve_init(&it);
    uint64_t prime;
    int i = 0;
    while (1) {
        prime = primesieve_next_prime(&it);
        if (prime * prime <= n) {
            while (!(n%prime)) {
                wrenSetSlotDouble(vm, 1, (double)prime);
                wrenInsertInList(vm, 0, i++, 1);
                n /= prime;
            }
        } else {
            break;
        }
    }
    if (n > 1) {
        wrenSetSlotDouble(vm, 1, (double)n);
        wrenInsertInList(vm, 0, i, 1);
    }
    primesieve_free_iterator(&it);
}

void Primes_sieveSize(WrenVM* vm) {
    int size = primesieve_get_sieve_size();
    wrenSetSlotDouble(vm, 0, (double)size);  
}

void Primes_set_sieveSize(WrenVM* vm) {
    int size = (int)wrenGetSlotDouble(vm, 1);
    primesieve_set_sieve_size(size);
}

void Primes_numThreads(WrenVM* vm) {
    int num = primesieve_get_num_threads();
    wrenSetSlotDouble(vm, 0, (double)num);  
}

void Primes_set_numThreads(WrenVM* vm) {
    int num = (int)wrenGetSlotDouble(vm, 1);
    primesieve_set_num_threads(num);
}

void Primes_version(WrenVM* vm) {
    wrenSetSlotString(vm, 0, primesieve_version());
}

void Primes_lastError(WrenVM* vm) {
    wrenSetSlotString(vm, 0, strerror(errno));
}

/* LPrimes functions */

void LPrimes_next(WrenVM* vm) {
    psi *pit = (psi *)wrenGetSlotForeign(vm, 0);
    uint64_t prime = primesieve_next_prime(pit);
    char s[21];
    sprintf(s, "%"PRIu64, prime);
    wrenSetSlotString(vm, 0, s);
}

void LPrimes_prev(WrenVM* vm) {
    psi *pit = (psi *)wrenGetSlotForeign(vm, 0);
    uint64_t prime = primesieve_prev_prime(pit);
    char s[21];
    sprintf(s, "%"PRIu64, prime);
    wrenSetSlotString(vm, 0, s);
}

void LPrimes_skipTo(WrenVM* vm) {
    psi *pit = (psi *)wrenGetSlotForeign(vm, 0);
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10); 
    primesieve_skipto(pit, start, stop);
}

void LPrimes_between(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    size_t size;
    uint64_t *primes = (uint64_t *)primesieve_generate_primes(start, stop, &size, UINT64_PRIMES);
    int i;
    char s[21];
    wrenEnsureSlots(vm, 2);
    wrenSetSlotNewList(vm, 0);
    for (i = 0; i < size; ++i) {
        sprintf(s, "%"PRIu64, primes[i]);
        wrenSetSlotString(vm, 1, s);
        wrenInsertInList(vm, 0, i, 1);
    }
    primesieve_free(primes);
}

void LPrimes_firstNfrom(WrenVM* vm) {
    uint64_t n = (uint64_t)wrenGetSlotDouble(vm, 1);
    uint64_t start = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    uint64_t *primes = (uint64_t *)primesieve_generate_n_primes(n, start, UINT64_PRIMES);
    int i;
    char s[21];
    wrenEnsureSlots(vm, 2);
    wrenSetSlotNewList(vm, 0);
    for (i = 0; i < n; ++i) {
        sprintf(s, "%"PRIu64, primes[i]);
        wrenSetSlotString(vm, 1, s);
        wrenInsertInList(vm, 0, i, 1);
    }
    primesieve_free(primes);
}

void LPrimes_firstFrom(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t prime = primesieve_nth_prime(0, start);
    char s[21];
    sprintf(s, "%"PRIu64, prime);
    wrenSetSlotString(vm, 0, s);
}

void LPrimes_nthAfter(WrenVM* vm) {
    int64_t n = (int64_t)wrenGetSlotDouble(vm, 1);
    uint64_t after = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    uint64_t prime = primesieve_nth_prime(n, after);
    char s[21];
    sprintf(s, "%"PRIu64, prime);
    wrenSetSlotString(vm, 0, s);
}

void LPrimes_nthBefore(WrenVM* vm) {
    int64_t n = (int64_t)wrenGetSlotDouble(vm, 1);
    uint64_t before = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    uint64_t prime = primesieve_nth_prime(-n, before);
    char s[21];
    sprintf(s, "%"PRIu64, prime);
    wrenSetSlotString(vm, 0, s);
}

void LPrimes_count(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    uint64_t count = primesieve_count_primes(start, stop);
    char s[21];
    sprintf(s, "%"PRIu64, count);
    wrenSetSlotString(vm, 0, s);
}

void LPrimes_count2(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    uint64_t count = primesieve_count_twins(start, stop);
    char s[21];
    sprintf(s, "%"PRIu64, count);
    wrenSetSlotString(vm, 0, s);
}

void LPrimes_count3(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    uint64_t count = primesieve_count_triplets(start, stop);
    char s[21];
    sprintf(s, "%"PRIu64, count);
    wrenSetSlotString(vm, 0, s);
}

void LPrimes_count4(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    uint64_t count = primesieve_count_quadruplets(start, stop);
    char s[21];
    sprintf(s, "%"PRIu64, count);
    wrenSetSlotString(vm, 0, s);
}

void LPrimes_count5(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    uint64_t count = primesieve_count_quintuplets(start, stop);
    char s[21];
    sprintf(s, "%"PRIu64, count);    
    wrenSetSlotString(vm, 0, s);
}

void LPrimes_count6(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    uint64_t count = primesieve_count_sextuplets(start, stop);
    char s[21];
    sprintf(s, "%"PRIu64, count);
    wrenSetSlotString(vm, 0, s);
}

void LPrimes_print(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    primesieve_print_primes(start, stop);
}

void LPrimes_print2(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    primesieve_print_twins(start, stop);
}

void LPrimes_print3(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    primesieve_print_triplets(start, stop);
}

void LPrimes_print4(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    primesieve_print_quadruplets(start, stop);
}

void LPrimes_print5(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    primesieve_print_quintuplets(start, stop);
}

void LPrimes_print6(WrenVM* vm) {
    uint64_t start = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    uint64_t stop  = strtoull(wrenGetSlotString(vm, 2), NULL, 10);
    primesieve_print_sextuplets(start, stop);
}

void LPrimes_factorize(WrenVM* vm) {
    uint64_t n = strtoull(wrenGetSlotString(vm, 1), NULL, 10);
    wrenEnsureSlots(vm, 2);
    wrenSetSlotNewList(vm, 0);
    if (n < 2) return;
    primesieve_iterator it;
    primesieve_init(&it);
    uint64_t prime;
    char s[21];
    int i = 0;
    while (1) {
        prime = primesieve_next_prime(&it);
        if (prime * prime <= n) {
            while (!(n%prime)) {
                sprintf(s, "%"PRIu64, prime);
                wrenSetSlotString(vm, 1, s);
                wrenInsertInList(vm, 0, i++, 1);
                n /= prime;
            }
        } else {
            break;
        }
    }
    if (n > 1) {
        sprintf(s, "%"PRIu64, n);
        wrenSetSlotString(vm, 1, s);
        wrenInsertInList(vm, 0, i, 1);
    }
    primesieve_free_iterator(&it);
}

WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
    WrenForeignClassMethods methods;
    methods.allocate = NULL;
    methods.finalize = NULL;
    if (strcmp(module, "./psieve") == 0) {
        if (strcmp(className, "Primes") == 0) {
            methods.allocate = Primes_iterator;
            methods.finalize = Primes_free;
        } else if (strcmp(className, "LPrimes") == 0) {
            methods.allocate = Primes_iterator;
            methods.finalize = Primes_free;
        }
    }
    return methods;
}

WrenForeignMethodFn bindForeignMethod(
    WrenVM* vm,
    const char* module,
    const char* className,
    bool isStatic,
    const char* signature) {
    if (strcmp(module, "./psieve") == 0) {
        if (strcmp(className, "Primes") == 0) {
            if( isStatic && strcmp(signature, "between(_,_)") == 0)    return Primes_between;
            if( isStatic && strcmp(signature, "firstNfrom(_,_)") == 0) return Primes_firstNfrom;
            if( isStatic && strcmp(signature, "firstFrom(_)") == 0)    return Primes_firstFrom;
            if( isStatic && strcmp(signature, "nthAfter(_,_)") == 0)   return Primes_nthAfter;
            if( isStatic && strcmp(signature, "nthBefore(_,_)") == 0)  return Primes_nthBefore;
            if( isStatic && strcmp(signature, "count(_,_)")  == 0)     return Primes_count;
            if( isStatic && strcmp(signature, "count2(_,_)") == 0)     return Primes_count2;
            if( isStatic && strcmp(signature, "count3(_,_)") == 0)     return Primes_count3;
            if( isStatic && strcmp(signature, "count4(_,_)") == 0)     return Primes_count4;
            if( isStatic && strcmp(signature, "count5(_,_)") == 0)     return Primes_count5;
            if( isStatic && strcmp(signature, "count6(_,_)") == 0)     return Primes_count6;
            if( isStatic && strcmp(signature, "print(_,_)")  == 0)     return Primes_print;
            if( isStatic && strcmp(signature, "print2(_,_)") == 0)     return Primes_print2;
            if( isStatic && strcmp(signature, "print3(_,_)") == 0)     return Primes_print3;
            if( isStatic && strcmp(signature, "print4(_,_)") == 0)     return Primes_print4;
            if( isStatic && strcmp(signature, "print5(_,_)") == 0)     return Primes_print5;
            if( isStatic && strcmp(signature, "print6(_,_)") == 0)     return Primes_print6;
            if( isStatic && strcmp(signature, "factorize(_)") == 0)    return Primes_factorize;
            if( isStatic && strcmp(signature, "sieveSize") == 0)       return Primes_sieveSize;
            if( isStatic && strcmp(signature, "sieveSize=(_)") == 0)   return Primes_set_sieveSize; 
            if( isStatic && strcmp(signature, "numThreads") == 0)      return Primes_numThreads;
            if( isStatic && strcmp(signature, "numThreads=(_)") == 0)  return Primes_set_numThreads;
            if( isStatic && strcmp(signature, "version") == 0)         return Primes_version;
            if( isStatic && strcmp(signature, "lastError") == 0)       return Primes_lastError;

            if(!isStatic && strcmp(signature, "next") == 0)            return Primes_next;
            if(!isStatic && strcmp(signature, "prev") == 0)            return Primes_prev;
            if(!isStatic && strcmp(signature, "skipTo(_,_)") == 0)     return Primes_skipTo;
        } else if (strcmp(className, "LPrimes") == 0) {
            if( isStatic && strcmp(signature, "between(_,_)") == 0)    return LPrimes_between;
            if( isStatic && strcmp(signature, "firstNfrom(_,_)") == 0) return LPrimes_firstNfrom;
            if( isStatic && strcmp(signature, "firstFrom(_)") == 0)    return LPrimes_firstFrom;
            if( isStatic && strcmp(signature, "nthAfter(_,_)") == 0)   return LPrimes_nthAfter;
            if( isStatic && strcmp(signature, "nthBefore(_,_)") == 0)  return LPrimes_nthBefore;
            if( isStatic && strcmp(signature, "count(_,_)")  == 0)     return LPrimes_count;
            if( isStatic && strcmp(signature, "count2(_,_)") == 0)     return LPrimes_count2;
            if( isStatic && strcmp(signature, "count3(_,_)") == 0)     return LPrimes_count3;
            if( isStatic && strcmp(signature, "count4(_,_)") == 0)     return LPrimes_count4;
            if( isStatic && strcmp(signature, "count5(_,_)") == 0)     return LPrimes_count5;
            if( isStatic && strcmp(signature, "count6(_,_)") == 0)     return LPrimes_count6;
            if( isStatic && strcmp(signature, "print(_,_)")  == 0)     return LPrimes_print;
            if( isStatic && strcmp(signature, "print2(_,_)") == 0)     return LPrimes_print2;
            if( isStatic && strcmp(signature, "print3(_,_)") == 0)     return LPrimes_print3;
            if( isStatic && strcmp(signature, "print4(_,_)") == 0)     return LPrimes_print4;
            if( isStatic && strcmp(signature, "print5(_,_)") == 0)     return LPrimes_print5;
            if( isStatic && strcmp(signature, "print6(_,_)") == 0)     return LPrimes_print6;
            if( isStatic && strcmp(signature, "factorize(_)") == 0)    return LPrimes_factorize;

            if(!isStatic && strcmp(signature, "next") == 0)            return LPrimes_next;
            if(!isStatic && strcmp(signature, "prev") == 0)            return LPrimes_prev;
            if(!isStatic && strcmp(signature, "skipTo(_,_)") == 0)     return LPrimes_skipTo;
        }
    }
    return NULL;
}

static void writeFn(WrenVM* vm, const char* text) {
    printf("%s", text);
}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
    switch (errorType) {
        case WREN_ERROR_COMPILE:
            printf("[%s line %d] [Error] %s\n", module, line, msg);
            break;
        case WREN_ERROR_STACK_TRACE:
            printf("[%s line %d] in %s\n", module, line, msg);
            break;
        case WREN_ERROR_RUNTIME:
            printf("[Runtime Error] %s\n", msg);
            break;
    }
}

char *readFile(const char *fileName) {
    FILE *f = fopen(fileName, "r");
    fseek(f, 0, SEEK_END);
    long fsize = ftell(f);
    rewind(f);
    char *script = malloc(fsize + 1);
    size_t ret = fread(script, 1, fsize, f);
    if (ret != fsize) printf("Error reading %s\n", fileName);
    fclose(f);
    script[fsize] = 0;
    return script;
}

static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) {
    if( result.source) free((void*)result.source);
}

WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) {
    WrenLoadModuleResult result = {0};
    if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
        result.onComplete = loadModuleComplete;
        char fullName[strlen(name) + 6];
        strcpy(fullName, name);
        strcat(fullName, ".wren");
        result.source = readFile(fullName);
    }
    return result;
}

int main(int argc, char **argv) {
    if (argc != 2) {
        printf("Please pass the name of the Wren file to be executed.\n");
        return 1;
    }
    WrenConfiguration config;
    wrenInitConfiguration(&config);
    config.writeFn = &writeFn;
    config.errorFn = &errorFn;
    config.bindForeignClassFn = &bindForeignClass;
    config.bindForeignMethodFn = &bindForeignMethod;
    config.loadModuleFn = &loadModule;
    WrenVM* vm = wrenNewVM(&config);
    const char* module = "main";
    const char* fileName = argv[1];
    char *script = readFile(fileName);
    WrenInterpretResult result = wrenInterpret(vm, module, script);
    switch (result) {
        case WREN_RESULT_COMPILE_ERROR:
            printf("Compile Error!\n");
            break;
        case WREN_RESULT_RUNTIME_ERROR:
            printf("Runtime Error!\n");
            break;
        case WREN_RESULT_SUCCESS:
            break;
    }
    wrenFreeVM(vm);
    free(script);
    return 0;
}