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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#[macro_export]
macro_rules! tree {
    ((None)) => { None };
    ((Some($($node:tt)*))) => { Some(tree!(($($node)*))) };

    ((
        Program @ $start:literal .. $end:literal,
        functions: [$($func:tt),* $(,)?],
        globals: [$($global:tt),* $(,)?] $(,)?
    )) => {
        Program {
            span: span!($start..$end),
            functions: vec![$(tree!($func)),*],
            globals: vec![$(tree!($global)),*],
        }
    };
    ((
        FunctionDefinition @ $start:literal .. $end:literal,
        name: $ident:tt,
        params @ $params_start:literal .. $params_end:literal: [$($param:tt),* $(,)?],
        return_type: $return_type:tt,
        block: $block:tt $(,)?
    )) => {
        FunctionDefinition {
            span: span!($start..$end),
            name: tree!($ident),
            params: tree!((vec![$(tree!($param)),*], @ $params_start..$params_end)),
            return_type: tree!($return_type),
            block: tree!($block),
        }
    };
    ((
        Parameter,
        mutable: $mutable:expr,
        name: $ident:tt,
        type: $type:tt $(,)?
    )) => {
        Parameter {
            mutable: $mutable,
            name: tree!($ident),
            type_: tree!($type),
        }
    };

    ((
        Let @ $start:literal .. $end:literal,
        mutable: $mut:literal,
        name: $ident:tt,
        type: $type:tt,
        expr: $expr:tt $(,)?
    )) => {
        LetStmt {
            span: span!($start..$end),
            mutable: $mut,
            name: tree!($ident),
            type_: tree!($type),
            expr: tree!($expr),
        }
    };
    ((LetStmt $($rest:tt)*)) => {
        Statement::Let(tree!((Let $($rest)*)))
    };
    ((ReturnStmt @ $start:literal .. $end:literal, $expr:tt $(,)?)) => {
        Statement::Return(ReturnStmt {
            span: span!($start..$end),
            expr: tree!($expr),
        })
    };
    ((ExprStmt @ $start:literal .. $end:literal, $expr:tt $(,)?)) => {
        Statement::Expr(ExprStmt {
            span: span!($start..$end),
            expr: tree!($expr),
        })
    };

    ((
        Block @ $start:literal .. $end:literal,
        stmts: [$($stmt:tt),* $(,)?],
        expr: $expr:tt $(,)?
    )) => {
        Block {
            span: span!($start..$end),
            stmts: vec![$(tree!($stmt)),*],
            expr: tree!($expr),
        }
    };
    ((BlockExpr $($rest:tt)*)) => {
        Expression::Block(tree!((Block $($rest)*)).into())
    };
    ((
        IfExpr @ $start:literal .. $end:literal,
        cond: $cond:tt,
        then_block: $then_block:tt,
        else_block: $else_block:tt $(,)?
    )) => {
        Expression::If(IfExpr {
            span: span!($start..$end),
            cond: tree!($cond),
            then_block: tree!($then_block),
            else_block: tree!($else_block),
        }.into())
    };
    ((Int $($rest:tt)*)) => { Expression::Int(tree!(($($rest)*))) };
    ((Float $($rest:tt)*)) => { Expression::Float(tree!(($($rest)*))) };
    ((Bool $($rest:tt)*)) => { Expression::Bool(tree!(($($rest)*))) };
    ((Char $($rest:tt)*)) => { Expression::Char(tree!(($($rest)*))) };
    ((Ident $($rest:tt)*)) => { Expression::Ident(tree!(($($rest)*))) };
    ((Grouped @ $start:literal .. $end:literal, $expr:tt)) => {
        Expression::Grouped(Spanned {
            span: span!($start..$end),
            inner: tree!($expr).into(),
        })
    };
    ((
        PrefixExpr @ $start:literal .. $end:literal,
        op: $op:expr,
        expr: $expr:tt $(,)?
    )) => {
        Expression::Prefix(PrefixExpr {
            span: span!($start..$end),
            op: $op,
            expr: tree!($expr),
        }.into())
    };
    ((
        InfixExpr @ $start:literal .. $end:literal,
        lhs: $lhs:tt,
        op: $op:expr,
        rhs: $rhs:tt $(,)?
    )) => {
        Expression::Infix(InfixExpr {
            span: span!($start..$end),
            lhs: tree!($lhs),
            op: $op,
            rhs: tree!($rhs),
        }.into())
    };
    ((
        AssignExpr @ $start:literal .. $end:literal,
        assignee: $assignee:tt,
        op: $op:expr,
        expr: $expr:tt $(,)?
    )) => {
        Expression::Assign(AssignExpr {
            span: span!($start..$end),
            assignee: tree!($assignee),
            op: $op,
            expr: tree!($expr),
        }.into())
    };
    ((
        CallExpr @ $start:literal .. $end:literal,
        func: $func:tt,
        args: [$($arg:tt),* $(,)?] $(,)?
    )) => {
        Expression::Call(CallExpr {
            span: span!($start..$end),
            func: tree!($func),
            args: vec![$(tree!($arg)),*],
        }.into())
    };
    ((
        CastExpr @ $start:literal .. $end:literal,
        expr: $expr:tt,
        type: $type:expr $(,)?
    )) => {
        Expression::Cast(CastExpr {
            span: span!($start..$end),
            expr: tree!($expr),
            type_: $type,
        }.into())
    };

    (($value:expr, @ $start:literal .. $end:literal)) => {
        Spanned {
            span: span!($start..$end),
            inner: $value,
        }
    };
}

#[macro_export]
macro_rules! tokens {
    ($($kind:ident $(($($tt:tt)*))? @ $start:literal .. $end:literal),* $(,)?) => {
        [$(TokenKind::$kind $(($($tt)*))? .spanned(span!($start..$end))),*]
    };
}