180 lines
7.7 KiB
Plaintext
180 lines
7.7 KiB
Plaintext
#
|
|
This file contains definitions of operators like "+" and "and".
|
|
|
|
use "core/metaprogramming.nom"
|
|
use "core/errors.nom"
|
|
|
|
# Comparison Operators
|
|
compile [%x < %y] to: Lua value "(\(%x as lua expr) < \(%y as lua expr))"
|
|
compile [%x > %y] to: Lua value "(\(%x as lua expr) > \(%y as lua expr))"
|
|
compile [%x <= %y] to: Lua value "(\(%x as lua expr) <= \(%y as lua expr))"
|
|
compile [%x >= %y] to: Lua value "(\(%x as lua expr) >= \(%y as lua expr))"
|
|
compile [%a is %b, %a = %b, %a == %b] to
|
|
Lua value "(\(%a as lua expr) == \(%b as lua expr))"
|
|
compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to
|
|
Lua value "(\(%a as lua expr) ~= \(%b as lua expr))"
|
|
# For strict identity checking, use (%x's id) is (%y's id)
|
|
lua> ".."
|
|
do
|
|
local new_uuid = require('uuid')
|
|
local NaN_surrogate = {}
|
|
local nil_surrogate = {}
|
|
IDS = setmetatable({}, {
|
|
__mode = "k",
|
|
__index = function(self, key)
|
|
if key == nil then return self[nil_surrogate]
|
|
elseif key ~= key then return self[NaN_surrogate] end
|
|
local id = new_uuid()
|
|
self[key] = id
|
|
return id
|
|
end
|
|
})
|
|
end
|
|
compile [%'s id, id of %] to: Lua value "IDS[\(% as lua expr)]"
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
# Variable assignment operator
|
|
compile [%var <- %value] to
|
|
lua> "local \%var_lua = \(%var as lua)"
|
|
assume %var_lua.is_value or barf "Invalid target for assignment: \%var"
|
|
lua> ".."
|
|
\%value = \%value:map(function(t)
|
|
if Action:is_instance(t) and t.stub == "?" then
|
|
return \%var
|
|
end
|
|
end)
|
|
local \%value_lua = \(%value as lua)
|
|
|
|
assume %value_lua.is_value or barf "Invalid value for assignment: \%value"
|
|
lua> ".."
|
|
local lua = LuaCode(tree.source, \%var_lua, ' = ', \%value_lua, ';')
|
|
if \%var.type == 'Var' then
|
|
lua:add_free_vars({tostring(nomsu:compile(\%var))})
|
|
end
|
|
return lua
|
|
|
|
# Simultaneous mutli-assignments like: x,y,z = 1,x,3;
|
|
compile [<- %assignments, assign %assignments] to
|
|
assume (%assignments.type is "Dict") or barf ".."
|
|
Expected a Dict for the assignments part of '<- %' statement, not \%assignments
|
|
lua> ".."
|
|
local lhs, rhs = LuaCode(tree.source), LuaCode(tree.source)
|
|
for i, item in ipairs(\%assignments) do
|
|
local \%target, \%value = item[1], item[2]
|
|
\%value = \%value:map(function(t)
|
|
if Action:is_instance(t) and t.stub == "?" then
|
|
return \%target
|
|
end
|
|
end)
|
|
local target_lua = \(%target as lua)
|
|
if not target_lua.is_value then error("Invalid target for assignment: "..\(%target as text)) end
|
|
local value_lua = \(%value as lua)
|
|
if not value_lua.is_value then error("Invalid value for assignment: "..\(%value as text)) end
|
|
if \%target.type == "Var" then
|
|
lhs:add_free_vars({tostring(target_lua)})
|
|
end
|
|
if i > 1 then
|
|
lhs:append(", ")
|
|
rhs:append(", ")
|
|
end
|
|
lhs:append(target_lua)
|
|
rhs:append(value_lua)
|
|
end
|
|
return LuaCode(tree.source, lhs, " = ", rhs, ";")
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
compile [external %var <- %value] to
|
|
%var_lua <- (%var as lua)
|
|
assume %var_lua.is_value or barf "Invalid target for assignment: \%var"
|
|
%value_lua <- (%value as lua)
|
|
assume %value_lua.is_value or barf "Invalid value for assignment: \%value"
|
|
return: Lua "\%var_lua = \%value_lua;"
|
|
|
|
compile [with external %externs %body] to
|
|
%body_lua <- (%body as lua statements)
|
|
lua> "\%body_lua:remove_free_vars(table.map(\%externs, function(v) return tostring(nomsu:compile(v)) end))"
|
|
return %body_lua
|
|
|
|
compile [with %assignments %body] to
|
|
%lua <- (%body as lua statements)
|
|
lua> ".."
|
|
local lhs, rhs = LuaCode(tree.source), LuaCode(tree.source)
|
|
local vars = {}
|
|
for i, item in ipairs(\%assignments) do
|
|
local \%target, \%value = item[1], item[2]
|
|
if not \%target.type == "Var" then
|
|
error("Invalid target for 'with' assignment: "..tostring(\%target))
|
|
end
|
|
local target_lua = \(%target as lua)
|
|
local value_lua = \(%value as lua)
|
|
if not value_lua.is_value then
|
|
error("Invalid value for assignment: "..tostring(\%value))
|
|
end
|
|
if i > 1 then
|
|
lhs:append(", ")
|
|
rhs:append(", ")
|
|
end
|
|
lhs:append(target_lua)
|
|
rhs:append(value_lua)
|
|
if \%target.type == "Var" then
|
|
vars[i] = tostring(target_lua)
|
|
end
|
|
end
|
|
\%lua:remove_free_vars(vars)
|
|
\%lua:prepend("local ", lhs, " = ", rhs, ";\n")
|
|
return
|
|
Lua ".."
|
|
do
|
|
\%lua
|
|
end -- 'with' block
|
|
|
|
# Math Operators
|
|
compile [%x wrapped around %y, %x mod %y] to: Lua value "(\(%x as lua expr) % \(%y as lua expr))"
|
|
|
|
# 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: Lua value "(\(%x as lua expr) and \(%y as lua expr))"
|
|
compile [%x or %y] to: Lua value "(\(%x as lua expr) or \(%y as lua expr))"
|
|
|
|
# Bitwise Operators
|
|
# TODO: support bit.???() for luajit and bit32.??? for lua 5.2
|
|
compile [%a OR %b, %a | %b] to: Lua value "(\(%a as lua expr) | \(%b as lua expr))"
|
|
compile [%a XOR %b] to: Lua value "(\(%a as lua expr) ^ \(%b as lua expr))"
|
|
compile [%a AND %b, %a & %b] to: Lua value "(\(%a as lua expr) & \(%b as lua expr))"
|
|
compile [NOT %, ~ %] to: Lua value "~(\(% as lua expr))"
|
|
compile [%x LSHIFT %shift, %x << %shift] to: Lua value "(\(%x as lua expr) << \(%shift as lua expr))"
|
|
compile [%x RSHIFT %shift, %x >>> %shift] to: Lua value "(\(%x as lua expr) >>> \(%shift as lua expr))"
|
|
compile [%x ARSHIFT %shift, %x >> %shift] to: Lua value "(\(%x as lua expr) >> \(%shift as lua expr))"
|
|
# TODO: implement OR, XOR, AND for multiple operands?
|
|
|
|
# Unary operators
|
|
compile [- %] to: Lua value "(- \(% as lua expr))"
|
|
compile [not %] to: Lua value "(not \(% as lua expr))"
|
|
test: assume: (length of [1,2,3]) = 3
|
|
compile [length of %list, || %list ||] to: Lua value "(#\(%list as lua expr))"
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
# Update operators
|
|
parse [%var + <- %, %var +<- %] as: %var <- (%var + %)
|
|
parse [%var - <- %, %var -<- %] as: %var <- (%var - %)
|
|
parse [%var * <- %, %var *<- %] as: %var <- (%var * %)
|
|
parse [%var / <- %, %var /<- %] as: %var <- (%var / %)
|
|
parse [%var ^ <- %, %var ^<- %] as: %var <- (%var ^ %)
|
|
parse [%var and <- %] as: %var <- (%var and %)
|
|
parse [%var or <- %] as: %var <- (%var or %)
|
|
parse [wrap %var around %] as: %var <- (%var wrapped around %)
|