-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathvalue.c
164 lines (133 loc) · 2.97 KB
/
value.c
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <memory.h>
#include <value.h>
/*
The value structure is defined as follows.
Let f be a pointer to a struct value.
f->N is the reference count.
f->T is the type, a C routine which steps the value during evaluation.
f->next links values on the free list after f->N drops to 0.
Every value f is one of three classes: combinator, atom, or apply.
1. combinator : (f->L == 0 && f->R == 0)
A combinator is a primary function with no arguments.
2. atom : (f->L != 0 && f->L->N == 0)
An atom is a piece of data. The data reside in the union which follows f->L.
The f->L->clear field is a function that frees the data when f->N drops to 0.
3. apply : (f->L != 0 && f->L->N > 0)
An apply is the application of f->L to f->R.
The "recycle" routine below succinctly reflects these rules.
Note that on most machines, (sizeof(struct value) == 32).
*/
static value free_list = 0;
// Recycle a value f with reference count 0, putting f on the free list and
// dropping its content. If f is an atom, its data is freed. If f is an
// apply, its L and R reference counts are decremented and those are also
// recycled if their counts reach 0.
static void recycle(value f)
{
if (f->L)
{
if (f->L->N)
{
drop(f->L);
drop(f->R);
}
else
f->L->clear(f);
}
f->next = free_list;
free_list = f;
}
/* Increment the reference count. */
value hold(value f)
{
f->N++;
return f;
}
/* Decrement the reference count and recycle if it drops to zero. */
void drop(value f)
{
if (--f->N == 0)
recycle(f);
}
void clear_free_list(void)
{
while (free_list)
{
value f = free_list;
free_list = f->next;
free_memory(f,sizeof(struct value));
}
}
void end_value(void)
{
clear_free_list();
end_memory();
}
static value new_value(void)
{
value f = free_list;
if (f)
{
free_list = f->next;
return f;
}
return new_memory(sizeof(struct value));
}
/* Return a value of type T with the given left and right side. */
value V(type T, value L, value R)
{
value f = new_value();
*f = (struct value){{.N=1}, {.T=T}, L, {.R = R}};
return f;
}
// Return a value of type T with a double value.
value V_double(type T, value L, double v_double)
{
value f = new_value();
*f = (struct value){{.N=1}, {.T=T}, L, {.v_double = v_double}};
return f;
}
/* Create a combinator of type T. Shorthand for "quote". */
value Q(type T)
{
return V(T,0,0);
}
/* Apply x to y where x is known to be already evaluated. */
value AV(value x, value y)
{
return V(x->T,x,y);
}
/* The type for function application */
value type_A(value f)
{
value x = arg(f->L);
if (x == f->L)
{
f->T = x->T;
drop(x);
return hold(f);
}
else
return AV(x,hold(f->R));
}
/* Apply x to y. */
value A(value x, value y)
{
return V(type_A,x,y);
}
/* Reduce the value until done. */
static value eval_normal(value f)
{
while (1)
{
value g = f->T(f);
if (g == 0) return f;
drop(f);
f = g;
}
}
value (*eval)(value f) = eval_normal;
value arg(value f)
{
return eval(hold(f));
}