diff --git a/Makefile b/Makefile index b2e5b91..bee65a8 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ -run: prompt.c loperations.o lnumbers.o lexpressions.o lio.o lerror.o lenvironment.o mpc.o - cc -std=c99 -Wall prompt.c loperations.o lnumbers.o lexpressions.o lio.o lerror.o lenvironment.o mpc.o -ledit -lm -o prompt +run: prompt.c lconditionals.o loperations.o lnumbers.o lexpressions.o lio.o lerror.o lenvironment.o mpc.o + cc -std=c99 -Wall prompt.c lconditionals.o loperations.o lnumbers.o lexpressions.o lio.o lerror.o lenvironment.o mpc.o -ledit -lm -o prompt +lconditionals.o: lval/conditionals.c lval/conditionals.h + cc -std=c99 -Wall -c lval/conditionals.c -o lconditionals.o loperations.o: lval/operations.c lval/operations.h cc -std=c99 -Wall -c lval/operations.c -o loperations.o lnumbers.o: lval/numbers.c lval/numbers.h diff --git a/lval.h b/lval.h index 5fb708e..dc28940 100644 --- a/lval.h +++ b/lval.h @@ -16,5 +16,7 @@ #include "lval/io.h" // Add environments, variables, and functions #include "lval/environment.h" +// Add conditional statements +#include "lval/conditionals.h" #endif diff --git a/lval/conditionals.c b/lval/conditionals.c new file mode 100644 index 0000000..8333d9f --- /dev/null +++ b/lval/conditionals.c @@ -0,0 +1,110 @@ +#include "conditionals.h" +#include "numbers.h" +#include "operations.h" +#include "error.h" + +lval* builtin_gt(lenv* e, lval* a) { + return builtin_ord(e, a, ">"); +} + +lval* builtin_lt(lenv* e, lval* a) { + return builtin_ord(e, a, "<"); +} + +lval* builtin_ge(lenv* e, lval* a) { + return builtin_ord(e, a, ">="); +} + +lval* builtin_le(lenv* e, lval* a) { + return builtin_ord(e, a, "<="); +} + +lval* builtin_ord(lenv* e, lval* a, char* op) { + LASSERT_NUM(op, a, 2); + LASSERT(a, + a->cell[0]->type == LVAL_LONG || a->cell[0]->type == LVAL_DOUBLE, + "Function '%s' passed incorrect type for argument %i. " \ + "Got %s, Expected %s.", op, 0, ltype_name(a->cell[0]->type), "LONG or DOUBLE") + LASSERT(a, + a->cell[1]->type == LVAL_LONG || a->cell[0]->type == LVAL_DOUBLE, + "Function '%s' passed incorrect type for argument %i. " \ + "Got %s, Expected %s.", op, 1, ltype_name(a->cell[0]->type), "LONG or DOUBLE") + + int r; + double xVal = (a->cell[0]->type == LVAL_LONG)? a->cell[0]->data.num : a->cell[0]->data.dec; + double yVal = (a->cell[1]->type == LVAL_LONG)? a->cell[1]->data.num : a->cell[1]->data.dec; + if (strcmp(op, ">") == 0) { + r = (xVal > yVal); + } + if (strcmp(op, "<") == 0) { + r = (xVal < yVal); + } + if (strcmp(op, ">=") == 0) { + r = (xVal >= yVal); + } + if (strcmp(op, "<=") == 0) { + r = (xVal <= yVal); + } + + lval_del(a); + return lval_long(r); +} + +int lval_eq(lval* x, lval* y) { + // Different types are always unequal + if (x->type != y->type) { return 0; } + + // Compare base on type + switch (x->type) { + // Compare numerical types + case LVAL_LONG: return (x->data.num == y->data.num); + case LVAL_DOUBLE: return (x->data.dec == y->data.dec); + + // Compare string values + case LVAL_ERR: return (strcmp(x->err, y->err) == 0); + case LVAL_SYM: return (strcmp(x->sym, y->sym) == 0); + + // If builtin compare, otherwise compare formals and body + case LVAL_FUN: + if (x->builtin || y->builtin) { + return x->builtin == y->builtin; + } else { + return lval_eq(x->formals, y->formals) && + lval_eq(x->body, y->body); + } + + case LVAL_QEXPR: + case LVAL_SEXPR: + if (x->count != y->count) { return 0; } + for (int i = 0; i < x->count; i++) { + // If any element not equal then whole list are not equal + if (!lval_eq(x->cell[i], y->cell[i])) { return 0; } + } + // Otherwise lists must be equal + return 1; + break; + } + + return 0; +} + +lval* builtin_cmp(lenv* e, lval* a, char* op) { + LASSERT_NUM(op, a, 2); + int r; + if (strcmp(op, "==") == 0) { + r = lval_eq(a->cell[0], a->cell[1]); + } + if (strcmp(op, "!=") == 0) { + r = !lval_eq(a->cell[0], a->cell[1]); + } + lval_del(a); + return lval_long(r); +} + +lval* builtin_eq(lenv* e, lval* a) { + return builtin_cmp(e, a, "=="); +} + +lval* builtin_ne(lenv* e, lval* a) { + return builtin_cmp(e, a, "!="); +} \ No newline at end of file diff --git a/lval/conditionals.h b/lval/conditionals.h new file mode 100644 index 0000000..2db2046 --- /dev/null +++ b/lval/conditionals.h @@ -0,0 +1,19 @@ +#ifndef LVAL_CONDITIONALS +#define LVAL_CONDITIONALS + +#include "base.h" + +lval* builtin_gt(lenv* e, lval* a); +lval* builtin_lt(lenv* e, lval* a); +lval* builtin_ge(lenv* e, lval* a); +lval* builtin_le(lenv* e, lval* a); + +lval* builtin_ord(lenv* e, lval* a, char* op); + +int lval_eq(lval* x, lval* y); +lval* builtin_cmp(lenv* e, lval* a, char* op); +lval* builtin_eq(lenv* e, lval* a); +lval* builtin_ne(lenv* e, lval* a); + + +#endif diff --git a/lval/environment.c b/lval/environment.c index 5ed1a76..04c5eba 100644 --- a/lval/environment.c +++ b/lval/environment.c @@ -3,6 +3,7 @@ #include "error.h" #include "expressions.h" #include "operations.h" +#include "conditionals.h" lenv* lenv_new(void) { lenv* e = (lenv*) malloc(sizeof(lenv)); @@ -126,6 +127,15 @@ void lenv_add_builtins(lenv* e) { lenv_add_builtin(e, "=", builtin_put); lenv_add_builtin(e, "ls", builtin_ls); lenv_add_builtin(e, "\\", builtin_lambda); + + // Conditional functions + lenv_add_builtin(e, "<", builtin_lt); + lenv_add_builtin(e, ">", builtin_gt); + lenv_add_builtin(e, "<=", builtin_le); + lenv_add_builtin(e, ">=", builtin_ge); + lenv_add_builtin(e, "==", builtin_eq); + lenv_add_builtin(e, "!=", builtin_ne); + } lval* builtin_ls(lenv* e, lval* a) {