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
165
166
167
168
#[macro_export]
macro_rules! analyzed_tree {
((None)) => { None };
((Some($($node:tt)*))) => { Some(analyzed_tree!(($($node)*))) };
((
Program,
globals: [$($global:tt),* $(,)?],
functions: [$($func:tt),* $(,)?],
main_fn: $main_fn:tt,
used_builtins: [$($name:expr),* $(,)?] $(,)?
)) => {
AnalyzedProgram {
globals: vec![$(analyzed_tree!($global)),*],
functions: vec![$(analyzed_tree!($func)),*],
main_fn: analyzed_tree!($main_fn),
used_builtins: HashSet::from([$($name),*]),
}
};
((
FunctionDefinition,
used: $used:expr,
name: $name:expr,
params: [$($param:tt),* $(,)?],
return_type: $return_type:expr,
block: $block:tt $(,)?
)) => {
AnalyzedFunctionDefinition {
used: $used,
name: $name,
params: vec![$(analyzed_tree!($param)),*],
return_type: $return_type,
block: analyzed_tree!($block),
}
};
((
Parameter,
mutable: $mutable:expr,
name: $name:expr,
type: $type:expr $(,)?
)) => {
AnalyzedParameter {
mutable: $mutable,
name: $name,
type_: $type,
}
};
((
Let,
name: $name:expr,
expr: $expr:tt $(,)?
)) => {
AnalyzedLetStmt {
name: $name,
expr: analyzed_tree!($expr),
}
};
((LetStmt $($rest:tt)*)) => {
AnalyzedStatement::Let(analyzed_tree!((Let $($rest)*)))
};
((ReturnStmt, $expr:tt $(,)?)) => {
AnalyzedStatement::Return(analyzed_tree!($expr))
};
((ExprStmt, $expr:tt $(,)?)) => {
AnalyzedStatement::Expr(analyzed_tree!($expr))
};
((
Block -> $result_type:expr,
stmts: [$($stmt:tt),* $(,)?],
expr: $expr:tt $(,)?
)) => {
AnalyzedBlock {
result_type: $result_type,
stmts: vec![$(analyzed_tree!($stmt)),*],
expr: analyzed_tree!($expr),
}
};
((BlockExpr $($rest:tt)*)) => {
AnalyzedExpression::Block(analyzed_tree!((Block $($rest)*)).into())
};
((
IfExpr -> $result_type:expr,
cond: $cond:tt,
then_block: $then_block:tt,
else_block: $else_block:tt $(,)?
)) => {
AnalyzedExpression::If(AnalyzedIfExpr {
result_type: $result_type,
cond: analyzed_tree!($cond),
then_block: analyzed_tree!($then_block),
else_block: analyzed_tree!($else_block),
}.into())
};
((Int $expr:expr)) => { AnalyzedExpression::Int($expr) };
((Float $expr:expr)) => { AnalyzedExpression::Float($expr) };
((Bool $expr:expr)) => { AnalyzedExpression::Bool($expr) };
((Char $expr:expr)) => { AnalyzedExpression::Char($expr) };
((Ident -> $type:expr, $ident:expr)) => {
AnalyzedExpression::Ident(AnalyzedIdentExpr {
result_type: $type,
ident: $ident,
})
};
((Grouped $expr:tt)) => {
AnalyzedExpression::Grouped(analyzed_tree!($expr).into())
};
((
PrefixExpr -> $result_type:expr,
op: $op:expr,
expr: $expr:tt $(,)?
)) => {
AnalyzedExpression::Prefix(AnalyzedPrefixExpr {
result_type: $result_type,
op: $op,
expr: analyzed_tree!($expr),
}.into())
};
((
InfixExpr -> $result_type:expr,
lhs: $lhs:tt,
op: $op:expr,
rhs: $rhs:tt $(,)?
)) => {
AnalyzedExpression::Infix(AnalyzedInfixExpr {
result_type: $result_type,
lhs: analyzed_tree!($lhs),
op: $op,
rhs: analyzed_tree!($rhs),
}.into())
};
((
AssignExpr -> $result_type:expr,
assignee: $assignee:expr,
op: $op:expr,
expr: $expr:tt $(,)?
)) => {
AnalyzedExpression::Assign(AnalyzedAssignExpr {
result_type: $result_type,
assignee: $assignee,
op: $op,
expr: analyzed_tree!($expr),
}.into())
};
((
CallExpr -> $result_type:expr,
func: $func:expr,
args: [$($arg:tt),* $(,)?] $(,)?
)) => {
AnalyzedExpression::Call(AnalyzedCallExpr {
result_type: $result_type,
func: $func,
args: vec![$(analyzed_tree!($arg)),*],
}.into())
};
((
CastExpr -> $result_type:expr,
expr: $expr:tt,
type: $type:expr $(,)?
)) => {
AnalyzedExpression::Cast(AnalyzedCastExpr {
result_type: $result_type,
expr: analyzed_tree!($expr),
type_: $type,
}.into())
};
}