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
|
/* String example */
pub struct string {
len usize;
buf *u8;
}
pub init(mut s *string)
{
s.len = 0;
s.buf = null;
}
pub deinit(mut s *string)
{
dealloc(s.buf);
}
pub init(mut s *string, u *u8)
{
len usize = 0;
r any = u;
while r++ {len++;}
s.len = len;
s.buf = alloc(s.len);
memcpy(s.buf, u);
}
pub copy(mut r *string, s *string) *string
{
dealloc(r.buf);
r.len = s.len;
r.buf = alloc(r.len);
memcpy(r.buf, s.buf);
}
pub move(mut r *string, mut s *string) *string
{
dealloc(r.buf);
r.len = s.len;
r.buf = s.buf;
s.buf = null;
s.len = 0;
}
pub length(s *string) usize
{
return s.len;
}
pub index(s *string, i usize) u8
{
assert(i < len, "index %zu out of bounds\n", i);
return s.buf[i];
}
pub add(r *string, a *string, b *string)
{
len any = length(a) + length(b);
buf any = alloc(l);
if r.buf == a.buf {
dealloc(a.buf);
} else if r.buf == b.buf {
dealloc(b.buf);
}
r.buf = buf;
r.len = len;
}
/* example of hygienic and recursive macros.
In macros, the last statement of the block is taken as the "return" value,
so the following two definitions would be enough to get the smallest
value of any number of parameters, without affecting any variables in
the parent context. If recursive blocks, the last of the blocks is taken.
In this case, the same thing could be done with functions of course.
Internally, if one of these macros is passed as a function argument, all
statements except the last (which has to be a certain type,
have to check exactly which rules I want to apply to it) will be moved
into the nearest "regular" context, i.e. not a function call in a function
call or something like that. The last variable's context is kept as the block
in which it was defined, but accessed "anonymously". In C, something like
// some counter to make sure we don't overlap some other variable
int min_res_12345;
{
const int _a = a;
const int _b = b;
const int _res = _a < _b ? _a : _b;
min_res_12345 = _res;
}
call(min_res_12345);
*/
define min(a, b) {{
_a const = a;
_b const = b;
_res const = if _a < _b {
_a
} else {
_b
};
_res;
}}
define min(a, b ...args) {{
_a const = a;
_b const = min(b, ...args);
_res const = if _a < _b {
_a
} else {
_b
};
_res;
}}
pub define new(x ...args)
{
x = alloc(sizeof(x));
init(@ ...args);
}
pub define ctx(x ...args)
{
init(&x ...args);
defer(deinit(@));
}
main(argc i32, argv [argc] * u8)
{
something = argv[10]; // run type bounds checking for ranged array?
// will not be automatically freed
new(a *string);
new(b *string, "hello");
c string; // undefined state
// will be automatically 'freed'
ctx(c string);
ctx(v vec<string>);
append(v, a);
append(v, c);
}
|