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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#[macro_export]
macro_rules! codegen {
    { [ $($ast:tt)* ] } => {
        codegen! {
            type: top,
            classes: [],
            buffer: [ $($ast)* ]
        }

        codegen_init! { [ $($ast)* ] }
    };

    {
        type: top,
        classes: [ $($class:tt)* ],
        buffer: []
    } => {
        codegen! {
            type: done,
            classes: [ $($class)* ]
        }
    };

    {
        type: top,
        classes: [
            $($class:tt)*
        ],
        buffer: [
            {
                type: class,
                rust_name: $rust_name:tt,
                ruby_name: $ruby_name:tt,
                meta: { pub: $pub:tt, reopen: $reopen:tt },
                struct: $struct:tt,
                methods: [ $($method:tt)* ]
            }
            $($rest:tt)*
        ]
    } => {
        codegen! {
            type: top,
            classes: [
                $($class)*
                {
                    rust_name: $rust_name,
                    ruby_name: $ruby_name,
                    struct: { codegen_struct! { pub: $pub, rust_name: $rust_name, ruby_name: $ruby_name, struct: $struct } },
                    methods: [ $( codegen_method! { $method } )* ]
                }
            ],
            buffer: [ $($rest)* ]
        }

        codegen_extra_impls!({
            type: class,
            rust_name: $rust_name,
            ruby_name: $ruby_name,
            meta: { pub: $pub, reopen: $reopen },
            struct: $struct,
            methods: [ $($method)* ]
        });
    };

    {
        type: done,
        classes: [ $(
            {
                rust_name: $rust_name:tt,
                ruby_name: $ruby_name:tt,
                struct: { $($struct:tt)* },
                methods: [ $($method:tt)* ]
            }
        )* ]
    } => {
        $(
            $($struct)*

            impl $rust_name {
                $($method)*
            }
        )*
    };
}

#[macro_export]
macro_rules! codegen_pub_classes {
    {
            $({
                type: class,
                rust_name: $rust_name:tt,
                ruby_name: $ruby_name:tt,
                meta: { pub: $pub:tt, reopen: $reopen:tt },
                struct: $struct:tt,
                methods: [ $($method:tt)* ]
            })*
    } => {
        $(
            codegen_pub_classes! {
                type: class,
                rust_name: $rust_name,
                ruby_name: $ruby_name,
                pub: $pub
            }
        )*
    };

    {
        type: class,
        rust_name: $rust_name:tt,
        ruby_name: $ruby_name:tt,
        pub: false
    } => {};

    {
        type: class,
        rust_name: $rust_name:tt,
        ruby_name: $ruby_name:tt,
        pub: true
    } => {
        pub use self::init_native::$rust_name;
    };
}

#[macro_export]
macro_rules! codegen_struct {
    { pub: false, rust_name: $rust_name:tt, ruby_name: $ruby_name:tt, struct: () } => {
        codegen_struct! { pub: {}, rust_name: $rust_name, ruby_name: $ruby_name, struct: {} }
    };

    { pub: true, rust_name: $rust_name:tt, ruby_name: $ruby_name:tt, struct: () } => {
        codegen_struct! { pub: { pub }, rust_name: $rust_name, ruby_name: $ruby_name, struct: {} }
    };

    { pub: false, rust_name: $rust_name:tt, ruby_name: $ruby_name:tt, struct: { $($rest:tt)* } } => {
        codegen_struct! { pub: {}, rust_name: $rust_name, ruby_name: $ruby_name, struct: { $($rest)* } }
    };

    { pub: true, rust_name: $rust_name:tt, ruby_name: $ruby_name:tt, struct: { $($rest:tt)* } } => {
        codegen_struct! { pub: { pub }, rust_name: $rust_name, ruby_name: $ruby_name, struct: { $($rest)* } }
    };

    {
        pub: { $($pub:tt)* },
        rust_name: $rust_name:tt,
        ruby_name: $ruby_name:tt,
        struct: { $($struct:tt)* }
    } => {
        #[derive(Clone, Debug)]
        #[repr(C)]
        $($pub)* struct $rust_name {
            helix: $crate::Metadata,
            $($struct)*
        }

        #[allow(non_upper_case_globals)]
        static mut $rust_name: usize = 0;
    }
}

#[macro_export]
macro_rules! codegen_method {
    {
        {
            type: initializer,
            rust_name: $rust_name:tt,
            ruby_name: $ruby_name:tt,
            self: {
                ownership: {},
                name: $self:tt
            },
            args: [ $($arg:tt : $argty:ty),* ],
            ret: { $($ret:tt)* },
            body: $body:block
        }
    } => {
        pub fn $rust_name($self : $crate::Metadata, $($arg : $argty),*) -> $($ret)* $body
    };

    {
        {
            type: class_method,
            rust_name: $rust_name:tt,
            ruby_name: $ruby_name:tt,
            self: (),
            args: [ $($args:tt)* ],
            ret: { $($ret:tt)* },
            body: $body:block
        }
    } => {
        pub fn $rust_name($($args)*) -> $($ret)* $body
    };

    {
        {
            type: instance_method,
            rust_name: $rust_name:tt,
            ruby_name: $ruby_name:tt,
            self: {
                ownership: { $($ownership:tt)* },
                name: $self:tt
            },
            args: [ $($args:tt)* ],
            ret: { $($ret:tt)* },
            body: $body:block
        }
    } => {
        pub fn $rust_name($($ownership)* $self, $($args)*) -> $($ret)* $body
    };
}

#[macro_export]
macro_rules! codegen_extra_impls {
    ($class:tt) => (
        codegen_allocator!($class);
        codegen_coercions!($class);
    )
}