cluna 1.1.0

Tool to convert Lua code into Clue code Made by MarkosTh09
Documentation
---
source: src/main.rs
expression: compiled
input_file: test-data/lua5.3-tests/code.lua
---
if T == nil {
    (Message || print)('\n >>> testC not active: skipping opcode tests <<<\n');
    return
}
print("testing code generation and optimizations");
{
    local fn f(a) {
        for k, v, w with a {
            
        }
    }
}
local fn checkKlist(func, list) {
    local k = T.listk(func)
    assert(#k == #list);
    for i = 1, #k {
        assert(k[(i)] == list[(i)] && math.type(k[(i)]) == math.type(list[(i)]));
    }
}
local fn foo() {
    local a
    a = 3
    a = 0
    a = 0.0
    a = -7 + 7
    a = 3.78 / 4
    a = 3.78 / 4
    a = -3.78 / 4
    a = 3.78 / 4
    a = -3.78 / 4
    a = -3.79 / 4
    a = 0.0
    a = -0
    a = 3
    a = 3.0
    a = 3
    a = 3.0
}
checkKlist(foo, {
    3, 
    0, 
    0.0, 
    3.78 / 4, 
    -3.78 / 4, 
    -3.79 / 4, 
    3.0
});
global fn check(f, ...) {
    local arg = {
        ...
    }
    local c = T.listcode(f)
    for i = 1, #arg {
        assert(string.find(c[(i)], '- ' .. arg[(i)] .. ' *%d'));
    }
    assert(c[(#arg + 2)] == nil);
}
global fn checkequal(a, b) {
    a = T.listcode(a)
    b = T.listcode(b)
    for i = 1, #a {
        a[(i)] = string.gsub(a[(i)], '%b()', '')
        b[(i)] = string.gsub(b[(i)], '%b()', '')
        assert(a[(i)] == b[(i)]);
    }
}
check(fn () {
    (fn () {
        
    })({
        f()
    });
}, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN');
check(fn () {
    local a, b, c
    local d
    local e
    local f, g, h
    d = nil
    d = nil
    b = nil
    a = nil
    c = nil
}, 'LOADNIL', 'RETURN');
check(fn () {
    local a, b, c, d = 1, 1, 1, 1
    d = nil
    c = nil
    b = nil
    a = nil
}, 'LOADK', 'LOADK', 'LOADK', 'LOADK', 'LOADNIL', 'RETURN');
{
    local a, b, c, d = 1, 1, 1, 1
    d = nil
    c = nil
    b = nil
    a = nil
    assert(a == nil && b == nil && c == nil && d == nil);
}
check(fn (a, b, c) {
    return a
}, 'RETURN');
check(fn () {
    while true {
        local a = -1
    }
}, 'LOADK', 'JMP', 'RETURN');
check(fn () {
    while 1 {
        local a = -1
    }
}, 'LOADK', 'JMP', 'RETURN');
check(fn () {
    loop  {
        local x = 1
    } until true
}, 'LOADK', 'RETURN');
check(fn (a, b, c, d) {
    return a .. b .. c .. d
}, 'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN');
check(fn () {
    return !!nil
}, 'LOADBOOL', 'RETURN');
check(fn () {
    return !!false
}, 'LOADBOOL', 'RETURN');
check(fn () {
    return !!true
}, 'LOADBOOL', 'RETURN');
check(fn () {
    return !!1
}, 'LOADBOOL', 'RETURN');
check(fn () {
    local a, b, c, d
    a = b * 2
    c[(2)], a[(b)] = -((a + d / 2 - a[(b)]) ^ a.x), b
}, 'LOADNIL', 'MUL', 'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETTABLE', 'POW', 'UNM', 'SETTABLE', 'SETTABLE', 'RETURN');
check(fn () {
    local a, b
    a.x = 3.2
    a.x = b
    a[(b)] = 'x'
}, 'LOADNIL', 'SETTABLE', 'SETTABLE', 'SETTABLE', 'RETURN');
check(fn () {
    local a, b
    a = 1 - a
    b = 1 / a
    b = 5 - 4
}, 'LOADNIL', 'SUB', 'DIV', 'LOADK', 'RETURN');
check(fn () {
    local a, b
    a[(true)] = false
}, 'LOADNIL', 'SETTABLE', 'RETURN');
local fn checkK(func, val) {
    check(func, 'LOADK', 'RETURN');
    local k = T.listk(func)
    assert(#k == 1 && k[(1)] == val && math.type(k[(1)]) == math.type(val));
    assert(func() == val);
}
checkK(fn () {
    return 0.0
}, 0.0);
checkK(fn () {
    return 0
}, 0);
checkK(fn () {
    return -0 /_ 1
}, 0);
checkK(fn () {
    return 3 ^ -1
}, 1 / 3);
checkK(fn () {
    return (1 + 1) ^ (50 + 50)
}, 2 ^ 100);
checkK(fn () {
    return (-2) ^ (31 - 2)
}, -0x20000000 + 0.0);
checkK(fn () {
    return (-3 ^ 0 + 5) /_ 3.0
}, 1.0);
checkK(fn () {
    return -3 % 5
}, 2);
checkK(fn () {
    return -((2.0 ^ 8 + -(-1)) % 8) / 2 * 4 - 3
}, -5.0);
checkK(fn () {
    return -((2 ^ 8 + -(-1)) % 8) /_ 2 * 4 - 3
}, -7.0);
checkK(fn () {
    return 240 | 204 ~ 0xAA & 0xFD
}, 0xF4);
checkK(fn () {
    return ^^(^^0xFF0 | 0xFF0)
}, 0);
checkK(fn () {
    return ^^ ~ -100024.0
}, -100024);
checkK(fn () {
    return ((100 << 6) << -4) >> 2
}, 100);
check(fn () {
    return -0.0
}, 'LOADK', 'UNM', 'RETURN');
check(fn () {
    return 3 / 0
}, 'DIV', 'RETURN');
check(fn () {
    return 0 % 0
}, 'MOD', 'RETURN');
check(fn () {
    return -4 /_ 0
}, 'IDIV', 'RETURN');
check(fn () {
    return -nil
}, 'LOADNIL', 'UNM', 'RETURN');
check(fn () {
    local a, b, c
    b[(c)], a = c, b
    b[(a)], a = c, b
    a, b = c, a
    a = a
}, 'LOADNIL', 'MOVE', 'MOVE', 'SETTABLE', 'MOVE', 'MOVE', 'MOVE', 'SETTABLE', 'MOVE', 'MOVE', 'MOVE', 'RETURN');
checkequal(fn () {
    if (a == nil) {
        a = 1
    }
    if a != nil {
        a = 1
    }
}, fn () {
    if (a == 9) {
        a = 1
    }
    if a != 9 {
        a = 1
    }
});
check(fn () {
    if a == nil {
        a = 'a'
    }
}, 'GETTABUP', 'EQ', 'JMP', 'SETTABUP', 'RETURN');
checkequal(fn () {
    local a
    if !(a || b) {
        b = a
    }
}, fn () {
    local a
    if (!a && !b) {
        b = a
    }
});
checkequal(fn (l) {
    local a
    return 0 <= a && a <= l
}, fn (l) {
    local a
    return !(!(a >= 0) || !(a <= l))
});
check(fn (a, b, c, d, e) {
    if a == b {
        
    } elseif if a == c {
        
    } elseif if a == d {
        
    } else {
        if a == e {
            
        } else {
            
        }
    }
}, 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'JMP', 'RETURN');
checkequal(fn (a) {
    while a < 10 {
        a = a + 1
    }
}, fn (a) {
    if !(a < 10) {
        
    }
    a = a + 1
});
checkequal(fn (a) {
    while a < 10 {
        a = a + 1
    }
}, fn (a) {
    while true {
        if !(a < 10) {
            break
        }
        a = a + 1
    }
});
print('OK');