Rust: مشكلة في التعقب لـ RFC 1566: وحدات الماكرو الإجرائية

تم إنشاؤها على ١٤ ديسمبر ٢٠١٦  ·  184تعليقات  ·  مصدر: rust-lang/rust

الحالة الحالية

تم إغلاق هذه المشكلة لصالح المزيد من مشكلات التتبع الدقيقة

~ الوصف المحدث ~

الخطوات التالية:

  • [x] [Stabilize use_extern_macros ] (https://github.com/rust-lang/rust/pull/50911)

    • في انتظار الحفرة

  • [] ثبّت ميزة proc_macro

سدادات محتملة لتحقيق الاستقرار

الوصف الأصلي

RFC .

يقترح RFC هذا تطورًا لنظام الماكرو الإجرائي لـ Rust (المعروف أيضًا باسم بناء الجملة
ملحقات ، ويعرف أيضًا باسم ملحقات المترجم). يحدد RFC هذا بناء الجملة للتعريف
من وحدات الماكرو الإجرائية ، وجهة نظر عالية المستوى لتنفيذها في المترجم ،
ويوضح كيفية تفاعلهم مع عملية التجميع.

في أعلى مستوى ، يتم تحديد وحدات الماكرو من خلال تنفيذ الوظائف المميزة بعلامة
سمة #[macro] . تعمل وحدات الماكرو على قائمة الرموز المميزة التي يوفرها ملف
برنامج التحويل البرمجي وإرجاع قائمة الرموز المميزة التي تم استبدال استخدام الماكرو بها. نحن
توفر تسهيلات منخفضة المستوى للعمل على هذه الرموز المميزة. مستوى أعلى
يجب أن توجد المرافق (على سبيل المثال ، لتحليل الرموز المميزة إلى AST) كصناديق مكتبة.

خارطة الطريق: https://github.com/rust-lang/rust/issues/38356#issuecomment -274377210.


مهام

  • [x] تنفيذ #[proc_macro_attribute] (PR # 38842).

    • [x] إصلاح # 39347 (PR # 39572).

    • [x] إصلاح # 39336 (PR # 44528).

  • [x] تنفيذ #[proc_macro] (PR # 40129).
  • [x] تحديد وتجميع استخدامات proc_macro_derive s في InvocationCollector (PR # 39391).
  • [x] دعم عمليات الاستيراد الموسعة proc_macro_derive .

    • على سبيل المثال:

#[derive(Trait, OtherTrait)] struct S; // Both these derives should resolve
macro_rules! m { () => {
    #[macro_use(Trait)] extern crate derives;
    use derives::OtherTrait; // this kind of import is gated behind `#![feature(proc_macro)]`
} }
m!();
  • [] قم بتوسيع العناصر قبل التوسيع المطبق proc_macro_derive s (PR # 48465).
  • [x] تنفيذ التحذيرات للواردات غير المستخدمة #[macro_use] (PR # 39060).
  • [x] إعادة تشكيل المحلل اللغوي لاستهلاك الأشجار المميزة (PR # 39118).
  • [x] تنظيف TokenStream استعدادًا لإعادة بناء ديون أخرى (PR # 39173).
  • [x] إزالة TokenTree::Sequence (PR # 39419).
  • [x] استخدم TokenStream s بدلاً من Vec<TokenTree> في المتغير tokenstream::TokenTree Delimited (PR # 40202).
  • [x] استخدم Path s و TokenStream s في ast::Attribute s (PR # 40346).

    • [x] دعم المسارات غير البديهية في وحدات ماكرو السمة / اشتقاق (على سبيل المثال #[foo::bar] ، #[derive(foo::Bar)] ).

  • [x] قم بتضمين معلومات النظافة مع جميع الرموز ، وليس فقط المعرفات (PR # 40597).
  • [x] تنفيذ الحد الأدنى من واجهة برمجة التطبيقات مقابل proc_macro::TokenStream كما هو موضح في RFC (PR # 40939).

    • [x] قم بتضمين المصدر TokenStream s لأجزاء AST المقحمة في Token::Interpolated الرموز المميزة.

    • [x] قم بتضمين أداة عرض أسعار TokenStream proc_macro::quote! خلف بوابة الميزة proc_macro .

  • [x] وفر طريقة لمؤلفي proc_macro لإنشاء التوسعات التي تستخدم العناصر في صندوق محدد مسبقًا foo بدون مطالبة مستخدم الماكرو بتضمين extern crate foo; في جذر الصندوق (PR # 40939).

    • [] تحسين بيئة العمل.

  • [] تضمين المصدر TokenStream s للعناصر في AST.
  • [] فحص الاستقرار (proc-) وحدات ماكرو (الإصدار رقم 34079).
  • [x] السماح للماكرو proc بتهيئة حقل خاص بقيمة def_site (الإصدار رقم 47311). (PR # 48082)
  • [x] عدم الاتساق بين الوصول إلى مجال البنية الداعمة مقابل بنية المجموعة في ماكرو proc (الإصدار رقم 47312). (PR # 48083)
  • [] جعل الأمراض المنقولة جنسياً متاحة لجذر الماكرو في المرحلة 1 (الإصدار رقم 47314).
  • [x] تحسين الخطأ من بناء جملة غير صالح داخل proc_macro::quote! (المشكلة رقم 47315).
  • [] عدم الاتساق بين العرض و IntoIterator في TokenStream الذي يحتوي على وحدة (المشكلة رقم 47627).
  • [x] # [cfg_attr] يجعل .to_string () يختلف مع TokenStream (الإصدار رقم 48644).
  • [x] قائمة أمنيات libproc_macro (قائمة التحقق في # 47786).
A-macros A-macros-1.2 A-macros-2.0 A-plugin B-RFC-approved B-unstable C-tracking-issue T-lang T-libs finished-final-comment-period

التعليق الأكثر فائدة

حسنًا ، هذه المشكلة ضخمة وقد وصلت إلى درجة أنني لا أعتقد أنه من المفيد جدًا الاستمرار في فتحها وتتبع واجهات برمجة التطبيقات. لتحقيق هذه الغاية ، فتحت https://github.com/rust-lang/rust/pull/54728 والذي يقسم هذه المشكلة إلى عدد من مشكلات التتبع الدقيقة:

في هذه المرحلة ، سأغلق هذا ، ولكن إذا نسيت فصل أي مشكلات تتبع أخرى ، فيرجى إبلاغي بذلك! يمكنني بالتأكيد فتح المزيد من المتابعات

ال 184 كومينتر

تضمين التغريدة

أرغب في تنفيذ #[proc_macro_attribute] قريبًا. لدي بالفعل نموذج أولي واختبار استخدام قمت به قبل أن أدرك أنه لا يوجد دعم مترجم حتى الآن: غير مستمتع:

النموذج الأولي: https://github.com/abonander/anterofit/blob/proc_macro/macros/src/lib.rs
مثال / اختبار: https://github.com/abonander/anterofit/blob/proc_macro/examples/post_service_proc_macro.rs

مهام

(تحرير dtolnay: نقل قائمة المراجعة لأعلى إلى OP)

سم مكعبnrcpetrochenkovdurkaRalith

jseyfried لقد واجهت مشكلة حيث إذا تم استيراد ماكرو قديم

abonander تشترك كافة وحدات الماكرو (فرقعة

آسف على تأخري في الحفلة. أنا سعيد بالتوجيه الخاص بكشف الرموز المميزة بدلاً من AST ، ولكن لدي بعض المخاوف بشأن واجهة برمجة التطبيقات TokenStream المقترحة في RFC :

pub enum TokenKind {
    Sequence(Delimiter, TokenStream),

    // The content of the comment can be found from the span.
    Comment(CommentKind),

    // `text` is the string contents, not including delimiters. It would be nice
    // to avoid an allocation in the common case that the string is in the
    // source code. We might be able to use `&'codemap str` or something.
    // `raw_markers` is for the count of `#`s if the string is a raw string. If
    // the string is not raw, then it will be `None`.
    String { text: Symbol, raw_markers: Option<usize>, kind: StringKind },

    // char literal, span includes the `'` delimiters.
    Char(char),

    // These tokens are treated specially since they are used for macro
    // expansion or delimiting items.
    Exclamation,  // `!`
    Dollar,       // `$`
    // Not actually sure if we need this or if semicolons can be treated like
    // other punctuation.
    Semicolon,    // `;`
    Eof,          // Do we need this?

    // Word is defined by Unicode Standard Annex 31 -
    // [Unicode Identifier and Pattern Syntax](http://unicode.org/reports/tr31/)
    Word(Symbol),
    Punctuation(char),
}

pub enum StringKind {
    Regular,
    Byte,
}

ليس من الواضح ما إذا كان المقصود من واجهة برمجة التطبيقات هذه أن تكون خطة كاملة تم قبولها عند دمج RFC ، أو مجرد مثال يتم العمل عليه لاحقًا.

بشكل عام ، يبدو هذا بعيدًا عن صيغة الصدأ "العادية" التي يقبلها المترجم خارج وحدات الماكرو. بينما سترغب بعض وحدات الماكرو في تحليل بعض اللغات الخاصة بالمجال المخصص ، سيرغب البعض الآخر في تحليل بنية "Rust الفعلي" وفهمها.

  1. (ثانوي) لا أعتقد أن Eof ضروري. من المفترض أن يتم استخدام Iterator للتكرار على TokenStream و Iterator::next لإرجاع None للإشارة إلى نهاية التكرار.

  2. (ثانوي) لا أعتقد أن Exclamation أو Dollar أو Semicolon ضرورية. المطابقة على Punctuation('!') على سبيل المثال ليست أكثر صعوبة.

  3. (ثانوي) كما ذكر آخرون في RFC PR ، قد نرغب في حذف التعليقات التي ليست تعليقات وثيقة. (أي حالة استخدام تريد الاحتفاظ بالتعليق تريد على الأرجح الاحتفاظ بالمسافة البيضاء أيضًا.)

  4. بقدر ما أستطيع أن أقول ، ما الذي يجب فعله مع المشغلين متعددي الأحرف (ربما يجب أن يكون كل منهم رمزًا مميزًا واحدًا) لا يزال سؤالًا مفتوحًا. تمت مناقشة أحد الحلول الممكنة في تعليقات العلاقات العامة ، ولكن يبدو أن ذلك لم يتم تحويله إلى نص RFC.

  5. عدد حرفية مفقودة. هل من المفترض أن تقوم وحدات الماكرو بتحليل [Punct('1'), Punct('_'), Punct('2'), Punct('3'), Punct('4'), Punct('.'), Punct('5'), Punct('e'), Punct('6')] بنفسها لتقييم حرفي؟ لا يمكنهم حتى استخدام str::parse::<f32> للقيام بذلك ، نظرًا لأن البنية التي يقبلها ليست هي نفسها البنية الحرفية لـ Rust (والتي يمكن أن تحتوي على _ في المنتصف ، على سبيل المثال).

    أتخيل أن هناك قلقًا بشأن الاستقرار هنا. هل يمكننا تقديم أنواع رقمية جديدة مثل u128 / i128 (وربما في المستقبل f128 ، u256 ،…) وقيمها الحرفية ، دون تغيير التغييرات إلى واجهة برمجة تطبيقات الرموز المميزة؟ قد تكون إحدى الطرق لتحقيق ذلك هي:

    struct IntegerLiteral { negative: bool, decimal_digits: String, type_suffix: Option<String> }
    impl TryInto<u32> IntegerLiteral { type Err = OutOfRange; /* … */ }
    // Other impls for integer types supported in this compiler version
    
    // Something similarly for floats
    

    أو ربما شيء آخر. لكنني لا أعتقد أن عبارة "التظاهر بعدم وجود الأرقام" هي طريقة جيدة للقيام بذلك.

  6. // تم تعريف الكلمة بواسطة ملحق معيار Unicode 31 -

    هذا التعريف يحتاج إلى أن يكون أكثر دقة من ذلك. يحدد UAX 31 صيغتين مختلفتين لصيغة المعرّف ، ولا يُطلق على أي منها اسم "كلمة". لكن اختيار الاختلاف الدقيق الذي نريده هو السبب في أن المعرّفات غير ASCII موصولة بالميزات في الوقت الحالي.

    بدلاً من ذلك ، أعتقد أنه يجب تعريف هذا على أنه "أيًا كان ما يقبله المترجم الحالي كمعرف أو كلمة أساسية" (والتي يمكن أن تتغير حسب # 28979). ربما باستخدام واجهة برمجة تطبيقات عامة pub fn is_identifier(&str) -> bool في libmacro.

  7. تشترك سلاسل Unicode وسلاسل البايت الحرفية في متغير رمز واحد ، والذي أعتقد أنه خطأ لأن تمثيلات الذاكرة لقيمها لها أنواع مختلفة ( str مقابل [u8] ). ليس من الواضح أيضًا ما إذا كان المكوِّن text: Symbol يهدف إلى أن يكون شريحة حرفية من الكود المصدري أو القيمة بعد حل هروب الخط المائل العكسي. أعتقد أنه يجب أن يكون بالتأكيد الأخير. (للمقارنة ، يجب أن يكون Char(char) هو الأخير نظرًا لأن \u{A0} يتطلب أكثر من char للتمثيل الحرفي.)

هناك طريقة أخرى لكتابة وحدات ماكرو عالية المستوى وهي استخدام وحدات الماكرو مثل وحدات الماكرو ، ولكن هذا قد يحتاج إلى تمثيل s-expression لكامل rust ast.

SimonSapin ،

كما ذكر آخرون في RFC PR ، قد نرغب في حذف التعليقات التي ليست تعليقات وثيقة. (أي حالة استخدام تريد الاحتفاظ بالتعليق تريد على الأرجح الاحتفاظ بالمسافة البيضاء أيضًا.)

من فضلك لا. لدي حالة استخدام حيث أريد استخدام التعليقات (على الرغم من عدم الاحتفاظ بها - سيتم كتابتها في منتج تجميع منفصل بدلاً من ذلك) في بناء الجملة.

على وجه التحديد ، أريد إنشاء وحدات ماكرو للترجمة من شأنها تحميل ترجمات لسلسلة من ملف (ملفات) مصدر منفصل وأود إنشاء قائمة من السلاسل لترجمتها كمنتج ثانوي في بناء التصحيح. ويجب أن تكون هناك طريقة لتضمين التعليقات التي سيتم إرسالها إلى تلك القائمة (rust-locale / rust-locale # 19). لذلك من المنطقي استخدام بناء جملة التعليقات ويحتاج الماكرو إلى رؤيتها.

أنا أتفق مع النقاط الأخرى في هذا المنشور.

@ jan-hudec
حتى إذا لم يكن لدينا TokenKind::Comment ، فلا يزال بإمكانك استخدام التعليقات من خلال النظر في محتويات الامتدادات بين الرموز المتتالية.

لا أعتقد أنه لا ينبغي أن يكون لدينا TokenKind::Comment لتشجيع وحدات الماكرو الإجرائية لتجاهل التعليقات حتى يكون المستخدمون أحرارًا في إضافة تعليقات إلى استدعاءات الماكرو دون القلق بشأن تغيير الدلالات.

@ jan-hudec هل هناك سبب لعدم نجاح السمات مع الحل الخاص بك؟

abonander ، السمات لا معنى لها على الإطلاق. تعمل السلاسل المترجمة على أنها حرفية وليست عناصر. لكن استخلاصها أثناء التجميع سيكون فقط للراحة - يمكن دائمًا إجراؤه على أنه تحليل منفصل (وفي الواقع ، قد ينتهي الأمر بذلك ، لأنني بحاجة إلى رؤية _ جميعهم_ في الصندوق وسيؤدي التجميع الإضافي إلى كسر ذلك).

أريد أن أصنع ماكروًا إجرائيًا يعتمد على اشتقاق serde (وبالتالي يستدعي وظائف serde tokenstream مباشرة) ولكن لا توجد طريقة للقول إنني أريد أن أستهلك اشتقاق serde كمكتبة بدلاً من ماكرو إجرائي. هذا ليس حصريًا لاشتقاق وحدات الماكرو ، يمكنني أن أرى شيئًا مشابهًا مطلوبًا لوحدات الماكرو الإجرائية "العادية" أيضًا.

يبدو أن الحل الوحيد في الوقت الحالي هو تفرع serde_derive.

المشكلة هي رسالة الخطأ هذه من rustc:

error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type

من السهل إزالة ذلك وجعله يعمل ، ولكن هناك أيضًا بعض التعقيد الذي لست متأكدًا من كيفية حله - قد يرغب صندوق الماكرو الإجرائي بشكل معقول في استخدام مشتق proc-macro من صندوق ماكرو إجرائي آخر ، وكذلك استدعاء الوظائف لتوليد المشتق لمستخدم في المصب. ماذا سيكون هذا يشبه؟ هل هناك أي شيء مشابه لهذا في الوقت الحالي ، حيث يمكن ربط الصندوق بطريقتين مختلفتين بناءً على طلب الصندوق المستهلك؟

تضمين التغريدة

يمكن أن يرغب صندوق الماكرو الإجرائي في استخدام كل من مشتق proc-macro من صندوق ماكرو إجرائي آخر ، بالإضافة إلى استدعاء الوظائف لتوليد المشتق لمستخدم المصب. ماذا سيكون هذا يشبه؟

لا يمكنك الوصول إلى الوظائف (أو أي شيء آخر إلى جانب وحدات الماكرو الإجرائية) من صندوق proc-macro . إذا كنت ترغب في استخدام وظائف TokenStream -> TokenStream ووحدات الماكرو الإجرائية المقابلة ، فستحتاج إلى وضع وظائف TokenStream -> TokenStream في صندوق منفصل غير proc-macro ، ثم الحصول أيضًا على صندوق proc-macro بتفويض هذه الوظائف فقط.

سيتم تنفيذ هذا RFC في الغالب مرة واحدة # 40939 الأراضي.

وفر طريقة لمؤلفي proc_macro لإنشاء التوسعات التي تستخدم العناصر الموجودة في صندوق محدد مسبقًا foo بدون مطالبة مستخدم الماكرو بتضمين extern crate foo; في جذر الصندوق

افترض أنني أريد تقديم صندوق واحد يحتوي على عناصر غير ماكرو وماكرو إجرائي يشير إلى العناصر المذكورة. عندما يهبط # 40939 ، هل سيكون هذا النمط ثلاثي الصناديق هو الطريقة الاصطلاحية لتحقيق هذا الهدف؟

  1. ضع جميع العناصر غير الكلية في foo_runtime
  2. قم بتنفيذ الماكرو الإجرائي في foo_macros ، بالإشارة إلى الرموز الموجودة في foo_runtime حسب الضرورة
  3. إضافة صندوق "واجهة" نهائي foo بحيث pub use s العناصر من foo_runtime و foo_macros

    • هذا هو الصندوق الوحيد الذي سيستورده المستخدم مباشرة

    • يعمل هذا لأن نظام النظافة يصلح وحدات الماكرو للإشارة إلى الصندوق الصحيح

أسأل لأن حالة الاستخدام الخاصة بي تتضمن استيراد صندوقين ، وسيكون أمرًا رائعًا لسهولة الاستخدام إذا كان بإمكاني التخلص من صندوق واحد فقط.

lfairy أعتقد أن نمط "

  1. ضع جميع العناصر غير الماكرو في foo
  2. قم بتنفيذ الماكرو الإجرائي في foo_macros ، بالإشارة إلى الرموز الموجودة في foo حسب الضرورة ، على سبيل المثال
#[proc_macro]
fn m(_: TokenStream) -> TokenStream {
    quote! {
        extern crate foo; // due to hygiene, this is never a conflict error
        foo::f();
        // --- or just --- (if/when we get the sugar)
        $universe::foo::f();
    }
}
  1. pub use عناصر من foo_macros في foo .

يعمل هذا لأن نظام النظافة يصلح وحدات الماكرو للإشارة إلى الصندوق الصحيح

لا تؤثر إعادة تصدير ماكرو إجرائي في صندوق مختلف على كيفية حل الأسماء من حل الماكرو الإجرائي.

jseyfried : هل تعرف ما إذا كانت خدعة إعادة التصدير هذه تعمل أيضًا مع

@ كولين كيجل
صناديق الاشتقاق المخصصة هي مجرد صناديق ماكرو proc التي لا تحتوي إلا على #[proc_macro_derive] s.
باستخدام #[feature(proc_macro)] ، يمكنك إعادة تصدير المشتقات المخصصة في الصناديق العادية ، تمامًا كما يمكنك إعادة تصدير وحدات ماكرو proc الأخرى.

jseyfried أنا على دراية بالموقف كما هو في الوقت الحالي ، طرحت السؤال لأنني لا أعتقد أنه مثالي

بعد قولي هذا ، أدركت مخاطر التوافق - تصبح tokentree التي تم إنشاؤها بواسطة ماكرو جزءًا من الواجهة المستقرة ، لذلك إذا غيّر serde كيفية إنشاء Derive في إصدار تصحيح وقمت بكتابة ماكرو هش ، سيتم كسر الماكرو لكل مستخدم جديد في الصندوق الخاص بي (على عكس الماكرو الهش في الحالة الحالية ، حيث في أسوأ الحالات ، سيعمل فقط لمدخلات محددة ، ولكن بشكل متسق).

تضمين التغريدة

هل هذا يسحب foo من قائمة البضائع الحالية؟ هذا يبدو سيئًا (على سبيل المثال ، هل سيفعل أي شيء غبيًا بشكل خاص إذا كان هناك صندوقان يحملان اسم foo مرتبطين بالثنائي الحالي؟).

aidanhs من شأنه أن يكون تغيير / إضافة رئيسي للغة يضمن RFC الخاص به.

@ arielb1

هل هذا يسحب foo من قائمة البضائع الحالية؟ هذا يبدو سيئا

نعم - للأسف ، الأسماء المقتبسة من extern crate ليست صحية ، أي أن الدقة تعتمد على أسماء الصناديق التي تقع في النطاق حيث يتم استخدام الماكرو الإجرائي. يمكننا التخفيف من ذلك باستخدام خدعة إعادة التصدير (على سبيل المثال ، إعادة تصدير foo_macros في foo حتى نعرف أن foo سيكون في النطاق) ، لكن هذا لا يحمي ضد أخطاء الغموض عند وجود صندوقين باسم foo .

أعتقد أن أفضل حل هنا هو إضافة تبعيات المرحلة 1 (أي مضيف wrt المستهدف مقابل الهدف) إلى الصناديق Cargo.toml لـ proc-macro عبر وسيطة سطر الأوامر --target-extern . سيسمح لنا ذلك بإدراج أسماء extern crate في النطاق صراحة داخل quote! .

تضمين التغريدة

الفكرة هي أن صندوق proc-macro سيكون له تبعية في البيانات الوصفية "المستهدفة" ، أليس كذلك؟

@ arielb1 نعم ، بالضبط.

سيتم تنفيذ هذا RFC في الغالب مرة واحدة # 40939 الأراضي.

jseyfried كما هو الحال في ، هل

كما هو الحال ، هل أنت مستعد للاستقرار عندما يهبط هذا العلاقات العامة؟

لا ، نريد الحصول على بعض الخبرة مع واجهة برمجة التطبيقات قبل التثبيت وربما إثبات النظافة المستقبلية لأسماء extern crate (أي معالجة هذه المشكلة التي أشار إليها @ arielb1 ).

ربما نرغب في إجراء تغييرات عاجلة على واجهة برمجة التطبيقات هذه ؛ اقترح eddyb / النظر في تعميم OpKind على جميع الأشجار المميزة. أيضًا ، قد نغير طريقة تعاملنا مع تعليقات المستندات ، وحرفية الفاصلة العائمة ، وما إلى ذلك بشكل عام ، فإن واجهة برمجة التطبيقات في هذا العلاقات العامة ليست ناضجة بما يكفي للنظر في الاستقرار حتى الآن.

bstrie للأسف ، فإن RFC لتسريع عملية تثبيت الماكرو proc (مع https://github.com/rust-lang/rfcs/ سحب / 1913

@ est31 مؤجل ، أشبه - بعد قليل من الخبرة مع واجهة برمجة التطبيقات هذه ، قد نتفق على مجموعة فرعية يمكننا الموافقة على المسار السريع إلى الاستقرار.

تتفاعل واجهة برمجة التطبيقات المستندة إلى String بشكل سيئ مع وحدات الماكرو التعريفية 2.0 وهي مقيدة بالفعل اليوم ، حتى بدون وحدات الماكرو 2.0 ومع #[derive] s فقط. نريد تجنب تكاثر واجهة برمجة التطبيقات المستندة إلى String بقدر الإمكان لتجنب المشكلات حيث يهاجر الأشخاص إلى وحدات الماكرو 2.0.

لقد فتحت إصدارًا #[proc_macro_attribute] ما يبدو لم يتم توسيعه في طرق السمات (ربما عناصر السمات بشكل عام؟)

نظرًا لأن هذه هي الآن مشكلة التعقب للصندوق proc_macro وواجهات برمجة التطبيقات الجديدة الخاصة به ، فقد اعتقدت أنني سأقوم بتدوين بعض الأفكار أيضًا. لقد قمت بنشر صندوق يسمى proc-macro2 والذي يُقصد به أن يكون مطابقًا تمامًا للصندوق الموجود في الشجرة proc_macro باستثناء أنه يوفر القدرة على التجميع على الصدأ المستقر. ثم لديه أيضًا القدرة على استخدام ميزة لتجميع الصدأ الليلي للاستفادة من معلومات الامتداد الأفضل. تهدف هذه المكتبة إلى أن تصبح الأساس للمكتبات الأخرى مثل syn ، وفي تطوير syn وجدنا بعض أوجه القصور التي قد نرغب في معالجتها في proc_macro مباشرة:

  • لا يوجد مُنشئ Literal لبعض أنواع القيم الحرفية. يتم العمل على هذا من خلال التشديد متبوعًا بالتحليل ، ولكن سيكون من الرائع أن تكون قادرًا على إنشاء هذه مباشرة دون الحاجة إلى المرور عبر سلسلة API.

    • السلاسل الأولية - r###" foo "###

    • سلاسل البايت الخام - rb#" foo "#

    • بايت حرفية - b'x'

    • تعليقات المستند - يتم تمثيلها حاليًا كرمز مميز Literal .

  • لا توجد طريقة لفحص Literal واستخراج قيمتها. في الوقت الحالي ، نعتمد على صندوق النص الحرفي إلى to_string a حرفيًا ونعيد تحليله ، ولكن هذه المعلومات من الناحية النظرية مخزنة بالفعل في Literal وسيكون من الجيد أن تكون قادرًا على ذلك الوصول إليه.
  • يمكن تفسير تعيين الرموز المميزة في بعض الحالات على أنه غريب بعض الشيء. أي تعليقات المستند الآن تتناسب مع النوع Literal .

أعتقد أنه تمت معالجة جميع الشواغل الأخرى التي بدأت هنا منذ ذلك الحين.

واجهت عطلًا عند الاختبار باستخدام #![feature(proc_macro)] يؤثر على المشتقات المخصصة التي تحتوي على #[proc_macro_derive(foo, attributes(foo))] . أي ، مشتق مخصص له اسم سمة مماثل للاشتقاق المخصص. أحد هذه الصناديق هو سلسلتي المشتقة من الخطأ ، والتي تحتوي على #[derive(error_chain)] #[error_chain(...)] struct ErrorKind { ... } . آخر مشتق جديد ، والذي يحتوي على #[derive(new)] #[new] struct S; . لا أعلم إذا كان هناك آخرون.

بالنسبة إلى رمز مثل هذا ، يشكو المترجم من السمة الثانية التي هي "foo" is a derive mode . هل هذا مقصود أم يمكن إصلاحه؟ إذا كنت بحاجة إلى التحضير لإعادة تسمية مشتق المخصص إلى ErrorChain أو شيء ما إذا كان ذلك مقصودًا.

تضمين التغريدة
كان هذا مقصودًا بشكل عام - نظرًا لأنه يجب توسيع proc_macro_attribute s قبل الاشتقاق ، إذا كان new proc_macro_attribute فإن التوسيع سيكون غامضًا. سيكون من الممكن السماح لـ new على وجه التحديد أن يكون proc_macro_derive ، لكنني لست متأكدًا من أنه يستحق ذلك (قد يكون أيضًا خطرًا على التوافق في المستقبل).

كان هذا مقصودًا بشكل عام - نظرًا لأنه يجب توسيع proc_macro_attributes قبل الاشتقاق ، إذا كان new proc_macro_attribute فإن التوسيع سيكون غامضًا.

حسنًا ، سأعيد تسمية #[derive(error_chain)] إلى #[derive(ErrorChain)] .

سيكون من الممكن السماح لـ new على وجه التحديد أن يكون proc_macro_derive ، لكنني لست متأكدًا من أنه يستحق ذلك (قد يكون أيضًا خطر التوافق في المستقبل).

بالتأكيد ، لم أكن أطلب new ليكون غلافًا خاصًا. لقد كان مجرد مثال من أحد proc_macro_derive s الذي أعرفه عنهما والذي كسره هذا.

Arnavion معذرةً ، تعليقي الأخير لم يكن أوضح - لم أقصد حالة خاصة new وجه التحديد ولكن للسماح #[derive(some_macro)] #[some_attr] struct S; عندما يتحول some_attr إلى proc_macro_derive . عندما يتحول some_attr إلى proc_macro_attribute ، يجب أن يكون هذا خطأ غموض ؛ اليوم ، يعد خطأ غموض إذا تم حل some_attr لأي ماكرو.

نعم حصلت عليها.

( آمل أن يكون هذا هو المكان المناسب لسؤال كهذا. )

ما هي حالة هذا؟

  • [] وفر طريقة لمؤلفي proc_macro لإنشاء التوسعات التي تستخدم العناصر الموجودة في صندوق محدد مسبقًا foo بدون مطالبة مستخدم الماكرو بتضمين extern crate foo; في جذر الصندوق (PR # 40939 ).

لقد هبطت العلاقات العامة ، لكن المربع لم يتم تحديده بعد. ذكر jseyfried شيئًا هنا ويبدو أنه يعمل نوعًا ما. ومع ذلك ، لا يبدو أنه يعمل مع use على الإطلاق:

let call_site_self = TokenTree {
    kind: TokenNode::Term(Term::intern("self")),
    span: Span::call_site(),
};
quote! {
    extern crate foo; // due to hygiene, this is never a conflict error

    // Neither of those works    
    use foo::f;
    use self::foo::f;
    use $call_site_self::foo:f;
}

هل فاتني شيء؟ ما هي الطريقة الاصطلاحية للرموز use من صندوق خارجي يتم استيراده في الماكرو؟

لا يمكنك استخدام use راجع https://github.com/rust-lang/rfcs/issues/959. ولكن بالنسبة إلى الماكرو ، ليس من العيب حقًا استخدام المسار المؤهل بالكامل في كل مرة. (باستثناء السمات على ما أعتقد)

parched شكرًا لربط هذه المشكلة الأخرى. كانت حالة الاستخدام الخاصة بي كما يلي:

في الماكرو الخاص بي ، أريد السماح للمستخدم بكتابة شيء مشابه لمطابقة المطابقة. على وجه التحديد ، يكتب المستخدم Term ويمكن أن يكون هذا إما متغيرًا من التعداد أو اسم متغير بسيط يربط قيمة المطابقة. لكتابة بعض التعليمات البرمجية الزائفة باستخدام بناء جملة macro_rules! :

macro_rules foo {
    ($matcher:ident) => {
        match something() {
            $matcher => {}
            _ => {}
        }
    }
}

الآن أريد أن يكون المستخدم قادرًا فقط على تحديد اسم المتغير بدون اسم التعداد. لذلك أود أن أدخل عبارة use my_crate::AnEnum::*; في الكود المُنشأ. ولكن نظرًا لأن هذا غير ممكن (في الوقت الحالي) ، فأنا بحاجة إلى التحقق بنفسي ما إذا كان $matcher متغيرًا من التعداد أم لا.

آمل أن يكون توضيحي مفهوما. أردت فقط تقديم حالة استخدام أخرى لـ use في رمز تم إنشاؤه باستخدام الماكرو.

LukasKalbertodt هل يمكنك فقط استخدام my_crate::AnEnum::$matcher => {} في match ؟
لا يهم ، أنا مشكلتك - أعتقد أننا سنحتاج https://github.com/rust-lang/rfcs/issues/959 لذلك.

jseyfried لا: يمكن أن يكون $matcher إما اسمًا متغيرًا (في هذه الحالة سيعمل الحل الخاص بك) أو اسم متغير بسيط مثل match x { simple_var_name => {} } . في الحالة الأخيرة لن تعمل AFAICT. (راجع للشغل ، أردت فقط أن أذكر حالة استخدام أخرى لتوضيح أن استخدام use مهم)

تضمين التغريدة

كان هذا مقصودًا بشكل عام - نظرًا لأنه يجب توسيع proc_macro_attributes قبل الاشتقاق ، إذا كان new proc_macro_attribute فإن التوسيع سيكون غامضًا.

حسنًا ، سأعيد تسمية #[derive(error_chain)] إلى #[derive(ErrorChain)] .

يبدو أن سمات المشتقات المخصصة تتعارض أيضًا مع وحدات الماكرو macro_rules ، بدلاً من تجاوزها مثل المشتقات المخصصة بناءً على أمر الاستيراد. هذا هو ، هذا الرمز يجمع:

#![feature(proc_macro)]
#[macro_use] extern crate error_chain; // macro_rules! error_chain
#[macro_use] extern crate derive_error_chain; // #[proc_macro_derive(error_chain, attributes(error_chain))]

#[derive(error_chain)] // No error. Resolves to custom derive
enum ErrorKind {
    /*#[error_chain]*/ // (1) As discussed above, can't use this any more since it conflicts with the name of the custom derive
    Foo,
}

هذا يطابق سلوك مستقر الحالي الصدأ، مع الاستثناء الذي (1) يعمل في مستقر. لقد وثقت بوضوح أن المستخدمين الذين يرغبون في استخدام #[macro_use] مع الصندوق error-chain سيحتاجون إلى استيراده قبل استيراد derive-error-chain .

ولكن حتى إذا قمت بإعادة تسمية المشتق المخصص إلى ErrorChain لجعل (1) يعمل مع ميزة proc_macro (والتي هي بالفعل تغيير فاصل واحد للرمز الثابت):

#![feature(proc_macro)]
#[macro_use] extern crate error_chain; // macro_rules! error_chain
#[macro_use] extern crate derive_error_chain; // #[proc_macro_derive(ErrorChain, attributes(error_chain))]

#[derive(ErrorChain)] // Unique name, so no error
enum ErrorKind {
    #[error_chain] // (2)
    Foo,
}

لا تزال غير مجمعة - السمة عند (2) تنتج الخطأ: macro `error_chain` may not be used in attributes لأن الماكرو macro_rules يتعارض على ما يبدو مع السمة المسجلة بواسطة المشتق المخصص بدلاً من تجاوزها مثل في الحالة الأولى.

لذلك يجب أن إعادة تسمية كل من ينحدر مخصصة وسمة لها. يتم استخدام السمة كثيرًا (واحد على كل متغير من التعداد) من المشتق المخصص (واحد في كل تعداد) ، لذلك يعد هذا تغيير كسر أكبر مما توقعت. أتفهم أن هذا موقف صعب بالنسبة للبناء الخاص بي (إعادة استخدام اسم الماكرو macro_rules لمشتق مخصص وسمته) ، ولكن هذا أيضًا رمز تم تجميعه في مستقر منذ أن كانت المشتقات المخصصة استقرت ، لذلك لم يكن لدي أي سبب للاعتقاد بأنها ستكون مشكلة بعد ستة أشهر.

هل يمكن إجراؤه بحيث تتجاوز سمات المشتقات المخصصة وحدات الماكرو macro_rules تمامًا مثلما تشتق العادة نفسها من وحدات الماكرو macro_rules ؟ في الواقع لا أرى كيف يمكن أن يكون هناك أي غموض بينهما ، لكنني أفترض أنه نفس السبب عند استيراد ماكرو macro_rules بعد مشتق مخصص يحمل نفس الاسم - حيث يتم وضع جميع وحدات الماكرو في نفس مساحة الاسم دون التفكير في نوع الماكرو.

هل هناك "مكان" أقل رسمية للحديث عن وحدات ماكرو proc؟ مثل قناة #rust-proc-macro IRC؟ أرغب في طرح أسئلة صغيرة حول الميزة من وقت لآخر ، ولكن من الخطأ إرسال بريد عشوائي غير مرغوب فيه: see_no_evil: وفي قناة #rust ، لم يعمل معظم الأشخاص مع proc-macros و خاصة واجهة برمجة التطبيقات الجديدة proc_macro (لأنها غير مستقرة وكلها). إذن: أي فكرة أين نناقش هذا الموضوع؟

LukasKalbertodt #rust-internals ، ربما ، أو مجرد بدء موضوع جديد على / r / rust.

TokenStream::from_str هلع عند استخدامه خارج الماكرو الإجرائي (على سبيل المثال في نص بناء):

thread 'main' panicked at 'proc_macro::__internal::with_sess() called before set_parse_sess()!', /checkout/src/libproc_macro/lib.rs:758:8

هل من الممكن / المرغوب استبدال هذا الذعر بخلق "جلسة" وهمية ضمنيًا؟ أو ربما تضيف واجهة برمجة تطبيقات عامة (مع مسار لتحقيق الاستقرار) لإنشاء واحدة؟

هل نظر أي شخص إلى الأدبيات الخاصة بوحدات الماكرو من الأنظمة الأخرى؟ أود أن أسمع أفكار الناس حول هذا. سأتحدث عن المخطط هنا ، لأن هذا أكثر ما أعرفه.

أنا شخصياً أعمل على تنفيذ syntax-rules لمخطط R7RS في مشروعي الخاص ، ووجدت أن syntax-case يمكن أن يشكل الأساس لدعم أنظمة الماكرو غير الصحية والصحية ( defmacro و syntax-rules ). يقوم جنو Guile بهذا. syntax-case أيضًا على دعم للمصدات التي يمكنها إجراء تحقق إضافي من صحة المسند في قوائم كائنات بناء الجملة (أو شيء ما بين سطور TokenStream في المخطط). أستطيع أن أرى أنه يتم العمل على Mark ، ويبدو أنه مستوحى من الروابط كمجموعات من النطاقات .

أيضًا ، هل يجب أن نناقش أيضًا ما إذا كان ينبغي دعم الحساب التعسفي في وقت الترجمة؟ يأخذ Racket في الواقع نهجًا "طوريًا" كاملًا للأشياء ، على ما يبدو ، مع begin-for-syntax يسمح بالتعريفات والحسابات (؟) على مستوى وقت الترجمة أثناء التوسع الكلي. .

من الممكن جدًا التحكم في النظافة باستخدام (datum->syntax <thing-to-copy-scope-from> <thing-to-apply-scope-to>) في المخطط ، مما يسمح لك بالهروب من نطاق الماكرو وبدلاً من ذلك تأخذ نطاقًا من كائن خارج النطاق المباشر.

خذ هذا المثال من The Scheme Programming Language ، الطبعة الثالثة. بواسطة R. Kent Dybvig (Chez Scheme ، الآن في Cisco Systems): http://www.scheme.com/tspl3/syntax.html . يوضح المثال (include "filename.scm") كماكرو syntax-case ، ويسمح للمترجم الفوري باستخدام ماكرو لإعداد وقت التشغيل للقراءة من ملف ومواصلة التقييم. السؤال الأعمق هنا هو ما إذا كنا نريد أن يسمح نظام ماكرو ماكرو بحدوث مثل هذه الأشياء في وقت التوسع الكلي ، وتشغيل حسابات وقت الترجمة مثل تشغيل استيراد ملف (على الرغم من أن هذا يبدو أنه يحدث في وظيفة المترجم المباشر ، لذلك ربما لا نريد القيام بذلك).

ماذا يجب أن تكون حدود وحدات الماكرو؟ أتخيل أن Rust ، الذي يريد تقليل وقت التجميع ، يريد تقييد تقييم وقت الترجمة (وخاصة تجنب الحلقات اللانهائية). لقد اتخذ المضرب منهج "برج المُعدين والموسعات" مع المراحل كما هو مشار إليه في Lisp in Small Pieces. هل نريد السماح بأشياء مثل السماح بالوصول إلى واجهة برمجة تطبيقات وقت الترجمة لإجراء إدخال / إخراج للملف وحساب متكرر محدود؟ هل يجب أن نسمح بأشياء مثل جعل وحدات الماكرو الإجرائية قادرة على تحويل مواصفات جدول بيانات CSV إلى عبارات تبديل؟

أحب أن أسمع عن أنظمة أخرى! سمعت أن Template Haskell لديه أسلوب مثير للاهتمام مع أنواع محددة جيدًا لتمثيل AST ، ويمكن للكسل في Haskell أن يحل محل العديد من استخدامات وحدات الماكرو لهياكل التحكم.

آسف إذا خرجت من الخط.

ماذا يجب أن تكون حدود وحدات الماكرو؟

بالنسبة لوحدات الماكرو الإجرائية ، التي تمت مناقشتها في هذه المسألة ، لا شيء . الماكرو الإجرائي هو امتداد مترجم. يمكن أن يستغرق الأمر قليلاً من كود C ++ ، وتشغيله من خلال clang وإضافة الكائن الناتج إلى التجميع. يمكن أن يستغرق الأمر بعض SQL ، والاستعلام عن قاعدة البيانات للعثور على نوع النتيجة المقابل وإنشاء مجموعة النتائج المناسبة. هذه حالات استخدام فعلية يريد الناس القيام بها!

لاحظ أن Rust لديه نظام ماكرو آخر . تمت الموافقة على التحديث باعتباره RFC 1584 ويتم تتبع التنفيذ من خلال https://github.com/rust-lang/rust/issues/39412.

VermillionAzure ، من نظرة سريعة على نماذج المخطط التي

macro_rules ، وتحديثهم لكل syntax-rules . إذا كانت لديك اقتراحات لتحسينها ، فربما يكون https://github.com/rust-lang/rust/issues/39412 هو أفضل مكان لمناقشة ذلك.

وحدات الماكرو proc ، التي تدور حولها هذه المشكلة ، تشبه النموذج العام define-syntax . وهذا RFC ( 1566 ) عمدا جدا لا يعرف أي شيء مثل syntax-case . فقط واجهة لاستدعاء وظيفة لتحويل تدفق الرمز المميز.

يتم تعريف الواجهة بطريقة تجعل شيئًا مثل syntax-case يمكن تنفيذه في صندوق منفصل (مكتبة) والهدف هو القيام بذلك بهذه الطريقة. إذا كنت تميل إلى هذا الحد ، فلا تتردد في اللعب. سيكون كل من أي نموذج أولي وتقرير عن مدى سهولة أو صعوبة استخدام واجهة برمجة التطبيقات موضع ترحيب بالتأكيد.

أعتقد أن الفكرة كانت ، تحديد وحدات الماكرو مثل الوظائف ، كما هو الحال في lisp ، ولكن مع وجود ماكرو ، يقوم بإرجاع الماكرو ، الذي يحدده macro_rules! .

لذا فإن ما يلي سيكون مكافئًا:

    macro_rules! foo {/*define macro here*/}
#[proc_macro]
pub fn foo(tokens: TokenStream) -> TokenStream {
    macro_case! tokens {/*define macro here*/} //takes `tokens` as first argument, returns a `TokenStream`
}

هكذا يبدو أن syntax-rules و syntax-case يعملان في المخطط.

تضمين التغريدة
هل هذا ما تريد؟

@ porky11 لا ، لا يبدو الأمر كذلك. أردت فقط أن نرى ما اذا كان حدات الماكرو مخطط ستكون فكرة ذات الصلة إضافة إلى مناقشة - فمن الواضح أنه منذ يقصد حدات الماكرو الإجرائية لتكون أكثر قوة بكثير من syntax-case النظام الكلي في مخطط أنها تافهة لتنفيذ جميع أنظمة الماكرو من حيث السلطة التعسفية المنصوص عليها هنا.

@ jan-hudec هل من الحكمة السماح بأي حساب تعسفي كامتداد مترجم دون أي نوع من الضمان الأمني؟ لقد تأثرت تمامًا بفكرة أن وحدات الماكرو الإجرائية ستكون قوية جدًا هنا ، ولكن هل سيعتبر أي مستخدم محتمل لـ Rust هذا جانبًا سلبيًا لاستخدام الحزم؟ أنا لست خبيرًا أمنيًا بأي وسيلة ، ولكن لا يمكن استخدام الثغرات الأمنية في أي مكتبات مستخدمة ضمن امتدادات المترجم بسهولة لتحويل مترجم Rust بشكل ضار إلى ناقل هجوم؟ بالإضافة إلى ذلك ، في حالة حدوث أي أخطاء في المكتبات المستخدمة في وحدات الماكرو الإجرائية (على سبيل المثال ، تم تشغيل segfault بواسطة رمز مكتبة C غير صحيح) ، فهل هذا يعني أن segfault قد تتسرب وتجعل المترجم يفشل بدون رسائل خطأ مناسبة؟

هل ستكون هناك طريقة لتغليف الأخطاء التي تحدث في وحدات الماكرو الإجرائية بطريقة لا تؤثر على أي أجزاء أخرى من المترجم؟

فكرة أخرى: متى يتم تنفيذ وحدات الماكرو الإجرائية؟ إذا كان بإمكان وحدات الماكرو الإجرائية التفاعل مع التعليمات البرمجية التي لها آثار جانبية يمكن أن تكون ذات صلة (على سبيل المثال ، الاتصال بخادم خارجي ذي حالة جيدة ، أو تغيير قاعدة بيانات SQL خارجية ، أو الحصول على مفتاح أمان لتسجيل الدخول إلى نظام خارجي) ، فهذا لا يعني أن الترتيب الذي يتم فيه تشغيل وحدات الماكرو الإجرائية من خلال عملية التجميع مهم؟

يمكن أن تحتوي حزم VermillionAzure Cargo بالفعل على نصوص برمجية تقوم بتنفيذ تعليمات برمجية عشوائية في وقت الترجمة ، لذلك لا تجعل وحدات الماكرو الإجرائية الأمور أسوأ على هذا الصعيد: فأنت تحتاج بالفعل إلى الوثوق في تبعياتك. (أصبح هذا الأمر أسهل إلى حد ما من خلال كون crates.io غير قابل للتغيير / إلحاق فقط ، وعدم تحديث التبعيات تلقائيًا إذا كان لديك ملف Cargo.lock : ما عليك سوى الوثوق بإصدارات محددة.) وحتى إذا لم يكن إنشاء البرامج النصية كذلك موجودة ، لا يزال بإمكان تبعياتك بطبيعتها تنفيذ تعليمات برمجية عشوائية في وقت التشغيل. هل وقت الترجمة أسوأ بكثير؟

هذه المناقشة تجعلني أفكر في مشكلة ذات صلة ولكنها مختلفة.

افترض أن أحد الصناديق يعرّف وحدتي ماكرو من proc: يكتب foo!() ملفًا مؤقتًا ، ويقرأ bar!() نفس الملف. يستدعي مستهلك هذا الصندوق كلاً من foo!() و bar!() في نفس الوحدة. بعد ذلك ، سيعتمد ما إذا كان التجميع ناجحًا أم لا على أي من foo!() أو bar!() يتم توسيعه أولاً. يتم تحديد هذا الترتيب حسب التنفيذ ، وإذا كتب عدد كافٍ من الأشخاص رمزًا مثل هذا ، فقد يصبح معيارًا واقعيًا.

لست متأكدًا من حجم المشكلة بالرغم من ذلك. فقط قلق بشأن ما إذا كان هذا سيؤدي إلى تكرار ترتيب المجال البنائي للخدع.

تضمين التغريدة

بينما أتفق مع موقفك ، يجب أن أشير إلى أن هناك فرقًا واحدًا مهمًا بين تنفيذ وقت الترجمة وتنفيذ وقت التشغيل:

يوفر نموذج تهديد مختلفًا نظرًا لأن الأشياء تميل إلى تجميعها مرة واحدة ثم نشرها على العديد من الأجهزة. (على سبيل المثال ، استغلال عدم انتباه المشرف بالإضافة إلى قصور في وضع الحماية في مجموعة إنشاء توزيعة Linux.)

lfairy نعم، هذه هي القضية الدقيقة التي مضرب كان قبل أكثر من عشر سنوات إلى الوراء في عام 2002. ماثيو فلات، وهو أعلى مساهم في مضرب، التي تم إنشاؤها ورقة بعنوان "Composable وتحويل البرمجي وحدات الماكرو: أنت تريد ذلك . رى كينت ديبويغ، الذي عمل في مخطط Chez ، كتب أيضًا ورقة حول مراحل تقييم المكتبات / الوحدات في "التدرج الضمني في مكتبات R6RS" .

SimonSapin يمكن أن يكون وقت

VermillionAzure ، لم أقرأ المقالات بعناية شديدة ، لكنني لا أعتقد أنها ذات صلة بالمناقشة ، لأن المشكلات التي يواجهها Rust مختلفة تمامًا عن المشكلات التي يواجهها Scheme.

في المخطط ، يمكن أن توفر مكتبة واحدة كلاً من الوظائف ووحدات الماكرو ، لذلك يجب على المترجم أن يفرز بشكل صحيح الوظائف التي يحتاجها وقت الترجمة وأيها يحتاج إلى وقت التشغيل. ومع ذلك ، في Rust ، يوفر الصندوق إما وحدات ماكرو إجرائية ، أو وظائف وقت التشغيل ، لذلك يكون هذا التقسيم واضحًا (في الوقت الحالي).

(لاحظ أن الصندوق الذي يوفر وظائف وقت التشغيل يمكن أن يوفر أيضًا وحدات ماكرو (صحية) قائمة على القواعد ، ولكنها آلية منفصلة في Rust)

المشكلة التي يتحدث عنها lfairy هي طلب تنفيذ وظائف الموسع. في Rust ، قد يكون التجميع متوازيًا لملفات منفصلة وقد يكون تزايديًا ، لذا فإن ترتيب تنفيذ الموسعات غير محدد. ولكن هل تتناول أي من المادتين ذلك بالفعل؟ لم اراه.

@ jan-hudec نعم ، أعتقد أنك على حق. لكن ترتيب التقييم سيكون مهمًا بالتأكيد إذا تم السماح بالآثار الجانبية في وقت التجميع ، إلا إذا كان بإمكانك ضمان أن وحدة معينة لا تنتج آثارًا جانبية. هل الوحدة النمطية "قابلة للكتابة؟"

أعتقد أن الماكرو الإجرائي "ربما لا ينبغي" أن يكون له آثار جانبية لأن بعض التفاصيل (انظر أدناه) لا يمكن الاعتماد عليها ، ولكن من المحتمل ألا يكون لدينا آلية شبيهة بالنظام في اللغة لإجبارها على أن تكون بحتة وظيفي.

تتضمن هذه التفاصيل طلب التنفيذ والتزامن مقارنة بوحدات ماكرو عملية أخرى ، وما إذا كان يتم إعادة تنفيذ ماكرو proc في بناء تزايدي. بالنسبة إلى الأخير ، قد نرغب في إضافة شيء ما للإعلان عن التبعيات المشابهة لـ rerun-if-changed في نصوص الإنشاء. ومثل إنشاء البرنامج النصي ، قد تكون هذه الإعلانات غير مكتملة أو عربات التي تجرها الدواب. لا يمكننا منع جميع الأخطاء بشكل ثابت.

أعتقد أننا يجب أن نتجنب ضمان أي شيء يتعلق بالآثار الجانبية (على سبيل المثال ، لا يُسمح لصناديق الماكرو proc بالاعتماد على تأثير الآثار الجانبية ، ولا يُسمح لها بالاعتماد على إعادة الربط لأي شيء بخلاف تغيير الكود في الوحدة التي يتم تطبيقها فيها ( لذلك ، لا توجد دولة عالمية).

يمكننا لاحقًا تخفيف هذا المطلب بطريقة لتحديد إعادة التشغيل - إذا - تغيير وأشياء أخرى.

(لدي اقتراح أمان ماكرو / برنامج نصي للبناء العام نصف مخبوز والذي سيساعد هنا إلى حد ما ، لكني لم أقم بصياغته بعد)

يجب وضع وحدات الماكرو / المشتق المخصص لـ IMO في بيئة وضع الحماية بدون أي إدخال / إخراج أو أي اتصال آخر بالخارج ويتم تقييمه بواسطة miri ، ربما باستخدام رافعة رافعة JIT.

@ est31 هذه فكرة جميلة ولكن أشياء مثل infer_schema الديزل! بالفعل
موجود ، يحتاج bindgen إلى قراءة الملفات وتشغيل البرامج ، بما في ذلك! و
الحسد! استخدم I / O.

في 9 تشرين الثاني (نوفمبر) 2017 06:19 ، كتب "est31" [email protected] :

يجب وضع وحدات الماكرو / المشتق المخصص لـ IMO في بيئة وضع الحماية
بدون أي إدخال / إخراج أو اتصال آخر بالخارج ويتم تقييمه بواسطة
ميري ، ربما مع ذراع الرافعة JIT.

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/rust-lang/rust/issues/38356#issuecomment-343124957 ،
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/AAC3n5VOPdKBsu81Sp3tp2XlIQ05L865ks5s0t_PgaJpZM4LMWlc
.

يبدو أن # 40939 و # 44528 قد تم دمجهما بالفعل ... هل يمكنك تحديث قائمة التحقق

تم تحديث @ mark-im.

هل تستطيع وحدات الماكرو الإجرائية إنشاء وحدات ماكرو إجرائية؟

VermillionAzure لم

أثناء المزامنة ، واجهنا قيودًا على proc_macro :: TokenNode اليوم - محددات الكتلة { ... } مرتبطة بمدى واحد فقط في TokenStream للإدخال لذا لا توجد طريقة لتشغيل خطأ يشير إلى إغلاق } . لا يبدو أن Rustc لديها هذا القيد.

mod m {
    type T =
}
error: expected type, found `}`
 --> src/main.rs:3:1
  |
3 | }
  | ^

أفضل الأشياء التي يمكننا القيام بها في ماكرو proc هي الإشارة إلى الرمز المميز الأخير داخل الكتلة ، أو الإشارة إلى الكتلة بأكملها ، أو الإشارة إلى الرمز المميز التالي بعد الكتلة ، ولا شيء من هذا هو ما تريده حقًا لخطأ مثل أعلاه.

قد يكون الحل العام هو جعل Span::start و Span::end إرجاع حرف واحد Span بدلاً من LineColumn كما يفعلون حاليًا ، ثم كشف طريقة انتقل من Span إلى السطر الأول / عمود الامتداد.

sp.begin().line // before
sp.line() // after

sp.end().line // before
sp.end().line() // after

sp.end() // after, not possible before

ذكر abonander الذي أضاف تلك API في # 43604.

اجعل Span :: start و Span :: end يعيدان Span من حرف واحد بدلاً من LineColumn كما يفعلون حاليًا ، ثم يعرضون طريقة للانتقال من Span إلى السطر الأول / عمود الامتداد.

وهذا من شأنه أن يجعل Span يتبنى السلوك الخاص الذي تحتاجه القوائم المحددة ، ولكنه سيكون خاطئًا بالنسبة لجميع النطاقات الأخرى. عموما هذا ليس صحيحا. ضع في اعتبارك الحصول على مدى لتعبير مثل foo(hi) خلال الانضمام إلى الأشياء. أنت الآن تريد أن تشير إلى foo وتأخذ sp.begin() ، لكن sp.begin() نقاط فقط إلى الحرف الأول foo .

أعتقد أن الحلول الأفضل ستكون إضافة فترتين إلى proc_macro::TokenNode::Group أو السماح بإنشاء مسافات عشوائية.

قد يتعين تغيير أنواع الإرجاع Span::begin / end على الرغم من: https://github.com/rust-lang/rust/pull/43604#issuecomment -327643229

أحاول الحصول على Span::def_site() لحل الأمور مقابل ما هو في النطاق في الماكرو الإجرائي الخاص بي. هل أنا أسيء فهم كيف من المفترض أن يعمل هذا؟

يعمل نفس الكود تقريبًا إذا استخدمت Span::call_site() ولديك MySend محددًا في main.rs ، وهو ما أتوقعه. لم أتمكن من تشغيله def_site() رغم ذلك.

#![feature(proc_macro)]

extern crate proc_macro;

use std::marker::Send as MySend;
use proc_macro::{TokenStream, TokenTree, TokenNode, Term, Delimiter, Span};

#[proc_macro]
pub fn impl_mysend_for(tokens: TokenStream) -> TokenStream {
    let span = Span::def_site();
    let ident = tokens.into_iter().next().unwrap();
    vec![
        TokenTree { span, kind: TokenNode::Term(Term::intern("unsafe")) },
        TokenTree { span, kind: TokenNode::Term(Term::intern("impl")) },
        TokenTree { span, kind: TokenNode::Term(Term::intern("MySend")) },
        TokenTree { span, kind: TokenNode::Term(Term::intern("for")) },
        ident,
        TokenTree { span, kind: TokenNode::Group(Delimiter::Brace, TokenStream::empty()) }
    ].into_iter().collect()
}
#![feature(proc_macro)]

extern crate mac;

struct S;
mac::impl_mysend_for!(S);

fn main() {}
error[E0405]: cannot find trait `MySend` in this scope
 --> src/main.rs:6:1
  |
6 | mac::impl_mysend_for!(S);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^ did you mean `Send`?

تتبع ذلك على جانب المزامنة: https://github.com/dtolnay/syn/issues/290.

تضمين التغريدة
تكمن المشكلة هنا في استيراد MySend في المرحلة 0 (على سبيل المثال ، لبنية المضيف عند التحويل البرمجي المتقاطع) ، لذا فهي غير متوفرة في المرحلة 1 (أي عند التجميع للعمارة الهدف).

الحل هنا هو السماح لصناديق proc-macro بالحصول على تبعيات المرحلة الأولى (البنية المستهدفة) حتى نتمكن من استيراد عناصر المرحلة الأولى إلى النطاق.

اليوم ، الحل هو العودة:

quote! { // n.b. non-interpolated tokens from `quote!` have `Span::def_site()`
    mod dummy {
        extern crate std;
        use self::std::marker::Send as MySend;
        unsafe impl MySend for $ident {} // this line is equivalent to what you have above
    }
} 

يمكنك أيضًا إنشاء هذا يدويًا ، فأنا فقط أستخدم quote! للراحة.

بسبب النظافة ، لن يتعارض dummy / std / MySend مع أي شيء آخر في النطاق ، على سبيل المثال ، من الآمن استخدام هذا الماكرو أكثر من مرة في نفس الوحدة ، من الآمن أن تكون "MySend" هي ident ، إلخ.

هذه المشكلة ، بالإضافة إلى الحاجة إلى mod dummy وحلها ، موصوفة بمزيد من التفصيل في https://github.com/rust-lang/rust/issues/45934#issuecomment -344497531.

للأسف ، حتى يتم تنفيذ تبعيات المرحلة الأولى ، سيكون هذا غير مريح.

شكرا jseyfried! انه يعمل انها تعمل. بعض أسئلة المتابعة:

  • في الكود الموجود في تعليقي السابق ، إذا قمت بتغيير impl_mysend_for لإنشاء أداة ضمنية لـ Send بدلاً من MySend فسيتم تجميع كل شيء. ما هو Send يتم حله ولماذا لا يصل إلى تمييز المرحلة 0 مقابل المرحلة 1؟ هل هذا يعمل عن قصد أم عن طريق الصدفة؟

  • ما الأشياء الأخرى الموجودة في النطاق والتي يمكن استخدامها من خلال عملاتي المميزة def_site() ، مثل Send ؟

  • إذا كان MySend يحتاج إلى أن يأتي من مكتبة (مثل تخيل أننا نستمد serde::Serialize ) فإن المستخدم النهائي لا يزال بحاجة إلى serde في ملف Cargo.toml الخاص به ، حتى لو لم نفعل ذلك في حاجة إليها لكتابة extern crate serde . هل سيكون من الممكن الحصول على extern crate مع حل تحديد def_site() مقابل الماكرو الإجرائي Cargo.toml ، و extern crate مع حل تحديد call_site() مقابل المصب Cargo.toml؟

بالنسبة للصناديق الخارجية ، أفترض أن الصناديق ستحتاج إلى أن تكون متاحة بشكل صريح للمرحلة 1 بواسطة الماكرو proc.

#[proc_macro_derive(Serialize, attributes(serde), crates(serde))]

تضمين التغريدة

في الكود الموجود في تعليقي السابق ، إذا قمت بتغيير impl_mysend_for لإنشاء أداة ضمنية للإرسال بدلاً من MySend ، فسيتم تجميع كل شيء. ما هو الإرسال الذي يتم حله ولماذا لا يصل إلى تمييز المرحلة 0 مقابل المرحلة 1؟ هل هذا يعمل عن قصد أم عن طريق الصدفة؟

سؤال جيد. الآن ، المقدمة في النطاق في موقع التعريف (ما لم يكن صندوق proc-macro #![no_implicit_prelude] ) وهذا حادث (بمعنى ما) بسبب تمييز المرحلة 0 مقابل المرحلة 1 كما أشرت .

ومع ذلك ، بالنسبة لبيئة العمل ، أعتقد أن المرحلة الأولى يجب أن تحتوي ضمنيًا على std عند جذر proc-macro (بحيث يمكنك دائمًا quote!(use std::...); ) ومقدمة للراحة / بيئة العمل وبما أن هذه ضمنية بالفعل في المرحلة 0. سيكون هناك مندوب علاقات عامة لإضافة std عند الجذر في المرحلة 1 قريبًا.

ما الأشياء الأخرى الموجودة في النطاق والتي يمكن استخدامها بواسطة الرموز المميزة def_site () الخاصة بي ، مثل Send؟

إلى جانب المقدمة و (قريبًا) std كما تمت مناقشته أعلاه ، فإن الأشياء الأخرى الوحيدة في النطاق في المرحلة 1 هي وحدات الماكرو proc نفسها (وليس وظائف proc-macro ، وهي المرحلة 0).

على سبيل المثال،

#[proc_macro]
fn f(input: TokenStream) -> TokenStream { ... }

#[proc_macro]
fn g(_input: TokenStream) -> TokenStream {
    quote! {
        f!(); ::f!(); // These both resolve to the above proc macro
        f(); // This doesn't resolve since the function is in phase 0
    }
}

هل سيكون من الممكن إنشاء صندوق خارجي باستخدام def_site () حل معرّف مقابل Cargo.toml الخاص بالماكرو الإجرائي ، والصندوق الخارجي مع حل تعريف call_site () مقابل Cargo.toml المتجه نحو المصب؟

نعم ، باستثناء أنني أعتقد أن صندوقًا خارجيًا به Span::def_site() يجب أن يتم حله مقابل تبعيات المرحلة 1 (الهدف) للماكرو الإجرائي Cargo.toml - تبعيات المرحلة 0 الحالية مرتبطة بالمكتبات المترجمة للنظام الأساسي المضيف . نظرًا لعدم وجود تبعيات المرحلة 1 بعد ، فإن اسم الصندوق الخارجي يتم حله بطريقة غير صحية ، وهو أمر مزعج كما أشرت.

بمجرد أن يكون لدينا تبعيات المرحلة 1 ، لن نحتاج إلى اقتباس extern crate s في كل توسيع لتبدأ به ، لذلك ستكون هذه مشكلة أقل. ومع ذلك ، لا يزال يتعين علينا إصلاحه - تتمثل الخطة الحالية في محاولة حل تبعيات الهدف لصندوق proc-macro أولاً ثم الرجوع إلى الدقة غير الصحية مع دورة تحذير ذات أولوية منخفضة لتجنب الاضطراب.

بالنسبة للصناديق الخارجية ، أفترض أن الصناديق ستحتاج إلى أن تكون متاحة بشكل صريح للمرحلة 1 بواسطة الماكرو proc.
#[proc_macro_derive(Serialize, attributes(serde), crates(serde))]

مثير للاهتمام ، يمكننا تنفيذه بهذه الطريقة.

كنت أفكر بدلاً من ذلك في أنه سيتم الإعلان عن صندوق المرحلة 1 في جذر صندوق proc-macro (على سبيل المثال #[phase(1)] extern crate foo; ) بحيث يكون متاحًا تلقائيًا في جميع وحدات الماكرو proc (على سبيل المثال quote!(use foo::bar); ). نظرًا لأن extern crate في طريقه للخروج على أي حال ، يمكننا تجنب الإعلان عن صناديق المرحلة 1 تمامًا - ستكون جميع التبعيات المستهدفة من Cargo.toml في النطاق تلقائيًا في جذر صندوق proc-macro في المرحلة 1.

في الكود الخاص بي ، وجدت أنني أستخدم الامتدادات لغرضين: للتحكم في دقة الاسم ، والتحكم في رسائل الخطأ. هل هذان مرتبطان بشكل لا ينفصل ، أم أنه من الممكن إنشاء امتداد يمزج بين جانب دقة الاسم لامتداد واحد مع مواقع رسالة خطأ الخط / العمود في نطاق مختلف؟ أتوقع أن تكون هذه حاجة مشتركة.

لكي أكون أكثر تحديدًا ، لدي سمة تم وضعها في النطاق داخل موقع def_site لمشتقتي المخصص وأريد استدعاء طرق السمات في حقول بنية المستخدم. إذا كان نوع الحقل لا ينفذ السمة الصحيحة ، فأنا أريد أن تحدد رسالة الخطأ حقل البنية المقابل.

يمكنني إنشاء استدعاء الأسلوب بامتداد def_site يقوم بالتجميع والتشغيل ولكن رسائل الخطأ للأسف تشير دائمًا إلى سمة الاشتقاق كما رأينا مع وحدات الماكرو 1.1.

  |
4 | #[derive(HeapSize)]
  |          ^^^^^^^^

أو يمكنني إنشاء استدعاء الطريقة بنفس امتداد معرف حقل البنية أو نوعه ، والذي يظهر التسطير الصحيح ولكنه يفشل في حل السمة في النطاق في موقع def_site الخاص بي.

  |
7 |     bad: std::thread::Thread,
  |     ^^^^^^^^^^^^^^^^^^^^^^^^

كيف يمكنني حل الأخطاء بشكل صحيح وإظهار الأخطاء بالطريقة التي أريدها؟

@ dtolnay هذه نقطة ممتازة ، شكرًا.

أعتقد أن الطريقة الصحيحة لإصلاح https://github.com/rust-lang/rust/issues/46489 قد تكون جعلها بحيث تكون الرموز المميزة #[derive(…)] التي تم إنشاؤها في نفس النطاق النطاق مثل تعريف النوع ، ويمتد رسائل الخطأ عند استدعاء الماكرو quote! {} الذي أنشأها.

ما قصة النظافة حاليا؟ لدي وظيفة مثل الماكرو الإجرائي الذي كان يعمل (منذ 4 أشهر) ولكن اعتبارًا من rustc 1.24.0-nightly (b65f0bedd 2018-01-01) يشكو من أن الحجة لا يمكن العثور عليها في النطاق.

عذرًا ، كان يجب أن يكون قد بحث في أداة تعقب المشكلات أولاً ، ويبدو أنني قمت للتو بالضغط على https://github.com/rust-lang/rust/issues/46489.

لقد قدمت رقم 47311 والذي أعتقد أنه يحظر حاليًا التنفيذ الصحيح للاشتقاق (إلغاء التسلسل). لا تستطيع وحدات الماكرو الإجرائية إنشاء بنية بها حقول خاصة.

قدم ملفًا آخر ، # 47312 حيث يكون للوصول إلى حقل بنية غير مسمى مثل self.0 متطلبات مختلفة على امتداد الرمز المميز . عن الوصول إلى حقل هيكلة مسمى مثل self.x .

تم إصلاح 47311 و # 47312 في # 48082 و # 48083 ، على التوالي.

لدي اثنين من العلاقات العامة أعلاه في انتظار المراجعة / التعليق.

يبدو أن https://github.com/rust-lang/rust/pull/41029 قد تم الآن؟

تم التخلي عن تلك العلاقات العامة ولكن تم إحياؤها واستمر العمل عليها في # 48465. تنتظر حاليا على كريتر.

تضمين التغريدة

بالنظر إلى syntax::ext::expand ، يبدو أن proc_macro_attribute s لا تتم معالجته حاليًا في سياقات متعددة (غير شاملة):

  • على الكتل ( fold_block() هو noop)
  • على العبارات / التعبيرات (# 41475 ، # 43988)
  • داخل كتل extern {} (# 48747)

لا يُدرج RFC 1566 أنواعًا معينة من عقد AST التي يمكن تطبيق وحدات ماكرو السمة عليها ، مما يشير إلى أنها يجب أن تكون قابلة للتطبيق على أي شيء تقريبًا. لكن هذا قد يكون سخيفًا بعض الشيء ، لذا يجب أن نحدد بوضوح ما الذي يجب معالجته ولكنه لا يحتاج إلى معالجة ، وأين يجب عدم السماح بالسمات مطلقًا ولكن قد تكون كذلك حاليًا (# 43988)

abonander القصد هو أنه يمكن استخدام سمات ماكرو proc في أي مكان يمكن أن تكون فيه سمة عادية وليس في أي مكان آخر ، وهو ما يجب أن أعتقد أنه يغطي كل ما سبق (على الرغم من أن بعضها غير مستقر ، وإذا قمنا بتثبيت وحدات ماكرو proc ، يجب أن نكون حريصين على فقط ثبّت الاستخدامات الثابتة للسمات الأخرى).

nrc موجود في أي مكان يعدد تلك المواقع لأن المرجع يقول فقط أنه يمكن تطبيق السمات على أي عنصر . ومع ذلك ، فأنا على يقين من أنه يمكن تطبيق سمات lint على الكتل والبيانات أيضًا.

nrc موجود في أي مكان يعدد تلك المواقع لأن المرجع يقول فقط أنه يمكن تطبيق السمات على أي عنصر. ومع ذلك ، فأنا على يقين من أنه يمكن تطبيق سمات lint على الكتل والبيانات أيضًا.

لا يوجد afaik - هناك RFC مقبول وعلامة ميزة غير مستقرة للسمات على أي تعبير ، لكنني أعتقد أننا استقرنا فقط على العبارات والكتل. المرجع هو خارج البيانات.

هذه المسألة:

فحص الاستقرار (proc-) وحدات ماكرو (الإصدار رقم 34079).

مغلق الآن WRT proc-macros. لم تضف العلاقات العامة الخاصة بي فقط التحقق من الاستقرار لوحدات ماكرو 2.0 ، وهذا هو السبب في أن المشكلة لا تزال مفتوحة (على الرغم من أنها ربما تكون مجرد مشكلة جديدة بدلاً من ذلك).

تضمينrfcbot fcp

أود أن أقترح تثبيت مجموعة فرعية من قصة وحدات الماكرو 2.0 مثل وحدات الماكرو 1.2 لإصدار Rust 1.28. يدخل Rust 1.28 ليلاً في 10 مايو 2018 (حوالي 2.5 أسبوعًا من كتابة هذه السطور) وسيصبح مستقرًا في 2 أغسطس 2018. أعتقد أن FCP قد ينتهي قبل قطع 10 مايو لـ 1.27 دخول بيتا ، لكني أرغب في الاستمرار إيقاف أي استقرار هنا إلى ما بعد حدوث هذا القطع وتأخير ذلك إلى الإصدار 1.28.

تمت مناقشة هذا الأمر في الأجزاء الداخلية مؤخرًا إلى جانب عدد من المشكلات المسجلة بواسطة petrochenkov والتي يجب إصلاحها الآن (ولكن لم يتم إصدارها بعد في الليل). أعتقد أنه سيكون من المفيد أن نلخص هنا ، لذا فهذه هي بالتحديد المجموعة الفرعية التي ستستقر.

تذكر أن هذه مجموعة فرعية . الوظيفة المفقودة هنا لا تعني أنه لن يتم تثبيتها أو إزالتها من المترجم. بدلاً من ذلك ، ستظل هذه الوظيفة غير مستقرة بعد مرور التثبيت المقترح هذا ليتم تثبيتها في تاريخ لاحق.

وحدات الماكرو ونظام الوحدة النمطية

مغطى بشكل أساسي بـ https://github.com/rust-lang/rust/issues/35896 والآن
بعد الانتهاء من FCP ، فإن الفكرة الرئيسية هي أنه يمكنك استخدام كشوف حسابات use لـ
استيراد وحدات الماكرو. على سبيل المثال رمز مثل هذا:

use some_proc_macro_crate::bar;

#[bar]
fn baz() {}

أو

use some_proc_macro_crate::bar;
bar!();

او حتى

pub use some_proc_macro_crate::bar; // reexport an attribute or macro

يقدم هذا مساحة اسم ثالثة في Rust (بالإضافة إلى القيمة / النوع
مساحات الاسم) ، مساحة اسم الماكرو. السمات ، والقواعد الكلية ، والإجرائية
جميع وحدات الماكرو موجودة في مساحة الاسم maro.

يتمثل الاختلاف عن نظام الوحدة النمطية الكامل في أنه عنصر واحد فقط سيسمح باستدعاء المساراتوحدات الماكرو .
على سبيل المثال ، لن يتم السماح بـ #[foo::bar] أو ::bar::baz!() . هذه
قد يتم رفع القيد يومًا ما ولكن هذا يعد طريقًا متحفظًا جيدًا لـ
أبدا ب.

أين يمكن أن يحدث التوسع؟

لا يمكن تطبيق السمات

تتضمن "العناصر" هنا أشياء مثل عناصر السمات والعناصر الضمنية والوحدة النمطية الأجنبية
العناصر. لن يكون توسيع الوحدة مستقرًا بعد بسبب hygeine و
تداعيات التنفيذ. يُترك لتحديد هذا وتثبيته عند أ
تاريخ لاحق.

لن تكون وحدات ماكرو البيانات وسمة التعبير مستقرة بعد. هذا هو
في المقام الأول بسبب الضرورة الحقيقية للنظافة على مستوى التعبير (مثل
على مستوى العنصر). يتم ترك هذا للاستقرار في وقت لاحق.

أخيرًا ، يجب أن تحتوي وحدات ماكرو السمات

على سبيل المثال ، #[foo] ، #[foo(bar)] ، و #[foo { bar baz ... @ | ^ hello }]
هي دعوات صحيحة. دعوات مثل #[foo = "baz"] أو #[foo bar] أو
لن يكون #[foo ... = ( baz )] مستقرًا في البداية.

كيف تبدو وحدات الماكرو الإجرائية؟

مثل الاشتقاق المخصص ، يتم تعريفهم في صناديق من نوع الصناديق proc-macro .
يتم تعريف وحدات الماكرو والسمات الإجرائية على النحو التالي:

extern crate proc_macro;
use proc_macro::TokenStream;

/// Invoked as `foo!()`
///
/// When invoked as `foo!(a b ( c ))` then the `TokenStream`
/// here will be `a b ( c )`.
///
/// The invocation is replaced with the `TokenStream` returned
#[proc_macro]
pub fn foo(a: TokenStream) -> TokenStream {
    // ...
}

/// Invoked as `#[bar]`
///
/// The first argument, `attr`, is the token stream inside of the attribute
/// itself. The second argument, `item`, is the token stream corresponding to
/// the item the attribute is attached to.
///
/// An attribute of the form `#[bar ( a b [ c ] )]` will have the `attr`
/// argument look like `a b [ c ]`. Note the lack of delimiters passed to
/// `attr`! An API may later be added to learn what delimiter a macro was
/// invoked with.
///
/// The `item` here is a tokenified version of the original item.
///
/// The return value here will contain all non-expanded attributes as well for
/// this attribute to inspect. The return value replaces the original item.
#[proc_macro]
pub fn bar(attr: TokenStream, item: TokenStream) -> TokenStream {
    // ...
}

ماذا عن النظافة؟

أعلاه ، لوحظ أنه لا يمكن توسيع وحدات الماكرو والسمات المخصصة إلا في
سياقات العنصر ، ولا سيما إنشاء عقد AST الجديدة التي هي عناصر. هذه
يعني أنه علينا فقط القلق بشأن نظافة إنشاء عنصر AST جديد
العقد.

ستتمتع العناصر الجديدة بنفس النظافة مثل macro_rules! اليوم. سيفعلون
لا تكون صحية. العناصر الجديدة المضافة إلى AST ستدخل نفس مساحة الاسم مثل
عناصر أخرى في الوحدة.

واجهة برمجة تطبيقات proc_macro .

من أجل تمكين كل هذا ، سيتم تثبيت مساحة السطح التالية
الصندوق proc_macro :

pub struct TokenStream(_);

impl TokenStream {
    pub fn empty() -> TokenStream;
    pub fn is_empty(&self) -> bool;
}

impl Clone for TokenStream { ... }
impl Debug for TokenStream { ... }
impl Display for TokenStream { ... }
impl FromStr for TokenStream { ... }
impl From<TokenTree> for TokenStream { ... }
impl FromIterator<TokenTree> for TokenStream { ... }
impl FromIterator<TokenStream> for TokenStream { ... }
impl !Send for TokenStream { ... }
impl !Sync for TokenStream { ... }

impl IntoIterator for TokenStream {
    type Item = TokenTree;
    type Iter = token_stream::IntoIter;
}

pub mod token_stream {
    pub struct IntoIter(_);

    impl Iterator for IntoIter {
        type Item = ::TokenTree;
    }
}

pub enum TokenTree {
    Op(Op),
    Term(Term),
    Literal(Literal),
    Group(Group),
}

impl TokenTree {
    pub fn span(&self) -> Span;
    pub fn set_span(&mut self, span: Span);
}

impl Clone for TokenTree { ... }
impl Debug for TokenTree { ... }
impl Display for TokenTree { ... }
impl From<Op> for TokenTree { ... }
impl From<Term> for TokenTree { ... }
impl From<Literal> for TokenTree { ... }
impl From<Group> for TokenTree { ... }
impl !Send for TokenTree { ... }
impl !Sync for TokenTree { ... }

pub struct Span(_);

impl Span {
    pub fn call_site() -> Span;
}

impl Clone for Span { ... }
impl Copy for Span { ... }
impl Debug for Span { ... }
impl !Send for Span { ... }
impl !Sync for Span { ... }

pub struct Group(_);

pub enum Delimiter {
    Parenthesis,
    Brace,
    Bracket,
    None,
}

impl Group {
    pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group;
    pub fn stream(&self) -> TokenStream;
    pub fn delimiter(&self) -> Delimiter;
    pub fn span(&self) -> Span;
    pub fn set_span(&mut self, span: Span);
}

impl Clone for Group { ... }
impl Debug for Group { ... }
impl Display for Group { ... }
impl !Send for Group { ... }
impl !Sync for Group { ... }

impl Copy for Delimiter { ... }
impl Clone for Delimiter { ... }
impl Debug for Delimiter { ... }
impl PartialEq for Delimiter { ... }
impl Eq for Delimeter { ... }

pub struct Term(_);

impl Term {
    pub fn new(s: &str, span: Span) -> Term;
    pub fn span(&self) -> Span;
    pub fn set_span(&mut self, span: Span);
}

impl Copy for Term { ... }
impl Clone for Term { ... }
impl Debug for Term { ... }
impl Display for Term { ... }
impl !Send for Term { ... }
impl !Sync for Term { ... }

pub struct Op(_);

pub enum Spacing {
   Alone,
   Joint,
}

impl Op {
    pub fn new(op: char, spacing: Spacing) -> Op;
    pub fn op(&self) -> char;
    pub fn spacing(&self) -> Spacing;
    pub fn span(&self) -> Span;
    pub fn set_span(&mut self, span: Span);
}

impl Debug for Op { ... }
impl Display for Op { ... }
impl Clone for Op { ... }
impl Copy for Op { ... }
impl !Send for Op { ... }
impl !Sync for Op { ... }

impl Copy for Spacing { ... }
impl Clone for Spacing { ... }
impl Debug for Spacing { ... }
impl PartialEq for Spacing { ... }
impl Eq for Spacing { ... }

pub struct Literal(_);

impl Literal {
  // panic on infinity and NaN
  pub fn f{32,64}_{un,}suffixed(f: f{32,64}) -> Literal;

  pub fn i{8,16,32,64,128,size}_{un,}suffixed(n: i{8,16,32,64,128,size}) -> Literal;
  pub fn u{8,16,32,64,128,size}_{un,}suffixed(n: u{8,16,32,64,128,size}) -> Literal;

  pub fn string(s: &str) -> Literal;
  pub fn character(c: char) -> Literal;
  pub fn byte_string(b: &[u8]) -> Literal;

  pub fn span(&self) -> Span;
  pub fn set_span(&mut self, span: Span) -> Span;
}

impl Clone for Literal { ... }
impl Debug for Literal { ... }
impl Display for Literal { ... }
impl !Send for Literal { ... }
impl !Sync for Literal { ... }

يمكن العثور على مزيد من المعلومات حول واجهة برمجة التطبيقات هذه الأصل العلاقات العامة

استراتيجية الاختبار

تم اختبار أنظمة الماكرو 1.1 ووحدات الماكرو 2.0 بشكل مكثف طوال الوقت
النظام البيئي لبعض الوقت الآن. ولا سيما هذا الاقتراح بأكمله
تم اختباره على نطاق واسع من خلال الإصدار 0.3 من الصندوق proc-macro2 as
وكذلك الصندوق syn . خلال الاختبار كان عدد من الأخطاء
محددة وثابتة والنظام الحالي يشعر بالصلابة الكافية للبدء في ذلك
استقر. (كي لا نقول أنها خالية من الأخطاء!)

اقترح عضو الفريق alexcrichton دمج هذا. الخطوة التالية هي المراجعة بواسطة بقية الفرق الموسومة:

  • [x] Kimundi
  • []SimonSapin
  • [x]alexcrichton
  • [x]aturon
  • [x]cramertj
  • [x] dtolnay
  • [x]eddyb
  • [x] @ joshtriplett
  • [x]nikomatsakis
  • [x]nrc
  • []pnkfelix
  • [x] @ scottmcm
  • [x]sfackler
  • [x] @ بدون قوارب

لا مخاوف مدرجة حاليا.

بمجرد موافقة غالبية المراجعين (وعدم اعتراضهم على ذلك) ، سيدخل هذا فترة التعليق النهائية. إذا اكتشفت مشكلة كبيرة لم تُثار في أي وقت في هذه العملية ، فيرجى التحدث!

راجع هذا المستند للحصول على معلومات حول الأوامر التي يمكن أن يقدمها لي أعضاء الفريق.

cc @ rust-lang / compiler ، أعلم أنكم مهتمون جدًا بهذا الأمر ولا تتردد في طرح أي اعتراضات. إذا كان لديك اعتراض حظر يمكنني أيضًا تسجيله لك

يبدو أنه باستخدام واجهة برمجة التطبيقات (API) المُقترحة لتحقيق الاستقرار ، يمكن لوحدات الماكرو proc بسهولة إنشاء جميع أنواع الرموز المميزة ، أو نسخها من الإدخال إلى الإخراج ، ولكن لا يمكنها بسهولة فحص تدفق الرموز حتى على المستوى السطحي. على سبيل المثال ، Literal لا يطبق Eq أو PartialEq . أي سبب معين لذلك؟ (وحتى هذا سيسمح فقط بالمقارنة مع القيم الثابتة المحددة ، بدلاً من استخراج قيمة ومعالجتها في التعليمات البرمجية.)

داخل تنفيذ ماكرو proc ، بالنظر إلى TokenStream ، ما الذي يمكن أن يفعله ماكرو proc لاستبطان قيمة حرفية؟ أو ، في هذا الصدد ، استخراج قيمة واحد؟ هل هذا ببساطة غير معتمد حتى الآن؟ هل هناك خطة لدعمها في المستقبل؟

(أنا لا أحاول منع استقرار المجموعة الفرعية المقترحة ؛ أود فقط أن أفهم هذه المجموعة الفرعية وميزاتها المقصودة بشكل أفضل.)

العناصر الجديدة في alexcrichton ستتمتع بنفس مستوى النظافة مثل قواعد الماكرو! يفعل اليوم. سيفعلون
لا تكون صحية. العناصر الجديدة المضافة إلى AST ستدخل نفس مساحة الاسم مثل
عناصر أخرى في الوحدة.

أنا لست عضوًا في فريق Rust الأساسي ، ولم ألقي نظرة شاملة على كل المناقشات السابقة ، لكن هذا يبدو سيئًا حقًا بالنسبة لي. ماذا لو أراد الماكرو إنشاء عناصر مساعدة لا يمكن الوصول إليها إلا عن طريق الماكرو؟

بدلاً من التخلص من النظافة ، أعتقد أنه من الأفضل فرض نظافة كاملة بنسبة 100٪ ، ولكن توفير وسيلة لوحدات الماكرو لتختار صراحةً عدم الالتزام بالنظافة لمتغير معين.

joshtriplett ستستخدم العرض الضمني لـ Literal.

joshtriplett نعم كما ذكر dtolnay أنك ستستخدم Display وهو ما تم بناء صندوق مثل النص الحرفي عليه. بشكل عام ، يُقصد من API أن تكون "الحد الأدنى" ، وليس واجهة برمجة تطبيقات من الدرجة الأولى تحتوي على جميع الأجراس والصفارات. من المحتمل أن يأتي هؤلاء لاحقًا!

تهدف جولة التثبيت هذه إلى أن تكون "الحد الأدنى إلى أقصى حد" بمعنى أنها توفر أقل قدر من الوظائف لتغطية جميع حالات الاستخدام (يُعرف أيضًا باسم Display مقابل Literal ولا يوجد شيء آخر يفسرها ).

Pauan ليس رائعًا ، نعم ، لكنه مماثل تمامًا لـ macro_rules! الذي ظل مستقرًا لسنوات حتى الآن ويعمل في العديد من السياقات المختلفة. نريد تمكين النظافة والعلاج الأفضل هنا ولكننا لسنا مستعدين تمامًا بعد. المُنشئ Span::call_site() هو العمود الفقري هنا حيث باستخدام ذلك فإنك تطلب "عدم وجود نظافة". في النهاية سنعمل على استقرار المزيد من الخيارات.

لسوء الحظ ، لم يتبق سوى سنوات على "النظافة الكاملة بنسبة 100٪" ، والغرض من هذا الاقتراح هو الحصول على شيء مستقر لـ Rust 2018

alexcrichton إذن هل خطة تحقيق الاستقرار الآن مع وجود ثقب في النظافة ، ثم بعد ذلك ، تعمل عهدين / عصور / طبعات لاحقًا على إصلاح هذا الثقب في النظافة؟

نظرًا لوجود Span::call_site() ، فهل هناك سبب يمنعه من التمتع بالنظافة الكاملة في الوقت الحالي؟ هل هو نقص في القوى العاملة / الوقت ، أم أن هناك مخاوف نظرية / دلالية لا تزال بحاجة إلى توضيح في طلب تقديمي؟

Pauan للتأكيد على أنه لا يوجد "ثقب" حقيقي بمعنى أنه موجود بالفعل اليوم. هذه هي نفس قصة النظافة تمامًا مع اشتقاق مخصص macro_rules! . هذا الاقتراح هو امتداد لذلك ، وليس تقديم أي شيء جديد.

بالنظر إلى "قصة النظافة المثالية" ، سنحتاج دائمًا إلى شكل من أشكال الانسحاب. في الوقت الحالي ، يكون إلغاء الاشتراك هو Span::call_site() (فعليًا). من خلال تحقيق الاستقرار فقط في أننا نقوم فقط بتثبيت آلية إلغاء الاشتراك الخاصة بالنظافة. في النهاية سنقوم بتثبيت المزيد من الوظائف لجعل العناصر صحية تمامًا عند الضرورة.

استقرار النظافة هو أبعد من ذلك بكثير. هناك (AFAIK) أسئلة بحثية لم يتم حلها ، إنها ليست مسألة قوة بشرية.

@ dtolnay آه ، فهمت. لذا ، يمكنك إنشاء نص ثم إعادة تحليل النص؟ أفترض أن هذا يعمل في الوقت الحاضر.

cc @ rust-lang / compiler ، أعلم أنكم مهتمون جدًا بهذا الأمر ولا تتردد في طرح أي اعتراضات. إذا كان لديك اعتراض حظر يمكنني أيضًا تسجيله لك

لا يزال لدي بعض الأشياء لمراجعتها والعلاقات العامة مع بعض التعديلات على واجهة برمجة التطبيقات proc-macro قيد التقدم.

هذه هي نفس قصة النظافة بالضبط مع قواعد الماكرو! وتشتق العرف.

بالتأكيد ، لكنني اعتقدت أن أحد الأهداف كان إنشاء نظام ماكرو أفضل ، لذا فإن الإشارة إلى النظام الحالي (المعطل والمحدود) لا يبدو مقنعًا للغاية بالنسبة لي.

بالنظر إلى "قصة النظافة المثالية" ، سنحتاج دائمًا إلى شكل من أشكال الانسحاب.

بالتأكيد ، لكن وجهة نظري هي أنه نظرًا لأنه من الممكن استخدام Span::call_site() لكسر النظافة (وبالتالي الحصول على وظيفة macro_rules! ) إذا رغبت في ذلك ، من خلال جعلها صحية بشكل افتراضي ، يمكنك الوصول إلى كل من النظافة و غير النظافة. في حين أنه إذا استقر مع عدم النظافة ، فإنه يكون عالقًا مع عدم النظافة فقط .

في النهاية سنقوم بتثبيت المزيد من الوظائف لجعل العناصر صحية تمامًا عند الضرورة.

يبدو هذا وكأنه أداة مساعدة ضيقة مزعجة إلى حد ما (ومربكة): ستكون وحدات الماكرو proc صحية في معظم المواقف (لكن ليس العناصر) ، ولكن يمكنك بعد ذلك استخدام ميزة جديدة للاشتراك في النظافة للعناصر. هل أفهم هذا صحيح؟

هناك (AFAIK) أسئلة بحثية لم يتم حلها ، إنها ليست مسألة قوة بشرية.

حسنًا ، هذا عادل بما يكفي. أفهم الرغبة في النفعية والبراغماتية. طالما أن الخطة تتمثل في النهاية في الحصول على نظافة قوية بشكل افتراضي في حقبة / حقبة / إصدار لاحق ، فأنا على ما يرام مع عادات النظافة السيئة مؤقتًا. أنا فقط لا أريد أن نحقق الاستقرار في شيء سنندم عليه لاحقًا.

بمعنى، أنه بالفعل هو "صحية افتراضيا،" انها مجرد أن الافتراضي غير معتمدة حتى الان. Span::call_site هو إلغاء الاشتراك. :)

Pauan لتوضيح ما قال alexcrichton :

يتطلب إنشاء معرف Span ، والذي يحتوي على معلومات النظافة. (انظر Term::new )

في المستقبل ، قد نكشف العديد من الطرق المختلفة لبناء Span s ، والتي تعكس خيارات مختلفة للنظافة. لكن في الوقت الحالي ، سنكشف فقط عن Span::call_site الذي يأخذ نطاق المتصل.

بهذه الطريقة ، يمكننا تجنب تثبيت نظام النظافة بالكامل على الفور ، مع الحفاظ على القدرة على إضافة النظافة في وقت لاحق. أعتقد أنها خدعة ذكية جدًا للتغلب على هذه المشكلة!

rpjohnst إذن أنت تقصد أن الطريقة الوحيدة لإرجاع عناصر جديدة من ماكرو proc هي استخدام Span::call_site ؟

إذا كان الأمر كذلك ، فهذا يبدو مثاليًا: في هذه الحالة يمكن بالفعل إضافة النظافة في المستقبل بطريقة نظيفة ومتوافقة مع الإصدارات السابقة.

lfairy Ahhh ، أرى ، لم أدرك أنه من الضروري استخدام Span::call_site ، اعتقدت أن هناك نطاقًا افتراضيًا غير صحي. شكرا لك على التفسير! أنت محق في هذه خدعة ذكية للغاية.

على هذا النحو ، ليس لدي المزيد من الاعتراضات.

تضمين التغريدة

السمات ، والقواعد الكلية ، والإجرائية
جميع وحدات الماكرو موجودة في مساحة الاسم maro.

آخر مرة راجعت فيها باستخدام #[feature(proc_macro)] ، كان بها تغيير غير متوافق مع الإصدارات السابقة في رمز ثابت لصندوق سلسلة أخطاء الاشتقاق كما هو موضح هنا. من البيان المقتبس ، يبدو أنه سيستمر على هذا النحو في وحدات الماكرو 1.2. هل هذا صحيح؟

Arnavion يا عزيزي ، هذا يبدو سيئا! لا يمكننا حقًا إجراء أي تغييرات كبيرة غير متوافقة مع الإصدارات السابقة ، لذلك يتعين علينا اكتشاف طريقة لجعل ذلك يعمل باستمرار. قد يكون أحد الحلول الممكنة هو تأجيل أخطاء "هذه ليست سمة" حتى بعد توسيع #[derive] .

يبدو أن # 48644 و # 47786 قد اكتملت. هل يمكن لشخص تحديث OP؟

alexcrichton هل Literal والأصدقاء؟ لقد فهمت أنها لم تعد تعدادًا لأسباب تتعلق بالتوافق العكسي ، ولكن هل هناك أي سبب لعدم وجود شيء مثل هذا مقابل Literal للبدء به:

    impl Literal {
        pub fn as_str(&self) -> Option<&str> {}
        pub fn to_int(&self) -> Option<i64> {}
        pub fn to_uint(&self) -> Option<u64> {}
        pub fn to_float(&self) -> Option<f64> {}
    }

يمكننا حتى الحصول على مجموعة من الضمانات TryFrom للأنواع الفرعية الحرفية المختلفة.

abonander لقد تمت مناقشته نعم ولكن النتيجة كانت إضافتهم لاحقًا بدلاً من جعلهم ضروريين للمرور الأول من التثبيت. يمكن بناؤها على crates.io من خلال تنفيذ Display ولدينا متسع لإضافة الآخر لاحقًا في المستقبل

: bell: هذا يدخل الآن فترة التعليق النهائية ، وفقًا للمراجعة أعلاه . :جرس:

تضمين التغريدة
لا تتم كتابة الضمانات !Send و !Sync لأنواع واجهة برمجة تطبيقات ماكرو بشكل صريح ، ولكن يتم استنتاجها.
بالنسبة لبعض الهياكل (على سبيل المثال Op ) يختلف الضمنت المستنتج عما هو محدد في https://github.com/rust-lang/rust/issues/38356#issuecomment -383693017.
ربما يكون من المنطقي إضافة الضمانات بشكل صريح.

عذرًا ، نعم بالفعل! لقد فتحت https://github.com/rust-lang/rust/pull/50453 لمعالجة ذلك

alexcrichton لدينا مشكلة سيئة مع Term::as_str : كنت أحاول رسم دليل غير رسمي على أنه بسبب النطاق الصارم ، يمكن تطبيق &'a Term -> &'a str للاقتراض من بعض المتدربين ، و 'a لا يمكن أبدًا أن يكون أكبر من نطاق المتدرب نفسه (وهو أمر مهم فقط إذا نجحت الوظيفة ، أي إذا تم استدعاؤها ضمن هذا النطاق الذي يعيش فيه المتدرب).

AFAICT ، Term::as_str سليم ، لكن فقط بافتراض حالة 'a .

وهو ما يدعمه على سبيل المثال thread_local! ، لأنه في حين أنه يتيح لك الهروب من قيمة Term ، فإنه يمنحك 'a s لفترة قصيرة جدًا ، والتي إذا كانت Term::as_str تنجح
بشكل عام ، الطريقة التي يحدث بها التوسع proc_macro ، ولأن Term هو موضوع محلي ، هناك طرق قليلة جدًا للهروب Term ، وافترضت thread_local! كان فعال الوحيد.

لكن Box::leak موجود أيضًا! لا يزال الوضع غير مستقر ، ولكن اليوم ، يعود &'static str Box::leak(Box::new(term)).as_str() &'static str . أتساءل عما إذا كان هناك تجريدات أخرى كسرها Box::leak (ccRalfJung)

OTOH ، هذا معقد فقط لأن Term لا يمكنه امتلاك بيانات السلسلة ، حيث إنها Copy .
إذا أزلنا Copy على Term ، فيمكننا إبقاء Option<Cell<Rc<String>> كسولًا هناك.

من المقرر إزالة Term::as_str ولم يتم تضمينه في التثبيت هنا ، فلا داعي للقلق! إنه يظل ثابتًا فقط لذا لا نكسر proc-macro2 ، ولكن بمجرد استقرار هذا يمكننا إصدار تغيير فاصل proc-macro2

eddyb لا أعرف السياق هنا ، لكن Box::leak له ما يبرره في نموذجي الرسمي. إذا كنت تمتلك بعض الذاكرة إلى الأبد (على سبيل المثال ، في صندوق) ، فيمكنك القول تمامًا أن لها أي عمر.

لدي بضعة أسئلة:

  1. هل quote! غير مستقر؟
  2. و quote! لديها proc_macro_non_items بوابة ميزة المطبق عليه؟ يتطلب الأمر تنفيذ 79630d4fdfc775b241cae0a209edec2687a29f0f الآن ، ولكن لا يزال يتم تمييز #[unstable(feature = "proc_macro" ... quote! #[unstable(feature = "proc_macro" ... .
  3. هل سيتم تقديم مشكلات التتبع لاستقرار proc_macro_path_invoc و proc_macro_mod و proc_macro_expr و proc_macro_non_items ؟

سؤال جانبي غير ذي صلة: أين يتم تنفيذ quote! ؟

mjbshaw Sooo قصة ممتعة: يتم تنفيذها في proc_macro::quote .
يتظاهر rustc_metadata بأن أي صندوق باسم proc_macro يحتوي على ماكرو إجرائي اسمه quote فيه ، لكن التطبيق المستخدم هو من proc_macro rustc_metadata الروابط ضد.

لا يزال لدي بعض الأشياء لمراجعتها والعلاقات العامة مع بعض التعديلات على واجهة برمجة التطبيقات proc-macro قيد التقدم.

مراجعة العلاقات العامة: https://github.com/rust-lang/rust/pull/50473

طلب ميزة لـ 1.2 API: إضافة محدد لأقواس الزاوية ( < / > ) لذا أشياء مثل <T> (في fn foo<T>() {} ) سيتم تحليلها أ Group . عدم القيام بذلك يجعل تحليل الأدوية الجنيسة ، على سبيل المثال ، معقدًا بلا داعٍ.

mjbshaw لا أعتقد أنه سيعمل على مستوى الرمز المميز لمحاولة تحديد ما إذا كان قد تم تجميع اثنين < > مع بعضهما البعض. على سبيل المثال في إدخال الماكرو التالي:

m!($A<$B, $C>=$D);

ربما يكون هذا عبارة عن تعبيرين منطقيين $A < $B و $C >= $D ، أو ربما يمثلان أنواعًا عامة في اسم مستعار من النوع على سبيل المثال التوسع إلى type $A <$B,$C> = $D; .

assert_both!(a<AMAX, b>=BMIN);

define_type_alias!(SwappedResult<E, T>=std::result::Result<T, E>);

لقد قمت بتحديث OP قليلاً ولكن لدينا ما يبدو لي مثل اثنين من الأخطاء المحتملة في showstopper المتعلقة بالنظافة ، اعتمادًا على كيفية ظهورها:

بالنسبة لأولئك الذين يتابعون هذا الموضوع ، من المحتمل تغيير واجهة برمجة التطبيقات من تعليق FCP الأصلي في https://github.com/rust-lang/rust/pull/50473 الذي اقترحهpetrochenkov. الملخص حتى الآن هو:

  • أعد تسمية Term::new إلى Term::ident وتحقق من صحة الإدخال
  • أضف Term::lifetime وتحقق من صحة الإدخال
  • أضف Term::raw_ident وتحقق من صحة الإدخال
  • أعد تسمية Op إلى Punct
  • تحقق من صحة الإدخال في Punct::new
  • إعادة تسمية Op::op إلى Punct::as_char

أحد طلبات واجهة برمجة التطبيقات الصغيرة التي أود تقديمها (ربما في # 50473 -petrochenkov) هو طريقة ما لإلحاق الرموز المميزة في TokenStream. ربما:

impl Extend<TokenTree> for TokenStream

أعتقد أن هذا سيجعل من الممكن التخلص من النوع quote::Tokens (وهو أساسًا Vec<TokenTree> ) وتقليل انتشار الأنواع المختلفة في النظام البيئي التي تعني جميعها "بعض الرموز المميزة" - يتم تتبعها في https : //github.com/dtolnay/syn/issues/205.

+1 على اقتراح @ dtolnay أعلاه.

اكتملت الآن فترة التعليق النهائية ، مع الاستعداد للدمج ، وفقًا للمراجعة أعلاه .

لدي سؤالان:

  1. كما تم طرحه هنا ، ماذا عن quote! ؟ ما الذي يجب أن تكون الطريقة الافتراضية لإنشاء TokenStream الأخير؟ هل يجب أن يتم ذلك يدويًا؟ أم يجب على المرء استخدام الصندوق quote ؟ هل من المفترض أن يستقر proc_macro::quote! في مرحلة ما في المستقبل؟

  2. هل فهمي صحيح في أن الاختلاف بين إعلان ماكرو يشبه الوظيفة وماكرو يشبه السمة هو مجرد عدد من الوسائط؟ بمعنى آخر:

    /// Invoked as `foo!()`
    #[proc_macro]
    pub fn foo(a: TokenStream) -> TokenStream {
        // ...
    }
    
    /// Invoked as `#[bar]`
    #[proc_macro]
    pub fn bar(attr: TokenStream, item: TokenStream) -> TokenStream {
        // ...
    }
    

    الفرق الوحيد هو أن واحد يأخذ واحدة TokenStream كوسيطة، حيث والآخر يأخذ اثنين. أليس هذا خفيًا بعض الشيء؟ لماذا لا تستخدم #[proc_macro_attribute] و #[proc_macro_function_like] بدلاً من ذلك؟ هل نوقش هذا في مكان ما؟ إذا كان الأمر كذلك ، فسأكون سعيدًا إذا تمكن أحد من ربط المناقشة.

شكرا لعملك في هذا! :)

LukasKalbertodt يتم الإعلان عن سمات #[proc_macro_attribute] . لا أعرف ما إذا كانت هناك نية متعمدة لتغيير ذلك أو إذا كان خطأ مطبعي في اقتراح FCP.

المشكلة: الرموز التي تم تحليلها من السلاسل لا تحصل على Span::call_site امتدادات: https://github.com/rust-lang/rust/issues/50050#issuecomment -390520317.

أعتقد أننا بحاجة إلى تغيير هذا وكذلك تغيير ما يعود Span::call_site لإصلاح آثار خلفية الماكرو ، ونظافة كليبي وإصدار الرموز المميزة باستخدام امتدادات مواقع الاتصال.

LukasKalbertodt لم يتم تثبيت الماكرو quote! في الصندوق proc_macro كجزء من FCP هذا ، لكن الصندوق quote على الصناديق.io يبني على واجهة برمجة التطبيقات المقترحة هنا. كما أشار abonander إلى أنه تم الإعلان عن وحدات ماكرو السمات بـ #[proc_macro_attribute] و #[proc_macro] محجوز حصريًا لـ foo!() -style وحدات الماكرو

ألا يجب تسمية #[proc_macro_attribute] #[proc_attribute_macro] أو #[attribute_proc_macro] ؟

Zoxc لدينا بالفعل #[proc_macro_derive] مستقر ، لذلك سيكون من الغريب عدم اتباع ذلك لوحدات ماكرو السمات.

هل يمكننا الحصول على PartialEq<char> و PartialEq<Punct> مقابل Punct (على غرار تطبيقات Ident PartialEq )؟ يبدو أنه يجب أن يكون آمنًا جدًا للإضافة. أنا سعيد بكتابة العلاقات العامة ، لكن لا أريد أن أفعل إذا كانت الفكرة محظورة.

mjbshaw ليت PartialEq<Punct> يمتد مقارنة أيضا؟ PartialEq<char> جيد ، OTOH.

eddyb PartialEq مقابل Ident لا يقارن الامتدادات (أعرف أن هذا مصدر proc-macro2 وليس مصدر proc-macro). أنا متناقض بشأن ما إذا كانت الفترات مدرجة في المقارنة ، لكنني أتوقع أن يتصرف Punct و Ident بالمثل في هذا الصدد. Punct أيضًا على Spacing ، والذي أفترض أنه سيتم تضمينه في المقارنة (على الرغم من أن الآخرين ربما يفكرون بشكل مختلف).

سأكون بخير فقط إذا قمت بتطبيق PartialEq<char> مقابل Punct في الوقت الحالي. يمكن تجزئة PartialEq<Punct> لاحقًا.

mjbshaw يتمتع صندوق proc-macro2 بحرية ألا يكون بالضبط ما هو عليه proc_macro ويمنحنا بعض الحرية لتجربة تعديلات مختلفة. أظن أنه إذا نجح الأمر بشكل جيد على الصناديق ، فيمكننا إضافته إلى proc_macro ، لكنه بالطبع متوافق مع الإصدارات السابقة للإضافة إلى proc_macro لذلك نبدأ بالحد الأدنى و يمكننا التوسع من هناك بمجرد استقرارها.

لقد قمت ببعض أعمال الفرز لجميع الأخطاء المتعلقة بوحدات الماكرو 1.2 . يمكن تصنيف معظم الأخطاء إلى "أخطاء خطيرة" أو "جميع الأخطاء المتعلقة بالامتداد". تؤثر الأخطاء المرتبطة بالامتداد حاليًا بشكل بحت على رسائل الخطأ (حيث أن القصد من وحدات الماكرو 1.2 ليس تغيير الدقة). الخطأ المتبقي غير المتعلق بالامتداد (المعروف أيضًا باسم الخطير) هو https://github.com/rust-lang/rust/issues/50050 ، والذي يمتلك petrochenkov حلًا له .

اندلعت فئة Gnome مع التغييرات التي تم إجراؤها على proc_macro2 / syn / quote ، بالإضافة إلى بوابة الميزات لتوليد الوحدات النمطية من وحدات الماكرو proc. تم إصلاحه الآن ، لحسن الحظ.

ما الأشياء التي يجب أن أراقبها لأظل على رأس التغييرات في هذا النظام البيئي الصغير؟

federicomenaquintero إذا كنت تستخدم ميزات غير مستقرة ، ففكر في الحصول على وظيفة CI منتظمة (يوميًا ، أسبوعيًا ، أيًا كان ما يناسبك) التي تجمع التعليمات البرمجية الخاصة بك مع أحدث إصدار Nightly وإعلامك إذا فشلت. (يدعم Travis-CI تمكين مثل هذه "وظيفة cron" في إعداداتها.)

SimonSapin شكرا ، هذه فكرة جيدة. نقوم بتثبيت إصدارات من هذه الصناديق في Cargo.toml الخاص بنا ، ولكن قد يكون الوقت قد حان لإزالة أرقام الإصدارات والسماح لشركة Cargo بتنزيل الأحدث. هل هذه هي الطريقة الصحيحة للقيام بذلك؟

federicomenaquintero هذا خارج عن الموضوع بشكل متزايد ، لذا إذا كنت ترغب في متابعة هذه المناقشة ، فيرجى القيام بذلك في مكان آخر مثل IRC أو http://users.rust-lang.org/ ، ولكن التوصية العامة هي أن التطبيقات (مثل على عكس المكتبات) يجب أن تشحن Cargo.lock مع كود المصدر الخاص بهم ، والذي يقوم بفاعلية بتثبيت التبعيات. في Cargo.toml ، يوصى بالإعلان عن تبعية مثل foo = "1.2.3" ، فهذا يعني ضمنيًا "هذا الإصدار أو أحدث ، إذا كان متوافقًا وفقًا لـ SemVer".

لذلك ، واجهت للتو مشكلة مع وحدات الماكرو الإجرائية التي تمنعني من تطوير صندوق أريد صنعه.

ضع في اعتبارك ما يلي:

#[my_attribute]
struct MyStruct {
  #[other_attribute]
  field: String,
}

هذا لا يعمل حاليًا لأن كلاً من الميزتين proc_macro و custom_attributes مطلوبان ولكن لا يمكن استخدامهما في نفس الوقت. كما أفهم ، سيؤدي تثبيت وحدات ماكرو proc إلى إلغاء الحاجة إلى علامات الميزات؟

الشيء الآخر هو أنه بهذه الطريقة يمكن أن يُنشئ #[my_attribute] رمزًا يمنع تشغيل #[other_attribute] الإطلاق. ما سيكون رائعًا حقًا إذا كان بإمكاني تسجيل السمات الداخلية التي تعمل بنفس الطريقة التي يعمل بها #[derive(Foo)] السمة "الخارجية".

ماذا عن تعليق SimonSapin حول الجلسة الوهمية ؟

هل من الممكن / المرغوب استبدال هذا الذعر بخلق "جلسة" وهمية ضمنيًا؟ أو ربما تضيف واجهة برمجة تطبيقات عامة (مع مسار لتحقيق الاستقرار) لإنشاء واحدة؟

أعتقد أنه سيكون من المفيد جدًا إجراء جلسة وهمية. اختبار وحدة الكتابة لصناديق proc-macro مستحيل إلى حد كبير أو على الأقل غير مريح للغاية بخلاف ذلك. علاوة على ذلك ، فهي ليست فقط TokenStream::from_str ، ولكن أيضًا وظائف أخرى تتطلب جلسة.

تضمين التغريدة

لقد قمت ببعض أعمال الفرز لجميع الأخطاء المتعلقة بوحدات الماكرو 1.2. يمكن تصنيف معظم الأخطاء إلى "أخطاء خطيرة" أو "جميع الأخطاء المتعلقة بالامتداد".

أرغب في ترقية https://github.com/rust-lang/rust/issues/50504 إلى الحالة "الخطيرة" - مشكلة الوحدة الموصوفة لا يوجد سوى عرض لمشكلة أعمق - معرفات التوسيع لوحدات الماكرو proc لا يتم تسجيلها بشكل صحيح. لا أعرف ما هي العواقب الأخرى التي قد تترتب على ذلك.
هناك علاقات عامة تعمل على إصلاح المشكلة الأساسية (https://github.com/rust-lang/rust/pull/51952) ، ولكن هناك انحدارات من الإصلاح ولم أتطرق إليها بعد.

لقد قمت بنشر علاقات عامة لتثبيت المزيد من وحدات الماكرو الإجرائية على https://github.com/rust-lang/rust/pull/52081

petrochenkov يبدو جيدًا بالنسبة لي ،

لقد نشرت للتو على مشكلة تتبع تسمية الماكرو حول المشكلات المتعلقة بسمات الطفل proc_macro_derive وكيفية تفاعلها مع نظام التسمية. هناك مشكلة أخرى تتعلق بالطريقة التي تتفاعل بها سمات الطفل proc_macro_derive مع تحديد النطاق والتسمية ، ولكن يبدو أنها أكثر صلة بالموضوع هنا. نظرًا لأن المسارات الموجودة في السمات ليست حاليًا في مسار التثبيت ، فإننا نحصل على احتمال أن يكون لدى #[derive(foo::Parent)] سمة فرعية #[foo::Child] ، لكن ماكرو الاشتقاق لن يكون له أي طريقة ، في ظاهره ، إلى تحديد ما إذا كانت السمة الفرعية هي بالفعل تابعة لها ، حيث لا يمكنها إجراء البحث عن الاسم. في الوقت الحالي ، ليس لدي حل سهل ، لكنني أعتقد أنه شيء يجب أن يكون على الرادار من أجل مستقبل السمات المترابطة ؛ لا يوجد سبب لعدم رغبة سمات proc_macro_attribute في التفاعل بطريقة تؤدي إلى مشكلات بحث مماثلة.

حاولت تجميع مشروعي اليوم ، ولكن هناك شيء ما معطل وهو على الأرجح متعلق بهذه المشكلة. كانت جميع رسائل الخطأ تحتوي على الرسالة التالية: "(راجع العدد رقم 38356)". هكذا وصلت إلى هنا.
أقوم هنا بتضمين رسالة الخطأ التي تلقيتها أثناء التجميع. أقوم أيضًا بتضمين Cargo.toml الخاص بي.

أجد هذا مفاجئًا للغاية ، حيث تم تثبيت مشروعي بإصدار Rust الليلي محدد (rustc 1.29.0-nightly (9 definitely458c9 2018-07-09)) ما الذي كان يمكن أن يتغير؟ ربما مكتبة محدثة؟

Cargo.toml

[[bin]]
name = "main"
path = "src/bin/main.rs"

[dependencies]
log = "0.4"
pretty_env_logger = "0.2"

rand = "0.4"
ring = "=0.13.0-alpha"
untrusted = "0.6"

bytes = "0.4"
futures = "0.1"
tokio-io = "0.1"
tokio-core = "0.1"
futures-await = "0.1"

capnp = "0.8"
rusqlite = "0.13"

async_mutex = { git = "https://github.com/realcr/async_mutex", rev = "a1d973ed7" }

num-bigint = "0.2.0"
num-traits = "0.2.4"

[dev-dependencies]

[dependencies.byteorder]
version = "1.1"
features = ["i128"]

[build-dependencies]
capnpc = "0.8"

[profile.release]
debug = true

أخطاء التجميع

$ cargo test
    Updating git repository `https://github.com/realcr/async_mutex`
   Compiling proc-macro2 v0.4.8                                                                                                                                                                                    
   Compiling cswitch v0.1.0 (file:///home/real/projects/d/cswitch)                                                                                                                                                 
error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)8: proc-macro2                                                                                                                        
  --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:33:40
   |
33 |     let works = panic::catch_unwind(|| proc_macro::Span::call_site()).is_ok();
   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:213:13
    |
213 |     Nightly(proc_macro::token_stream::IntoIter),
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:438:11
    |
438 | impl From<proc_macro::Span> for ::Span {
    |           ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:284:13
    |
284 |     Nightly(proc_macro::SourceFile, FileName),
    |             ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:332:13
    |
332 |     Nightly(proc_macro::Span),
    |             ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:461:13
    |
461 |     Nightly(proc_macro::Ident),
    |             ^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:523:13
    |
523 |     Nightly(proc_macro::Literal),
    |             ^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:116:47
    |
116 |                     Delimiter::Parenthesis => proc_macro::Delimiter::Parenthesis,
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:117:43
    |
117 |                     Delimiter::Bracket => proc_macro::Delimiter::Bracket,
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:118:41
    |
118 |                     Delimiter::Brace => proc_macro::Delimiter::Brace,
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:119:40
    |
119 |                     Delimiter::None => proc_macro::Delimiter::None,
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:122:33
    |
122 |                 let mut group = proc_macro::Group::new(delim, tt.stream.inner.unwrap_nightly());
    |                                 ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:128:39
    |
128 |                     Spacing::Joint => proc_macro::Spacing::Joint,
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:129:39
    |
129 |                     Spacing::Alone => proc_macro::Spacing::Alone,
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:131:30
    |
131 |                 let mut op = proc_macro::Punct::new(tt.as_char(), spacing);
    |                              ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:113:17
    |
113 |         let tt: proc_macro::TokenTree = match token {
    |                 ^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:238:13
    |
238 |             proc_macro::TokenTree::Group(tt) => {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:240:21
    |
240 |                     proc_macro::Delimiter::Parenthesis => Delimiter::Parenthesis,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:241:21
    |
241 |                     proc_macro::Delimiter::Bracket => Delimiter::Bracket,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:242:21
    |
242 |                     proc_macro::Delimiter::Brace => Delimiter::Brace,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:243:21
    |
243 |                     proc_macro::Delimiter::None => Delimiter::None,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:250:13
    |
250 |             proc_macro::TokenTree::Punct(tt) => {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:252:21
    |
252 |                     proc_macro::Spacing::Joint => Spacing::Joint,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:253:21
    |
253 |                     proc_macro::Spacing::Alone => Spacing::Alone,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:259:13
    |
259 |             proc_macro::TokenTree::Ident(s) => ::Ident::_new(Ident::Nightly(s)).into(),
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:260:13
    |
260 |             proc_macro::TokenTree::Literal(l) => ::Literal::_new(Literal::Nightly(l)).into(),
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:289:20
    |
289 |     fn nightly(sf: proc_macro::SourceFile) -> Self {
    |                    ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:339:27
    |
339 |             Span::Nightly(proc_macro::Span::call_site())
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:347:27
    |
347 |             Span::Nightly(proc_macro::Span::def_site())
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:369:30
    |
369 |     pub fn unstable(self) -> proc_macro::Span {
    |                              ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:430:32
    |
430 |     fn unwrap_nightly(self) -> proc_macro::Span {
    |                                ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:439:24
    |
439 |     fn from(proc_span: proc_macro::Span) -> ::Span {
    |                        ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:468:48
    |
468 |             Span::Nightly(s) => Ident::Nightly(proc_macro::Ident::new(string, s)),
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:475:48
    |
475 |             Span::Nightly(s) => Ident::Nightly(proc_macro::Ident::new_raw(string, s)),
    |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:495:32
    |
495 |     fn unwrap_nightly(self) -> proc_macro::Ident {
    |                                ^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:583:30
    |
583 |             Literal::Nightly(proc_macro::Literal::f32_unsuffixed(f))
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:591:30
    |
591 |             Literal::Nightly(proc_macro::Literal::f64_unsuffixed(f))
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:599:30
    |
599 |             Literal::Nightly(proc_macro::Literal::string(t))
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:607:30
    |
607 |             Literal::Nightly(proc_macro::Literal::character(t))
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:615:30
    |
615 |             Literal::Nightly(proc_macro::Literal::byte_string(bytes))
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:636:32
    |
636 |     fn unwrap_nightly(self) -> proc_macro::Literal {
    |                                ^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/lib.rs:322:30
    |
322 |     pub fn unstable(self) -> proc_macro::Span {
    |                              ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:531:34
    |
531 |                   Literal::Nightly(proc_macro::Literal::$name(n))
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
...
552 | /     suffixed_numbers! {
553 | |         u8_suffixed => u8,
554 | |         u16_suffixed => u16,
555 | |         u32_suffixed => u32,
...   |
565 | |         f64_suffixed => f64,
566 | |     }
    | |_____- in this macro invocation
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:543:34
    |
543 |                   Literal::Nightly(proc_macro::Literal::$name(n))
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
...
568 | /     unsuffixed_integers! {
569 | |         u8_unsuffixed => u8,
570 | |         u16_unsuffixed => u16,
571 | |         u32_unsuffixed => u32,
...   |
578 | |         isize_unsuffixed => isize,
579 | |     }
    | |_____- in this macro invocation
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
  --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:45:34
   |
45 |             TokenStream::Nightly(proc_macro::TokenStream::new())
   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
  --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:53:46
   |
53 |             TokenStream::Nightly(tts) => tts.is_empty(),
   |                                              ^^^^^^^^
   |
   = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:123:23
    |
123 |                 group.set_span(span.inner.unwrap_nightly());
    |                       ^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:132:20
    |
132 |                 op.set_span(tt.span().inner.unwrap_nightly());
    |                    ^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:239:38
    |
239 |                 let delim = match tt.delimiter() {
    |                                      ^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:245:74
    |
245 |                 let stream = ::TokenStream::_new(TokenStream::Nightly(tt.stream()));
    |                                                                          ^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:247:58
    |
247 |                 g.set_span(::Span::_new(Span::Nightly(tt.span())));
    |                                                          ^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:251:40
    |
251 |                 let spacing = match tt.spacing() {
    |                                        ^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:255:43
    |
255 |                 let mut o = Punct::new(tt.as_char(), spacing);
    |                                           ^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:256:58
    |
256 |                 o.set_span(::Span::_new(Span::Nightly(tt.span())));
    |                                                          ^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:290:45
    |
290 |         let filename = stable::file_name(sf.path().to_string());
    |                                             ^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:304:44
    |
304 |             SourceFile::Nightly(a, _) => a.is_real(),
    |                                            ^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:355:69
    |
355 |             (Span::Nightly(a), Span::Nightly(b)) => Span::Nightly(a.resolved_at(b)),
    |                                                                     ^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:363:69
    |
363 |             (Span::Nightly(a), Span::Nightly(b)) => Span::Nightly(a.located_at(b)),
    |                                                                     ^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:424:55
    |
424 |             (Span::Nightly(a), Span::Nightly(b)) => a.eq(b),
    |                                                       ^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:482:50
    |
482 |             Ident::Nightly(t) => Span::Nightly(t.span()),
    |                                                  ^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:489:56
    |
489 |             (Ident::Nightly(t), Span::Nightly(s)) => t.set_span(s),
    |                                                        ^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:623:56
    |
623 |             Literal::Nightly(lit) => Span::Nightly(lit.span()),
    |                                                        ^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:630:62
    |
630 |             (Literal::Nightly(lit), Span::Nightly(s)) => lit.set_span(s),
    |                                                              ^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error: aborting due to 63 previous errors

For more information about this error, try `rustc --explain E0658`.
error: Could not compile `proc-macro2`. 

هل لديك فكرة عما يمكن أن يحدث ، وكيف يمكن إصلاحه؟ شكرا!

realcr للصندوق proc-macro2 يمكنك ببساطة تشغيل cargo update وهذا سيفي بالغرض!

alexcrichton لا أعتقد أن هذه هي المشكلة هنا. أعتقد أن realcr قام بالفعل بتحديث proc-macro2 لأن رسالة الخطأ تقول proc-macro2-0.4.8 كل مكان. المشكلة هي أن الإصدار الليلي يتم إصلاحه لنسخة لا تتضمن # 52081. عانيت من نفس المشكلة اليوم وتساءلت عن السبب الذي جعل proc-macro2 يصطدم بالنسخة الثانوية فقط. لكني لست على دراية بكيفية تعامل proc-macro2 مع التوافق.

realcr حاول تحديث المترجم الليلي أو فرض إصدار proc-macro-2 < 0.4.8 في مشروعك.

alexcrichton ، LukasKalbertodt : شكرا على الرد السريع.
لقد قمت للتو بتحديث مترجمي الليلي إلى أحدث إصدار. لقد تخلصت من مشاكل proc-macro-2 ، لكنني حصلت على الكثير من أخطاء الترجمة الجديدة. مثال:

error[E0277]: the trait bound `impl futures::Future: std::future::Future` is not satisfied
   --> src/networker/messenger/handler/handle_neighbor.rs:191:25
    |
191 |         let signature = await!(self.security_module_client.request_signature(failure_signature_buffer))
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `impl futures::Future`
    |
    = note: required by `std::future::poll_in_task_cx`
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

...

error[E0627]: yield statement outside of generator literal
   --> src/networker/messenger/handler/handle_neighbor.rs:403:13
    |
403 | /             await!(self.reply_with_failure(remote_public_key.clone(), 
404 | |                                            channel_index,
405 | |                                            request_send_msg.clone()))?
    | |_____________________________________________________________________^
    |
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

للتأكيد ، الإصدار الحالي الخاص بي من rustc:

rustc 1.29.0-nightly (1ecf6929d 2018-07-16)

من أجل تتبع مصدر المشكلة ، حاولت تجميع المثال الأساسي من futures_await ولكنه توقف أيضًا عن العمل. سأقدم مشكلة هناك حتى نتمكن من حل هذه المشكلة.

LukasKalbertodt https://github.com/alexcrichton/proc-macro2#unstable -features

لأنك تستخدم الميزة غير المستقرة.

realcr لا تتعلق مشكلة متابعة الموضوع.

TeXitoi : لا تتردد في تعديل أو إزالة أي شيء إذا كنت تعتقد أنه غير ذي صلة. أبذل قصارى جهدي لمساعدتك ، من الصعب عليّ معرفة ما هو موضوع وما هو غير ذلك. رسالة الخطأ "(راجع الإصدار رقم 38356)" هي ما أوصلني إلى هنا.

حاولت ترقية إصدار المترجم الخاص بي ولدي هذا الخطأ. رمز بلدي

#![no_std]
#![feature(proc_macro)]
#![feature(proc_macro_gen)]
#![feature(custom_attribute)]
#![feature(alloc)]

#[macro_use(eth_abi)]
extern crate pwasm_abi_derive;

والخطأ الذي يفيد بأنني لم أستخدم #![feature(proc_macro)] ، لكنني فعلت ذلك!

error[E0658]: attribute procedural macros are experimental (see issue #38356)
  --> src\lib.rs:67:5
   |
8  | #[macro_use(eth_abi)]
   |             ------- procedural macro imported here
...
67 |     #[eth_abi(TokenEndpoint, TokenClient)]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: add #![feature(proc_macro)] to the crate attributes to enable

Pzixel ، سترغب في تبديل #![feature(proc_macro)] إلى #![feature(use_extern_macros)] وهذا سيفي بالغرض

أعتقد أنك ستحتاج أيضًا إلى استخدام نظام الوحدة النمطية لاستيراد وحدات الماكرو الإجرائية (وتأكد من أن لديك مترجمًا ليليًا محدثًا)

alexcrichton نعم ، لقد اكتشفت ذلك بفضل المقال . ومع ذلك ، فإنه لا يزال لا يعمل:

error[E0433]: failed to resolve. Use of undeclared type or module `Vec`
  --> src\lib.rs:66:5
   |
66 |     #[eth_abi(TokenEndpoint, TokenClient)]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use of undeclared type or module `Vec`

error[E0412]: cannot find type `Vec` in this scope
  --> src\lib.rs:66:5
   |
66 |     #[eth_abi(TokenEndpoint, TokenClient)]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope

تغيرت قواعد الاستيراد لوحدات الماكرو أيضا؟ أو لا يمكنني معرفة سبب بدء الشكوى هنا.

Pzixel التي قد تكون خطأ في الماكرو الإجرائي أو المترجم ، هل يمكنك تقديم مشكلة مخصصة لذلك؟

حسنًا ، أعتقد أنه يجب علي إعادة كتابة الكود الخاص بي أولاً لجعله يبدو يعمل على الأقل :) في الوقت الحالي لم يحدث ذلك ، لقد غيرتم كثيرًا باستخدام هذه الميزة. BRB عند الانتهاء. إذا لم تختف ، فأنشئ مشكلة.

تضمين التغريدة
هل تعرف ما هي "المعالجة المسبقة" المطبقة على الرموز قبل أن يتم تمريرها إلى ماكرو إجرائي؟
أعلم أن المشتقات قد تم التخلص منها على الأقل $crate وتم توسيع cfg قبل أن تحصل على رموز الإدخال (بالإضافة إلى الرحلات ذهابًا وإيابًا عبر السلاسل ليست خالية تمامًا من الخسائر ، ولكن هذا قابل للإصلاح).

يجب أن نتأكد من عدم حدوث أي من هذا مع وحدات الماكرو الإجرائية المستقرة حديثًا وأنهم يحصلون على رموز الإدخال بدقة (أخطاء modulo).

alexcrichton آسف ، cargo expand لا يعمل على هذا الصندوق لسبب ما. لا يمكن تأكيد ما إذا كانت المشكلة من جانبي أم على المترجم. لذلك سأستمر في إلقاء اللوم على نفسي حتى لا يتم استبعاد هذا الاحتمال تمامًا.

petrochenkov تم فحص توسيع proc-macros جيدًا حتى الآن ، لذا فأنا أقل قلقًا بشأن ذلك من قطع دقة الاسم. أنا لست على علم شخصيًا بالمعالجة المسبقة ، لكنني أعلم أن هناك أمر توسع حيث يتم تشغيل المشتقات أخيرًا ، وتشغيل cfgs أولاً ، وبخلاف ذلك ، يكون في الغالب تكراريًا.

أوافق على الرغم من أنه من الجيد التدقيق!

ربما فاتني شيء واضح. ولكن ، أليست هناك طريقة لاستدعاء دالة ، واستخدام نوع ، وما إلى ذلك من صندوق تعريف proc_macro من توسع ماكرو إجرائي؟ (أو أي صندوق آخر معروف من صندوق proc_macro ، FWIW)

هناك حلول بديلة ، لكن AFAIU لن يعملوا إذا تمت إعادة تسمية الصندوق بواسطة مستخدم الماكرو الإجرائي.

عادةً ما يتم تجميع صناديق Ekleog proc-macro فقط لغرض بناء الصناديق التي تستخدمها. إنها ليست تبعيات وقت التشغيل. يمكنك التفكير في صندوق proc-macro بأكمله كنوع من مكون إضافي للمترجم ، وليس مكتبة "عادية".

يكون هذا مرئيًا بشكل خاص عند التحويل البرمجي المتقاطع: مثل إنشاء البرامج النصية ، يتم تجميع وحدات الماكرو proc لمنصة المضيف ، وليس النظام الأساسي المستهدف.

SimonSapin أنا أتفق معك ، ولكن قد يكون من المفيد حقًا تفويض جزء من العمل إلى وظيفة يوفرها الصندوق ، حتى لو لم يكن صندوق proc-macro (على سبيل المثال ، في الرابط أعلاه ، X-derive crate يحاول استخدام دالة من الصندوق X ). لأنه بخلاف ذلك ، قد يعني ذلك أن جميع التعليمات البرمجية التي تم إنشاؤها بواسطة وحدات الماكرو proc يجب أن تكون إما ذاتية الاحتواء أو تضع افتراضات بشأن حالة موقع الاتصال.

بعد ذلك ، يمكنني أن أفهم أن rustc ليس جاهزًا بعد لهذا النوع من الميزات (لأنني أعتقد أنه سيعمل بشكل أفضل دون الحاجة إلى فصل proc-macro من الصناديق غير التابعة لـ proc-macro ، والتي يبدو أنها في مكان ما على المدى الطويل- خارطة طريق المصطلح). لكنني أتساءل ، إذا كانت الواجهة الحالية التي تستخدم TokenStreams مستقرة ، فهل سيكون من الممكن تعديل هذه الميزة لاحقًا؟ ألن تحتاج إلى شيء مثل الرمز المميز PathToBeResolvedFromTopOfGeneratingProcMacroCrate ؟ (والذي سيكون تغييرًا جذريًا إذا تمت إضافته لاحقًا ، afaiu)

ربما سيكون من الممكن جعل الأمور أكثر مرونة في النهاية ، لكن هذا يبدو بعيد المنال.

في غضون ذلك ، إذا كنت مؤلف مكتبة ، ففكر في امتلاك صندوق foo-proc-macros أو foo-derive لوحدات الماكرو الإجرائية ، ومكتبة "عادية" foo تحتوي على وقت التشغيل رمز ولكن أيضًا يعيد تصدير وحدات الماكرو الإجرائية. بهذه الطريقة يمكن الاحتفاظ بواجهة برمجة التطبيقات التي تواجه المستخدم في صندوق واحد. هذا ما يفعله serde (في بعض التكوينات) https://github.com/serde-rs/serde/blob/v1.0.71/serde/src/lib.rs#L304

تجدر الإشارة إلى أن هذا الحل البديل لا يزال لا يعالج مشكلة إعادة تسمية المستخدم لصندوق الجذر (مثل

Ekleog ، TokenStream هو دفق TokenTree s وكل TokenTree يقترن Span ، والذي يحمل معلومات النطاق. باستثناء أنه لا توجد طريقة حاليًا لإنشاء Span لأي نطاق آخر غير "موقع الاتصال" (أو فارغ). ما هو مطلوب بشكل أساسي هو التوصل إلى طريقة مريحة بشكل معقول لإنشاء Span s بالإشارة إلى صندوق معين.

سبب سؤالي هو أن مربع الاختيار لم يتم تحديده. سيكون من الجيد وضع علامة عليه بعد ذلك!

مع استقرار #![feature(proc_macro)] ، ما الذي تبقى من هذه المشكلة؟

@ jan-hudec حسنًا ، اعتقدت أن Span s كانت مخصصة فقط للإبلاغ عن الأخطاء ، حيث أشارت منشورات المدونة المبكرة إلى هيكل Hygiene (أو اسم مشابه) لعب هذا الدور. كنت قد افترضت أن هذه قد اختفت ، ومن الواضح أنها كانت خاطئة. شكرا! :)

مع #! [ميزة (proc_macro)] مستقرة ، ما الذي تبقى من هذه المشكلة؟

من الناحية المثالية ، يجب تقديم مشكلات جديدة لجميع المشكلات الفردية المتبقية وليس الميزات المستقرة ، ومن ثم يمكن إغلاق هذه المشكلة (بنفس الطريقة التي تم بها ذلك من أجل https://github.com/rust-lang/rust/issues/ 44660).

أوه ، اعتقدت أن Spans كانت مخصصة فقط للإبلاغ عن الأخطاء ، حيث ذكرت منشورات المدونة المبكرة بنية Hygiene (أو المسماة بالمثل) التي لعبت هذا الدور. كنت قد افترضت أن هذه قد اختفت ، ومن الواضح أنها كانت خاطئة. شكرا! :)

IIUC ، الامتدادات هي الطريقة الأساسية لتتبع سياق النظافة.

@ mark-im نوع من. وهي تشمل معلومات موقع رمز المصدر (للرسائل / التشخيصات التي تواجه المستخدم) وسياق بناء الجملة (أي معلومات النظافة).

بالنظر إلى مقدار المناقشة / الزيارات التي تحصل عليها هذه المشكلة ، هل من المنطقي نقل proc_macro_diagnostic لمشكلة التتبع الخاصة بها؟ أود أيضًا معرفة ماهية الحواجز لتثبيت هذه الميزة ، ومعرفة ما إذا كان بإمكاننا دفعها من خلالها. يستخدمه ديزل ، وقد كان رائعًا حتى الآن. يؤدي عدم وجود هذه الميزة على المستقر إلى قيام المجتمع بإنشاء حلول غير تقليدية ، مثل أحدث إصدار من syn يستخدم compile_error! في مكانه.

sgrif لقد فتحت مثل هذه المشكلة: https://github.com/rust-lang/rust/issues/54140.

لذلك أنا مهتم بالمساعدة في تثبيت الأساليب في Span و LineColumn. سألقي نظرة على المشكلات المفتوحة في التعليق الأول ، ولكن إذا أراد أي شخص توجيه مبتدئ إلى المترجم في اتجاه معين ، فسأقدر ذلك: +1:

لقد وجهتني بوابة الميزة proc_macro_gen هنا ، لكن في قائمة التحقق الموجودة في الجزء العلوي ، لا أرى شيئًا يشير بوضوح إلى ماكرو (proc_) الذي يولد تعريفات ماكرو أخرى. هل تم احتساب هذا (بخلاف بوابة ميزة rustc)؟

jjpe من الأفضل في هذا الوقت أن

alexcrichton أنا بخير تمامًا مع ذلك ، إنه أكثر من ذلك أثناء النظر إلى ميزة proc_macro_gen ، لقد أشار إلي هنا فقط لأجد أنه لم يذكر ذلك جيدًا. هذا غريب بعض الشيء بالنسبة لي ، لذلك قررت أن أذكره على الأقل.

xieyuheng ما الذي يمكن أن يبدو عليه CodeString / Code على سبيل المثال ، ماذا ستكون دلالاته؟
ضع في اعتبارك أن TokenStream ليس أكثر من رمز المصدر حرفيًا باستثناء سلسلة من القيم المميزة بدلاً من النص المزعج.

واجهة برمجة التطبيقات الموسعة لـ TokenStream (مع TokenTree ) مستقرة في 1.29. سيكون استيراد وحدات ماكرو proc التي تشبه الوظيفة مستقرًا في 1.30.

يبدو أنه منذ rustc 1.30.0-nightly (63d51e89a 2018-09-28) لم يعد من الممكن اجتياز الكود داخل الوحدة النمطية في ملف منفصل. إذا قمت بمعالجة mod module; ، فستحصل على TokenStream يحتوي على mod module; ، WYSIWYG.

أفهم أن هذا ضروري للحفاظ على الامتدادات والنظافة والاتساق مع التعليمات البرمجية المعالجة. هل هناك أو ستكون هناك طريقة للعمل مع محتوى الوحدات في ملفات منفصلة؟ قد يكون نقصه مربكًا للمستخدمين النهائيين عندما تؤدي إعادة هيكلة تنظيم الوحدة النمطية إلى حدوث تغيير في سلوك الماكرو.

حسنًا ، هذه المشكلة ضخمة وقد وصلت إلى درجة أنني لا أعتقد أنه من المفيد جدًا الاستمرار في فتحها وتتبع واجهات برمجة التطبيقات. لتحقيق هذه الغاية ، فتحت https://github.com/rust-lang/rust/pull/54728 والذي يقسم هذه المشكلة إلى عدد من مشكلات التتبع الدقيقة:

في هذه المرحلة ، سأغلق هذا ، ولكن إذا نسيت فصل أي مشكلات تتبع أخرى ، فيرجى إبلاغي بذلك! يمكنني بالتأكيد فتح المزيد من المتابعات

alexcrichton ماذا عن السمات الفرعية لماكرو يشبه السمة؟
https://github.com/rust-lang/rust/issues/38356#issuecomment -397095541
هل هناك مشكلة لهذا؟

XX
لا يجب بالضرورة أن تكون مثل هذه السمات الفرعية ميزة لغوية؟
في حالة derive يلزم تسجيل السمات المخصصة لأن وحدات الماكرو المشتقة لا يمكنها إزالة السمات من مدخلاتها (الإدخال غير قابل للتغيير).
يمكن لوحدات ماكرو السمات إزالة #[other_attribute] s من المدخلات الخاصة به ، لذلك لن يتمكنوا أبدًا من تحديد تحليل الاسم ولن يبلغوا أبدًا عن خطأ "السمة التي لم يتم حلها".

(إلى جانب السمات المخصصة القديمة غير المستقرة والمذكورة في https://github.com/rust-lang/rust/issues/38356#issuecomment-397095541 ، تتوافق الآن مع وحدات الماكرو proc.)

petrochenkov نعم ، شكرًا على التوضيح.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات