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
122
123
124
125
126
127
128
129
130
131
132
133
|
use "lib/metaprogramming.nom"
# Literals
compile [yes] to: "true"
compile [no] to: "false"
compile [nil, null] to: "nil"
compile [infinity, inf] to: "math.huge"
compile [not a number, NaN, nan] to: "(0/0)"
compile [pi, Pi, PI] to: "math.pi"
compile [tau, Tau, TAU] to: "(2*math.pi)"
compile [phi, Phi, PHI, golden ratio] to: "((1+math.sqrt(5))/2)"
compile [do nothing] to code: ""
# Ternary operator
#.. Note: this uses a function instead of "(condition and if_expr or else_expr)"
because that breaks if %if_expr is falsey, e.g. "x < 5 and false or 99"
compile [..]
%when_true_expr if %condition else %when_false_expr
%when_true_expr if %condition otherwise %when_false_expr
%when_false_expr unless %condition else %when_true_expr
%when_false_expr unless %condition then %when_true_expr
..to:
lua> ".."
local condition = nomsu:tree_to_lua(\%condition).expr;
local when_true = nomsu:tree_to_lua(\%when_true_expr).expr;
local when_false = nomsu:tree_to_lua(\%when_false_expr).expr;
local safe = {Text=true, List=true, Dict=true, Number=true};
if safe[\%when_true_expr.type] then
return "("..condition.." and "..when_true.." or "..when_false..")";
else
return ([[
(function(nomsu)
if %s then
return %s;
else
return %s;
end
end)(nomsu)]]):format(condition, when_true, when_false);
end
# Indexing:
compile [%obj'%key, %obj's %key, %obj -> %key] to: "(\(%obj as lua))[\(%key as lua)]"
# Substring
# TODO: improve this syntax
compile [%str |%start|] to: "\(%str as lua):sub(\(%start as lua), \(%start as lua))"
compile [%str |%start - %stop|] to: "\(%str as lua):sub(\(%start as lua), \(%stop as lua))"
# Variable assignment operator, and += type versions
compile [set %var = %val] to code:
lua> ".."
if \%var.type == 'List' and \%val.type == 'List' then
local lhs = {};
for i,x in ipairs(\%var.value) do lhs[i] = nomsu:tree_to_lua(x).expr; end
local rhs = {};
for i,x in ipairs(\%val.value) do rhs[i] = nomsu:tree_to_lua(x).expr; end
return table.concat(lhs, ", ").." = "..table.concat(rhs, ", ")..";";
else
return \(%var as lua).." = "..\(%val as lua)..";";
end
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 [wrap %var around %val] to code: "\(%var as lua) = \(%var as lua) % \(%val as lua);"
# Math Operators
compile [%x + %y] to: "(\(%x as lua) + \(%y as lua))"
compile [%x - %y] to: "(\(%x as lua) - \(%y as lua))"
compile [%x * %y] to: "(\(%x as lua) * \(%y as lua))"
compile [%x / %y] to: "(\(%x as lua) / \(%y as lua))"
compile [%x ^ %y] to: "(\(%x as lua) ^ \(%y as lua))"
compile [%x wrapped around %y, %x mod %y] to: "(\(%x as lua) % \(%y as lua))"
# Comparison Operators
compile [%x < %y] to: "(\(%x as lua) < \(%y as lua))"
compile [%x > %y] to: "(\(%x as lua) > \(%y as lua))"
compile [%x <= %y] to: "(\(%x as lua) <= \(%y as lua))"
compile [%x >= %y] to: "(\(%x as lua) >= \(%y as lua))"
compile [%a is %b, %a = %b, %a == %b] to:
lua> ".."
local safe = {Text=true, Number=true};
local a_lua, b_lua = nomsu:tree_to_lua(\%a).expr, nomsu:tree_to_lua(\%b).expr;
if safe[\%a.type] or safe[\%b.type] then
return "("..a_lua.." == "..b_lua..")";
else
return "nomsu.utils.equivalent("..a_lua..", "..b_lua..")";
end
compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to:
lua> ".."
local safe = {Text=true, Number=true};
local a_lua, b_lua = nomsu:tree_to_lua(\%a).expr, nomsu:tree_to_lua(\%b).expr;
if safe[\%a.type] or safe[\%b.type] then
return "("..a_lua.." ~= "..b_lua..")";
else
return "(not nomsu.utils.equivalent("..a_lua..", "..b_lua.."))";
end
# For strict identity checking, use (%x's id) is (%y's id)
compile [%'s id, id of %] to: "nomsu.ids[\(% as lua)]"
# 3-part chained comparisons
# (uses a lambda to avoid re-evaluating middle value, while still being an expression)
parse [%x < %y < %z] as: =lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)"
parse [%x <= %y < %z] as: =lua "(function(x,y,z) return x <= y and y < z; end)(\%x,\%y,\%z)"
parse [%x < %y <= %z] as: =lua "(function(x,y,z) return x < y and y <= z; end)(\%x,\%y,\%z)"
parse [%x <= %y <= %z] as: =lua "(function(x,y,z) return x <= y and y <= z; end)(\%x,\%y,\%z)"
parse [%x > %y > %z] as: =lua "(function(x,y,z) return x > y and y > z; end)(\%x,\%y,\%z)"
parse [%x >= %y > %z] as: =lua "(function(x,y,z) return x >= y and y > z; end)(\%x,\%y,\%z)"
parse [%x > %y >= %z] as: =lua "(function(x,y,z) return x > y and y >= z; end)(\%x,\%y,\%z)"
parse [%x >= %y >= %z] as: =lua "(function(x,y,z) return x >= y and y >= z; end)(\%x,\%y,\%z)"
# TODO: optimize for common case where x,y,z are all either variables or number literals
# Boolean Operators
compile [%x and %y] to: "(\(%x as lua) and \(%y as lua))"
compile [%x or %y] to: "(\(%x as lua) or \(%y as lua))"
# Bitwise Operators
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, %x >>> %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))"
# TODO: implement OR, XOR, AND for multiple operands?
# Unary operators
compile [- %] to: "-(\(% as lua))"
compile [not %] to: "not (\(% as lua))"
|