aboutsummaryrefslogtreecommitdiff
path: root/lib/operators.nom
blob: 17d7e34b198a6dafd4ff64d85891bfed86aca25b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
require "lib/metaprogramming.nom"

# Literals
compile [true, yes] to: "true"
compile [false, no] to: "false"
compile [nil, null] to: "nil"
compile [inf, infinity] to: "math.huge"
compile [nan, NaN, not a number] to: "(0/0)"
compile [pi, PI] to: "math.pi"
compile [tau, TAU] to: "(2*math.pi)"
compile [phi, PHI, golden ratio] to: "((1+math.sqrt(5))/2)"
compile [nop, pass] to code: ""

# Ternary operator
compile [%if_expr if %condition else %else_expr] to: ".."
    #.. Note: this uses a function instead of (condition and if_expr or else_expr)
        because that breaks if %if_expr is falsey.
    |(function(nomsu, vars)
    |    if \(%condition) then;
    |        return \(%if_expr);
    |    else;
    |        return \(%else_expr);
    |    end;
    |end)(nomsu, vars)

# Indexing:
compile [%obj's %key, %obj -> %key] to: "(\(%obj as lua))[\(%key as lua)]"

# Variable assignment operator, and += type versions
compile [%var = %val] to code: "\(%var as lua) = \(%val as lua);"
compile [%var += %val] to code: "\(%var as lua) = \(%var as lua) + \(%val as lua);"
compile [%var -= %val] to code: "\(%var as lua) = \(%var as lua) - \(%val as lua);"
compile [%var *= %val] to code: "\(%var as lua) = \(%var as lua) * \(%val as lua);"
compile [%var /= %val] to code: "\(%var as lua) = \(%var as lua) / \(%val as lua);"
compile [%var ^= %val] to code: "\(%var as lua) = \(%var as lua) ^ \(%val as lua);"
compile [%var and= %val] to code: "\(%var as lua) = \(%var as lua) and\(%val as lua);"
compile [%var or= %val] to code: "\(%var as lua) = \(%var as lua) or \(%val as lua);"
compile [%var join= %val] to code: "\(%var as lua) = \(%var as lua) .. \(%val as lua);"
compile [%var mod= %val] to code: "\(%var as lua) = \(%var as lua) % \(%val as lua);"

# Binary Operators
lua block ".."
    |local binops = {"-","/","<","<=",">",">=","^",{"===","=="},{"!==","~="},{"mod","%"}};
    |for _,op in ipairs(binops) do;
    |    local nomsu_alias = op;
    |    if type(op) == 'table' then;
    |        nomsu_alias, op = unpack(op);
    |    end;
    |    nomsu:defmacro("%a "..nomsu_alias.." %b", (function(nomsu, vars)
    |        return "("..nomsu:tree_to_lua(vars.a).." "..op.." "..nomsu:tree_to_lua(vars.b)..")";
    |    end), [["(\\(%a) ]]..op..[[ \\(%b))"]]);
    |end;
# TODO: implement OR, XOR, AND for multiple operands
compile [%a OR %b, %a | %b] to: "bit32.bor(\(%a as lua), \(%b as lua))"
compile [%a XOR %b] to: "bit32.bxor(\(%a as lua), \(%b as lua))"
compile [%a AND %b, %a & %b] to: "bit32.band(\(%a as lua), \(%b as lua))"
compile [NOT %, ~ %] to: "bit32.bnot(\(% as lua))"
compile [%x LSHIFT %shift, %x << %shift] to: "bit32.lshift(\(%x as lua), \(%shift as lua))"
compile [%x RSHIFT %shift] to: "bit32.rshift(\(%x as lua), \(%shift as lua))"
compile [%x ARSHIFT %shift, %x >> %shift] to: "bit32.arshift(\(%x as lua), \(%shift as lua))"
# == and != do equivalence checking, rather than identity checking
compile [%a == %b] to: "nomsu.utils.equivalent(\(%a as lua), \(%b as lua))"
compile [%a != %b] to: "(not nomsu.utils.equivalent(\(%a as lua), \(%b as lua)))"

# Commutative Operators defined for up to 8 operands
# TODO: work out solution for commutative operators using more clever macros
lua block ".."
    |local max_operands = 8;
    |local comops = {"+","*","and","or"};
    |for _,_op in ipairs(comops) do;
    |    local op = _op;
    |    local spec = "%1 ";
    |    for n=2,max_operands do;
    |        spec = spec .." "..op.." %"..tostring(n);
    |        nomsu:defmacro(spec, (function(nomsu, vars)
    |            local bits = {};
    |            for i=1,n do;
    |                table.insert(bits, (nomsu:tree_to_lua(vars[tostring(i)])));
    |            end;
    |            return "("..table.concat(bits, " "..op.." ")..")";
    |        end));
    |    end;
    |end;

# Chained compairsions (e.g. x < y <= z) are defined up to 3 operands
lua block ".."
    |local max_operands = 3;
    |for _,chainers in ipairs({{"<","<="},{">",">="}}) do;
    |    local function recurse(chainers, chain)
    # The 1-op versions are already more efficiently defined, and a 0-op version doesnt make sense
    |        if #chain >= 2 then;
    |            local spec = "%1";
    |            for i,op in ipairs(chain) do;
    |                spec = spec .. " "..op.." %"..tostring(i+1);
    |            end;
    # Chained comparisons need to be functions to avoid re-evaluating their arguments :\
    |            nomsu:def(spec, function(nomsu, vars)
    |                for i,op in ipairs(chain) do;
    |                    local a, b, result = vars[i], vars[i+1];
    |                    if     op == "<"  then; result = a < b;
    |                    elseif op == "<=" then; result = a <= b;
    |                    elseif op == ">"  then; result = a > b;
    |                    elseif op == ">=" then; result = a >= b; end;
    # Short circuit
    |                    if not result then; return false; end;
    |                end;
    |            end);
    |        end;
    |        if #chain + 1 >= max_operands then; return; end;
    |        for _,c in ipairs(chainers) do;
    |            table.insert(chain, c);
    |            recurse(chainers, chain);
    |            table.remove(chain);
    |        end;
    |    end;
    |    recurse(chainers, {});
    |end;

# Unary operators
compile [- %] to: "-(\(% as lua))"
compile [not %] to: "not (\(% as lua))"