added two string functions, doc updates
This commit is contained in:
parent
783aa6976b
commit
a752ebdf12
|
|
@ -1,15 +1,12 @@
|
||||||
|
|
||||||
### BUGS
|
### BUGS
|
||||||
- (read-file "nonexisting/file.csv") shows only "could not open file" - should print filename
|
- (read-file "nonexisting/file.csv") shows only "could not open file" - should print filename
|
||||||
- error: the expression `("/usr/local/var/mlisp")` with message "cannot cast" - should add to what is casting
|
|
||||||
- better error reporting..for example ls_dir on non existing dir should prind `pwd` dir
|
- better error reporting..for example ls_dir on non existing dir should prind `pwd` dir
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
- add debug support, at least call stack
|
- add debug support, at least call stack
|
||||||
- add stdtest - to test every functionality
|
|
||||||
- add parenthesis coloring into linenoise
|
|
||||||
- multiline editing (kilo editor)
|
- multiline editing (kilo editor)
|
||||||
- execute system command should capture stderr
|
- execute system command should capture stderr
|
||||||
- add some mem stats to benchmark
|
- add some mem stats to benchmark
|
||||||
|
|
|
||||||
47
doc/Doc.md
47
doc/Doc.md
|
|
@ -57,7 +57,7 @@
|
||||||
|`(include file)`|Read a file and execute its code||
|
|`(include file)`|Read a file and execute its code||
|
||||||
|`(read-file filename)`|Get the contents of a file||
|
|`(read-file filename)`|Get the contents of a file||
|
||||||
|`(write-file filename)`|Write a string to a file||
|
|`(write-file filename)`|Write a string to a file||
|
||||||
|`(read-url url [headers])`|Reads URL|Returnd list (status_code content)|
|
|`(read-url url [headers])`|Reads URL|Returns list (status_code content)|
|
||||||
|`(system-cmd command_str)`|Execute system command||
|
|`(system-cmd command_str)`|Execute system command||
|
||||||
|`(ls-dir ..)`|List a dir|List of directory entries|
|
|`(ls-dir ..)`|List a dir|List of directory entries|
|
||||||
|`(is-file? ..)`|Returns true if passed filename is a file||
|
|`(is-file? ..)`|Returns true if passed filename is a file||
|
||||||
|
|
@ -77,7 +77,7 @@
|
||||||
|`(string-pad str len char rpad_lpad)`|||
|
|`(string-pad str len char rpad_lpad)`|||
|
||||||
|`(string-lpad str len char)`|Pad string from start with char to length len|`>>> (string-lpad "0" 10 "x") => "xxxxxxxxx0"`|
|
|`(string-lpad str len char)`|Pad string from start with char to length len|`>>> (string-lpad "0" 10 "x") => "xxxxxxxxx0"`|
|
||||||
|`(string-rpad str len char)`|Pad string from righ with char to length len|`>>> (string-rpad "0" 10 "x") => "0xxxxxxxxx"`|
|
|`(string-rpad str len char)`|Pad string from righ with char to length len|`>>> (string-rpad "0" 10 "x") => "0xxxxxxxxx"`|
|
||||||
|`(string-split str separator)`|||
|
|`(string-split str separator)`|Splits string into list by regexp|`>>> (string-split "split me by space" "\s+") => ("split" "me" "by" "space")`|
|
||||||
`(string-rltrim str len RKRRKR)`| ||
|
`(string-rltrim str len RKRRKR)`| ||
|
||||||
`(string-ltrim str)`|Removes " \n\r\t" from the begininfg of str||
|
`(string-ltrim str)`|Removes " \n\r\t" from the begininfg of str||
|
||||||
`(string-rtrim str)`|Removes " \n\r\t" from the end of str||
|
`(string-rtrim str)`|Removes " \n\r\t" from the end of str||
|
||||||
|
|
@ -85,24 +85,26 @@
|
||||||
`(string-case str RKRRKR)`|||
|
`(string-case str RKRRKR)`|||
|
||||||
`(string-upcase str)`|Returns up cased string|`>>> (string-upcase "abcdefghchijklmn") => "ABCDEFGHCHIJKLMN"`|
|
`(string-upcase str)`|Returns up cased string|`>>> (string-upcase "abcdefghchijklmn") => "ABCDEFGHCHIJKLMN"`|
|
||||||
`(string-downcase str)`|Returns down cased string |`>>> (string-downcase "ABCDefghchijklmn") => "abcdefghchijklmn"`|
|
`(string-downcase str)`|Returns down cased string |`>>> (string-downcase "ABCDefghchijklmn") => "abcdefghchijklmn"`|
|
||||||
`(string-join lst sep)`|Returns string created as elements of concatenation of lst elements separated by sep||
|
`(string-join lst sep)`|Returns string created as elements of concatenation of lst elements separated by sep|`>>> (string-join ("A" "B" "C" "D") ",") => "A,B,C,D"`|
|
||||||
`(endl)`|||
|
`(string-len str)`|Returns string length|`>>> (string-len "abcdef") => 6`|
|
||||||
|
`(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|`>>> (string-substr "ABCD" -2 2) => "CD"`|
|
||||||
|
`(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`|
|
||||||
|`(int value)`|Cast an item to an int|`>>> (int 3.41) => 3`|
|
|`(int value)`|Cast an item to an int|`>>> (int 3.41) => 3`|
|
||||||
|`(float value)`|Cast item to a float|`>>> (int 3.41) => 3.14`|
|
|`(float value)`|Cast item to a float|`>>> (int 3.41) => 3.14`|
|
||||||
|`(string value)`|Cast int or float item to a string|`>>> (string 3.14) => "3.14"`|
|
|`(string value)`|Cast int or float item to a string|`>>> (string 3.14) => "3.14"`|
|
||||||
|`(eval <exp>)`|Eval returns the value of the second evaluation|`>>> (eval '(+ 1 2)) => 3`|
|
|`(eval <exp>)`|Eval returns the value of the second evaluation|`>>> (eval '(+ 1 2)) => 3`|
|
||||||
|`(type e)`|Returns data type of e|`>>> (type (+ 1 2)) => "int"`|
|
|`(type e)`|Returns data type of e|`>>> (type (+ 1 2)) => "int"`|
|
||||||
|`(parse ..)`|||
|
|`(parse ..)`||`>>> (eval (first (parse "(+ 1 2)"))) => 3`|
|
||||||
|`(make-list-of size value)`|Makes list with size elements of values||
|
|`(make-list-of size value)`|Makes list with size elements of values|`>>> (make-list-of 5 0) => (0 0 0 0 0)`|
|
||||||
|`(make-list size)`|Makes list of nil values with size length||
|
|`(make-list size)`|Makes list of nil values with size length|`>>> (make-list 5) => (nil nil nil nil nil)`|
|
||||||
|`(empty-list? lst)`|Return true is lst is list with zero elements||
|
|`(empty-list? lst)`|Return true is lst is list with zero elements|`>>> (empty-list? '()) => 1`|
|
||||||
|`(memeber lst item)`|Returns 1 when item is inluded in lst otherwise 0||
|
|`(memeber lst item)`|Returns 1 when item is inluded in lst otherwise 0||
|
||||||
|`(uniq list)`|Filter out any duplicates from list|`>>> (uniq '(1 2 2 3 4 5 2 2)) => (1 2 3 4 5)`|
|
|`(uniq list)`|Filter out any duplicates from list|`>>> (uniq '(1 2 2 3 4 5 2 2)) => (1 2 3 4 5)`|
|
||||||
|`(flatten list)`||`>>> (flatten '(1 (2 2) 3)) => (1 2 2 3)`|
|
|`(flatten list)`||`>>> (flatten '(1 (2 2) 3)) => (1 2 2 3)`|
|
||||||
|`(quick-sort-by list cmp)`|||
|
|`(quick-sort-by list cmp)`|||
|
||||||
|`(quick-sort list)`|return sorted list|`>>> (quick-sort '(2 4 6 1 7 3 3 9 5)) => (1 2 3 3 4 5 6 7 9)`|
|
|`(quick-sort list)`|return sorted list|`>>> (quick-sort '(2 4 6 1 7 3 3 9 5)) => (1 2 3 3 4 5 6 7 9)`|
|
||||||
|`(not c)`|Logical NOT of c||
|
|`(not c)`|Logical NOT of c|`>>> (not 1) => nil`|
|
||||||
|`(new n)`|Negates number||
|
|`(neg n)`|Negates number|`>>> (neg -5) => 5`|
|
||||||
|`(is-pos? n)`|Returns true if n is positive number||
|
|`(is-pos? n)`|Returns true if n is positive number||
|
||||||
|`(is-neg? n)`|Returns true if n is negative number||
|
|`(is-neg? n)`|Returns true if n is negative number||
|
||||||
|`(dec n)`|Return n decremented by 1|`>>> (dec 5) => 4`|
|
|`(dec n)`|Return n decremented by 1|`>>> (dec 5) => 4`|
|
||||||
|
|
@ -115,29 +117,6 @@
|
||||||
|`(fifth l)`|Returns fifth element of list||
|
|`(fifth l)`|Returns fifth element of list||
|
||||||
|`(nth i l)`|Return i-th elemenet of list. First element has index 1||
|
|`(nth i l)`|Return i-th elemenet of list. First element has index 1||
|
||||||
|`( make-csv list)`|creates csv string from list of lists|(print (make-csv '(("r1c1" "r1c2") ("r2c1" "r2c2"))))
|
|`( make-csv list)`|creates csv string from list of lists|(print (make-csv '(("r1c1" "r1c2") ("r2c1" "r2c2"))))
|
||||||
|`(sprintf ..)`|||
|
|`(sprintf ..)`||`>>> (sprintf "%s, %d, %.2f" (list "string" 1000 3.14)) => "string, 1000, 3.14"`|
|
||||||
|
|
||||||
|`(xx ..)`|||
|
|`(xx ..)`|||
|
||||||
|
|
||||||
```
|
|
||||||
(define term-rst-esc "\x1B[0m")
|
|
||||||
(define term-red-esc '"\x1B[31m")
|
|
||||||
(define term-green-esc "\x1B[32m")
|
|
||||||
(define term-yellow-esc "\x1B[33m")
|
|
||||||
(define term-blue-esc "\x1B[34m")
|
|
||||||
(define term-magenta-esc "\x1B[35m")
|
|
||||||
(define term-cyan-esc "\x1B[36m")
|
|
||||||
(define term-white-esc "\x1B[37m")
|
|
||||||
(define term-bold-esc "\x1B[1m")
|
|
||||||
(define term-underline-esc "\x1B[4m")
|
|
||||||
|
|
||||||
(defun term-red (str) (sprintf (+ term-red-esc str term-rst-esc)))
|
|
||||||
(defun term-green (str) (sprintf (+ term-green-esc str term-rst-esc)))
|
|
||||||
(defun term-yellow (str) (sprintf (+ term-yellow-esc str term-rst-esc)))
|
|
||||||
(defun term-blue (str) (sprintf (+ term-blue-esc str term-rst-esc)))
|
|
||||||
(defun term-magenta (str) (sprintf (+ term-magenta-esc str term-rst-esc)))
|
|
||||||
(defun term-cyan (str) (sprintf (+ term-cyan-esc str term-rst-esc)))
|
|
||||||
(defun term-white (str) (sprintf (+ term-white-esc str term-rst-esc)))
|
|
||||||
(defun term-bold (str) (sprintf (+ term-bold-esc str term-rst-esc)))
|
|
||||||
(defun term-underline (str) (sprintf (+ term-underline-esc str term-rst-esc)))
|
|
||||||
```
|
|
||||||
44
ml.cpp
44
ml.cpp
|
|
@ -40,6 +40,7 @@
|
||||||
#define INTERNAL_ERROR "internal virtual machine error"
|
#define INTERNAL_ERROR "internal virtual machine error"
|
||||||
#define INDEX_OUT_OF_RANGE "index out of range"
|
#define INDEX_OUT_OF_RANGE "index out of range"
|
||||||
#define MALFORMED_PROGRAM "malformed program"
|
#define MALFORMED_PROGRAM "malformed program"
|
||||||
|
#define NOT_IMPLEMENTED_YET_ERROR "not implemented yet"
|
||||||
|
|
||||||
|
|
||||||
#define STRING_TYPE "string"
|
#define STRING_TYPE "string"
|
||||||
|
|
@ -1552,9 +1553,6 @@ namespace builtin {
|
||||||
throw MlError(args[0], env, INVALID_ARGUMENT);
|
throw MlError(args[0], env, INVALID_ARGUMENT);
|
||||||
std::vector<MlValue> parsed = ::parse(args[0].as_string());
|
std::vector<MlValue> parsed = ::parse(args[0].as_string());
|
||||||
|
|
||||||
// if (parsed.size() == 1)
|
|
||||||
// return parsed[0];
|
|
||||||
// else return MlValue(parsed);
|
|
||||||
return MlValue(parsed);
|
return MlValue(parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1602,11 +1600,46 @@ namespace builtin {
|
||||||
eval_args(args, env);
|
eval_args(args, env);
|
||||||
|
|
||||||
if (args.size() != 2)
|
if (args.size() != 2)
|
||||||
throw MlError(MlValue("string_case", string_case), env, args.size() > 2 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
|
throw MlError(MlValue("string-case", string_case), env, args.size() > 2 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
|
||||||
|
|
||||||
return MlValue::string(string_lucase(args[0].as_string(), args[1].as_string()));
|
return MlValue::string(string_lucase(args[0].as_string(), args[1].as_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MlValue string_len(std::vector<MlValue> args, MlEnvironment &env) {
|
||||||
|
eval_args(args, env);
|
||||||
|
|
||||||
|
if (args.size() != 1)
|
||||||
|
throw MlError(MlValue("string-len", string_len), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
|
||||||
|
|
||||||
|
return MlValue{(long)args[0].as_string().size()};
|
||||||
|
}
|
||||||
|
|
||||||
|
MlValue string_substr(std::vector<MlValue> args, MlEnvironment &env) {
|
||||||
|
eval_args(args, env);
|
||||||
|
|
||||||
|
if (args.size() < 1 || args.size() > 3)
|
||||||
|
throw MlError(MlValue("string-substr", string_substr), env, args.size() > 3 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
|
||||||
|
|
||||||
|
const std::string& str = args[0].as_string();
|
||||||
|
long pos = args.size() > 1 ? args[1].as_int() : 0;
|
||||||
|
long count = args.size() > 2 ? args[2].as_int() : str.size();
|
||||||
|
|
||||||
|
return MlValue::string(string_substring(str, pos, count));
|
||||||
|
}
|
||||||
|
|
||||||
|
MlValue string_find(std::vector<MlValue> args, MlEnvironment &env) {
|
||||||
|
eval_args(args, env);
|
||||||
|
|
||||||
|
if (args.size() < 2 || args.size() > 3)
|
||||||
|
throw MlError(MlValue("string-find", string_find), env, args.size() > 3 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
|
||||||
|
|
||||||
|
size_t start_pos = args.size() > 2 ? args[2].as_int() : 0;
|
||||||
|
size_t pos = string_find_substr(args[0].as_string(), args[1].as_string(), start_pos);
|
||||||
|
|
||||||
|
return pos == -1 ? MlValue::nil() : MlValue((long)pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// trims characters " \n\r\t" from left or right or both ends of a string
|
// trims characters " \n\r\t" from left or right or both ends of a string
|
||||||
MlValue string_rltrim(std::vector<MlValue> args, MlEnvironment &env) {
|
MlValue string_rltrim(std::vector<MlValue> args, MlEnvironment &env) {
|
||||||
eval_args(args, env);
|
eval_args(args, env);
|
||||||
|
|
@ -1966,6 +1999,9 @@ MlValue MlEnvironment::get(const std::string &name) const {
|
||||||
if (name == "string-pad") return MlValue("string-pad", builtin::string_pad);
|
if (name == "string-pad") return MlValue("string-pad", builtin::string_pad);
|
||||||
if (name == "string-rltrim") return MlValue("string-rltrim", builtin::string_rltrim);
|
if (name == "string-rltrim") return MlValue("string-rltrim", builtin::string_rltrim);
|
||||||
if (name == "string-case") return MlValue("string-case", builtin::string_case);
|
if (name == "string-case") return MlValue("string-case", builtin::string_case);
|
||||||
|
if (name == "string-len") return MlValue("string-len", builtin::string_len);
|
||||||
|
if (name == "string-substr") return MlValue("string-substr", builtin::string_substr);
|
||||||
|
if (name == "string-find") return MlValue("string-find", builtin::string_find);
|
||||||
|
|
||||||
// Casting operations
|
// Casting operations
|
||||||
if (name == "int") return MlValue("int", builtin::cast_to_int);
|
if (name == "int") return MlValue("int", builtin::cast_to_int);
|
||||||
|
|
|
||||||
|
|
@ -77,3 +77,28 @@ std::string string_padd(const std::string &str, int pad_len, char fill_char, boo
|
||||||
else
|
else
|
||||||
return std::string(pad_len - str.size(), fill_char) + str;
|
return std::string(pad_len - str.size(), fill_char) + str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string string_substring(const std::string & str, long pos, long count) {
|
||||||
|
size_t start_pos = pos;
|
||||||
|
|
||||||
|
if (pos < 0) {
|
||||||
|
start_pos = str.size() - abs(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (start_pos >= str.size()) || (count < 1) || (start_pos < 0) ) {
|
||||||
|
throw std::invalid_argument("Invalid parameter(s) for string-substr.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.substr(start_pos, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t string_find_substr(const std::string & str, const std::string & pattern, long pos) {
|
||||||
|
if (pos >= str.size()) {
|
||||||
|
throw std::invalid_argument("Invalid parameter(s) for string-find.");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t p = str.find(pattern, pos);
|
||||||
|
|
||||||
|
return p != str.npos ? p : -1;
|
||||||
|
}
|
||||||
|
|
@ -18,4 +18,8 @@ std::string string_lucase(std::string s, const std::string &strcase);
|
||||||
|
|
||||||
std::string string_trim(std::string s, const std::string &chars_to_trim, const std::string &rltrim);
|
std::string string_trim(std::string s, const std::string &chars_to_trim, const std::string &rltrim);
|
||||||
|
|
||||||
std::string string_padd(const std::string & str, int pad_len, char fill_char, bool from_right);
|
std::string string_padd(const std::string & str, int pad_len, char fill_char, bool from_right);
|
||||||
|
|
||||||
|
std::string string_substring(const std::string & str, long pos, long count);
|
||||||
|
|
||||||
|
size_t string_find_substr(const std::string & str, const std::string & pattern, long pos);
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
(defun ut::assert-false (test) (ut::assert-equal nil test))
|
(defun ut::assert-false (test) (ut::assert-equal nil test))
|
||||||
|
|
||||||
|
(defun ut::assert-nil (test) (ut::assert-equal nil test))
|
||||||
|
|
||||||
(defun ut::define-test (name exp_list)
|
(defun ut::define-test (name exp_list)
|
||||||
(set! ut::tests_list (push ut::tests_list (list name exp_list))))
|
(set! ut::tests_list (push ut::tests_list (list name exp_list))))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,19 @@
|
||||||
(ut::define-test "result of (string-split \"split me by space\" \"\\s+\")" '(ut::assert-equal '("split" "me" "by" "space") (string-split "split me by space" "\\s+")))
|
(ut::define-test "result of (string-split \"split me by space\" \"\\s+\")" '(ut::assert-equal '("split" "me" "by" "space") (string-split "split me by space" "\\s+")))
|
||||||
(ut::define-test "result of (string-upcase \"abcABCD\")" '(ut::assert-equal "ABCABCD" (string-upcase "abcABCD")))
|
(ut::define-test "result of (string-upcase \"abcABCD\")" '(ut::assert-equal "ABCABCD" (string-upcase "abcABCD")))
|
||||||
(ut::define-test "result of (string-downcase \"abcABCD\")" '(ut::assert-equal "abcabcd" (string-downcase "abcABCD")))
|
(ut::define-test "result of (string-downcase \"abcABCD\")" '(ut::assert-equal "abcabcd" (string-downcase "abcABCD")))
|
||||||
|
(ut::define-test "result of (string-len \"abcdef\")" '(ut::assert-equal 6 (string-len "abcdef")))
|
||||||
|
|
||||||
|
(ut::define-test "result of (string-substr \"ABCDEF\")" '(ut::assert-equal "ABCDEF" (string-substr "ABCDEF")))
|
||||||
|
(ut::define-test "result of (string-substr \"ABCDEF\" 1)" '(ut::assert-equal "BCDEF" (string-substr "ABCDEF" 1)))
|
||||||
|
(ut::define-test "result of (string-substr \"ABCDEF\" 2 3)" '(ut::assert-equal "CDE" (string-substr "ABCDEF" 2 3)))
|
||||||
|
(ut::define-test "result of (string-substr \"ABCDEF\"4 42)" '(ut::assert-equal "EF" (string-substr "ABCDEF" 4 42)))
|
||||||
|
(ut::define-test "result of (string-substr \"ABCDEF\" -2 2)" '(ut::assert-equal "EF" (string-substr "ABCDEF" -2 2)))
|
||||||
|
|
||||||
|
(ut::define-test "result of (string-find \" long long int;\" \"long\")" '(ut::assert-equal 1 (string-find " long long int;" "long")))
|
||||||
|
(ut::define-test "result of (string-find \" long long int;\" \"long\" 2)" '(ut::assert-equal 6 (string-find " long long int;" "long" 2)))
|
||||||
|
(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 (write-file \"/tmp/file\" \"write-file test\")" '(ut::assert-equal 1 (write-file "/tmp/file" "write-file test\n")))
|
(ut::define-test "result of (write-file \"/tmp/file\" \"write-file test\")" '(ut::assert-equal 1 (write-file "/tmp/file" "write-file test\n")))
|
||||||
(ut::define-test "result of (is-file? \"/tmp/file\")" '(ut::assert-true (is-file? "/tmp/file")))
|
(ut::define-test "result of (is-file? \"/tmp/file\")" '(ut::assert-true (is-file? "/tmp/file")))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue