nomsu/core/operators.nom

226 lines
7.9 KiB
Plaintext
Raw Normal View History

#!/usr/bin/env nomsu -V2.5.4.3
2018-05-15 18:55:55 -07:00
#
This file contains definitions of operators like "+" and "and".
use "core/metaprogramming.nom"
2018-06-14 22:17:26 -07:00
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] to (..)
2018-06-18 15:44:29 -07:00
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 (..)
2018-06-18 15:44:29 -07:00
Lua value "(\(%a as lua expr) ~= \(%b as lua expr))"
2018-06-18 15:44:29 -07:00
# 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:
2018-06-18 15:44:29 -07:00
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)
2018-06-18 15:44:29 -07:00
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
2018-06-18 18:10:59 -07:00
lua:add_free_vars({tostring(nomsu:compile(\%var))})
2018-06-18 15:44:29 -07:00
end
return lua
2018-06-18 15:44:29 -07:00
# Simultaneous mutli-assignments like: x,y,z = 1,x,3;
compile [set %assignments] to:
2018-06-18 15:44:29 -07:00
assume (%assignments.type is "Dict") or barf ".."
Expected a Dict for the assignments part of '<- %' statement, not \%assignments
2018-06-18 15:44:29 -07:00
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
2018-06-18 15:44:29 -07:00
return \%target
end
end)
2018-06-18 15:44:29 -07:00
local target_lua = \(%target as lua)
if not target_lua.is_value then error("Invalid target for assignment: "..\(..)
%target as text
..) end
2018-06-18 15:44:29 -07:00
local value_lua = \(%value as lua)
if not value_lua.is_value then error("Invalid value for assignment: "..\(..)
%value as text
..) end
2018-06-18 15:44:29 -07:00
if \%target.type == "Var" then
2018-06-18 18:10:59 -07:00
lhs:add_free_vars({tostring(target_lua)})
2018-06-18 15:44:29 -07:00
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, ";")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2018-06-18 15:44:29 -07:00
compile [external %var = %value] to:
%var_lua = (%var as lua)
2018-06-18 15:44:29 -07:00
assume %var_lua.is_value or barf "Invalid target for assignment: \%var"
%value_lua = (%value as lua)
2018-06-18 15:44:29 -07:00
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))
2018-06-18 15:44:29 -07:00
return %body_lua
compile [with %assignments %body] to:
%lua = (%body as lua statements)
2018-06-18 15:44:29 -07:00
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))
2018-04-13 15:29:16 -07:00
end
2018-06-18 15:44:29 -07:00
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
2018-06-18 15:44:29 -07:00
if i > 1 then
lhs:append(", ")
rhs:append(", ")
2018-04-19 17:23:44 -07:00
end
2018-06-18 15:44:29 -07:00
lhs:append(target_lua)
rhs:append(value_lua)
2018-06-18 18:10:59 -07:00
if \%target.type == "Var" then
vars[i] = tostring(target_lua)
end
2018-06-18 15:44:29 -07:00
end
\%lua:remove_free_vars(vars)
\%lua:prepend("local ", lhs, " = ", rhs, ";\\n")
return (..)
Lua ".."
do
\%lua
end -- 'with' block
2018-06-18 15:44:29 -07:00
2018-06-18 15:44:29 -07:00
# Math Operators
compile [%x wrapped around %y, %x mod %y] to (..)
Lua value "(\(%x as lua expr) % \(%y as lua expr))"
2018-06-18 15:44:29 -07:00
# 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)"
2018-06-18 15:44:29 -07:00
# TODO: optimize for common case where x,y,z are all either variables or number literals
2018-06-18 15:44:29 -07:00
# 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))")
2018-06-18 15:44:29 -07:00
# 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))"
2018-06-18 15:44:29 -07:00
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?
2018-06-18 15:44:29 -07:00
# 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, len %list, || %list ||] to (Lua value "(#\(%list as lua expr))")
compile [%list is empty] to (Lua value "(#\(%list as lua expr) == 0)")
2018-06-18 15:44:29 -07:00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Update operators
parse [%var += %] as (%var = (%var + %))
parse [%var -= %] as (%var = (%var - %))
parse [%var *= %] as (%var = (%var * %))
parse [%var /= %] as (%var = (%var / %))
parse [%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 %))