✨ add string.replace
This commit is contained in:
parent
94114416fe
commit
d37dfec225
1
makefile
1
makefile
|
@ -331,6 +331,7 @@ test:nasal
|
|||
@ ./nasal -e test/qrcode.nas
|
||||
@ ./nasal -t -d test/quick_sort.nas
|
||||
@ ./nasal -t -d test/regex_test.nas
|
||||
@ ./nasal -t -d test/replace_test.nas
|
||||
@ ./nasal -e test/scalar.nas hello world
|
||||
@ ./nasal test/subprocess_test.nas
|
||||
@ ./nasal -e test/trait.nas
|
||||
|
|
|
@ -154,6 +154,7 @@ void dbg::step_info() {
|
|||
|
||||
src.load(files[bytecode[ctx.pc].fidx]);
|
||||
|
||||
std::clog << clear_screen << set_cursor;
|
||||
std::clog << "\nsource code:\n";
|
||||
for(u64 i = begin; i<end && i<src.size(); ++i) {
|
||||
std::clog << (i==line? back_white:reset);
|
||||
|
@ -200,7 +201,9 @@ void dbg::interact() {
|
|||
std::getline(std::cin, cmd);
|
||||
auto res = parse(cmd);
|
||||
if (res.size()==0) {
|
||||
step_info();
|
||||
// enter key without input using cmd_next by default
|
||||
next = true;
|
||||
return;
|
||||
} else if (res.size()==1) {
|
||||
switch(get_cmd_type(res[0])) {
|
||||
case cmd_kind::cmd_help: help(); break;
|
||||
|
|
|
@ -85,8 +85,9 @@ private:
|
|||
{"exit", cmd_kind::cmd_exit}
|
||||
};
|
||||
cmd_kind get_cmd_type(const std::string& cmd) const {
|
||||
return command_table.count(cmd)?
|
||||
command_table.at(cmd):cmd_kind::cmd_error;
|
||||
return command_table.count(cmd)
|
||||
? command_table.at(cmd)
|
||||
: cmd_kind::cmd_error;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -14,6 +14,21 @@ struct for_reset {
|
|||
static for_reset windows_system_set;
|
||||
#endif
|
||||
|
||||
std::ostream& clear_screen(std::ostream& s) {
|
||||
// TODO: winapi clear screen
|
||||
s << "\033c";
|
||||
return s;
|
||||
}
|
||||
|
||||
std::ostream& set_cursor(std::ostream& s) {
|
||||
#ifdef _WIN32
|
||||
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), {0, 0});
|
||||
#else
|
||||
s << "\033[0;0H";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
std::ostream& back_white(std::ostream& s) {
|
||||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0xf0);
|
||||
|
|
|
@ -22,6 +22,8 @@ struct span {
|
|||
}
|
||||
};
|
||||
|
||||
std::ostream& clear_screen(std::ostream&);
|
||||
std::ostream& set_cursor(std::ostream&);
|
||||
std::ostream& back_white(std::ostream&);
|
||||
std::ostream& red(std::ostream&);
|
||||
std::ostream& cyan(std::ostream&);
|
||||
|
|
|
@ -92,36 +92,38 @@ var builtin_input(context* ctx, gc* ngc) {
|
|||
|
||||
var builtin_split(context* ctx, gc* ngc) {
|
||||
auto local = ctx->localr;
|
||||
var delimeter = local[1];
|
||||
var separator = local[1];
|
||||
var str = local[2];
|
||||
if (!delimeter.is_str()) {
|
||||
if (!separator.is_str()) {
|
||||
return nas_err("native::split", "\"separator\" must be string");
|
||||
}
|
||||
if (!str.is_str()) {
|
||||
return nas_err("native::split", "\"str\" must be string");
|
||||
}
|
||||
const auto& deli = delimeter.str();
|
||||
const auto& sep = separator.str();
|
||||
const auto& s = str.str();
|
||||
|
||||
// avoid being sweeped
|
||||
auto res = ngc->temp = ngc->alloc(vm_type::vm_vec);
|
||||
auto& vec = res.vec().elems;
|
||||
|
||||
if (!deli.length()) {
|
||||
// empty separator means split every char
|
||||
if (!sep.length()) {
|
||||
for(auto i : s) {
|
||||
vec.push_back(ngc->newstr(i));
|
||||
}
|
||||
ngc->temp = nil;
|
||||
return res;
|
||||
}
|
||||
|
||||
usize last = 0;
|
||||
usize pos = s.find(deli, 0);
|
||||
usize pos = s.find(sep, 0);
|
||||
while(pos!=std::string::npos) {
|
||||
if (pos>last) {
|
||||
vec.push_back(ngc->newstr(s.substr(last, pos-last)));
|
||||
}
|
||||
last = pos+deli.length();
|
||||
pos = s.find(deli, last);
|
||||
last = pos + sep.length();
|
||||
pos = s.find(sep, last);
|
||||
}
|
||||
if (last!=s.length()) {
|
||||
vec.push_back(ngc->newstr(s.substr(last)));
|
||||
|
@ -130,6 +132,54 @@ var builtin_split(context* ctx, gc* ngc) {
|
|||
return res;
|
||||
}
|
||||
|
||||
var builtin_split_with_empty_substr(context* ctx, gc* ngc) {
|
||||
auto local = ctx->localr;
|
||||
var separator = local[1];
|
||||
var str = local[2];
|
||||
if (!separator.is_str()) {
|
||||
return nas_err(
|
||||
"native::split_with_empty_substr",
|
||||
"\"separator\" must be string"
|
||||
);
|
||||
}
|
||||
if (!str.is_str()) {
|
||||
return nas_err(
|
||||
"native::split_with_empty_substr",
|
||||
"\"str\" must be string"
|
||||
);
|
||||
}
|
||||
const auto& sep = separator.str();
|
||||
const auto& s = str.str();
|
||||
|
||||
// avoid being sweeped
|
||||
auto res = ngc->temp = ngc->alloc(vm_type::vm_vec);
|
||||
auto& vec = res.vec().elems;
|
||||
|
||||
// empty separator means split every char
|
||||
if (!sep.length()) {
|
||||
for(auto i : s) {
|
||||
vec.push_back(ngc->newstr(i));
|
||||
}
|
||||
ngc->temp = nil;
|
||||
return res;
|
||||
}
|
||||
|
||||
usize last = 0;
|
||||
usize pos = s.find(sep, 0);
|
||||
while(pos!=std::string::npos) {
|
||||
if (pos>=last) {
|
||||
vec.push_back(ngc->newstr(s.substr(last, pos-last)));
|
||||
}
|
||||
last = pos + sep.length();
|
||||
pos = s.find(sep, last);
|
||||
}
|
||||
if (last<=s.length()) {
|
||||
vec.push_back(ngc->newstr(s.substr(last)));
|
||||
}
|
||||
ngc->temp = nil;
|
||||
return res;
|
||||
}
|
||||
|
||||
var builtin_rand(context* ctx, gc* ngc) {
|
||||
auto val = ctx->localr[1];
|
||||
if (!val.is_num() && !val.is_nil()) {
|
||||
|
@ -746,6 +796,7 @@ nasal_builtin_table builtin[] = {
|
|||
{"__system", builtin_system},
|
||||
{"__input", builtin_input},
|
||||
{"__split", builtin_split},
|
||||
{"__split_with_empty_substr", builtin_split_with_empty_substr},
|
||||
{"__rand", builtin_rand},
|
||||
{"__id", builtin_id},
|
||||
{"__int", builtin_int},
|
||||
|
|
|
@ -39,6 +39,7 @@ var builtin_setsize(context*, gc*);
|
|||
var builtin_system(context*, gc*);
|
||||
var builtin_input(context*, gc*);
|
||||
var builtin_split(context*, gc*);
|
||||
var builtin_split_with_empty_substr(context*, gc*);
|
||||
var builtin_rand(context*, gc*);
|
||||
var builtin_id(context*, gc*);
|
||||
var builtin_int(context*, gc*);
|
||||
|
|
|
@ -39,3 +39,28 @@ var to_char = func(number) {
|
|||
var to_num = func(character) {
|
||||
return __temp_contains(__char_to_num, character)? __char_to_num[character]:-1;
|
||||
}
|
||||
|
||||
var __string_split_with_empty_substr = func(separator, str) {
|
||||
return __split_with_empty_substr(separator, str);
|
||||
}
|
||||
|
||||
var replace = func(needle, haystack, replacement) {
|
||||
var needle_size = size(needle);
|
||||
var haystack_size = size(haystack);
|
||||
var replacement_size = size(replacement);
|
||||
|
||||
if (needle_size == 0 or
|
||||
haystack_size == 0 or
|
||||
replacement_size == 0 or
|
||||
needle_size > haystack_size
|
||||
) {
|
||||
return haystack;
|
||||
}
|
||||
if (needle == haystack) {
|
||||
return replacement;
|
||||
}
|
||||
|
||||
var vec = __string_split_with_empty_substr(needle, haystack);
|
||||
|
||||
return join(replacement, vec);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
use std.string;
|
||||
|
||||
var test_set = [
|
||||
["{}", "{}", "a", "a"],
|
||||
["{}", "a{}", "a", "aa"],
|
||||
["{}", "{}a", "a", "aa"],
|
||||
["{}", "a{}a", "a", "aaa"],
|
||||
["{}", "{}a{}", "a", "aaa"],
|
||||
["{}", "{{}}", "a", "{a}"],
|
||||
["{}", "{}{}{}", "a", "aaa"]
|
||||
];
|
||||
|
||||
foreach(var i; test_set) {
|
||||
if (string.replace(i[0], i[1], i[2]) != i[3]) {
|
||||
println("Error: string.replace(",
|
||||
i[0], ", ",
|
||||
i[1], ", ",
|
||||
i[2], ") != ",
|
||||
i[3]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue