예제 #1
0
O_TYPE mpsl_exec_i(O_ARGS)
/* Executes one MPSL instruction in the MPSL virtual machine. Called
   from mpsl_exec_p() (which holds the flow control status variable) */
{
    mpdm_t ret = NULL;

    mpdm_ref(c);
    mpdm_ref(a);
    mpdm_ref(l);

    /* if aborted or NULL, do nothing */
    if (!mpsl_abort && c != NULL) {
        /* gets the opcode and calls it */
        ret = op_table[mpdm_ival(C0)].func(c, a, l, f);

        if (mpsl_trap_func != NULL) {
            mpdm_t f = mpsl_trap_func;

            mpdm_ref(ret);

            mpsl_trap_func = NULL;
            mpdm_exec_3(f, c, a, ret, l);
            mpsl_trap_func = f;

            mpdm_unrefnd(ret);
        }
    }

    mpdm_unref(l);
    mpdm_unref(a);
    mpdm_unref(c);

    return ret;
}
예제 #2
0
/**
 * mpsl_set_symbol - Sets value to a symbol.
 * @s: symbol name
 * @v: value
 * @l: local symbol table
 *
 * Assigns the value @v to the @s symbol. If the value exists as
 * a local symbol, it's assigned to it; otherwise, it's set as a global
 * symbol (and created if it does not exist).
 */
mpdm_t mpsl_set_symbol(mpdm_t s, mpdm_t v, mpdm_t l)
{
    int n;
    mpdm_t r, p, w;

    mpdm_ref(l);
    mpdm_ref(s);
    mpdm_ref(v);

    /* get the local or global symbol table */
    if ((r = find_local_symtbl(s, l)) == NULL)
        r = mpdm_root();

    /* splits the path, if needed */
    if (MPDM_IS_ARRAY(s))
        p = mpdm_ref(s);
    else
        p = mpdm_ref(mpdm_split_s(s, L"."));

    w = r;

    for (n = 0; w != NULL && n < mpdm_size(p); n++) {
        /* is executable? run it and take its output */
        while (MPDM_IS_EXEC(w))
            w = mpdm_exec(w, NULL, NULL);

        /* last component? */
        if (n == mpdm_size(p) - 1) {
            /* yes; do the setting */
            if (MPDM_IS_HASH(w))
                w = mpdm_hset(w, mpdm_aget(p, n), v);
            else
            if (MPDM_IS_ARRAY(w))
                w = mpdm_aset(w, v, mpdm_ival(mpdm_aget(p, n)));
        }
        else {
            if (MPDM_IS_HASH(w))
                w = mpdm_hget(w, mpdm_aget(p, n));
            else
            if (MPDM_IS_ARRAY(w))
                w = mpdm_aget(w, mpdm_ival(mpdm_aget(p, n)));
            else {
                mpdm_void(w);
                w = NULL;
            }
        }
    }

    mpdm_unref(p);
    mpdm_unref(v);
    mpdm_unref(s);
    mpdm_unref(l);

    return w;
}
예제 #3
0
파일: mpdm_o.c 프로젝트: angelortega/mpdm
/**
 * mpdm_set_o - Sets a value in an object.
 * @o: the object
 * @v: the value
 * @i: the index
 *
 * Sets the value @v inside the object @o, accesible by index @i.
 * Returns @v.
 * [Objects]
 */
mpdm_t mpdm_set_o(mpdm_t o, mpdm_t v, mpdm_t i)
/* do not use it; use mpdm_set() */
{
    mpdm_t b, r;
    int n;

    mpdm_ref(i);
    mpdm_ref(v);

    /* if hash is empty, create an optimal number of buckets */
    if (mpdm_size(o) == 0)
        mpdm_expand(o, 0, mpdm_hash_buckets);

    n = HASH_BUCKET(o, i);

    if ((b = mpdm_get_i(o, n)) != NULL) {
        int pos;

        /* bucket exists; try to find the key there */
        n = mpdm_bseek(b, i, 2, &pos);

        if (n < 0) {
            /* the pair does not exist: create it */
            n = pos;
            mpdm_expand(b, n, 2);

            mpdm_set_i(b, i, n);
        }
    }
    else {
        /* the bucket does not exist; create it */
        b = MPDM_A(2);

        /* put the bucket into the hash */
        mpdm_set_i(o, b, n);

        /* offset 0 */
        n = 0;

        /* insert the key */
        mpdm_set_i(b, i, n);
    }

    r = mpdm_set_i(b, v, n + 1);

    mpdm_unref(v);
    mpdm_unref(i);

    return r;
}
예제 #4
0
파일: mpsl_f.c 프로젝트: angelortega/mpsl
/** array = sort(a, sorting_func); */
static mpdm_t F_sort(F_ARGS)
{
    mpdm_t r, v;

    v = mpdm_ref(A0);
    r = mpdm_sort_cb(mpdm_clone(v), 1, A1);
    mpdm_unref(v);

    return r;
}
예제 #5
0
파일: mpdm_o.c 프로젝트: angelortega/mpdm
/**
 * mpdm_get_o - Gets a value from an object.
 * @o: the object
 * @i: the index
 *
 * Returns the value from @o by index @i, or NULL if there is no
 * value addressable by that index.
 * [Objects]
 */
mpdm_t mpdm_get_o(const mpdm_t o, const mpdm_t i)
/* do not use it; use mpdm_get() */
{
    mpdm_t r;

    mpdm_ref(i);
    r = mpdm_get_wcs(o, mpdm_string(i));
    mpdm_unref(i);

    return r;
}
예제 #6
0
파일: mpsl_f.c 프로젝트: angelortega/mpsl
/** v = eval(code, args); */
static mpdm_t F_eval(F_ARGS)
{
    mpdm_t r, c;

    a = mpdm_ref(mpdm_clone(a));
    c = mpdm_shift(a);

    r = mpsl_eval(c, a, l);

    mpdm_unref(a);

    return r;
}
예제 #7
0
파일: mpsl_f.c 프로젝트: angelortega/mpsl
/** argn = push(a, arg1 [, arg2, ... argn]); */
static mpdm_t F_push(F_ARGS)
{
    int n;
    mpdm_t r = NULL;

    for (n = 1; n < mpdm_size(a); n++) {
        mpdm_unref(r);
        r = mpdm_push(A0, A(n));
        mpdm_ref(r);
    }

    return mpdm_unrefnd(r);
}
예제 #8
0
static void set_local_symbols(mpdm_t s, mpdm_t v, mpdm_t l)
/* sets (or creates) a list of local symbols with a list of values */
{
    if (l != NULL) {
        mpdm_t h;

        mpdm_ref(s);
        mpdm_ref(v);
        mpdm_ref(l);

        /* gets the top local variable frame */
        h = mpdm_aget(l, -1);

        if (MPDM_IS_ARRAY(s) || MPDM_IS_ARRAY(v)) {
            int n;
            mpdm_t a;

            for (n = 0; n < mpdm_size(s); n++)
                mpdm_hset(h, mpdm_aget(s, n), mpdm_aget(v, n));

            if (n < mpdm_size(v)) {
                /* store the rest of arguments into _ */
                a = mpdm_hset_s(h, L"_", MPDM_A(0));

                for (; n < mpdm_size(v); n++)
                    mpdm_push(a, mpdm_aget(v, n));
            }
        }
        else
            mpdm_hset(h, s, v);

        mpdm_unref(l);
        mpdm_unref(v);
        mpdm_unref(s);
    }
}
예제 #9
0
파일: stress.c 프로젝트: angelortega/mpsl
void test_mpsl_file(void)
{
    mpdm_t v;
    mpdm_t inc;

    mpsl_trap(NULL);

    inc = mpdm_ref(MPDM_A(0));
    mpdm_push(inc, MPDM_S(L"."));

    printf("Compiling from file:\n");
    v = do_test_mpsl_file("test.mpsl", inc);
    v = do_test_exec(v, NULL);

    mpdm_unref(inc);
}
예제 #10
0
파일: mpsl_f.c 프로젝트: angelortega/mpsl
/** string = sprintf(fmt, arg1 [,arg2 ... argn]); */
static mpdm_t F_sprintf(F_ARGS)
{
    mpdm_t f, v, r;

    a = mpdm_ref(mpdm_clone(a));
    f = mpdm_shift(a);

    /* if the first argument is an array, take it as the arguments */
    if ((v = mpdm_get_i(a, 0)) != NULL && mpdm_type(v) == MPDM_TYPE_ARRAY)
        a = v;

    r = mpdm_sprintf(f, a);

    mpdm_unref(a);

    return r;
}
예제 #11
0
파일: mpdm_o.c 프로젝트: angelortega/mpdm
/**
 * mpdm_exists - Tests if there is a value available by index.
 * @o: the object
 * @i: the index
 *
 * Returns 1 if exists a value indexable by @i in @h, or 0 othersize.
 * [Hashes]
 */
int mpdm_exists(const mpdm_t o, const mpdm_t i)
{
    mpdm_t b;
    int ret = 0;

    mpdm_ref(i);

    if (mpdm_size(o)) {
        if ((b = mpdm_get_i(o, HASH_BUCKET(o, i))) != NULL) {
            /* if bucket exists, binary-seek it */
            if (mpdm_bseek(b, i, 2, NULL) >= 0)
                ret = 1;
        }
    }

    mpdm_unref(i);

    return ret;
}
예제 #12
0
파일: mpdm_o.c 프로젝트: angelortega/mpdm
/**
 * mpdm_keys - Returns the keys of a hash.
 * @h: the hash
 *
 * Returns an array containing all the keys of the @h hash.
 * [Hashes]
 * [Arrays]
 */
mpdm_t mpdm_keys(const mpdm_t h)
{
    int c;
    mpdm_t a, i;

    printf("Warning: deprecated function mpdm_keys()\n");

    mpdm_ref(h);

    /* create an array with the same number of elements */
    a = MPDM_A(0);

    c = 0;
    while (mpdm_iterator(h, &c, NULL, &i))
        mpdm_push(a, i);

    mpdm_unref(h);

    return a;
}
예제 #13
0
파일: stress.c 프로젝트: angelortega/mpsl
void test_abort_and_eval(void)
{
    mpdm_t v;
    mpdm_t e;

    mpsl_abort = 0;
    v = mpdm_ref(mpsl_compile(MPDM_S(L"1000;"), NULL));
    do_test("Abort 1", mpdm_ival(mpdm_exec(v, NULL, NULL)) == 1000);

    /* set global abort function */
    mpsl_abort = 1;
    do_test("Abort 2", mpdm_exec(v, NULL, NULL) == NULL);

    mpsl_abort = 0;
    do_test("Abort 3", mpdm_ival(mpdm_exec(v, NULL, NULL)) == 1000);
    mpdm_unref(v);

    mpsl_error(NULL);

    v = mpsl_eval(MPDM_S(L"invalid_code()"), NULL, NULL);
    e = mpdm_get_wcs(mpdm_root(), L"ERROR");
    printf("The following error is OK:\n");
    mpdm_dump(e);
    do_test("eval 1", v == NULL && e != NULL);

    v = mpsl_eval(MPDM_S(L"undef_func();"), NULL, NULL);
    e = mpdm_get_wcs(mpdm_root(), L"ERROR");
    printf("The following error is also OK:\n");
    mpdm_dump(e);
    do_test("eval 2", v == NULL && e != NULL);

    v = mpsl_eval(MPDM_S(L"load('unexistent_file.mpsl');"), NULL, NULL);
    e = mpdm_get_wcs(mpdm_root(), L"ERROR");
    printf("The following error is also OK:\n");
    mpdm_dump(e);
    do_test("eval 3", v == NULL && e != NULL);

    v = mpsl_eval(MPDM_S(L"2000;"), NULL, NULL);
    e = mpdm_get_wcs(mpdm_root(), L"ERROR");
    do_test("eval 4", mpdm_ival(v) == 2000 && e == NULL);
}
예제 #14
0
파일: mpsl_f.c 프로젝트: angelortega/mpsl
/** o = new(c1 [, c2, ...cn]); */
static mpdm_t F_new(F_ARGS)
{
    int n;
    mpdm_t r = MPDM_O();

    for (n = 0; n < mpdm_size(a); n++) {
        mpdm_t w, v, i;
        int m = 0;

        w = mpdm_ref(A(n));

        if (mpdm_type(w) == MPDM_TYPE_OBJECT) {
            while (mpdm_iterator(w, &m, &v, &i))
                mpdm_set(r, mpdm_clone(v), i);
        }

        mpdm_unref(w);
    }

    return r;
}
예제 #15
0
파일: mpdm_o.c 프로젝트: angelortega/mpdm
/**
 * mpdm_del_o - Deletes a value from an object.
 * @o: the value
 * @i: the index
 *
 * Deletes the element accesible by index @i from @o. Returns NULL
 * (versions prior to 1.0.10 returned the deleted value).
 * [Objects]
 */
mpdm_t mpdm_del_o(mpdm_t o, const mpdm_t i)
/* do not use it; use mpdm_del() */
{
    mpdm_t b;
    int n;

    mpdm_ref(i);

    if (mpdm_size(o)) {
        if ((b = mpdm_get_i(o, HASH_BUCKET(o, i))) != NULL) {
            /* bucket exists */
            if ((n = mpdm_bseek(b, i, 2, NULL)) >= 0) {
                /* collapse the bucket */
                mpdm_collapse(b, n, 2);
            }
        }
    }

    mpdm_unref(i);

    return NULL;
}
예제 #16
0
파일: stress.c 프로젝트: angelortega/mpsl
void test_compiler_diffs(void)
{
    mpdm_t r, cc, ac;
    int n;
    struct {
        wchar_t *code;
        int line;
    } compiler_tests[] = {
//        CT(L"local a = 1, b = 2, c, d = 3;"),
//        CT(L"local a = 1;"),
//        CT(L"local v; 1;"),
//        CT(L"local x, y, z; 2;"),
        CT(L"a |= 6;"),
        CT(L"a %= 6;"),
        CT(L"a /= 6;"),
        CT(L"a *= 6;"),
        CT(L"a -= 6;"),
        CT(L"a += 6;"),
        CT(L"for (n = 0; n < 100; n = n + 1) { print('kill'); } 1234;"),
        CT(L"for (;;) { print('kill'); } 1234;"),
        CT(L"foreach (v, i, [1, 2, 3]) { print(e); } 666;"),
        CT(L"eol = driver == 'win32' && 'crlf' || 'lf';"),
        CT(L"255 $ '%x';"),
        CT(L"foreach (e, [1, 2, 3]) { print(e); } 666;"),
//        CT(L"global v; 1;"),
//        CT(L"global x, y, z; 2;"),
        CT(L"sub pi { 3.1416; } 100;"),
        CT(L"sub pi () { 3.1416; } 200;"),
        CT(L"sub by2(v) { v * 2; } 250;"),
        CT(L"sub mul(v1, v2) { v1 * v2; } 300;"),
        CT(L"mul = sub (v1, v2) { v1 * v2; }; 123;"),
        CT(L"by2 = sub (e) { e * 2; }; 100;"),
        CT(L"pi = sub { 3.14; }; 6;"),
        CT(L"f->write('hi', string(1 + 3), eol); 1;"),
        CT(L"f->read(); 1;"),
        CT(L"while (1) 2;"),
        CT(L"while (1) { 2; 3; }"),
        CT(L"while (a < 10) { a = a + 1; }"),
        CT(L"if (a == 1) { b = 2 + 4; c = 3 * 2; } else { d = 3; e = d / 2; }"), 
        CT(L"if (1) 2; else 3;"), 
        CT(L"if (1) { 2; 3; }"),
        CT(L"if (1) { 2; }"),
        CT(L"if (1) 2;"),
        CT(L"if (2 + 3) 4 + 5;"),
        CT(L"if (a == 1) b = 2;"),
        CT(L"list[0];"),
        CT(L"list[1] = 1;"),
        CT(L"MPSL['OPCODE'];"),
        CT(L"q = 1 + 2 * 3;"),
        CT(L"q.q = 1 * 2 + 3; q2 = [];"),
        CT(L"q = 100;"),
        CT(L"MPSL.CORE.random;"),
        CT(L"1 + 2; [1, 2] ; {};"),
        CT(L"a + 1;"),
        CT(L"1 * (2 + 3);"),
        CT(L"{};"),
        CT(L"{a: 1};"),
        CT(L"{c: 2, d: 3};"),
        CT(L"{'e' => 4, 'f' => 5};"),
        CT(L"{g: 6, 'h' => 7};"),
        CT(L"{a: 2 * 3, b: 5 + 8};"),
        CT(L"[];"),
        CT(L"[1, 2, 3];"),
        CT(L"[1, 2 + 3, 4];"),
        CT(L"MPSL.CORE.random();"),
        CT(L"bool(1, 2) + 666;"),
        CT(L"1 ; 2 ; 3;"),
        CT(L"random();"),
        CT(L"5 != '5';"),
        CT(L"10 == '10';"),
        CT(L"10 > 1 + 2;"),
        CT(L"1 + 2 * 3;"),
        CT(L"1 * 2 + 3;"),
        CT(L"1.2 + 3.4;"),
        CT(L"/* test test */"),
        CT(L"1;"),
        CT(L"!1;"),
        CT(L"'abcde';"),
        CT(L"3.14;"),
        CT(NULL)
    };

    printf("\nComparing the output of the two compilers:\n");

    r  = mpdm_get_wcs(mpdm_root(), L"MPSL");
    cc = mpdm_get_wcs(r, L"c_compiler");
    ac = mpdm_get_wcs(r, L"a_compiler");

    for (n = 0; compiler_tests[n].code; n++) {
        mpdm_t c, x1, x2, d1, d2;

        c = MPDM_S(compiler_tests[n].code);

        mpdm_ref(c);

        mpdm_set_wcs(r, cc, L"compiler");
        x1 = mpsl_compile(c, NULL);
        d1 = mpsl_decompile(x1);

        mpdm_set_wcs(r, ac, L"compiler");
        x2 = mpsl_compile(c, NULL);
        d2 = mpsl_decompile(x2);

/*        printf("%ls\n", mpdm_string(d1));
        printf("%ls\n", mpdm_string(d2));*/

        _do_test("compiler output equal",
            mpdm_cmp(d1, d2) == 0, compiler_tests[n].line);

        mpdm_unref(c);
    }

    mpdm_set_wcs(r, cc, L"compiler");
}
예제 #17
0
파일: stress.c 프로젝트: angelortega/mpsl
void do_set(mpdm_t * v1, mpdm_t v2)
{
    mpdm_ref(v2);
    mpdm_unref(*v1);
    *v1 = v2;
}
예제 #18
0
파일: stress.c 프로젝트: angelortega/mpsl
void test_mpsl2(void)
{
    mpdm_t v;
    mpdm_t w;

    /* execution tests */
    v = do_test_mpsl("666;");
    mpdm_dump(v);
    v = do_test_exec(v, NULL);
    do_test("literal number", mpdm_ival(v) == 666);

    v = do_test_mpsl("\"goodbye\";");
    v = do_test_exec(v, NULL);
    do_test("literal string", mpdm_cmp(v, MPDM_S(L"goodbye")) == 0);

    v = do_test_mpsl("1 + 3 + 5;");
    v = do_test_exec(v, NULL);
    do_test("mpsl calculator 1", mpdm_rval(v) == 9.0);

    v = do_test_mpsl("1 + ((3 - 5) * 8);");
    v = do_test_exec(v, NULL);
    do_test("mpsl calculator 2", mpdm_rval(v) == -15.0);

    /* next value cannot be tested as an exact equality,
       as rounding errors will manifest */
    v = do_test_mpsl("1.5 + ((3.1 - 5.8) * 8.0);");
    v = do_test_exec(v, NULL);
    do_test("mpsl calculator 3", mpdm_rval(v) < -20.0 && mpdm_rval(v) > -21.0);

    v = do_test_mpsl("2 + 3 * 4;");
    v = do_test_exec(v, NULL);
    do_test("mpsl calculator 4", mpdm_rval(v) == 14.0);

    v = do_test_mpsl("2 * 3 + 4;");
    v = do_test_exec(v, NULL);
    do_test("mpsl calculator 5", mpdm_rval(v) == 10.0);

    v = do_test_exec(do_test_mpsl("2 + 3 * 4;"), NULL);
    mpdm_ref(v);
    w = do_test_exec(do_test_mpsl("2 + (3 * 4);"), NULL);
    do_test("mpsl calculator 6 (operator precedence)", mpdm_rval(v) == mpdm_rval(w));
    mpdm_unref(v);

    v = do_test_exec(do_test_mpsl("2 + 3 * 4;"), NULL);
    mpdm_ref(v);
    w = do_test_exec(do_test_mpsl("(2 + 3) * 4;"), NULL);
    do_test("mpsl calculator 7 (operator precedence)", mpdm_rval(v) != mpdm_rval(w));
    mpdm_unref(v);

    v = do_test_mpsl("/* array */ [\"this\", \"one\", \"is\", 666, \"cool\"];");
    v = do_test_exec(v, NULL);
    mpdm_dump(v);
    do_test("mpsl array", mpdm_ival(mpdm_get_i(v, 3)) == 666);

    v = do_test_mpsl
        ("/* hash */ { \"enero\" => \"january\", \"febrero\" => \"february\" };");
    v = do_test_exec(v, NULL);
    mpdm_dump(v);
    do_test("mpsl hash", mpdm_cmp(mpdm_get(v,
                        MPDM_S(L"febrero")),
                      MPDM_S(L"february")) == 0);

    v = do_test_mpsl("! 1;");
    v = do_test_exec(v, NULL);
    do_test("boolean not 1", !mpdm_is_true(v));
    v = do_test_mpsl("! 0;");
    v = do_test_exec(v, NULL);
    do_test("boolean not 2", v != NULL);

    v = do_test_mpsl("1 && 3;");
    v = do_test_exec(v, NULL);
    do_test("boolean and 1", mpdm_ival(v) == 3);
    v = do_test_mpsl("1 && 0;");
    v = do_test_exec(v, NULL);
    do_test("boolean and 2", !mpdm_is_true(v));
    v = do_test_mpsl("0 && 1;");
    v = do_test_exec(v, NULL);
    do_test("boolean and 3", !mpdm_is_true(v));

    v = do_test_mpsl("1 || 3;");
    v = do_test_exec(v, NULL);
    do_test("boolean or 1", mpdm_ival(v) == 1);
    v = do_test_mpsl("2 || 0;");
    v = do_test_exec(v, NULL);
    do_test("boolean or 2", mpdm_ival(v) == 2);
    v = do_test_mpsl("0 || 3;");
    v = do_test_exec(v, NULL);
    do_test("boolean or 3", mpdm_ival(v) == 3);

    v = do_test_mpsl("6 == 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric == 1", v != NULL);
    v = do_test_mpsl("8.0 == 8.0;");
    v = do_test_exec(v, NULL);
    do_test("numeric == 2", v != NULL);
    v = do_test_mpsl("6 == 8;");
    v = do_test_exec(v, NULL);
    do_test("numeric == 3", !mpdm_is_true(v));

    v = do_test_mpsl("6 != 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric != 1", !mpdm_is_true(v));
    v = do_test_mpsl("8.0 != 8.0;");
    v = do_test_exec(v, NULL);
    do_test("numeric != 2", !mpdm_is_true(v));
    v = do_test_mpsl("6 != 8;");
    v = do_test_exec(v, NULL);
    do_test("numeric != 3", v != NULL);

    v = do_test_mpsl("6 < 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric < 1", !mpdm_is_true(v));
    v = do_test_mpsl("8 < 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric < 2", !mpdm_is_true(v));
    v = do_test_mpsl("5 < 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric < 3", v != NULL);

    v = do_test_mpsl("6 > 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric > 1", !mpdm_is_true(v));
    v = do_test_mpsl("8 > 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric > 2", v != NULL);
    v = do_test_mpsl("5 > 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric > 3", !mpdm_is_true(v));

    v = do_test_mpsl("6 <= 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric <= 1", v != NULL);
    v = do_test_mpsl("8 <= 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric <= 2", !mpdm_is_true(v));
    v = do_test_mpsl("5 <= 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric <= 3", v != NULL);

    v = do_test_mpsl("6 >= 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric >= 1", v != NULL);
    v = do_test_mpsl("8 >= 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric >= 2", v != NULL);
    v = do_test_mpsl("5 >= 6;");
    v = do_test_exec(v, NULL);
    do_test("numeric >= 3", !mpdm_is_true(v));

    v = do_test_mpsl("11 % 6;");
    v = do_test_exec(v, NULL);
    do_test("modulo", mpdm_ival(v) == 5);

    v = do_test_mpsl("variable=16384;");
    mpdm_dump(v);
    v = do_test_exec(v, NULL);
    do_test("assign 1", mpdm_ival(v) == 16384);

    v = do_test_mpsl("array=[10, 20, 30, 40];");
    v = do_test_exec(v, NULL);
    do_test("assign 2", mpdm_ival(mpdm_get_i(v, 2)) == 30);

    v = do_test_mpsl("a=1; b=2; c=3;");
    mpdm_dump(v);
    v = do_test_exec(v, NULL);

    v = do_test_mpsl("CACHE={}; CACHE.regex=[]; CACHE.regex[0]=12345;");
    v = do_test_exec(v, NULL);

    v = do_test_mpsl("variable;");
    v = do_test_exec(v, NULL);
    do_test("symval 1", mpdm_ival(v) == 16384);

    v = do_test_mpsl("variable2=1 + ((3 - 5) * 8); variable2;");
    mpdm_dump(v);
    v = do_test_exec(v, NULL);
    do_test("symval 2", mpdm_rval(v) == -15);

    v = do_test_mpsl("variable3=variable2 * 2;");
    v = do_test_exec(v, NULL);
    do_test("symval 3", mpdm_ival(v) == -30);

    v = do_test_mpsl("sub mysum(a, b) { a + b; }");
    mpdm_dump(v);
    v = do_test_exec(v, NULL);
    do_test("sub 1", v != NULL);

    v = do_test_mpsl("sub pi() { 3.1416; }");
    mpdm_dump(v);
    v = do_test_exec(v, NULL);
    do_test("sub 2", v != NULL);

    v = do_test_mpsl("var10=pi();");
    v = do_test_exec(v, NULL);
    do_test("exec 1", mpdm_rval(v) == 3.1416);

    v = do_test_mpsl("var11=pi() * 10000; var11;");
    v = do_test_exec(v, NULL);
    do_test("exec 2", mpdm_rval(v) == 31416);

    v = do_test_mpsl("mysum(100, 20);");
    v = do_test_exec(v, NULL);
    do_test("exec 3", mpdm_rval(v) == 120.0);

    v = do_test_mpsl("a = NULL;");
    v = do_test_exec(v, NULL);
    do_test("NULL 1", v == NULL);

    v = do_test_mpsl("a == NULL;");
    v = do_test_exec(v, NULL);
    do_test("NULL 2", mpdm_ival(v) == 1);

    v = do_test_mpsl("local a, b; a = 1; b = 2;");
    v = do_test_exec(v, NULL);

    v = do_test_mpsl("a == NULL;");
    v = do_test_exec(v, NULL);
    do_test("local 1", mpdm_ival(v) == 1);

    v = do_test_mpsl("66 * -1;");
    v = do_test_exec(v, NULL);
    do_test("uminus", mpdm_ival(v) == -66);

    v = do_test_mpsl("\"test\" eq \"test\";");
    v = do_test_exec(v, NULL);
    do_test("streq 1", mpdm_is_true(v));

    v = do_test_mpsl("\"test\" eq \"prueba\";");
    v = do_test_exec(v, NULL);
    do_test("streq 1", !mpdm_is_true(v));

    v = do_test_mpsl("a = 6; ++ a;");
    v = do_test_exec(v, NULL);
    do_test("pinc", mpdm_ival(v) == 7);

    v = do_test_mpsl("a++;");
    v = do_test_exec(v, NULL);
    do_test("sinc", mpdm_ival(v) == 7);

    v = do_test_mpsl("a += 10;");
    v = do_test_exec(v, NULL);
    do_test("iadd", mpdm_ival(v) == 18);

    v = do_test_mpsl("local a, b, c; a=1; b=2; c=3; if(a == b) c=1000; c;");
    v = do_test_exec(v, NULL);
    do_test("if 1", mpdm_ival(v) == 3);

    v = do_test_mpsl("local a, b, c; a=1; b=2; c=3; if(a <= b) c=1000; c;");
    v = do_test_exec(v, NULL);
    do_test("if 2", mpdm_ival(v) == 1000);

    v = do_test_mpsl("local a, b, c; a=1; b=2; if(a == b) c=1000; else c=2000; c;");
    v = do_test_exec(v, NULL);
    do_test("ifelse", mpdm_ival(v) == 2000);

    v = do_test_mpsl("local a; a = 0; while(a < 100) { a++; } a;");
    v = do_test_exec(v, NULL);
    do_test("ifelse", mpdm_ival(v) == 100);

    v = do_test_mpsl("a=mysum(100, 50); a;");
    v = do_test_exec(v, NULL);
    do_test("mysum 1", mpdm_ival(v) == 150);

    v = do_test_mpsl("a=mysum(2000, 500); a;");
    v = do_test_exec(v, NULL);
    do_test("mysum 2", mpdm_ival(v) == 2500);

    w = mpdm_ref(MPDM_A(2));
    mpdm_set_i(w, MPDM_I(100), 0);
    mpdm_set_i(w, MPDM_I(50), 1);

    /* asks for the value of the mysum symbol (the code) */
    v = do_test_mpsl("mysum;");
    /* executes, so mysum() itself is being returned */
    v = do_test_exec(v, NULL);
    mpdm_dump(v);
    do_test("mysum 3", mpdm_ival(do_test_exec(v, w)) == 150);

    mpdm_set_i(w, MPDM_I(75), 1);
    do_test("mysum 4", mpdm_ival(do_test_exec(v, w)) == 175);

    /* compiles (and executes) the definition of gcd() */
    v = do_test_mpsl
        ("/* greatest common divisor (Euclid's algorithm) */ sub gcd(m, n) { while (m > 0) { if(n > m) { local t = m; m = n; n = t; } m -= n; } n; }");
    do_test_exec(v, NULL);

    /* gets a pointer to gcd() */
    v = do_test_exec(do_test_mpsl("gcd;"), NULL);
    mpdm_dump(v);

    /* executes gcd(100, 50); */
    mpdm_set_i(w, MPDM_I(50), 1);
    do_test("gcd() 1", mpdm_ival(do_test_exec(v, w)) == 50);

    /* executes gcd(100, 75); */
    mpdm_set_i(w, MPDM_I(75), 1);
    do_test("gcd() 2", mpdm_ival(do_test_exec(v, w)) == 25);

    mpdm_unref(w);

    /* string concatenation */
    w = mpdm_ref(MPDM_S(L"big lebowski"));

    v = do_test_mpsl("\"big\" ~ \" lebowski\";");
    do_test("~ (strcat 1)", mpdm_cmp(do_test_exec(v, NULL), w) == 0);

    v = do_test_mpsl("\"big\" ~ \" \" ~ \"lebowski\";");
    do_test("~ (strcat 2)", mpdm_cmp(do_test_exec(v, NULL), w) == 0);

    mpdm_unref(w);
}