Load Function
We want to built a function that can load and evaluate a file when passed a string of its name. To implement this function we’ll need to make use of our grammar as we’ll need it to to read in the file contents, parse, and evaluate them. Our load function is going to rely on our mpc_parser*
called Lispy
.
Therefore, just like with functions, we need to forward declare our parser pointers, and place them at the top of the file.
mpc_parser_t* Number;
mpc_parser_t* Symbol;
mpc_parser_t* String;
mpc_parser_t* Comment;
mpc_parser_t* Sexpr;
mpc_parser_t* Qexpr;
mpc_parser_t* Expr;
mpc_parser_t* Lispy;
Our load
function will be just like any other builtin. We need to start by checking that the input argument is a single string. Then we can use the mpc_parse_contents
function to read in the contents of a file using a grammar. Just like mpc_parse
this parses the contents of a file into some mpc_result
object, which is our case is an abstract syntax tree again or an error.
Slightly differently to our command prompt, on successfully parsing a file we shouldn’t treat it like one expression. When typing into a file we let users list multiple expressions and evaluate all of them individually. To achieve this behaviour we need to loop over each expression in the contents of the file and evaluate it one by one. If there are any errors we should print them and continue.
If there is a parse error we’re going to extract the message and put it into a error lval
which we return. If there are no errors the return value for this builtin can just be the empty expression. The full code for this looks like this.
lval* builtin_load(lenv* e, lval* a) {
LASSERT_NUM("load", a, 1);
LASSERT_TYPE("load", a, 0, LVAL_STR);
/* Parse File given by string name */
mpc_result_t r;
if (mpc_parse_contents(a->cell[0]->str, Lispy, &r)) {
/* Read contents */
lval* expr = lval_read(r.output);
mpc_ast_delete(r.output);
/* Evaluate each Expression */
while (expr->count) {
lval* x = lval_eval(e, lval_pop(expr, 0));
/* If Evaluation leads to error print it */
if (x->type == LVAL_ERR) { lval_println(x); }
lval_del(x);
}
/* Delete expressions and arguments */
lval_del(expr);
lval_del(a);
/* Return empty list */
return lval_sexpr();
} else {
/* Get Parse Error as String */
char* err_msg = mpc_err_string(r.error);
mpc_err_delete(r.error);
/* Create new error message using it */
lval* err = lval_err("Could not load Library %s", err_msg);
free(err_msg);
lval_del(a);
/* Cleanup and return error */
return err;
}
}