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
|
Table generation syntax and macros
----------------------------------
It would be nice to have some form of table generation syntax:
type CharType = enum {
Control
Space
Special
Linebreak
Digit
Uppercase
Lowercase
}
date byte[128] char_type = table(
0x0..0x7 = Control
0x8 = Control
0x9 = Space
0xA = Linebreak
0xB..0xC = Control
0xD = Linebreak
0xE..0x1F = Control
0x20 = Space
0x21..0x2F = Special
0x30..0x39 = Digit
0x3A..0x40 = Special
0x41..0x5A = Uppercase
0x5B..0x60 = Special
0x61..0x7A = Lowercase
0x7B..0x7E = Special
0x7F = Control
)
Alternatively, it could be generated through some kind of meta-compilation:
defmacro make_table(...)
{
require_state(.Expression)
# XXX how to declare that the lifetime of tok is only valid until the next, and possibly implicit, .next() call
ref Token tok = tokens.next()
tok.must_be(.Number)
size arraysize = tok.as_size()
# implcit length parameter
ref [arraysize]?ref Expr elements = .new()
tokens.skip(.Comma)
for ref Token tok in tokens {
tok.must_be(.Number)
size from_num = tok.as_size()
next tok
if tok == .DotDot {
next tok
tok.must_be(.Number)
size to_num = tok.as_size()
next tok
tok.must_be(.Equal)
next tok
# FIXME this does not support multi-token values (e.g. "10+value*2")
tok.must_be_in_group(.Expression)
for size i in .range_incl(from_num, to_num) {
elements[i] = tok.clone()
}
} else {
next tok
tok.must_be(.Equal)
next tok
tok.must_be_in_group(.Expression)
elements[from_num] = tok.clone()
}
}
output(.LSquare)
# TODO array index access in for loops?
size i
#for size i, ?ref Expr elem in elements { <-- perhaps like this?
for ?ref Expr elem in elements {
if elem == none {
error_param(0, i)
error("Element number {0} is missing")
}
output(elem)
output(.Comma)
i += 1
}
output(.RSquare)
}
date byte[128] char_type = callmacro make_table(128,
0x0..0x7 = Control
0x8 = Control
0x9 = Space
...
)
Restrict where macros can appears, and what they can generate?
- basically, macros should not be able to break out of expressions or definitions
- allow macros at:
- top level
- must return at top level
- type
- must generate full type, and nothing more
- expression
- must generate full (sub-)expression, and nothing more
- statement
- can generate any number of statements
- last statement must be complete
- must return in starting block
Block macros? To avoid having to pass every "inside/wrapped" token through the macro
defmacro access_lock(..., {})
callmacro access_lock(mylock, {
work()
})
Macros an ABIs:
- slightly problematic, because macros cannot change in a released version, so
older versions need to be kept alongside the new ones
|