diff --git a/makefile b/makefile index af03a18..933e146 100644 --- a/makefile +++ b/makefile @@ -4,9 +4,9 @@ ifndef OS OS = $(shell uname) endif ifeq ($(OS), Darwin) - CXXFLAGS = -std=$(STD) -c -O3 -fno-exceptions -fPIC -mmacosx-version-min=10.15 + CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15 else - CXXFLAGS = -std=$(STD) -c -O3 -fno-exceptions -fPIC + CXXFLAGS = -std=$(STD) -c -O3 -fPIC endif NASAL_HEADER = \ @@ -35,7 +35,8 @@ NASAL_HEADER = \ src/json_lib.h\ src/unix_lib.h\ src/coroutine.h\ - src/repl.h + src/repl.h\ + src/regex_lib.h NASAL_OBJECT = \ build/nasal_err.o\ @@ -64,6 +65,7 @@ NASAL_OBJECT = \ build/nasal_vm.o\ build/nasal_dbg.o\ build/repl.o\ + build/regex_lib.o\ build/main.o @@ -177,6 +179,13 @@ build/unix_lib.o: \ src/unix_lib.h src/unix_lib.cpp | build $(CXX) $(CXXFLAGS) src/unix_lib.cpp -o build/unix_lib.o +build/regex_lib.o: \ + src/nasal.h\ + src/nasal_type.h\ + src/nasal_gc.h\ + src/regex_lib.h src/regex_lib.cpp | build + $(CXX) $(CXXFLAGS) src/regex_lib.cpp -o build/regex_lib.o + build/fg_props.o: \ src/nasal.h\ src/nasal_type.h\ @@ -279,6 +288,7 @@ test:nasal @ ./nasal -t -d test/prime.nas @ ./nasal -e test/qrcode.nas @ ./nasal -t -d test/quick_sort.nas + @ ./nasal -t -d test/regex_test.nas @ ./nasal -e test/scalar.nas hello world @ ./nasal -e test/trait.nas @ ./nasal -t -d test/turingmachine.nas diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index c6328a0..cfc84ab 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -37,6 +37,7 @@ void codegen::init_native_function() { load_native_function_table(dylib_lib_native); load_native_function_table(unix_lib_native); load_native_function_table(json_lib_native); + load_native_function_table(regex_lib_native); } void codegen::check_id_exist(identifier* node) { diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index 9d8ec7f..10d8b9b 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -17,6 +17,7 @@ #include "json_lib.h" #include "dylib_lib.h" #include "unix_lib.h" +#include "regex_lib.h" #include #include diff --git a/src/regex_lib.cpp b/src/regex_lib.cpp new file mode 100644 index 0000000..aa9b3e1 --- /dev/null +++ b/src/regex_lib.cpp @@ -0,0 +1,99 @@ +#include "regex_lib.h" + +namespace nasal { + +var builtin_regex_match(context* ctx, gc* ngc) { + auto source = ctx->localr[1]; + auto reg_str = ctx->localr[2]; + if (!source.is_str()) { + return nas_err("regex::match", "\"src\" must be a string"); + } + if (!reg_str.is_str()) { + return nas_err("regex::match", "\"reg\" must be a format string"); + } + try { + auto res = std::regex_match(source.str(), std::regex(reg_str.str())); + return res? one:zero; + } catch(const std::regex_error& e) { + return nas_err("regex::match", e.what()); + } + return zero; +} + +var builtin_regex_search(context* ctx, gc* ngc) { + auto source = ctx->localr[1]; + auto reg_str = ctx->localr[2]; + if (!source.is_str()) { + return nas_err("regex::search", "\"src\" must be a string"); + } + if (!reg_str.is_str()) { + return nas_err("regex::search", "\"reg\" must be a format string"); + } + try { + auto res = std::regex_search(source.str(), std::regex(reg_str.str())); + return res? one:zero; + } catch(const std::regex_error& e) { + return nas_err("regex::search", e.what()); + } + return nil; +} + +var builtin_regex_replace(context* ctx, gc* ngc) { + auto source = ctx->localr[1]; + auto reg_str = ctx->localr[2]; + auto fmt = ctx->localr[3]; + if (!source.is_str()) { + return nas_err("regex::replace", "\"src\" must be a string"); + } + if (!reg_str.is_str()) { + return nas_err("regex::replace", "\"reg\" must be a format string"); + } + if (!fmt.is_str()) { + return nas_err("regex::replace", "\"fmt\" must be a format string"); + } + try { + auto res = std::regex_replace( + source.str(), + std::regex(reg_str.str()), + fmt.str() + ); + return ngc->newstr(res); + } catch(const std::regex_error& e) { + return nas_err("regex::replace", e.what()); + } + return ngc->newstr(source.str()); +} + +var builtin_regex_match_all(context* ctx, gc* ngc) { + auto source = ctx->localr[1]; + auto reg_str = ctx->localr[2]; + if (!source.is_str()) { + return nas_err("regex::match_all", "\"src\" must be a string"); + } + if (!reg_str.is_str()) { + return nas_err("regex::match_all", "\"reg\" must be a format string"); + } + auto res = ngc->temp = ngc->alloc(vm_type::vm_vec); + try { + const auto& src = source.str(); + auto words_regex = std::regex(reg_str.str()); + auto begin = std::sregex_iterator(src.begin(), src.end(), words_regex); + auto end = std::sregex_iterator(); + for (auto i = begin; i!=end; ++i) { + res.vec().elems.push_back(ngc->newstr((*i).str())); + } + } catch(const std::regex_error& e) { + return nas_err("regex::match_all", e.what()); + } + return res; +} + +nasal_builtin_table regex_lib_native[] = { + {"__regex_match", builtin_regex_match}, + {"__regex_search", builtin_regex_search}, + {"__regex_replace", builtin_regex_replace}, + {"__regex_match_all", builtin_regex_match_all}, + {nullptr, nullptr} +}; + +} \ No newline at end of file diff --git a/src/regex_lib.h b/src/regex_lib.h new file mode 100644 index 0000000..4e51389 --- /dev/null +++ b/src/regex_lib.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "nasal.h" +#include "nasal_gc.h" +#include "nasal_builtin.h" + +namespace nasal { + +var builtin_regex_match(context*, gc*); +var builtin_regex_search(context*, gc*); +var builtin_regex_replace(context*, gc*); +var builtin_regex_match_all(context*, gc*); + +extern nasal_builtin_table regex_lib_native[]; + +} \ No newline at end of file diff --git a/std/regex.nas b/std/regex.nas new file mode 100644 index 0000000..67e73a7 --- /dev/null +++ b/std/regex.nas @@ -0,0 +1,18 @@ +# regex.nas +# 2024/3/1 by ValKmjolnir + +var match = func(src, reg) { + return __regex_match(src, reg); +} + +var search = func(src, reg) { + return __regex_search(src, reg); +} + +var replace = func(src, reg, fmt) { + return __regex_replace(src, reg, fmt); +} + +var match_all = func(src, reg) { + return __regex_match_all(src, reg); +} \ No newline at end of file diff --git a/test/regex_test.nas b/test/regex_test.nas new file mode 100644 index 0000000..4553d26 --- /dev/null +++ b/test/regex_test.nas @@ -0,0 +1,10 @@ +use std.regex; + +println(regex.match("aaa", "[a]*")); +println(regex.search("aabcaa", "abc")); + +var s = "aaaaa"; +println(regex.replace(s, "a", "[$&]")); +println(s); + +println(regex.match_all("a,b,c,d,e,f,g,h,i", "[a-z]")); \ No newline at end of file