#include "complex.h"
#include "a/complex.h"
static int liba_complex_isok(lua_State *L, int idx)
{
int ok = 0;
if (lua_getmetatable(L, idx))
{
lua_registry_get(L, liba_complex_new);
ok = lua_rawequal(L, -1, -2);
lua_pop(L, 2);
}
return ok;
}
static int liba_complex_from(lua_State *L, a_complex *z, int idx)
{
int type = lua_type(L, idx);
switch (type)
{
case LUA_TNUMBER:
z->real = (a_float)lua_tonumber(L, idx);
z->imag = 0;
break;
case LUA_TSTRING:
a_complex_parse(z, lua_tostring(L, idx));
break;
case LUA_TUSERDATA:
if (liba_complex_isok(L, idx))
{
*z = *(a_complex *)lua_touserdata(L, idx);
break;
}
A_FALLTHROUGH;
default:
z->real = 0;
z->imag = 0;
}
return type;
}
static a_complex *liba_complex_new_(lua_State *L)
{
a_complex *const ctx = lua_newclass(L, a_complex);
lua_registry_get(L, liba_complex_new);
lua_setmetatable(L, -2);
return ctx;
}
static int liba_complex_tostring(lua_State *L)
{
a_complex const *const ctx = (a_complex const *)lua_touserdata(L, 1);
if (ctx)
{
lua_pushfstring(L, "(%f,%f)", (double)ctx->real, (double)ctx->imag);
return 1;
}
return 0;
}
int liba_complex_new(lua_State *L)
{
a_complex z = A_COMPLEX_C(0.0, 0.0);
int const top = lua_gettop(L);
if (top >= 1)
{
int const type = liba_complex_from(L, &z, 1);
if (type == LUA_TNUMBER && top >= 2)
{
z.imag = (a_float)lua_tonumber(L, 2);
}
}
*liba_complex_new_(L) = z;
return 1;
}
int liba_complex_rect(lua_State *L)
{
a_float real = 0, imag = 0;
int const top = lua_gettop(L);
if (top >= 1) { real = (a_float)lua_tonumber(L, 1); }
if (top >= 2) { imag = (a_float)lua_tonumber(L, 2); }
a_complex_rect(liba_complex_new_(L), real, imag);
return 1;
}
int liba_complex_polar(lua_State *L)
{
a_float rho = 0, theta = 0;
int const top = lua_gettop(L);
if (top >= 1) { rho = (a_float)lua_tonumber(L, 1); }
if (top >= 2) { theta = (a_float)lua_tonumber(L, 2); }
a_complex_polar(liba_complex_new_(L), rho, theta);
return 1;
}
int liba_complex_eq(lua_State *L)
{
if (lua_gettop(L) >= 2)
{
a_complex x, y;
liba_complex_from(L, &x, 1);
liba_complex_from(L, &y, 2);
lua_pushboolean(L, a_complex_eq(x, y));
return 1;
}
return 0;
}
int liba_complex_ne(lua_State *L)
{
if (lua_gettop(L) >= 2)
{
a_complex x, y;
liba_complex_from(L, &x, 1);
liba_complex_from(L, &y, 2);
lua_pushboolean(L, a_complex_ne(x, y));
return 1;
}
return 0;
}
#undef F1
#define F1(func) \
int liba_complex_##func(lua_State *L) \
{ \
if (lua_gettop(L) >= 1) \
{ \
a_complex z; \
liba_complex_from(L, &z, 1); \
z.real = a_complex_##func(z); \
lua_pushnumber(L, (lua_Number)z.real); \
return 1; \
} \
return 0; \
}
F1(logabs)
F1(abs2)
F1(abs)
F1(arg)
#undef F1
#define F1(func) \
int liba_complex_##func(lua_State *L) \
{ \
if (lua_gettop(L) >= 1) \
{ \
a_complex z, *ctx; \
ctx = liba_complex_new_(L); \
liba_complex_from(L, &z, 1); \
a_complex_##func(ctx, z); \
return 1; \
} \
return 0; \
}
F1(proj)
F1(conj)
F1(neg)
F1(inv)
#undef F1
#define F1(func) \
int liba_complex_##func(lua_State *L) \
{ \
if (lua_gettop(L) >= 2) \
{ \
a_complex x, y, *ctx; \
ctx = liba_complex_new_(L); \
liba_complex_from(L, &x, 1); \
liba_complex_from(L, &y, 2); \
a_complex_##func(ctx, x, y); \
return 1; \
} \
return 0; \
}
#undef F2
#define F2(func) \
int liba_complex_##func(lua_State *L) \
{ \
if (lua_gettop(L) >= 2) \
{ \
a_complex x, y, *ctx = liba_complex_new_(L); \
liba_complex_from(L, &x, 1); \
if (liba_complex_from(L, &y, 2) == LUA_TNUMBER) \
{ \
a_complex_##func##_real(ctx, x, y.real); \
} \
else { a_complex_##func(ctx, x, y); } \
return 1; \
} \
return 0; \
}
F2(add)
F2(sub)
F2(mul)
F2(div)
F1(pow)
F1(logb)
#undef F1
#define F1(func) \
int liba_complex_##func(lua_State *L) \
{ \
if (lua_gettop(L) >= 1) \
{ \
a_complex z, *ctx; \
ctx = liba_complex_new_(L); \
liba_complex_from(L, &z, 1); \
a_complex_##func(ctx, z); \
return 1; \
} \
return 0; \
}
#undef F2
#define F2(func) \
int liba_complex_##func(lua_State *L) \
{ \
if (lua_gettop(L) >= 1) \
{ \
a_complex z, *ctx = liba_complex_new_(L); \
int type = liba_complex_from(L, &z, 1); \
if (type == LUA_TNUMBER) \
{ \
a_complex_##func##_real(ctx, z.real); \
} \
else { a_complex_##func(ctx, z); } \
return 1; \
} \
return 0; \
}
F1(exp)
F1(log)
F2(sqrt)
F1(log2)
F1(log10)
F1(sin)
F1(cos)
F1(tan)
F1(sec)
F1(csc)
F1(cot)
F2(asin)
F2(acos)
F1(atan)
F2(asec)
F2(acsc)
F1(acot)
F1(sinh)
F1(cosh)
F1(tanh)
F1(sech)
F1(csch)
F1(coth)
F1(asinh)
F2(acosh)
F2(atanh)
F1(asech)
F1(acsch)
F1(acoth)
static int liba_complex_set(lua_State *L)
{
a_complex *const ctx = (a_complex *)lua_touserdata(L, 1);
switch (a_hash_bkdr(lua_tostring(L, 2), 0))
{
case 0x0F6133A2: ctx->real = (a_float)luaL_checknumber(L, 3);
break;
case 0x0E2E9172: ctx->imag = (a_float)luaL_checknumber(L, 3);
break;
case 0x001E0FA9: {
a_float const rho = (a_float)luaL_checknumber(L, 3);
a_float const theta = a_complex_arg(*ctx);
a_complex_polar(ctx, rho, theta);
break;
}
case 0x0240D1F6: {
a_float const theta = (a_float)luaL_checknumber(L, 3);
a_float const rho = a_complex_abs(*ctx);
a_complex_polar(ctx, rho, theta);
break;
}
case 0x0CD3E0FC: case 0x906DF07D: case 0x90705068: case 0x906B0E8D: case 0x906FCDE0: case 0x906E3BB4: case 0x906BDA49: case 0x906F01C8: case 0xE8859EEB: case 0xA65758B2: case 0xAEB551C6: case 0x5DA21A54: break;
default:
lua_getmetatable(L, 1);
lua_replace(L, 1);
lua_rawset(L, 1);
}
return 0;
}
static int liba_complex_get(lua_State *L)
{
a_complex const *const ctx = (a_complex const *)lua_touserdata(L, 1);
switch (a_hash_bkdr(lua_tostring(L, 2), 0))
{
case 0x0F6133A2: lua_pushnumber(L, (lua_Number)ctx->real);
break;
case 0x0E2E9172: lua_pushnumber(L, (lua_Number)ctx->imag);
break;
case 0x001E0FA9: lua_pushnumber(L, (lua_Number)a_complex_abs(*ctx));
break;
case 0x0240D1F6: lua_pushnumber(L, (lua_Number)a_complex_arg(*ctx));
break;
case 0xA65758B2: lua_registry_get(L, liba_complex_new);
lua_num_set(L, -1, "real", ctx->real);
lua_num_set(L, -1, "imag", ctx->imag);
lua_num_set(L, -1, "rho", a_complex_abs(*ctx));
lua_num_set(L, -1, "theta", a_complex_arg(*ctx));
break;
default:
lua_getmetatable(L, 1);
lua_replace(L, 1);
lua_rawget(L, 1);
}
return 1;
}
static int liba_complex_(lua_State *L)
{
lua_pushcfunction(L, liba_complex_new);
lua_replace(L, 1);
lua_call(L, lua_gettop(L) - 1, 1);
return 1;
}
int luaopen_liba_complex(lua_State *L)
{
static lua_fun const funcs[] = {
{"new", liba_complex_new},
{"rect", liba_complex_rect},
{"polar", liba_complex_polar},
{"eq", liba_complex_eq},
{"ne", liba_complex_ne},
{"logabs", liba_complex_logabs},
{"proj", liba_complex_proj},
{"conj", liba_complex_conj},
{"abs2", liba_complex_abs2},
{"abs", liba_complex_abs},
{"arg", liba_complex_arg},
{"unm", liba_complex_neg},
{"add", liba_complex_add},
{"sub", liba_complex_sub},
{"mul", liba_complex_mul},
{"div", liba_complex_div},
{"inv", liba_complex_inv},
{"pow", liba_complex_pow},
{"exp", liba_complex_exp},
{"log", liba_complex_log},
{"log2", liba_complex_log2},
{"log10", liba_complex_log10},
{"logb", liba_complex_logb},
{"sqrt", liba_complex_sqrt},
{"sin", liba_complex_sin},
{"cos", liba_complex_cos},
{"tan", liba_complex_tan},
{"sec", liba_complex_sec},
{"csc", liba_complex_csc},
{"cot", liba_complex_cot},
{"asin", liba_complex_asin},
{"acos", liba_complex_acos},
{"atan", liba_complex_atan},
{"asec", liba_complex_asec},
{"acsc", liba_complex_acsc},
{"acot", liba_complex_acot},
{"sinh", liba_complex_sinh},
{"cosh", liba_complex_cosh},
{"tanh", liba_complex_tanh},
{"sech", liba_complex_sech},
{"csch", liba_complex_csch},
{"coth", liba_complex_coth},
{"asinh", liba_complex_asinh},
{"acosh", liba_complex_acosh},
{"atanh", liba_complex_atanh},
{"asech", liba_complex_asech},
{"acsch", liba_complex_acsch},
{"acoth", liba_complex_acoth},
};
lua_createtable(L, 0, A_LEN(funcs));
lua_fun_reg(L, -1, funcs, A_LEN(funcs));
lua_createtable(L, 0, 1);
lua_fun_set(L, -1, "__call", liba_complex_);
lua_setmetatable(L, -2);
static lua_fun const metas[] = {
{"__tostring", liba_complex_tostring},
{"__newindex", liba_complex_set},
{"__index", liba_complex_get},
{"__len", liba_complex_abs},
{"__unm", liba_complex_neg},
{"__add", liba_complex_add},
{"__sub", liba_complex_sub},
{"__mul", liba_complex_mul},
{"__div", liba_complex_div},
{"__pow", liba_complex_pow},
{"__eq", liba_complex_eq},
};
lua_createtable(L, 0, A_LEN(metas) + A_LEN(funcs) + 1);
lua_fun_reg(L, -1, metas, A_LEN(metas));
lua_fun_reg(L, -1, funcs, A_LEN(funcs));
lua_str_set(L, -1, "__name", "a.complex");
lua_registry_set(L, liba_complex_new);
return 1;
}