From cd9822fcf28a2e0ea4f688d7207a5682fb34eb6e Mon Sep 17 00:00:00 2001 From: vaclavt Date: Sun, 13 Mar 2022 10:32:43 +0100 Subject: [PATCH] string-cmp and string-cmp-ic added --- Readme.md | 1 - doc/Doc.md | 2 ++ ml.cpp | 18 ++++++++++++++++++ ml.h | 1 + stdlib/stdlib.lsp | 2 ++ tests/test.lsp | 2 ++ usql/parser.h | 2 +- 7 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 33843d7..0bfebd8 100644 --- a/Readme.md +++ b/Readme.md @@ -89,7 +89,6 @@ utils/local_install.sh #### Language - string functions - - compare - needed for sorting, cmp ignore case - regexp match, regexp tokens #### Performance diff --git a/doc/Doc.md b/doc/Doc.md index 30f33e0..f0ac2c9 100644 --- a/doc/Doc.md +++ b/doc/Doc.md @@ -134,6 +134,8 @@ |`(string-len str)`|Returns string length|`>>> (string-len "abcdef") => 6`|String manipulation| |`(string-substr str pos len)`|Returns substring from str starting at pos with len. If pos is negative returns substring from the end of string. First character is on pos 0|`>>> (string-substr "ABCD" -2 2) => "CD"`|String manipulation| |`(string-find str lookup pos)`|Returns position of lookup in str starting on position. First char index is 0. If not found returns nil|`>>> (string-find " long long int;" "long" 2) => 6`|String manipulation| +|`(string-cmp str1 str2)`|Compares two strings. Returns 0 where strangs are equal; < 0 when the value of the first character that does not match is lower in the compared string, or all compared characters match but the compared string is shorter.; >0 when the value of the first character that does not match is greater in the compared string, or all compared characters match but the compared string is longer.|`>>> (string-cmp "aaa" "xaa") => -23`|String manipulation| +|`(string-cmp-ic str1 str2)`|Compares two strings ignoring case. Returns 0, < 0, > 0.|`>>> (string-cmp-ic "aaa" "AaA") => 0`|String manipulation| |`(int value)`|Cast an item to an int|`>>> (int 3.41) => 3`|Type casting| |`(float value)`|Cast item to a float|`>>> (int 3.41) => 3.14`|Type casting| |`(string value)`|Cast int or float item to a string|`>>> (string 3.14) => "3.14"`|Type casting| diff --git a/ml.cpp b/ml.cpp index c90b3d8..7d27f57 100644 --- a/ml.cpp +++ b/ml.cpp @@ -184,6 +184,10 @@ std::vector MlValue::get_used_atoms() { } } +bool MlValue::is_nil() const { + return type == NIL; +} + bool MlValue::is_builtin() const { return type == BUILTIN; } @@ -1857,6 +1861,19 @@ MlValue string_find(std::vector args, MlEnvironment &env) { return pos == -1 ? MlValue::nil() : MlValue((long) pos); } +MlValue string_cmp(std::vector args, MlEnvironment &env) { + eval_args(args, env); + + if (args.size() != 2) + throw MlError(MlValue("string-cmp", string_cmp), env, args.size() > 2 ? TOO_MANY_ARGS : TOO_FEW_ARGS); + + if ( (args[0].is_nil() || (args[0].is_list() && args[0].as_list().empty())) || + (args[1].is_nil() || (args[1].is_list() && args[1].as_list().empty())) ) + return MlValue::nil(); + + + return MlValue((long)args[0].as_string().compare(args[1].as_string())); +} // trims characters " \n\r\t" from left or right or both ends of a string MlValue string_rltrim(std::vector args, MlEnvironment &env) { @@ -2240,6 +2257,7 @@ std::map builtin_funcs std::make_pair("string-len", builtin::string_len), std::make_pair("string-substr", builtin::string_substr), std::make_pair("string-find", builtin::string_find), + std::make_pair("string-cmp", builtin::string_cmp), // Casting operations std::make_pair("int", builtin::cast_to_int), diff --git a/ml.h b/ml.h index 84ccaec..3ddcce6 100644 --- a/ml.h +++ b/ml.h @@ -141,6 +141,7 @@ public: // Evaluate this value as lisp code. MlValue eval(MlEnvironment &env); + bool is_nil() const; bool is_builtin() const; bool is_macro() const; bool is_number() const; diff --git a/stdlib/stdlib.lsp b/stdlib/stdlib.lsp index 5e5ad0a..59beea0 100644 --- a/stdlib/stdlib.lsp +++ b/stdlib/stdlib.lsp @@ -26,6 +26,8 @@ (defn string-downcase (str) (string-case str "lower")) +(defn string-cmp-ic (a b) + (string-cmp (string-upcase a) (string-upcase b))) (defn string-join (lst sep) (do diff --git a/tests/test.lsp b/tests/test.lsp index a71ba42..7d1fd79 100644 --- a/tests/test.lsp +++ b/tests/test.lsp @@ -101,6 +101,8 @@ (ut::define-test "result of (string-find \" long long int;\" \" \")" '(ut::assert-equal 0 (string-find " long long int;" " "))) (ut::define-test "result of (string-find \" long long int;\" \"o\")" '(ut::assert-equal 2 (string-find " long long int;" "o"))) (ut::define-test "result of (string-find \" long long int;\" \"float\")" '(ut::assert-nil (string-find " long long int;" "float"))) +(ut::define-test "result of (string-cmp \"aaa\" \"aaa\")" '(ut::assert-equal 0 (string-cmp "aaa" "aaa"))) +(ut::define-test "result of (string-cmp-ic \"aaa\" \"AaA\")" '(ut::assert-equal 0 (string-cmp-ic "aaa" "AaA"))) (ut::define-test "result of (is-pos? -1)" '(ut::assert-false (is-pos? -1))) (ut::define-test "result of (is-neg? -1)" '(ut::assert-true (is-neg? -1))) diff --git a/usql/parser.h b/usql/parser.h index b7efea5..ee09e75 100644 --- a/usql/parser.h +++ b/usql/parser.h @@ -145,7 +145,7 @@ struct FunctionNode : Node { if (str=="pp") return Type::pp; if (str=="lower") return Type::lower; if (str=="upper") return Type::upper; - if (str=="coalesce") return Type::coalesce; + if (str=="coalesce") return Type::coalesce; if (str=="min") return Type::min; if (str=="max") return Type::max; if (str=="count") return Type::count;