nomsu/lib/operators.nom
Bruce Hill f97ab858ed Modernized the codebase a bit to include "immediately:" for immediately
running code before further parsing takes place. That means that in the
default case, whole files can be run at once, which makes all but the
weirdest edge cases make a lot more sense and operate smoothly.
2018-01-08 18:53:57 -08:00

120 lines
5.7 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: ".."
(function(nomsu, vars)
if \(%condition as lua) then
return \(%when_true_expr as lua);
else
return \(%when_false_expr as lua);
end
end)(nomsu, vars)
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))"