improve call and conditions api

This commit is contained in:
Dmitriy Pleshevskiy 2024-04-20 19:11:24 +03:00
parent f3796d29b4
commit ce62a78f5a
Signed by: pleshevskiy
GPG key ID: 17041163DA10A9A2
2 changed files with 76 additions and 120 deletions

68
lib.nix
View file

@ -26,6 +26,9 @@ let
################################################################################
error = message: throw "[nix2lua] ${message}";
validationError = expr: message:
let val = if builtins.isFunction expr then "Function" else "Value '${toString expr}'"; in
error "${val} ${message}";
warn = msg: builtins.trace "[nix2lua] warning: ${msg}";
deprecated = before: now: warn "`${before}` is deprecated. Use `${now}` instead";
@ -34,11 +37,11 @@ let
validString = expr:
if isRaw expr then validString expr.raw
else if isString expr || isPath expr then toString expr
else error "Value '${toString expr}' is not a valid string";
else validationError expr "is not a valid string";
validFuncName = fnName:
if isString fnName && builtins.stringLength fnName > 0 then raw fnName
else error "Value '${toString fnName}' is not a valid function name";
else validationError fnName "is not a valid function name";
################################################################################
# Low-Level
@ -46,25 +49,16 @@ let
isRaw = expr: getType expr == "raw";
raw = expr:
if isRaw expr then
{ _type = "raw"; raw = expr.raw; }
else if isString expr then
{ _type = "raw"; raw = expr; }
else
error "Value '${toString expr}' is not supported for a raw type";
if isRaw expr then { _type = "raw"; raw = expr.raw; }
else if isString expr then { _type = "raw"; raw = expr; }
else validationError expr "is not supported for a raw type";
isJoin = expr: getType expr == "_join";
join = sep: expr:
if isList expr then { _type = "_join"; sep = validString sep; parts = expr; }
else error "Value '${toString expr}' is not supported for a join type";
else validationError expr "is not supported for a join type";
concat = join "";
concatLines = lines:
join "\n" (
lines
# add an empty line at the end
++ [ (raw "") ]
);
pipe = join ".";
pipe1 = lft: rgt: pipe [ lft rgt ];
spaceBetween = join " ";
@ -74,10 +68,17 @@ let
wrapParen = wrap "(" ")";
call = fnName: args:
concat [ (validFuncName fnName) (wrapParen (join ", " args)) ];
concat [
(validFuncName fnName)
(wrapParen (
if isList args then join ", " args
else if builtins.isFunction args then validationError args "is not supported to call args"
else args
))
];
call0 = fnName: call fnName [ ];
call1 = fnName: arg: call fnName [ arg ];
require = name: call1 "require" name;
require = name: call "require" name;
kw_and = raw "and";
kw_or = raw "or";
@ -117,36 +118,38 @@ let
or = op kw_or;
not = expr: spaceBetween [ kw_not expr ];
# Type: validBlockBody :: a -> [b]
validBlockBody = body:
if isList body then body
else if isAttrs body then [ body ]
else validationError body "is not valid block body";
local = expr: spaceBetween [ kw_local expr ];
set = variable: value: join " = " [ (raw variable) value ];
func = fnName: params: body:
let
f =
if isList body then concatLines
else if isAttrs body then spaceBetween
else error "Value ${toString body} is not a valid function body";
in
(f
(spaceBetween
([
(concat [
(spaceBetween [ kw_function (validFuncName fnName) ])
(wrapParen (join ", " (map raw params)))
])
]
++ (if isList body then body else if isAttrs body then [ body ] else [ ])
++ (validBlockBody body)
++ [ kw_end ])
);
func0 = fnName: func fnName [ ];
lambda = func "";
lambda0 = lambda [ ];
return = expr: spaceBetween ([ kw_return expr ]);
return_void = return null;
return_void = return
null;
ifelse = condition: trueBody: falseBody:
(concatLines
([ (spaceBetween [ kw_if condition kw_then ]) ]
++ trueBody
++ (if falseBody != [ ] then [ kw_else ] ++ falseBody else [ ])
(spaceBetween
([ kw_if condition kw_then ]
++ (validBlockBody trueBody)
++ (if falseBody != [ ] then [ kw_else ] ++ (validBlockBody falseBody) else [ ])
++ [ kw_end ])
);
if' = condition: trueBody: ifelse condition trueBody [ ];
@ -198,17 +201,18 @@ in
mkLuaRaw = deprecated "mkLuaRaw" "raw" raw;
mkCall = deprecated "mkCall" "call" call;
mkNamedField = deprecated "mkNamedField" "namedField" namedField;
concatLines = deprecated "concatLines" "spaceBetween" spaceBetween;
inherit toLua;
inherit LuaNil;
inherit raw join concat concatLines;
inherit raw join concat spaceBetween;
inherit pipe pipe1;
inherit namedField require local set ifelse if';
inherit call call0 call1;
inherit func lambda lambda0;
inherit func func0 lambda lambda0;
inherit op;
inherit eq ne gt lt gte lte;

View file

@ -33,11 +33,11 @@ with nix2lua; pkgs.lib.runTests {
};
"test returns a lua string" = {
expr = toLua "hello world";
expected = "\"hello world\"";
expected = ''"hello world"'';
};
"test returns a path as a lua string" = {
expr = toLua /hello/world;
expected = "\"/hello/world\"";
expected = ''"/hello/world"'';
};
"test returns an integer number" = {
expr = toLua 10;
@ -61,11 +61,11 @@ with nix2lua; pkgs.lib.runTests {
};
"test returns table with all primitive types" = {
expr = toLua [ "hello" 10 10.1 true ];
expected = "{ \"hello\", 10, 10.100000, true }";
expected = ''{ "hello", 10, 10.100000, true }'';
};
"test returns table without null values" = {
expr = toLua [ null "hello" null 10 null 10.1 null true null ];
expected = "{ \"hello\", 10, 10.100000, true }";
expected = ''{ "hello", 10, 10.100000, true }'';
};
"test returns named table" = {
expr = toLua {
@ -75,11 +75,11 @@ with nix2lua; pkgs.lib.runTests {
success = true;
fail = false;
};
expected = "{ [\"fail\"] = false, [\"float\"] = 10.100000, [\"foo\"] = \"hello\", [\"int\"] = 10, [\"success\"] = true }";
expected = ''{ ["fail"] = false, ["float"] = 10.100000, ["foo"] = "hello", ["int"] = 10, ["success"] = true }'';
};
"test returns named table without nullable items" = {
expr = toLua { foo = "hello"; bar = null; };
expected = "{ [\"foo\"] = \"hello\" }";
expected = ''{ ["foo"] = "hello" }'';
};
"test returns recursive named table" = {
expr = toLua {
@ -89,11 +89,11 @@ with nix2lua; pkgs.lib.runTests {
};
};
};
expected = "{ [\"first\"] = { [\"second\"] = { [\"last\"] = \"hello\" } } }";
expected = ''{ ["first"] = { ["second"] = { ["last"] = "hello" } } }'';
};
"test return recursive table" = {
expr = toLua [ [ [ "foo" ] "bar" ] ];
expected = "{ { { \"foo\" }, \"bar\" } }";
expected = ''{ { { "foo" }, "bar" } }'';
};
"test returns table with one named field" = {
expr = toLua [
@ -101,7 +101,7 @@ with nix2lua; pkgs.lib.runTests {
(namedField "foo" "hello")
10
];
expected = "{ \"foo\", [\"foo\"] = \"hello\", 10 }";
expected = ''{ "foo", ["foo"] = "hello", 10 }'';
};
"test returns raw string" = {
expr = toLua (raw "hello");
@ -113,7 +113,7 @@ with nix2lua; pkgs.lib.runTests {
};
"test returns path as string" = {
expr = toLua /foo/bar;
expected = "\"/foo/bar\"";
expected = ''"/foo/bar"'';
};
"test throws an error when you try to use named field withoun table" = {
expr = tryEval (toLua (namedField "foo" "bar"));
@ -121,17 +121,14 @@ with nix2lua; pkgs.lib.runTests {
};
"test returns call function with arguments" = {
expr = toLua (call "root_pattern" [ "deno.json" "deno.jsonc" ]);
expected = "root_pattern(\"deno.json\", \"deno.jsonc\")";
expected = ''root_pattern("deno.json", "deno.jsonc")'';
};
"test returns concated lines" = {
expr = toLua (concatLines [
"test returns concated expressions" = {
expr = toLua (spaceBetween [
(call "foo" [ 1 2 ])
(call "bar" [ "baz" "biz" ])
]);
expected = ''
foo(1, 2)
bar("baz", "biz")
'';
expected = ''foo(1, 2) bar("baz", "biz")'';
};
"test returns a pipe with many function call" = {
expr = toLua (pipe [
@ -149,18 +146,13 @@ with nix2lua; pkgs.lib.runTests {
expected = "local parser_config.d2 = { }";
};
"test returns all operations" = {
expr = toLua (concatLines [
(eq (mul (add 1 2) (sub 2 1)) 3)
(not (eq (mul (add 1 2) (sub 2 1)) 3))
(not 10)
(gt 10 5)
expr = toLua (spaceBetween [
(set "a" (eq (mul (add 1 2) (sub 2 1)) 3))
(set "b" (not (eq (mul (add 1 2) (sub 2 1)) 3)))
(set "c" (not 10))
(set "d" (gt 10 5))
]);
expected = ''
(((1 + 2) * (2 - 1)) == 3)
not (((1 + 2) * (2 - 1)) == 3)
not 10
(10 > 5)
'';
expected = ''a = (((1 + 2) * (2 - 1)) == 3) b = not (((1 + 2) * (2 - 1)) == 3) c = not 10 d = (10 > 5)'';
};
"test returns rendered condition" = {
expr = toLua (set "name"
@ -168,82 +160,42 @@ with nix2lua; pkgs.lib.runTests {
);
expected = "name = ((a >= 1) and (a <= 10))";
};
"test returns defined multiline function" = {
"test returns defined function" = {
expr = toLua (func "hello" [ "a" "b" ] [
(eq (mul (add (var "a") 2) (sub 2 1)) 3)
(not (eq (mul (add (var "b") 2) (sub 2 1)) 3))
(not 10)
(gt 10 5)
(set "a" (eq (mul (add 1 2) (sub 2 1)) 3))
(set "b" (not (eq (mul (add 1 2) (sub 2 1)) 3)))
(set "c" (not 10))
(set "d" (gt 10 5))
]);
expected = ''
function hello(a, b)
(((a + 2) * (2 - 1)) == 3)
not (((b + 2) * (2 - 1)) == 3)
not 10
(10 > 5)
end
'';
expected = ''function hello(a, b) a = (((1 + 2) * (2 - 1)) == 3) b = not (((1 + 2) * (2 - 1)) == 3) c = not 10 d = (10 > 5) end'';
};
"test returns defined singleline function" = {
expr = toLua (func "hello" [ "a" ] (call1 "h.world" (var "a")));
expected = "function hello(a) h.world(a) end";
};
"test returns if statement" = {
expr = toLua (if' (eq 10 10) [
(call "print" [ 10 ])
]);
expected = ''
if (10 == 10) then
print(10)
end
'';
expr = toLua (if' (eq 10 10) (call "print" [ 10 ]));
expected = ''if (10 == 10) then print(10) end'';
};
"test returns if else statement" = {
expr = toLua (ifelse (eq 10 10) [
(call "print" [ "10 == 10" ])
(call "print" "10 == 10")
(call "print" "10 == 10")
] [
(call "print" [ "10 != 10" ])
(call "print" "10 != 10")
(call "print" "10 != 10")
]);
expected = ''
if (10 == 10) then
print("10 == 10")
else
print("10 != 10")
end
'';
expected = ''if (10 == 10) then print("10 == 10") print("10 == 10") else print("10 != 10") print("10 != 10") end'';
};
"test returns a deep if else statement" = {
expr = toLua (ifelse (eq 10 10) [
(if' true [ (call "print" [ "yes" ]) ])
] [
(if' true [ (call "print" [ "no" ]) ])
]);
expected = ''
if (10 == 10) then
if true then
print("yes")
end
else
if true then
print("no")
end
end
'';
expr = toLua (ifelse (eq 10 10)
(if' true (call "print" "yes"))
(if' true (call "print" "no"))
);
expected = ''if (10 == 10) then if true then print("yes") end else if true then print("no") end end'';
};
"test returns a returns keyword" = {
expr = toLua (ifelse (eq 10 10) [
return_void
] [
(return 10)
]);
expected = ''
if (10 == 10) then
return
else
return 10
end
'';
expr = toLua (ifelse (eq 10 10) return_void (return 10));
expected = ''if (10 == 10) then return else return 10 end'';
};
}