summaryrefslogtreecommitdiff
path: root/Notes/MacroHygine.md
blob: 972e7cc13bdf0e07f3758bb707d4f3cbed0e036f (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
% Macro Hygiene rules and notes

Use-cases
=========

A variable defined within the macro won't collide with one in a capture
```rust
macro_rules! foo {
    ($v:expr) => {{ let a = 123; a + $v }};
}

fn bar(a: usize) -> usize {
    // `a` here must resolve to the argument, not the macro parameter
    foo!(a)
}
```

Macros within functions can access values defined before the invocation
```rust
fn bar(a: usize) -> usize {
    let b = 1;
    macro_rules! foo {
        ($v:expr) => {{ a + b + $v }};
    }
    let a = 123;
    // `a` here must resolve to the local above, while the one in the macro resolves to the argument
    foo!(a)
}
```


Macros in outer scope can access any outer-scope name

Identifiers introduced within macros are inaccessible outside
```rust
fn bar() {
    macro_rules! foo {
        ($v:expr) => {let a = $v;};
    }

    foo!(123);
    //let b = a;    // ERROR
}
```

Implementation Notes
===================

Idea 1: Index list
-------------------

Lexer maintains a stack of counts - incremented after every TT end (closing bracket) and for every IDENT lexed. The stack grows into each TT.

This stack is the hygiene information for an identifier. During lookup a symbol is only usable if its hygiene information is a superset or before yours.
```
if( item_hygine[..-1].is_subset_of(my_hygine) && item_hygiene[-1] < my_hygiene[item_hygiene.len] ) {
    /* allowed */
}
```

Hygiene storage points:
- Relative paths (of the leading node)
- Pattern bindings (variable definitions)
- _TODO: Where else?_
- ?Generic definitions
- Items? (when would that be checked? They're "globally" addressable)


Problem: Destructuring patterns end up with an incorrect hygiene using this system.

Idea 2: Hygiene is directly related to the parser state
--------------------------

- Each lexer has a hygiene tag
- Token trees carry with them the hygiene tag for the contained tokens
- :ident captures a TT with associated hygiene context


<!-- vim: ft=markdown
-->