From 0f184461fea3bbee7105d927234722717357413b Mon Sep 17 00:00:00 2001 From: vaclavt Date: Fri, 25 Feb 2022 00:04:14 +0100 Subject: [PATCH] new functions, doc updates --- Readme.md | 7 +----- doc/Doc.md | 9 +++++--- ml.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++ stdlib/stdlib.lsp | 5 +---- tests/test.lsp | 11 ++++++---- 5 files changed, 70 insertions(+), 17 deletions(-) diff --git a/Readme.md b/Readme.md index e82440b..ca453ef 100644 --- a/Readme.md +++ b/Readme.md @@ -80,10 +80,8 @@ utils/local_install.sh - better output of !e in repl (resp !e !ee) #### Doc -- fix an error in printing multiline examples in doc -- string-case, save-csv fix doc +- string-case, make-csv fix doc - add functions from stdlib into doc -- fix man entry on (member) example and retval - doc for set! #### Code @@ -95,9 +93,6 @@ utils/local_install.sh - string functions - compare - needed for sorting, cmp ignore case - regexp match, regexp tokens -- env functions - - get-env, set-env; set-env cannot be implemented in stdlib.lsp, because popen is in fact subshell -- macros and then loop, let etc #### Performance - push_back - repeatedly without reserving size diff --git a/doc/Doc.md b/doc/Doc.md index 93b5fd7..9ea7b90 100644 --- a/doc/Doc.md +++ b/doc/Doc.md @@ -65,7 +65,7 @@ |`(first list)`|Returns first element of a list|`>>> (first '(1 2 3)) => 1`|List manipulation| |`(last list)`|Returns last element of list|`>>> (last '(1 2 3)) => 2`|List manipulation| |`(range low high)`|Returns list with elements in range low .. high|`(range 1 5) => (1 2 3 4)`|List manipulation| -|`(member lst item)`|Returns #t when item is inluded in lst otherwise nil||List manipulation| +|`(member lst item)`|Returns #t when item is inluded in lst otherwise nil|`>>> (member '(1 2 3) 1) => #t`|List manipulation| |`(uniq list)`|Filter out any duplicates from list|`>>> (uniq '(1 2 2 3 4 5 2 2)) => (1 2 3 4 5)`|List manipulation| |`(flatten list)`|Flattens a list to single level|`>>> (flatten '(1 (2 2) 3)) => (1 2 2 3)`|List manipulation| |`(take list count)`|Returns sublist with count element of list|`>>> (take '(1 2 3 4) 3) => (1 2 3)`|List manipulation| @@ -83,6 +83,8 @@ |`(input [prompt])`|Get user input with an optional prompt||IO| |`(random low high)`|Get a random number between two numbers inclusively||System| |`(include file)`|Read a file and execute its code||IO| +|`(read)`|Reads in the printed representation of a Lisp object from input-stream, builds a corresponding Lisp object, and returns the object||IO| +|`(read-line)`|Reads in a line of text terminated by a newline||IO| |`(read-file filename)`|Get the contents of a file||IO| |`(read-file-lines filename lambda)`|Reads file and for each line call lambda with passing the line as a parameter|`(read-file-lines "/tmp/f.txt" (lambda (ln) (print ln))`|IO| |`(write-file filename content-str)`|Write a string to a file||IO| @@ -94,9 +96,9 @@ |`(tcp-server port handler)`|Starts listening on port and when request comes calls passed lambda and writes its returned value back to client. Lambda must return either string or two element list where first element is boolean and second string.When first element is true it closes listening socker.|(`tcp-server 7777 (lambda (str) (list #t (string-upcase str))))`|IO| |`(tcp-client address port data)`|Opens connection to server on port, writes there data and returns response.|`(print (tcp-client "127.0.0.1" 7777 "abcd"))`|IO| |`(is-dir? filename)`|Returns true if passed filename is a directory||IO| -|`(parse-csv string)`|Parse CSV string||String manipulation| +|`(parse-csv string)`|Parse CSV string|`>>> (make-csv '(("A" "B")(1 1)(2 2))) => "A,B\n1,1\n2,2"`|String manipulation| |`(parse-json json_string)`|Parse JSON string||String manipulation| -|`(save-csv ..)`|Save list as csv||IO| +|`(make-csv ..)`|Returns list as csv string||IO| |`(get-universal-time)`|Get current time as secs from epoch|`>>> (get-universal-time) => 1642152733`|Date and time| |`(get-localtime-offset)`|Offset in seconds between local time and gmt time||Date and time| |`(date-to-str date format)`|Converts date to formated string. Format is strftime format (https://www.tutorialspoint.com/c_standard_library/c_function_strftime.htm)|`>>> (date-to-str (get-universal-time) "%Y-%m-%d %H:%M:%S") => "2021-03-13 19:53:01"`|Date and time| @@ -165,6 +167,7 @@ |`(doc::look "string")`|Alias for appropos||Language| |`(doc::lookup "string")`|Alias for appropos||Language| |`(get-env var)`|Return environment variable var|`>>> (get-env "HOME") => "/Users/vaclavt"`|System| +|`(set-env var value)`|Sets environment variable var to value|`>>> (set-env "XXYYZZ" "haha") => "haha"`|System| |`(second list)`|Returns second element of list|`>>> (second '(1 2 3 4 5 6 7)) => 2`|List manipulation| |`(third list)`|Returns third element of list|`>>> (third '(1 2 3 4 5 6 7)) => 3`|List manipulation| |`(fourth list)`|Returns fourth element of list|`>>> (fourth '(1 2 3 4 5 6 7)) => 4`|List manipulation| diff --git a/ml.cpp b/ml.cpp index edd790b..7e9d1e5 100644 --- a/ml.cpp +++ b/ml.cpp @@ -1153,6 +1153,30 @@ MlValue parse_csv(std::vector args, MlEnvironment &env) { return csv.parseCSV(args[0].as_string()); } +// Reads in the printed representation of a Lisp object from input-stream, builds a corresponding Lisp object, and returns the object +MlValue read(std::vector args, MlEnvironment &env) { + eval_args(args, env); + + if (args.size() != 0) + throw MlError(MlValue("read", read), env, TOO_MANY_ARGS); + + std::string line; + std::getline(std::cin, line); + return run(line, env); +} + +// Read line from stdin +MlValue read_line(std::vector args, MlEnvironment &env) { + eval_args(args, env); + + if (args.size() != 0) + throw MlError(MlValue("read-line", read_line), env, TOO_MANY_ARGS); + + std::string line; + std::getline(std::cin, line); + return MlValue::string(line); +} + // Get the contents of a file MlValue read_file(std::vector args, MlEnvironment &env) { eval_args(args, env); @@ -1346,6 +1370,7 @@ MlValue is_dir(std::vector args, MlEnvironment &env) { return MlValue(is_path_dir(args[0].as_string())); } +// starts tcp listening server MlValue tcp_server(std::vector args, MlEnvironment &env) { eval_args(args, env); @@ -1369,6 +1394,7 @@ MlValue tcp_server(std::vector args, MlEnvironment &env) { return MlValue((long)r); } +// tcp client MlValue tcp_client(std::vector args, MlEnvironment &env) { eval_args(args, env); @@ -1389,6 +1415,31 @@ MlValue tcp_client(std::vector args, MlEnvironment &env) { } } +// get environment variable +MlValue get_env(std::vector args, MlEnvironment &env) { + eval_args(args, env); + + if (args.size() != 1) + throw MlError(MlValue("get-env", get_env), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS); + + if (const char* env_p = std::getenv(args[0].as_string().c_str())) + return MlValue::string(env_p); + else + return MlValue::nil(); +} + +// set environment variable +MlValue set_env(std::vector args, MlEnvironment &env) { + eval_args(args, env); + + if (args.size() != 2) + throw MlError(MlValue("set-env", set_env), env, args.size() > 2 ? TOO_MANY_ARGS : TOO_FEW_ARGS); + + setenv(args[0].as_string().c_str(), args[1].as_string().c_str(), true); + + return args[1]; +} + // Read a file and execute its code MlValue include(std::vector args, MlEnvironment &env) { eval_args(args, env); @@ -2160,6 +2211,8 @@ std::map builtin_funcs std::make_pair("input", builtin::input), std::make_pair("random", builtin::random), std::make_pair("include", builtin::include), + std::make_pair("read", builtin::read), + std::make_pair("read-line", builtin::read_line), std::make_pair("read-file", builtin::read_file), std::make_pair("read-file-lines", builtin::read_file_lines), std::make_pair("write-file", builtin::write_file), @@ -2170,6 +2223,8 @@ std::map builtin_funcs std::make_pair("is-dir?", builtin::is_dir), std::make_pair("tcp-server", builtin::tcp_server), std::make_pair("tcp-client", builtin::tcp_client), + std::make_pair("get-env", builtin::get_env), + std::make_pair("set-env", builtin::set_env), // parsing operations std::make_pair("parse-csv", builtin::parse_csv), diff --git a/stdlib/stdlib.lsp b/stdlib/stdlib.lsp index 7b000e1..0761c86 100644 --- a/stdlib/stdlib.lsp +++ b/stdlib/stdlib.lsp @@ -46,9 +46,6 @@ (defn sleep (time) (system-cmd (+ "sleep " (string time)))) -(defn get-env (var) - (second (system-cmd (+ "echo ${" var "} | tr -d \"\n\"")))) - (defn third (l) (index l 2)) (defn fourth (l) (index l 3)) @@ -196,7 +193,7 @@ (def c 0) (for col row (if (= c 0) - (def cols_str col) + (def cols_str (display col)) (def cols_str (+ cols_str "," (display col)))) (def c (inc c))) (if (= r 0) diff --git a/tests/test.lsp b/tests/test.lsp index 84717b7..8ffbc93 100644 --- a/tests/test.lsp +++ b/tests/test.lsp @@ -43,11 +43,11 @@ (ut::define-test "result of (def a 20) (cond ((> a 30)" '(ut::assert-equal "a <= 20" (cond ((> a 30) "a > 30") ((> a 20) "a > 20")(#t "a <= 20")))) (ut::define-test "result of (def b 30) (cond ((> b 30)" '(ut::assert-equal "b > 20" (cond ((> b 30) "b > 30") ((> b 20) "b > 20")(#t "b <= 20")))) -(ut::define-test "result of (member '(1 2 3) 1" '(ut::assert-true (member '(1 2 3) 1))) -(ut::define-test "result of (member '(1 2 3) 3" '(ut::assert-true (member '(1 2 3) 3))) -(ut::define-test "result of (member '(1 2 3) 4" '(ut::assert-false (member '(1 2 3) 4))) +(ut::define-test "result of (member '(1 2 3) 1)" '(ut::assert-true (member '(1 2 3) 1))) +(ut::define-test "result of (member '(1 2 3) 3)" '(ut::assert-true (member '(1 2 3) 3))) +(ut::define-test "result of (member '(1 2 3) 4)" '(ut::assert-false (member '(1 2 3) 4))) -(ut::define-test "result of (take '(1 2 3 4) 3" '(ut::assert-equal '(1 2 3) (take '(1 2 3 4) 3))) +(ut::define-test "result of (take '(1 2 3 4) 3)" '(ut::assert-equal '(1 2 3) (take '(1 2 3 4) 3))) (ut::define-test "result of (make-list 3)" '(ut::assert-equal '(nil nil nil) (make-list 3))) (ut::define-test "result of (make-list-of 3 999)" '(ut::assert-equal '(999 999 999) (make-list-of 3 999))) @@ -115,6 +115,8 @@ (ut::define-test "result of (sprintf \"%.2f\" '(1.23456))" '(ut::assert-equal "1.23" (sprintf "%.2f" '(1.23456)))) (ut::define-test "result of (sprintf \"%.d\" '(10000000))" '(ut::assert-equal "10000000" (sprintf "%.d" '(10000000)))) +(ut::define-test "result of (set-env \"XXYYZZ\" \"haha\")" '(ut::assert-equal "haha" (set-env "XXYYZZ" "haha"))) +(ut::define-test "result of (get-env \"XXYYZZ\")" '(ut::assert-equal "haha" (get-env "XXYYZZ"))) (ut::define-test "result of (get-env \"HOME\")" '(ut::assert-equal "/Users/vaclavt" (get-env "HOME"))) (ut::define-test "result of (!= nil nil)" '(ut::assert-false (!= nil nil))) @@ -138,6 +140,7 @@ (ut::define-test "result of (end-of-year)" '(ut::assert-equal 1640995199 (end-of-year (str-to-date "2021-05-13 10:32:12" "%Y-%m-%d %H:%M:%S")))) (ut::define-test "result of (decode-universal-time 0)" '(ut::assert-equal '(0 0 0 1 1 1970 4) (decode-universal-time 0))) +;(ut::define-test "result of (print ( + 15.0 (read)))" '(ut::assert-equal 30 (print ( + 15.0 (read))))) (ut::define-test "result of (read-file-lines \"/tmp/f.txt\" counter)" '(ut::assert-equal 3 (read-file-lines "/tmp/f.txt" counter))) (ut::define-test "result of create table" '(ut::assert-equal ((0 "table created" 0)) (usql "create table a (i integer not null, s varchar(64), f float null, d date null, b boolean)")))