aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-06-23 20:29:57 +0800
committerMistivia <i@mistivia.com>2025-06-23 20:29:57 +0800
commit15821fd796d3f1e1b14bbb4aa32715aab4f49c56 (patch)
tree996f215d25d5897c3b666df4fdb48d198072b1d2 /src
parent69e9065635b1c20fe0f973bdebeb2745171bace1 (diff)
add string functions
Diffstat (limited to 'src')
-rw-r--r--src/builtins.c104
-rw-r--r--src/builtins.h18
-rw-r--r--src/interp.c13
3 files changed, 133 insertions, 2 deletions
diff --git a/src/builtins.c b/src/builtins.c
index fe14b8f..48cb4f0 100644
--- a/src/builtins.c
+++ b/src/builtins.c
@@ -6,6 +6,110 @@
#include <float.h>
#include <math.h>
+SExpRef builtin_string(Interp *interp, SExpRef args) {
+ for (SExpRef i = args; !NILP(i); i = CDR(i)) {
+ SExpRef x = CAR(i);
+ if (VALTYPE(x) != kIntegerSExp && VALTYPE(x) != kCharSExp) {
+ return new_error(interp, "string: type error.\n");
+ }
+ }
+ str_builder_t sb;
+ init_str_builder(&sb);
+ for (SExpRef i = args; !NILP(i); i = CDR(i)) {
+ SExpRef x = CAR(i);
+ if (VALTYPE(x) == kIntegerSExp) {
+ str_builder_append_char(&sb, REF(x)->integer);
+ } else {
+ str_builder_append_char(&sb, REF(x)->character);
+ }
+ }
+ str_builder_append_char(&sb, '\0');
+ SExpRef ret = new_string(interp, sb.buf);
+ free(sb.buf);
+ return ret;
+}
+
+SExpRef builtin_string_eq(Interp *interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "string=: arg num error.\n");
+ SExpRef s1 = CAR(args), s2 = CADR(args);
+ if (VALTYPE(s1) != kStringSExp || VALTYPE(s2) != kStringSExp) {
+ return new_error(interp, "string=: type error.\n");
+ }
+ return new_boolean(interp, strcmp(REF(s1)->str, REF(s2)->str) == 0);
+}
+
+SExpRef builtin_string_gt(Interp *interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "string>: arg num error.\n");
+ SExpRef s1 = CAR(args), s2 = CADR(args);
+ if (VALTYPE(s1) != kStringSExp || VALTYPE(s2) != kStringSExp) {
+ return new_error(interp, "string>: type error.\n");
+ }
+ return new_boolean(interp, strcmp(REF(s1)->str, REF(s2)->str) > 0);
+
+}
+
+SExpRef builtin_string_lt(Interp *interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "string<: arg num error.\n");
+ SExpRef s1 = CAR(args), s2 = CADR(args);
+ if (VALTYPE(s1) != kStringSExp || VALTYPE(s2) != kStringSExp) {
+ return new_error(interp, "string<: type error.\n");
+ }
+ return new_boolean(interp, strcmp(REF(s1)->str, REF(s2)->str) < 0);
+}
+
+SExpRef builtin_string_ge(Interp *interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "string>=: arg num error.\n");
+ SExpRef s1 = CAR(args), s2 = CADR(args);
+ if (VALTYPE(s1) != kStringSExp || VALTYPE(s2) != kStringSExp) {
+ return new_error(interp, "string>=: type error.\n");
+ }
+ return new_boolean(interp, strcmp(REF(s1)->str, REF(s2)->str) >= 0);
+}
+
+SExpRef builtin_string_le(Interp *interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "string<=: arg num error.\n");
+ SExpRef s1 = CAR(args), s2 = CADR(args);
+ if (VALTYPE(s1) != kStringSExp || VALTYPE(s2) != kStringSExp) {
+ return new_error(interp, "string<=: type error.\n");
+ }
+ return new_boolean(interp, strcmp(REF(s1)->str, REF(s2)->str) <= 0);
+}
+
+SExpRef builtin_string_neq(Interp *interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "string/=: arg num error.\n");
+ SExpRef s1 = CAR(args), s2 = CADR(args);
+ if (VALTYPE(s1) != kStringSExp || VALTYPE(s2) != kStringSExp) {
+ return new_error(interp, "string/=: type error.\n");
+ }
+ return new_boolean(interp, strcmp(REF(s1)->str, REF(s2)->str) != 0);
+}
+
+SExpRef builtin_split_string(Interp *interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "split-string: arg num error.\n");
+ SExpRef s1 = CAR(args), s2 = CADR(args);
+ if (VALTYPE(s1) != kStringSExp || VALTYPE(s2) != kCharSExp) {
+ return new_error(interp, "split-string: type error.\n");
+ }
+ char **ss;
+ ss = str_split((char*)REF(s1)->str, REF(s2)->character);
+ SExpRef lst = NIL;
+ for (char **i = ss; *i != NULL; i++) {
+ lst = CONS(new_string(interp, *i), lst);
+ }
+ destroy_str_list(ss);
+ return lisp_nreverse(interp, lst);
+}
+
+SExpRef builtin_strip_string(Interp *interp, SExpRef args) {
+ if (LENGTH(args) != 1) return new_error(interp, "strip-string: arg num error.\n");
+ SExpRef s = CAR(args);
+ if (VALTYPE(s) != kStringSExp) return new_error(interp, "strip-string: type error.\n");
+ char *news = str_strip((char*)REF(s)->str);
+ SExpRef ret = new_string(interp, news);
+ free(news);
+ return ret;
+}
+
SExpRef builtin_alwaysgc(Interp *interp, SExpRef args) {
if (LENGTH(args) != 1) return new_error(interp, "_alwaysgc: arg num error.\n");
SExpRef arg = CAR(args);
diff --git a/src/builtins.h b/src/builtins.h
index eb95f2d..608df98 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -3,6 +3,24 @@
#include "interp.h"
+// - char=
+// - char>
+// - char<
+// - char>=
+// - char<=
+// - char/=
+// - ord
+// - chr
+
+SExpRef builtin_string(Interp *interp, SExpRef args);
+SExpRef builtin_string_eq(Interp *interp, SExpRef args);
+SExpRef builtin_string_gt(Interp *interp, SExpRef args);
+SExpRef builtin_string_lt(Interp *interp, SExpRef args);
+SExpRef builtin_string_ge(Interp *interp, SExpRef args);
+SExpRef builtin_string_le(Interp *interp, SExpRef args);
+SExpRef builtin_string_neq(Interp *interp, SExpRef args);
+SExpRef builtin_split_string(Interp *interp, SExpRef args);
+SExpRef builtin_strip_string(Interp *interp, SExpRef args);
SExpRef builtin_symbol2string(Interp *interp, SExpRef args);
SExpRef builtin_intern(Interp *interp, SExpRef args);
SExpRef builtin_gensym(Interp *interp, SExpRef args);
diff --git a/src/interp.c b/src/interp.c
index 7d89641..242b821 100644
--- a/src/interp.c
+++ b/src/interp.c
@@ -106,6 +106,15 @@ void Interp_init(Interp *self) {
Interp_add_userfunc(self, "=", builtin_num_equal);
Interp_add_userfunc(self, "/=", builtin_num_neq);
Interp_add_userfunc(self, "concat", builtin_concat);
+ Interp_add_userfunc(self, "string", builtin_string);
+ Interp_add_userfunc(self, "string=", builtin_string_eq);
+ Interp_add_userfunc(self, "string>=", builtin_string_ge);
+ Interp_add_userfunc(self, "string<=", builtin_string_le);
+ Interp_add_userfunc(self, "string>", builtin_string_gt);
+ Interp_add_userfunc(self, "string<", builtin_string_lt);
+ Interp_add_userfunc(self, "string/=", builtin_string_neq);
+ Interp_add_userfunc(self, "split-string", builtin_split_string);
+ Interp_add_userfunc(self, "strip-string", builtin_strip_string);
Interp_add_userfunc(self, "print", builtin_print);
Interp_add_userfunc(self, "format", builtin_format);
Interp_add_userfunc(self, "truncate", builtin_truncate);
@@ -330,11 +339,11 @@ void Interp_gc(Interp *interp, SExpRef tmproot) {
// enlarge heap
heapsize = SExpVector_len(&interp->objs);
int usedsize = heapsize - IntVector_len(&interp->empty_space);
- if (heapsize < usedsize * 2) {
+ if (heapsize < usedsize * 4) {
SExp sexp;
sexp.marked = false;
sexp.type = kEmptySExp;
- while (SExpVector_len(&interp->objs) < usedsize * 2) {
+ while (SExpVector_len(&interp->objs) < usedsize * 4) {
SExpVector_push_back(&interp->objs, sexp);
IntVector_push_back(&interp->empty_space, SExpVector_len(&interp->objs) - 1);
}