Share macro code between tp_new and other class methods.
This commit is contained in:
parent
79707c03d2
commit
a14e3d2b77
|
@ -26,6 +26,8 @@
|
||||||
shared, // for std::ptr::Shared (#27730)
|
shared, // for std::ptr::Shared (#27730)
|
||||||
//recover, // for converting panics to python exceptions (#27719)
|
//recover, // for converting panics to python exceptions (#27719)
|
||||||
// -- TODO wait for stable release and promote recover code from cfg(nightly)
|
// -- TODO wait for stable release and promote recover code from cfg(nightly)
|
||||||
|
|
||||||
|
// -- TODO remove <DUMMY> hack when it's no longer necessary on stable
|
||||||
))]
|
))]
|
||||||
|
|
||||||
#![allow(unused_imports)] // because some imports are only necessary with python 2.x or 3.x
|
#![allow(unused_imports)] // because some imports are only necessary with python 2.x or 3.x
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
This python script generates the py_class_impl! macro.
|
This python script generates the py_class_impl! macro.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
import sys
|
||||||
|
|
||||||
header = '''
|
header = '''
|
||||||
// Copyright (c) 2016 Daniel Grunwald
|
// Copyright (c) 2016 Daniel Grunwald
|
||||||
//
|
//
|
||||||
|
@ -230,47 +233,142 @@ def data_decl():
|
||||||
}};
|
}};
|
||||||
''')
|
''')
|
||||||
|
|
||||||
def tp_new(with_params):
|
indentation = [' ']
|
||||||
if with_params:
|
last_char = '\n'
|
||||||
param_capture = ', $($p:tt)+'
|
|
||||||
tp_new = '''py_argparse_parse_plist_impl!{
|
def write(text):
|
||||||
py_class_wrap_newfunc {$class::__new__}
|
global last_char
|
||||||
[] ($($p)+,)
|
for line in text.splitlines(True):
|
||||||
}'''
|
line = line.lstrip(' ')
|
||||||
impl = '''py_argparse_parse_plist_impl!{
|
if len(line.strip()) == 0 and last_char == '\n':
|
||||||
py_class_impl_item { $class, $py, __new__($cls: &$crate::PyType,) $res_type; { $($body)* } }
|
continue
|
||||||
[] ($($p)+,)
|
if last_char == '\n':
|
||||||
}'''
|
initial_closing = 0
|
||||||
print(' // def __new__(cls, params)')
|
for c in line:
|
||||||
|
if c in ']}':
|
||||||
|
initial_closing += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if initial_closing:
|
||||||
|
sys.stdout.write(''.join(indentation[:-initial_closing]))
|
||||||
|
else:
|
||||||
|
sys.stdout.write(''.join(indentation))
|
||||||
|
elif last_char not in ' \n' and len(line) > 0 and line[0] not in ' \n;':
|
||||||
|
sys.stdout.write(' ')
|
||||||
|
sys.stdout.write(line)
|
||||||
|
min_indent_level = len(indentation)
|
||||||
|
for c in line:
|
||||||
|
if c in '[{':
|
||||||
|
if len(indentation) > min_indent_level:
|
||||||
|
indentation.append('')
|
||||||
|
else:
|
||||||
|
indentation.append(' ')
|
||||||
|
elif c in ']}':
|
||||||
|
indentation.pop()
|
||||||
|
if len(indentation) < min_indent_level:
|
||||||
|
min_indent_level = len(indentation)
|
||||||
|
last_char = line[-1]
|
||||||
|
|
||||||
|
Slot = namedtuple('Slot', ['slot_type', 'slot_name'])
|
||||||
|
|
||||||
|
def generate_case(pattern, new_impl=None, new_slots=None, new_members=None):
|
||||||
|
write('{ $class:ident $py:ident')
|
||||||
|
write('$info:tt')
|
||||||
|
if new_slots:
|
||||||
|
write('\n/* slots: */ {\n')
|
||||||
|
if any(s.slot_type == 'type_slots' for s, v in new_slots):
|
||||||
|
write('\n/* type_slots */ [ $( $type_slot_name:ident : $type_slot_value:expr, )* ]\n')
|
||||||
|
else:
|
||||||
|
write('$type_slots:tt')
|
||||||
|
write('$as_number:tt')
|
||||||
|
write('$as_sequence:tt')
|
||||||
|
write('\n}\n')
|
||||||
else:
|
else:
|
||||||
param_capture = ''
|
write('$slots:tt')
|
||||||
tp_new = 'py_class_wrap_newfunc!($class::__new__ [])'
|
if new_impl is not None:
|
||||||
impl = 'py_class_impl_item! { $class, $py, __new__($cls: &$crate::PyType,) $res_type; { $($body)* } [] }'
|
write('\n{ $( $imp:item )* }\n')
|
||||||
print(' // def __new__(cls)')
|
else:
|
||||||
print(''' { $class:ident $py:ident $info:tt
|
write('$impls:tt')
|
||||||
/* slots: */ {
|
if new_members:
|
||||||
/* type_slots */ [ $( $slot_name:ident : $slot_value:expr, )* ]
|
write('\n{ $( $member_name:ident = $member_expr:expr; )* }')
|
||||||
$as_number:tt $as_sequence:tt
|
else:
|
||||||
}
|
write('$members:tt')
|
||||||
{ $( $imp:item )* } $members:tt;
|
write(';\n')
|
||||||
def __new__ ($cls:ident%s)
|
write(pattern)
|
||||||
-> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
write('$($tail:tt)*\n')
|
||||||
} => { py_class_impl! {
|
write('} => { py_class_impl! {\n')
|
||||||
$class $py $info
|
write('$class $py')
|
||||||
/* slots: */ {
|
write('$info')
|
||||||
/* type_slots */ [
|
if new_slots:
|
||||||
$( $slot_name : $slot_value, )*
|
write('\n/* slots: */ {\n')
|
||||||
tp_new: Some(%s),
|
if any(s.slot_type == 'type_slots' for s, v in new_slots):
|
||||||
]
|
write('\n/* type_slots */ [\n')
|
||||||
$as_number $as_sequence
|
write('$( $type_slot_name : $type_slot_value, )*\n')
|
||||||
}
|
for s, v in new_slots:
|
||||||
/* impl: */ {
|
if s.slot_type == 'type_slots':
|
||||||
$($imp)*
|
write('%s: %s,\n' % (s.slot_name, v))
|
||||||
%s
|
write(']\n')
|
||||||
}
|
else:
|
||||||
$members;
|
write('$type_slots')
|
||||||
$($tail)*
|
write('$as_number')
|
||||||
}};''' % (param_capture, tp_new, impl))
|
write('$as_sequence')
|
||||||
|
write('\n}\n')
|
||||||
|
else:
|
||||||
|
write('$slots')
|
||||||
|
if new_impl is not None:
|
||||||
|
write('\n/* impl: */ {\n')
|
||||||
|
write('$($imp)*\n')
|
||||||
|
write(new_impl)
|
||||||
|
write('\n}\n')
|
||||||
|
else:
|
||||||
|
write('$impls')
|
||||||
|
if new_members:
|
||||||
|
write('\n/* members: */ {\n')
|
||||||
|
write('$( $member_name = $member_expr; )*\n')
|
||||||
|
for name, val in new_members:
|
||||||
|
write('%s = %s;\n' % (name, val))
|
||||||
|
write('}')
|
||||||
|
else:
|
||||||
|
write('$members')
|
||||||
|
write('; $($tail)*\n')
|
||||||
|
write('}};\n')
|
||||||
|
|
||||||
|
def class_method(decoration='', special_name=None,
|
||||||
|
slot=None, add_member=False, value_macro=None, value_args=None):
|
||||||
|
assert(slot is None or isinstance(slot, Slot))
|
||||||
|
name_pattern = special_name or '$name:ident'
|
||||||
|
name_use = special_name or '$name'
|
||||||
|
def impl(with_params):
|
||||||
|
if with_params:
|
||||||
|
param_pattern = ', $($p:tt)+'
|
||||||
|
impl = '''py_argparse_parse_plist_impl!{
|
||||||
|
py_class_impl_item { $class, $py, %s($cls: &$crate::PyType,) $res_type; { $($body)* } }
|
||||||
|
[] ($($p)+,)
|
||||||
|
}''' % name_use
|
||||||
|
value = 'py_argparse_parse_plist_impl!{%s {%s} [] ($($p)+,)}' \
|
||||||
|
% (value_macro, value_args)
|
||||||
|
else:
|
||||||
|
param_pattern = ''
|
||||||
|
impl = 'py_class_impl_item! { $class, $py,%s($cls: &$crate::PyType,) $res_type; { $($body)* } [] }' \
|
||||||
|
% name_use
|
||||||
|
value = '%s!{%s []}' % (value_macro, value_args)
|
||||||
|
pattern = '%s def %s ($cls:ident%s) -> $res_type:ty { $( $body:tt )* }' \
|
||||||
|
% (decoration, name_pattern, param_pattern)
|
||||||
|
slots = []
|
||||||
|
if slot is not None:
|
||||||
|
slots.append((slot, value))
|
||||||
|
members = []
|
||||||
|
if add_member:
|
||||||
|
members.append((name_use, value))
|
||||||
|
generate_case(pattern, new_impl=impl, new_slots=slots, new_members=members)
|
||||||
|
impl(False) # without parameters
|
||||||
|
impl(True) # with parameters
|
||||||
|
|
||||||
|
def tp_new():
|
||||||
|
class_method(special_name='__new__',
|
||||||
|
slot=Slot('type_slots', 'tp_new'),
|
||||||
|
value_macro='py_class_wrap_newfunc',
|
||||||
|
value_args='$class::__new__')
|
||||||
|
|
||||||
def traverse_and_clear():
|
def traverse_and_clear():
|
||||||
print('''
|
print('''
|
||||||
|
@ -342,7 +440,7 @@ def traverse_and_clear():
|
||||||
$($tail)*
|
$($tail)*
|
||||||
}};''')
|
}};''')
|
||||||
|
|
||||||
general_cases = '''
|
instance_method = '''
|
||||||
// def instance_method(&self)
|
// def instance_method(&self)
|
||||||
{ $class:ident $py:ident $info:tt $slots:tt
|
{ $class:ident $py:ident $info:tt $slots:tt
|
||||||
{ $( $imp:item )* }
|
{ $( $imp:item )* }
|
||||||
|
@ -385,50 +483,9 @@ general_cases = '''
|
||||||
};
|
};
|
||||||
$($tail)*
|
$($tail)*
|
||||||
}};
|
}};
|
||||||
|
'''
|
||||||
|
|
||||||
// @classmethod def class_method(cls)
|
static_method = '''
|
||||||
{ $class:ident $py:ident $info:tt $slots:tt
|
|
||||||
{ $( $imp:item )* }
|
|
||||||
{ $( $member_name:ident = $member_expr:expr; )* };
|
|
||||||
@classmethod def $name:ident ($cls:ident)
|
|
||||||
-> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
|
||||||
} => { py_class_impl! {
|
|
||||||
$class $py $info $slots
|
|
||||||
/* impl: */ {
|
|
||||||
$($imp)*
|
|
||||||
py_class_impl_item! { $class, $py, $name($cls: &$crate::PyType,) $res_type; { $($body)* } [] }
|
|
||||||
}
|
|
||||||
/* members: */ {
|
|
||||||
$( $member_name = $member_expr; )*
|
|
||||||
$name = py_class_class_method!{$py, $class::$name []};
|
|
||||||
};
|
|
||||||
$($tail)*
|
|
||||||
}};
|
|
||||||
// @classmethod def class_method(cls, params)
|
|
||||||
{ $class:ident $py:ident $info:tt $slots:tt
|
|
||||||
{ $( $imp:item )* }
|
|
||||||
{ $( $member_name:ident = $member_expr:expr; )* };
|
|
||||||
@classmethod def $name:ident ($cls:ident, $($p:tt)+)
|
|
||||||
-> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
|
||||||
} => { py_class_impl! {
|
|
||||||
$class $py $info $slots
|
|
||||||
/* impl: */ {
|
|
||||||
$($imp)*
|
|
||||||
py_argparse_parse_plist_impl!{
|
|
||||||
py_class_impl_item { $class, $py, $name($cls: &$crate::PyType,) $res_type; { $($body)* } }
|
|
||||||
[] ($($p)+,)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* members: */ {
|
|
||||||
$( $member_name = $member_expr; )*
|
|
||||||
$name = py_argparse_parse_plist_impl!{
|
|
||||||
py_class_class_method {$py, $class::$name}
|
|
||||||
[] ($($p)+,)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
$($tail)*
|
|
||||||
}};
|
|
||||||
|
|
||||||
// @staticmethod def static_method(params)
|
// @staticmethod def static_method(params)
|
||||||
{ $class:ident $py:ident $info:tt $slots:tt
|
{ $class:ident $py:ident $info:tt $slots:tt
|
||||||
{ $( $imp:item )* }
|
{ $( $imp:item )* }
|
||||||
|
@ -627,12 +684,16 @@ def main():
|
||||||
print(macro_start)
|
print(macro_start)
|
||||||
print(base_case)
|
print(base_case)
|
||||||
data_decl()
|
data_decl()
|
||||||
tp_new(False)
|
tp_new()
|
||||||
tp_new(True)
|
|
||||||
traverse_and_clear()
|
traverse_and_clear()
|
||||||
for name, f in sorted(special_names.items()):
|
for name, f in sorted(special_names.items()):
|
||||||
f(name)
|
f(name)
|
||||||
print(general_cases)
|
print(instance_method)
|
||||||
|
class_method(decoration='@classmethod',
|
||||||
|
add_member=True,
|
||||||
|
value_macro='py_class_class_method',
|
||||||
|
value_args='$py, $class::$name')
|
||||||
|
print(static_method)
|
||||||
print(macro_end)
|
print(macro_end)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -224,49 +224,43 @@ macro_rules! py_class_impl {
|
||||||
$($tail)*
|
$($tail)*
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// def __new__(cls)
|
|
||||||
{ $class:ident $py:ident $info:tt
|
{ $class:ident $py:ident $info:tt
|
||||||
/* slots: */ {
|
/* slots: */ {
|
||||||
/* type_slots */ [ $( $slot_name:ident : $slot_value:expr, )* ]
|
/* type_slots */ [ $( $type_slot_name:ident : $type_slot_value:expr, )* ]
|
||||||
$as_number:tt $as_sequence:tt
|
$as_number:tt $as_sequence:tt
|
||||||
}
|
}
|
||||||
{ $( $imp:item )* } $members:tt;
|
{ $( $imp:item )* }
|
||||||
def __new__ ($cls:ident)
|
$members:tt;
|
||||||
-> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
def __new__ ($cls:ident) -> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
||||||
} => { py_class_impl! {
|
} => { py_class_impl! {
|
||||||
$class $py $info
|
$class $py $info
|
||||||
/* slots: */ {
|
/* slots: */ {
|
||||||
/* type_slots */ [
|
/* type_slots */ [
|
||||||
$( $slot_name : $slot_value, )*
|
$( $type_slot_name : $type_slot_value, )*
|
||||||
tp_new: Some(py_class_wrap_newfunc!($class::__new__ [])),
|
tp_new: py_class_wrap_newfunc!{$class::__new__ []},
|
||||||
]
|
]
|
||||||
$as_number $as_sequence
|
$as_number $as_sequence
|
||||||
}
|
}
|
||||||
/* impl: */ {
|
/* impl: */ {
|
||||||
$($imp)*
|
$($imp)*
|
||||||
py_class_impl_item! { $class, $py, __new__($cls: &$crate::PyType,) $res_type; { $($body)* } [] }
|
py_class_impl_item! { $class, $py,__new__($cls: &$crate::PyType,) $res_type; { $($body)* } [] }
|
||||||
}
|
}
|
||||||
$members;
|
$members; $($tail)*
|
||||||
$($tail)*
|
|
||||||
}};
|
}};
|
||||||
// def __new__(cls, params)
|
|
||||||
{ $class:ident $py:ident $info:tt
|
{ $class:ident $py:ident $info:tt
|
||||||
/* slots: */ {
|
/* slots: */ {
|
||||||
/* type_slots */ [ $( $slot_name:ident : $slot_value:expr, )* ]
|
/* type_slots */ [ $( $type_slot_name:ident : $type_slot_value:expr, )* ]
|
||||||
$as_number:tt $as_sequence:tt
|
$as_number:tt $as_sequence:tt
|
||||||
}
|
}
|
||||||
{ $( $imp:item )* } $members:tt;
|
{ $( $imp:item )* }
|
||||||
def __new__ ($cls:ident, $($p:tt)+)
|
$members:tt;
|
||||||
-> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
def __new__ ($cls:ident, $($p:tt)+) -> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
||||||
} => { py_class_impl! {
|
} => { py_class_impl! {
|
||||||
$class $py $info
|
$class $py $info
|
||||||
/* slots: */ {
|
/* slots: */ {
|
||||||
/* type_slots */ [
|
/* type_slots */ [
|
||||||
$( $slot_name : $slot_value, )*
|
$( $type_slot_name : $type_slot_value, )*
|
||||||
tp_new: Some(py_argparse_parse_plist_impl!{
|
tp_new: py_argparse_parse_plist_impl!{py_class_wrap_newfunc {$class::__new__} [] ($($p)+,)},
|
||||||
py_class_wrap_newfunc {$class::__new__}
|
|
||||||
[] ($($p)+,)
|
|
||||||
}),
|
|
||||||
]
|
]
|
||||||
$as_number $as_sequence
|
$as_number $as_sequence
|
||||||
}
|
}
|
||||||
|
@ -277,8 +271,7 @@ macro_rules! py_class_impl {
|
||||||
[] ($($p)+,)
|
[] ($($p)+,)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$members;
|
$members; $($tail)*
|
||||||
$($tail)*
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// def __traverse__(self, visit)
|
// def __traverse__(self, visit)
|
||||||
|
@ -992,30 +985,25 @@ macro_rules! py_class_impl {
|
||||||
$($tail)*
|
$($tail)*
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// @classmethod def class_method(cls)
|
|
||||||
{ $class:ident $py:ident $info:tt $slots:tt
|
{ $class:ident $py:ident $info:tt $slots:tt
|
||||||
{ $( $imp:item )* }
|
{ $( $imp:item )* }
|
||||||
{ $( $member_name:ident = $member_expr:expr; )* };
|
{ $( $member_name:ident = $member_expr:expr; )* };
|
||||||
@classmethod def $name:ident ($cls:ident)
|
@classmethod def $name:ident ($cls:ident) -> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
||||||
-> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
|
||||||
} => { py_class_impl! {
|
} => { py_class_impl! {
|
||||||
$class $py $info $slots
|
$class $py $info $slots
|
||||||
/* impl: */ {
|
/* impl: */ {
|
||||||
$($imp)*
|
$($imp)*
|
||||||
py_class_impl_item! { $class, $py, $name($cls: &$crate::PyType,) $res_type; { $($body)* } [] }
|
py_class_impl_item! { $class, $py,$name($cls: &$crate::PyType,) $res_type; { $($body)* } [] }
|
||||||
}
|
}
|
||||||
/* members: */ {
|
/* members: */ {
|
||||||
$( $member_name = $member_expr; )*
|
$( $member_name = $member_expr; )*
|
||||||
$name = py_class_class_method!{$py, $class::$name []};
|
$name = py_class_class_method!{$py, $class::$name []};
|
||||||
};
|
}; $($tail)*
|
||||||
$($tail)*
|
|
||||||
}};
|
}};
|
||||||
// @classmethod def class_method(cls, params)
|
|
||||||
{ $class:ident $py:ident $info:tt $slots:tt
|
{ $class:ident $py:ident $info:tt $slots:tt
|
||||||
{ $( $imp:item )* }
|
{ $( $imp:item )* }
|
||||||
{ $( $member_name:ident = $member_expr:expr; )* };
|
{ $( $member_name:ident = $member_expr:expr; )* };
|
||||||
@classmethod def $name:ident ($cls:ident, $($p:tt)+)
|
@classmethod def $name:ident ($cls:ident, $($p:tt)+) -> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
||||||
-> $res_type:ty { $( $body:tt )* } $($tail:tt)*
|
|
||||||
} => { py_class_impl! {
|
} => { py_class_impl! {
|
||||||
$class $py $info $slots
|
$class $py $info $slots
|
||||||
/* impl: */ {
|
/* impl: */ {
|
||||||
|
@ -1027,12 +1015,8 @@ macro_rules! py_class_impl {
|
||||||
}
|
}
|
||||||
/* members: */ {
|
/* members: */ {
|
||||||
$( $member_name = $member_expr; )*
|
$( $member_name = $member_expr; )*
|
||||||
$name = py_argparse_parse_plist_impl!{
|
$name = py_argparse_parse_plist_impl!{py_class_class_method {$py, $class::$name} [] ($($p)+,)};
|
||||||
py_class_class_method {$py, $class::$name}
|
}; $($tail)*
|
||||||
[] ($($p)+,)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
$($tail)*
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// @staticmethod def static_method(params)
|
// @staticmethod def static_method(params)
|
||||||
|
|
|
@ -106,6 +106,6 @@ macro_rules! py_class_wrap_newfunc {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
wrap_newfunc::<()>
|
Some(wrap_newfunc::<()>)
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue