aboutsummaryrefslogtreecommitdiff
path: root/src/builtin.h
blob: 144ed4cb563abcce8a5a29e55cd8de9e1e95cd4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#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