diff options
| author | Mistivia <i@mistivia.com> | 2025-06-20 21:19:25 +0800 |
|---|---|---|
| committer | Mistivia <i@mistivia.com> | 2025-06-20 21:19:32 +0800 |
| commit | 4fa87778453cb0364cb6fa1c53481484622658f4 (patch) | |
| tree | 96dd407432352959062c2a40e85b1f6f0892c59c /src/builtins.c | |
| parent | 0a6ff7031819b77e978f5c9f99eecb0577179ba7 (diff) | |
and/or/not
Diffstat (limited to 'src/builtins.c')
| -rw-r--r-- | src/builtins.c | 157 |
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"); |
