MyLang هي لغة برمجة تعليمية بسيطة مستوحاة من Python
و JavaScript
و C
، تمت كتابتها كتحدي شخصي، في وقت قصير، غالبًا للاستمتاع بكتابة محلل أصل عودي واستكشاف عالم المترجمين الفوريين. لا تتوقع لغة برمجة نصية كاملة مع مكتبات وأطر عمل جاهزة للاستخدام في الإنتاج. ومع ذلك، يحتوي MyLang
على الحد الأدنى من العناصر المضمنة، ويمكن استخدامه لأغراض عملية أيضًا.
تمت كتابة MyLang بلغة C++ 17 المحمولة : في الوقت الحالي، لا يحتوي المشروع على أي تبعيات بخلاف مكتبة C++ القياسية. لإنشائه، إذا كان GNU make
مثبتًا لديك، فما عليك سوى تشغيل:
$ make -j
بخلاف ذلك، ما عليك سوى تمرير كافة ملفات .cpp إلى المترجم الخاص بك وإضافة الدليل src/
إلى مسار البحث المتضمن. من أجمل الأشياء المتعلقة بعدم وجود تبعيات هو عدم الحاجة إلى نظام إنشاء للإنشاءات لمرة واحدة.
ما عليك سوى تمرير خيار BUILD_DIR
لإجراء make
:
$ make -j BUILD_DIR=other_build_directory
إذا كنت تريد تشغيل اختبارات MyLang أيضًا، فأنت بحاجة فقط إلى التجميع باستخدام TESTS=1 وتعطيل التحسينات باستخدام OPT=0، للحصول على تجربة تصحيح أفضل:
$ make -j TESTS=1 OPT=0
ثم قم بإجراء جميع الاختبارات باستخدام:
$ ./build/mylang -rt
تجدر الإشارة إلى أنه على الرغم من أن أطر الاختبار مثل GoogleTest وBoost.Test هي أكثر قوة ومرونة بكثير من محرك الاختبار البسيط الموجود في src/tests.cpp
، إلا أنها تبعيات خارجية . كلما قلت التبعيات، كلما كان ذلك أفضل، أليس كذلك؟ :-)
أقصر طريقة لوصف MyLang
هي: لغة بايثون ديناميكية ذات مظهر C. ربما تكون أسرع طريقة لتعلم هذه اللغة هي التحقق من البرامج النصية الموجودة في الدليل samples/
أثناء إلقاء نظرة على الوثائق القصيرة أدناه.
MyLang
هي لغة ديناميكية لكتابة البطة، مثل Python
. إذا كنت تعرف Python
وكنت على استعداد لاستخدام الأقواس { }
، فستتمكن تلقائيًا من استخدامها. لا مفاجآت. السلاسل النصية غير قابلة للتغيير كما هو الحال في Python
، ويمكن تعريف المصفوفات باستخدام [ ]
كما في Python
، ويمكن تعريف القواميس باستخدام { }
أيضًا. تدعم اللغة أيضًا شرائح المصفوفات باستخدام نفس بناء الجملة [start:end]
الذي تستخدمه Python
.
يقال إن MyLang
يختلف عن Python
ولغات البرمجة النصية الأخرى في عدة جوانب:
هناك دعم لثوابت وقت التحليل المعلنة باستخدام const
.
يجب الإعلان عن كافة المتغيرات باستخدام var
.
المتغيرات لها نطاق كما في C
. يتم دعم التظليل عند إعادة تعريف المتغير بشكل صريح باستخدام var
في كتلة متداخلة.
يجب أن تنتهي جميع عبارات التعبير بـ ;
كما هو الحال في C
و C++
و Java
.
الكلمات الرئيسية true
false
موجودة، ولكن لا يوجد نوع boolean
. كما هو الحال في لغة C، 0
خطأ، وكل شيء آخر true
. ومع ذلك، فإن السلاسل والمصفوفات والقواميس لها قيمة منطقية، تمامًا كما هو الحال في Python
(على سبيل المثال، تعتبر المصفوفة الفارغة false
). إن المضمن true
هو مجرد اسم مستعار للعدد الصحيح 1
.
يمكن استخدام عامل التعيين =
كما هو الحال في C
، داخل التعبيرات، ولكن لا يوجد شيء مثل عامل الفاصلة، بسبب ميزة توسيع المصفوفة.
يدعم MyLang كلا من حلقة for
الكلاسيكية وحلقة foreach
الصريحة.
لا يدعم MyLang الأنواع المخصصة في الوقت الحالي. ومع ذلك، تدعم القواميس سكرًا نحويًا لطيفًا: بالإضافة إلى بناء الجملة الرئيسي d["key"]
، بالنسبة لمفاتيح السلسلة، يتم دعم بناء الجملة d.key
أيضًا.
يتم دائمًا الإعلان عن المتغيرات باستخدام var
وتعيش في النطاق الذي تم الإعلان عنه (بينما تكون مرئية في النطاقات المتداخلة). على سبيل المثال:
# Variable declared in the global scope
var a = 42 ;
{
var b = 12 ;
# Here we can see both `a` and `b`
print ( a , b ) ;
}
# But here we cannot see `b` .
من الممكن الإعلان عن متغيرات متعددة باستخدام الصيغة المألوفة التالية:
var a , b , c ;
ولكن هناك تحذير، ربما الميزة "المفاجئة" الوحيدة في MyLang
: تهيئة المتغيرات لا تعمل كما هو الحال في لغة C. خذ بعين الاعتبار العبارة التالية:
var a , b , c = 42 ;
في هذه الحالة، بدلاً من مجرد الإعلان عن a
و b
والتهيئة من c
إلى 42، فإننا نقوم بتهيئة جميع المتغيرات الثلاثة إلى القيمة 42. لتهيئة كل متغير إلى قيمة مختلفة، استخدم صيغة توسيع المصفوفة:
var a , b , c = [ 1 , 2 , 3 ] ;
يتم الإعلان عن الثوابت بطريقة مشابهة للمتغيرات ولكن لا يمكن تظليلها في النطاقات المتداخلة. على سبيل المثال:
const c = 42 ;
{
# That's not allowed
const c = 1 ;
# That's not allowed as well
var c = 99 ;
}
في MyLang
يتم تقييم الثوابت في وقت التحليل ، بطريقة مشابهة لإعلانات constexpr الخاصة بـ C++
(لكننا نتحدث هنا عن وقت الترجمة ). أثناء تهيئة const
، يمكن استخدام أي نوع من العناصر الحرفية بالإضافة إلى المجموعة الكاملة من إضافات const . على سبيل المثال:
const val = sum ( [ 1 , 2 , 3 ] ) ;
const x = " hello " + " world " + " " + join ( [ " a " , " b " , " c " ] , " , " ) ;
لفهم كيفية تقييم الثابت بالضبط، قم بتشغيل المترجم باستخدام الخيار -s
، لتفريغ شجرة بناء الجملة المجردة قبل تشغيل البرنامج النصي. على سبيل المثال أعلاه:
$ cat > t
const val = sum([1,2,3]);
const x = "hello" + " world" + " " + join(["a","b","c"], ",");
$ ./build/mylang t
$ ./build/mylang -s t
Syntax tree
--------------------------
Block(
)
--------------------------
متفاجئ؟ حسنًا، الثوابت بخلاف المصفوفات والقواميس لا يتم حتى إنشاء مثيل لها كمتغيرات. هم فقط غير موجودين في وقت التشغيل . دعونا نضيف عبارة باستخدام x
:
$ cat >> t
print(x);
$ cat t
const val = sum([1,2,3]);
const x = "hello" + " world" + " " + join(["a","b","c"], ",");
print(x);
$ ./build/mylang -s t
Syntax tree
--------------------------
Block(
CallExpr(
Id("print")
ExprList(
"hello world a,b,c"
)
)
)
--------------------------
hello world a,b,c
الآن، كل شيء يجب أن يكون منطقيا. يحدث نفس الشيء تقريبًا مع المصفوفات والقواميس باستثناء أنه يتم إنشاء مثيل لها في وقت التشغيل أيضًا، وذلك لتجنب وجود قيم حرفية ضخمة محتملة في كل مكان. خذ بعين الاعتبار المثال التالي:
$ ./build/mylang -s -e 'const ar=range(4); const s=ar[2:]; print(ar, s, s[0]);'
Syntax tree
--------------------------
Block(
ConstDecl(
Id("ar")
Op '='
LiteralArray(
Int(0)
Int(1)
Int(2)
Int(3)
)
)
ConstDecl(
Id("s")
Op '='
LiteralArray(
Int(2)
Int(3)
)
)
CallExpr(
Id("print")
ExprList(
Id("ar")
Id("s")
Int(2)
)
)
)
--------------------------
[0, 1, 2, 3] [2, 3] 2
كما ترون، تم تقييم عملية الشريحة في وقت التحليل أثناء تهيئة الثابت s
، ولكن كلا المصفوفتين موجودتان في وقت التشغيل أيضًا. بدلاً من ذلك، يتم تحويل العمليات المنخفضة في تعبيرات const إلى قيم حرفية. يبدو ذلك بمثابة مقايضة جيدة للأداء: يتم تحويل القيم الصغيرة مثل الأعداد الصحيحة والأعداد العشرية والسلاسل إلى قيم حرفية أثناء تقييم const ، بينما تُترك المصفوفات والقواميس (التي قد تكون كبيرة) كرموز للقراءة فقط في وقت التشغيل، ولكنها لا تزال تسمح بذلك سيتم تقييم بعض العمليات عليها (مثل [index]
و len(arr)
) بشكل مستمر.
يدعم MyLang
، في الوقت الحالي، الأنواع (المدمجة) التالية فقط:
لا شيء نوع none
، أي ما يعادل None
في بايثون. المتغيرات التي تم الإعلان عنها للتو دون تعيين قيمة لها، none
لها قيمة (على سبيل المثال var x;
). وينطبق الشيء نفسه على الوظائف التي ليس لها قيمة إرجاع. أيضًا، يتم استخدامها كقيمة خاصة من خلال الإضافات المضمنة مثل find()
، في حالة الفشل.
عدد صحيح عدد صحيح بحجم المؤشر (على سبيل المثال 3
).
تعويم رقم الفاصلة العائمة (على سبيل المثال 1.23
). داخليًا، إنه مزدوج طويل.
سلسلة سلسلة مثل "مرحبا". السلاسل النصية غير قابلة للتغيير وتدعم الشرائح (على سبيل المثال s[3:5]
أو s[3:]
أو s[-2:]
، ولها نفس المعنى كما في Python
).
Array نوع قابل للتغيير للمصفوفات والصفوف (على سبيل المثال [1,2,3]
). يمكن أن يحتوي على عناصر من أنواع مختلفة ويدعم الشرائح القابلة للكتابة. تتصرف شرائح المصفوفة مثل النسخ، بينما تستخدم، تحت الغطاء، تقنيات النسخ عند الكتابة.
قواميس القاموس عبارة عن خرائط تجزئة محددة باستخدام بناء جملة Python
: {"a": 3, "b": 4}
. يتم الوصول إلى العناصر باستخدام الصيغة المألوفة d["key-string"]
أو d[23]
، ويمكن البحث عنها باستخدام find()
وحذفها باستخدام erase()
. في الوقت الحالي، يمكن استخدام السلاسل والأعداد الصحيحة والعوامات فقط كمفاتيح للقاموس. الامتيازات : يمكن الوصول إلى مفاتيح السلسلة الشبيهة بالمعرف أيضًا من خلال بناء جملة "عضو في": d.key
.
الوظيفة كل من الوظائف المستقلة و lambda لها نفس نوع الكائن ويمكن تمريرها مثل أي كائن آخر (انظر أدناه). لكن لامدا فقط هي التي يمكنها الحصول على قائمة التقاط. لا يمكن تنفيذ الوظائف العادية أثناء التقييم الثابت، بينما يمكن تنفيذ الوظائف pure
. يمكن للوظائف البحتة رؤية الثوابت ووسائطها فقط.
الاستثناء هو النوع الوحيد من الكائنات التي يمكن رميها. لإنشائها، استخدم exception()
المدمج أو اختصاره ex()
.
تعمل العبارات الشرطية تمامًا كما في C
بناء الجملة هو:
if ( conditionExpr ) {
# Then block
} else {
# Else block
}
ويمكن حذف الأقواس { }
كما في C
، في حالة الكتل ذات العبارة المفردة. يمكن أن يكون conditionExpr
أي تعبير، على سبيل المثال: (a=3)+b >= c && !d
.
عندما يكون conditionExpr
تعبيرًا يمكن تقييمه بشكل ثابت، يتم استبدال عبارة if بأكملها بالفرع الحقيقي، بينما يتم تجاهل الفرع الخاطئ. على سبيل المثال، خذ بعين الاعتبار البرنامج النصي التالي:
const a = 3 ;
const b = 4 ;
if ( a < b ) {
print ( " yes " ) ;
} else {
print ( " no " ) ;
}
لا يقتصر الأمر على طباعة "نعم" دائمًا فحسب، بل لا يحتاج حتى إلى التحقق من أي شيء قبل القيام بذلك. تحقق من شجرة بناء الجملة المجردة:
$ ./build/mylang -s t
Syntax tree
--------------------------
Block(
Block(
CallExpr(
Id("print")
ExprList(
"yes"
)
)
)
)
--------------------------
yes
يدعم MyLang
حلقات while
و for
الكلاسيكية.
while ( condition ) {
# body
if ( something )
break ;
if ( something_else )
continue ;
}
for ( var i = 0 ; i < 10 ; i += 1 ) {
# body
if ( something )
break ;
if ( something_else )
continue ;
}
هنا يمكن حذف الأقواس { }
كما في الحالة أعلاه. لا يوجد سوى اختلافات قليلة عن C
تستحق الإشارة إليها:
العاملان ++
--
غير موجودين في MyLang
في الوقت الحالي.
للإعلان عن متغيرات متعددة، استخدم الصيغة: var a, b = [3,4];
أو فقط var a,b,c,d = 0;
إذا كنت تريد أن يكون لجميع المتغيرات نفس القيمة الأولية.
لزيادة قيمة المتغيرات المتعددة استخدم الصيغة: a, b += [1, 2]
. في الحالات النادرة والمعقدة للغاية عندما نحتاج في عبارة الزيادة في حلقة for إلى تعيين متغير جديد لكل متغير باستخدام تعبيرات مختلفة، والاستفادة من بناء جملة التوسيع في المهمة: i, j = [i+2, my_next(i, j*3)]
.
يدعم MyLang
حلقات foreach
باستخدام بناء جملة مألوف جدًا:
var arr = [ 1 , 2 , 3 ] ;
foreach ( var e in arr ) {
print ( " elem: " , e ) ;
}
يمكن استخدام حلقات Foreach للمصفوفات والسلاسل والقواميس. على سبيل المثال، يعد التكرار خلال كل زوج <key, value>
في القاموس أمرًا سهلاً كما يلي:
var d = { " a " : 3 , " b " : 10 , " c " : 42 } ;
foreach ( var k , v in d ) {
print ( k + " => " + str ( v ) ) ;
}
للتكرار فقط من خلال كل مفتاح، فقط استخدم var k in d
بدلاً من ذلك.
يدعم MyLang
التعداد في حلقات foreach أيضًا. تحقق من المثال التالي:
var arr = [ " a " , " b " , " c " ] ;
foreach ( var i , elem in indexed arr ) {
print ( " elem[ " + str ( i ) + " ] = " + elem ) ;
}
بمعنى آخر، عندما يسبق اسم الحاوية الكلمة الأساسية indexed
، يتم تعيين رقم تدريجي للمتغير الأول في كل تكرار.
أثناء التكرار عبر مصفوفة من المصفوفات الصغيرة ذات الحجم الثابت (فكر في الصف)، من الممكن توسيع تلك "الصفوف" مباشرة في حلقة foreach:
var arr = [
[ " hello " , 42 ] ,
[ " world " , 11 ]
] ;
foreach ( var name , value in arr ) {
print ( name , value ) ;
}
# This is a shortcut for :
foreach ( var elem in arr ) {
# regular array expansion
var name , value = elem ;
print ( name , value ) ;
}
# Which is a shortcut for :
foreach ( var elem in arr ) {
var name = elem [ 0 ] ;
var value = elem [ 1 ] ;
print ( name , value ) ;
}
الإعلان عن وظيفة بسيط كما يلي:
func add ( x , y ) {
return x + y ;
}
ولكن يتم دعم العديد من الاختصارات أيضًا. على سبيل المثال، في حالة وظائف العبارة المفردة مثل تلك المذكورة أعلاه، يمكن استخدام بناء الجملة التالي:
func add ( x , y ) => x + y ;
أيضًا، على الرغم من أنه من الممارسات الجيدة دائمًا كتابة ()
للدوال التي لا تحتوي على معلمات، إلا أنها في الواقع اختيارية في هذه اللغة:
func do_something { print ( " hello " ) ; }
يتم التعامل مع الوظائف كرموز عادية في MyLang
ولا توجد اختلافات جوهرية بين الوظائف المستقلة و lambdas في هذه اللغة. على سبيل المثال، يمكننا أن نعلن عن وظيفة add
(أعلاه) كدالة لامدا بهذه الطريقة:
var add = func ( x , y ) => x + y ;
ملاحظة: عند إنشاء كائنات دالة في التعبيرات، لا يُسمح لنا بتعيين اسم لها.
تدعم Lambdas قائمة الالتقاط أيضًا، ولكن لا يتم دعم عمليات الالتقاط الضمنية، وذلك من أجل فرض الوضوح. بالطبع، يمكن إرجاع lambdas كأي كائن آخر. على سبيل المثال:
func create_adder_func ( val ) =>
func [ val ] ( x ) => x + val ;
var f = create_adder_func ( 5 ) ;
print ( f ( 1 ) ) ; # Will print 6
print ( f ( 10 ) ) ; # Will print 15
لامبدا مع الأسر لديها حالة ، كما يتوقع أي شخص. خذ بعين الاعتبار البرنامج النصي التالي:
func gen_counter ( val ) => func [ val ] {
val += 1 ;
return val ;
} ;
var c1 = gen_counter ( 5 ) ;
for ( var i = 0 ; i < 3 ; i += 1 )
print ( " c1: " , c1 ( ) ) ;
# Clone the `c1` lambda object as `c2` : now it will have
# its own state , indipendent from `c1` .
var c2 = clone ( c1 ) ;
print ( ) ;
for ( var i = 0 ; i < 3 ; i += 1 )
print ( " c2: " , c2 ( ) ) ;
print ( ) ;
for ( var i = 0 ; i < 3 ; i += 1 )
print ( " c1: " , c1 ( ) ) ;
يولد الإخراج:
c1: 6
c1: 7
c1: 8
c2: 9
c2: 10
c2: 11
c1: 9
c1: 10
c1: 11
لا تعتبر كائنات الوظائف العادية المحددة من قبل المستخدم (بما في ذلك lambdas) const
، وبالتالي لا يمكن تشغيلها أثناء التقييم الثابت. هذا قيد قوي جدًا. خذ بعين الاعتبار المثال التالي:
const people = [
[ " jack " , 3 ] ,
[ " alice " , 11 ] ,
[ " mario " , 42 ] ,
[ " bob " , 38 ]
] ;
const sorted_people = sort ( people , func ( a , y ) => a [ 0 ] < b [ 0 ] ) ;
في هذه الحالة، لا يمكن للبرنامج النصي إنشاء مصفوفة sorted_people
. نظرًا لأننا قمنا بتمرير كائن دالة إلى الدالة constsort sort()
، فسوف نحصل على خطأ ExpressionIsNotConstEx
. بالتأكيد، إذا تم الإعلان عن sorted_people
كـ var
، فسيتم تشغيل البرنامج النصي، لكن المصفوفة لن تكون ثابتة بعد الآن، ولن نتمكن من الاستفادة من أي تحسين لوقت التحليل . لذلك، على الرغم من أنه يمكن استدعاء الصنف sort()
أثناء التقييم الثابت، إلا أنه عندما يحتوي على معلمة compare func
مخصصة، لم يعد هذا ممكنًا بعد الآن.
للتغلب على القيود الموصوفة للتو، لدى MyLang
بناء جملة خاص للوظائف النقية . عندما يتم الإعلان عن دالة باستخدام الكلمة الأساسية pure
التي تسبق func
، فإن المترجم يعاملها بطريقة خاصة: يمكن استدعاؤها في أي وقت، سواء أثناء تقييم const أو أثناء وقت التشغيل ، لكن الدالة لا يمكنها رؤية المتغيرات العامة، ولا التقاط أي شيء: يمكنها فقط استخدام الثوابت وقيمة معلماتها: هذا بالضبط ما نحتاجه أثناء التقييم الثابت. على سبيل المثال، لإنشاء sorted_people
أثناء التقييم الثابت، يكفي كتابة ما يلي:
const sorted_people = sort ( people , pure func ( a , b ) => a [ 0 ] < b [ 0 ] ) ;
يمكن تعريف الوظائف النقية على أنها وظائف مستقلة ويمكن استخدامها مع معلمات غير ثابتة أيضًا. لذلك، إذا كان من الممكن الإعلان عن دالة على أنها pure
، فيجب دائمًا الإعلان عنها بهذه الطريقة. على سبيل المثال، خذ بعين الاعتبار البرنامج النصي التالي:
pure func add2 ( x ) => x + 2 ;
var non_const = 25 ;
print ( add2 ( non_const ) ) ;
print ( add2 ( 5 ) ) ;
شجرة بناء الجملة المجردة التي سيستخدمها محرك اللغة في وقت التشغيل ستكون:
$ ./build/mylang -s t
Syntax tree
--------------------------
Block(
FuncDeclStmt(
Id("add2")
<NoCaptures>
IdList(
Id("x")
)
Expr04(
Id("x")
Op '+'
Int(2)
)
)
VarDecl(
Id("non_const")
Op '='
Int(25)
)
CallExpr(
Id("print")
ExprList(
CallExpr(
Id("add2")
ExprList(
Id("non_const")
)
)
)
)
CallExpr(
Id("print")
ExprList(
Int(7)
)
)
)
--------------------------
27
7
كما ترون، في الحالة الأولى يحدث استدعاء دالة فعلية لأن non_const
ليس ثابتًا، بينما في الحالة الثانية يكون الأمر كما لو أننا مررنا عددًا صحيحًا حرفيًا إلى print()
.
كما هو الحال مع البنيات الأخرى، لدى MyLang
معالجة استثناء مشابهة لتلك الموجودة Python
، ولكن باستخدام بناء جملة مشابه لـ C++
. البناء الأساسي هو بيان try-catch
. دعونا نرى مثالا:
try {
var input_str = " blah " ;
var a = int ( input_str ) ;
} catch ( TypeErrorEx ) {
print ( " Cannot convert the string to integer " ) ;
}
ملاحظة: إذا تم إنشاء استثناء بواسطة تعبيرات ثابتة (على سبيل المثال int("blah")
)، أثناء تقييم const، فسيتم الإبلاغ عن الخطأ مباشرة، متجاوزًا أي منطق لمعالجة الاستثناء. والسبب في ذلك هو فرض الفشل المبكر .
يُسمح أيضًا ببيانات catch
المتعددة:
try {
# body
} catch ( TypeErrorEx ) {
# error handling
} catch ( DivisionByZeroEx ) {
# error handling
}
وفي حالة إمكانية معالجة العديد من الاستثناءات بنفس الكود، يمكن استخدام بناء جملة أقصر أيضًا:
try {
# body
} catch ( TypeErrorEx , DivisionByZeroEx as e ) {
# error handling
print ( e ) ;
} catch ( OutOfBoundsEx ) {
# error handling
}
قد تحتوي الاستثناءات على بيانات، لكن لا تحتوي أي من الاستثناءات المضمنة حاليًا على بيانات. قائمة استثناءات وقت التشغيل المضمنة التي يمكن اكتشافها باستخدام كتل try-catch
هي:
بدلاً من ذلك، لا يمكن اكتشاف الاستثناءات الأخرى مثل SyntaxErrorEx
. من الممكن أيضًا في MyLang
التقاط أي استثناء باستخدام كتلة التقاط أي شيء:
try {
# body
} catch {
# Something went wrong .
}
هذه اللغة لا تدعم الأنواع المخصصة في الوقت الحالي. لذلك، ليس من الممكن رمي أي نوع من الأشياء كما هو الحال في بعض اللغات الأخرى. لطرح استثناء، من الضروري استخدام الدالة المضمنة الخاصة exception()
أو اختصارها ex()
. خذ بعين الاعتبار المثال التالي:
try {
throw ex ( " MyError " , 1234 ) ;
} catch ( MyError as e ) {
print ( " Got MyError, data: " , exdata ( e ) ) ;
}
كما يوحي الحدس، باستخدام ex()
قمنا بإنشاء كائن استثناء يسمى MyError
ثم قمنا بإلقائه لاحقًا، ويحتوي على 1234
كبيانات حمولة. لاحقًا، في كتلة catch
، اكتشفنا الاستثناء واستخرجنا بيانات الحمولة باستخدام exdata()
المدمج.
في حالة عدم حاجة استثناء معين إلى حمولة، فمن الممكن فقط حفظ نتيجة ex()
في متغير وإلقائها لاحقًا باستخدام بناء جملة ربما يكون أكثر متعة:
var MyError = ex ( " MyError " ) ;
throw MyError ;
يدعم MyLang
إعادة طرح استثناء في نص عبارات الالتقاط باستخدام الكلمة الأساسية المخصصة rethrow
:
try {
do_something ( ) ;
} catch {
print ( " Something went wrong!! " ) ;
rethrow ;
}
في بعض الحالات، قد يكون من الضروري إجراء بعض عمليات التنظيف، بعد تنفيذ كتلة من التعليمات البرمجية التي قد تسبب استثناءً. في هذه الحالات، يدعم MyLang
الجملة finally
المعروفة، والتي تعمل تمامًا كما في C#
:
try {
step1_might_throw ( ) ;
step2_might_throw ( ) ;
step3_might_throw ( ) ;
step4_might_throw ( ) ;
} catch ( TypeErrorEx ) {
# some error handling
} finally {
# clean - up
}
تجدر الإشارة إلى أن بنيات try-finally
(بدون أي جملة catch
) مسموح بها أيضًا.
سيتم تقييم الوظائف المضمنة التالية أثناء وقت التحليل عندما يتم تمرير وسيطات const إليها.
defined(symbol)
تحقق مما إذا تم تعريف symbol
. يُرجع 1 إذا تم تعريف الرمز، ويعيد 0 بخلاف ذلك.
len(container)
إرجاع عدد العناصر في الحاوية المحددة.
str(value, [decimal_digits])
تحويل القيمة المعطاة إلى سلسلة. إذا كانت value
عائمة، تشير المعلمة الثانية إلى العدد المطلوب من الأرقام العشرية في سلسلة الإخراج.
int(value)
تحويل السلسلة المحددة إلى عدد صحيح. إذا كانت القيمة عائمة، فسيتم اقتطاعها. إذا كانت القيمة عبارة عن سلسلة، فسيتم تحليلها وتحويلها إلى عدد صحيح، إن أمكن. إذا كانت القيمة عددًا صحيحًا بالفعل، فسيتم إرجاعها كما هي.
float(value)
تحويل القيمة المعطاة إلى تعويم. إذا كانت القيمة عددًا صحيحًا، فسيتم تحويلها إلى رقم الفاصلة العائمة. إذا كانت القيمة عبارة عن سلسلة، فسيتم تحليلها وتحويلها إلى قيمة عائمة، إن أمكن. إذا كانت القيمة عائمة بالفعل، فسيتم إرجاعها كما هي.
clone(obj)
استنساخ الكائن المحدد. مفيد للكائنات غير التافهة مثل المصفوفات والقواميس ولامدا مع اللقطات.
type(value)
قم بإرجاع اسم نوع القيمة المحددة في شكل سلسلة. مفيدة لتصحيح الأخطاء.
hash(value)
قم بإرجاع قيمة التجزئة التي تستخدمها القواميس داخليًا عند استخدام value
كمفتاح. في الوقت الحالي، تدعم الأعداد الصحيحة والعوامات والسلاسل فقط hash()
.
array(N)
إرجاع مجموعة من none