130 lines
6.1 KiB
Plaintext
130 lines
6.1 KiB
Plaintext
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
|
|
#.. 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
|
|
parse [..]
|
|
%true if %x == %y else %false, %true if %x == %y otherwise %false
|
|
%false unless %x == %y else %true, %false unless %x == %y otherwise %true
|
|
..as:
|
|
%true if (%x == %y) else %false
|
|
|
|
parse [..]
|
|
%true if %x != %y else %false, %true if %x != %y otherwise %false
|
|
%false unless %x != %y else %true, %false unless %x != %y otherwise %true
|
|
..as:
|
|
%true if (%x != %y) else %false
|
|
|
|
# Indexing:
|
|
compile [%obj'%key, %obj's %key, %obj -> %key] to: "(\(%obj as lua))[\(%key as lua)]"
|
|
|
|
# Substring
|
|
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 [%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 [%var mod= %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 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))"
|
|
# == 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)))"
|
|
# For strict identity checking:
|
|
compile [%x === %y] to: "(\(%x as lua) == \(%y as lua))"
|
|
compile [%x !== %y] to: "(\(%x as lua) ~= \(%y 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))"
|