#include "value.h" #define PROCEDURES(X) \ /* X(symbol, name, argc) */ \ X(plus, "+", 2) \ X(minus, "-", 2) \ X(cons, "cons", 2) \ X(car, "car", 1) \ X(cdr, "cdr", 1) \ // Number of builtin procedures #define PLUS_ONE(_symbol, _name, _argc) 1 + #define BUILTIN_PROCEDURES PROCEDURES(PLUS_ONE) 0 // Forward decalration of the procedures #define DECLARE_PROCEDURE(proc) value_t proc(value_t *args) #define FORWARD_DECLARATION(symbol, _name, _argc) \ DECLARE_PROCEDURE(symbol); PROCEDURES(FORWARD_DECLARATION) // Fill procedure struct for the value_t #define PROC_DESCRIPTION(symbol, _name, argc) \ {argc, symbol}, struct proc_builtin builtin_proc_descriptions[] = { PROCEDURES(PROC_DESCRIPTION) }; // List of ordered names of procedures #define PROC_NAME(symbol, name, _argc) \ name, const char *builtin_proc_name_list[] = { PROCEDURES(PROC_NAME) }; // ----- Definitions ----- #define ASSERT_TYPE(proc, args, pos, vtype, fail) \ if(args[pos]->type != vtype) { \ err("Expected arg %d of %s to be %s instead of %s", \ pos, #proc, "", ""); \ fail; \ } #define PROC_ASSERT_TYPE(pos, vtype, fail) \ ASSERT_TYPE(P, args, pos, vtype, fail) #define P plus DECLARE_PROCEDURE(P) { PROC_ASSERT_TYPE(0, VALUE_INT, return VALUE_EMPTY); PROC_ASSERT_TYPE(1, VALUE_INT, return VALUE_EMPTY); int sum = args[0]->value.num + args[1]->value.num; return value_create(VALUE_INT, &sum); } #undef P #define P minus DECLARE_PROCEDURE(P) { PROC_ASSERT_TYPE(0, VALUE_INT, return VALUE_EMPTY); PROC_ASSERT_TYPE(1, VALUE_INT, return VALUE_EMPTY); int difference = args[0]->value.num - args[1]->value.num; return value_create(VALUE_INT, &difference); } #undef P #define P cons DECLARE_PROCEDURE(P) { struct cons cons = {value_copy(args[0]), value_copy(args[1])}; return value_create(VALUE_CONS, &cons); } #undef P #define P car DECLARE_PROCEDURE(P) { PROC_ASSERT_TYPE(0, VALUE_CONS, return VALUE_EMPTY); value_t left = value_copy(args[0]->value.cons.left); return left; } #undef P #define P cdr DECLARE_PROCEDURE(P) { PROC_ASSERT_TYPE(0, VALUE_CONS, return VALUE_EMPTY); value_t right = value_copy(args[0]->value.cons.right); return right; } #undef P