#include "conditionals.h" #include "numbers.h" #include "operations.h" #include "expressions.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->data.err, y->data.err) == 0); case LVAL_SYM: return (strcmp(x->data.sym, y->data.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]); } if (strcmp(op, "or") == 0) { LASSERT_TYPE("or", a, 0, LVAL_LONG) LASSERT_TYPE("or", a, 1, LVAL_LONG) r = (a->cell[0]->data.num || a->cell[1]->data.num); } if (strcmp(op, "and") == 0) { LASSERT_TYPE("and", a, 0, LVAL_LONG) LASSERT_TYPE("and", a, 1, LVAL_LONG) r = (a->cell[0]->data.num && a->cell[1]->data.num); } 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, "!="); } lval* builtin_or(lenv* e, lval* a) { return builtin_cmp(e, a, "or"); } lval* builtin_and(lenv* e, lval* a) { return builtin_cmp(e, a, "and"); } lval* builtin_if(lenv* e, lval* a) { LASSERT_NUM("if", a, 3) LASSERT_TYPE("if", a, 0, LVAL_LONG) LASSERT_TYPE("if", a, 1, LVAL_QEXPR) LASSERT_TYPE("if", a, 2, LVAL_QEXPR) // Mark both expressions as evaluable lval* x; a->cell[1]->type = LVAL_SEXPR; a->cell[2]->type = LVAL_SEXPR; if (a->cell[0]->data.num) { x = lval_eval(e, lval_pop(a, 1)); } else { x = lval_eval(e, lval_pop(a, 2)); } // Delete the argument list and return lval_del(a); return x; }