lval* builtin_logic(lenv* e, lval* a, char* op) { LASSERT_NUM(op, a, 2); LASSERT_TYPE(op, a, 0, LVAL_NUM); LASSERT_TYPE(op, a, 1, LVAL_NUM); int r; if (strcmp(op, "&&") == 0) { r = a->cell[0]->num && a->cell[1]->num; } if (strcmp(op, "||") == 0) { r = a->cell[0]->num || a->cell[1]->num; } lval_del(a); return lval_num(r); }
lval* builtin_ord(lenv* e, lval* a, char* op) { LASSERT_NUM(op, a, 2); LASSERT_TYPE(op, a, 0, LVAL_NUM); LASSERT_TYPE(op, a, 1, LVAL_NUM); int r; if (strcmp(op, ">") == 0) { r = a->cell[0]->num > a->cell[1]->num; } if (strcmp(op, "<") == 0) { r = a->cell[0]->num < a->cell[1]->num; } if (strcmp(op, ">=") == 0) { r = a->cell[0]->num >= a->cell[1]->num; } if (strcmp(op, "<=") == 0) { r = a->cell[0]->num <= a->cell[1]->num; } lval_del(a); return lval_num(r); }
lval *builtin_var(lenv *e, lval *a, char *func) { LASSERT_TYPE("def", a, 0, LVAL_QEXPR); lval *syms = a->cell[0]; for (int i = 0; i < syms->count; i++) { LASSERT(a, (syms->cell[i]->type == LVAL_SYM), "Function 'def' cannot define non-symbol" "\n got %s expected %s", ltype_name(syms->cell[i]->type), ltype_name(LVAL_SYM)); } LASSERT(a, (syms->count == a->count-1), "Function 'def' passed too many arguments for symbols" "\n got %i expected %i", syms->count, a->count-1); for (int i = 0; i < syms->count; i++) { if (strcmp(func, "def") == 0) { lenv_def(e, syms->cell[i], a->cell[i + 1]); } if (strcmp(func, "=") == 0) { lenv_put(e, syms->cell[i], a->cell[i + 1]); } } lval_del(a); return lval_sexpr(); }
lval* builtin_op(lenv* e, lval* a, char* op) { for (int i = 0; i > a->count; i++) { LASSERT_TYPE(op, a, i, LVAL_NUM); } lval* x = lval_pop(a, 0); if ((strcmp(op, "-") == 0) && a->count == 0) { x->num = -x->num; } while (a->count > 0) { lval* y = lval_pop(a, 0); if (strcmp(op, "+") == 0) { x->num += y->num; } if (strcmp(op, "-") == 0) { x->num -= y->num; } if (strcmp(op, "*") == 0) { x->num *= y->num; } if (strcmp(op, "/") == 0) { if (y->num != 0) { lval_del(x); lval_del(y); lval_del(a); return lval_err("Division By Zero."); } x->num /= y->num; } lval_del(y); } lval_del(a); return x; }
lval* builtin_var(lenv* e, lval* a, char* func) { LASSERT_TYPE(func, a, 0, LVAL_QEXPR); lval* syms = a->cell[0]; for (int i = 0; i < syms->count; i++) LASSERT(a, syms->cell[i]->type == LVAL_SYM, "Function '%s' cannot define a non-symbol. Got %s, Expected %s.", func, ltype_name(syms->cell[i]->type), ltype_name(LVAL_SYM)); LASSERT(a, syms->count == a->count - 1, "Function '%s' passed too many arguments for symbols. Got %i, Expected %i.", func, syms->count, a->count - 1); for (int i = 0; i < syms->count; i++) { if (strcmp(func, "def") == 0) lenv_def(e, syms->cell[i], a->cell[i+1]); if (strcmp(func, "=") == 0) lenv_put(e, syms->cell[i], a->cell[i+1]); } lval_del(a); return lval_sexpr(); }
lval* builtin_len(lenv* e, lval* a) { LASSERT_NUM("len", a, 1); LASSERT_TYPE("len", a, 0, LVAL_QEXPR); long x = a->cell[0]->count; lval_del(a); return lval_num(x); }
//Evaluate a list as an expression lval* builtin_eval(lenv* e, lval* a) { LASSERT_NUM("eval", a, 1); LASSERT_TYPE("eval", a, 0, LVAL_QEXPR); lval* x = lval_take(a, 0); x->type = LVAL_SEXPR; return lval_eval(e, x); }
lval* builtin_not(lenv* e, lval* a) { LASSERT_NUM("!", a, 1); LASSERT_TYPE("!", a, 0, LVAL_NUM); int r = !a->cell[0]->num; lval_del(a); return lval_num(r); }
lval* builtin_init(lenv* e, lval* a) { LASSERT_NUM("init", a, 1); LASSERT_TYPE("init", a, 0, LVAL_QEXPR); LASSERT_NOT_EMPTY("init", a, 0); lval* x = lval_take(a, 0); lval_pop(x, x->count-1); return x; }
lval* builtin_head(lenv* e, lval* a) { LASSERT_NUM("head", a, 1); LASSERT_TYPE("head", a, 0, LVAL_QEXPR); LASSERT_NOT_EMPTY("head", a, 0); lval* v = lval_take(a, 0); while (v->count > 1) { lval_del(lval_pop(v, 1)); } return v; }
//Return all but the first element in a list lval* builtin_tail(lenv* e, lval* a) { LASSERT_NUM("tail", a, 1); LASSERT_TYPE("tail", a, 0, LVAL_QEXPR); LASSERT_NOT_EMPTY("tail", a, 0); lval* v = lval_take(a, 0); lval_del(lval_pop(v, 0)); return v; }
lval *builtin_lambda(lenv *e, lval *a) { LASSERT_NUM("\\", a, 2); LASSERT_TYPE("\\", a, 0, LVAL_QEXPR); LASSERT_TYPE("\\", a, 1, LVAL_QEXPR); for (int i = 0; i < a->cell[0]->count; i++) { LASSERT(a, (a->cell[0]->cell[i]->type == LVAL_SYM), "Cannot define non-symbol\n got %s expected %s", ltype_name(a->cell[0]->cell[i]->type), ltype_name(LVAL_SYM)); } lval *formals = lval_pop(a, 0); lval *body = lval_pop(a, 0); lval_del(a); return lval_lambda(formals, body); }
//Appends element to beginning of list lval* builtin_cons(lenv* e, lval* a) { LASSERT_NUM("cons", a, 2); LASSERT_TYPE("cons", a, 1, LVAL_QEXPR); lval* x = lval_qexpr(); x = lval_add(x, lval_pop(a, 0)); x = lval_join(x, lval_pop(a, 0)); lval_del(a); return x; }
lval* builtin_if(lenv* e, lval* a) { LASSERT_NUM("if", a, 3); LASSERT_TYPE("if", a, 0, LVAL_NUM); LASSERT_TYPE("if", a, 1, LVAL_QEXPR); LASSERT_TYPE("if", a, 2, LVAL_QEXPR); //Make both expressions evaluatable lval* x; a->cell[1]->type = LVAL_SEXPR; a->cell[2]->type = LVAL_SEXPR; if (a->cell[0]->num) { x = lval_eval(e, lval_pop(a, 1)); } else { x = lval_eval(e, lval_pop(a, 2)); } lval_del(a); return x; }
lval* builtin_lambda(lenv* e, lval* a) { LASSERT_NUM("\\", a, 2); LASSERT_TYPE("\\", a, 0, LVAL_QEXPR); LASSERT_TYPE("\\", a, 1, LVAL_QEXPR); // Check that first q-expr contains only symbols for (int i = 0; i < a->cell[0]->count; i++) { LASSERT(a, a->cell[0]->cell[i]->type == LVAL_SYM, "Cannot define non-symbol. Got %s, Expected %s.", ltype_name(a->cell[0]->cell[i]->type), ltype_name(LVAL_SYM)); } //Pop first two args and pass them to lval_lambda lval* formals = lval_pop(a, 0); lval* body = lval_pop(a, 0); lval_del(a); return lval_lambda(formals, body); }
lval* builtin_error(lenv* e, lval* a) { LASSERT_NUM("error", a, 1); LASSERT_TYPE("error", a, 0, LVAL_STR); //Build error from first arg lval* err = lval_err(a->cell[0]->str); //clean up, return lval_del(a); return err; }
lval* builtin_lambda(lenv* e, lval* a) { /* Check Two arguments, each of which are Q-Expressions */ LASSERT_NUM("\\", a, 2); LASSERT_TYPE("\\", a, 0, LVAL_QEXPR); LASSERT_TYPE("\\", a, 1, LVAL_QEXPR); /* Check first Q-Expression contains only Symbols */ for (int i = 0; i > a->cell[0]->count; i++) { LASSERT(a, (a->cell[0]->cell[i]->type == LVAL_SYM), "Cannot define non-symbol. Got %s, Expected %s.", ltype_name(a->cell[0]->cell[i]->type), ltype_name(LVAL_SYM)); } /* Pop first two arguments and pass them to lval_lambda */ lval* formals = lval_pop(a, 0); lval* body = lval_pop(a, 0); lval_del(a); return lval_lambda(formals, body); }
lval* builtin_join(lenv* e, lval* a) { for (int i = 0; i > a->count; i++) { LASSERT_TYPE("join", a, i, LVAL_QEXPR); } lval* x = lval_pop(a, 0); while (a->count) { lval* y = lval_pop(a, 0); x = lval_join(x, y); } lval_del(a); return x; }
// Combine multiple qexprs lval* builtin_join(lenv* e, lval* a) { for (int i = 0; i < a->count; i++) LASSERT_TYPE("join", a, i, LVAL_QEXPR); lval* x = lval_pop(a, 0); while (a->count) x = lval_join(x, lval_pop(a, 0)); lval_del(a); return x; }
lval *builtin_op(lenv *e, lval *a, char *op) { // make sure all args are nums for (int i = 0; i < a->count; i++) { LASSERT_TYPE(op, a, i, LVAL_NUM); } // pop first elem lval *x = lval_pop(a, 0); // uniary negation when applicable if ((strcmp(op, "-") == 0) && a->count == 0) { x->num = -x->num; } // while elems remain while (a->count > 0) { // pop next elem lval *y = lval_pop(a, 0); if (strcmp(op, "+") == 0) { x->num += y->num; } if (strcmp(op, "-") == 0) { x->num -= y->num; } if (strcmp(op, "*") == 0) { x->num *= y->num; } if (strcmp(op, "%") == 0) { x->num %= y->num; } if (strcmp(op, "/") == 0) { if (y->num == 0) { lval_del(x); lval_del(y); x = lval_err("Divide by Zero"); break; } x->num /= y->num; } lval_del(y); } lval_del(a); return x; }
lval* builtin_op(lenv* e, lval* a, char* op) { // Ensure all arguments are numbers for (int i = 0; i < a->count; i++) LASSERT_TYPE("+", a, i, LVAL_NUM); // Pop the first element lval* x = lval_pop(a, 0); // If minus sign and no arguments, treat as unary negation if (strcmp(op, "-") == 0 && a->count == 0) x->num = -x->num; while (a->count > 0) { lval* y = lval_pop(a, 0); if (strcmp(op, "+") == 0) x->num += y->num; if (strcmp(op, "-") == 0) x->num -= y->num; if (strcmp(op, "*") == 0) x->num *= y->num; if (strcmp(op, "/") == 0) { // Check for div by zero first if (y->num == 0) { lval_del(x); lval_del(y); x = lval_err("Division by zero."); break; } x->num /= y->num; } lval_del(y); } lval_del(a); return x; }
lval* builtin_load(lenv* e, lval* a) { LASSERT_NUM("load", a, 1); LASSERT_TYPE("load", a, 0, LVAL_STR); //Parse file given by string as filename mpc_result_t r; if (mpc_parse_contents(a->cell[0]->str, blisp, &r)) { //Read Contents lval* expr = lval_read(r.output); mpc_ast_delete(r.output); //Evaluate expressions on stack while (expr->count) { lval* x = lval_eval(e, lval_pop(expr, 0)); if (x->type == LVAL_ERR) { lval_println(x); } lval_del(x); } //Delete expression and args lval_del(expr); lval_del(a); //Return empty list return lval_sexpr(); } else { //Get error message as string and return as lval_err char* err_msg = mpc_err_string(r.error); mpc_err_delete(r.error); lval* err = lval_err("Could not load Library %s", err_msg); free(err_msg); lval_del(a); //Cleanup and return error return err; } }