This repository has been archived by the owner on Jan 16, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
/
015$var.cc
65 lines (58 loc) · 1.98 KB
/
015$var.cc
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
//// implicit gensyms: $vars turn into a unique sym in every top-level form
// Variables defined in macros can cause subtle bugs:
// mac bad-swap(x y)
// `(let tmp ,x # tmp can be captured
// (,x = ,y)
// (,y = tmp))
//
// (withs (a 3 b 4)
// (bad-swap a b)
// (list a b))
// => (4 3) # seems ok
//
// (withs (a 3 tmp 4)
// (bad-swap a tmp)
// (list a tmp))
// => (3 4) # oops
//
// To avoid such bugs, use an implicit gensym:
// mac good-swap(x y)
// `(let $tmp ,x
// (,x = ,y)
// (,y = $tmp))
//
// When reading this definition, occurrences of $tmp are replaced with a
// unique symbol like tmp2417. Occurrences of $tmp elsewhere will get a
// *different* unique symbol.
// Design considered the following:
// simple implementation
// so uniqueness isn't perfectly guaranteed, just overwhelmingly likely
// runs after infix transformation, so $+ => +147 isn't turned into '(+ 147)
// don't expand $vars in compiled primitives; we won't know what to lookup()
// Alternative: explicit gensyms make for less concise macros:
// mac old-swap(x y)
// let tmp (uniq)
// `(let ,tmp ,x
// (,x = ,y)
// (,y = ,tmp))
cell* transform_dollar_vars(cell* input) {
table map; // transform $vars identically within each top-level expression
return transform_dollar_vars(input, map);
}
cell* transform_dollar_vars(cell* input, table& map) {
if (is_sym(input) && to_string(input)[0] == '$') {
if (!map[input])
map[mkref(input)] = mkref(gensym(new_sym(to_string(input).substr(1))));
return map[input];
}
if (!is_cons(input)) return input; // no tables or compiledfns in static code
set_car(input, transform_dollar_vars(car(input), map));
set_cdr(input, transform_dollar_vars(cdr(input), map));
return input;
}
cell* gensym(cell* x) {
static long counter = 0;
ostringstream os;
os << (x == nil ? "sym" : to_string(x)) << ++counter;
return new_sym(os.str());
}