aboutsummaryrefslogtreecommitdiff
path: root/src/builtins.c
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-06-20 21:19:25 +0800
committerMistivia <i@mistivia.com>2025-06-20 21:19:32 +0800
commit4fa87778453cb0364cb6fa1c53481484622658f4 (patch)
tree96dd407432352959062c2a40e85b1f6f0892c59c /src/builtins.c
parent0a6ff7031819b77e978f5c9f99eecb0577179ba7 (diff)
and/or/not
Diffstat (limited to 'src/builtins.c')
-rw-r--r--src/builtins.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/builtins.c b/src/builtins.c
index 2ad3916..abd2ae9 100644
--- a/src/builtins.c
+++ b/src/builtins.c
@@ -50,6 +50,20 @@ static SExp raw_add(SExp a, SExp b) {
}
}
+static SExp raw_mul(SExp a, SExp b) {
+ if (a.type == kRealSExp || b.type == kRealSExp) {
+ double result = 1.0;
+ if (a.type == kRealSExp) result += a.real;
+ else result *= a.integer;
+ if (b.type == kRealSExp) result += b.real;
+ else result *= b.integer;
+ return (SExp){ .type = kRealSExp, .real = result };
+ } else {
+ int64_t result;
+ return (SExp){ .type = kIntegerSExp, .integer= a.integer * b.integer};
+ }
+}
+
static SExp raw_sub(SExp a, SExp b) {
if (a.type == kRealSExp || b.type == kRealSExp) {
double result = 0;
@@ -63,6 +77,29 @@ static SExp raw_sub(SExp a, SExp b) {
}
}
+static SExp raw_div(SExp a, SExp b) {
+ double lhs, rhs;
+ if (a.type == kRealSExp) lhs = a.real;
+ else lhs = a.integer;
+ if (b.type == kRealSExp) rhs = b.real;
+ else rhs = b.integer;
+ return (SExp){ .type = kRealSExp, .real = lhs / rhs};
+}
+
+static SExp raw_idiv(SExp a, SExp b) {
+ int64_t lhs, rhs;
+ lhs = a.integer;
+ rhs = b.integer;
+ return (SExp){ .type = kIntegerSExp, .integer = lhs / rhs};
+}
+
+static SExp raw_mod(SExp a, SExp b) {
+ int64_t lhs, rhs;
+ lhs = a.integer;
+ rhs = b.integer;
+ return (SExp){ .type = kIntegerSExp, .integer = lhs % rhs};
+}
+
SExpRef builtin_add(Interp *interp, SExpRef args) {
SExpRef ret;
SExp acc = {.type = kIntegerSExp, .integer = 0};
@@ -83,6 +120,26 @@ SExpRef builtin_add(Interp *interp, SExpRef args) {
return ret;
}
+SExpRef builtin_mul(Interp *interp, SExpRef args) {
+ SExpRef ret;
+ SExp acc = {.type = kIntegerSExp, .integer = 1};
+ SExpRef cur = args;
+ while (!NILP(cur)) {
+ if (REF(CAR(cur))->type != kIntegerSExp && REF(CAR(cur))->type != kRealSExp) {
+ return new_error(interp, "*: wrong argument type.\n");
+ }
+ cur = CDR(cur);
+ }
+ cur = args;
+ while (!NILP(cur)) {
+ acc = raw_mul(acc, *REF(CAR(cur)));
+ cur = CDR(cur);
+ }
+ ret = new_sexp(interp);
+ *REF(ret) = acc;
+ return ret;
+}
+
SExpRef builtin_sub(Interp *interp, SExpRef args) {
SExpRef ret;
SExpRef cur = args;
@@ -109,6 +166,77 @@ SExpRef builtin_sub(Interp *interp, SExpRef args) {
return new_error(interp, "-: wrong argument number.\n");
}
+SExpRef builtin_div(Interp *interp, SExpRef args) {
+ SExpRef ret;
+ SExpRef cur = args;
+ while (!NILP(cur)) {
+ if (REF(CAR(cur))->type != kIntegerSExp && REF(CAR(cur))->type != kRealSExp) {
+ return new_error(interp, "/: wrong argument type.\n");
+ }
+ cur = CDR(cur);
+ }
+ int args_len = lisp_length(interp, args);
+ if (args_len == 1) {
+ SExp num = *REF(CAR(args));
+ if (num.type == kIntegerSExp) {
+ return new_integer(interp, 1.0/num.integer);
+ }
+ return new_real(interp, 1.0/num.real);
+ }
+ if (args_len == 2) {
+ SExp num = raw_div(*REF(CAR(args)), *REF(CADR(args)));
+ ret = new_sexp(interp);
+ *REF(ret) = num;
+ return ret;
+ }
+ return new_error(interp, "/: wrong argument number.\n");
+}
+
+SExpRef builtin_idiv(Interp *interp, SExpRef args) {
+ SExpRef ret;
+ SExpRef cur = args;
+ while (!NILP(cur)) {
+ if (REF(CAR(cur))->type != kIntegerSExp) {
+ return new_error(interp, "i/: wrong argument type.\n");
+ }
+ cur = CDR(cur);
+ }
+ int args_len = lisp_length(interp, args);
+ if (args_len == 2) {
+ SExp num = raw_idiv(*REF(CAR(args)), *REF(CADR(args)));
+ ret = new_sexp(interp);
+ *REF(ret) = num;
+ return ret;
+ }
+ return new_error(interp, "i/: wrong argument number.\n");
+}
+
+SExpRef builtin_mod(Interp *interp, SExpRef args) {
+ SExpRef ret;
+ SExpRef cur = args;
+ while (!NILP(cur)) {
+ if (REF(CAR(cur))->type != kIntegerSExp) {
+ return new_error(interp, "mod: wrong argument type.\n");
+ }
+ cur = CDR(cur);
+ }
+ int args_len = lisp_length(interp, args);
+ if (args_len == 2) {
+ SExp num = raw_mod(*REF(CAR(args)), *REF(CADR(args)));
+ ret = new_sexp(interp);
+ *REF(ret) = num;
+ return ret;
+ }
+ return new_error(interp, "mod: wrong argument number.\n");
+}
+
+SExpRef builtin_not(Interp *interp, SExpRef args) {
+ int args_len = lisp_length(interp, args);
+ if (args_len != 1) return new_error(interp, "not: wrong argument number.\n");
+ if (TRUEP(CAR(args))) return interp->f;
+ return interp->t;
+}
+
SExpRef builtin_num_equal(Interp *interp, SExpRef args) {
int args_len = lisp_length(interp, args);
if (args_len != 2) return new_error(interp, "=: wrong argument number.\n");
@@ -138,6 +266,35 @@ SExpRef builtin_num_equal(Interp *interp, SExpRef args) {
}
}
+SExpRef builtin_num_neq(Interp *interp, SExpRef args) {
+ int args_len = lisp_length(interp, args);
+ if (args_len != 2) return new_error(interp, "/=: wrong argument number.\n");
+ SExpRef lhs = CAR(args);
+ SExpRef rhs = CADR(args);
+ if (VALTYPE(lhs) != kRealSExp && VALTYPE(lhs) != kIntegerSExp) {
+ return new_error(interp, "/=: type error.\n");
+ }
+ if (VALTYPE(rhs) != kRealSExp && VALTYPE(rhs) != kIntegerSExp) {
+ return new_error(interp, "/=: type error.\n");
+ }
+ if (VALTYPE(lhs) == kRealSExp || VALTYPE(rhs) == kRealSExp) {
+ double flhs, frhs;
+ if (VALTYPE(lhs) == kIntegerSExp) {
+ flhs = REF(lhs)->integer;
+ } else {
+ flhs = REF(lhs)->real;
+ }
+ if (VALTYPE(rhs) == kIntegerSExp) {
+ frhs = REF(rhs)->integer;
+ } else {
+ frhs = REF(rhs)->real;
+ }
+ return new_boolean(interp, flhs != frhs);
+ } else {
+ return new_boolean(interp, REF(lhs)->integer != REF(rhs)->integer);
+ }
+}
+
SExpRef builtin_gt(Interp *interp, SExpRef args) {
int args_len = lisp_length(interp, args);
if (args_len != 2) return new_error(interp, ">: wrong argument number.\n");